diff -Nru a/CREDITS b/CREDITS
--- a/CREDITS	Tue Oct  1 00:08:15 2002
+++ b/CREDITS	Tue Oct  1 00:08:15 2002
@@ -39,7 +39,7 @@
 
 N: Tigran A. Aivazian
 E: tigran@veritas.com
-W: http://www.ocston.org/~tigran
+W: http://www.moses.uklinux.net/patches
 D: BFS filesystem
 D: Intel IA32 CPU microcode update support
 D: Various kernel patches
@@ -437,6 +437,13 @@
 S: Kopmansg 2
 S: 411 13  Goteborg
 S: Sweden
+
+N: Dominik Brodowski
+E: linux@brodo.de
+W: http://www.brodo.de/
+P: 1024D/725B37C6  190F 3E77 9C89 3B6D BECD  46EE 67C3 0308 725B 37C6
+D: parts of CPUFreq code, ACPI bugfixes
+S: Tuebingen, Germany
 
 N: Andries Brouwer
 E: aeb@cwi.nl
diff -Nru a/Documentation/Changes b/Documentation/Changes
--- a/Documentation/Changes	Tue Oct  1 00:08:20 2002
+++ b/Documentation/Changes	Tue Oct  1 00:08:20 2002
@@ -55,7 +55,7 @@
 o  modutils               2.4.2                   # insmod -V
 o  e2fsprogs              1.25                    # tune2fs
 o  jfsutils               1.0.14                  # fsck.jfs -V
-o  reiserfsprogs          3.x.1b                  # reiserfsck 2>&1|grep reiserfsprogs
+o  reiserfsprogs          3.6.3                   # reiserfsck -V 2>&1|grep reiserfsprogs
 o  xfsprogs               2.1.0                   # xfs_db -V
 o  pcmcia-cs              3.1.21                  # cardmgr -V
 o  PPP                    2.4.0                   # pppd --version
@@ -229,7 +229,6 @@
 version v0.99.0 or higher. Running old versions may cause problems
 with programs using shared memory.
 
-
 Networking
 ==========
 
@@ -326,7 +325,7 @@
 
 Reiserfsprogs
 -------------
-o  <ftp://ftp.namesys.com/pub/reiserfsprogs/reiserfsprogs-3.x.1b.tar.gz>
+o  <http://www.namesys.com/pub/reiserfsprogs/reiserfsprogs-3.6.3.tar.gz>
 
 Xfsprogs
 --------
diff -Nru a/Documentation/DocBook/sis900.tmpl b/Documentation/DocBook/sis900.tmpl
--- a/Documentation/DocBook/sis900.tmpl	Tue Oct  1 00:08:14 2002
+++ b/Documentation/DocBook/sis900.tmpl	Tue Oct  1 00:08:14 2002
@@ -323,8 +323,8 @@
 The 1.06 revision can be found in kernel version later than 2.3.15 and pre-2.2.14, 
 and 1.07 revision can be found in kernel version 2.4.0.
 If you have no prior experience in networking under Linux, please read
-<ULink URL="http://www.linuxdoc.org/">Ethernet HOWTO</ULink> and
-<ULink URL="http://www.linuxdoc.org/">Networking HOWTO</ULink> available from
+<ULink URL="http://www.tldp.org/">Ethernet HOWTO</ULink> and
+<ULink URL="http://www.tldp.org/">Networking HOWTO</ULink> available from
 Linux Documentation Project (LDP).
 </Para>
 
@@ -435,7 +435,7 @@
 Typical values are "10baseT"(twisted-pair 10Mbps Ethernet) or "100baseT"
 (twisted-pair 100Mbps Ethernet). For more information on how to configure 
 network interface, please refer to  
-<ULink URL="http://www.linuxdoc.org/">Networking HOWTO</ULink>.
+<ULink URL="http://www.tldp.org/">Networking HOWTO</ULink>.
 </Para>
 
 <Para>
diff -Nru a/Documentation/cpufreq b/Documentation/cpufreq
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/cpufreq	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,361 @@
+     CPU frequency and voltage scaling code in the Linux(TM) kernel
+
+
+		         L i n u x    C P U F r e q
+
+
+
+
+		    Dominik Brodowski  <linux@brodo.de>
+		     David Kimdon <dwhedon@debian.org>
+
+
+
+   Clock scaling allows you to change the clock speed of the CPUs on the
+    fly. This is a nice method to save battery power, because the lower
+            the clock speed, the less power the CPU consumes.
+
+
+
+Contents:
+---------
+1.  Supported architectures
+2.  User interface
+2.1   /proc/cpufreq interface  [2.6]
+2.2.  /proc/sys/cpu/ interface [2.4]
+3.  CPUFreq core and interfaces
+3.1   General information
+3.2   CPUFreq notifiers
+3.3   CPUFreq architecture drivers
+4.  Mailing list and Links
+
+
+
+1. Supported architectures
+==========================
+
+ARM:
+    ARM Integrator, SA 1100, SA1110
+--------------------------------
+    This driver will be ported to new CPUFreq core soon, so
+    far it will not work.
+
+
+AMD Elan:
+    SC400, SC410
+--------------------------------
+    You need to specify the highest allowed CPU frequency as 
+    a module parameter ("max_freq") or as boot parameter 
+    ("elanfreq="). Else the available speed range will be 
+    limited to the speed at which the CPU runs while this
+    module is loaded.
+
+
+VIA Cyrix Longhaul:
+    VIA Samuel/CyrixIII, VIA Cyrix Samuel/C3, 
+    VIA Cyrix Ezra, VIA Cyrix Ezra-T
+--------------------------------
+    If you do not want to scale the Front Side Bus or voltage,
+    pass the module parameter "dont_scale_fsb 1" or
+    "dont_scale_voltage 1". Additionally, it is advised that
+    you pass the current Front Side Bus speed (in MHz) to 
+    this module as module parameter "current_fsb", e.g. 
+    "current_fsb 133" for a Front Side Bus speed of 133 MHz.
+
+
+Intel SpeedStep:
+    certain mobile Intel Pentium III (Coppermine), and all mobile
+    Intel Pentium III-M (Tualatin) and mobile Intel Pentium 4 P4-Ms.
+--------------------------------
+    Unfortunately only modern Intel ICH2-M and ICH3-M chipsets are 
+    supported.
+
+
+P4 CPU Clock Modulation:
+    Intel Pentium 4 Xeon processors
+---------------------------------
+    Note that you can only switch the speed of two logical CPUs at
+    once - but each phyiscal CPU may have different throttling levels.
+
+
+PowerNow! K6:
+    mobile AMD K6-2+ / mobile K6-3+:
+--------------------------------
+    No known issues.
+
+
+Transmeta Crusoe Longrun:
+    Transmeta Crusoe processors:
+--------------------------------
+    Does not work with the 2.4. /proc/sys/cpu/ interface.
+
+
+
+2. User Interface
+=================
+
+2.1   /proc/cpufreq interface [2.6]
+***********************************
+
+Starting in the patches for kernel 2.5.33, CPUFreq uses a "policy"
+interface /proc/cpufreq.
+
+When you "cat" this file, you'll find something like:
+
+--
+          minimum CPU frequency  -  maximum CPU frequency  -  policy
+CPU  0       1200000 ( 75%)      -     1600000 (100%)      -  performance
+--
+
+This means the current policy allows this CPU to be run anywhere
+between 1.2 GHz (the value is in kHz) and 1.6 GHz with an eye towards
+performance.
+
+To change the policy, "echo" the desired new policy into
+/proc/cpufreq. Use one of the following formats:
+
+cpu_nr:min_freq:max_freq:policy
+cpu_nr%min_freq%max_freq%policy
+min_freq:max_freq:policy
+min_freq%max_freq%policy
+
+with cpu_nr being the CPU which shall be affected, min_freq and
+max_freq the lower and upper limit of the CPU core frequency in kHz,
+and policy either "performance" or "powersave".
+A few examples:
+
+root@notebook:#echo -n "0:0:0:powersave" > /proc/cpufreq
+     sets the CPU #0 to the lowest supported frequency.
+
+root@notebook:#echo -n "1%100%100%performance" > /proc/cpufreq
+     sets the CPU #1 to the highest supported frequency.
+
+root@notebook:#echo -n "1000000:2000000:performance" > /proc/cpufreq
+     to set the frequency of all CPUs between 1 GHz and 2 GHz and to
+     the policy "performance".
+
+Please note that the values you "echo" into /proc/cpufreq are
+validated first, and may be limited by hardware or thermal
+considerations. Because of this, a read from /proc/cpufreq might 
+differ from what was written into it.
+
+
+When you read /proc/cpufreq for the first time after a CPUFreq driver
+has been initialized, you'll see the "default policy" for this
+driver. If this does not suit your needs, you can pass a boot
+parameter to the cpufreq core. Use the following syntax for this:
+   "cpufreq=min_freq:max_freq:policy", i.e. you may not chose a
+specific CPU and you need to specify the limits in kHz and not in
+per cent.
+
+
+2.2   /proc/cpufreq interface [2.4]
+***********************************
+
+Previsiously (and still available as a config option), CPUFreq used 
+a "sysctl" interface which is located in 
+	/proc/sys/cpu/0/
+	/proc/sys/cpu/1/ ...	(SMP only)
+
+In these directories, you will find three files of importance for
+CPUFreq: speed-max, speed-min and speed: 
+
+speed		    shows the current CPU frequency in kHz, 
+speed-min	    the minimum supported CPU frequency, and
+speed-max	    the maximum supported CPU frequency.
+
+
+To change the CPU frequency, "echo" the desired CPU frequency (in kHz)
+to speed. For example, to set the CPU speed to the lowest/highest
+allowed frequency do:
+
+root@notebook:# cat /proc/sys/cpu/0/speed-min > /proc/sys/cpu/0/speed
+root@notebook:# cat /proc/sys/cpu/0/speed-max > /proc/sys/cpu/0/speed
+
+
+
+3.  CPUFreq core and interfaces
+===============================
+
+3.1   General information
+*************************
+
+The CPUFreq core code is located in linux/kernel/cpufreq.c. This
+cpufreq code offers a standardized interface for the CPUFreq
+architecture drivers (those pieces of code that do actual
+frequency transitions), as well as to "notifiers". These are device
+drivers or other part of the kernel that need to be informed of
+policy changes (like thermal modules like ACPI) or of all
+frequency changes (like timing code) or even need to force certain
+speed limits (like LCD drivers on ARM architecture). Additionally, the
+kernel "constant" loops_per_jiffy is updated on frequency changes
+here.
+
+
+3.2   CPUFreq notifiers
+***********************
+
+CPUFreq notifiers conform to the standard kernel notifier interface.
+See linux/include/linux/notifier.h for details on notifiers.
+
+There are two different CPUFreq notifiers - policy notifiers and
+transition notifiers.
+
+
+3.2.1 CPUFreq policy notifiers
+******************************
+
+These are notified when a new policy is intended to be set. Each
+CPUFreq policy notifier is called three times for a policy transition:
+
+1.) During CPUFREQ_ADJUST all CPUFreq notifiers may change the limit if
+    they see a need for this - may it be thermal considerations or
+    hardware limitations.
+
+2.) During CPUFREQ_INCOMPATIBLE only changes may be done in order to avoid
+    hardware failure.
+
+3.) And during CPUFREQ_NOTIFY all notifiers are informed of the new policy
+   - if two hardware drivers failed to agree on a new policy before this
+   stage, the incompatible hardware shall be shut down, and the user
+   informed of this.
+
+The phase is specified in the second argument to the notifier.
+
+The third argument, a void *pointer, points to a struct cpufreq_policy
+consisting of five values: cpu, min, max, policy and max_cpu_freq. Min 
+and max are the lower and upper frequencies (in kHz) of the new
+policy, policy the new policy, cpu the number of the affected CPU or
+CPUFREQ_ALL_CPUS for all CPUs; and max_cpu_freq the maximum supported
+CPU frequency. This value is given for informational purposes only.
+
+
+3.2.2 CPUFreq transition notifiers
+**********************************
+
+These are notified twice when the CPUfreq driver switches the CPU core
+frequency and this change has any external implications.
+
+The second argument specifies the phase - CPUFREQ_PRECHANGE or
+CPUFREQ_POSTCHANGE.
+
+The third argument is a struct cpufreq_freqs with the following
+values:
+cpu	- number of the affected CPU or CPUFREQ_ALL_CPUS
+old	- old frequency
+new	- new frequency
+
+
+3.3   CPUFreq architecture drivers
+**********************************
+
+CPUFreq architecture drivers are the pieces of kernel code that
+actually perform CPU frequency transitions. These need to be
+initialized separately (separate initcalls), and may be
+modularized. They interact with the CPUFreq core in the following way:
+
+cpufreq_register()
+------------------
+cpufreq_register registers an arch driver to the CPUFreq core. Please
+note that only one arch driver may be registered at any time. -EBUSY
+is returned when an arch driver is already registered. The argument to
+cpufreq_register, struct cpufreq_driver *driver, is described later.
+
+cpufreq_unregister()
+--------------------
+cpufreq_unregister unregisters an arch driver, e.g. on module
+unloading. Please note that there is no check done that this is called
+from the driver which actually registered itself to the core, so
+please only call this function when you are sure the arch driver got
+registered correctly before.
+
+cpufreq_notify_transition()
+---------------------------
+On "dumb" hardware where only fixed frequency can be set, the driver
+must call cpufreq_notify_transition() once before, and once after the
+actual transition.
+
+struct cpufreq_driver
+---------------------
+On initialization, the arch driver is supposed to pass a pointer
+to a struct cpufreq_driver *cpufreq_driver consisting of the following
+entries:
+
+cpufreq_verify_t verify: This is a pointer to a function with the
+	following definition:
+	void verify_function (struct cpufreq_policy *policy).
+	This function must verify the new policy is within the limits
+	supported by the CPU, and at least one supported CPU is within
+	this range. It may be useful to use cpufreq.h /
+	cpufreq_verify_within_limits for this.
+
+cpufreq_setpolicy_t setpolicy: This is a pointer to a function with
+	the following definition:
+	void setpolicy_function (struct cpufreq_policy *policy).
+	This function must set the CPU to the new policy. If it is a
+	"dumb" CPU which only allows fixed frequencies to be set, it
+	shall set it to the lowest within the limit for
+	CPUFREQ_POLICY_POWERSAVE, and to the highest for
+	CPUFREQ_POLICY_PERFORMANCE. Once CONFIG_CPU_FREQ_DYNAMIC is
+	implemented, it can use a dynamic method to adjust the speed
+	between the lower and upper limit.
+
+struct cpufreq_policy   *policy: This is an array of NR_CPUS struct
+	cpufreq_policies, containing the current policies set for these
+	CPUs. Note that policy[0].max_cpu_freq must contain the
+	absolute maximum CPU frequency supported by _all_ CPUs.
+
+In case the driver is expected to run with the 2.4.-style API
+(/proc/sys/cpu/.../), two more values must be passed
+#ifdef CONFIG_CPU_FREQ_24_API
+	unsigned int            cpu_min_freq;
+	unsigned int            cpu_cur_freq[NR_CPUS];
+#endif
+	with cpu_min_freq being the minimum CPU frequency supported by
+	the CPUs; and the entries in cpu_cur_freq reflecting the
+	current speed of the appropriate CPU.
+
+Some Requirements to CPUFreq architecture drivers
+-------------------------------------------------
+* Only call cpufreq_register() when the ability to switch CPU
+  frequencies is _verified_ or can't be missing
+* cpufreq_unregister() may only be called if cpufreq_register() has
+  been successfully(!) called before.
+* kfree() the struct cpufreq_driver only after the call to 
+  cpufreq_unregister(), unless cpufreq_register() failed.
+* Be aware that there is currently no error management in the
+  setpolicy() code in the CPUFreq core. So only call yourself a
+  cpufreq_driver if you are really a working cpufreq_driver!
+
+
+
+4. Mailing list and Links
+*************************
+
+
+Mailing List
+------------
+There is a CPU frequency changing CVS commit and general list where
+you can report bugs, problems or submit patches. To post a message,
+send an email to cpufreq@www.linux.org.uk, to subscribe go to
+http://www.linux.org.uk/mailman/listinfo/cpufreq. Previous post to the
+mailing list are available to subscribers at
+http://www.linux.org.uk/mailman/private/cpufreq/.
+
+
+Links
+-----
+the FTP archives:
+* ftp://ftp.linux.org.uk/pub/linux/cpufreq/
+
+how to access the CVS repository:
+* http://cvs.arm.linux.org.uk/
+
+the CPUFreq Mailing list:
+* http://www.linux.org.uk/mailman/listinfo/cpufreq
+
+Clock and voltage scaling for the SA-1100:
+* http://www.lart.tudelft.nl/projects/scaling
+
+CPUFreq project homepage
+* http://www.brodo.de/cpufreq/
diff -Nru a/Documentation/filesystems/isofs.txt b/Documentation/filesystems/isofs.txt
--- a/Documentation/filesystems/isofs.txt	Tue Oct  1 00:08:15 2002
+++ b/Documentation/filesystems/isofs.txt	Tue Oct  1 00:08:15 2002
@@ -29,3 +29,10 @@
   unhide        Show hidden files.
   session=x     Select number of session on multisession CD
   sbsector=xxx  Session begins from sector xxx
+
+Recommended documents about ISO 9660 standard are located at:
+http://www.y-adagio.com/public/standards/iso_cdromr/tocont.htm
+ftp://ftp.ecma.ch/ecma-st/Ecma-119.pdf
+Quoting from the PDF "This 2nd Edition of Standard ECMA-119 is technically 
+identical with ISO 9660.", so it is a valid and gratis substitute of the
+official ISO specification.
diff -Nru a/Documentation/i810_rng.txt b/Documentation/i810_rng.txt
--- a/Documentation/i810_rng.txt	Tue Oct  1 00:08:18 2002
+++ b/Documentation/i810_rng.txt	Tue Oct  1 00:08:18 2002
@@ -72,6 +72,7 @@
 
 	Version 0.9.8:
 	* Support other i8xx chipsets by adding 82801E detection
+	* 82801DB detection is the same as for 82801CA.
 
 	Version 0.9.7:
 	* Support other i8xx chipsets too (by adding 82801BA(M) and
diff -Nru a/Documentation/kernel-docs.txt b/Documentation/kernel-docs.txt
--- a/Documentation/kernel-docs.txt	Tue Oct  1 00:08:18 2002
+++ b/Documentation/kernel-docs.txt	Tue Oct  1 00:08:18 2002
@@ -41,7 +41,7 @@
        
      * Title: "The Linux Kernel"
        Author: David A. Rusling.
-       URL: http://www.linuxdoc.org/LDP/tlk/tlk.html
+       URL: http://www.tldp.org/LDP/tlk/tlk.html
        Keywords: everything!, book.
        Description: On line, 200 pages book describing most aspects of
        the Linux Kernel. Probably, the first reference for beginners.
@@ -57,7 +57,7 @@
        
      * Title: "The Linux Kernel Hackers' Guide"
        Author: Michael K.Johnson and others.
-       URL: http://www.linuxdoc.org/LDP/khg/HyperNews/get/khg.html
+       URL: http://www.tldp.org/LDP/khg/HyperNews/get/khg.html
        Keywords: everything!
        Description: No more Postscript book-like version. Only HTML now.
        Many people have contributed. The interface is similar to web
@@ -277,7 +277,7 @@
        
      * Title: "Linux Kernel Module Programming Guide"
        Author: Ori Pomerantz.
-       URL: http://www.linuxdoc.org/LDP/lkmpg/mpg.html
+       URL: http://www.tldp.org/LDP/lkmpg/mpg.html
        Keywords: modules, GPL book, /proc, ioctls, system calls,
        interrupt handlers .
        Description: Very nice 92 pages GPL book on the topic of modules
diff -Nru a/Documentation/networking/00-INDEX b/Documentation/networking/00-INDEX
--- a/Documentation/networking/00-INDEX	Tue Oct  1 00:08:19 2002
+++ b/Documentation/networking/00-INDEX	Tue Oct  1 00:08:19 2002
@@ -44,6 +44,10 @@
 	- the Digi International RightSwitch SE-X Ethernet driver
 dmfe.txt
 	- info on the Davicom DM9102(A)/DM9132/DM9801 fast ethernet driver.
+e100.txt
+	- info on Intel's EtherExpress PRO/100 line of 10/100 boards
+e1000.txt
+	- info on Intel's E1000 line of gigabit ethernet boards
 eql.txt
 	- serial IP load balancing
 ethertap.txt
diff -Nru a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
--- a/Documentation/networking/ip-sysctl.txt	Tue Oct  1 00:08:17 2002
+++ b/Documentation/networking/ip-sysctl.txt	Tue Oct  1 00:08:17 2002
@@ -89,7 +89,7 @@
 
 tcp_retries1 - INTEGER
 	How many times to retry before deciding that something is wrong
-	and it is necessary to report this suspection to network layer.
+	and it is necessary to report this suspicion to network layer.
 	Minimal RFC value is 3, it is default, which corresponds
 	to ~3sec-8min depending on RTO.
 
@@ -200,7 +200,7 @@
 	Enable select acknowledgments (SACKS).
 
 tcp_fack - BOOLEAN
-	Enable FACK congestion avoidance and fast restransmission.
+	Enable FACK congestion avoidance and fast retransmission.
 	The value is not used, if tcp_sack is not enabled.
 
 tcp_dsack - BOOLEAN
@@ -256,7 +256,7 @@
 
 	pressure: when amount of memory allocated by TCP exceeds this number
 	of pages, TCP moderates its memory consumption and enters memory
-	pressure mode, which is exited when memory consumtion falls
+	pressure mode, which is exited when memory consumption falls
 	under "low".
 
 	high: number of pages allowed for queueing by all TCP sockets.
@@ -278,7 +278,7 @@
 tcp_rfc1337 - BOOLEAN
 	If set, the TCP stack behaves conforming to RFC1337. If unset,
 	we are not conforming to RFC, but prevent TCP TIME_WAIT
-	asassination.	
+	assassination.   
 	Default: 0
 
 ip_local_port_range - 2 INTEGERS
@@ -295,7 +295,7 @@
 	2000 connections per second to systems supporting timestamps.
 
 ip_nonlocal_bind - BOOLEAN
-	If set, allows processes to bind() to non-local IP adresses,
+	If set, allows processes to bind() to non-local IP addresses,
 	which can be quite useful - but may break some applications.
 	Default: 0
 
diff -Nru a/Documentation/s390/Debugging390.txt b/Documentation/s390/Debugging390.txt
--- a/Documentation/s390/Debugging390.txt	Tue Oct  1 00:08:15 2002
+++ b/Documentation/s390/Debugging390.txt	Tue Oct  1 00:08:15 2002
@@ -238,7 +238,7 @@
 
 On 390 our limitations & strengths make us slightly different.
 For backward compatibility ( because of the psw address hi bit which
-indicates whether we are in 31 or 24 bit mode ) we are only allowed 
+indicates whether we are in 31 or 64 bit mode ) we are only allowed 
 use 31 bits (2GB) of our 32 bit addresses. However, 
 we use entirely separate address  spaces for the user & kernel.
 
diff -Nru a/Documentation/scsi-generic.txt b/Documentation/scsi-generic.txt
--- a/Documentation/scsi-generic.txt	Tue Oct  1 00:08:18 2002
+++ b/Documentation/scsi-generic.txt	Tue Oct  1 00:08:18 2002
@@ -30,7 +30,7 @@
 =======================
 The most recent documentation of the sg driver is kept at the Linux
 Documentation Project's (LDP) site: 
-http://www.linuxdoc.org/HOWTO/SCSI-Generic-HOWTO
+http://www.tldp.org/HOWTO/SCSI-Generic-HOWTO
 This describes the sg version 3 driver found in the lk 2.4 series.
 The LDP renders documents in single and multiple page HTML, postscript
 and pdf. This document can also be found at:
@@ -51,7 +51,7 @@
 can be found at the top of the /usr/src/linux/drivers/scsi/sg.c file.
 
 A more general description of the Linux SCSI subsystem of which sg is a 
-part can be found at http://www.linuxdoc.org/HOWTO/SCSI-2.4-HOWTO .
+part can be found at http://www.tldp.org/HOWTO/SCSI-2.4-HOWTO .
 
 
 Example code and utilities
diff -Nru a/Documentation/scsi.txt b/Documentation/scsi.txt
--- a/Documentation/scsi.txt	Tue Oct  1 00:08:15 2002
+++ b/Documentation/scsi.txt	Tue Oct  1 00:08:15 2002
@@ -2,7 +2,7 @@
 ============================
 The Linux Documentation Project (LDP) maintains a document describing
 the SCSI subsystem in the Linux kernel (lk) 2.4 series. See:
-http://www.linuxdoc.org/HOWTO/SCSI-2.4-HOWTO . The LDP has single
+http://www.tldp.org/HOWTO/SCSI-2.4-HOWTO . The LDP has single
 and multiple page HTML renderings as well as postscript and pdf.
 It can also be found at http://www.torque.net/scsi/SCSI-2.4-HOWTO .
 
diff -Nru a/Documentation/sound/alsa/serial-u16550.txt b/Documentation/sound/alsa/serial-u16550.txt
--- a/Documentation/sound/alsa/serial-u16550.txt	Tue Oct  1 00:08:18 2002
+++ b/Documentation/sound/alsa/serial-u16550.txt	Tue Oct  1 00:08:18 2002
@@ -8,6 +8,7 @@
   1 - Midiator MS-124T support (1)
   2 - Midiator MS-124W S/A mode (2)
   3 - MS-124W M/B mode support (3)
+  4 - Generic device with multiple input support (4)
 
 For the Midiator MS-124W, you must set the physical M-S and A-B
 switches on the Midiator to match the driver mode you select.
@@ -82,3 +83,9 @@
 I do have documentation (tim.mann@compaq.com) that partially covers these models,
 but no units to experiment with.  The MS-124W support is tested with a real unit.
 The MS-124T support is untested, but should work.
+
+The Generic driver supports multiple input and output substreams over a single
+serial port.  Similar to Roland Soundcanvas mode, F5 NN is used to select the
+appropriate input or output stream (depending on the data direction).
+Additionally, the CTS signal is used to regulate the data flow.  The number of
+inputs is specified by the snd_ins parameter.
diff -Nru a/Documentation/sound/oss/PAS16 b/Documentation/sound/oss/PAS16
--- a/Documentation/sound/oss/PAS16	Tue Oct  1 00:08:20 2002
+++ b/Documentation/sound/oss/PAS16	Tue Oct  1 00:08:20 2002
@@ -71,7 +71,7 @@
   interrupt and DMA channel), because you will be asked for it.
 
   You want to read the Sound-HOWTO, available from
-  http://www.linuxdoc.org/docs.html#howto . General information
+  http://www.tldp.org/docs.html#howto . General information
   about the modular sound system is contained in the files
   Documentation/sound/Introduction. The file
   Documentation/sound/README.OSS contains some slightly outdated but
diff -Nru a/Documentation/sparc/README-2.5 b/Documentation/sparc/README-2.5
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/sparc/README-2.5	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,46 @@
+BTFIXUP
+-------
+
+To build new kernels you have to issue "make image". The ready kernel
+in ELF format is placed in arch/sparc/boot/image. Explanation is below.
+
+BTFIXUP is a unique feature of Linux/sparc among other architectures,
+developed by Jakub Jelinek (I think... Obviously David S. Miller took
+part, too). It allows to boot the same kernel at different 
+sub-architectures, such as sun4c, sun4m, sun4d, where SunOS uses
+different kernels. This feature is convinient for people who you move
+disks between boxes and for distrution builders.
+
+To function, BTFIXUP must link the kernel "in the draft" first,
+analyze the result, write a special stub code based on that, and
+build the final kernel with the stub (btfix.o).
+
+Kai Germaschewski improved the build system of the kernel in the 2.5 series
+significantly. Unfortunately, the traditional way of running the draft
+linking from architecture specific Makefile before the actual linking
+by generic Makefile is nearly impossible to support properly in the
+new build system. Therefore, the way we integrate BTFIXUP with the
+build system was changed in 2.5.40. Now, generic Makefile performs
+the draft linking and stores the result in file vmlinux. Architecture
+specific post-processing invokes BTFIXUP machinery and final linking
+in the same way as other architectures do bootstraps.
+
+Implications of that change are as follows.
+
+1. Hackers must type "make image" now, instead of just "make", in the same
+   way as s390 people do now. It is analogous to "make bzImage" on i386.
+   This does NOT affect sparc64, you continue to use "make" to build sparc64
+   kernels.
+
+2. vmlinux is not the final kernel, so RPM builders have to adjust
+   their spec files (if they delivered vmlinux for debugging).
+   System.map generated for vmlinux is still valid.
+
+3. Scripts that produce a.out images have to be changed. First, if they
+   invoke make, they have to use "make image". Second, they have to pick up
+   the new kernel in arch/sparc/boot/image instead of vmlinux.
+
+4. Since we are compliant with Kai's build system now, make -j is permitted.
+
+-- Pete Zaitcev
+zaitcev@yahoo.com
diff -Nru a/Documentation/vm/hugetlbpage.txt b/Documentation/vm/hugetlbpage.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/vm/hugetlbpage.txt	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,85 @@
+2002  Rohit Seth <rohit.seth@intel.com>
+
+The intent of this file is to give a brief summary of hugetlbpage support in
+the Linux kernel.  This support is built on top of multiple page size support
+that is provided by most of modern architectures.  For example, IA-32
+architecture supports 4K and 4M (2M in PAE mode) page sizes, IA-64
+architecture supports multiple page sizes 4K, 8K, 64K, 256K, 1M, 4M, 16M,
+256M.  A TLB is a cache of virtual-to-physical translations.  Typically this
+is a very scarce resource on processor.  Operating systems try to make best
+use of limited number of TLB resources.  This optimization is more critical
+now as bigger and bigger physical memories (several GBs) are more readily
+available.
+
+The current support is provided in kernel using the following two system calls:
+
+1) sys_alloc_hugepages(int key, unsigned long addr, size_t len, int prot, int flag)
+
+2) sys_free_hugepages(unsigned long addr)
+
+Arguments to these system calls are defined as follows:
+
+key: If a user application wants to share hugepages with other
+      processes then this input argument needs to be greater than 0. 
+      Different applications can use the same key to map the same physical
+      memory (mapped by hugeTLBs) in their address space.  When a process
+      forks, then children share the same physical memory with their parent.
+
+      For the cases when an application wishes to keep the huge pages
+      private, the key value of 0 is defined.  In this case kernel allocates
+      hugetlb pages to the process that are not shareable across different
+      processes.  These segments are marked private for the process.  These
+      segments are not copied to children's address space on forks.
+
+AKPM: So what is present at that address within the child?
+
+      The key manangement (and assignment) part is left to user
+      applications.
+
+addr: This is an address hint.  The kernel will perform a sanity check
+      on this address (alignment etc.) before using it.  It is possible that
+      kernel will allocates a different address (on success).
+
+len:  Length of the required segment.  Applications are expected to give
+      HPAGE_SIZE aligned length.  (Else EINVAL is returned.)
+
+prot: The prot parameter specifies the desired memory protection on the
+      requested hugepages.  The possible values are PROT_EXEC, PROT_READ,
+      PROT_WRITE.
+
+flag: This parameter can only take the value IPC_CREAT for the cases
+      when "key" value greater than zero (shared hugepage cases).  It is
+      ignored for values of "key" that are <= 0.
+
+      This parameter indicates that the kernel should create a new huge
+      page segment (corresponding to "key"), if none already exists.  If this
+      flag is not set, then sys_allochugepages() will return ENOENT if there
+      is no segment associated with corresponding "key".
+
+In case of success, sys_alloc_hugepages() return the allocated virtual address.
+
+sys_free_hugepages() frees the hugetlb resources from the calling process's
+address space.  The input argument "addr" specifies the segment that needs to
+be freed.  It is important to note that for the shared hugepage cases, the
+underlying hugepages are freed onlyafter all the users of those pages have
+either freed those hugepages or have exited.
+
+/proc/sys/vm_nr_hugepages indicates the current number of configured hugetlb
+pages in the kernel.  Super user privileges are required for modification of
+this value.  The allocation of hugetlb pages is posible only if there are
+enough physically contiguous free pages in system OR if there are enough
+hugetlb pages free that can be transfered back to regular memory pool.
+
+/proc/meminfo also gives the information about the total number of hugetlb
+pages configured in the kernel.  It also displays information about the
+number of free hugetlb pages at any time.  It also displays information about
+the configured hugepage size - this is needed for generting the proper
+alignment and size of the arguments to the above system calls.
+
+Pages that are used as hugetlb pages are marked reserved inside the kernel. 
+This allows hugetlb pages to be always locked in memory.  The user either
+needs to be super user to use these pages or one of supplementary group
+should include root.  In future there will be support to check RLIMIT_MLOCK
+for limited (number of hugetlb pages) usage to unprivileged applications.
+
+If the kernel does not support hugepages these system calls will return ENOSYS.
diff -Nru a/MAINTAINERS b/MAINTAINERS
--- a/MAINTAINERS	Tue Oct  1 00:08:17 2002
+++ b/MAINTAINERS	Tue Oct  1 00:08:17 2002
@@ -364,6 +364,11 @@
 W:	http://www.fi.muni.cz/~kas/cosa/
 S:	Maintained
 
+CPU FREQUENCY DRIVERS
+L:      cpufreq@www.linux.org.uk
+W:      http://www.brodo.de/cpufreq/
+S:      Maintained
+
 CPUID/MSR DRIVER
 P:	H. Peter Anvin
 M:	hpa@zytor.com
@@ -547,7 +552,7 @@
 EMU10K1 SOUND DRIVER
 P:	Rui Sousa	
 M:	rui.p.m.sousa@clix.pt	
-L:	emu10k1-devel@opensource.creative.com
+L:	emu10k1-devel@lists.sourceforge.net
 W:	http://opensource.creative.com/
 S:	Maintained
 
@@ -570,14 +575,12 @@
 S:	Maintained
 
 EXT2 FILE SYSTEM
-P:	Remy Card
-M:	Remy.Card@linux.org
-L:	linux-kernel@vger.kernel.org
+L:	ext2-devel@lists.sourceforge.net
 S:	Maintained
 
 EXT3 FILE SYSTEM
-P:	Remy Card, Stephen Tweedie
-M:	sct@redhat.com, akpm@zip.com.au, adilger@turbolinux.com
+P:	Stephen Tweedie, Andrew Morton
+M:	sct@redhat.com, akpm@zip.com.au, adilger@clusterfs.com
 L:	ext3-users@redhat.com
 S:	Maintained
 
@@ -703,7 +706,7 @@
 
 i386 BOOT CODE
 P:	Riley H. Williams
-M:	rhw@memalpha.cx
+M:	Riley@Williams.Name
 L:	Linux-Kernel@vger.kernel.org
 S:	Maintained
 
@@ -734,9 +737,9 @@
 S:	Maintained
 
 IBM ServeRAID RAID DRIVER
-P: 	Jack Hammer
+P:	Jack Hammer
 P:	Dave Jeffrey	
-M:	ipslinux@us.ibm.com
+M:	ipslinux@adaptec.com
 W:	http://www.developer.ibm.com/welcome/netfinity/serveraid.html
 S:	Supported 
 
@@ -834,7 +837,7 @@
 IOC3 DRIVER
 P:	Ralf Baechle
 M:	ralf@oss.sgi.com
-L:	linux-mips@oss.sgi.com
+L:	linux-mips@linux-mips.org
 S:	Maintained
 
 IP MASQUERADING:
@@ -1047,7 +1050,7 @@
 P:	Ralf Baechle
 M:	ralf@gnu.org
 W:	http://oss.sgi.com/mips/mips-howto.html
-L:	linux-mips@oss.sgi.com
+L:	linux-mips@linux-mips.org
 S:	Maintained
 
 MISCELLANEOUS MCA-SUPPORT
@@ -1079,8 +1082,8 @@
 
 NATSEMI ETHERNET DRIVER (DP8381x)
 P: 	Tim Hockin
-M:  thockin@hockin.org
-S:  Maintained
+M:	thockin@hockin.org
+S:	Maintained
 
 NCP FILESYSTEM
 P:	Petr Vandrovec
@@ -1328,10 +1331,10 @@
 S:	Maintained
 
 RADEON FRAMEBUFFER DISPLAY DRIVER
-P:  Ani Joshi
-M:  ajoshi@shell.unixbox.com
-L:  linux-fbdev-devel@lists.sourceforge.net
-S:  Maintained
+P:	Ani Joshi
+M:	ajoshi@shell.unixbox.com
+L:	linux-fbdev-devel@lists.sourceforge.net
+S:	Maintained
 
 RAGE128 FRAMEBUFFER DISPLAY DRIVER
 P:	Ani Joshi
diff -Nru a/Makefile b/Makefile
--- a/Makefile	Tue Oct  1 00:08:15 2002
+++ b/Makefile	Tue Oct  1 00:08:15 2002
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 5
-SUBLEVEL = 39
+SUBLEVEL = 40
 EXTRAVERSION =
 
 # *DOCUMENTATION*
@@ -706,7 +706,7 @@
 	include/asm \
 	.hdepend $(TOPDIR)/include/linux/modversions.h \
 	tags TAGS kernel.spec \
-	.tmpversion
+	.tmp*
 
 # 	directories removed with 'make mrproper'
 MRPROPER_DIRS += \
@@ -732,8 +732,8 @@
 	@find . $(RCS_FIND_IGNORE) \
 		\( -name .depend -o -name .\*.cmd \) \
 		-type f -print | xargs rm -f
-	@rm -f $(MRPROPER_FILES)
 	@rm -rf $(MRPROPER_DIRS)
+	@rm -f $(MRPROPER_FILES)
 	@$(MAKE) -C scripts mrproper
 	@$(MAKE) -f Documentation/DocBook/Makefile mrproper
 
@@ -756,7 +756,7 @@
 	  find arch/$(ARCH) $(RCS_FIND_IGNORE) \
 	       -name '*.[chS]' -print; \
 	  find include $(RCS_FIND_IGNORE) \
-	       \( -name config -o -name 'asm-*' \) -prune -o \
+	       \( -name config -o -name 'asm-*' \) -prune \
 	       -o -name '*.[chS]' -print; \
 	  find include/asm-$(ARCH) $(RCS_FIND_IGNORE) \
 	       -name '*.[chS]' -print; \
diff -Nru a/Rules.make b/Rules.make
--- a/Rules.make	Tue Oct  1 00:08:16 2002
+++ b/Rules.make	Tue Oct  1 00:08:16 2002
@@ -517,6 +517,13 @@
   include $(cmd_files)
 endif
 
+# Emacs compile mode works best with relative paths to find files (OK
+# if verbose, as it tracks the make[1] entries and exits, etc.)
+
+ifneq ($(KBUILD_VERBOSE),1)
+  filter-output = 2>&1 | sed 's \(^[^/][A-Za-z0-9_./-]*:[ 0-9]\) $(RELDIR)/\1 '
+endif
+
 # function to only execute the passed command if necessary
 
 if_changed = $(if $(strip $? \
@@ -536,7 +543,7 @@
 			  $(filter-out $(cmd_$@),$(cmd_$(1)))),\
 	@set -e; \
 	$(if $($(quiet)cmd_$(1)),echo '  $($(quiet)cmd_$(1))';) \
-	$(cmd_$(1)); \
+	$(cmd_$(1)) $(filter-output); \
 	$(TOPDIR)/scripts/fixdep $(depfile) $@ $(TOPDIR) '$(cmd_$(1))' > $(@D)/.$(@F).tmp; \
 	rm -f $(depfile); \
 	mv -f $(@D)/.$(@F).tmp $(@D)/.$(@F).cmd)
diff -Nru a/arch/arm/Config.help b/arch/arm/Config.help
--- a/arch/arm/Config.help	Tue Oct  1 00:08:17 2002
+++ b/arch/arm/Config.help	Tue Oct  1 00:08:17 2002
@@ -453,24 +453,6 @@
   keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
   unless you really know what this hack does.
 
-CONFIG_ARCH_ARCA5K
-  This selects what ARM system you wish to build the kernel for. It
-  also selects to some extent the CPU type. If you are unsure what
-  to set this option to, please consult any information supplied with
-  your system.
-
-CONFIG_ARCH_A5K
-  Say Y here to to support the Acorn A5000.  Linux can support the
-  internal IDE disk and CD-ROM interface, serial and parallel port,
-  and the floppy drive.  Note that on some A5000s the floppy is
-  plugged into the wrong socket on the motherboard.
-
-CONFIG_ARCH_ARC
-  The Acorn Archimedes was an personal computer based on an 8K ARM2
-  processor, released in 1987.  It supported 512K of RAM and 2 800K
-  floppy disks.  Picture and more detailed specifications at
-  <http://www.computingmuseum.com/museum/archi.htm>.
-
 CONFIG_ARCH_EBSA110
   This is an evaluation board for the StrongARM processor available
   from Digital. It has limited hardware on-board, including an onboard
@@ -481,32 +463,6 @@
   On the Acorn Risc-PC, Linux can support the internal IDE disk and
   CD-ROM interface, serial and parallel port, and the floppy drive.
 
-CONFIG_PAGESIZE_16
-  Say Y here if your Archimedes or A5000 system has only 2MB of
-  memory, otherwise say N.  The resulting kernel will not run on a
-  machine with 4MB of memory.
-
-CONFIG_ARCH_CATS
-  Say Y here if you intend to run this kernel on the CATS.
-
-  Saying N will reduce the size of the Footbridge kernel.
-
-CONFIG_ARCH_EBSA285_ADDIN
-  Say Y here if you intend to run this kernel on the EBSA285 card
-  in addin mode.
-
-  Saying N will reduce the size of the Footbridge kernel.
-
-CONFIG_ARCH_EBSA285_HOST
-  Say Y here if you intend to run this kernel on the EBSA285 card
-  in host ("central function") mode.
-
-  Saying N will reduce the size of the Footbridge kernel.
-
-CONFIG_ARCH_IQ80310
-  Say Y here if you want to run your kernel on the Intel IQ80310
-  evaluation kit for the IOP310 chipset.
-
 CONFIG_ARCH_L7200
   Say Y here if you intend to run this kernel on a LinkUp Systems
   L7200 Software Development Board which uses an ARM720T processor.
@@ -517,128 +473,6 @@
   If you have any questions or comments about the Linux kernel port
   to this board, send e-mail to sjhill@cotw.com.
 
-CONFIG_ARCH_NETWINDER
-  Say Y here if you intend to run this kernel on the Rebel.COM
-  NetWinder.  Information about this machine can be found at:
-
-  <http://www.netwinder.org/>
-
-  Saying N will reduce the size of the Footbridge kernel.
-
-CONFIG_ARCH_P720T
-  Say Y here if you intend to run this kernel on the ARM Prospector
-  720T.
-
-CONFIG_ARCH_PERSONAL_SERVER
-  Say Y here if you intend to run this kernel on the Compaq
-  Personal Server.
-
-  Saying N will reduce the size of the Footbridge kernel.
-
-  The Compaq Personal Server is not available for purchase.
-  There are no product plans beyond the current research
-  prototypes at this time.  Information is available at:
-
-  <http://crl.research.compaq.com/projects/personalserver/>
-
-  If you have any questions or comments about the  Compaq Personal
-  Server, send e-mail to skiff@crl.dec.com.
-
-CONFIG_PLD_HOTSWAP
-  This enables support for the dynamic loading and configuration of
-  compatible drivers when the contents of the PLD are changed. This
-  is still experimental and requires configuration tools which are
-  not yet generally available. Say N here. You must enable the kernel
-  module loader for this feature to work.
-
-CONFIG_SA1100_ASSABET
-  Say Y here if you are using the Intel(R) StrongARM(R) SA-1110
-  Microprocessor Development Board (also known as the Assabet).
-
-CONFIG_ASSABET_NEPONSET
-  Say Y here if you are using the Intel(R) StrongARM(R) SA-1110
-  Microprocessor Development Board (Assabet)  with the SA-1111
-  Development Board (Nepon).
-
-CONFIG_SA1100_BADGE4
-  Say Y here if you want to build a kernel for the HP Laboratories
-  BadgePAD 4.
-
-CONFIG_SA1100_BRUTUS
-  Say Y here if you are using the Intel(R) StrongARM(R) SA-1100
-  Microprocessor Development Board (also known as the Brutus).
-
-CONFIG_SA1100_CERF
-  The Intrinsyc CerfBoard is based on the StrongARM 1110.
-  More information is available at:
-  <http://www.intrinsyc.com/products/referenceplatforms/cerfboard.html>.
-
-  Say Y if configuring for an Intrinsyc CerfBoard.
-  Say N otherwise.
-
-CONFIG_SA1100_FLEXANET
-  Say Y here if you intend to run this kernel on the FlexaNet
-  handheld instruments. Information about this machine can be
-  found at: <http://www.flexanet.com/>.
-
-CONFIG_SA1100_GRAPHICSCLIENT
-  Say Y here if you are using an Applied Data Systems Intel(R)
-  StrongARM(R) SA-1100 based Graphics Client SBC.  See
-  <http://www.flatpanels.com/> for information on this system.
-
-CONFIG_SA1100_H3600
-  Say Y here if you intend to run this kernel on the Compaq iPAQ
-  H3600 handheld computer.  Information about this machine and the
-  Linux port to this machine can be found at:
-
-  <http://www.handhelds.org/Compaq/index.html#iPAQ_H3600>
-  <http://www.compaq.com/products/handhelds/pocketpc/>
-
-CONFIG_SA1100_LART
-  Say Y here if you are using the Linux Advanced Radio Terminal
-  (also known as the LART).  See <http://www.lart.tudelft.nl/> for
-  information on the LART.
-
-CONFIG_SA1100_NANOENGINE
-  The nanoEngine is a StrongARM 1110-based single board computer
-  from Bright Star Engineering. More information is available at:
-  <http://www.brightstareng.com/arm/nanoeng.htm>.
-
-  Say Y if configuring for a nanoEngine.
-  Say N otherwise.
-
-CONFIG_SA1100_PANGOLIN
-  Pangolin is a StrongARM 1110-based evaluation platform produced
-  by Dialogue Technology.  It has EISA slots for ease of configuration
-  with SDRAM/Flash memory card, USB/Serial/Audio card, Compact Flash
-  card, and TFT-LCD card.
-
-  Say Y if configuring for a Pangolin.
-  Say N otherwise.
-
-CONFIG_SA1100_PFS168
-  The Radisys Corp. PFS-168 (aka Tulsa) is an IntelŪ StrongArmŪ SA-1110 based
-  computer which includes the SA-1111 Microprocessor Companion Chip and other
-  custom I/O designed to add connectivity and multimedia features for vending
-  and business machine applications. Say Y here if you require support for
-  this target.
-
-CONFIG_SA1100_SHANNON
-  The Shannon (also known as a Tuxscreen, and also as a IS2630) was a
-  limited edition webphone produced by Philips. The Shannon is a SA1100
-  platform with a 640x480 LCD, touchscreen, CIR keyboard, PCMCIA slots,
-  and a telco interface.
-
-CONFIG_SA1100_STORK
-  Say Y here if you intend to run this kernel on the Stork
-  handheld computer.
-
-CONFIG_SA1100_VICTOR
-  Say Y here if you are using a Visu Aide Intel(R) StrongARM(R)
-  SA-1100 based Victor Digital Talking Book Reader.  See
-  <http://www.visuaide.com/pagevictor.en.html> for information on
-  this system.
-
 CONFIG_CPU_ARM610
   The ARM610 is the successor to the ARM3 processor
   and was produced by VLSI Technology Inc.
@@ -858,89 +692,6 @@
   written) to implement the policy. If you don't understand what this
   is all about, it's safe to say 'N'.
 
-CONFIG_ARCH_EDB7211
-  Say Y here if you intend to run this kernel on a Cirrus Logic EDB-7211
-  evaluation board.
-
-CONFIG_SA1100_H3100
-  Say Y here if you intend to run this kernel on the Compaq iPAQ
-  H3100 handheld computer.  Information about this machine and the
-  Linux port to this machine can be found at:
-
-  <http://www.handhelds.org/Compaq/index.html#iPAQ_H3100>
-  <http://www.compaq.com/products/handhelds/pocketpc/>
-
-CONFIG_SA1100_H3800
-  Say Y here if you intend to run this kernel on the Compaq iPAQ H3800
-  series handheld computer.  Information about this machine and the
-  Linux port to this machine can be found at:
-
-  <http://www.handhelds.org/Compaq/index.html#iPAQ_H3800>
-  <http://www.compaq.com/products/handhelds/pocketpc/>
-
-CONFIG_H3600_SLEEVE
-  Choose this option to enable support for extension packs (sleeves)
-  for the Compaq iPAQ H3XXX series of handheld computers.  This option
-  is required for the CF, PCMCIA, Bluetooth and GSM/GPRS extension
-  packs.
-
-CONFIG_SA1100_GRAPHICSMASTER
-  Say Y here if you are using an Applied Data Systems Intel(R)
-  StrongARM(R) SA-1100 based Graphics Master SBC with SA-1111
-  StrongARM companion chip.  See
-  <http://www.applieddata.net/products_masterSpec.asp> for information
-  on this system.
-
-CONFIG_SA1100_ADSBITSY
-  Say Y here if you are using Applied Data Systems Intel(R)
-  StrongARM(R) 1110 based Bitsy, 3 x 5 inches in size, Compaq - IPAQ -
-  like platform. See
-  <http://www.applieddata.net/products_bitsySpec.asp> for more
-  information.
-
-CONFIG_SA1100_ITSY
-  Say Y here if you are using the Compaq Itsy experimental pocket
-  computer. See <http://research.compaq.com/wrl/projects/itsy/> for
-  more information.
-
-CONFIG_SA1100_HUW_WEBPANEL
-  Say Y here to support the HuW Webpanel produced by Hoeft & Wessel
-  AG.  English-language website is at
-  <http://www.hoeft-wessel.de/en.htm>; credits and build instructions
-  at Documentation/arm/SA1100/HUW_WEBPANEL.
-
-CONFIG_SA1100_PLEB
-  Say Y here if you are using a Portable Linux Embedded Board
-  (also known as PLEB). See <http://www.cse.unsw.edu.au/~pleb/>
-  for more information.
-
-CONFIG_SA1100_SHERMAN
-  Say Y here to support the Blazie Engineering `Sherman' StrongARM
-  1110-based SBC, used primarily in assistance products for the
-  visually impaired.  The company is now Freedom Scientific, with
-  a website at <http://www.freedomscientific.com/index.html>. The
-  Sherman product, however, appears to have been discontinued.
-
-CONFIG_SA1100_YOPY
-  Say Y here to support the Yopy PDA.  Product information at
-  <http://www.yopy.com/>.  See Documentation/arm/SA110/Yopy
-  for more.
-
-CONFIG_SA1100_CERF_CPLD
-  Say Y here to support the Linux CerfPDA development kit from
-  Intrinsyc. This is a StrongARM-1110-based reference platform for
-  designing custom PDAs.  Product info is at
-  <http://www.intrinsyc.com/products/referencedesigns/cerfpda.asp>.
-
-CONFIG_SA1100_FREEBIRD
-  Support the FreeBird board used in Coventive embedded products.  See
-  Documentation/arm/SA1100/Freebird for more.
-
-CONFIG_SA1100_PT_SYSTEM3
-   Say Y here if you intend to build a kernel suitable to run on
-   a Pruftechnik Digital Board. For more information see
-   <http://www.pruftechnik.com>
-
 CONFIG_CPU_ARM926T
   This is a variant of the ARM920.  It has slightly different
   instruction sequences for cache and TLB operations.  Curiously,
@@ -949,40 +700,3 @@
   Say Y if you want support for the ARM926T processor.
   Otherwise, say N.
 
-CONFIG_SA1100_JORNADA720
-  Say Y here if you want to build a kernel for the HP Jornada 720
-  handheld computer.  See <http://www.hp.com/jornada/products/720>
-  for details.
-
-CONFIG_SA1100_OMNIMETER
-  Say Y here if you are using the inhand electronics OmniMeter.  See
-  <http://www.inhandelectronics.com/html/omni1.html> for details.
-
-CONFIG_SA1100_SIMPAD
-  The SIEMENS webpad SIMpad is based on the StrongARM 1110. There
-  are two different versions CL4 and SL4. CL4 has 32MB RAM and 16MB
-  FLASH. The SL4 version got 64 MB RAM and 32 MB FLASH and a
-  PCMCIA-Slot. The version for the Germany Telecom (DTAG) is the same
-  like CL4 in additional it has a PCMCIA-Slot. For more information
-  visit <http://www.my-siemens.com or www.siemens.ch>.
-
-CONFIG_ARCH_CDB89712
-  This is an evaluation board from Cirrus for the CS89712 processor.
-  The board includes 2 serial ports, Ethernet, IRDA, and expansion
-  headers.  It comes with 16 MB SDRAM and 8 MB flash ROM.
-
-CONFIG_ARCH_AUTCPU12
-  Say Y if you intend to run the kernel on the autronix autcpu12
-  board. This board is based on a Cirrus Logic CS89712.
-
-CONFIG_EP72XX_ROM_BOOT
-  If you say Y here, your CLPS711x-based kernel will use the bootstrap
-  mode memory map instead of the normal memory map.
-
-  Processors derived from the Cirrus CLPS-711X core support two boot
-  modes.  Normal mode boots from the external memory device at CS0.
-  Bootstrap mode rearranges parts of the memory map, placing an
-  internal 128 byte bootstrap ROM at CS0.  This option performs the
-  address map changes required to support booting in this mode.
-
-  You almost surely want to say N here.
diff -Nru a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile
--- a/arch/arm/boot/Makefile	Tue Oct  1 00:08:15 2002
+++ b/arch/arm/boot/Makefile	Tue Oct  1 00:08:15 2002
@@ -10,6 +10,11 @@
 
 SYSTEM	=$(TOPDIR)/vmlinux
 
+# Note: the following conditions must always be true:
+#   ZRELADDR == virt_to_phys(TEXTADDR)
+#   PARAMS_PHYS must be with 4MB of ZRELADDR
+#   INITRD_PHYS must be in RAM
+
 ifeq ($(CONFIG_CPU_26),y)
 ZRELADDR	 = 0x02080000
 PARAMS_PHYS	 = 0x0207c000
@@ -129,14 +134,14 @@
 bootpImage: bootp/bootp
 	$(OBJCOPY) $(OBJCOPYFLAGS) $< $@
 
-compressed/vmlinux: $(TOPDIR)/vmlinux
+compressed/vmlinux: $(TOPDIR)/vmlinux FORCE
 	@$(MAKE) -C compressed vmlinux
 
-bootp/bootp: zImage initrd
+bootp/bootp: zImage initrd FORCE
 	@$(MAKE) -C bootp bootp
 
 initrd:
-	@test "$(INITRD_PHYS)" != "" || (echo This architecture does not support INITRD; exit -1)
+	@test "$(INITRD_PHYS)" != "" || (echo This machine does not support INITRD; exit -1)
 	@test "$(INITRD)" != "" || (echo You must specify INITRD; exit -1)
 
 install: Image
@@ -149,3 +154,5 @@
 	$(RM) Image zImage bootpImage
 	@$(MAKE) -C compressed clean
 	@$(MAKE) -C bootp clean
+
+FORCE:
diff -Nru a/arch/arm/boot/bootp/Makefile b/arch/arm/boot/bootp/Makefile
--- a/arch/arm/boot/bootp/Makefile	Tue Oct  1 00:08:19 2002
+++ b/arch/arm/boot/bootp/Makefile	Tue Oct  1 00:08:19 2002
@@ -5,8 +5,7 @@
 ZSYSTEM		=$(TOPDIR)/arch/arm/boot/zImage
 ZLDFLAGS	=-p -X -T bootp.lds \
 		 --defsym initrd_addr=$(INITRD_PHYS) \
-		 --defsym params=$(PARAMS_PHYS) \
-		 --defsym kernel_addr=$(ZTEXTADDR)
+		 --defsym params=$(PARAMS_PHYS)
 
 all:		bootp
 
diff -Nru a/arch/arm/boot/bootp/bootp.lds b/arch/arm/boot/bootp/bootp.lds
--- a/arch/arm/boot/bootp/bootp.lds	Tue Oct  1 00:08:15 2002
+++ b/arch/arm/boot/bootp/bootp.lds	Tue Oct  1 00:08:15 2002
@@ -1,7 +1,7 @@
 /*
  *  linux/arch/arm/boot/bootp/bootp.lds
  *
- *  Copyright (C) 2000 Russell King
+ *  Copyright (C) 2000-2002 Russell King
  *
  * 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
@@ -15,13 +15,9 @@
   _text = .;
   .text : {
    _stext = .;
-   _start = .;
-   init.o(.start)
-   kernel_start = .;
+   *(.start)
    kernel.o
-   kernel_len = . - kernel_start;
    . = ALIGN(32);
-   *(.text)
    initrd_start = .;
    initrd.o
    initrd_len = . - initrd_start;
diff -Nru a/arch/arm/boot/bootp/init.S b/arch/arm/boot/bootp/init.S
--- a/arch/arm/boot/bootp/init.S	Tue Oct  1 00:08:18 2002
+++ b/arch/arm/boot/bootp/init.S	Tue Oct  1 00:08:18 2002
@@ -1,7 +1,7 @@
 /*
  *  linux/arch/arm/boot/bootp/init.S
  *
- *  Copyright (C) 2000 Russell King
+ *  Copyright (C) 2000-2002 Russell King
  *
  * 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
@@ -11,8 +11,9 @@
  *  r0 through to r3 straight through.
  */
 		.section .start,#alloc,#execinstr
-		.type	_entry, #function
-_entry:		adr	r10, initdata
+		.type	_start, #function
+		.globl	_start
+_start:		adr	r10, initdata
 		ldr	r11, initdata
 		sub	r11, r10, r11		@ work out exec offset
 		b	splitify
@@ -22,17 +23,11 @@
 initdata:	.word	initdata		@ compiled address of this
 		.size	initdata,. - initdata
 
-		.text
 splitify:	adr	r13, data
 		ldmia	r13!, {r4-r6}		@ move the initrd
 		add	r4, r4, r11		@ correction
 		bl	move
 
-		ldmia	r13!, {r4-r6}		@ then the kernel
-		mov	r12, r5
-		add	r4, r4, r11		@ correction
-		bl	move
-
 /*
  * Setup the initrd parameters to pass to the kernel.  This can either be
  * passed in via a param_struct or a tag list.  We spot the param_struct
@@ -76,6 +71,7 @@
 		mov	r4, #16			@ length of initrd tag
 		mov	r9, #0			@ end of tag list terminator
 		stmia	r8, {r4, r5, r6, r7, r9}
+		adr	r12, kernel_start
 		mov	pc, r12			@ call kernel
 
 /*
@@ -97,15 +93,12 @@
 		.word	initrd_addr
 		.word	initrd_len
 
-		.word	kernel_start
-		.word	kernel_addr
-		.word	kernel_len
-
 		.word	0x54410001		@ r4 = ATAG_CORE
 		.word	0x54420005		@ r5 = ATAG_INITRD
 		.word	initrd_addr		@ r6
 		.word	initrd_len		@ r7
 		.word	params			@ r8
 
-		.type	kernel_start,#object
 		.type	initrd_start,#object
+
+kernel_start:
diff -Nru a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
--- a/arch/arm/boot/compressed/head.S	Tue Oct  1 00:08:20 2002
+++ b/arch/arm/boot/compressed/head.S	Tue Oct  1 00:08:20 2002
@@ -19,6 +19,13 @@
  */
 #ifdef DEBUG
 #if defined(CONFIG_DEBUG_DC21285_PORT)
+		.macro	loadsp, rb
+		mov	\rb, #0x42000000
+		.endm
+		.macro	writeb, rb
+		str	\rb, [r3, #0x160]
+		.endm
+#elif defined(CONFIG_FOOTBRIDGE)
 		.macro	loadsp,	rb
 		mov	\rb, #0x7c000000
 		.endm
@@ -36,6 +43,14 @@
 #elif defined(CONFIG_ARCH_INTEGRATOR)
 		.macro	loadsp, rb
 		mov	\rb, #0x16000000
+		.endm
+		.macro	writeb, rb
+		strb	\rb, [r3, #0]
+		.endm
+#elif defined(CONFIG_ARCH_PXA) /* Xscale-type */
+		.macro 	loadsp, rb
+		mov	\rb, #0x40000000
+		orr	\rb, \rb, #0x00100000
 		.endm
 		.macro	writeb, rb
 		strb	\rb, [r3, #0]
diff -Nru a/arch/arm/config.in b/arch/arm/config.in
--- a/arch/arm/config.in	Tue Oct  1 00:08:15 2002
+++ b/arch/arm/config.in	Tue Oct  1 00:08:15 2002
@@ -37,142 +37,13 @@
  	 SA1100-based		CONFIG_ARCH_SA1100 \
 	 Shark			CONFIG_ARCH_SHARK" RiscPC
 
-mainmenu_option next_comment
-comment 'Archimedes/A5000 Implementations'
-# These architectures will be combined.  However, until this
-# is complete...  Note that the ARC will take precedence over
-# A5K
-comment 'Archimedes/A5000 Implementations (select only ONE)'
-dep_bool '  Archimedes' CONFIG_ARCH_ARC $CONFIG_ARCH_ARCA5K
-dep_bool '  A5000' CONFIG_ARCH_A5K $CONFIG_ARCH_ARCA5K
-endmenu
-
-mainmenu_option next_comment
-comment 'Footbridge Implementations'
-dep_bool '  CATS' CONFIG_ARCH_CATS $CONFIG_ARCH_FOOTBRIDGE
-dep_bool '  Compaq Personal Server' CONFIG_ARCH_PERSONAL_SERVER $CONFIG_ARCH_FOOTBRIDGE
-dep_bool '  EBSA285 (addin mode)' CONFIG_ARCH_EBSA285_ADDIN $CONFIG_ARCH_FOOTBRIDGE
-dep_bool '  EBSA285 (host mode)' CONFIG_ARCH_EBSA285_HOST $CONFIG_ARCH_FOOTBRIDGE
-dep_bool '  NetWinder' CONFIG_ARCH_NETWINDER $CONFIG_ARCH_FOOTBRIDGE
-endmenu
-
-mainmenu_option next_comment
-comment 'SA11x0 Implementations'
-dep_bool '  Assabet' CONFIG_SA1100_ASSABET $CONFIG_ARCH_SA1100
-dep_bool '    Include support for Neponset' CONFIG_ASSABET_NEPONSET $CONFIG_SA1100_ASSABET
-dep_bool '  ADS Bitsy' CONFIG_SA1100_ADSBITSY $CONFIG_ARCH_SA1100
-dep_bool '  Brutus' CONFIG_SA1100_BRUTUS $CONFIG_ARCH_SA1100
-dep_bool '  CerfBoard' CONFIG_SA1100_CERF $CONFIG_ARCH_SA1100
-if [ "$CONFIG_SA1100_CERF" = "y" ]; then
-   choice 'Cerf Flash available'  \
-        "8MB    CONFIG_SA1100_CERF_FLASH_8MB \
-         16MB   CONFIG_SA1100_CERF_FLASH_16MB \
-         32MB   CONFIG_SA1100_CERF_FLASH_32MB" 8MB
-   bool 'Cerf w/CPLD support (CerfPDA)' CONFIG_SA1100_CERF_CPLD
-fi
-dep_bool '  Compaq iPAQ H3100' CONFIG_SA1100_H3100 $CONFIG_ARCH_SA1100
-dep_bool '  Compaq iPAQ H3600/H3700' CONFIG_SA1100_H3600 $CONFIG_ARCH_SA1100
-dep_bool '  Compaq iPAQ H3800' CONFIG_SA1100_H3800 $CONFIG_ARCH_SA1100
-if [ "$CONFIG_SA1100_H3100" = "y" -o "$CONFIG_SA1100_H3600" = "y" -o "$CONFIG_SA1100_H3800" = "y" ]; then
-  define_bool CONFIG_SA1100_H3XXX y
-else
-  define_bool CONFIG_SA1100_H3XXX n
-fi
-#dep_bool '  Empeg' CONFIG_SA1100_EMPEG $CONFIG_ARCH_SA1100
-dep_bool '  Extenex HandHeld Theater (Squashtail)' CONFIG_SA1100_EXTENEX1 $CONFIG_ARCH_SA1100
-if [ "$CONFIG_SA1100_EXTENEX1" = "y" ]; then
-   bool '    Support 16 MB of DRAM (not just 8)' CONFIG_SA1100_EXTENEX1_16MB
-fi
-dep_bool '  FlexaNet' CONFIG_SA1100_FLEXANET $CONFIG_ARCH_SA1100
-dep_bool '  FreeBird-v1.1' CONFIG_SA1100_FREEBIRD $CONFIG_ARCH_SA1100
-dep_bool '  GraphicsClient Plus' CONFIG_SA1100_GRAPHICSCLIENT $CONFIG_ARCH_SA1100
-dep_bool '  GraphicsMaster' CONFIG_SA1100_GRAPHICSMASTER $CONFIG_ARCH_SA1100
-dep_bool '  HP Labs BadgePAD 4' CONFIG_SA1100_BADGE4 $CONFIG_ARCH_SA1100
-dep_bool '  HP Jornada 720' CONFIG_SA1100_JORNADA720 $CONFIG_ARCH_SA1100
-dep_bool '  HuW WebPanel' CONFIG_SA1100_HUW_WEBPANEL $CONFIG_ARCH_SA1100
-dep_bool '  Itsy' CONFIG_SA1100_ITSY $CONFIG_ARCH_SA1100
-dep_bool '  LART' CONFIG_SA1100_LART $CONFIG_ARCH_SA1100
-dep_bool '  nanoEngine' CONFIG_SA1100_NANOENGINE $CONFIG_ARCH_SA1100
-dep_bool '  OmniMeter' CONFIG_SA1100_OMNIMETER $CONFIG_ARCH_SA1100
-dep_bool '  Pangolin' CONFIG_SA1100_PANGOLIN $CONFIG_ARCH_SA1100
-dep_bool '  PLEB' CONFIG_SA1100_PLEB $CONFIG_ARCH_SA1100
-dep_bool '  PT System 3' CONFIG_SA1100_PT_SYSTEM3 $CONFIG_ARCH_SA1100
-dep_bool '  Shannon' CONFIG_SA1100_SHANNON $CONFIG_ARCH_SA1100
-dep_bool '  Sherman' CONFIG_SA1100_SHERMAN $CONFIG_ARCH_SA1100
-dep_bool '  Simpad' CONFIG_SA1100_SIMPAD $CONFIG_ARCH_SA1100
-dep_bool '  Tulsa' CONFIG_SA1100_PFS168 $CONFIG_ARCH_SA1100
-dep_bool '  Victor' CONFIG_SA1100_VICTOR $CONFIG_ARCH_SA1100
-dep_bool '  XP860' CONFIG_SA1100_XP860 $CONFIG_ARCH_SA1100
-dep_bool '  Yopy' CONFIG_SA1100_YOPY $CONFIG_ARCH_SA1100
-dep_bool '  Stork' CONFIG_SA1100_STORK $CONFIG_ARCH_SA1100
-
-# Determine if SA1111 support is required
-if [ "$CONFIG_ASSABET_NEPONSET" = "y" -o \
-     "$CONFIG_SA1100_JORNADA720" = "y" -o \
-     "$CONFIG_SA1100_PFS168" = "y" -o \
-     "$CONFIG_SA1100_XP860" = "y" -o \
-     "$CONFIG_SA1100_GRAPHICSMASTER" = "y" -o \
-     "$CONFIG_SA1100_PT_SYSTEM3" = "y" -o \
-     "$CONFIG_SA1100_ADSBITSY" = "y" -o \
-     "$CONFIG_SA1100_BADGE4" = "y" ]; then
-   define_bool CONFIG_SA1111 y
-   define_int CONFIG_FORCE_MAX_ZONEORDER 9
-fi
-
-dep_tristate 'SA1100 USB function support' CONFIG_SA1100_USB $CONFIG_ARCH_SA1100
-dep_tristate '  Support for SA11x0 USB network link function' CONFIG_SA1100_USB_NETLINK $CONFIG_SA1100_USB
-dep_tristate '  Support for SA11x0 USB character device emulation' CONFIG_SA1100_USB_CHAR $CONFIG_SA1100_USB
-
-dep_tristate 'Compaq iPAQ Handheld sleeve support' CONFIG_H3600_SLEEVE $CONFIG_SA1100_H3600
-endmenu
-
-mainmenu_option next_comment
-comment 'Intel PXA250/210 Implementations'
-dep_bool '  Intel DBPXA250 Development Platform' CONFIG_ARCH_LUBBOCK $CONFIG_ARCH_PXA
-dep_bool '  Accelent Xscale IDP' CONFIG_ARCH_PXA_IDP $CONFIG_ARCH_PXA
-
-if [ "$CONFIG_ARCH_LUBBOCK" = "y" ]; then
-   define_bool CONFIG_SA1111 y
-fi
-endmenu
-
-mainmenu_option next_comment
-comment 'CLPS711X/EP721X Implementations'
-dep_bool '  AUTCPU12' CONFIG_ARCH_AUTCPU12 $CONFIG_ARCH_CLPS711X
-dep_bool '  CDB89712' CONFIG_ARCH_CDB89712 $CONFIG_ARCH_CLPS711X
-dep_bool '  CLEP7312' CONFIG_ARCH_CLEP7312 $CONFIG_ARCH_CLPS711X
-dep_bool '  EDB7211' CONFIG_ARCH_EDB7211 $CONFIG_ARCH_CLPS711X
-dep_bool '  P720T' CONFIG_ARCH_P720T $CONFIG_ARCH_CLPS711X
-dep_bool '  FORTUNET' CONFIG_ARCH_FORTUNET $CONFIG_ARCH_CLPS711X
-
-# XXX Maybe these should indicate register compatibility
-# instead of being mutually exclusive.
-if [ "$CONFIG_ARCH_EDB7211" = "y" ]; then
-   define_bool CONFIG_ARCH_EP7211 y
-else
-   define_bool CONFIG_ARCH_EP7211 n
-fi
-if [ "$CONFIG_ARCH_P720T" = "y" ]; then
-   define_bool CONFIG_ARCH_EP7212 y
-else
-   define_bool CONFIG_ARCH_EP7212 n
-fi
-
-if [ "$CONFIG_ARCH_EP7211" = "y" -o \
-     "$CONFIG_ARCH_EP7212" = "y" ]; then
-   bool '  EP72xx ROM boot' CONFIG_EP72XX_ROM_BOOT
-fi
-endmenu
-
-mainmenu_option next_comment
-comment 'IOP310 Implementation Options'
-dep_bool '  IQ80310' CONFIG_ARCH_IQ80310 $CONFIG_ARCH_IOP310
-comment 'IOP310 Chipset Features'
-dep_bool 'Support Intel 80312 Application Accelerator Unit (EXPERIMENTAL)' CONFIG_IOP310_AAU $CONFIG_ARCH_IOP310 $CONFIG_EXPERIMENTAL
-dep_bool 'Support Intel 80312 DMA (EXPERIMENTAL)' CONFIG_IOP310_DMA $CONFIG_ARCH_IOP310 $CONFIG_EXPERIMENTAL
-dep_bool 'Support Intel 80312 Messaging Unit (EXPERIMENTAL)' CONFIG_IOP310_MU $CONFIG_ARCH_IOP310 $CONFIG_EXPERIMENTAL
-dep_bool 'Support Intel 80312 Performance Monitor (EXPERIMENTAL)' CONFIG_IOP310_PMON $CONFIG_ARCH_IOP310 $CONFIG_EXPERIMENTAL
-endmenu
+source arch/arm/mach-arc/Config.in
+source arch/arm/mach-clps711x/Config.in
+source arch/arm/mach-epxa10db/Config.in
+source arch/arm/mach-footbridge/Config.in
+source arch/arm/mach-iop310/Config.in
+source arch/arm/mach-pxa/Config.in
+source arch/arm/mach-sa1100/Config.in
 
 # Definitions to make life easier
 if [ "$CONFIG_ARCH_ARCA5K" = "y" -o \
@@ -182,7 +53,8 @@
    define_bool CONFIG_ARCH_ACORN n
 fi
 
-# see Documentation/arm/ConfigVars for a description of these
+#####################################################################
+# Footbridge support
 if [ "$CONFIG_ARCH_CO285" = "y" -o \
      "$CONFIG_ARCH_FOOTBRIDGE" = "y" ]; then
    define_bool CONFIG_FOOTBRIDGE y
@@ -208,44 +80,33 @@
    define_bool CONFIG_ARCH_EBSA285 y
 fi
 
+#####################################################################
+# SA1111 support
+if [ "$CONFIG_ASSABET_NEPONSET" = "y" -o \
+     "$CONFIG_SA1100_ADSBITSY" = "y" -o \
+     "$CONFIG_SA1100_BADGE4" = "y" -o \
+     "$CONFIG_SA1100_CONSUS" = "y" -o \
+     "$CONFIG_SA1100_GRAPHICSMASTER" = "y" -o \
+     "$CONFIG_SA1100_JORNADA720" = "y" -o \
+     "$CONFIG_ARCH_LUBBOCK" = "y" -o \
+     "$CONFIG_SA1100_PFS168" = "y" -o \
+     "$CONFIG_SA1100_PT_SYSTEM3" = "y" -o \
+     "$CONFIG_SA1100_XP860" = "y" ]; then
+   define_bool CONFIG_SA1111 y
+   define_int CONFIG_FORCE_MAX_ZONEORDER 9
+fi
+
+comment 'Processor Type'
+
 # Figure out whether this system uses 26-bit or 32-bit CPUs.
 if [ "$CONFIG_ARCH_ARCA5K" = "y" ]; then
    define_bool CONFIG_CPU_32 n
    define_bool CONFIG_CPU_26 y
-   bool '2MB physical memory' CONFIG_PAGESIZE_16
 else
    define_bool CONFIG_CPU_32 y
    define_bool CONFIG_CPU_26 n
 fi
 
-comment 'Processor Type'
-
-# Firstly, figure out what processor architecture version we should be using.
-# This defines the compiler instruction set which depends on the machine type.
-
-if [ "$CONFIG_ARCH_RPC"        = "y" -o "$CONFIG_ARCH_CLPS7500" = "y" ]; then
-   define_bool CONFIG_CPU_32v3 y
-else
-   define_bool CONFIG_CPU_32v3 n
-fi
-if [ "$CONFIG_ARCH_EBSA110"    = "y" -o "$CONFIG_FOOTBRIDGE"    = "y" -o \
-     "$CONFIG_ARCH_TBOX"       = "y" -o "$CONFIG_ARCH_SHARK"    = "y" -o \
-     "$CONFIG_ARCH_NEXUSPCI"   = "y" -o "$CONFIG_ARCH_CLPS711X" = "y" -o \
-     "$CONFIG_ARCH_INTEGRATOR" = "y" -o "$CONFIG_ARCH_SA1100"   = "y" -o \
-     "$CONFIG_ARCH_L7200"      = "y" -o "$CONFIG_ARCH_ANAKIN"	= "y" -o \
-     "$CONFIG_ARCH_CAMELOT"    = "y" ]; then
-   define_bool CONFIG_CPU_32v4 y
-else
-   define_bool CONFIG_CPU_32v4 n
-fi
-if [ "$CONFIG_ARCH_IOP310" = "y" -o \
-     "$CONFIG_ARCH_ADIFCC" = "y" -o \
-     "$CONFIG_ARCH_PXA" = "y" ]; then
-   define_bool CONFIG_CPU_32v5 y
-else
-   define_bool CONFIG_CPU_32v5 n
-fi
-
 # Select CPU types depending on the architecture selected.  This selects
 # which CPUs we support in the kernel image, and the compiler instruction
 # optimiser behaviour.
@@ -338,14 +199,30 @@
    define_bool CONFIG_CPU_XSCALE n
 fi
 
-#if [ "$CONFIG_CPU_XSCALE" = "y" ]; then
-#  bool 'Use XScale PMU as timer source' CONFIG_XSCALE_PMU_TIMER
-#fi
+# Figure out what processor architecture version we should be using.
+# This defines the compiler instruction set which depends on the machine type.
 
-if [ "$CONFIG_CPU_XSCALE" = "y" -a "$CONFIG_XSCALE_PMU_TIMER" != "y" ]; then
-   define_bool CONFIG_XSCALE_PMU y
+if [ "$CONFIG_ARCH_RPC"        = "y" -o "$CONFIG_ARCH_CLPS7500" = "y" ]; then
+   define_bool CONFIG_CPU_32v3 y
+else
+   define_bool CONFIG_CPU_32v3 n
+fi
+if [ "$CONFIG_ARCH_EBSA110"    = "y" -o "$CONFIG_FOOTBRIDGE"    = "y" -o \
+     "$CONFIG_ARCH_TBOX"       = "y" -o "$CONFIG_ARCH_SHARK"    = "y" -o \
+     "$CONFIG_ARCH_NEXUSPCI"   = "y" -o "$CONFIG_ARCH_CLPS711X" = "y" -o \
+     "$CONFIG_ARCH_INTEGRATOR" = "y" -o "$CONFIG_ARCH_SA1100"   = "y" -o \
+     "$CONFIG_ARCH_L7200"      = "y" -o "$CONFIG_ARCH_ANAKIN"	= "y" -o \
+     "$CONFIG_ARCH_CAMELOT"    = "y" ]; then
+   define_bool CONFIG_CPU_32v4 y
+else
+   define_bool CONFIG_CPU_32v4 n
+fi
+if [ "$CONFIG_ARCH_IOP310" = "y" -o \
+     "$CONFIG_ARCH_ADIFCC" = "y" -o \
+     "$CONFIG_ARCH_PXA" = "y" ]; then
+   define_bool CONFIG_CPU_32v5 y
 else
-   define_bool CONFIG_XSCALE_PMU n
+   define_bool CONFIG_CPU_32v5 n
 fi
 
 comment 'Processor Features'
@@ -372,6 +249,15 @@
    bool 'Disable branch prediction' CONFIG_CPU_BPREDICT_DISABLE
 fi
 
+if [ "$CONFIG_CPU_XSCALE" = "y" ]; then
+#  bool 'Use XScale PMU as timer source' CONFIG_XSCALE_PMU_TIMER
+   if [ "$CONFIG_XSCALE_PMU_TIMER" != "y" ]; then
+      define_bool CONFIG_XSCALE_PMU y
+   else
+      define_bool CONFIG_XSCALE_PMU n
+   fi
+fi
+
 endmenu
 
 mainmenu_option next_comment
@@ -449,6 +335,16 @@
 if [ "$CONFIG_ARCH_SA1100" = "y" -o \
      "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then
    dep_bool 'Support CPU clock change (EXPERIMENTAL)' CONFIG_CPU_FREQ $CONFIG_EXPERIMENTAL
+else
+   define_bool CONFIG_CPU_FREQ n
+fi
+
+if [ "$CONFIG_CPU_FREQ" = "y" ]; then
+   define_bool CONFIG_CPU_FREQ_24_API y
+   define_bool CONFIG_CPU_FREQ_26_API y
+else
+   define_bool CONFIG_CPU_FREQ_24_API n
+   define_bool CONFIG_CPU_FREQ_26_API n
 fi
 
 source drivers/pci/Config.in
@@ -494,9 +390,9 @@
 	   "$CONFIG_ARCH_SHARK" = "y" -o      \
 	   "$CONFIG_ARCH_CO285" = "y" -o      \
 	   "$CONFIG_ARCH_SA1100" = "y" -o     \
-          "$CONFIG_ARCH_LUBBOCK" = "y" -o    \
+	   "$CONFIG_ARCH_LUBBOCK" = "y" -o    \
 	   "$CONFIG_ARCH_PXA_IDP" = "y" -o    \
-           "$CONFIG_ARCH_INTEGRATOR" = "y" -o \
+	   "$CONFIG_ARCH_INTEGRATOR" = "y" -o \
 	   "$CONFIG_ARCH_P720T" = "y" ]; then
          bool '  Timer LED' CONFIG_LEDS_TIMER
          bool '  CPU usage LED' CONFIG_LEDS_CPU
@@ -601,31 +497,6 @@
 if [ "$CONFIG_VT" = "y" ]; then
    mainmenu_option next_comment
    comment 'Console drivers'
-   # Select the keyboard type for this architecture.
-   if [ "$CONFIG_FOOTBRIDGE_HOST" = "y" -o \
-        "$CONFIG_ARCH_CLPS7500" = "y" -o   \
-        "$CONFIG_ARCH_SHARK" = "y" ]; then
-      define_bool CONFIG_PC_KEYB y
-   fi
-   if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then
-      define_bool CONFIG_KMI_KEYB y
-      define_bool CONFIG_KMI_MOUSE y
-   fi
-   if [ "$CONFIG_ARCH_L7200" = "y" ]; then
-      define_bool CONFIG_L7200_KEYB y
-   fi
-
-   # Do we use the PC-type keyboard map?
-   if [ "$CONFIG_FOOTBRIDGE_HOST" = "y" -o \
-        "$CONFIG_ARCH_SHARK" = "y" -o      \
-        "$CONFIG_ARCH_SA1100" = "y" -o     \
-        "$CONFIG_ARCH_INTEGRATOR" = "y" -o \
-        "$CONFIG_ARCH_TBOX" = "y" -o       \
-        "$CONFIG_ARCH_CLPS7500" = "y" -o   \
-        "$CONFIG_ARCH_P720T" = "y" -o      \
-        "$CONFIG_ARCH_ANAKIN" = "y" ]; then
-      define_bool CONFIG_PC_KEYMAP y
-   fi
    if [ "$CONFIG_ARCH_ACORN" != "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then
       bool 'VGA text console' CONFIG_VGA_CONSOLE
    fi
diff -Nru a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
--- a/arch/arm/kernel/armksyms.c	Tue Oct  1 00:08:16 2002
+++ b/arch/arm/kernel/armksyms.c	Tue Oct  1 00:08:16 2002
@@ -73,6 +73,7 @@
 extern void ret_from_exception(void);
 extern void fpundefinstr(void);
 extern void fp_enter(void);
+extern void fp_init(union fp_state *);
 
 /*
  * This has a special calling convention; it doesn't
@@ -129,6 +130,7 @@
 EXPORT_SYMBOL(set_irq_type);
 EXPORT_SYMBOL(pm_idle);
 EXPORT_SYMBOL(pm_power_off);
+EXPORT_SYMBOL(fp_init);
 
 	/* processor dependencies */
 EXPORT_SYMBOL(__machine_arch_type);
diff -Nru a/arch/arm/kernel/compat.c b/arch/arm/kernel/compat.c
--- a/arch/arm/kernel/compat.c	Tue Oct  1 00:08:15 2002
+++ b/arch/arm/kernel/compat.c	Tue Oct  1 00:08:15 2002
@@ -95,13 +95,14 @@
 {
 	struct tag *tag = taglist;
 
-	printk(KERN_DEBUG "Converting old-style param struct to taglist\n");
-
 	if (params->u1.s.page_size != PAGE_SIZE) {
 		printk(KERN_WARNING "Warning: bad configuration page, "
 		       "trying to continue\n");
 		return;
 	}
+
+	printk(KERN_DEBUG "Converting old-style param struct to taglist\n");
+
 #ifdef CONFIG_ARCH_NETWINDER
 	if (params->u1.s.nr_pages != 0x02000 &&
 	    params->u1.s.nr_pages != 0x04000 &&
diff -Nru a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
--- a/arch/arm/kernel/entry-armv.S	Tue Oct  1 00:08:16 2002
+++ b/arch/arm/kernel/entry-armv.S	Tue Oct  1 00:08:16 2002
@@ -657,7 +657,7 @@
 
 #if defined CONFIG_FPE_NWFPE || defined CONFIG_FPE_FASTFPE
 		/* The FPE is always present */
-		.equ	fpe_not_present, 0
+		.equ	fpe_not_present, fpundefinstr
 #else
 wfs_mask_data:	.word	0x0e200110			@ WFS/RFS
 		.word	0x0fef0fff
@@ -788,15 +788,16 @@
 		.align	5
 __und_svc:	sub	sp, sp, #S_FRAME_SIZE
 		stmia	sp, {r0 - r12}			@ save r0 - r12
-		ldr	r7, .LCund
-		mov	r6, lr
-		ldmia	r7, {r7 - r9}
-		add	r5, sp, #S_FRAME_SIZE
-		add	r4, sp, #S_SP
-		stmia	r4, {r5 - r9}			@ save sp_SVC, lr_SVC, pc, cpsr, old_ro
-
-		adrsvc	al, r9, 1f			@ r9  = normal FP return
-		bl	call_fpe			@ lr  = undefined instr return
+		ldr	r3, .LCund
+		mov	r4, lr
+		ldmia	r3, {r5 - r7}
+		add	r3, sp, #S_FRAME_SIZE
+		add	r2, sp, #S_SP
+		stmia	r2, {r3 - r7}			@ save sp_SVC, lr_SVC, pc, cpsr, old_ro
+
+		ldr	r0, [r5, #-4]			@ r0 = instruction
+		adrsvc	al, r9, 1f			@ r9 = normal FP return
+		bl	call_fpe			@ lr = undefined instr return
 
 		mov	r0, sp				@ struct pt_regs *regs
 		bl	do_undefinstr
@@ -913,17 +914,58 @@
 		zero_fp
 		tst	r6, #PSR_T_BIT			@ Thumb mode?
 		bne	fpundefinstr			@ ignore FP
+		sub	r4, r5, #4
+1:		ldrt	r0, [r4]			@ r0  = instruction
 		adrsvc	al, r9, ret_from_exception	@ r9  = normal FP return
 		adrsvc	al, lr, fpundefinstr		@ lr  = undefined instr return
 
-call_fpe:	enable_irq r0				@ Enable interrupts
-		get_thread_info r10			@ get current thread
+/*
+ * The out of line fixup for the ldrt above.
+ */
+		.section .fixup, "ax"
+2:		mov	pc, r9
+		.previous
+		.section __ex_table,"a"
+		.long	1b, 2b
+		.previous
+
+/*
+ * r0 = instruction.
+ *
+ * Check whether the instruction is a co-processor instruction.
+ * If yes, we need to call the relevant co-processor handler.
+ *
+ * Note that we don't do a full check here for the co-processor
+ * instructions; all instructions with bit 27 set are well
+ * defined.  The only instructions that should fault are the
+ * co-processor instructions.  However, we have to watch out
+ * for the ARM6/ARM7 SWI bug.
+ *
+ * Emulators may wish to make use of the instruction value we
+ * prepared for them in r0.
+ */
+call_fpe:	enable_irq r10				@ Enable interrupts
+		tst	r0, #0x08000000			@ only CDP/CPRT/LDC/STC have bit 27
+#if defined(CONFIG_CPU_ARM610) || defined(CONFIG_CPU_ARM710)
+		and	r10, r0, #0x0f000000		@ mask out op-code bits
+		teqne	r10, #0x0f000000		@ SWI (ARM6/7 bug)?
+#endif
+		moveq	pc, lr
+do_fpe:		get_thread_info r10			@ get current thread
 		ldr	r4, [r10, #TI_TASK]		@ get current task
 		mov	r8, #1
 		strb	r8, [r4, #TSK_USED_MATH]	@ set current->used_math
 		ldr	r4, .LCfp
 		add	r10, r10, #TI_FPSTATE		@ r10 = workspace
 		ldr	pc, [r4]			@ Call FP module USR entry point
+/*
+ * The FP module is called with these registers set:
+ *  r0  = instruction
+ *  r5  = PC
+ *  r9  = normal "successful" return address
+ *  r10 = FP workspace
+ *  lr  = unrecognised FP instruction return address
+ */
 
 fpundefinstr:	mov	r0, sp
 		adrsvc	al, lr, ret_from_exception
diff -Nru a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
--- a/arch/arm/kernel/head.S	Tue Oct  1 00:08:14 2002
+++ b/arch/arm/kernel/head.S	Tue Oct  1 00:08:14 2002
@@ -117,8 +117,8 @@
 #ifdef CONFIG_ALIGNMENT_TRAP
 	orr	r0, r0, #2			@ ...........A.
 #endif
-	mcr	p15, 0, r0, c1, c0
-	mov	r0, r0
+	mcr	p15, 0, r0, c1, c0, 0		@ write control reg
+	mrc	p15, 0, r0, c1, c0, 0		@ read it back.
 	mov	r0, r0
 	mov	r0, r0
 	mov	pc, lr
diff -Nru a/arch/arm/kernel/init_task.c b/arch/arm/kernel/init_task.c
--- a/arch/arm/kernel/init_task.c	Tue Oct  1 00:08:20 2002
+++ b/arch/arm/kernel/init_task.c	Tue Oct  1 00:08:20 2002
@@ -12,7 +12,7 @@
 
 static struct fs_struct init_fs = INIT_FS;
 static struct files_struct init_files = INIT_FILES;
-static struct signal_struct init_signals = INIT_SIGNALS;
+static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 struct mm_struct init_mm = INIT_MM(init_mm);
 
 /*
diff -Nru a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
--- a/arch/arm/kernel/irq.c	Tue Oct  1 00:08:13 2002
+++ b/arch/arm/kernel/irq.c	Tue Oct  1 00:08:13 2002
@@ -18,12 +18,12 @@
  *  Naturally it's not a 1:1 relation, but there are similarities.
  */
 #include <linux/config.h>
-#include <linux/ptrace.h>
 #include <linux/kernel_stat.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
+#include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/random.h>
 #include <linux/smp.h>
@@ -217,14 +217,11 @@
 
 	desc->triggered = 1;
 
-	irq_enter();
 	kstat.irqs[cpu][irq]++;
 
 	action = desc->action;
 	if (action)
 		__do_irq(irq, desc->action, regs);
-
-	irq_exit();
 }
 
 /*
@@ -256,7 +253,6 @@
 	 */
 	desc->running = 1;
 
-	irq_enter();
 	kstat.irqs[cpu][irq]++;
 
 	do {
@@ -272,9 +268,7 @@
 		}
 
 		__do_irq(irq, action, regs);
-	} while (desc->pending);
-
-	irq_exit();
+	} while (desc->pending && desc->enabled);
 
 	desc->running = 0;
 
@@ -311,7 +305,6 @@
 	desc->chip->ack(irq);
 
 	if (likely(desc->enabled)) {
-		irq_enter();
 		kstat.irqs[cpu][irq]++;
 
 		/*
@@ -325,7 +318,6 @@
 				   !check_irq_lock(desc, irq, regs)))
 				desc->chip->unmask(irq);
 		}
-		irq_exit();
 	}
 }
 
@@ -345,12 +337,11 @@
 	if (irq >= NR_IRQS)
 		desc = &bad_irq_desc;
 
+	irq_enter();
 	spin_lock(&irq_controller_lock);
 	desc->handle(irq, desc, regs);
 	spin_unlock(&irq_controller_lock);
-
-	if (softirq_pending(smp_processor_id()))
-		do_softirq();
+	irq_exit();
 }
 
 void __set_irq_handler(unsigned int irq, irq_handler_t handle, int is_chained)
@@ -578,7 +569,7 @@
  *	On a shared IRQ the caller must ensure the interrupt is disabled
  *	on the card it drives before calling this function.
  *
- *	This function may be called from interrupt context.
+ *	This function must not be called from interrupt context.
  */
 void free_irq(unsigned int irq, void *dev_id)
 {
@@ -600,15 +591,19 @@
 
 	    	/* Found it - now free it */
 		*p = action->next;
-		kfree(action);
-		goto out;
+		break;
 	}
-	printk(KERN_ERR "Trying to free free IRQ%d\n",irq);
+	spin_unlock_irqrestore(&irq_controller_lock, flags);
+
+	if (!action) {
+		printk(KERN_ERR "Trying to free free IRQ%d\n",irq);
 #ifdef CONFIG_DEBUG_ERRORS
-	__backtrace();
+		__backtrace();
 #endif
-out:
-	spin_unlock_irqrestore(&irq_controller_lock, flags);
+	} else {
+		synchronize_irq(irq);
+		kfree(action);
+	}
 }
 
 /* Start the interrupt probing.  Unlike other architectures,
diff -Nru a/arch/arm/kernel/plx90x0.c b/arch/arm/kernel/plx90x0.c
--- a/arch/arm/kernel/plx90x0.c	Tue Oct  1 00:08:16 2002
+++ b/arch/arm/kernel/plx90x0.c	Tue Oct  1 00:08:16 2002
@@ -34,9 +34,9 @@
 #define PLX_SET_CONFIG							\
 	{ unsigned long flags;						\
 	local_irq_save(flags);						\
-	__raw_writel((1<<31 | (dev->bus->number << 16)			\
-		| (dev->devfn << 8) | (where & ~3)			\
-		| ((dev->bus->number == 0)?0:1)), PLX_BASE + 0xac);	\
+	__raw_writel((1<<31 | (bus->number << 16)			\
+		| (devfn << 8) | (where & ~3)				\
+		| ((bus->number == 0)?0:1)), PLX_BASE + 0xac);		\
 
 #define PLX_CONFIG_WRITE(size)						\
 	PLX_SET_CONFIG							\
@@ -58,47 +58,47 @@
 
 /* Configuration space access routines */
 
-static int
-plx90x0_read_config_byte (struct pci_dev *dev,
-			  int where, u8 *value)
-{
-	PLX_CONFIG_READ(b)
-}
-
-static int
-plx90x0_read_config_word (struct pci_dev *dev,
-			  int where, u16 *value)
-{
-	PLX_CONFIG_READ(w)
-}
-
-static int 
-plx90x0_read_config_dword (struct pci_dev *dev,
-			   int where, u32 *value)
-{
-	PLX_CONFIG_READ(l)
-}
-
 static int 
-plx90x0_write_config_byte (struct pci_dev *dev,
-			   int where, u8 value)
+plx90x0_read_config (struct pci_bus *bus, unsigned int devfn, int where,
+		     int where, int size, u32 *value)
 {
-	PLX_CONFIG_WRITE(b)
+	switch (size) {
+	case 1:
+		PLX_CONFIG_READ(b)
+		break;
+	case 2:
+		PLX_CONFIG_READ(w)
+		break;
+	case 4:
+		PLX_CONFIG_READ(l)
+		break;
+	}
+	return PCIBIOS_SUCCESSFUL;
 }
 
 static int 
-plx90x0_write_config_word (struct pci_dev *dev,
-			   int where, u16 value)
+plx90x0_write_config (struct pci_bus *bus, unsigned int devfn, int where,
+		      int where, int size, u32 value)
 {
-	PLX_CONFIG_WRITE(w)
+	switch (size) {
+	case 1:
+		PLX_CONFIG_WRITE(b)
+		break;
+	case 2:
+		PLX_CONFIG_WRITE(w)
+		break;
+	case 4:
+		PLX_CONFIG_WRITE(l)
+		break;
+	}
+	return PCIBIOS_SUCCESSFUL;
 }
 
-static int 
-plx90x0_write_config_dword (struct pci_dev *dev,
-			    int where, u32 value)
+static struct pci_ops plx90x0_ops = 
 {
-	PLX_CONFIG_WRITE(l)
-}
+	.read	= plx90x0_read_config,
+	.write	= plx90x0_write_config,
+};
 
 static void 
 plx_syserr_handler(int irq, void *handle, struct pt_regs *regs)
@@ -107,17 +107,6 @@
 	       readw(PLX_BASE + 6), regs->ARM_pc);
 	__raw_writew(0xf000, PLX_BASE + 6);
 }
-
-static struct pci_ops 
-plx90x0_ops = 
-{
-	plx90x0_read_config_byte,
-	plx90x0_read_config_word,
-	plx90x0_read_config_dword,
-	plx90x0_write_config_byte,
-	plx90x0_write_config_word,
-	plx90x0_write_config_dword,
-};
 
 /*
  * Initialise the PCI system.
diff -Nru a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
--- a/arch/arm/kernel/process.c	Tue Oct  1 00:08:20 2002
+++ b/arch/arm/kernel/process.c	Tue Oct  1 00:08:20 2002
@@ -177,9 +177,9 @@
 		flags & PSR_Z_BIT ? 'Z' : 'z',
 		flags & PSR_C_BIT ? 'C' : 'c',
 		flags & PSR_V_BIT ? 'V' : 'v');
-	printk("  IRQs %s  FIQs %s  Mode %s%s  Segment %s\n",
-		interrupts_enabled(regs) ? "on" : "off",
-		fast_interrupts_enabled(regs) ? "on" : "off",
+	printk("  IRQs o%s  FIQs o%s  Mode %s%s  Segment %s\n",
+		interrupts_enabled(regs) ? "n" : "ff",
+		fast_interrupts_enabled(regs) ? "n" : "ff",
 		processor_modes[processor_mode(regs)],
 		thumb_mode(regs) ? " (T)" : "",
 		get_fs() == get_ds() ? "kernel" : "user");
@@ -293,15 +293,22 @@
 {
 }
 
+static void default_fp_init(union fp_state *fp)
+{
+	memset(fp, 0, sizeof(union fp_state));
+}
+
+void (*fp_init)(union fp_state *) = default_fp_init;
+
 void flush_thread(void)
 {
 	struct thread_info *thread = current_thread_info();
 	struct task_struct *tsk = current;
 
-	memset(&tsk->thread.debug, 0, sizeof(struct debug_info));
-	memset(&thread->fpstate, 0, sizeof(union fp_state));
+	tsk->used_math = 0;
 
-	current->used_math = 0;
+	memset(&tsk->thread.debug, 0, sizeof(struct debug_info));
+	fp_init(&thread->fpstate);
 }
 
 void release_thread(struct task_struct *dead_task)
diff -Nru a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
--- a/arch/arm/kernel/ptrace.c	Tue Oct  1 00:08:15 2002
+++ b/arch/arm/kernel/ptrace.c	Tue Oct  1 00:08:15 2002
@@ -339,7 +339,7 @@
 	return res;
 }
 
-int ptrace_set_bpt(struct task_struct *child)
+void ptrace_set_bpt(struct task_struct *child)
 {
 	struct pt_regs *regs;
 	unsigned long pc, insn;
@@ -350,7 +350,7 @@
 
 	if (thumb_mode(regs)) {
 		printk(KERN_WARNING "ptrace: can't handle thumb mode\n");
-		return -EINVAL;
+		return;
 	}
 
 	res = read_tsk_long(child, pc, &insn);
@@ -376,8 +376,6 @@
 		if (!alt || predicate(insn) != PREDICATE_ALWAYS)
 			res = add_breakpoint(child, dbg, pc + 4);
 	}
-
-	return res;
 }
 
 /*
diff -Nru a/arch/arm/kernel/ptrace.h b/arch/arm/kernel/ptrace.h
--- a/arch/arm/kernel/ptrace.h	Tue Oct  1 00:08:17 2002
+++ b/arch/arm/kernel/ptrace.h	Tue Oct  1 00:08:17 2002
@@ -8,7 +8,7 @@
  * published by the Free Software Foundation.
  */
 extern void __ptrace_cancel_bpt(struct task_struct *);
-extern int ptrace_set_bpt(struct task_struct *);
+extern void ptrace_set_bpt(struct task_struct *);
 extern void ptrace_break(struct task_struct *, struct pt_regs *);
 
 /*
diff -Nru a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
--- a/arch/arm/kernel/setup.c	Tue Oct  1 00:08:14 2002
+++ b/arch/arm/kernel/setup.c	Tue Oct  1 00:08:14 2002
@@ -77,6 +77,8 @@
 unsigned char aux_device_present;
 char elf_platform[ELF_PLATFORM_SIZE];
 char saved_command_line[COMMAND_LINE_SIZE];
+unsigned long phys_initrd_start __initdata = 0;
+unsigned long phys_initrd_size __initdata = 0;
 
 static struct meminfo meminfo __initdata = { 0, };
 static struct proc_info_item proc_info;
@@ -326,6 +328,22 @@
 			mi->bank[mi->nr_banks].size  = size;
 			mi->bank[mi->nr_banks].node  = PHYS_TO_NID(start);
 			mi->nr_banks += 1;
+		} else if (c == ' ' && !memcmp(from, "initrd=", 7)) {
+			unsigned long start, size;
+
+			/*
+			 * Remove space character
+			 */
+			if (to != command_line)
+				to -= 1;
+
+			start = memparse(from + 7, &from);
+			if (*from == ',') {
+				size = memparse(from + 1, &from);
+
+				phys_initrd_start = start;
+				phys_initrd_size = size;
+			}
 		}
 		c = *from++;
 		if (!c)
@@ -353,19 +371,6 @@
 #endif
 }
 
-/*
- * initial ram disk
- */
-static void __init setup_initrd(unsigned int start, unsigned int size)
-{
-#ifdef CONFIG_BLK_DEV_INITRD
-	if (start == 0)
-		size = 0;
-	initrd_start = start;
-	initrd_end   = start + size;
-#endif
-}
-
 static void __init
 request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc)
 {
@@ -499,7 +504,8 @@
 
 static int __init parse_tag_initrd(const struct tag *tag)
 {
-	setup_initrd(tag->u.initrd.start, tag->u.initrd.size);
+	phys_initrd_start = __virt_to_phys(tag->u.initrd.start);
+	phys_initrd_size = tag->u.initrd.size;
 	return 0;
 }
 
@@ -507,13 +513,8 @@
 
 static int __init parse_tag_initrd2(const struct tag *tag)
 {
-	unsigned long start = 0;
-
-	if (tag->u.initrd.size) {
-		start = (unsigned long)phys_to_virt(tag->u.initrd.start);
-
-		setup_initrd(start, tag->u.initrd.size);
-	}
+	phys_initrd_start = tag->u.initrd.start;
+	phys_initrd_size = tag->u.initrd.size;
 	return 0;
 }
 
diff -Nru a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
--- a/arch/arm/kernel/signal.c	Tue Oct  1 00:08:14 2002
+++ b/arch/arm/kernel/signal.c	Tue Oct  1 00:08:14 2002
@@ -373,7 +373,7 @@
 	regs->ARM_r0 = usig;
 	regs->ARM_sp = (unsigned long)frame;
 	regs->ARM_lr = retcode;
-	regs->ARM_pc = handler & (thumb ? ~1 : ~3);
+	regs->ARM_pc = handler;
 
 #ifdef CONFIG_CPU_32
 	regs->ARM_cpsr = cpsr;
@@ -503,7 +503,6 @@
  */
 static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
 {
-	struct k_sigaction *ka;
 	siginfo_t info;
 	int single_stepping;
 
@@ -519,11 +518,22 @@
 	single_stepping = ptrace_cancel_bpt(current);
 
 	for (;;) {
-		unsigned long signr;
-
-		spin_lock_irq (&current->sigmask_lock);
-		signr = dequeue_signal(&current->blocked, &info);
-		spin_unlock_irq (&current->sigmask_lock);
+		unsigned long signr = 0;
+		struct k_sigaction *ka;
+		sigset_t *mask = &current->blocked;
+
+		local_irq_disable();
+		if (current->sig->shared_pending.head) {
+			spin_lock(&current->sig->siglock);
+			signr = dequeue_signal(&current->sig->shared_pending, mask, &info);
+			spin_unlock(&current->sig->siglock);
+		}
+		if (!signr) {
+			spin_lock(&current->sigmask_lock);
+			signr = dequeue_signal(&current->pending, mask, &info);
+			spin_unlock(&current->sigmask_lock);
+		}
+		local_irq_enable();
 
 		if (!signr)
 			break;
@@ -531,13 +541,14 @@
 		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
 			/* Let the debugger run.  */
 			current->exit_code = signr;
-			current->state = TASK_STOPPED;
+			set_current_state(TASK_STOPPED);
 			notify_parent(current, SIGCHLD);
 			schedule();
 			single_stepping |= ptrace_cancel_bpt(current);
 
 			/* We're back.  Did the debugger cancel the sig?  */
-			if (!(signr = current->exit_code))
+			signr = current->exit_code;
+			if (signr == 0)
 				continue;
 			current->exit_code = 0;
 
@@ -589,7 +600,7 @@
 
 			case SIGSTOP: {
 				struct signal_struct *sig;
-				current->state = TASK_STOPPED;
+				set_current_state(TASK_STOPPED);
 				current->exit_code = signr;
 				sig = current->parent->sig;
 				if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
diff -Nru a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c
--- a/arch/arm/kernel/sys_arm.c	Tue Oct  1 00:08:15 2002
+++ b/arch/arm/kernel/sys_arm.c	Tue Oct  1 00:08:15 2002
@@ -239,7 +239,7 @@
 asmlinkage int sys_fork(struct pt_regs *regs)
 {
 	struct task_struct *p;
-	p = do_fork(SIGCHLD, regs->ARM_sp, regs, 0);
+	p = do_fork(SIGCHLD, regs->ARM_sp, regs, 0, NULL);
 	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
 }
 
@@ -249,16 +249,25 @@
 asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, struct pt_regs *regs)
 {
 	struct task_struct *p;
+
+	/*
+	 * We don't support SETTID / CLEARTID
+	 */
+	if (clone_flags & (CLONE_SETTID | CLONE_CLEARTID))
+		return -EINVAL;
+
 	if (!newsp)
 		newsp = regs->ARM_sp;
-	p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, regs, 0);
+
+	p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, regs, 0, NULL);
+
 	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
 }
 
 asmlinkage int sys_vfork(struct pt_regs *regs)
 {
 	struct task_struct *p;
-	p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->ARM_sp, regs, 0);
+	p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->ARM_sp, regs, 0, NULL);
 	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
 }
 
diff -Nru a/arch/arm/kernel/via82c505.c b/arch/arm/kernel/via82c505.c
--- a/arch/arm/kernel/via82c505.c	Tue Oct  1 00:08:14 2002
+++ b/arch/arm/kernel/via82c505.c	Tue Oct  1 00:08:14 2002
@@ -15,63 +15,49 @@
 
 #define MAX_SLOTS		7
 
-#define CONFIG_CMD(dev, where)   (0x80000000 | (dev->bus->number << 16) | (dev->devfn << 8) | (where & ~3))
+#define CONFIG_CMD(bus, devfn, where)   (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3))
 
 static int
-via82c505_read_config_byte(struct pci_dev *dev, int where, u8 *value)
+via82c505_read_config(struct pci_bus *bus, unsigned int devfn, int where,
+		      int size, u32 *value)
 {
 	outl(CONFIG_CMD(dev,where),0xCF8);
-	*value=inb(0xCFC + (where&3));
+	switch (size) {
+	case 1:
+		*value=inb(0xCFC + (where&3));
+		break;
+	case 2:
+		*value=inw(0xCFC + (where&2));
+		break;
+	case 4:
+		*value=inl(0xCFC);
+		break;
+	}
 	return PCIBIOS_SUCCESSFUL;
 }
 
 static int
-via82c505_read_config_word(struct pci_dev *dev, int where, u16 *value)
-{
-	outl(CONFIG_CMD(dev,where),0xCF8);
-	*value=inw(0xCFC + (where&2));
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-via82c505_read_config_dword(struct pci_dev *dev, int where, u32 *value)
-{
-	outl(CONFIG_CMD(dev,where),0xCF8);
-	*value=inl(0xCFC);
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-via82c505_write_config_byte(struct pci_dev *dev, int where, u8 value)
-{
-	outl(CONFIG_CMD(dev,where),0xCF8);
-	outb(value, 0xCFC + (where&3));
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-via82c505_write_config_word(struct pci_dev *dev, int where, u16 value)
-{
-	outl(CONFIG_CMD(dev,where),0xCF8);
-	outw(value, 0xCFC + (where&2));
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-via82c505_write_config_dword(struct pci_dev *dev, int where, u32 value)
-{
-	outl(CONFIG_CMD(dev,where),0xCF8);
-	outl(value, 0xCFC);
+via82c505_write_config(struct pci_bus *bus, unsigned int devfn, int where
+		       int size, u32 value)
+{
+	outl(CONFIG_CMD(bus,devfn,where),0xCF8);
+	switch (size) {
+	case 1:
+		outb(value, 0xCFC + (where&3));
+		break;
+	case 2:
+		outw(value, 0xCFC + (where&2));
+		break;
+	case 4:
+		outl(value, 0xCFC);
+		break;
+	}
 	return PCIBIOS_SUCCESSFUL;
 }
 
 static struct pci_ops via82c505_ops = {
-	via82c505_read_config_byte,
-	via82c505_read_config_word,
-	via82c505_read_config_dword,
-	via82c505_write_config_byte,
-	via82c505_write_config_word,
-	via82c505_write_config_dword,
+	.read	= via82c505_read_config,
+	.write	= via82c505_write_config,
 };
 
 void __init via82c505_preinit(void *sysdata)
diff -Nru a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
--- a/arch/arm/lib/Makefile	Tue Oct  1 00:08:18 2002
+++ b/arch/arm/lib/Makefile	Tue Oct  1 00:08:18 2002
@@ -17,8 +17,6 @@
 obj-m		:=
 obj-n		:=
 
-obj-$(CONFIG_VT)+= kbd.o
-
 obj-arc		:= ecard.o io-acorn.o floppydma.o
 obj-rpc		:= ecard.o io-acorn.o floppydma.o
 obj-clps7500	:= io-acorn.o
diff -Nru a/arch/arm/lib/findbit.S b/arch/arm/lib/findbit.S
--- a/arch/arm/lib/findbit.S	Tue Oct  1 00:08:17 2002
+++ b/arch/arm/lib/findbit.S	Tue Oct  1 00:08:17 2002
@@ -83,7 +83,15 @@
 /*
  * One or more bits in the LSB of r3 are assumed to be set.
  */
-.found:		tst	r3, #0x0f
+.found:
+#if __LINUX_ARM_ARCH__ >= 5
+		rsb	r1, r3, #0
+		and	r3, r3, r1
+		clz	r3, r3
+		rsb	r3, r3, #31
+		add	r0, r2, r3
+#else
+		tst	r3, #0x0f
 		addeq	r2, r2, #4
 		movne	r3, r3, lsl #4
 		tst	r3, #0x30
@@ -92,5 +100,6 @@
 		tst	r3, #0x40
 		addeq	r2, r2, #1
 		mov	r0, r2
+#endif
 		RETINSTR(mov,pc,lr)
 
diff -Nru a/arch/arm/lib/kbd.c b/arch/arm/lib/kbd.c
--- a/arch/arm/lib/kbd.c	Tue Oct  1 00:08:17 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,279 +0,0 @@
-#include <linux/config.h>
-#include <linux/kd.h>
-#include <linux/kbd_ll.h>
-#include <linux/kbd_kern.h>
-
-/*
- * 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
-
-/* for USB 106 keyboard */
-#define E0_YEN         124
-#define E0_BACKSLASH   89
-
-
-#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
-
-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, E0_BACKSLASH, 0, 0,	/* 0x70-0x77 */
-	0, 0, 0, E0_YEN, 0, 0, 0, 0	/* 0x78-0x7f */
-};
-
-static int gen_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;
-}
-
-static int gen_getkeycode(unsigned int scancode)
-{
-	return
-	    (scancode < SC_LIM || scancode > 255) ? -EINVAL :
-	    (scancode <
-	     128) ? high_keys[scancode - SC_LIM] : e0_keys[scancode - 128];
-}
-
-static int
-gen_translate(unsigned char scancode, unsigned char *keycode, char raw_mode)
-{
-	static int prev_scancode = 0;
-
-	/* 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;
-}
-
-static char gen_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;
-}
-
-/*
- * These are the default mappings
- */
-int  (*k_setkeycode)(unsigned int, unsigned int) = gen_setkeycode;
-int  (*k_getkeycode)(unsigned int) = gen_getkeycode;
-int  (*k_translate)(unsigned char, unsigned char *, char) = gen_translate;
-char (*k_unexpected_up)(unsigned char) = gen_unexpected_up;
-void (*k_leds)(unsigned char);
-
-/* Simple translation table for the SysRq keys */
-
-#ifdef CONFIG_MAGIC_SYSRQ
-static unsigned char gen_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 */
-
-unsigned char *k_sysrq_xlate = gen_sysrq_xlate;
-int k_sysrq_key = 0x54;
-#endif
diff -Nru a/arch/arm/lib/strchr.S b/arch/arm/lib/strchr.S
--- a/arch/arm/lib/strchr.S	Tue Oct  1 00:08:20 2002
+++ b/arch/arm/lib/strchr.S	Tue Oct  1 00:08:20 2002
@@ -15,11 +15,12 @@
 		.text
 		.align	5
 ENTRY(strchr)
+		and	r1, r1, #0xff
 1:		ldrb	r2, [r0], #1
 		teq	r2, r1
 		teqne	r2, #0
 		bne	1b
-		teq	r2, #0
-		moveq	r0, #0
-		subne	r0, r0, #1
+		teq	r2, r1
+		movne	r0, #0
+		subeq	r0, r0, #1
 		RETINSTR(mov,pc,lr)
diff -Nru a/arch/arm/mach-arc/Config.help b/arch/arm/mach-arc/Config.help
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/arm/mach-arc/Config.help	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,24 @@
+CONFIG_ARCH_ARCA5K
+  This selects what ARM system you wish to build the kernel for. It
+  also selects to some extent the CPU type. If you are unsure what
+  to set this option to, please consult any information supplied with
+  your system.
+
+CONFIG_ARCH_A5K
+  Say Y here to to support the Acorn A5000.  Linux can support the
+  internal IDE disk and CD-ROM interface, serial and parallel port,
+  and the floppy drive.  Note that on some A5000s the floppy is
+  plugged into the wrong socket on the motherboard.
+
+CONFIG_ARCH_ARC
+  The Acorn Archimedes was an personal computer based on an 8K ARM2
+  processor, released in 1987.  It supported 512K of RAM and 2 800K
+  floppy disks.  Picture and more detailed specifications at
+  <http://www.computingmuseum.com/museum/archi.htm>.
+
+CONFIG_PAGESIZE_16
+  Say Y here if your Archimedes or A5000 system has only 2MB of
+  memory, otherwise say N.  The resulting kernel will not run on a
+  machine with 4MB of memory.
+
+
diff -Nru a/arch/arm/mach-arc/Config.in b/arch/arm/mach-arc/Config.in
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/arm/mach-arc/Config.in	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,15 @@
+mainmenu_option next_comment
+comment 'Archimedes/A5000 Implementations'
+# These architectures will be combined.  However, until this
+# is complete...  Note that the ARC will take precedence over
+# A5K
+comment 'Archimedes/A5000 Implementations (select only ONE)'
+dep_bool '  Archimedes' CONFIG_ARCH_ARC $CONFIG_ARCH_ARCA5K
+dep_bool '  A5000' CONFIG_ARCH_A5K $CONFIG_ARCH_ARCA5K
+
+if [ "$CONFIG_ARCH_ARCA5K" = "y" ]; then
+   bool '2MB physical memory' CONFIG_PAGESIZE_16
+fi
+
+endmenu
+
diff -Nru a/arch/arm/mach-clps711x/Config.help b/arch/arm/mach-clps711x/Config.help
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/arm/mach-clps711x/Config.help	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,33 @@
+CONFIG_ARCH_AUTCPU12
+  Say Y if you intend to run the kernel on the autronix autcpu12
+  board. This board is based on a Cirrus Logic CS89712.
+
+CONFIG_ARCH_CDB89712
+  This is an evaluation board from Cirrus for the CS89712 processor.
+  The board includes 2 serial ports, Ethernet, IRDA, and expansion
+  headers.  It comes with 16 MB SDRAM and 8 MB flash ROM.
+
+CONFIG_ARCH_CEIVA
+  Say Y here if you intend to run this kernel on the Ceiva/Polaroid
+  PhotoMax Digital Picture Frame.
+
+CONFIG_ARCH_EDB7211
+  Say Y here if you intend to run this kernel on a Cirrus Logic EDB-7211
+  evaluation board.
+
+CONFIG_ARCH_P720T
+  Say Y here if you intend to run this kernel on the ARM Prospector
+  720T.
+
+CONFIG_EP72XX_ROM_BOOT
+  If you say Y here, your CLPS711x-based kernel will use the bootstrap
+  mode memory map instead of the normal memory map.
+
+  Processors derived from the Cirrus CLPS-711X core support two boot
+  modes.  Normal mode boots from the external memory device at CS0.
+  Bootstrap mode rearranges parts of the memory map, placing an
+  internal 128 byte bootstrap ROM at CS0.  This option performs the
+  address map changes required to support booting in this mode.
+
+  You almost surely want to say N here.
+
diff -Nru a/arch/arm/mach-clps711x/Config.in b/arch/arm/mach-clps711x/Config.in
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/arm/mach-clps711x/Config.in	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,31 @@
+mainmenu_option next_comment
+comment 'CLPS711X/EP721X Implementations'
+dep_bool '  AUTCPU12' CONFIG_ARCH_AUTCPU12 $CONFIG_ARCH_CLPS711X
+dep_bool '  CDB89712' CONFIG_ARCH_CDB89712 $CONFIG_ARCH_CLPS711X
+dep_bool '  CEIVA' CONFIG_ARCH_CEIVA $CONFIG_ARCH_CLPS711X
+dep_bool '  CLEP7312' CONFIG_ARCH_CLEP7312 $CONFIG_ARCH_CLPS711X
+dep_bool '  EDB7211' CONFIG_ARCH_EDB7211 $CONFIG_ARCH_CLPS711X
+dep_bool '  P720T' CONFIG_ARCH_P720T $CONFIG_ARCH_CLPS711X
+dep_bool '  FORTUNET' CONFIG_ARCH_FORTUNET $CONFIG_ARCH_CLPS711X
+
+# XXX Maybe these should indicate register compatibility
+# instead of being mutually exclusive.
+if [ "$CONFIG_ARCH_EDB7211" = "y" ]; then
+   define_bool CONFIG_ARCH_EP7211 y
+else
+   define_bool CONFIG_ARCH_EP7211 n
+fi
+
+if [ "$CONFIG_ARCH_P720T" = "y" -o \
+     "$CONFIG_ARCH_CEIVA" = "y" ]; then
+   define_bool CONFIG_ARCH_EP7212 y
+else
+   define_bool CONFIG_ARCH_EP7212 n
+fi
+
+if [ "$CONFIG_ARCH_EP7211" = "y" -o \
+     "$CONFIG_ARCH_EP7212" = "y" ]; then
+   bool '  EP72xx ROM boot' CONFIG_EP72XX_ROM_BOOT
+fi
+endmenu
+
diff -Nru a/arch/arm/mach-clps711x/Makefile b/arch/arm/mach-clps711x/Makefile
--- a/arch/arm/mach-clps711x/Makefile	Tue Oct  1 00:08:21 2002
+++ b/arch/arm/mach-clps711x/Makefile	Tue Oct  1 00:08:21 2002
@@ -9,8 +9,7 @@
 obj-n			:=
 obj-			:=
 
-export-objs		:= leds-p720t.o
-
+obj-$(CONFIG_ARCH_CEIVA) += ceiva.o
 obj-$(CONFIG_ARCH_AUTCPU12) += autcpu12.o
 obj-$(CONFIG_ARCH_CDB89712) += cdb89712.o
 obj-$(CONFIG_ARCH_CLEP7312) += clep7312.o
diff -Nru a/arch/arm/mach-clps711x/ceiva.c b/arch/arm/mach-clps711x/ceiva.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/arm/mach-clps711x/ceiva.c	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,61 @@
+/*
+ *  linux/arch/arm/mach-clps711x/arch-ceiva.c
+ *
+ *  Copyright (C) 2002, Rob Scott <rscott@mtrob.fdns.net>
+ *
+ * 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/init.h>
+#include <linux/types.h>
+#include <linux/string.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <linux/kernel.h>
+
+#include <asm/hardware.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/sizes.h>
+
+#include <asm/mach/map.h>
+
+extern void clps711x_init_irq(void);
+
+static struct map_desc ceiva_io_desc[] __initdata = {
+ /* virtual, physical, length, type */
+
+ /* SED1355 controlled video RAM & registers */
+ { CEIVA_VIRT_SED1355, CEIVA_PHYS_SED1355, SZ_2M, MT_DEVICE }
+
+};
+
+
+static void __init ceiva_map_io(void)
+{
+        clps711x_map_io();
+        iotable_init(ceiva_io_desc, ARRAY_SIZE(ceiva_io_desc));
+}
+
+
+MACHINE_START(CEIVA, "CEIVA/Polaroid Photo MAX Digital Picture Frame")
+	MAINTAINER("Rob Scott")
+	BOOT_MEM(0xc0000000, 0x80000000, 0xff000000)
+	BOOT_PARAMS(0xc0000100)
+	MAPIO(ceiva_map_io)
+	INITIRQ(clps711x_init_irq)
+MACHINE_END
diff -Nru a/arch/arm/mach-clps711x/p720t-leds.c b/arch/arm/mach-clps711x/p720t-leds.c
--- a/arch/arm/mach-clps711x/p720t-leds.c	Tue Oct  1 00:08:18 2002
+++ b/arch/arm/mach-clps711x/p720t-leds.c	Tue Oct  1 00:08:18 2002
@@ -64,4 +64,4 @@
 	return 0;
 }
 
-__initcall(leds_init);
+arch_initcall(leds_init);
diff -Nru a/arch/arm/mach-epxa10db/Config.help b/arch/arm/mach-epxa10db/Config.help
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/arm/mach-epxa10db/Config.help	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,8 @@
+CONFIG_PLD_HOTSWAP
+  This enables support for the dynamic loading and configuration of
+  compatible drivers when the contents of the PLD are changed. This
+  is still experimental and requires configuration tools which are
+  not yet generally available. Say N here. You must enable the kernel
+  module loader for this feature to work.
+
+
diff -Nru a/arch/arm/mach-epxa10db/Config.in b/arch/arm/mach-epxa10db/Config.in
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/arm/mach-epxa10db/Config.in	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,10 @@
+mainmenu_option next_comment
+comment 'Epxa10db'
+
+if [ "$CONFIG_ARCH_CAMELOT" = "y" ]; then
+   comment 'PLD hotswap support'
+   define_bool CONFIG_PLD y
+   dep_bool 'Support for PLD device hotplugging (experimental)' CONFIG_PLD_HOTSWAP $CONFIG_EXPERIMENTAL
+fi
+
+endmenu
diff -Nru a/arch/arm/mach-footbridge/Config.help b/arch/arm/mach-footbridge/Config.help
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/arm/mach-footbridge/Config.help	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,40 @@
+CONFIG_ARCH_CATS
+  Say Y here if you intend to run this kernel on the CATS.
+
+  Saying N will reduce the size of the Footbridge kernel.
+
+CONFIG_ARCH_EBSA285_ADDIN
+  Say Y here if you intend to run this kernel on the EBSA285 card
+  in addin mode.
+
+  Saying N will reduce the size of the Footbridge kernel.
+
+CONFIG_ARCH_EBSA285_HOST
+  Say Y here if you intend to run this kernel on the EBSA285 card
+  in host ("central function") mode.
+
+  Saying N will reduce the size of the Footbridge kernel.
+
+CONFIG_ARCH_NETWINDER
+  Say Y here if you intend to run this kernel on the Rebel.COM
+  NetWinder.  Information about this machine can be found at:
+
+  <http://www.netwinder.org/>
+
+  Saying N will reduce the size of the Footbridge kernel.
+
+CONFIG_ARCH_PERSONAL_SERVER
+  Say Y here if you intend to run this kernel on the Compaq
+  Personal Server.
+
+  Saying N will reduce the size of the Footbridge kernel.
+
+  The Compaq Personal Server is not available for purchase.
+  There are no product plans beyond the current research
+  prototypes at this time.  Information is available at:
+
+  <http://crl.research.compaq.com/projects/personalserver/>
+
+  If you have any questions or comments about the  Compaq Personal
+  Server, send e-mail to skiff@crl.dec.com.
+
diff -Nru a/arch/arm/mach-footbridge/Config.in b/arch/arm/mach-footbridge/Config.in
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/arm/mach-footbridge/Config.in	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,9 @@
+mainmenu_option next_comment
+comment 'Footbridge Implementations'
+dep_bool '  CATS' CONFIG_ARCH_CATS $CONFIG_ARCH_FOOTBRIDGE
+dep_bool '  Compaq Personal Server' CONFIG_ARCH_PERSONAL_SERVER $CONFIG_ARCH_FOOTBRIDGE
+dep_bool '  EBSA285 (addin mode)' CONFIG_ARCH_EBSA285_ADDIN $CONFIG_ARCH_FOOTBRIDGE
+dep_bool '  EBSA285 (host mode)' CONFIG_ARCH_EBSA285_HOST $CONFIG_ARCH_FOOTBRIDGE
+dep_bool '  NetWinder' CONFIG_ARCH_NETWINDER $CONFIG_ARCH_FOOTBRIDGE
+endmenu
+
diff -Nru a/arch/arm/mach-footbridge/dc21285.c b/arch/arm/mach-footbridge/dc21285.c
--- a/arch/arm/mach-footbridge/dc21285.c	Tue Oct  1 00:08:17 2002
+++ b/arch/arm/mach-footbridge/dc21285.c	Tue Oct  1 00:08:17 2002
@@ -36,12 +36,11 @@
 extern void register_isa_ports(unsigned int, unsigned int, unsigned int);
 
 static unsigned long
-dc21285_base_address(struct pci_dev *dev)
+dc21285_base_address(struct pci_bus *bus, unsigned int devfn)
 {
 	unsigned long addr = 0;
-	unsigned int devfn = dev->devfn;
 
-	if (dev->bus->number == 0) {
+	if (bus->number == 0) {
 		if (PCI_SLOT(devfn) == 0)
 			/*
 			 * For devfn 0, point at the 21285
@@ -54,54 +53,33 @@
 				addr = PCICFG0_BASE | 0xc00000 | (devfn << 8);
 		}
 	} else
-		addr = PCICFG1_BASE | (dev->bus->number << 16) | (devfn << 8);
+		addr = PCICFG1_BASE | (bus->number << 16) | (devfn << 8);
 
 	return addr;
 }
 
 static int
-dc21285_read_config_byte(struct pci_dev *dev, int where, u8 *value)
+dc21285_read_config(struct pci_bus *bus, unsigned int devfn, int where,
+		    int size, u32 *value)
 {
-	unsigned long addr = dc21285_base_address(dev);
-	u8 v;
-
-	if (addr)
-		asm("ldr%?b	%0, [%1, %2]"
-			: "=r" (v) : "r" (addr), "r" (where));
-	else
-		v = 0xff;
-
-	*value = v;
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-dc21285_read_config_word(struct pci_dev *dev, int where, u16 *value)
-{
-	unsigned long addr = dc21285_base_address(dev);
-	u16 v;
-
-	if (addr)
-		asm("ldr%?h	%0, [%1, %2]"
-			: "=r" (v) : "r" (addr), "r" (where));
-	else
-		v = 0xffff;
-
-	*value = v;
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-dc21285_read_config_dword(struct pci_dev *dev, int where, u32 *value)
-{
-	unsigned long addr = dc21285_base_address(dev);
+	unsigned long addr = dc21285_base_address(bus, devfn);
 	u32 v;
 
 	if (addr)
-		asm("ldr%?	%0, [%1, %2]"
-			: "=r" (v) : "r" (addr), "r" (where));
+		switch (size) {
+		case 1:
+			asm("ldr%?b	%0, [%1, %2]"
+				: "=r" (v) : "r" (addr), "r" (where));
+			break;
+		case 2:
+			asm("ldr%?h	%0, [%1, %2]"
+				: "=r" (v) : "r" (addr), "r" (where));
+			break;
+		case 4:
+			asm("ldr%?	%0, [%1, %2]"
+				: "=r" (v) : "r" (addr), "r" (where));
+			break;
+		}
 	else
 		v = 0xffffffff;
 
@@ -111,48 +89,33 @@
 }
 
 static int
-dc21285_write_config_byte(struct pci_dev *dev, int where, u8 value)
-{
-	unsigned long addr = dc21285_base_address(dev);
-
-	if (addr)
-		asm("str%?b	%0, [%1, %2]"
-			: : "r" (value), "r" (addr), "r" (where));
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-dc21285_write_config_word(struct pci_dev *dev, int where, u16 value)
-{
-	unsigned long addr = dc21285_base_address(dev);
-
-	if (addr)
-		asm("str%?h	%0, [%1, %2]"
-			: : "r" (value), "r" (addr), "r" (where));
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-dc21285_write_config_dword(struct pci_dev *dev, int where, u32 value)
+dc21285_write_config(struct pci_bus *bus, unsigned int devfn, int where,
+		     int size, u32 value)
 {
-	unsigned long addr = dc21285_base_address(dev);
+	unsigned long addr = dc21285_base_address(bus, devfn);
 
 	if (addr)
-		asm("str%?	%0, [%1, %2]"
-			: : "r" (value), "r" (addr), "r" (where));
+		switch (size) {
+		case 1:
+			asm("str%?b	%0, [%1, %2]"
+				: : "r" (value), "r" (addr), "r" (where));
+			break;
+		case 2:
+			asm("str%?h	%0, [%1, %2]"
+				: : "r" (value), "r" (addr), "r" (where));
+			break;
+		case 4:
+			asm("str%?	%0, [%1, %2]"
+				: : "r" (value), "r" (addr), "r" (where));
+			break;
+		}
 
 	return PCIBIOS_SUCCESSFUL;
 }
 
 static struct pci_ops dc21285_ops = {
-	dc21285_read_config_byte,
-	dc21285_read_config_word,
-	dc21285_read_config_dword,
-	dc21285_write_config_byte,
-	dc21285_write_config_word,
-	dc21285_write_config_dword,
+	.read	= dc21285_read_config,
+	.write	= dc21285_write_config,
 };
 
 static struct timer_list serr_timer;
diff -Nru a/arch/arm/mach-ftvpci/leds.c b/arch/arm/mach-ftvpci/leds.c
--- a/arch/arm/mach-ftvpci/leds.c	Tue Oct  1 00:08:15 2002
+++ b/arch/arm/mach-ftvpci/leds.c	Tue Oct  1 00:08:15 2002
@@ -5,6 +5,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/init.h>
 
 #include <asm/hardware.h>
 #include <asm/leds.h>
@@ -26,6 +27,10 @@
 	}
 }
 
-void (*leds_event)(led_event_t) = ftvpci_leds_event;
+static int __init ftvpci_leds_init(void)
+{
+	leds_event = ftvpci_leds_event;
+	return 0;
+}
 
-EXPORT_SYMBOL(leds_event);
+arch_initcall(ftvpci_leds_init);
diff -Nru a/arch/arm/mach-integrator/Makefile b/arch/arm/mach-integrator/Makefile
--- a/arch/arm/mach-integrator/Makefile	Tue Oct  1 00:08:19 2002
+++ b/arch/arm/mach-integrator/Makefile	Tue Oct  1 00:08:19 2002
@@ -9,8 +9,6 @@
 obj-n			:=
 obj-			:=
 
-export-objs		:= leds.o
-
 obj-$(CONFIG_LEDS)	+= leds.o
 obj-$(CONFIG_PCI)	+= pci_v3.o pci.o
 
diff -Nru a/arch/arm/mach-integrator/arch.c b/arch/arm/mach-integrator/arch.c
--- a/arch/arm/mach-integrator/arch.c	Tue Oct  1 00:08:18 2002
+++ b/arch/arm/mach-integrator/arch.c	Tue Oct  1 00:08:18 2002
@@ -29,37 +29,9 @@
 #include <asm/mach-types.h>
 
 #include <asm/mach/arch.h>
-#include <asm/mach/amba_kmi.h>
 
 extern void integrator_map_io(void);
 extern void integrator_init_irq(void);
-
-#ifdef CONFIG_KMI_KEYB
-static struct kmi_info integrator_keyboard __initdata = {
-	.base		= IO_ADDRESS(KMI0_BASE),
-	.irq		= IRQ_KMIINT0,
-	.divisor	= 24 / 8 - 1,
-	.type		= KMI_KEYBOARD,
-};
-
-static struct kmi_info integrator_mouse __initdata = {
-	.base		= IO_ADDRESS(KMI1_BASE),
-	.irq		= IRQ_KMIINT1,
-	.divisor	= 24 / 8 - 1,
-	.type		= KMI_MOUSE,
-};
-#endif
-
-static int __init integrator_init(void)
-{
-#ifdef CONFIG_KMI_KEYB
-	register_kmi(&integrator_keyboard);
-	register_kmi(&integrator_mouse);
-#endif
-	return 0;
-}
-
-__initcall(integrator_init);
 
 MACHINE_START(INTEGRATOR, "ARM-Integrator")
 	MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd")
diff -Nru a/arch/arm/mach-integrator/cpu.c b/arch/arm/mach-integrator/cpu.c
--- a/arch/arm/mach-integrator/cpu.c	Tue Oct  1 00:08:17 2002
+++ b/arch/arm/mach-integrator/cpu.c	Tue Oct  1 00:08:17 2002
@@ -181,4 +181,4 @@
 	return 0;
 }
 
-__initcall(integrator_cpu_init);
+core_initcall(integrator_cpu_init);
diff -Nru a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c
--- a/arch/arm/mach-integrator/pci_v3.c	Tue Oct  1 00:08:15 2002
+++ b/arch/arm/mach-integrator/pci_v3.c	Tue Oct  1 00:08:15 2002
@@ -181,11 +181,12 @@
 #undef V3_LB_BASE_PREFETCH
 #define V3_LB_BASE_PREFETCH 0
 
-static unsigned long v3_open_config_window(struct pci_dev *dev, int offset)
+static unsigned long v3_open_config_window(struct pci_bus *bus,
+					   unsigned int devfn, int offset)
 {
 	unsigned int address, mapaddress, busnr;
 
-	busnr = dev->bus->number;
+	busnr = bus->number;
 
 	/*
 	 * Trap out illegal values
@@ -194,11 +195,11 @@
 		BUG();
 	if (busnr > 255)
 		BUG();
-	if (dev->devfn > 255)
+	if (devfn > 255)
 		BUG();
 
 	if (busnr == 0) {
-		int slot = PCI_SLOT(dev->devfn);
+		int slot = PCI_SLOT(devfn);
 
 		/*
 		 * local bus segment so need a type 0 config cycle
@@ -210,7 +211,7 @@
 		 *  3:1 = config cycle (101)
 		 *  0   = PCI A1 & A0 are 0 (0)
 		 */
-		address = PCI_FUNC(dev->devfn) << 8;
+		address = PCI_FUNC(devfn) << 8;
 		mapaddress = V3_LB_MAP_TYPE_CONFIG;
 
 		if (slot > 12)
@@ -237,7 +238,7 @@
 		 *  0   = PCI A1 & A0 from host bus (1)
 		 */
 		mapaddress = V3_LB_MAP_TYPE_CONFIG | V3_LB_MAP_AD_LOW_EN;
-		address = (busnr << 16) | (dev->devfn << 8);
+		address = (busnr << 16) | (devfn << 8);
 	}
 
 	/*
@@ -276,52 +277,29 @@
 			V3_LB_BASE_ADR_SIZE_256MB | V3_LB_BASE_ENABLE);
 }
 
-static int v3_read_config_byte(struct pci_dev *dev, int where, u8 *val)
-{
-	unsigned long addr;
-	unsigned long flags;
-	u8 v;
-
-	spin_lock_irqsave(&v3_lock, flags);
-	addr = v3_open_config_window(dev, where);
-
-	v = __raw_readb(addr);
-
-	v3_close_config_window();
-	spin_unlock_irqrestore(&v3_lock, flags);
-
-	*val = v;
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int v3_read_config_word(struct pci_dev *dev, int where, u16 *val)
-{
-	unsigned long addr;
-	unsigned long flags;
-	u16 v;
-
-	spin_lock_irqsave(&v3_lock, flags);
-	addr = v3_open_config_window(dev, where);
-
-	v = __raw_readw(addr);
-
-	v3_close_config_window();
-	spin_unlock_irqrestore(&v3_lock, flags);
-
-	*val = v;
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int v3_read_config_dword(struct pci_dev *dev, int where, u32 *val)
+static int v3_read_config(struct pci_bus *bus, unsigned int devfn, int where,
+			  int size, u32 *val)
 {
 	unsigned long addr;
 	unsigned long flags;
 	u32 v;
 
 	spin_lock_irqsave(&v3_lock, flags);
-	addr = v3_open_config_window(dev, where);
+	addr = v3_open_config_window(bus, devfn, where);
 
-	v = __raw_readl(addr);
+	switch (size) {
+	case 1:
+		v = __raw_readb(addr);
+		break;
+
+	case 2:
+		v = __raw_readw(addr);
+		break;
+
+	case 4:
+		v = __raw_readl(addr);
+		break;
+	}
 
 	v3_close_config_window();
 	spin_unlock_irqrestore(&v3_lock, flags);
@@ -330,50 +308,31 @@
 	return PCIBIOS_SUCCESSFUL;
 }
 
-static int v3_write_config_byte(struct pci_dev *dev, int where, u8 val)
-{
-	unsigned long addr;
-	unsigned long flags;
-
-	spin_lock_irqsave(&v3_lock, flags);
-	addr = v3_open_config_window(dev, where);
-
-	__raw_writeb(val, addr);
-	__raw_readb(addr);
-	
-	v3_close_config_window();
-	spin_unlock_irqrestore(&v3_lock, flags);
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int v3_write_config_word(struct pci_dev *dev, int where, u16 val)
+static int v3_write_config(struct pci_bus *bus, unsigned int devfn, int where,
+			   int size, u32 val)
 {
 	unsigned long addr;
 	unsigned long flags;
 
 	spin_lock_irqsave(&v3_lock, flags);
-	addr = v3_open_config_window(dev, where);
+	addr = v3_open_config_window(bus, devfn, where);
 
-	__raw_writew(val, addr);
-	__raw_readw(addr);
+	switch (size) {
+	case 1:
+		__raw_writeb((u8)val, addr);
+		__raw_readb(addr);
+		break;
 
-	v3_close_config_window();
-	spin_unlock_irqrestore(&v3_lock, flags);
+	case 2:
+		__raw_writew((u16)val, addr);
+		__raw_readw(addr);
+		break;
 
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int v3_write_config_dword(struct pci_dev *dev, int where, u32 val)
-{
-	unsigned long addr;
-	unsigned long flags;
-
-	spin_lock_irqsave(&v3_lock, flags);
-	addr = v3_open_config_window(dev, where);
-
-	__raw_writel(val, addr);
-	__raw_readl(addr);
+	case 4:
+		__raw_writel(val, addr);
+		__raw_readl(addr);
+		break;
+	}
 
 	v3_close_config_window();
 	spin_unlock_irqrestore(&v3_lock, flags);
@@ -382,12 +341,8 @@
 }
 
 static struct pci_ops pci_v3_ops = {
-	.read_byte	= v3_read_config_byte,
-	.read_word	= v3_read_config_word,
-	.read_dword	= v3_read_config_dword,
-	.write_byte	= v3_write_config_byte,
-	.write_word	= v3_write_config_word,
-	.write_dword	= v3_write_config_dword,
+	.read	= v3_read_config,
+	.write	= v3_write_config,
 };
 
 static struct resource non_mem = {
diff -Nru a/arch/arm/mach-iop310/Config.help b/arch/arm/mach-iop310/Config.help
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/arm/mach-iop310/Config.help	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,5 @@
+CONFIG_ARCH_IQ80310
+  Say Y here if you want to run your kernel on the Intel IQ80310
+  evaluation kit for the IOP310 chipset.
+
+
diff -Nru a/arch/arm/mach-iop310/Config.in b/arch/arm/mach-iop310/Config.in
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/arm/mach-iop310/Config.in	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,10 @@
+mainmenu_option next_comment
+comment 'IOP310 Implementation Options'
+dep_bool '  IQ80310' CONFIG_ARCH_IQ80310 $CONFIG_ARCH_IOP310
+comment 'IOP310 Chipset Features'
+dep_bool 'Support Intel 80312 Application Accelerator Unit (EXPERIMENTAL)' CONFIG_IOP310_AAU $CONFIG_ARCH_IOP310 $CONFIG_EXPERIMENTAL
+dep_bool 'Support Intel 80312 DMA (EXPERIMENTAL)' CONFIG_IOP310_DMA $CONFIG_ARCH_IOP310 $CONFIG_EXPERIMENTAL
+dep_bool 'Support Intel 80312 Messaging Unit (EXPERIMENTAL)' CONFIG_IOP310_MU $CONFIG_ARCH_IOP310 $CONFIG_EXPERIMENTAL
+dep_bool 'Support Intel 80312 Performance Monitor (EXPERIMENTAL)' CONFIG_IOP310_PMON $CONFIG_ARCH_IOP310 $CONFIG_EXPERIMENTAL
+endmenu
+
diff -Nru a/arch/arm/mach-iop310/iop310-pci.c b/arch/arm/mach-iop310/iop310-pci.c
--- a/arch/arm/mach-iop310/iop310-pci.c	Tue Oct  1 00:08:16 2002
+++ b/arch/arm/mach-iop310/iop310-pci.c	Tue Oct  1 00:08:16 2002
@@ -55,22 +55,23 @@
 #define  DBG(x...) do { } while (0)
 #endif
 
-extern int (*external_fault)(unsigned long, struct pt_regs *);
-
-static u32 iop310_cfg_address(struct pci_dev *dev, int where)
+/*
+ * Calculate the address, etc from the bus, devfn and register
+ * offset.  Note that we have two root buses, so we need some
+ * method to determine whether we need config type 0 or 1 cycles.
+ * We use a root bus number in our bus->sysdata structure for this.
+ */
+static u32 iop310_cfg_address(struct pci_bus *bus, int devfn, int where)
 {
-	struct pci_sys_data *sys = dev->sysdata;
+	struct pci_sys_data *sys = bus->sysdata;
 	u32 addr;
 
-	where &= ~3;
-
-	if (sys->busnr == dev->bus->number)
-		addr = 1 << (PCI_SLOT(dev->devfn) + 16);
+	if (sys->busnr == bus->number)
+		addr = 1 << (PCI_SLOT(devfn) + 16);
 	else
-		addr = dev->bus->number << 16 |
-		       PCI_SLOT(dev->devfn) << 11 | 1;
+		addr = bus->number << 16 | PCI_SLOT(devfn) << 11 | 1;
 
-	addr |=	PCI_FUNC(dev->devfn) << 8 | where;
+	addr |=	PCI_FUNC(devfn) << 8 | (where & ~3);
 
 	return addr;
 }
@@ -106,9 +107,13 @@
 	return ret;
 }
 
-static inline u32 iop310_pri_read(struct pci_dev *dev, int where)
+/*
+ * Simply write the address register and read the configuration
+ * data.  Note that the 4 nop's ensure that we are able to handle
+ * a delayed abort (in theory.)
+ */
+static inline u32 iop310_pri_read(unsigned long addr)
 {
-	unsigned long addr = iop310_cfg_address(dev, where);
 	u32 val;
 
 	__asm__ __volatile__(
@@ -125,111 +130,59 @@
 }
 
 static int
-iop310_pri_rd_cfg_byte(struct pci_dev *dev, int where, u8 *p)
-{
-	u8 val;
-
-	val = iop310_pri_read(dev, where) >> ((where & 3) * 8);
-
-	if (iop310_pri_pci_status())
-		val = 0xff;
-
-	*p = val;
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-iop310_pri_rd_cfg_word(struct pci_dev *dev, int where, u16 *p)
-{
-	u16 val;
-
-	val = iop310_pri_read(dev, where) >> ((where & 3) * 8);
-
-	if (iop310_pri_pci_status())
-		val = 0xffff;
-
-	*p = val;
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-iop310_pri_rd_cfg_dword(struct pci_dev *dev, int where, u32 *p)
+iop310_pri_read_config(struct pci_bus *bus, unsigned int devfn, int where,
+		       int size, u32 *value)
 {
-	u32 val;
-
-	val = iop310_pri_read(dev, where);
+	unsigned long addr = iop310_cfg_address(bus, devfn, where);
+	u32 val = iop310_pri_read(addr) >> ((where & 3) * 8);
 
 	if (iop310_pri_pci_status())
 		val = 0xffffffff;
 
-	*p = val;
+	*value = val;
 
 	return PCIBIOS_SUCCESSFUL;
 }
 
 static int
-iop310_pri_wr_cfg_byte(struct pci_dev *dev, int where, u8 v)
+iop310_pri_write_config(struct pci_bus *bus, unsigned int devfn, int where
+			int size, u32 value)
 {
+	unsigned long addr = iop310_cfg_address(bus, devfn, where);
 	u32 val;
 
-	val = iop310_pri_read(dev, where);
+	if (size != 4) {
+		val = iop310_pri_read(addr);
+		if (!iop310_pri_pci_status() == 0)
+			return PCIBIOS_SUCCESSFUL;
 
-	if (iop310_pri_pci_status() == 0) {
 		where = (where & 3) * 8;
-		val &= ~(0xff << where);
-		val |= v << where;
-		*IOP310_POCCDR = val;
-	}
-
-	return PCIBIOS_SUCCESSFUL;
-}
 
-static int
-iop310_pri_wr_cfg_word(struct pci_dev *dev, int where, u16 v)
-{
-	u32 val;
-
-	val = iop310_pri_read(dev, where);
-
-	if (iop310_pri_pci_status() == 0) {
-		where = (where & 2) * 8;
-		val &= ~(0xffff << where);
-		val |= v << where;
-		*IOP310_POCCDR = val;
+		if (size == 1)
+			val &= ~(0xff << where);
+		else
+			val &= ~(0xffff << where);
+
+		*IOP310_POCCDR = val | v << where;
+	} else {
+		asm volatile(
+			"str	%1, [%2]\n\t"
+			"str	%0, [%3]\n\t"
+			"nop\n\t"
+			"nop\n\t"
+			"nop\n\t"
+			"nop\n\t"
+			:
+			: "r" (val), "r" (addr),
+			  "r" (IOP310_POCCAR), "r" (IOP310_POCCDR));
 	}
 
 	return PCIBIOS_SUCCESSFUL;
 }
 
-static int
-iop310_pri_wr_cfg_dword(struct pci_dev *dev, int where, u32 val)
-{
-	unsigned long addr;
-
-	addr = iop310_cfg_address(dev, where);
-
-	__asm__ __volatile__(
-		"str	%1, [%2]\n\t"
-		"str	%0, [%3]\n\t"
-		"nop\n\t"
-		"nop\n\t"
-		"nop\n\t"
-		"nop\n\t"
-		:
-		: "r" (val), "r" (addr), "r" (IOP310_POCCAR), "r" (IOP310_POCCDR));
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
 static struct pci_ops iop310_primary_ops = {
-	iop310_pri_rd_cfg_byte,
-	iop310_pri_rd_cfg_word,
-	iop310_pri_rd_cfg_dword,
-	iop310_pri_wr_cfg_byte,
-	iop310_pri_wr_cfg_word,
-	iop310_pri_wr_cfg_dword,
+	.read	= iop310_pri_read_config,
+	.write	= iop310_pri_write_config,
 };
 
 /*
@@ -255,9 +208,13 @@
 	return ret;
 }
 
-static inline u32 iop310_sec_read(struct pci_dev *dev, int where)
+/*
+ * Simply write the address register and read the configuration
+ * data.  Note that the 4 nop's ensure that we are able to handle
+ * a delayed abort (in theory.)
+ */
+static inline u32 iop310_sec_read(unsigned long addr)
 {
-	unsigned long addr = iop310_cfg_address(dev, where);
 	u32 val;
 
 	__asm__ __volatile__(
@@ -274,111 +231,60 @@
 }
 
 static int
-iop310_sec_rd_cfg_byte(struct pci_dev *dev, int where, u8 *p)
-{
-	u8 val;
-
-	val = iop310_sec_read(dev, where) >> ((where & 3) * 8);
-
-	if (iop310_sec_pci_status())
-		val = 0xff;
-
-	*p = val;
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-iop310_sec_rd_cfg_word(struct pci_dev *dev, int where, u16 *p)
+iop310_sec_read_config(struct pci_bus *bus, unsigned int devfn, int where,
+		       int size, u32 *value)
 {
-	u16 val;
-
-	val = iop310_sec_read(dev, where) >> ((where & 3) * 8);
-
-	if (iop310_sec_pci_status())
-		val = 0xffff;
-
-	*p = val;
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-iop310_sec_rd_cfg_dword(struct pci_dev *dev, int where, u32 *p)
-{
-	u32 val;
-
-	val = iop310_sec_read(dev, where);
+	unsigned long addr = iop310_cfg_address(bus, devfn, where);
+	u32 val = iop310_sec_read(addr) >> ((where & 3) * 8);
 
 	if (iop310_sec_pci_status())
 		val = 0xffffffff;
 
-	*p = val;
+	*value = val;
 
 	return PCIBIOS_SUCCESSFUL;
 }
 
 static int
-iop310_sec_wr_cfg_byte(struct pci_dev *dev, int where, u8 v)
+iop310_sec_write_config(struct pci_bus *bus, unsigned int devfn, int where
+			int size, u32 value)
 {
+	unsigned long addr = iop310_cfg_address(bus, devfn, where);
 	u32 val;
 
-	val = iop310_sec_read(dev, where);
+	if (size != 4) {
+		val = iop310_sec_read(addr);
 
-	if (iop310_sec_pci_status() == 0) {
-		where = (where & 3) * 8;
-		val &= ~(0xff << where);
-		val |= v << where;
-		*IOP310_SOCCDR = val;
-	}
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-iop310_sec_wr_cfg_word(struct pci_dev *dev, int where, u16 v)
-{
-	u32 val;
+		if (!iop310_sec_pci_status() == 0)
+			return PCIBIOS_SUCCESSFUL;
 
-	val = iop310_sec_read(dev, where);
+		where = (where & 3) * 8;
 
-	if (iop310_sec_pci_status() == 0) {
-		where = (where & 2) * 8;
-		val &= ~(0xffff << where);
-		val |= v << where;
-		*IOP310_SOCCDR = val;
+		if (size == 1)
+			val &= ~(0xff << where);
+		else
+			val &= ~(0xffff << where);
+
+		*IOP310_SOCCDR = val | v << where;
+	} else {
+		asm volatile(
+			"str	%1, [%2]\n\t"
+			"str	%0, [%3]\n\t"
+			"nop\n\t"
+			"nop\n\t"
+			"nop\n\t"
+			"nop\n\t"
+			:
+			: "r" (val), "r" (addr),
+			  "r" (IOP310_SOCCAR), "r" (IOP310_SOCCDR));
 	}
 
 	return PCIBIOS_SUCCESSFUL;
 }
 
-static int
-iop310_sec_wr_cfg_dword(struct pci_dev *dev, int where, u32 val)
-{
-	unsigned long addr;
-
-	addr = iop310_cfg_address(dev, where);
-
-	__asm__ __volatile__(
-		"str	%1, [%2]\n\t"
-		"str	%0, [%3]\n\t"
-		"nop\n\t"
-		"nop\n\t"
-		"nop\n\t"
-		"nop\n\t"
-		:
-		: "r" (val), "r" (addr), "r" (IOP310_SOCCAR), "r" (IOP310_SOCCDR));
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
 static struct pci_ops iop310_secondary_ops = {
-	iop310_sec_rd_cfg_byte,
-	iop310_sec_rd_cfg_word,
-	iop310_sec_rd_cfg_dword,
-	iop310_sec_wr_cfg_byte,
-	iop310_sec_wr_cfg_word,
-	iop310_sec_wr_cfg_dword,
+	.read	= iop310_sec_read_config,
+	.write	= iop310_sec_write_config,
 };
 
 /*
@@ -524,5 +430,5 @@
 	 */
 	*IOP310_PCR &= 0xfff8;
 
-	hook_fault_code(6, iop310_pci_abort, SIGBUS, "imprecise external abort");
+	hook_fault_code(16+6, iop310_pci_abort, SIGBUS, "imprecise external abort");
 }
diff -Nru a/arch/arm/mach-pxa/Config.in b/arch/arm/mach-pxa/Config.in
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/arm/mach-pxa/Config.in	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,6 @@
+mainmenu_option next_comment
+comment 'Intel PXA250/210 Implementations'
+dep_bool '  Intel DBPXA250 Development Platform' CONFIG_ARCH_LUBBOCK $CONFIG_ARCH_PXA
+dep_bool '  Accelent Xscale IDP' CONFIG_ARCH_PXA_IDP $CONFIG_ARCH_PXA
+endmenu
+
diff -Nru a/arch/arm/mach-pxa/dma.c b/arch/arm/mach-pxa/dma.c
--- a/arch/arm/mach-pxa/dma.c	Tue Oct  1 00:08:21 2002
+++ b/arch/arm/mach-pxa/dma.c	Tue Oct  1 00:08:21 2002
@@ -81,9 +81,9 @@
 	unsigned long flags;
 
 	if (!dma_channels[dma_ch].name) {
-		printk (KERN_CRIT __FUNCTION__
-			": trying to free channel %d which is already freed\n",
-			dma_ch);
+		printk (KERN_CRIT
+			"%s: trying to free channel %d which is already freed\n",
+			__FUNCTION__, dma_ch);
 		return;
 	}
 
@@ -124,7 +124,7 @@
 	return ret;
 }
 
-__initcall(pxa_dma_init);
+arch_initcall(pxa_dma_init);
 
 EXPORT_SYMBOL(pxa_request_dma);
 EXPORT_SYMBOL(pxa_free_dma);
diff -Nru a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c
--- a/arch/arm/mach-pxa/idp.c	Tue Oct  1 00:08:13 2002
+++ b/arch/arm/mach-pxa/idp.c	Tue Oct  1 00:08:13 2002
@@ -9,6 +9,8 @@
  *
  *  2001-09-13: Cliff Brake <cbrake@accelent.com>
  *              Initial code
+ *
+ * Expected command line: mem=32M initrd=0xa1000000,4M root=/dev/ram ramdisk=8192
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -29,8 +31,6 @@
 
 #include "generic.h"
 
-#define PXA_IDP_REV02
-
 #ifndef PXA_IDP_REV02
 /* shadow registers for write only registers */
 unsigned int idp_cpld_led_control_shadow = 0x1;
@@ -103,8 +103,18 @@
 	pxa_map_io();
 	iotable_init(idp_io_desc, ARRAY_SIZE(idp_io_desc));
 
-	set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(TOUCH_PANEL_IRQ), TOUCH_PANEL_IRQ_EDGE);
+	set_irq_type(IRQ_TO_GPIO_2_80(TOUCH_PANEL_IRQ), TOUCH_PANEL_IRQ_EDGE);
+
+	// serial ports 2 & 3
+	pxa_gpio_mode(GPIO42_BTRXD_MD);
+	pxa_gpio_mode(GPIO43_BTTXD_MD);
+	pxa_gpio_mode(GPIO44_BTCTS_MD);
+	pxa_gpio_mode(GPIO45_BTRTS_MD);
+	pxa_gpio_mode(GPIO46_STRXD_MD);
+	pxa_gpio_mode(GPIO47_STTXD_MD);
+
 }
+
 
 MACHINE_START(PXA_IDP, "Accelent Xscale IDP")
 	MAINTAINER("Accelent Systems Inc.")
diff -Nru a/arch/arm/mach-rpc/riscpc.c b/arch/arm/mach-rpc/riscpc.c
--- a/arch/arm/mach-rpc/riscpc.c	Tue Oct  1 00:08:15 2002
+++ b/arch/arm/mach-rpc/riscpc.c	Tue Oct  1 00:08:15 2002
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 
 #include <asm/elf.h>
+#include <asm/io.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 #include <asm/hardware.h>
@@ -70,6 +71,11 @@
 void __init rpc_map_io(void)
 {
 	iotable_init(rpc_io_desc, ARRAY_SIZE(rpc_io_desc));
+
+	/*
+	 * Turn off floppy.
+	 */
+	outb(0xc, 0x3f2);
 
 	/*
 	 * RiscPC can't handle half-word loads and stores
diff -Nru a/arch/arm/mach-sa1100/Config.help b/arch/arm/mach-sa1100/Config.help
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/arm/mach-sa1100/Config.help	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,189 @@
+CONFIG_SA1100_ASSABET
+  Say Y here if you are using the Intel(R) StrongARM(R) SA-1110
+  Microprocessor Development Board (also known as the Assabet).
+
+CONFIG_ASSABET_NEPONSET
+  Say Y here if you are using the Intel(R) StrongARM(R) SA-1110
+  Microprocessor Development Board (Assabet)  with the SA-1111
+  Development Board (Nepon).
+
+CONFIG_SA1100_ADSBITSY
+  Say Y here if you are using Applied Data Systems Intel(R)
+  StrongARM(R) 1110 based Bitsy, 3 x 5 inches in size, Compaq - IPAQ -
+  like platform. See
+  <http://www.applieddata.net/products_bitsySpec.asp> for more
+  information.
+
+CONFIG_SA1100_BRUTUS
+  Say Y here if you are using the Intel(R) StrongARM(R) SA-1100
+  Microprocessor Development Board (also known as the Brutus).
+
+CONFIG_SA1100_CERF
+  The Intrinsyc CerfBoard is based on the StrongARM 1110.
+  More information is available at:
+  <http://www.intrinsyc.com/products/referenceplatforms/cerfboard.html>.
+
+  Say Y if configuring for an Intrinsyc CerfBoard.
+  Say N otherwise.
+
+CONFIG_SA1100_CERF_CPLD
+  Say Y here to support the Linux CerfPDA development kit from
+  Intrinsyc. This is a StrongARM-1110-based reference platform for
+  designing custom PDAs.  Product info is at
+  <http://www.intrinsyc.com/products/referencedesigns/cerfpda.asp>.
+
+CONFIG_SA1100_H3100
+  Say Y here if you intend to run this kernel on the Compaq iPAQ
+  H3100 handheld computer.  Information about this machine and the
+  Linux port to this machine can be found at:
+
+  <http://www.handhelds.org/Compaq/index.html#iPAQ_H3100>
+  <http://www.compaq.com/products/handhelds/pocketpc/>
+
+CONFIG_SA1100_H3600
+  Say Y here if you intend to run this kernel on the Compaq iPAQ
+  H3600 handheld computer.  Information about this machine and the
+  Linux port to this machine can be found at:
+
+  <http://www.handhelds.org/Compaq/index.html#iPAQ_H3600>
+  <http://www.compaq.com/products/handhelds/pocketpc/>
+
+CONFIG_SA1100_H3800
+  Say Y here if you intend to run this kernel on the Compaq iPAQ H3800
+  series handheld computer.  Information about this machine and the
+  Linux port to this machine can be found at:
+
+  <http://www.handhelds.org/Compaq/index.html#iPAQ_H3800>
+  <http://www.compaq.com/products/handhelds/pocketpc/>
+
+CONFIG_H3600_SLEEVE
+  Choose this option to enable support for extension packs (sleeves)
+  for the Compaq iPAQ H3XXX series of handheld computers.  This option
+  is required for the CF, PCMCIA, Bluetooth and GSM/GPRS extension
+  packs.
+
+CONFIG_SA1100_FLEXANET
+  Say Y here if you intend to run this kernel on the FlexaNet
+  handheld instruments. Information about this machine can be
+  found at: <http://www.flexanet.com/>.
+
+CONFIG_SA1100_FREEBIRD
+  Support the FreeBird board used in Coventive embedded products.  See
+  Documentation/arm/SA1100/Freebird for more.
+
+CONFIG_SA1100_GRAPHICSCLIENT
+  Say Y here if you are using an Applied Data Systems Intel(R)
+  StrongARM(R) SA-1100 based Graphics Client SBC.  See
+  <http://www.flatpanels.com/> for information on this system.
+
+CONFIG_SA1100_GRAPHICSMASTER
+  Say Y here if you are using an Applied Data Systems Intel(R)
+  StrongARM(R) SA-1100 based Graphics Master SBC with SA-1111
+  StrongARM companion chip.  See
+  <http://www.applieddata.net/products_masterSpec.asp> for information
+  on this system.
+
+CONFIG_SA1100_BADGE4
+  Say Y here if you want to build a kernel for the HP Laboratories
+  BadgePAD 4.
+
+CONFIG_SA1100_JORNADA720
+  Say Y here if you want to build a kernel for the HP Jornada 720
+  handheld computer.  See <http://www.hp.com/jornada/products/720>
+  for details.
+
+CONFIG_SA1100_HUW_WEBPANEL
+  Say Y here to support the HuW Webpanel produced by Hoeft & Wessel
+  AG.  English-language website is at
+  <http://www.hoeft-wessel.de/en.htm>; credits and build instructions
+  at Documentation/arm/SA1100/HUW_WEBPANEL.
+
+CONFIG_SA1100_ITSY
+  Say Y here if you are using the Compaq Itsy experimental pocket
+  computer. See <http://research.compaq.com/wrl/projects/itsy/> for
+  more information.
+
+CONFIG_SA1100_LART
+  Say Y here if you are using the Linux Advanced Radio Terminal
+  (also known as the LART).  See <http://www.lart.tudelft.nl/> for
+  information on the LART.
+
+CONFIG_SA1100_NANOENGINE
+  The nanoEngine is a StrongARM 1110-based single board computer
+  from Bright Star Engineering. More information is available at:
+  <http://www.brightstareng.com/arm/nanoeng.htm>.
+
+  Say Y if configuring for a nanoEngine.
+  Say N otherwise.
+
+CONFIG_SA1100_OMNIMETER
+  Say Y here if you are using the inhand electronics OmniMeter.  See
+  <http://www.inhandelectronics.com/html/omni1.html> for details.
+
+CONFIG_SA1100_PANGOLIN
+  Pangolin is a StrongARM 1110-based evaluation platform produced
+  by Dialogue Technology.  It has EISA slots for ease of configuration
+  with SDRAM/Flash memory card, USB/Serial/Audio card, Compact Flash
+  card, and TFT-LCD card.
+
+  Say Y if configuring for a Pangolin.
+  Say N otherwise.
+
+CONFIG_SA1100_PLEB
+  Say Y here if you are using a Portable Linux Embedded Board
+  (also known as PLEB). See <http://www.cse.unsw.edu.au/~pleb/>
+  for more information.
+
+CONFIG_SA1100_PT_SYSTEM3
+   Say Y here if you intend to build a kernel suitable to run on
+   a Pruftechnik Digital Board. For more information see
+   <http://www.pruftechnik.com>
+
+CONFIG_SA1100_SHANNON
+  The Shannon (also known as a Tuxscreen, and also as a IS2630) was a
+  limited edition webphone produced by Philips. The Shannon is a SA1100
+  platform with a 640x480 LCD, touchscreen, CIR keyboard, PCMCIA slots,
+  and a telco interface.
+
+CONFIG_SA1100_SHERMAN
+  Say Y here to support the Blazie Engineering `Sherman' StrongARM
+  1110-based SBC, used primarily in assistance products for the
+  visually impaired.  The company is now Freedom Scientific, with
+  a website at <http://www.freedomscientific.com/index.html>. The
+  Sherman product, however, appears to have been discontinued.
+
+CONFIG_SA1100_SIMPAD
+  The SIEMENS webpad SIMpad is based on the StrongARM 1110. There
+  are two different versions CL4 and SL4. CL4 has 32MB RAM and 16MB
+  FLASH. The SL4 version got 64 MB RAM and 32 MB FLASH and a
+  PCMCIA-Slot. The version for the Germany Telecom (DTAG) is the same
+  like CL4 in additional it has a PCMCIA-Slot. For more information
+  visit <http://www.my-siemens.com or www.siemens.ch>.
+
+CONFIG_SA1100_PFS168
+  The Radisys Corp. PFS-168 (aka Tulsa) is an IntelŪ StrongArmŪ SA-1110 based
+  computer which includes the SA-1111 Microprocessor Companion Chip and other
+  custom I/O designed to add connectivity and multimedia features for vending
+  and business machine applications. Say Y here if you require support for
+  this target.
+
+CONFIG_SA1100_VICTOR
+  Say Y here if you are using a Visu Aide Intel(R) StrongARM(R)
+  SA-1100 based Victor Digital Talking Book Reader.  See
+  <http://www.visuaide.com/pagevictor.en.html> for information on
+  this system.
+
+CONFIG_SA1100_XP860
+  :: Config help missing ::
+  :: 06 August 2002 ::
+
+CONFIG_SA1100_YOPY
+  Say Y here to support the Yopy PDA.  Product information at
+  <http://www.yopy.com/>.  See Documentation/arm/SA110/Yopy
+  for more.
+
+CONFIG_SA1100_STORK
+  Say Y here if you intend to run this kernel on the Stork
+  handheld computer.
+
+
diff -Nru a/arch/arm/mach-sa1100/Config.in b/arch/arm/mach-sa1100/Config.in
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/arm/mach-sa1100/Config.in	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,58 @@
+mainmenu_option next_comment
+comment 'SA11x0 Implementations'
+dep_bool '  Assabet' CONFIG_SA1100_ASSABET $CONFIG_ARCH_SA1100
+dep_bool '    Include support for Neponset' CONFIG_ASSABET_NEPONSET $CONFIG_SA1100_ASSABET
+dep_bool '  ADS Bitsy' CONFIG_SA1100_ADSBITSY $CONFIG_ARCH_SA1100
+dep_bool '  Brutus' CONFIG_SA1100_BRUTUS $CONFIG_ARCH_SA1100
+dep_bool '  CerfBoard' CONFIG_SA1100_CERF $CONFIG_ARCH_SA1100
+if [ "$CONFIG_SA1100_CERF" = "y" ]; then
+   choice 'Cerf Flash available'  \
+        "8MB    CONFIG_SA1100_CERF_FLASH_8MB \
+         16MB   CONFIG_SA1100_CERF_FLASH_16MB \
+         32MB   CONFIG_SA1100_CERF_FLASH_32MB" 8MB
+   bool 'Cerf w/CPLD support (CerfPDA)' CONFIG_SA1100_CERF_CPLD
+fi
+dep_bool '  Compaq iPAQ H3100' CONFIG_SA1100_H3100 $CONFIG_ARCH_SA1100
+dep_bool '  Compaq iPAQ H3600/H3700' CONFIG_SA1100_H3600 $CONFIG_ARCH_SA1100
+dep_bool '  Compaq iPAQ H3800' CONFIG_SA1100_H3800 $CONFIG_ARCH_SA1100
+if [ "$CONFIG_SA1100_H3100" = "y" -o "$CONFIG_SA1100_H3600" = "y" -o "$CONFIG_SA1100_H3800" = "y" ]; then
+  define_bool CONFIG_SA1100_H3XXX y
+else
+  define_bool CONFIG_SA1100_H3XXX n
+fi
+#dep_bool '  Consus' CONFIG_SA1100_CONSUS $CONFIG_ARCH_SA1100
+#dep_bool '  Empeg' CONFIG_SA1100_EMPEG $CONFIG_ARCH_SA1100
+dep_bool '  Extenex HandHeld Theater (Squashtail)' CONFIG_SA1100_EXTENEX1 $CONFIG_ARCH_SA1100
+if [ "$CONFIG_SA1100_EXTENEX1" = "y" ]; then
+   bool '    Support 16 MB of DRAM (not just 8)' CONFIG_SA1100_EXTENEX1_16MB
+fi
+dep_bool '  FlexaNet' CONFIG_SA1100_FLEXANET $CONFIG_ARCH_SA1100
+dep_bool '  FreeBird-v1.1' CONFIG_SA1100_FREEBIRD $CONFIG_ARCH_SA1100
+dep_bool '  GraphicsClient Plus' CONFIG_SA1100_GRAPHICSCLIENT $CONFIG_ARCH_SA1100
+dep_bool '  GraphicsMaster' CONFIG_SA1100_GRAPHICSMASTER $CONFIG_ARCH_SA1100
+dep_bool '  HP Labs BadgePAD 4' CONFIG_SA1100_BADGE4 $CONFIG_ARCH_SA1100
+dep_bool '  HP Jornada 720' CONFIG_SA1100_JORNADA720 $CONFIG_ARCH_SA1100
+dep_bool '  HuW WebPanel' CONFIG_SA1100_HUW_WEBPANEL $CONFIG_ARCH_SA1100
+dep_bool '  Itsy' CONFIG_SA1100_ITSY $CONFIG_ARCH_SA1100
+dep_bool '  LART' CONFIG_SA1100_LART $CONFIG_ARCH_SA1100
+dep_bool '  nanoEngine' CONFIG_SA1100_NANOENGINE $CONFIG_ARCH_SA1100
+dep_bool '  OmniMeter' CONFIG_SA1100_OMNIMETER $CONFIG_ARCH_SA1100
+dep_bool '  Pangolin' CONFIG_SA1100_PANGOLIN $CONFIG_ARCH_SA1100
+dep_bool '  PLEB' CONFIG_SA1100_PLEB $CONFIG_ARCH_SA1100
+dep_bool '  PT System 3' CONFIG_SA1100_PT_SYSTEM3 $CONFIG_ARCH_SA1100
+dep_bool '  Shannon' CONFIG_SA1100_SHANNON $CONFIG_ARCH_SA1100
+dep_bool '  Sherman' CONFIG_SA1100_SHERMAN $CONFIG_ARCH_SA1100
+dep_bool '  Simpad' CONFIG_SA1100_SIMPAD $CONFIG_ARCH_SA1100
+dep_bool '  Tulsa' CONFIG_SA1100_PFS168 $CONFIG_ARCH_SA1100
+dep_bool '  Victor' CONFIG_SA1100_VICTOR $CONFIG_ARCH_SA1100
+dep_bool '  XP860' CONFIG_SA1100_XP860 $CONFIG_ARCH_SA1100
+dep_bool '  Yopy' CONFIG_SA1100_YOPY $CONFIG_ARCH_SA1100
+dep_bool '  Stork' CONFIG_SA1100_STORK $CONFIG_ARCH_SA1100
+
+dep_tristate 'SA1100 USB function support' CONFIG_SA1100_USB $CONFIG_ARCH_SA1100
+dep_tristate '  Support for SA11x0 USB network link function' CONFIG_SA1100_USB_NETLINK $CONFIG_SA1100_USB
+dep_tristate '  Support for SA11x0 USB character device emulation' CONFIG_SA1100_USB_CHAR $CONFIG_SA1100_USB
+
+dep_tristate 'Compaq iPAQ Handheld sleeve support' CONFIG_H3600_SLEEVE $CONFIG_SA1100_H3600
+endmenu
+
diff -Nru a/arch/arm/mach-sa1100/Makefile b/arch/arm/mach-sa1100/Makefile
--- a/arch/arm/mach-sa1100/Makefile	Tue Oct  1 00:08:21 2002
+++ b/arch/arm/mach-sa1100/Makefile	Tue Oct  1 00:08:21 2002
@@ -9,8 +9,8 @@
 obj-  :=
 led-y := leds.o
 
-export-objs :=	dma.o generic.o irq.o pcipool.o sa1111.o sa1111-pcibuf.o \
-		usb_ctl.o usb_recv.o usb_send.o pm.o
+export-objs :=	dma.o generic.o pcipool.o pm.o sa1111.o sa1111-pcibuf.o \
+		usb_ctl.o usb_recv.o usb_send.o
 
 # This needs to be cleaned up.  We probably need to have SA1100
 # and SA1110 config symbols.
@@ -24,8 +24,8 @@
 endif
 
 # Next, the SA1111 stuff.
-obj-$(CONFIG_SA1111)		+= sa1111.o
-obj-$(CONFIG_USB_OHCI_SA1111)	+= sa1111-pcibuf.o pcipool.o
+obj-$(CONFIG_SA1111)			+= sa1111.o
+obj-$(CONFIG_USB_OHCI_HCD)		+= sa1111-pcibuf.o pcipool.o
 
 # Specific board support
 obj-$(CONFIG_SA1100_ADSBITSY)		+= adsbitsy.o
diff -Nru a/arch/arm/mach-sa1100/adsbitsy.c b/arch/arm/mach-sa1100/adsbitsy.c
--- a/arch/arm/mach-sa1100/adsbitsy.c	Tue Oct  1 00:08:14 2002
+++ b/arch/arm/mach-sa1100/adsbitsy.c	Tue Oct  1 00:08:14 2002
@@ -28,7 +28,6 @@
 #include <asm/mach/serial_sa1100.h>
 
 #include "generic.h"
-#include "sa1111.h"
 
 static int __init adsbitsy_init(void)
 {
@@ -53,7 +52,7 @@
 	/*
 	 * Probe for SA1111.
 	 */
-	ret = sa1111_init(NULL, 0x18000000, IRQ_GPIO0);
+	ret = sa1111_init(0x18000000, IRQ_GPIO0);
 	if (ret < 0)
 		return ret;
 
@@ -69,7 +68,7 @@
 	return 0;
 }
 
-__initcall(adsbitsy_init);
+arch_initcall(adsbitsy_init);
 
 static void __init adsbitsy_init_irq(void)
 {
diff -Nru a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
--- a/arch/arm/mach-sa1100/assabet.c	Tue Oct  1 00:08:14 2002
+++ b/arch/arm/mach-sa1100/assabet.c	Tue Oct  1 00:08:14 2002
@@ -18,6 +18,7 @@
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/serial_core.h>
+#include <linux/delay.h>
 
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
@@ -73,12 +74,19 @@
 		ASSABET_BCR_clear(ASSABET_BCR_LIGHT_ON);
 }
 
+/*
+ * Turn on/off the backlight.  When turning the backlight on,
+ * we wait 500us after turning it on so we don't cause the
+ * supplies to droop when we enable the LCD controller (and
+ * cause a hard reset.)
+ */
 static void assabet_lcd_power(int on)
 {
 #ifndef ASSABET_PAL_VIDEO
-	if (on)
+	if (on) {
 		ASSABET_BCR_set(ASSABET_BCR_LCD_ON);
-	else
+		udelay(500);
+	} else
 #endif
 		ASSABET_BCR_clear(ASSABET_BCR_LCD_ON);
 }
@@ -89,6 +97,12 @@
 		return -EINVAL;
 
 	/*
+	 * Ensure that the power supply is in "high power" mode.
+	 */
+	GPDR |= GPIO_GPIO16;
+	GPSR = GPIO_GPIO16;
+
+	/*
 	 * Ensure that these pins are set as outputs and are driving
 	 * logic 0.  This ensures that we won't inadvertently toggle
 	 * the WS latch in the CPLD, and we don't float causing
@@ -126,7 +140,7 @@
 	return 0;
 }
 
-__initcall(assabet_init);
+arch_initcall(assabet_init);
 
 
 /*
diff -Nru a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c
--- a/arch/arm/mach-sa1100/badge4.c	Tue Oct  1 00:08:15 2002
+++ b/arch/arm/mach-sa1100/badge4.c	Tue Oct  1 00:08:15 2002
@@ -32,7 +32,6 @@
 #include <asm/mach/serial_sa1100.h>
 
 #include "generic.h"
-#include "sa1111.h"
 
 static int __init badge4_sa1111_init(void)
 {
@@ -45,7 +44,7 @@
 	/*
 	 * Probe for SA1111.
 	 */
-	return sa1111_init(NULL, BADGE4_SA1111_BASE, BADGE4_IRQ_GPIO_SA1111);
+	return sa1111_init(BADGE4_SA1111_BASE, BADGE4_IRQ_GPIO_SA1111);
 }
 
 static int __init badge4_init(void)
@@ -57,8 +56,9 @@
 
 	ret = badge4_sa1111_init();
 	if (ret < 0)
-		printk(KERN_ERR __FUNCTION__
-		       ": SA-1111 initialization failed (%d)\n", ret);
+		printk(KERN_ERR
+		       "%s: SA-1111 initialization failed (%d)\n",
+			__FUNCTION__, ret);
 
 	/* N.B, according to rmk this is the singular place that GPDR
            should be set */
@@ -109,7 +109,7 @@
 	return 0;
 }
 
-__initcall(badge4_init);
+arch_initcall(badge4_init);
 
 
 static unsigned badge4_5V_bitmap = 0;
@@ -132,11 +132,11 @@
 	/* detect on->off and off->on transitions */
 	if ((!old_5V_bitmap) && (badge4_5V_bitmap)) {
 		/* was off, now on */
-		printk(KERN_INFO __FUNCTION__ ": enabling 5V supply rail\n");
+		printk(KERN_INFO "%s: enabling 5V supply rail\n", __FUNCTION__);
 		GPSR = BADGE4_GPIO_PCMEN5V;
 	} else if ((old_5V_bitmap) && (!badge4_5V_bitmap)) {
 		/* was on, now off */
-		printk(KERN_INFO __FUNCTION__ ": disabling 5V supply rail\n");
+		printk(KERN_INFO "%s: disabling 5V supply rail\n", __FUNCTION__);
 		GPCR = BADGE4_GPIO_PCMEN5V;
 	}
 
diff -Nru a/arch/arm/mach-sa1100/cpu-sa1100.c b/arch/arm/mach-sa1100/cpu-sa1100.c
--- a/arch/arm/mach-sa1100/cpu-sa1100.c	Tue Oct  1 00:08:15 2002
+++ b/arch/arm/mach-sa1100/cpu-sa1100.c	Tue Oct  1 00:08:15 2002
@@ -90,9 +90,7 @@
 
 #include <asm/hardware.h>
 
-extern unsigned int sa11x0_freq_to_ppcr(unsigned int khz);
-extern unsigned int sa11x0_validatespeed(unsigned int cpu, unsigned int khz);
-extern unsigned int sa11x0_getspeed(void);
+#include "generic.h"
 
 typedef struct {
 	int speed;
@@ -107,7 +105,7 @@
 
 static sa1100_dram_regs_t sa1100_dram_settings[] =
 {
-	/* { mdcnfg, mdcas0, mdcas1, mdcas2 } */ /* clock frequency */
+	/* speed,     mdcnfg,     mdcas0,     mdcas1,     mdcas2  clock frequency */
 	{  59000, 0x00dc88a3, 0xcccccccf, 0xfffffffc, 0xffffffff }, /*  59.0 MHz */
 	{  73700, 0x011490a3, 0xcccccccf, 0xfffffffc, 0xffffffff }, /*  73.7 MHz */
 	{  88500, 0x014e90a3, 0xcccccccf, 0xfffffffc, 0xffffffff }, /*  88.5 MHz */
@@ -127,28 +125,25 @@
 	{ 0, 0, 0, 0, 0 } /* last entry */
 };
 
-
-
-
 static void sa1100_update_dram_timings(int current_speed, int new_speed)
 {
 	sa1100_dram_regs_t *settings = sa1100_dram_settings;
 
 	/* find speed */
-	while(settings->speed != 0) {
+	while (settings->speed != 0) {
 		if(new_speed == settings->speed)
 			break;
 		
 		settings++;
 	}
 
-	if(settings->speed == 0) {
+	if (settings->speed == 0) {
 		panic("%s: couldn't find dram setting for speed %d\n",
 		      __FUNCTION__, new_speed);
 	}
 
 	/* No risk, no fun: run with interrupts on! */
-	if(new_speed > current_speed) {
+	if (new_speed > current_speed) {
 		/* We're going FASTER, so first relax the memory
 		 * timings before changing the core frequency 
 		 */
@@ -181,60 +176,39 @@
 	}
 }
 
-
-
-
-static int sa1100_dram_notifier(struct notifier_block *nb, 
-				unsigned long val, void *data)
+static void sa1100_setspeed(struct cpufreq_policy *policy)
 {
-	struct cpufreq_freqs *ci = data;
-	
-	switch(val) {
-	case CPUFREQ_MINMAX:
-		cpufreq_updateminmax(data, sa1100_dram_settings->speed, -1);
-		break;
-
-	case CPUFREQ_PRECHANGE:
-		if(ci->new > ci->cur)
-			sa1100_update_dram_timings(ci->cur, ci->new);
-		break;
-
-	case CPUFREQ_POSTCHANGE:
-		if(ci->new < ci->cur)
-			sa1100_update_dram_timings(ci->cur, ci->new);
-		break;
-		
-	default:
-		printk(KERN_INFO "%s: ignoring unknown notifier type (%ld)\n",
-		       __FUNCTION__, val);
-	}
-
-	return 0;
-}
+	unsigned int cur = sa11x0_getspeed();
+	struct cpufreq_freqs freqs;
 
+	freqs.old = cur;
+	freqs.new = policy->max;
+	freqs.cpu = CPUFREQ_ALL_CPUS;
 
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 
+	if (policy->max > cur)
+		sa1100_update_dram_timings(cur, policy->max);
 
-static struct notifier_block sa1100_dram_block = {
-	.notifier_call	= sa1100_dram_notifier,
-};
+	PPCR = sa11x0_freq_to_ppcr(policy->max);
 
+	if (policy->max < cur)
+		sa1100_update_dram_timings(cur, policy->max);
 
-static void sa1100_setspeed(unsigned int cpu, unsigned int khz)
-{
-	PPCR = sa11x0_freq_to_ppcr(khz);
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 }
 
-static struct cpufreq_freqs sa1100_freqs = {
-	.min		= 59000,
-	.max		= 287000,
+static struct cpufreq_policy sa1100_policy = {
+	.cpu		= 0,
+	.policy		= CPUFREQ_POLICY_POWERSAVE,
+	.max_cpu_freq	= 287000,
 };
 
 static struct cpufreq_driver sa1100_driver = {
-	.freq		= &sa1100_freqs,
-	.validate	= sa11x0_validatespeed,
-	.setspeed	= sa1100_setspeed,
-	.sync		= 1,
+	.verify		= sa11x0_verify_speed,
+	.setpolicy	= sa1100_setspeed,
+	.policy		= &sa1100_policy,
+	.cpu_min_freq	= 59000,
 };
 
 static int __init sa1100_dram_init(void)
@@ -242,11 +216,9 @@
 	int ret = -ENODEV;
 
 	if ((processor_id & CPU_SA1100_MASK) == CPU_SA1100_ID) {
-		ret = cpufreq_register_notifier(&sa1100_dram_block);
-		if (ret)
-			return ret;
-
-		sa1100_freqs.cur = sa11x0_getspeed();
+		sa1100_driver.cpu_curr_freq[0] =
+		sa1100_policy.min =
+		sa1100_policy.max = sa11x0_getspeed();
 
 		ret = cpufreq_register(&sa1100_driver);
 	}
@@ -254,4 +226,4 @@
 	return ret;
 }
 
-__initcall(sa1100_dram_init);
+core_initcall(sa1100_dram_init);
diff -Nru a/arch/arm/mach-sa1100/cpu-sa1110.c b/arch/arm/mach-sa1100/cpu-sa1110.c
--- a/arch/arm/mach-sa1100/cpu-sa1110.c	Tue Oct  1 00:08:14 2002
+++ b/arch/arm/mach-sa1100/cpu-sa1110.c	Tue Oct  1 00:08:14 2002
@@ -28,11 +28,9 @@
 #include <asm/io.h>
 #include <asm/system.h>
 
-#undef DEBUG
+#include "generic.h"
 
-extern unsigned int sa11x0_freq_to_ppcr(unsigned int khz);
-extern unsigned int sa11x0_validatespeed(unsigned int cpu, unsigned int khz);
-extern unsigned int sa11x0_getspeed(void);
+#undef DEBUG
 
 struct sdram_params {
 	u_char  rows;		/* bits				 */
@@ -214,15 +212,16 @@
  * above, we can match for an exact frequency.  If we don't find
  * an exact match, we will to set the lowest frequency to be safe.
  */
-static void sa1110_setspeed(unsigned int cpu, unsigned int khz)
+static void sa1110_setspeed(struct cpufreq_policy *policy)
 {
 	struct sdram_params *sdram = &sdram_params;
+	struct cpufreq_freqs freqs;
 	struct sdram_info sd;
 	unsigned long flags;
 	unsigned int ppcr, unused;
 
-	ppcr = sa11x0_freq_to_ppcr(khz);
-	sdram_calculate_timing(&sd, khz, sdram);
+	ppcr = sa11x0_freq_to_ppcr(policy->max);
+	sdram_calculate_timing(&sd, policy->max, sdram);
 
 #if 0
 	/*
@@ -230,7 +229,7 @@
 	 * and errata, but they seem to work.  Need to get a storage
 	 * scope on to the SDRAM signals to work out why.
 	 */
-	if (khz < 147500) {
+	if (policy->max < 147500) {
 		sd.mdrefr |= MDREFR_K1DB2;
 		sd.mdcas[0] = 0xaaaaaa7f;
 	} else {
@@ -240,6 +239,13 @@
 	sd.mdcas[1] = 0xaaaaaaaa;
 	sd.mdcas[2] = 0xaaaaaaaa;
 #endif
+
+	freqs.old = sa11x0_getspeed();
+	freqs.new = policy->max;
+	freqs.cpu = CPUFREQ_ALL_CPUS;
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
 	/*
 	 * The clock could be going away for some time.  Set the SDRAMs
 	 * to refresh rapidly (every 64 memory clock cycles).  To get
@@ -257,7 +263,7 @@
 	 * the programming.
 	 */
 	local_irq_save(flags);
-	asm("mcr p15, 0, %0, c10, c4" : : "r" (0));
+	asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (0));
 	udelay(10);
 	__asm__ __volatile__("
 		b	2f
@@ -282,19 +288,22 @@
 	/*
 	 * Now, return the SDRAM refresh back to normal.
 	 */
-	sdram_update_refresh(khz, sdram);
+	sdram_update_refresh(policy->max, sdram);
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 }
 
-static struct cpufreq_freqs sa1110_freqs = {
-	.min		= 59000,
-	.max		= 287000,
+static struct cpufreq_policy sa1110_policy = {
+	.cpu		= 0,
+	.policy		= CPUFREQ_POLICY_POWERSAVE,
+	.max_cpu_freq	= 287000,
 };
 
 static struct cpufreq_driver sa1110_driver = {
-	.freq		= &sa1110_freqs,
-	.validate	= sa11x0_validatespeed,
-	.setspeed	= sa1110_setspeed,
-	.sync		= 1,
+	.verify		= sa11x0_verify_speed,
+	.setpolicy	= sa1110_setspeed,
+	.policy		= &sa1110_policy,
+	.cpu_min_freq	= 59000,
 };
 
 static int __init sa1110_clk_init(void)
@@ -318,8 +327,11 @@
 
 		memcpy(&sdram_params, sdram, sizeof(sdram_params));
 
-		sa1110_freqs.cur = sa11x0_getspeed();
-		sa1110_setspeed(0, sa1110_freqs.cur);
+		sa1110_driver.cpu_cur_freq[0] =
+		sa1110_policy.min =
+		sa1110_policy.max = sa11x0_getspeed();
+
+		sa1110_setspeed(&sa1110_policy);
 
 		return cpufreq_register(&sa1110_driver);
 	}
@@ -327,4 +339,4 @@
 	return 0;
 }
 
-__initcall(sa1110_clk_init);
+core_initcall(sa1110_clk_init);
diff -Nru a/arch/arm/mach-sa1100/dma.c b/arch/arm/mach-sa1100/dma.c
--- a/arch/arm/mach-sa1100/dma.c	Tue Oct  1 00:08:15 2002
+++ b/arch/arm/mach-sa1100/dma.c	Tue Oct  1 00:08:15 2002
@@ -126,9 +126,9 @@
 	err = request_irq(IRQ_DMA0 + i, dma_irq_handler, SA_INTERRUPT,
 			  device_id, regs);
 	if (err) {
-		printk(KERN_ERR __FUNCTION__
-		       "unable to request IRQ %d for %s\n",
-		       IRQ_DMA0 + i, device_id);
+		printk(KERN_ERR
+		       "%s: unable to request IRQ %d for %s\n",
+		       __FUNCTION__, IRQ_DMA0 + i, device_id);
 		dma->device = 0;
 		return err;
 	}
@@ -164,12 +164,12 @@
 		if (regs == (dma_regs_t *)&DDAR(i))
 			break;
 	if (i >= SA1100_DMA_CHANNELS) {
-		printk(KERN_ERR __FUNCTION__ ": bad DMA identifier\n");
+		printk(KERN_ERR "%s: bad DMA identifier\n", __FUNCTION__);
 		return;
 	}
 
 	if (!dma_chan[i].device) {
-		printk(KERN_ERR __FUNCTION__ "Trying to free free DMA\n");
+		printk(KERN_ERR "%s: Trying to free free DMA\n", __FUNCTION__);
 		return;
 	}
 
@@ -215,10 +215,14 @@
 
 int sa1100_start_dma(dma_regs_t *regs, dma_addr_t dma_ptr, u_int size)
 {
-	long flags;
+	unsigned long flags;
 	u_long status;
 	int ret;
 
+	if (dma_ptr & 3)
+		printk(KERN_WARNING "DMA: unaligned start address (0x%08lx)\n",
+		       (unsigned long)dma_ptr);
+
 	if (size > MAX_DMA_SIZE)
 		return -EOVERFLOW;
 
@@ -324,7 +328,7 @@
 		if (regs == (dma_regs_t *)&DDAR(i))
 			break;
 	if (i >= SA1100_DMA_CHANNELS) {
-		printk(KERN_ERR __FUNCTION__ ": bad DMA identifier\n");
+		printk(KERN_ERR "%s: bad DMA identifier\n", __FUNCTION__);
 		return;
 	}
 
diff -Nru a/arch/arm/mach-sa1100/flexanet.c b/arch/arm/mach-sa1100/flexanet.c
--- a/arch/arm/mach-sa1100/flexanet.c	Tue Oct  1 00:08:17 2002
+++ b/arch/arm/mach-sa1100/flexanet.c	Tue Oct  1 00:08:17 2002
@@ -143,14 +143,6 @@
 }
 
 
-static int __init flexanet_init(void)
-{
-	return 0;
-}
-
-__initcall(flexanet_init);
-
-
 static struct map_desc flexanet_io_desc[] __initdata = {
  /* virtual     physical    length      type */
   { 0xf0000000, 0x10000000, 0x00001000, MT_DEVICE }, /* Board Control Register */
diff -Nru a/arch/arm/mach-sa1100/freebird.c b/arch/arm/mach-sa1100/freebird.c
--- a/arch/arm/mach-sa1100/freebird.c	Tue Oct  1 00:08:15 2002
+++ b/arch/arm/mach-sa1100/freebird.c	Tue Oct  1 00:08:15 2002
@@ -48,7 +48,7 @@
 	return 0;
 }
 
-__initcall(freebird_init);
+arch_initcall(freebird_init);
 
 static struct map_desc freebird_io_desc[] __initdata = {
  /* virtual     physical    length      type */
diff -Nru a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c
--- a/arch/arm/mach-sa1100/generic.c	Tue Oct  1 00:08:16 2002
+++ b/arch/arm/mach-sa1100/generic.c	Tue Oct  1 00:08:16 2002
@@ -8,11 +8,6 @@
  * 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.
- *
- * Since this file should be linked before any other machine specific file,
- * the __initcall() here will be executed first.  This serves as default
- * initialization stuff for SA1100 machines which can be overriden later if
- * need be.
  */
 #include <linux/config.h>
 #include <linux/module.h>
@@ -60,20 +55,26 @@
 
 	khz /= 100;
 
-	for (i = NR_FREQS - 1; i > 0; i--)
-		if (cclk_frequency_100khz[i] <= khz)
+	for (i = 0; i < ARRAY_SIZE(cclk_frequency_100khz); i--)
+		if (cclk_frequency_100khz[i] >= khz)
 			break;
 
 	return i;
 }
 
 /*
- * Validate the speed in khz.  If we can't generate the precise
- * frequency requested, round it down (to be on the safe side).
+ * Validate the policy.  We aren't able to do any fancy in-kernel
+ * scaling, so we force min=max, and set the policy to "performance".
+ * If we can't generate the precise frequency requested, round it up.
  */
-unsigned int sa11x0_validatespeed(unsigned int cpu, unsigned int khz)
+void sa11x0_verify_speed(struct cpufreq_policy *policy)
 {
-	return cclk_frequency_100khz[sa11x0_freq_to_ppcr(khz)] * 100;
+	if (policy->max > policy->max_cpu_freq)
+		policy->max = policy->max_cpu_freq;
+
+	policy->max = cclk_frequency_100khz[sa11x0_freq_to_ppcr(policy->max)] * 100;
+	policy->min = policy->max;
+	policy->policy = CPUFREQ_POLICY_POWERSAVE;
 }
 
 unsigned int sa11x0_getspeed(void)
@@ -117,7 +118,7 @@
 	return 0;
 }
 
-__initcall(sa1100_init);
+core_initcall(sa1100_init);
 
 void (*sa1100fb_backlight_power)(int on);
 void (*sa1100fb_lcd_power)(int on);
diff -Nru a/arch/arm/mach-sa1100/generic.h b/arch/arm/mach-sa1100/generic.h
--- a/arch/arm/mach-sa1100/generic.h	Tue Oct  1 00:08:18 2002
+++ b/arch/arm/mach-sa1100/generic.h	Tue Oct  1 00:08:18 2002
@@ -17,3 +17,9 @@
 
 extern void sa1110_mb_enable(void);
 extern void sa1110_mb_disable(void);
+
+struct cpufreq_policy;
+
+extern unsigned int sa11x0_freq_to_ppcr(unsigned int khz);
+extern void sa11x0_verify_speed(struct cpufreq_policy *policy);
+extern unsigned int sa11x0_getspeed(void);
diff -Nru a/arch/arm/mach-sa1100/graphicsmaster.c b/arch/arm/mach-sa1100/graphicsmaster.c
--- a/arch/arm/mach-sa1100/graphicsmaster.c	Tue Oct  1 00:08:17 2002
+++ b/arch/arm/mach-sa1100/graphicsmaster.c	Tue Oct  1 00:08:17 2002
@@ -25,7 +25,6 @@
 #include <asm/mach/serial_sa1100.h>
 
 #include "generic.h"
-#include "sa1111.h"
 
 static int __init graphicsmaster_init(void)
 {
@@ -43,7 +42,7 @@
 	/*
 	 * Probe for SA1111.
 	 */
-	ret = sa1111_init(NULL, 0x18000000, ADS_EXT_IRQ(0));
+	ret = sa1111_init(0x18000000, ADS_EXT_IRQ(0));
 	if (ret < 0)
 		return ret;
 
@@ -59,7 +58,7 @@
 	return 0;
 }
 
-__initcall(graphicsmaster_init);
+arch_initcall(graphicsmaster_init);
 
 /*
  * Handlers for GraphicsMaster's external IRQ logic
diff -Nru a/arch/arm/mach-sa1100/h3600.c b/arch/arm/mach-sa1100/h3600.c
--- a/arch/arm/mach-sa1100/h3600.c	Tue Oct  1 00:08:15 2002
+++ b/arch/arm/mach-sa1100/h3600.c	Tue Oct  1 00:08:15 2002
@@ -24,65 +24,171 @@
 #include <linux/kernel.h>
 #include <linux/tty.h>
 #include <linux/sched.h>
+#include <linux/pm.h>
+#include <linux/serial_core.h>
 
 #include <asm/irq.h>
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/setup.h>
 
+#include <asm/mach/irq.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/serial_sa1100.h>
-#include <linux/serial_core.h>
+
+#include <asm/arch/h3600.h>
+
+#if defined (CONFIG_SA1100_H3600) || defined (CONFIG_SA1100_H3100)
 #include <asm/arch/h3600_gpio.h>
+#endif
+
+#ifdef CONFIG_SA1100_H3800
+#include <asm/arch/h3600_asic.h>
+#endif
 
 #include "generic.h"
 
+struct ipaq_model_ops ipaq_model_ops;
+EXPORT_SYMBOL(ipaq_model_ops);
+
+static void msleep(unsigned int msec)
+{
+	current->state = TASK_INTERRUPTIBLE;
+	schedule_timeout((msec * HZ + 999) / 1000);
+}
+
 /*
- * H3600 has extended, write-only memory-mapped GPIO's
- * H3100 has 1/2 extended, write-only GPIO and 1/2 on
- *	 regular GPIO lines.
- * H3800 has memory-mapped GPIO through ASIC1 & 2
+ * low-level UART features
  */
 
-#define H3600_EGPIO	(*(volatile unsigned int *)H3600_EGPIO_VIRT)
+static void h3600_uart_set_mctrl(struct uart_port *port, u_int mctrl)
+{
+	if (port->mapbase == _Ser3UTCR0) {
+		if (mctrl & TIOCM_RTS)
+			GPCR = GPIO_H3600_COM_RTS;
+		else
+			GPSR = GPIO_H3600_COM_RTS;
+	}
+}
 
-static unsigned int h3600_egpio;
+static u_int h3600_uart_get_mctrl(struct uart_port *port)
+{
+	u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
 
-/************************* H3100 *************************/
+	if (port->mapbase == _Ser3UTCR0) {
+		int gplr = GPLR;
+		/* DCD and CTS bits are inverted in GPLR by RS232 transceiver */
+		if (gplr & GPIO_H3600_COM_DCD)
+			ret &= ~TIOCM_CD;
+		if (gplr & GPIO_H3600_COM_CTS)
+			ret &= ~TIOCM_CTS;
+	}
 
-#define H3100_DIRECT_EGPIO (GPIO_H3100_BT_ON	  \
-			  | GPIO_H3100_GPIO3	  \
-			  | GPIO_H3100_QMUTE	  \
-			  | GPIO_H3100_LCD_3V_ON  \
-			  | GPIO_H3100_AUD_ON	  \
-			  | GPIO_H3100_AUD_PWR_ON \
-			  | GPIO_H3100_IR_ON	  \
-			  | GPIO_H3100_IR_FSEL)
+	return ret;
+}
 
-static void h3100_init_egpio( void )
+static void h3600_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
 {
-	GPDR |= H3100_DIRECT_EGPIO;
-	GPCR = H3100_DIRECT_EGPIO;   /* Initially all off */
+	if (port->mapbase == _Ser2UTCR0) { /* TODO: REMOVE THIS */
+		assign_h3600_egpio(IPAQ_EGPIO_IR_ON, !state);
+	} else if (port->mapbase == _Ser3UTCR0) {
+		assign_h3600_egpio(IPAQ_EGPIO_RS232_ON, !state);
+	}
+}
 
-	/* Older bootldrs put GPIO2-9 in alternate mode on the
-	   assumption that they are used for video */
-	GAFR &= ~H3100_DIRECT_EGPIO;
+/*
+ * Enable/Disable wake up events for this serial port.
+ * Obviously, we only support this on the normal COM port.
+ */
+static int h3600_uart_set_wake(struct uart_port *port, u_int enable)
+{
+	int err = -EINVAL;
 
-	h3600_egpio = EGPIO_H3600_RS232_ON;
-	H3600_EGPIO = h3600_egpio;
+	if (port->mapbase == _Ser3UTCR0) {
+		if (enable)
+			PWER |= PWER_GPIO23 | PWER_GPIO25; /* DCD and CTS */
+		else
+			PWER &= ~(PWER_GPIO23 | PWER_GPIO25); /* DCD and CTS */
+		err = 0;
+	}
+	return err;
 }
 
-static void h3100_control_egpio( enum ipaq_egpio_type x, int setp )
+static struct sa1100_port_fns h3600_port_fns __initdata = {
+	.set_mctrl	= h3600_uart_set_mctrl,
+	.get_mctrl	= h3600_uart_get_mctrl,
+	.pm		= h3600_uart_pm,
+	.set_wake	= h3600_uart_set_wake,
+};
+
+/*
+ * helper for sa1100fb
+ */
+static void h3xxx_lcd_power(int enable)
+{
+	assign_h3600_egpio(IPAQ_EGPIO_LCD_POWER, enable);
+}
+
+static struct map_desc h3600_io_desc[] __initdata = {
+ /* virtual	       physical 	  length      type */
+  { H3600_BANK_2_VIRT, SA1100_CS2_PHYS,   0x02800000, MT_DEVICE }, /* static memory bank 2  CS#2 */
+  { H3600_BANK_4_VIRT, SA1100_CS4_PHYS,   0x00800000, MT_DEVICE }, /* static memory bank 4  CS#4 */
+  { H3600_EGPIO_VIRT,  H3600_EGPIO_PHYS,  0x01000000, MT_DEVICE }, /* EGPIO 0		CS#5 */
+};
+
+/*
+ * Common map_io initialization
+ */
+
+static void __init h3xxx_map_io(void)
+{
+	sa1100_map_io();
+	iotable_init(h3600_io_desc, ARRAY_SIZE(h3600_io_desc));
+
+	sa1100_register_uart_fns(&h3600_port_fns);
+	sa1100_register_uart(0, 3); /* Common serial port */
+//	sa1100_register_uart(1, 1); /* Microcontroller on 3100/3600 */
+
+	/* Ensure those pins are outputs and driving low  */
+	PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
+	PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+
+	/* Configure suspend conditions */
+	PGSR = 0;
+	PWER = PWER_GPIO0 | PWER_RTC;
+	PCFR = PCFR_OPDE;
+	PSDR = 0;
+
+	sa1100fb_lcd_power = h3xxx_lcd_power;
+}
+
+static __inline__ void do_blank(int setp)
+{
+	if (ipaq_model_ops.blank_callback)
+		ipaq_model_ops.blank_callback(1-setp);
+}
+
+/************************* H3100 *************************/
+
+#ifdef CONFIG_SA1100_H3100
+
+#define H3100_EGPIO	(*(volatile unsigned int *)H3600_EGPIO_VIRT)
+static unsigned int h3100_egpio = 0;
+
+static void h3100_control_egpio(enum ipaq_egpio_type x, int setp)
 {
 	unsigned int egpio = 0;
 	long	     gpio = 0;
 	unsigned long flags;
 
 	switch (x) {
-	case IPAQ_EGPIO_LCD_ON:
+	case IPAQ_EGPIO_LCD_POWER:
 		egpio |= EGPIO_H3600_LCD_ON;
 		gpio  |= GPIO_H3100_LCD_3V_ON;
+		do_blank(setp);
+		break;
+	case IPAQ_EGPIO_LCD_ENABLE:
 		break;
 	case IPAQ_EGPIO_CODEC_NRESET:
 		egpio |= EGPIO_H3600_CODEC_NRESET;
@@ -120,65 +226,104 @@
 		break;
 	}
 
-	local_irq_save(flags);
-	if ( setp ) {
-		h3600_egpio |= egpio;
-		GPSR = gpio;
-	} else {
-		h3600_egpio &= ~egpio;
-		GPCR = gpio;
+	if (egpio || gpio) {
+		local_irq_save(flags);
+		if (setp) {
+			h3100_egpio |= egpio;
+			GPSR = gpio;
+		} else {
+			h3100_egpio &= ~egpio;
+			GPCR = gpio;
+		}
+		H3100_EGPIO = h3100_egpio;
+		local_irq_restore(flags);
 	}
-	H3600_EGPIO = h3600_egpio;
-	local_irq_restore(flags);
+}
 
-	/*
-	if ( x != IPAQ_EGPIO_VPP_ON ) {
-		printk(__FUNCTION__ " : type=%d (%s) gpio=0x%x (0x%x) egpio=0x%x (0x%x) setp=%d\n",
-		       x, egpio_names[x], GPLR, gpio, h3600_egpio, egpio, setp );
-	}
-	*/
+static unsigned long h3100_read_egpio(void)
+{
+	return h3100_egpio;
 }
 
-static unsigned long h3100_read_egpio( void )
+static int h3100_pm_callback(int req)
 {
-	return h3600_egpio;
+	if (ipaq_model_ops.pm_callback_aux)
+		return ipaq_model_ops.pm_callback_aux(req);
+	return 0;
 }
 
 static struct ipaq_model_ops h3100_model_ops __initdata = {
-	model	     : IPAQ_H3100,
-	generic_name : "3100",
-	initialize   : h3100_init_egpio,
-	control      : h3100_control_egpio,
-	read	     : h3100_read_egpio
+	.generic_name	= "3100",
+	.control	= h3100_control_egpio,
+	.read		= h3100_read_egpio,
+	.pm_callback	= h3100_pm_callback
 };
 
+#define H3100_DIRECT_EGPIO (GPIO_H3100_BT_ON	  \
+			  | GPIO_H3100_GPIO3	  \
+			  | GPIO_H3100_QMUTE	  \
+			  | GPIO_H3100_LCD_3V_ON  \
+			  | GPIO_H3100_AUD_ON	  \
+			  | GPIO_H3100_AUD_PWR_ON \
+			  | GPIO_H3100_IR_ON	  \
+			  | GPIO_H3100_IR_FSEL)
 
-/************************* H3600 *************************/
-
-static void h3600_init_egpio( void )
+static void __init h3100_map_io(void)
 {
-	h3600_egpio = EGPIO_H3600_RS232_ON;
-	H3600_EGPIO = h3600_egpio;
+	h3xxx_map_io();
+
+	/* Initialize h3100-specific values here */
+	GPCR = 0x0fffffff;	 /* All outputs are set low by default */
+	GPDR = GPIO_H3600_COM_RTS  | GPIO_H3600_L3_CLOCK |
+	       GPIO_H3600_L3_MODE  | GPIO_H3600_L3_DATA  |
+	       GPIO_H3600_CLK_SET1 | GPIO_H3600_CLK_SET0 |
+	       H3100_DIRECT_EGPIO;
+
+	/* Older bootldrs put GPIO2-9 in alternate mode on the
+	   assumption that they are used for video */
+	GAFR &= ~H3100_DIRECT_EGPIO;
+
+	H3100_EGPIO = h3100_egpio;
+	ipaq_model_ops = h3100_model_ops;
 }
 
-static void h3600_control_egpio( enum ipaq_egpio_type x, int setp )
+MACHINE_START(H3100, "Compaq iPAQ H3100")
+	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+	BOOT_PARAMS(0xc0000100)
+	MAPIO(h3100_map_io)
+	INITIRQ(sa1100_init_irq)
+MACHINE_END
+
+#endif /* CONFIG_SA1100_H3100 */
+
+/************************* H3600 *************************/
+
+#ifdef CONFIG_SA1100_H3600
+
+#define H3600_EGPIO	(*(volatile unsigned int *)H3600_EGPIO_VIRT)
+static unsigned int h3600_egpio = EGPIO_H3600_RS232_ON;
+
+static void h3600_control_egpio(enum ipaq_egpio_type x, int setp)
 {
 	unsigned int egpio = 0;
 	unsigned long flags;
 
 	switch (x) {
-	case IPAQ_EGPIO_LCD_ON:
+	case IPAQ_EGPIO_LCD_POWER:
 		egpio |= EGPIO_H3600_LCD_ON |
 			 EGPIO_H3600_LCD_PCI |
 			 EGPIO_H3600_LCD_5V_ON |
 			 EGPIO_H3600_LVDD_ON;
+		do_blank(setp);
+		break;
+	case IPAQ_EGPIO_LCD_ENABLE:
 		break;
 	case IPAQ_EGPIO_CODEC_NRESET:
 		egpio |= EGPIO_H3600_CODEC_NRESET;
 		break;
 	case IPAQ_EGPIO_AUDIO_ON:
 		egpio |= EGPIO_H3600_AUD_AMP_ON |
-			EGPIO_H3600_AUD_PWR_ON;
+			 EGPIO_H3600_AUD_PWR_ON;
 		break;
 	case IPAQ_EGPIO_QMUTE:
 		egpio |= EGPIO_H3600_QMUTE;
@@ -209,288 +354,441 @@
 		break;
 	}
 
-	local_irq_save(flags);
-	if ( setp )
-		h3600_egpio |= egpio;
-	else
-		h3600_egpio &= ~egpio;
-	H3600_EGPIO = h3600_egpio;
-	local_irq_restore(flags);
+	if (egpio) {
+		local_irq_save(flags);
+		if (setp)
+			h3600_egpio |= egpio;
+		else
+			h3600_egpio &= ~egpio;
+		H3600_EGPIO = h3600_egpio;
+		local_irq_restore(flags);
+	}
 }
 
-static unsigned long h3600_read_egpio( void )
+static unsigned long h3600_read_egpio(void)
 {
 	return h3600_egpio;
 }
 
+static int h3600_pm_callback(int req)
+{
+	if (ipaq_model_ops.pm_callback_aux)
+		return ipaq_model_ops.pm_callback_aux(req);
+	return 0;
+}
+
 static struct ipaq_model_ops h3600_model_ops __initdata = {
-	model	     : IPAQ_H3600,
-	generic_name : "3600",
-	initialize   : h3600_init_egpio,
-	control      : h3600_control_egpio,
-	read	     : h3600_read_egpio
+	.generic_name	= "3600",
+	.control	= h3600_control_egpio,
+	.read		= h3600_read_egpio,
+	.pm_callback	= h3600_pm_callback
 };
 
-/************************* H3800 *************************/
+static void __init h3600_map_io(void)
+{
+	h3xxx_map_io();
 
-#define ASIC1_OUTPUTS	 0x7fff   /* First 15 bits are used */
+	/* Initialize h3600-specific values here */
+
+	GPCR = 0x0fffffff;	 /* All outputs are set low by default */
+	GPDR = GPIO_H3600_COM_RTS  | GPIO_H3600_L3_CLOCK |
+	       GPIO_H3600_L3_MODE  | GPIO_H3600_L3_DATA  |
+	       GPIO_H3600_CLK_SET1 | GPIO_H3600_CLK_SET0 |
+	       GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 |
+	       GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9  | GPIO_LDD8;
 
-static unsigned int h3800_asic1_gpio;
-static unsigned int h3800_asic2_gpio;
+	H3600_EGPIO = h3600_egpio;	   /* Maintains across sleep? */
+	ipaq_model_ops = h3600_model_ops;
+}
 
-static void h3800_init_egpio(void)
-{
-	/* Set up ASIC #1 */
-	H3800_ASIC1_GPIO_Direction    = ASIC1_OUTPUTS;		  /* All outputs */
-	H3800_ASIC1_GPIO_Mask	      = ASIC1_OUTPUTS;		  /* No interrupts */
-	H3800_ASIC1_GPIO_SleepMask    = ASIC1_OUTPUTS;
-	H3800_ASIC1_GPIO_SleepDir     = ASIC1_OUTPUTS;
-	H3800_ASIC1_GPIO_SleepOut     = GPIO_H3800_ASIC1_EAR_ON_N;
-	H3800_ASIC1_GPIO_BattFaultDir = ASIC1_OUTPUTS;
-	H3800_ASIC1_GPIO_BattFaultOut = GPIO_H3800_ASIC1_EAR_ON_N;
-
-	h3800_asic1_gpio = GPIO_H3800_ASIC1_IR_ON_N   /* TODO: Check IR level */
-		| GPIO_H3800_ASIC1_RS232_ON
-		| GPIO_H3800_ASIC1_EAR_ON_N;
+MACHINE_START(H3600, "Compaq iPAQ H3600")
+	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+	BOOT_PARAMS(0xc0000100)
+	MAPIO(h3600_map_io)
+	INITIRQ(sa1100_init_irq)
+MACHINE_END
 
-	H3800_ASIC1_GPIO_Out = h3800_asic1_gpio;
+#endif /* CONFIG_SA1100_H3600 */
 
-	/* Set up ASIC #2 */
-	H3800_ASIC2_GPIO_Direction = GPIO_H3800_ASIC2_PEN_IRQ
-		| GPIO_H3800_ASIC2_SD_DETECT
-		| GPIO_H3800_ASIC2_EAR_IN_N
-		| GPIO_H3800_ASIC2_USB_DETECT_N
-		| GPIO_H3800_ASIC2_SD_CON_SLT;
-
-	h3800_asic2_gpio = GPIO_H3800_ASIC2_IN_Y1_N | GPIO_H3800_ASIC2_IN_X1_N;
-	H3800_ASIC2_GPIO_Data	      = h3800_asic2_gpio;
-	H3800_ASIC2_GPIO_BattFaultOut = h3800_asic2_gpio;
+#ifdef CONFIG_SA1100_H3800
 
-	/* TODO : Set sleep states & battery fault states */
+#define SET_ASIC1(x) \
+   do {if (setp) { H3800_ASIC1_GPIO_OUT |= (x); } else { H3800_ASIC1_GPIO_OUT &= ~(x); }} while(0)
 
-	/* Clear VPP Enable */
-	H3800_ASIC1_FlashWP_VPP_ON = 0;
+#define SET_ASIC2(x) \
+   do {if (setp) { H3800_ASIC2_GPIOPIOD |= (x); } else { H3800_ASIC2_GPIOPIOD &= ~(x); }} while(0)
+
+#define CLEAR_ASIC1(x) \
+   do {if (setp) { H3800_ASIC1_GPIO_OUT &= ~(x); } else { H3800_ASIC1_GPIO_OUT |= (x); }} while(0)
+
+#define CLEAR_ASIC2(x) \
+   do {if (setp) { H3800_ASIC2_GPIOPIOD &= ~(x); } else { H3800_ASIC2_GPIOPIOD |= (x); }} while(0)
+
+
+/*
+  On screen enable, we get
+
+     h3800_video_power_on(1)
+     LCD controller starts
+     h3800_video_lcd_enable(1)
+
+  On screen disable, we get
+
+     h3800_video_lcd_enable(0)
+     LCD controller stops
+     h3800_video_power_on(0)
+*/
+
+
+static void h3800_video_power_on(int setp)
+{
+	if (setp) {
+		H3800_ASIC1_GPIO_OUT |= GPIO1_LCD_ON;
+		msleep(30);
+		H3800_ASIC1_GPIO_OUT |= GPIO1_VGL_ON;
+		msleep(5);
+		H3800_ASIC1_GPIO_OUT |= GPIO1_VGH_ON;
+		msleep(50);
+		H3800_ASIC1_GPIO_OUT |= GPIO1_LCD_5V_ON;
+		msleep(5);
+	} else {
+		msleep(5);
+		H3800_ASIC1_GPIO_OUT &= ~GPIO1_LCD_5V_ON;
+		msleep(50);
+		H3800_ASIC1_GPIO_OUT &= ~GPIO1_VGL_ON;
+		msleep(5);
+		H3800_ASIC1_GPIO_OUT &= ~GPIO1_VGH_ON;
+		msleep(100);
+		H3800_ASIC1_GPIO_OUT &= ~GPIO1_LCD_ON;
+	}
+}
+
+static void h3800_video_lcd_enable(int setp)
+{
+	if (setp) {
+		msleep(17);	// Wait one from before turning on
+		H3800_ASIC1_GPIO_OUT |= GPIO1_LCD_PCI;
+	} else {
+		H3800_ASIC1_GPIO_OUT &= ~GPIO1_LCD_PCI;
+		msleep(30);	// Wait before turning off
+	}
 }
 
-static void h3800_control_egpio( enum ipaq_egpio_type x, int setp )
-{
-	unsigned int set_asic1_egpio = 0;
-	unsigned int clear_asic1_egpio = 0;
-	unsigned long flags;
 
+static void h3800_control_egpio(enum ipaq_egpio_type x, int setp)
+{
 	switch (x) {
-	case IPAQ_EGPIO_LCD_ON:
-		set_asic1_egpio |= GPIO_H3800_ASIC1_LCD_5V_ON
-			| GPIO_H3800_ASIC1_LCD_ON
-			| GPIO_H3800_ASIC1_LCD_PCI
-			| GPIO_H3800_ASIC1_VGH_ON
-			| GPIO_H3800_ASIC1_VGL_ON;
+	case IPAQ_EGPIO_LCD_POWER:
+		h3800_video_power_on(setp);
 		break;
-	case IPAQ_EGPIO_CODEC_NRESET:
+	case IPAQ_EGPIO_LCD_ENABLE:
+		h3800_video_lcd_enable(setp);
 		break;
+	case IPAQ_EGPIO_CODEC_NRESET:
 	case IPAQ_EGPIO_AUDIO_ON:
-		break;
 	case IPAQ_EGPIO_QMUTE:
+		printk(__FUNCTION__ ": error - should not be called\n");
 		break;
 	case IPAQ_EGPIO_OPT_NVRAM_ON:
+		SET_ASIC2(GPIO2_OPT_ON_NVRAM);
 		break;
 	case IPAQ_EGPIO_OPT_ON:
+		SET_ASIC2(GPIO2_OPT_ON);
 		break;
 	case IPAQ_EGPIO_CARD_RESET:
+		SET_ASIC2(GPIO2_OPT_PCM_RESET);
 		break;
 	case IPAQ_EGPIO_OPT_RESET:
+		SET_ASIC2(GPIO2_OPT_RESET);
 		break;
 	case IPAQ_EGPIO_IR_ON:
-		clear_asic1_egpio |= GPIO_H3800_ASIC1_IR_ON_N;	 /* TODO : This is backwards? */
+		CLEAR_ASIC1(GPIO1_IR_ON_N);
 		break;
 	case IPAQ_EGPIO_IR_FSEL:
 		break;
 	case IPAQ_EGPIO_RS232_ON:
-		set_asic1_egpio |= GPIO_H3800_ASIC1_RS232_ON;
+		SET_ASIC1(GPIO1_RS232_ON);
 		break;
 	case IPAQ_EGPIO_VPP_ON:
-		H3800_ASIC1_FlashWP_VPP_ON = setp;
+		H3800_ASIC2_FlashWP_VPP_ON = setp;
 		break;
 	}
+}
 
-	local_irq_save(flags);
-	if ( setp ) {
-		h3800_asic1_gpio |= set_asic1_egpio;
-		h3800_asic1_gpio &= ~clear_asic1_egpio;
-	}
-	else {
-		h3800_asic1_gpio &= ~set_asic1_egpio;
-		h3800_asic1_gpio |= clear_asic1_egpio;
-	}
-	H3800_ASIC1_GPIO_Out = h3800_asic1_gpio;
-	local_irq_restore(flags);
+static unsigned long h3800_read_egpio(void)
+{
+	return H3800_ASIC1_GPIO_OUT | (H3800_ASIC2_GPIOPIOD << 16);
 }
 
-static unsigned long h3800_read_egpio( void )
+/* We need to fix ASIC2 GPIO over suspend/resume.  At the moment,
+   it doesn't appear that ASIC1 GPIO has the same problem */
+
+static int h3800_pm_callback(int req)
 {
-	return h3800_asic1_gpio | (h3800_asic2_gpio << 16);
+	static u16 asic1_data;
+	static u16 asic2_data;
+	int result = 0;
+
+	printk(__FUNCTION__ " %d\n", req);
+
+	switch (req) {
+	case PM_RESUME:
+		MSC2 = (MSC2 & 0x0000ffff) | 0xE4510000;  /* Set MSC2 correctly */
+
+		H3800_ASIC2_GPIOPIOD = asic2_data;
+		H3800_ASIC2_GPIODIR = GPIO2_PEN_IRQ
+			| GPIO2_SD_DETECT
+			| GPIO2_EAR_IN_N
+			| GPIO2_USB_DETECT_N
+			| GPIO2_SD_CON_SLT;
+
+		H3800_ASIC1_GPIO_OUT = asic1_data;
+
+		if (ipaq_model_ops.pm_callback_aux)
+			result = ipaq_model_ops.pm_callback_aux(req);
+		break;
+
+	case PM_SUSPEND:
+		if (ipaq_model_ops.pm_callback_aux &&
+		     ((result = ipaq_model_ops.pm_callback_aux(req)) != 0))
+			return result;
+
+		asic1_data = H3800_ASIC1_GPIO_OUT;
+		asic2_data = H3800_ASIC2_GPIOPIOD;
+		break;
+	default:
+		printk(__FUNCTION__ ": unrecognized PM callback\n");
+		break;
+	}
+	return result;
 }
 
 static struct ipaq_model_ops h3800_model_ops __initdata = {
-	model	     : IPAQ_H3800,
-	generic_name : "3800",
-	initialize   : h3800_init_egpio,
-	control      : h3800_control_egpio,
-	read	     : h3800_read_egpio
+	.generic_name	= "3800",
+	.control	= h3800_control_egpio,
+	.read		= h3800_read_egpio,
+	.pm_callback	= h3800_pm_callback
+};
+
+#define MAX_ASIC_ISR_LOOPS    20
+
+/* The order of these is important - see #include <asm/arch/irqs.h> */
+static u32 kpio_irq_mask[] = {
+	KPIO_KEY_ALL,
+	KPIO_SPI_INT,
+	KPIO_OWM_INT,
+	KPIO_ADC_INT,
+	KPIO_UART_0_INT,
+	KPIO_UART_1_INT,
+	KPIO_TIMER_0_INT,
+	KPIO_TIMER_1_INT,
+	KPIO_TIMER_2_INT
 };
 
+static u32 gpio_irq_mask[] = {
+	GPIO2_PEN_IRQ,
+	GPIO2_SD_DETECT,
+	GPIO2_EAR_IN_N,
+	GPIO2_USB_DETECT_N,
+	GPIO2_SD_CON_SLT,
+};
 
-static void h3600_lcd_power(int on)
+static void h3800_IRQ_demux(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
 {
-	if (on)
-		set_h3600_egpio(IPAQ_EGPIO_LCD_ON);
-	else
-		clr_h3600_egpio(IPAQ_EGPIO_LCD_ON);
-}
+	int i;
 
+	if (0) printk(__FUNCTION__ ": interrupt received\n");
 
-struct ipaq_model_ops ipaq_model_ops;
-EXPORT_SYMBOL(ipaq_model_ops);
+	desc->chip->ack(irq);
 
-static int __init h3600_init_model_ops(void)
-{
-	if (machine_is_h3xxx()) {
-		sa1100fb_lcd_power = h3600_lcd_power;
+	for (i = 0; i < MAX_ASIC_ISR_LOOPS && (GPLR & GPIO_H3800_ASIC); i++) {
+		u32 irq;
+		int j;
 
-		if (machine_is_h3100()) {
-			ipaq_model_ops = h3100_model_ops;
-		} else if (machine_is_h3600()) {
-			ipaq_model_ops = h3600_model_ops;
-		} else if (machine_is_h3800()) {
-			ipaq_model_ops = h3800_model_ops;
-		}
-		init_h3600_egpio();
+		/* KPIO */
+		irq = H3800_ASIC2_KPIINTFLAG;
+		if (0) printk(__FUNCTION__" KPIO 0x%08X\n", irq);
+		for (j = 0; j < H3800_KPIO_IRQ_COUNT; j++)
+			if (irq & kpio_irq_mask[j])
+				do_edge_IRQ(H3800_KPIO_IRQ_COUNT + j, irq_desc + H3800_KPIO_IRQ_COUNT + j, regs);
+
+		/* GPIO2 */
+		irq = H3800_ASIC2_GPIINTFLAG;
+		if (0) printk(__FUNCTION__" GPIO 0x%08X\n", irq);
+		for (j = 0; j < H3800_GPIO_IRQ_COUNT; j++)
+			if (irq & gpio_irq_mask[j])
+				do_edge_IRQ(H3800_GPIO_IRQ_COUNT + j, irq_desc + H3800_GPIO_IRQ_COUNT + j , regs);
 	}
-	return 0;
+
+	if (i >= MAX_ASIC_ISR_LOOPS)
+		printk(__FUNCTION__ ": interrupt processing overrun\n");
+
+	/* For level-based interrupts */
+	desc->chip->unmask(irq);
+
 }
 
-__initcall(h3600_init_model_ops);
+static struct irqaction h3800_irq = {
+	.name		= "h3800_asic",
+	.handler	= h3800_IRQ_demux,
+	.flags		= SA_INTERRUPT,
+};
 
-/*
- * low-level UART features
+u32 kpio_int_shadow = 0;
+
+
+/* mask_ack <- IRQ is first serviced.
+       mask <- IRQ is disabled.
+     unmask <- IRQ is enabled
+
+     The INTCLR registers are poorly documented.  I believe that writing
+     a "1" to the register clears the specific interrupt, but the documentation
+     indicates writing a "0" clears the interrupt.  In any case, they shouldn't
+     be read (that's the INTFLAG register)
  */
 
-static void h3600_uart_set_mctrl(struct uart_port *port, u_int mctrl)
+static void h3800_mask_ack_kpio_irq(unsigned int irq)
 {
-	if (port->mapbase == _Ser3UTCR0) {
-		if (mctrl & TIOCM_RTS)
-			GPCR = GPIO_H3600_COM_RTS;
-		else
-			GPSR = GPIO_H3600_COM_RTS;
-	}
+	u32 mask = kpio_irq_mask[irq - H3800_KPIO_IRQ_START];
+	kpio_int_shadow &= ~mask;
+	H3800_ASIC2_KPIINTSTAT = kpio_int_shadow;
+	H3800_ASIC2_KPIINTCLR  = mask;
 }
 
-static u_int h3600_uart_get_mctrl(struct uart_port *port)
+static void h3800_mask_kpio_irq(unsigned int irq)
 {
-	u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
+	u32 mask = kpio_irq_mask[irq - H3800_KPIO_IRQ_START];
+	kpio_int_shadow &= ~mask;
+	H3800_ASIC2_KPIINTSTAT = kpio_int_shadow;
+}
 
-	if (port->mapbase == _Ser3UTCR0) {
-		int gplr = GPLR;
-		if (gplr & GPIO_H3600_COM_DCD)
-			ret &= ~TIOCM_CD;
-		if (gplr & GPIO_H3600_COM_CTS)
-			ret &= ~TIOCM_CTS;
-	}
+static void h3800_unmask_kpio_irq(unsigned int irq)
+{
+	u32 mask = kpio_irq_mask[irq - H3800_KPIO_IRQ_START];
+	kpio_int_shadow |= mask;
+	H3800_ASIC2_KPIINTSTAT = kpio_int_shadow;
+}
 
-	return ret;
+static void h3800_mask_ack_gpio_irq(unsigned int irq)
+{
+	u32 mask = gpio_irq_mask[irq - H3800_GPIO_IRQ_START];
+	H3800_ASIC2_GPIINTSTAT &= ~mask;
+	H3800_ASIC2_GPIINTCLR	= mask;
 }
 
-static void h3600_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
+static void h3800_mask_gpio_irq(unsigned int irq)
 {
-	if (port->mapbase == _Ser2UTCR0) {
-		assign_h3600_egpio( IPAQ_EGPIO_IR_ON, !state );
-	} else if (port->mapbase == _Ser3UTCR0) {
-		assign_h3600_egpio( IPAQ_EGPIO_RS232_ON, !state );
+	u32 mask = gpio_irq_mask[irq - H3800_GPIO_IRQ_START];
+	H3800_ASIC2_GPIINTSTAT &= ~mask;
 	}
+
+static void h3800_unmask_gpio_irq(unsigned int irq)
+{
+	u32 mask = gpio_irq_mask[irq - H3800_GPIO_IRQ_START];
+	H3800_ASIC2_GPIINTSTAT |= mask;
 }
 
-/*
- * Enable/Disable wake up events for this serial port.
- * Obviously, we only support this on the normal COM port.
- */
-static int h3600_uart_set_wake(struct uart_port *port, u_int enable)
+static void __init h3800_init_irq(void)
 {
-	int err = -EINVAL;
+	int i;
 
-	if (port->mapbase == _Ser3UTCR0) {
-		if (enable)
-			PWER |= PWER_GPIO23 | PWER_GPIO25 ; /* DCD and CTS */
-		else
-			PWER &= ~(PWER_GPIO23 | PWER_GPIO25); /* DCD and CTS */
-		err = 0;
+	/* Initialize standard IRQs */
+	sa1100_init_irq();
+
+	/* Disable all IRQs and set up clock */
+	H3800_ASIC2_KPIINTSTAT	   =  0;     /* Disable all interrupts */
+	H3800_ASIC2_GPIINTSTAT	   =  0;
+
+	H3800_ASIC2_KPIINTCLR	   =  0;     /* Clear all KPIO interrupts */
+	H3800_ASIC2_GPIINTCLR	   =  0;     /* Clear all GPIO interrupts */
+
+//	H3800_ASIC2_KPIINTCLR	   =  0xffff;	  /* Clear all KPIO interrupts */
+//	H3800_ASIC2_GPIINTCLR	   =  0xffff;	  /* Clear all GPIO interrupts */
+
+	H3800_ASIC2_CLOCK_Enable       |= ASIC2_CLOCK_EX0;   /* 32 kHZ crystal on */
+	H3800_ASIC2_INTR_ClockPrescale |= ASIC2_INTCPS_SET;
+	H3800_ASIC2_INTR_ClockPrescale	= ASIC2_INTCPS_CPS(0x0e) | ASIC2_INTCPS_SET;
+	H3800_ASIC2_INTR_TimerSet	= 1;
+
+#if 0
+	for (i = 0; i < H3800_KPIO_IRQ_COUNT; i++) {
+		int irq = i + H3800_KPIO_IRQ_START;
+		irq_desc[irq].valid    = 1;
+		irq_desc[irq].probe_ok = 1;
+		set_irq_chip(irq, &h3800_kpio_irqchip);
 	}
-	return err;
+
+	for (i = 0; i < H3800_GPIO_IRQ_COUNT; i++) {
+		int irq = i + H3800_GPIO_IRQ_START;
+		irq_desc[irq].valid    = 1;
+		irq_desc[irq].probe_ok = 1;
+		set_irq_chip(irq, &h3800_gpio_irqchip);
+	}
+#endif
+	set_irq_type(IRQ_GPIO_H3800_ASIC, IRQT_RISING);
+	set_irq_chained_handler(IRQ_GPIO_H3800_ASIC, &h3800_IRQ_demux);
 }
 
-static struct sa1100_port_fns h3600_port_fns __initdata = {
-	.set_mctrl	= h3600_uart_set_mctrl,
-	.get_mctrl	= h3600_uart_get_mctrl,
-	.pm		= h3600_uart_pm,
-	.set_wake	= h3600_uart_set_wake,
-};
 
-static struct map_desc h3600_io_desc[] __initdata = {
- /* virtual	       physical    length      type */
-  { H3600_EGPIO_VIRT,  0x49000000, 0x01000000, MT_DEVICE }, /* EGPIO 0		 CS#5 */
-  { H3600_BANK_2_VIRT, 0x10000000, 0x02800000, MT_DEVICE }, /* static memory bank 2  CS#2 */
-  { H3600_BANK_4_VIRT, 0x40000000, 0x00800000, MT_DEVICE }  /* static memory bank 4  CS#4 */
-};
+#define ASIC1_OUTPUTS	 0x7fff   /* First 15 bits are used */
 
-static void __init h3600_map_io(void)
+static void __init h3800_map_io(void)
 {
-	sa1100_map_io();
-	iotable_init(h3600_io_desc, ARRAY_SIZE(h3600_io_desc));
+	h3xxx_map_io();
 
-	sa1100_register_uart_fns(&h3600_port_fns);
-	sa1100_register_uart(0, 3);
-	sa1100_register_uart(1, 1); /* isn't this one driven elsewhere? */
+	/* Add wakeup on AC plug/unplug */
+	PWER  |= PWER_GPIO12;
 
-	/*
-	 * Default GPIO settings.  Should be set by machine
-	 */
-	GPCR = 0x0fffffff;
-//	GPDR = 0x0401f3fc;
-	GPDR = GPIO_H3600_COM_RTS  | GPIO_H3600_L3_CLOCK |
-	       GPIO_H3600_L3_MODE  | GPIO_H3600_L3_DATA  |
-	       GPIO_H3600_CLK_SET1 | GPIO_H3600_CLK_SET0 |
-	       GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 |
-	       GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9  | GPIO_LDD8;
+	/* Initialize h3800-specific values here */
+	GPCR = 0x0fffffff;	 /* All outputs are set low by default */
+	GAFR =	GPIO_H3800_CLK_OUT |
+		GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 |
+		GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9  | GPIO_LDD8;
+	GPDR =	GPIO_H3800_CLK_OUT |
+		GPIO_H3600_COM_RTS  | GPIO_H3600_L3_CLOCK |
+		GPIO_H3600_L3_MODE  | GPIO_H3600_L3_DATA  |
+		GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 |
+		GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9  | GPIO_LDD8;
+	TUCR =	TUCR_3_6864MHz;   /* Seems to be used only for the Bluetooth UART */
 
-	init_h3600_egpio();
+	/* Fix the memory bus */
+	MSC2 = (MSC2 & 0x0000ffff) | 0xE4510000;
 
-	/*
-	 * Ensure those pins are outputs and driving low.
-	 */
-	PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
-	PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
+	/* Set up ASIC #1 */
+	H3800_ASIC1_GPIO_DIR		= ASIC1_OUTPUTS;	    /* All outputs */
+	H3800_ASIC1_GPIO_MASK		= ASIC1_OUTPUTS;	    /* No interrupts */
+	H3800_ASIC1_GPIO_SLEEP_MASK	= ASIC1_OUTPUTS;
+	H3800_ASIC1_GPIO_SLEEP_DIR	= ASIC1_OUTPUTS;
+	H3800_ASIC1_GPIO_SLEEP_OUT	= GPIO1_EAR_ON_N;
+	H3800_ASIC1_GPIO_BATT_FAULT_DIR = ASIC1_OUTPUTS;
+	H3800_ASIC1_GPIO_BATT_FAULT_OUT = GPIO1_EAR_ON_N;
+
+	H3800_ASIC1_GPIO_OUT = GPIO1_IR_ON_N
+				      | GPIO1_RS232_ON
+				      | GPIO1_EAR_ON_N;
 
-	/* Configure suspend conditions */
-	PGSR = 0;
-	PWER = PWER_GPIO0 | PWER_RTC;
-	PCFR = PCFR_OPDE;
-	PSDR = 0;
+	/* Set up ASIC #2 */
+	H3800_ASIC2_GPIOPIOD	= GPIO2_IN_Y1_N | GPIO2_IN_X1_N;
+	H3800_ASIC2_GPOBFSTAT	= GPIO2_IN_Y1_N | GPIO2_IN_X1_N;
+
+	H3800_ASIC2_GPIODIR	= GPIO2_PEN_IRQ
+				      | GPIO2_SD_DETECT
+				      | GPIO2_EAR_IN_N
+				      | GPIO2_USB_DETECT_N
+				      | GPIO2_SD_CON_SLT;
+
+	/* TODO : Set sleep states & battery fault states */
+
+	/* Clear VPP Enable */
+	H3800_ASIC2_FlashWP_VPP_ON = 0;
+	ipaq_model_ops = h3800_model_ops;
 }
 
-MACHINE_START(H3600, "Compaq iPAQ H3600")
-	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
-	BOOT_PARAMS(0xc0000100)
-	MAPIO(h3600_map_io)
-	INITIRQ(sa1100_init_irq)
-MACHINE_END
-MACHINE_START(H3100, "Compaq iPAQ H3100")
-	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
-	BOOT_PARAMS(0xc0000100)
-	MAPIO(h3600_map_io)
-	INITIRQ(sa1100_init_irq)
-MACHINE_END
 MACHINE_START(H3800, "Compaq iPAQ H3800")
 	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
 	BOOT_PARAMS(0xc0000100)
-	MAPIO(h3600_map_io)
-	INITIRQ(sa1100_init_irq)
+	MAPIO(h3800_map_io)
+	INITIRQ(h3800_init_irq)
 MACHINE_END
+
+#endif /* CONFIG_SA1100_H3800 */
diff -Nru a/arch/arm/mach-sa1100/huw_webpanel.c b/arch/arm/mach-sa1100/huw_webpanel.c
--- a/arch/arm/mach-sa1100/huw_webpanel.c	Tue Oct  1 00:08:17 2002
+++ b/arch/arm/mach-sa1100/huw_webpanel.c	Tue Oct  1 00:08:17 2002
@@ -52,7 +52,7 @@
 	return 0;
 }
 
-__initcall(init_huw_cs3);
+arch_initcall(init_huw_cs3);
 
 
 /**
diff -Nru a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c
--- a/arch/arm/mach-sa1100/jornada720.c	Tue Oct  1 00:08:21 2002
+++ b/arch/arm/mach-sa1100/jornada720.c	Tue Oct  1 00:08:21 2002
@@ -16,7 +16,6 @@
 #include <asm/mach/serial_sa1100.h>
 
 #include "generic.h"
-#include "sa1111.h"
 
 
 #define JORTUCR_VAL	0x20000400
@@ -46,14 +45,10 @@
 	PPSR &= ~(PPC_LDD3 | PPC_LDD4);
 	PPDR |= PPC_LDD3 | PPC_LDD4;
 
-	/* initialize extra IRQs */
-	set_GPIO_IRQ_edge(GPIO_GPIO1, GPIO_RISING_EDGE);
-	sa1111_init_irq(IRQ_GPIO1);	/* chained on GPIO 1 */
-
-	return 0;
+	return sa1111_init(0x40000000, IRQ_GPIO1);
 }
 
-__initcall(jornada720_init);
+arch_initcall(jornada720_init);
 
 static struct map_desc jornada720_io_desc[] __initdata = {
  /* virtual     physical    length      type */
diff -Nru a/arch/arm/mach-sa1100/leds.c b/arch/arm/mach-sa1100/leds.c
--- a/arch/arm/mach-sa1100/leds.c	Tue Oct  1 00:08:15 2002
+++ b/arch/arm/mach-sa1100/leds.c	Tue Oct  1 00:08:15 2002
@@ -44,4 +44,4 @@
 	return 0;
 }
 
-__initcall(sa1100_leds_init);
+core_initcall(sa1100_leds_init);
diff -Nru a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
--- a/arch/arm/mach-sa1100/neponset.c	Tue Oct  1 00:08:17 2002
+++ b/arch/arm/mach-sa1100/neponset.c	Tue Oct  1 00:08:17 2002
@@ -11,6 +11,7 @@
 #include <linux/ioport.h>
 #include <linux/serial_core.h>
 #include <linux/device.h>
+#include <linux/slab.h>
 
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
@@ -23,13 +24,6 @@
 #include <asm/hardware/sa1111.h>
 #include <asm/sizes.h>
 
-#include "sa1111.h"
-
-static struct device neponset_device = {
-	.name	= "Neponset",
-	.bus_id	= "nep_bus",
-};
-
 /*
  * Install handler for Neponset IRQ.  Note that we have to loop here
  * since the ETHERNET and USAR IRQs are level based, and we need to
@@ -163,6 +157,52 @@
 	.get_mctrl	= neponset_get_mctrl,
 };
 
+/*
+ * LDM power management.
+ */
+static int neponset_suspend(struct device *dev, u32 state, u32 level)
+{
+	/*
+	 * Save state.
+	 */
+	if (level == SUSPEND_SAVE_STATE ||
+	    level == SUSPEND_DISABLE ||
+	    level == SUSPEND_POWER_DOWN) {
+		if (!dev->saved_state)
+			dev->saved_state = kmalloc(sizeof(unsigned int), GFP_KERNEL);
+		if (!dev->saved_state)
+			return -ENOMEM;
+
+		*(unsigned int *)dev->saved_state = NCR_0;
+	}
+
+	return 0;
+}
+
+static int neponset_resume(struct device *dev, u32 level)
+{
+	if (level == RESUME_RESTORE_STATE || level == RESUME_ENABLE) {
+		if (dev->saved_state) {
+			NCR_0 = *(unsigned int *)dev->saved_state;
+			kfree(dev->saved_state);
+			dev->saved_state = NULL;
+		}
+	}
+
+	return 0;
+}
+
+static struct device_driver neponset_device_driver = {
+	.suspend = neponset_suspend,
+	.resume  = neponset_resume,
+};
+
+static struct device neponset_device = {
+	.name	= "Neponset",
+	.bus_id	= "neponset",
+	.driver = &neponset_device_driver,
+};
+
 static int __init neponset_init(void)
 {
 	int ret;
@@ -191,7 +231,7 @@
 		return -ENODEV;
 	}
 
-	ret = device_register(&neponset_device);
+	ret = register_sys_device(&neponset_device);
 	if (ret)
 		return ret;
 
@@ -213,10 +253,10 @@
 	/*
 	 * Probe and initialise the SA1111.
 	 */
-	return sa1111_init(&neponset_device, 0x40000000, IRQ_NEPONSET_SA1111);
+	return sa1111_init(0x40000000, IRQ_NEPONSET_SA1111);
 }
 
-__initcall(neponset_init);
+arch_initcall(neponset_init);
 
 static struct map_desc neponset_io_desc[] __initdata = {
  /* virtual     physical    length type */
diff -Nru a/arch/arm/mach-sa1100/omnimeter.c b/arch/arm/mach-sa1100/omnimeter.c
--- a/arch/arm/mach-sa1100/omnimeter.c	Tue Oct  1 00:08:13 2002
+++ b/arch/arm/mach-sa1100/omnimeter.c	Tue Oct  1 00:08:13 2002
@@ -39,7 +39,7 @@
 	return 0;
 }
 
-__initcall(omnimeter_init);
+arch_initcall(omnimeter_init);
 
 static struct map_desc omnimeter_io_desc[] __initdata = {
  /* virtual     physical    length      type */
diff -Nru a/arch/arm/mach-sa1100/pcipool.c b/arch/arm/mach-sa1100/pcipool.c
--- a/arch/arm/mach-sa1100/pcipool.c	Tue Oct  1 00:08:18 2002
+++ b/arch/arm/mach-sa1100/pcipool.c	Tue Oct  1 00:08:18 2002
@@ -20,8 +20,6 @@
 
 #include <asm/page.h>
 
-#include "pcipool.h"
-
 /*
  * Pool allocator ... wraps the pci_alloc_consistent page allocator, so
  * small blocks are easily used by drivers for bus mastering controllers.
@@ -33,7 +31,6 @@
 	spinlock_t		lock;
 	size_t			blocks_per_page;
 	size_t			size;
-	int			flags;
 	struct pci_dev		*dev;
 	size_t			allocation;
 	char			name [32];
@@ -52,6 +49,19 @@
 
 // #define CONFIG_PCIPOOL_DEBUG
 
+static inline const char *slot_name(const struct pci_pool *pool)
+{
+	const struct pci_dev *pdev = pool->dev;
+
+	if (pdev == 0)
+		return "[0]";
+
+	else if (dev_is_sa1111(pdev))
+		return "[SA-1111]";
+	else
+		return pdev->slot_name;
+}
+
 
 /**
  * pci_pool_create - Creates a pool of pci consistent memory blocks, for dma.
@@ -60,7 +70,7 @@
  * @size: size of the blocks in this pool.
  * @align: alignment requirement for blocks; must be a power of two
  * @allocation: returned blocks won't cross this boundary (or zero)
- * @flags: SLAB_* flags (not all are supported).
+ * @mem_flags: SLAB_* flags.
  *
  * Returns a pci allocation pool with the requested characteristics, or
  * null if one can't be created.  Given one of these pools, pci_pool_alloc()
@@ -76,7 +86,7 @@
  */
 struct pci_pool *
 pci_pool_create (const char *name, struct pci_dev *pdev,
-	size_t size, size_t align, size_t allocation, int flags)
+	size_t size, size_t align, size_t allocation, int mem_flags)
 {
 	struct pci_pool		*retval;
 
@@ -100,13 +110,9 @@
 	} else if (allocation < size)
 		return 0;
 
-	if (!(retval = kmalloc (sizeof *retval, flags)))
+	if (!(retval = kmalloc (sizeof *retval, mem_flags)))
 		return retval;
 
-#ifdef	CONFIG_PCIPOOL_DEBUG
-	flags |= SLAB_POISON;
-#endif
-
 	strncpy (retval->name, name, sizeof retval->name);
 	retval->name [sizeof retval->name - 1] = 0;
 
@@ -114,14 +120,13 @@
 	INIT_LIST_HEAD (&retval->page_list);
 	spin_lock_init (&retval->lock);
 	retval->size = size;
-	retval->flags = flags;
 	retval->allocation = allocation;
 	retval->blocks_per_page = allocation / size;
 	init_waitqueue_head (&retval->waitq);
 
 #ifdef CONFIG_PCIPOOL_DEBUG
 	printk (KERN_DEBUG "pcipool create %s/%s size %d, %d/page (%d alloc)\n",
-		pdev ? pdev->slot_name : NULL, retval->name, size,
+		slot_name(retval), retval->name, size,
 		retval->blocks_per_page, allocation);
 #endif
 
@@ -143,11 +148,13 @@
 	if (!page)
 		return 0;
 	page->vaddr = pci_alloc_consistent (pool->dev,
-				pool->allocation, &page->dma);
+					    pool->allocation,
+					    &page->dma);
 	if (page->vaddr) {
 		memset (page->bitmap, 0xff, mapsize);	// bit set == free
-		if (pool->flags & SLAB_POISON)
-			memset (page->vaddr, POOL_POISON_BYTE, pool->allocation);
+#ifdef	CONFIG_DEBUG_SLAB
+		memset (page->vaddr, POOL_POISON_BYTE, pool->allocation);
+#endif
 		list_add (&page->page_list, &pool->page_list);
 	} else {
 		kfree (page);
@@ -173,8 +180,9 @@
 {
 	dma_addr_t	dma = page->dma;
 
-	if (pool->flags & SLAB_POISON)
-		memset (page->vaddr, POOL_POISON_BYTE, pool->allocation);
+#ifdef	CONFIG_DEBUG_SLAB
+	memset (page->vaddr, POOL_POISON_BYTE, pool->allocation);
+#endif
 	pci_free_consistent (pool->dev, pool->allocation, page->vaddr, dma);
 	list_del (&page->page_list);
 	kfree (page);
@@ -195,8 +203,7 @@
 
 #ifdef CONFIG_PCIPOOL_DEBUG
 	printk (KERN_DEBUG "pcipool destroy %s/%s\n",
-		pool->dev ? pool->dev->slot_name : NULL,
-		pool->name);
+		slot_name(pool), pool->name);
 #endif
 
 	spin_lock_irqsave (&pool->lock, flags);
@@ -206,8 +213,7 @@
 				struct pci_page, page_list);
 		if (is_page_busy (pool->blocks_per_page, page->bitmap)) {
 			printk (KERN_ERR "pci_pool_destroy %s/%s, %p busy\n",
-				pool->dev ? pool->dev->slot_name : NULL,
-				pool->name, page->vaddr);
+				slot_name(pool), pool->name, page->vaddr);
 			/* leak the still-in-use consistent memory */
 			list_del (&page->page_list);
 			kfree (page);
@@ -327,35 +333,32 @@
 	int			map, block;
 
 	if ((page = pool_find_page (pool, dma)) == 0) {
-		printk (KERN_ERR "pci_pool_free %s/%s, %p/%x (bad dma)\n",
-			pool->dev ? pool->dev->slot_name : NULL,
-			pool->name, vaddr, dma);
-		return;
-	}
-#ifdef	CONFIG_PCIPOOL_DEBUG
-	if (((dma - page->dma) + (void *)page->vaddr) != vaddr) {
-		printk (KERN_ERR "pci_pool_free %s/%s, %p (bad vaddr)/%x\n",
+		printk (KERN_ERR "pci_pool_free %s/%s, %p/%lx (bad dma)\n",
 			pool->dev ? pool->dev->slot_name : NULL,
-			pool->name, vaddr, dma);
+			pool->name, vaddr, (unsigned long) dma);
 		return;
 	}
-#endif
 
 	block = dma - page->dma;
 	block /= pool->size;
 	map = block / BITS_PER_LONG;
 	block %= BITS_PER_LONG;
 
-#ifdef	CONFIG_PCIPOOL_DEBUG
+#ifdef	CONFIG_DEBUG_SLAB
+	if (((dma - page->dma) + (void *)page->vaddr) != vaddr) {
+		printk (KERN_ERR "pci_pool_free %s/%s, %p (bad vaddr)/%lx\n",
+			pool->dev ? pool->dev->slot_name : NULL,
+			pool->name, vaddr, (unsigned long) dma);
+		return;
+	}
 	if (page->bitmap [map] & (1UL << block)) {
 		printk (KERN_ERR "pci_pool_free %s/%s, dma %x already free\n",
 			pool->dev ? pool->dev->slot_name : NULL,
 			pool->name, dma);
 		return;
 	}
+	memset (vaddr, POOL_POISON_BYTE, pool->size);
 #endif
-	if (pool->flags & SLAB_POISON)
-		memset (vaddr, POOL_POISON_BYTE, pool->size);
 
 	spin_lock_irqsave (&pool->lock, flags);
 	set_bit (block, &page->bitmap [map]);
@@ -369,9 +372,19 @@
 	spin_unlock_irqrestore (&pool->lock, flags);
 }
 
-
 EXPORT_SYMBOL (pci_pool_create);
 EXPORT_SYMBOL (pci_pool_destroy);
 EXPORT_SYMBOL (pci_pool_alloc);
 EXPORT_SYMBOL (pci_pool_free);
 
+/* **************************************** */
+
+static int __init pcipool_init(void)
+{
+	MOD_INC_USE_COUNT;	/* never unload */
+
+	return 0;
+}
+module_init(pcipool_init);
+
+MODULE_LICENSE("GPL");
diff -Nru a/arch/arm/mach-sa1100/pcipool.h b/arch/arm/mach-sa1100/pcipool.h
--- a/arch/arm/mach-sa1100/pcipool.h	Tue Oct  1 00:08:14 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,8 +0,0 @@
-
-struct pci_pool *pci_pool_create (const char *name, struct pci_dev *dev,
-		size_t size, size_t align, size_t allocation, int flags);
-void pci_pool_destroy (struct pci_pool *pool);
-
-void *pci_pool_alloc (struct pci_pool *pool, int flags, dma_addr_t *handle);
-void pci_pool_free (struct pci_pool *pool, void *vaddr, dma_addr_t addr);
-
diff -Nru a/arch/arm/mach-sa1100/pfs168.c b/arch/arm/mach-sa1100/pfs168.c
--- a/arch/arm/mach-sa1100/pfs168.c	Tue Oct  1 00:08:14 2002
+++ b/arch/arm/mach-sa1100/pfs168.c	Tue Oct  1 00:08:14 2002
@@ -17,7 +17,6 @@
 #include <asm/mach/serial_sa1100.h>
 
 #include "generic.h"
-#include "sa1111.h"
 
 
 static int __init pfs168_init(void)
@@ -36,10 +35,10 @@
 	/*
 	 * Probe for SA1111.
 	 */
-	return sa1111_init(NULL, 0x40000000, IRQ_GPIO25);
+	return sa1111_init(0x40000000, IRQ_GPIO25);
 }
 
-__initcall(pfs168_init);
+arch_initcall(pfs168_init);
 
 
 static void __init pfs168_init_irq(void)
diff -Nru a/arch/arm/mach-sa1100/pm.c b/arch/arm/mach-sa1100/pm.c
--- a/arch/arm/mach-sa1100/pm.c	Tue Oct  1 00:08:16 2002
+++ b/arch/arm/mach-sa1100/pm.c	Tue Oct  1 00:08:16 2002
@@ -30,6 +30,7 @@
 #include <linux/interrupt.h>
 #include <linux/sysctl.h>
 #include <linux/errno.h>
+#include <linux/device.h>
 #include <linux/cpufreq.h>
 
 #include <asm/hardware.h>
@@ -193,11 +194,29 @@
 {
 	int retval;
 
+	/*
+	 * Suspend "legacy" devices.
+	 */
 	retval = pm_send_all(PM_SUSPEND, (void *)3);
-
 	if (retval == 0) {
+		/*
+		 * Suspend LDM devices.
+		 */
+		device_suspend(4, SUSPEND_NOTIFY);
+		device_suspend(4, SUSPEND_SAVE_STATE);
+		device_suspend(4, SUSPEND_DISABLE);
+
 		retval = pm_do_suspend();
 
+		/*
+		 * Resume LDM devices.
+		 */
+		device_resume(RESUME_RESTORE_STATE);
+		device_resume(RESUME_ENABLE);
+
+		/*
+		 * Resume "legacy" devices.
+		 */
 		pm_send_all(PM_RESUME, (void *)0);
 	}
 
@@ -225,7 +244,7 @@
 	return 0;
 }
 
-__initcall(pm_init);
+fs_initcall(pm_init);
 
 #endif
 
diff -Nru a/arch/arm/mach-sa1100/sa1111-pcibuf.c b/arch/arm/mach-sa1100/sa1111-pcibuf.c
--- a/arch/arm/mach-sa1100/sa1111-pcibuf.c	Tue Oct  1 00:08:13 2002
+++ b/arch/arm/mach-sa1100/sa1111-pcibuf.c	Tue Oct  1 00:08:13 2002
@@ -1,272 +1,410 @@
 /*
  *  linux/arch/arm/mach-sa1100/pci-sa1111.c
  *
- *  Special pci_map/unmap_single routines for SA-1111.   These functions
- *  compensate for a bug in the SA-1111 hardware which don't allow DMA
- *  to/from addresses above 1MB.
+ *  Special pci_{map/unmap/dma_sync}_* routines for SA-1111.
  *
- *  Brad Parker (brad@heeltoe.com)
+ *  These functions utilize bouncer buffers to compensate for a bug in
+ *  the SA-1111 hardware which don't allow DMA to/from addresses
+ *  certain addresses above 1MB.
  *
- *  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.
+ *  Re-written by Christopher Hoover <ch@murgatroid.com>
+ *  Original version by Brad Parker (brad@heeltoe.com)
  *
- *  06/13/2001 - created.
- */
+ *  Copyright (C) 2002 Hewlett Packard Company.
+ *
+ *  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/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
+#include <linux/list.h>
+#include <asm/hardware/sa1111.h>
 
-#include "pcipool.h"
+//#define DEBUG
+#ifdef DEBUG
+#define DPRINTK(...) do { printk(KERN_DEBUG __VA_ARGS__); } while (0)
+#else
+#define DPRINTK(...) do { } while (0)
+#endif
+
+
+struct safe_buffer {
+	struct list_head node;
+
+	/* original request */
+	void		*ptr;
+	size_t		size;
+	int		direction;
 
-/*
- * simple buffer allocator for copying of unsafe to safe buffers
- * uses __alloc/__free for actual buffers
- * keeps track of safe buffers we've allocated so we can recover the
- * unsafe buffers.
- */
+	/* safe buffer info */
+	struct pci_pool *pool;
+	void		*safe;
+	dma_addr_t	safe_dma_addr;
+};
 
-#define MAX_SAFE	32
-#define SIZE_SMALL	1024
-#define SIZE_LARGE	(16*1024)
+LIST_HEAD(safe_buffers);
 
-static long mapped_alloc_size;
-static char *safe_buffers[MAX_SAFE][2];
 
+#define SIZE_SMALL	1024
+#define SIZE_LARGE	(16*1024)
 
-static struct pci_pool *small_buffer_cache, *large_buffer_cache;
+static struct pci_pool *small_buffer_pool, *large_buffer_pool;
 
-static int
-init_safe_buffers(struct pci_dev *dev)
+static int __init
+create_safe_buffer_pools(void)
 {
-	small_buffer_cache = pci_pool_create("pci_small_buffer",
-					    dev,
+	small_buffer_pool = pci_pool_create("sa1111_small_dma_buffer",
+					    SA1111_FAKE_PCIDEV,
 					    SIZE_SMALL,
 					    0 /* byte alignment */,
 					    0 /* no page-crossing issues */,
-					    GFP_KERNEL | GFP_DMA);
-
-	if (small_buffer_cache == 0)
+					    SLAB_KERNEL);
+	if (0 == small_buffer_pool) {
+		printk(KERN_ERR
+		       "sa1111_pcibuf: could not allocate small pci pool\n");
 		return -1;
+	}
 
-	large_buffer_cache = pci_pool_create("pci_large_buffer",
-					    dev,
+	large_buffer_pool = pci_pool_create("sa1111_large_dma_buffer",
+					    SA1111_FAKE_PCIDEV,
 					    SIZE_LARGE,
 					    0 /* byte alignment */,
 					    0 /* no page-crossing issues */,
-					    GFP_KERNEL | GFP_DMA);
-	if (large_buffer_cache == 0)
+					    SLAB_KERNEL);
+	if (0 == large_buffer_pool) {
+		printk(KERN_ERR
+		       "sa1111_pcibuf: could not allocate large pci pool\n");
+		pci_pool_destroy(small_buffer_pool);
+		small_buffer_pool = 0;
 		return -1;
+	}
 
 	return 0;
 }
 
+static void __exit
+destroy_safe_buffer_pools(void)
+{
+	if (small_buffer_pool)
+		pci_pool_destroy(small_buffer_pool);
+	if (large_buffer_pool)
+		pci_pool_destroy(large_buffer_pool);
+
+	small_buffer_pool = large_buffer_pool = 0;
+}
+
+
 /* allocate a 'safe' buffer and keep track of it */
-static char *
-alloc_safe_buffer(char *unsafe, int size, dma_addr_t *pbus)
+static struct safe_buffer *
+alloc_safe_buffer(struct pci_dev *hwdev, void *ptr, size_t size, int direction)
 {
-	char *safe;
-	dma_addr_t busptr;
+	struct safe_buffer *buf;
 	struct pci_pool *pool;
-	int i;
+	void *safe;
+	dma_addr_t safe_dma_addr;
 
-	if (0) printk("alloc_safe_buffer(size=%d)\n", size);
+	DPRINTK("%s(ptr=%p, size=%d, direction=%d)\n",
+		__func__, ptr, size, direction);
 
-	if (size <= SIZE_SMALL)
-		pool = small_buffer_cache;
-	else
-		if (size < SIZE_LARGE)
-			pool = large_buffer_cache;
-				else
-					return 0;
-
-	safe = pci_pool_alloc(pool, SLAB_ATOMIC, &busptr);
-	if (safe == 0)
+	buf = kmalloc(sizeof(struct safe_buffer), GFP_ATOMIC);
+	if (buf == 0) {
+		printk(KERN_WARNING "%s: kmalloc failed\n", __func__);
 		return 0;
+	}
 
-	for (i = 0; i < MAX_SAFE; i++)
-		if (safe_buffers[i][0] == 0) {
-			break;
-		}
-
-	if (i == MAX_SAFE) {
-		panic(__FILE__ ": exceeded MAX_SAFE buffers");
+	if (size <= SIZE_SMALL) {
+		pool = small_buffer_pool;
+		safe = pci_pool_alloc(pool, GFP_ATOMIC, &safe_dma_addr);
+	} else if (size <= SIZE_LARGE) {
+		pool = large_buffer_pool;
+		safe = pci_pool_alloc(pool, GFP_ATOMIC, &safe_dma_addr);
+	} else {
+		printk(KERN_DEBUG
+		       "sa111_pcibuf: resorting to pci_alloc_consistent\n");
+		pool = 0;
+		safe = pci_alloc_consistent(SA1111_FAKE_PCIDEV, size,
+					    &safe_dma_addr);
 	}
 
-	/* place the size index and the old buffer ptr in the first 8 bytes
-	 * and return a ptr + 12 to caller
-	 */
-	((int *)safe)[0] = i;
-	((char **)safe)[1] = (char *)pool;
-	((char **)safe)[2] = unsafe;
+	if (safe == 0) {
+		printk(KERN_WARNING
+		       "%s: could not alloc dma memory (size=%d)\n",
+		       __func__, size);
+		kfree(buf);
+		return 0;
+	}
 
-	busptr += sizeof(int) + sizeof(char *) + sizeof(char *);
+	BUG_ON(sa1111_check_dma_bug(safe_dma_addr));	// paranoia
 
-	safe_buffers[i][0] = (void *)busptr;
-	safe_buffers[i][1] = (void *)safe;
+	buf->ptr = ptr;
+	buf->size = size;
+	buf->direction = direction;
+	buf->pool = pool;
+	buf->safe = safe;
+	buf->safe_dma_addr = safe_dma_addr;
 
-	safe += sizeof(int) + sizeof(char *) + sizeof(char *);
+	MOD_INC_USE_COUNT;
+	list_add(&buf->node, &safe_buffers);
 
-	*pbus = busptr;
-	return safe;
+	return buf;
 }
 
 /* determine if a buffer is from our "safe" pool */
-static char *
-find_safe_buffer(char *busptr, char **unsafe)
+static struct safe_buffer *
+find_safe_buffer(dma_addr_t safe_dma_addr)
 {
-	int i;
-	char *buf;
+	struct list_head *entry;
 
-	for (i = 0; i < MAX_SAFE; i++) {
-		if (safe_buffers[i][0] == busptr) {
-			if (0) printk("find_safe_buffer(%p) found @ %d\n", busptr, i);
-			buf = safe_buffers[i][1];
-			*unsafe = ((char **)buf)[2];
-			return buf + sizeof(int) + sizeof(char *) + sizeof(char *);
+	list_for_each(entry, &safe_buffers) {
+		struct safe_buffer *b =
+			list_entry(entry, struct safe_buffer, node);
+
+		if (b->safe_dma_addr == safe_dma_addr) {
+			return b;
 		}
 	}
 
-	return (char *)0;
+	return 0;
 }
 
 static void
-free_safe_buffer(char *buf)
+free_safe_buffer(struct safe_buffer *buf)
 {
-	int index;
-	struct pci_pool *pool;
-	char *dma;
+	DPRINTK("%s(buf=%p)\n", __func__, buf);
 
-	if (0) printk("free_safe_buffer(buf=%p)\n", buf);
+	list_del(&buf->node);
 
-	/* retrieve the buffer size index */
-	buf -= sizeof(int) + sizeof(char*) + sizeof(char*);
-	index = ((int *)buf)[0];
-	pool = (struct pci_pool *)((char **)buf)[1];
+	if (buf->pool)
+		pci_pool_free(buf->pool, buf->safe, buf->safe_dma_addr);
+	else
+		pci_free_consistent(SA1111_FAKE_PCIDEV, buf->size, buf->safe,
+				    buf->safe_dma_addr);
+	kfree(buf);
 
-	if (0) printk("free_safe_buffer(%p) index %d\n",
-		      buf, index);
+	MOD_DEC_USE_COUNT;
+}
 
-	if (index < 0 || index >= MAX_SAFE) {
-		printk(__FILE__ ": free_safe_buffer() corrupt buffer\n");
-		return;
-	}
+static inline int
+dma_range_is_safe(dma_addr_t addr, size_t size)
+{
+	unsigned int physaddr = SA1111_DMA_ADDR((unsigned int) addr);
 
-	dma = safe_buffers[index][0];
-	safe_buffers[index][0] = 0;
+	/* Any address within one megabyte of the start of the target
+         * bank will be OK.  This is an overly conservative test:
+         * other addresses can be OK depending on the dram
+         * configuration.  (See sa1111.c:sa1111_check_dma_bug() * for
+         * details.)
+	 *
+	 * We take care to ensure the entire dma region is within
+	 * the safe range.
+	 */
 
-	pci_pool_free(pool, buf, (u32)dma);
+	return ((physaddr + size - 1) < (1<<20));
 }
 
 /*
-  NOTE:
-  replace pci_map/unmap_single with local routines which will
-  do buffer copies if buffer is above 1mb...
-*/
-
-/*
  * see if a buffer address is in an 'unsafe' range.  if it is
  * allocate a 'safe' buffer and copy the unsafe buffer into it.
  * substitute the safe buffer for the unsafe one.
  * (basically move the buffer from an unsafe area to a safe one)
- *
- * we assume calls to map_single are symmetric with calls to unmap_single...
  */
 dma_addr_t
-sa1111_map_single(struct pci_dev *hwdev, void *virtptr,
-	       size_t size, int direction)
+sa1111_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction)
 {
-	dma_addr_t busptr;
+	unsigned long flags;
+	dma_addr_t dma_addr;
+
+	DPRINTK("%s(hwdev=%p,ptr=%p,size=%d,dir=%x)\n",
+	       __func__, hwdev, ptr, size, direction);
 
-	mapped_alloc_size += size;
+	BUG_ON(hwdev != SA1111_FAKE_PCIDEV);
+	BUG_ON(direction == PCI_DMA_NONE);
 
-	if (0) printk("pci_map_single(hwdev=%p,ptr=%p,size=%d,dir=%x) "
-		      "alloced=%ld\n",
-		      hwdev, virtptr, size, direction, mapped_alloc_size);
+	local_irq_save(flags);
 
-	busptr = virt_to_bus(virtptr);
+	dma_addr = virt_to_bus(ptr);
 
-	/* we assume here that a buffer will never be >=64k */
-	if ( (((unsigned long)busptr) & 0x100000) ||
-	     ((((unsigned long)busptr)+size) & 0x100000) )
-	{
-		char *safe;
+	if (!dma_range_is_safe(dma_addr, size)) {
+		struct safe_buffer *buf;
 
-		safe = alloc_safe_buffer(virtptr, size, &busptr);
-		if (safe == 0) {
-			printk("unable to map unsafe buffer %p!\n", virtptr);
+		buf = alloc_safe_buffer(hwdev, ptr, size, direction);
+		if (buf == 0) {
+			printk(KERN_ERR
+			       "%s: unable to map unsafe buffer %p!\n",
+			       __func__, ptr);
+			local_irq_restore(flags);
 			return 0;
 		}
 
-		if (0) printk("unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n",
-			      virtptr, (void *)virt_to_bus(virtptr),
-			      safe, (void *)busptr);
-
-		memcpy(safe, virtptr, size);
-		consistent_sync(safe, size, direction);
+		DPRINTK("%s: unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n",
+			__func__,
+			buf->ptr, (void *) virt_to_bus(buf->ptr),
+			buf->safe, (void *) buf->safe_dma_addr);
+
+		if ((direction == PCI_DMA_TODEVICE) ||
+		    (direction == PCI_DMA_BIDIRECTIONAL)) {
+			DPRINTK("%s: copy out from unsafe %p, to safe %p, size %d\n",
+				__func__, ptr, buf->safe, size);
+			memcpy(buf->safe, ptr, size);
+		}
+		consistent_sync(buf->safe, size, direction);
 
-		return busptr;
+		dma_addr = buf->safe_dma_addr;
+	} else {
+		consistent_sync(ptr, size, direction);
 	}
 
-	consistent_sync(virtptr, size, direction);
-	return busptr;
+	local_irq_restore(flags);
+	return dma_addr;
 }
 
 /*
- * see if a mapped address was really a "safe" buffer and if so,
- * copy the data from the safe buffer back to the unsafe buffer
- * and free up the safe buffer.
- * (basically return things back to the way they should be)
+ * see if a mapped address was really a "safe" buffer and if so, copy
+ * the data from the safe buffer back to the unsafe buffer and free up
+ * the safe buffer.  (basically return things back to the way they
+ * should be)
  */
+
 void
 sa1111_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
-		 size_t size, int direction)
+		    size_t size, int direction)
 {
-	char *safe, *unsafe;
-	void *buf;
+	unsigned long flags;
+	struct safe_buffer *buf;
+
+	DPRINTK("%s(hwdev=%p,ptr=%p,size=%d,dir=%x)\n",
+		__func__, hwdev, (void *) dma_addr, size, direction);
 
-	/* hack; usb-ohci.c never sends hwdev==NULL, all others do */
-	if (hwdev == NULL) {
-		return;
+	BUG_ON(hwdev != SA1111_FAKE_PCIDEV);
+	BUG_ON(direction == PCI_DMA_NONE);
+
+	local_irq_save(flags);
+
+	buf = find_safe_buffer(dma_addr);
+	if (buf) {
+		BUG_ON(buf->size != size);
+		BUG_ON(buf->direction != direction);
+
+		DPRINTK("%s: unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n",
+			__func__,
+			buf->ptr, (void *) virt_to_bus(buf->ptr),
+			buf->safe, (void *) buf->safe_dma_addr);
+
+		if ((direction == PCI_DMA_FROMDEVICE) ||
+		    (direction == PCI_DMA_BIDIRECTIONAL)) {
+			DPRINTK("%s: copy back from safe %p, to unsafe %p size %d\n",
+				__func__, buf->safe, buf->ptr, size);
+			memcpy(buf->ptr, buf->safe, size);
+		}
+		free_safe_buffer(buf);
 	}
 
-	mapped_alloc_size -= size;
+	local_irq_restore(flags);
+}
 
-	if (0) printk("pci_unmap_single(hwdev=%p,ptr=%p,size=%d,dir=%x) "
-		      "alloced=%ld\n",
-		      hwdev, (void *)dma_addr, size, direction,
-		      mapped_alloc_size);
-
-	if ((safe = find_safe_buffer((void *)dma_addr, &unsafe))) {
-		if (0) printk("copyback unsafe %p, safe %p, size %d\n",
-			      unsafe, safe, size);
-
-		consistent_sync(safe, size, PCI_DMA_FROMDEVICE);
-		memcpy(unsafe, safe, size);
-		free_safe_buffer(safe);
+int
+sa1111_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+	      int nents, int direction)
+{
+	BUG();			/* Not implemented. */
+}
+
+void
+sa1111_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents,
+	     int direction)
+{
+	BUG();			/* Not implemented. */
+}
+
+void
+sa1111_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
+		       size_t size, int direction)
+{
+	unsigned long flags;
+	struct safe_buffer *buf;
+
+	DPRINTK("%s(hwdev=%p,ptr=%p,size=%d,dir=%x)\n",
+		__func__, hwdev, (void *) dma_addr, size, direction);
+
+	BUG_ON(hwdev != SA1111_FAKE_PCIDEV);
+
+	local_irq_save(flags);
+
+	buf = find_safe_buffer(dma_addr);
+	if (buf) {
+		BUG_ON(buf->size != size);
+		BUG_ON(buf->direction != direction);
+
+		DPRINTK("%s: unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n",
+			__func__,
+			buf->ptr, (void *) virt_to_bus(buf->ptr),
+			buf->safe, (void *) buf->safe_dma_addr);
+
+		switch (direction) {
+		case PCI_DMA_FROMDEVICE:
+			DPRINTK("%s: copy back from safe %p, to unsafe %p size %d\n",
+				__func__, buf->safe, buf->ptr, size);
+			memcpy(buf->ptr, buf->safe, size);
+			break;
+		case PCI_DMA_TODEVICE:
+			DPRINTK("%s: copy out from unsafe %p, to safe %p, size %d\n",
+				__func__,buf->ptr, buf->safe, size);
+			memcpy(buf->safe, buf->ptr, size);
+			break;
+		case PCI_DMA_BIDIRECTIONAL:
+			BUG();	/* is this allowed?  what does it mean? */
+		default:
+			BUG();
+		}
+		consistent_sync(buf->safe, size, direction);
 	} else {
-		/* assume this is normal memory */
-		buf = bus_to_virt(dma_addr);
-		consistent_sync(buf, size, PCI_DMA_FROMDEVICE);
+		consistent_sync(bus_to_virt(dma_addr), size, direction);
 	}
+
+	local_irq_restore(flags);
+}
+
+void
+sa1111_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+		   int nelems, int direction)
+{
+	BUG();			/* Not implemented. */
 }
 
 EXPORT_SYMBOL(sa1111_map_single);
 EXPORT_SYMBOL(sa1111_unmap_single);
+EXPORT_SYMBOL(sa1111_map_sg);
+EXPORT_SYMBOL(sa1111_unmap_sg);
+EXPORT_SYMBOL(sa1111_dma_sync_single);
+EXPORT_SYMBOL(sa1111_dma_sync_sg);
 
-static int __init sa1111_init_safe_buffers(void)
+/* **************************************** */
+
+static int __init sa1111_pcibuf_init(void)
 {
-	printk("Initializing SA1111 buffer pool for DMA workaround\n");
-	init_safe_buffers(NULL);
-	return 0;
+	int ret;
+
+	printk(KERN_DEBUG
+	       "sa1111_pcibuf: initializing SA-1111 DMA workaround\n");
+
+	ret = create_safe_buffer_pools();
+
+	return ret;
 }
+module_init(sa1111_pcibuf_init);
 
-static void free_safe_buffers(void)
+static void __exit sa1111_pcibuf_exit(void)
 {
-	pci_pool_destroy(small_buffer_cache);
-	pci_pool_destroy(large_buffer_cache);
+	BUG_ON(!list_empty(&safe_buffers));
+
+	destroy_safe_buffer_pools();
 }
+module_exit(sa1111_pcibuf_exit);
 
-module_init(sa1111_init_safe_buffers);
-module_exit(free_safe_buffers);
+MODULE_AUTHOR("Christopher Hoover <ch@hpl.hp.com>");
+MODULE_DESCRIPTION("Special pci_{map/unmap/dma_sync}_* routines for SA-1111.");
+MODULE_LICENSE("GPL");
diff -Nru a/arch/arm/mach-sa1100/sa1111.c b/arch/arm/mach-sa1100/sa1111.c
--- a/arch/arm/mach-sa1100/sa1111.c	Tue Oct  1 00:08:16 2002
+++ b/arch/arm/mach-sa1100/sa1111.c	Tue Oct  1 00:08:16 2002
@@ -25,6 +25,7 @@
 #include <linux/ioport.h>
 #include <linux/device.h>
 #include <linux/slab.h>
+#include <linux/spinlock.h>
 
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
@@ -34,11 +35,132 @@
 
 #include <asm/hardware/sa1111.h>
 
-#include "sa1111.h"
+/*
+ * We keep the following data for the overall SA1111.  Note that the
+ * struct device and struct resource are "fake"; they should be supplied
+ * by the bus above us.  However, in the interests of getting all SA1111
+ * drivers converted over to the device model, we provide this as an
+ * anchor point for all the other drivers.
+ */
+struct sa1111 {
+	struct device	dev;
+	struct resource	res;
+	int		irq;
+	spinlock_t	lock;
+	void		*base;
+};
+
+/*
+ * We _really_ need to eliminate this.  Its only users
+ * are the PWM and DMA checking code.
+ */
+static struct sa1111 *g_sa1111;
 
-struct sa1111_device *sa1111;
+static struct sa1111_dev usb_dev = {
+	.dev = {
+		.name	= "Intel Corporation SA1111 [USB Controller]",
+	},
+	.skpcr_mask	= SKPCR_UCLKEN,
+	.devid		= SA1111_DEVID_USB,
+	.irq = {
+		IRQ_USBPWR,
+		IRQ_NHCIM,
+		IRQ_HCIBUFFACC,
+		IRQ_HCIRMTWKP,
+		IRQ_NHCIMFCIR,
+		IRQ_USB_PORT_RESUME
+	},
+};
 
-EXPORT_SYMBOL(sa1111);
+static struct sa1111_dev sac_dev = {
+	.dev = {
+		.name	= "Intel Corporation SA1111 [Audio Controller]",
+	},
+	.skpcr_mask	= SKPCR_I2SCLKEN | SKPCR_L3CLKEN,
+	.devid		= SA1111_DEVID_SAC,
+	.irq = {
+		AUDXMTDMADONEA,
+		AUDXMTDMADONEB,
+		AUDRCVDMADONEA,
+		AUDRCVDMADONEB
+	},
+};
+
+static struct sa1111_dev ssp_dev = {
+	.dev = {
+		.name	= "Intel Corporation SA1111 [SSP Controller]",
+	},
+	.skpcr_mask	= SKPCR_SCLKEN,
+	.devid		= SA1111_DEVID_SSP,
+};
+
+static struct sa1111_dev kbd_dev = {
+	.dev = {
+		.name	= "Intel Corporation SA1111 [PS2]",
+	},
+	.skpcr_mask	= SKPCR_PTCLKEN,
+	.devid		= SA1111_DEVID_PS2,
+	.irq = {
+		IRQ_TPRXINT,
+		IRQ_TPTXINT
+	},
+};
+
+static struct sa1111_dev mse_dev = {
+	.dev = {
+		.name	= "Intel Corporation SA1111 [PS2]",
+	},
+	.skpcr_mask	= SKPCR_PMCLKEN,
+	.devid		= SA1111_DEVID_PS2,
+	.irq = {
+		IRQ_MSRXINT,
+		IRQ_MSTXINT
+	},
+};
+
+static struct sa1111_dev int_dev = {
+	.dev = {
+		.name	= "Intel Corporation SA1111 [Interrupt Controller]",
+	},
+	.skpcr_mask	= 0,
+	.devid		= SA1111_DEVID_INT,
+};
+
+static struct sa1111_dev pcmcia_dev = {
+	.dev = {
+		.name	= "Intel Corporation SA1111 [PCMCIA Controller]",
+	},
+	.skpcr_mask	= 0,
+	.devid		= SA1111_DEVID_PCMCIA,
+	.irq = {
+		IRQ_S0_READY_NINT,
+		IRQ_S0_CD_VALID,
+		IRQ_S0_BVD1_STSCHG,
+		IRQ_S1_READY_NINT,
+		IRQ_S1_CD_VALID,
+		IRQ_S1_BVD1_STSCHG,
+	},
+};
+
+static struct sa1111_dev *devs[] = {
+	&usb_dev,
+	&sac_dev,
+	&ssp_dev,
+	&kbd_dev,
+	&mse_dev,
+	&int_dev,
+	&pcmcia_dev,
+};
+
+static unsigned int dev_offset[] = {
+	SA1111_USB,
+	0x0600,
+	0x0800,
+	SA1111_KBD,
+	SA1111_MSE,
+	SA1111_INTC,
+	0x1800,
+};
 
 /*
  * SA1111 interrupt support.  Since clearing an IRQ while there are
@@ -50,11 +172,15 @@
 {
 	unsigned int stat0, stat1, i;
 
-	desc->chip->ack(irq);
-
 	stat0 = INTSTATCLR0;
 	stat1 = INTSTATCLR1;
 
+	INTSTATCLR0 = stat0;
+
+	desc->chip->ack(irq);
+
+	INTSTATCLR1 = stat1;
+
 	if (stat0 == 0 && stat1 == 0) {
 		do_bad_IRQ(irq, desc, regs);
 		return;
@@ -75,9 +201,8 @@
 #define SA1111_IRQMASK_LO(x)	(1 << (x - IRQ_SA1111_START))
 #define SA1111_IRQMASK_HI(x)	(1 << (x - IRQ_SA1111_START - 32))
 
-static void sa1111_ack_lowirq(unsigned int irq)
+static void sa1111_ack_irq(unsigned int irq)
 {
-	INTSTATCLR0 = SA1111_IRQMASK_LO(irq);
 }
 
 static void sa1111_mask_lowirq(unsigned int irq)
@@ -133,18 +258,13 @@
 }
 
 static struct irqchip sa1111_low_chip = {
-	.ack		= sa1111_ack_lowirq,
+	.ack		= sa1111_ack_irq,
 	.mask		= sa1111_mask_lowirq,
 	.unmask		= sa1111_unmask_lowirq,
 	.rerun		= sa1111_rerun_lowirq,
 	.type		= sa1111_type_lowirq,
 };
 
-static void sa1111_ack_highirq(unsigned int irq)
-{
-	INTSTATCLR1 = SA1111_IRQMASK_HI(irq);
-}
-
 static void sa1111_mask_highirq(unsigned int irq)
 {
 	INTEN1 &= ~SA1111_IRQMASK_HI(irq);
@@ -198,34 +318,40 @@
 }
 
 static struct irqchip sa1111_high_chip = {
-	.ack		= sa1111_ack_highirq,
+	.ack		= sa1111_ack_irq,
 	.mask		= sa1111_mask_highirq,
 	.unmask		= sa1111_unmask_highirq,
 	.rerun		= sa1111_rerun_highirq,
 	.type		= sa1111_type_highirq,
 };
 
-static void __init sa1111_init_irq(int irq_nr)
+static void __init sa1111_init_irq(struct sa1111_dev *sadev)
 {
 	unsigned int irq;
 
-	request_mem_region(_INTTEST0, 512, "irqs");
+	/*
+	 * We're guaranteed that this region hasn't been taken.
+	 */
+	request_mem_region(sadev->res.start, 512, "irqs");
 
 	/* disable all IRQs */
-	INTEN0 = 0;
-	INTEN1 = 0;
+	sa1111_writel(0, sadev->mapbase + SA1111_INTEN0);
+	sa1111_writel(0, sadev->mapbase + SA1111_INTEN1);
+	sa1111_writel(0, sadev->mapbase + SA1111_WAKEEN0);
+	sa1111_writel(0, sadev->mapbase + SA1111_WAKEEN1);
 
 	/*
 	 * detect on rising edge.  Note: Feb 2001 Errata for SA1111
 	 * specifies that S0ReadyInt and S1ReadyInt should be '1'.
 	 */
-	INTPOL0 = 0;
-	INTPOL1 = SA1111_IRQMASK_HI(S0_READY_NINT) |
-		  SA1111_IRQMASK_HI(S1_READY_NINT);
+	sa1111_writel(0, sadev->mapbase + SA1111_INTPOL0);
+	sa1111_writel(SA1111_IRQMASK_HI(IRQ_S0_READY_NINT) |
+		      SA1111_IRQMASK_HI(IRQ_S1_READY_NINT),
+		      sadev->mapbase + SA1111_INTPOL1);
 
 	/* clear all IRQs */
-	INTSTATCLR0 = ~0;
-	INTSTATCLR1 = ~0;
+	sa1111_writel(~0, sadev->mapbase + SA1111_INTSTATCLR0);
+	sa1111_writel(~0, sadev->mapbase + SA1111_INTSTATCLR1);
 
 	for (irq = IRQ_GPAIN0; irq <= SSPROR; irq++) {
 		set_irq_chip(irq, &sa1111_low_chip);
@@ -233,7 +359,7 @@
 		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
 	}
 
-	for (irq = AUDXMTDMADONEA; irq <= S1_BVD1_STSCHG; irq++) {
+	for (irq = AUDXMTDMADONEA; irq <= IRQ_S1_BVD1_STSCHG; irq++) {
 		set_irq_chip(irq, &sa1111_high_chip);
 		set_irq_handler(irq, do_edge_IRQ);
 		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
@@ -242,24 +368,11 @@
 	/*
 	 * Register SA1111 interrupt
 	 */
-	set_irq_type(irq_nr, IRQT_RISING);
-	set_irq_chained_handler(irq_nr, sa1111_irq_handler);
+	set_irq_type(sadev->irq[0], IRQT_RISING);
+	set_irq_chained_handler(sadev->irq[0], sa1111_irq_handler);
 }
 
-static int sa1111_suspend(struct device *dev, u32 state, u32 level)
-{
-	return 0;
-}
-
-static int sa1111_resume(struct device *dev, u32 level)
-{
-	return 0;
-}
-
-static struct device_driver sa1111_device_driver = {
-	.suspend	= sa1111_suspend,
-	.resume		= sa1111_resume,
-};
+static struct device_driver sa1111_device_driver;
 
 /**
  *	sa1111_probe - probe for a single SA1111 chip.
@@ -274,30 +387,38 @@
  *	%0		successful.
  */
 static int __init
-sa1111_probe(struct device *parent, unsigned long phys_addr)
+sa1111_probe(unsigned long phys_addr, int irq)
 {
-	struct sa1111_device *sa;
+	struct sa1111 *sachip;
 	unsigned long id;
-	int ret = -ENODEV;
+	unsigned int has_devs;
+	int i, ret = -ENODEV;
 
-	sa = kmalloc(sizeof(struct sa1111_device), GFP_KERNEL);
-	if (!sa)
+	sachip = kmalloc(sizeof(struct sa1111), GFP_KERNEL);
+	if (!sachip)
 		return -ENOMEM;
 
-	memset(sa, 0, sizeof(struct sa1111_device));
+	memset(sachip, 0, sizeof(struct sa1111));
+
+	spin_lock_init(&sachip->lock);
 
-	sa->resource.name  = "SA1111";
-	sa->resource.start = phys_addr;
-	sa->resource.end   = phys_addr + 0x2000;
+	strncpy(sachip->dev.name, "Intel Corporation SA1111", sizeof(sachip->dev.name));
+	snprintf(sachip->dev.bus_id, sizeof(sachip->dev.bus_id), "%8.8lx", phys_addr);
+	sachip->dev.driver = &sa1111_device_driver;
+	sachip->dev.driver_data = sachip;
 
-	if (request_resource(&iomem_resource, &sa->resource)) {
+	sachip->res.name  = sachip->dev.name;
+	sachip->res.start = phys_addr;
+	sachip->res.end   = phys_addr + 0x2000;
+	sachip->irq = irq;
+
+	if (request_resource(&iomem_resource, &sachip->res)) {
 		ret = -EBUSY;
 		goto out;
 	}
 
-	/* eventually ioremap... */
-	sa->base = (void *)0xf4000000;
-	if (!sa->base) {
+	sachip->base = ioremap(phys_addr, PAGE_SIZE * 2);
+	if (!sachip->base) {
 		ret = -ENOMEM;
 		goto release;
 	}
@@ -305,7 +426,7 @@
 	/*
 	 * Probe for the chip.  Only touch the SBI registers.
 	 */
-	id = sa1111_readl(sa->base + SA1111_SKID);
+	id = sa1111_readl(sachip->base + SA1111_SKID);
 	if ((id & SKID_ID_MASK) != SKID_SA1111_ID) {
 		printk(KERN_DEBUG "SA1111 not detected: ID = %08lx\n", id);
 		ret = -ENODEV;
@@ -315,12 +436,7 @@
 	/*
 	 * We found the chip.
 	 */
-	strcpy(sa->dev.name, "SA1111");
-	sprintf(sa->dev.bus_id, "%8.8lx", phys_addr);
-	sa->dev.parent = parent;
-	sa->dev.driver = &sa1111_device_driver;
-
-	ret = device_register(&sa->dev);
+	ret = register_sys_device(&sachip->dev);
 	if (ret)
 		printk("sa1111 device_register failed: %d\n", ret);
 
@@ -328,19 +444,64 @@
 		"silicon revision %lx, metal revision %lx\n",
 		(id & SKID_SIREV_MASK)>>4, (id & SKID_MTREV_MASK));
 
-	sa1111 = sa;
+	g_sa1111 = sachip;
+
+	has_devs = ~0;
+	if (machine_is_assabet() || machine_is_jornada720() ||
+	    machine_is_badge4())
+		has_devs &= ~(1 << 4);
+	else
+		has_devs &= ~(1 << 1);
+
+	for (i = 0; i < ARRAY_SIZE(devs); i++) {
+		if (!(has_devs & (1 << i)))
+			continue;
+
+		snprintf(devs[i]->dev.bus_id, sizeof(devs[i]->dev.bus_id),
+			 "%4.4x", dev_offset[i]);
+
+		devs[i]->dev.parent = &sachip->dev;
+		devs[i]->dev.bus    = &sa1111_bus_type;
+		devs[i]->res.start  = sachip->res.start + dev_offset[i];
+		devs[i]->res.end    = devs[i]->res.start + 511;
+		devs[i]->res.name   = devs[i]->dev.name;
+		devs[i]->res.flags  = IORESOURCE_MEM;
+		devs[i]->mapbase    = sachip->base + dev_offset[i];
+
+		if (request_resource(&sachip->res, &devs[i]->res)) {
+			printk("SA1111: failed to allocate resource for %s\n",
+				devs[i]->res.name);
+			continue;
+		}
+
+		device_register(&devs[i]->dev);
+	}
 
 	return 0;
 
  unmap:
-//	iounmap(sa->base);
+	iounmap(sachip->base);
  release:
-	release_resource(&sa->resource);
+	release_resource(&sachip->res);
  out:
-	kfree(sa);
+	kfree(sachip);
 	return ret;
 }
 
+static void __sa1111_remove(struct sa1111 *sachip)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(devs); i++) {
+		put_device(&devs[i]->dev);
+		release_resource(&devs[i]->res);
+	}
+
+	iounmap(sachip->base);
+	release_resource(&sachip->res);
+	kfree(sachip);
+}
+
 /*
  * Bring the SA1111 out of reset.  This requires a set procedure:
  *  1. nRESET asserted (by hardware)
@@ -355,12 +516,11 @@
  *   SBI_SMCR
  *   SBI_SKID
  */
-void sa1111_wake(void)
+static void sa1111_wake(struct sa1111 *sachip)
 {
-	struct sa1111_device *sa = sa1111;
 	unsigned long flags, r;
 
-	local_irq_save(flags);
+	spin_lock_irqsave(&sachip->lock, flags);
 
 	/*
 	 * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111:
@@ -373,11 +533,11 @@
 	/*
 	 * Turn VCO on, and disable PLL Bypass.
 	 */
-	r = sa1111_readl(sa->base + SA1111_SKCR);
+	r = sa1111_readl(sachip->base + SA1111_SKCR);
 	r &= ~SKCR_VCO_OFF;
-	sa1111_writel(r, sa->base + SA1111_SKCR);
+	sa1111_writel(r, sachip->base + SA1111_SKCR);
 	r |= SKCR_PLL_BYPASS | SKCR_OE_EN;
-	sa1111_writel(r, sa->base + SA1111_SKCR);
+	sa1111_writel(r, sachip->base + SA1111_SKCR);
 
 	/*
 	 * Wait lock time.  SA1111 manual _doesn't_
@@ -389,7 +549,7 @@
 	 * Enable RCLK.  We also ensure that RDYEN is set.
 	 */
 	r |= SKCR_RCLKEN | SKCR_RDYEN;
-	sa1111_writel(r, sa->base + SA1111_SKCR);
+	sa1111_writel(r, sachip->base + SA1111_SKCR);
 
 	/*
 	 * Wait 14 RCLK cycles for the chip to finish coming out
@@ -400,76 +560,31 @@
 	/*
 	 * Ensure all clocks are initially off.
 	 */
-	sa1111_writel(0, sa->base + SA1111_SKPCR);
+	sa1111_writel(0, sachip->base + SA1111_SKPCR);
 
-	local_irq_restore(flags);
-}
-
-void sa1111_doze(void)
-{
-	struct sa1111_device *sa = sa1111;
-	unsigned long flags;
-	unsigned int val;
-
-	local_irq_save(flags);
-
-	if (sa1111_readl(sa->base + SA1111_SKPCR) & SKPCR_UCLKEN) {
-		local_irq_restore(flags);
-		printk("SA1111 doze mode refused\n");
-		return;
-	}
-
-	val = sa1111_readl(sa->base + SA1111_SKCR);
-	sa1111_writel(val & ~SKCR_RCLKEN, sa->base + SA1111_SKCR);
-	local_irq_restore(flags);
+	spin_unlock_irqrestore(&sachip->lock, flags);
 }
 
 /*
  * Configure the SA1111 shared memory controller.
  */
-void sa1111_configure_smc(int sdram, unsigned int drac, unsigned int cas_latency)
+void
+sa1111_configure_smc(struct sa1111 *sachip, int sdram, unsigned int drac,
+		     unsigned int cas_latency)
 {
-	struct sa1111_device *sa = sa1111;
 	unsigned int smcr = SMCR_DTIM | SMCR_MBGE | FInsrt(drac, SMCR_DRAC);
 
 	if (cas_latency == 3)
 		smcr |= SMCR_CLAT;
 
-	sa1111_writel(smcr, sa->base + SA1111_SMCR);
+	sa1111_writel(smcr, sachip->base + SA1111_SMCR);
 }
 
-EXPORT_SYMBOL(sa1111_wake);
-EXPORT_SYMBOL(sa1111_doze);
-
-void sa1111_enable_device(unsigned int mask)
-{
-	struct sa1111_device *sa = sa1111;
-	unsigned int val;
-
-	preempt_disable();
-	val = sa1111_readl(sa->base + SA1111_SKPCR);
-	sa1111_writel(val | mask, sa->base + SA1111_SKPCR);
-	preempt_enable();
-}
-
-void sa1111_disable_device(unsigned int mask)
-{
-	struct sa1111_device *sa = sa1111;
-	unsigned int val;
-
-	preempt_disable();
-	val = sa1111_readl(sa->base + SA1111_SKPCR);
-	sa1111_writel(val & ~mask, sa->base + SA1111_SKPCR);
-	preempt_enable();
-}
-
-EXPORT_SYMBOL(sa1111_enable_device);
-EXPORT_SYMBOL(sa1111_disable_device);
-
-/* According to the "Intel StrongARM SA-1111 Microprocessor Companion
+/*
+ * According to the "Intel StrongARM SA-1111 Microprocessor Companion
  * Chip Specification Update" (June 2000), erratum #7, there is a
- * significant bug in Serial Audio Controller DMA. If the SAC is
- * accessing a region of memory above 1MB relative to the bank base,
+ * significant bug in the SA1111 SDRAM shared memory controller.  If
+ * an access to a region of memory above 1MB relative to the bank base,
  * it is important that address bit 10 _NOT_ be asserted. Depending
  * on the configuration of the RAM, bit 10 may correspond to one
  * of several different (processor-relative) address bits.
@@ -479,7 +594,9 @@
  */
 int sa1111_check_dma_bug(dma_addr_t addr)
 {
-	unsigned int physaddr=SA1111_DMA_ADDR((unsigned int)addr);
+	struct sa1111 *sachip = g_sa1111;
+	unsigned int physaddr = SA1111_DMA_ADDR((unsigned int)addr);
+	unsigned int smcr;
 
 	/* Section 4.6 of the "Intel StrongARM SA-1111 Development Module
 	 * User's Guide" mentions that jumpers R51 and R52 control the
@@ -494,9 +611,10 @@
 	 * above the start of the target bank:
 	 */
 	if (physaddr<(1<<20))
-	  	return 0;
+		return 0;
 
-	switch (FExtr(SBI_SMCR, SMCR_DRAC)) {
+	smcr = sa1111_readl(sachip->base + SA1111_SMCR);
+	switch (FExtr(smcr, SMCR_DRAC)) {
 	case 01: /* 10 row + bank address bits, A<20> must not be set */
 	  	if (physaddr & (1<<20))
 		  	return -1;
@@ -523,27 +641,26 @@
 		break;
 	default:
 	  	printk(KERN_ERR "%s(): invalid SMCR DRAC value 0%lo\n",
-		       __FUNCTION__, FExtr(SBI_SMCR, SMCR_DRAC));
+		       __FUNCTION__, FExtr(smcr, SMCR_DRAC));
 		return -1;
 	}
 
 	return 0;
 }
 
-EXPORT_SYMBOL(sa1111_check_dma_bug);
-
-int sa1111_init(struct device *parent, unsigned long phys, unsigned int irq)
+int sa1111_init(unsigned long phys, unsigned int irq)
 {
+	unsigned int val;
 	int ret;
 
-	ret = sa1111_probe(parent, phys);
+	ret = sa1111_probe(phys, irq);
 	if (ret < 0)
 		return ret;
 
 	/*
 	 * We found it.  Wake the chip up.
 	 */
-	sa1111_wake();
+	sa1111_wake(g_sa1111);
 
 	/*
 	 * The SDRAM configuration of the SA1110 and the SA1111 must
@@ -552,7 +669,7 @@
 	 * MBGNT signal, so we must have called sa1110_mb_disable()
 	 * beforehand.
 	 */
-	sa1111_configure_smc(1,
+	sa1111_configure_smc(g_sa1111, 1,
 			     FExtr(MDCNFG, MDCNFG_SA1110_DRAC0),
 			     FExtr(MDCNFG, MDCNFG_SA1110_TDL0));
 
@@ -560,7 +677,8 @@
 	 * We only need to turn on DCLK whenever we want to use the
 	 * DMA.  It can otherwise be held firmly in the off position.
 	 */
-	sa1111_enable_device(SKPCR_DCLKEN);
+	val = sa1111_readl(g_sa1111->base + SA1111_SKPCR);
+	sa1111_writel(val | SKPCR_DCLKEN, g_sa1111->base + SA1111_SKPCR);
 
 	/*
 	 * Enable the SA1110 memory bus request and grant signals.
@@ -570,7 +688,341 @@
 	/*
 	 * Initialise SA1111 IRQs
 	 */
-	sa1111_init_irq(irq);
+	int_dev.irq[0] = irq;
+	sa1111_init_irq(&int_dev);
+
+	return 0;
+}
+
+struct sa1111_save_data {
+	unsigned int	skcr;
+	unsigned int	skpcr;
+	unsigned int	skcdr;
+	unsigned char	skaud;
+	unsigned char	skpwm0;
+	unsigned char	skpwm1;
+
+	/*
+	 * Interrupt controller
+	 */
+	unsigned int	intpol0;
+	unsigned int	intpol1;
+	unsigned int	inten0;
+	unsigned int	inten1;
+	unsigned int	wakepol0;
+	unsigned int	wakepol1;
+	unsigned int	wakeen0;
+	unsigned int	wakeen1;
+};
+
+static int sa1111_suspend(struct device *dev, u32 state, u32 level)
+{
+	struct sa1111 *sachip = dev->driver_data;
+	unsigned long flags;
+	char *base;
+
+	/*
+	 * Save state.
+	 */
+	if (level == SUSPEND_SAVE_STATE ||
+	    level == SUSPEND_DISABLE ||
+	    level == SUSPEND_POWER_DOWN) {
+		struct sa1111_save_data *save;
+
+		if (!dev->saved_state)
+			dev->saved_state = kmalloc(sizeof(struct sa1111_save_data), GFP_KERNEL);
+		if (!dev->saved_state)
+			return -ENOMEM;
+
+		save = (struct sa1111_save_data *)dev->saved_state;
+
+		spin_lock_irqsave(&sachip->lock, flags);
+		base = sachip->base;
+		save->skcr     = sa1111_readl(base + SA1111_SKCR);
+		save->skpcr    = sa1111_readl(base + SA1111_SKPCR);
+		save->skcdr    = sa1111_readl(base + SA1111_SKCDR);
+		save->skaud    = sa1111_readl(base + SA1111_SKAUD);
+		save->skpwm0   = sa1111_readl(base + SA1111_SKPWM0);
+		save->skpwm1   = sa1111_readl(base + SA1111_SKPWM1);
+
+		base = sachip->base + SA1111_INTC;
+		save->intpol0  = sa1111_readl(base + SA1111_INTPOL0);
+		save->intpol1  = sa1111_readl(base + SA1111_INTPOL1);
+		save->inten0   = sa1111_readl(base + SA1111_INTEN0);
+		save->inten1   = sa1111_readl(base + SA1111_INTEN1);
+		save->wakepol0 = sa1111_readl(base + SA1111_WAKEPOL0);
+		save->wakepol1 = sa1111_readl(base + SA1111_WAKEPOL1);
+		save->wakeen0  = sa1111_readl(base + SA1111_WAKEEN0);
+		save->wakeen1  = sa1111_readl(base + SA1111_WAKEEN1);
+		spin_unlock_irqrestore(&sachip->lock, flags);
+	}
+
+	/*
+	 * Disable.
+	 */
+	if (level == SUSPEND_DISABLE && state == 4) {
+		unsigned int val;
+
+		spin_lock_irqsave(&sachip->lock, flags);
+		base = sachip->base;
+
+		sa1111_writel(0, base + SA1111_SKPWM0);
+		sa1111_writel(0, base + SA1111_SKPWM1);
+		val = sa1111_readl(base + SA1111_SKCR);
+		sa1111_writel(val | SKCR_SLEEP, base + SA1111_SKCR);
+
+		spin_unlock_irqrestore(&sachip->lock, flags);
+	}
 
 	return 0;
 }
+
+/*
+ *	sa1111_resume - Restore the SA1111 device state.
+ *	@dev: device to restore
+ *	@level: resume level
+ *
+ *	Restore the general state of the SA1111; clock control and
+ *	interrupt controller.  Other parts of the SA1111 must be
+ *	restored by their respective drivers, and must be called
+ *	via LDM after this function.
+ */
+static int sa1111_resume(struct device *dev, u32 level)
+{
+	struct sa1111 *sachip = dev->driver_data;
+	struct sa1111_save_data *save;
+	unsigned long flags, id;
+	char *base;
+
+	if (level != RESUME_RESTORE_STATE && level != RESUME_ENABLE)
+		return 0;
+
+	save = (struct sa1111_save_data *)dev->saved_state;
+	if (!save)
+		return 0;
+
+	dev->saved_state = NULL;
+
+	/*
+	 * Ensure that the SA1111 is still here.
+	 */
+	id = sa1111_readl(sachip->base + SA1111_SKID);
+	if ((id & SKID_ID_MASK) != SKID_SA1111_ID) {
+		__sa1111_remove(sachip);
+		kfree(save);
+		return 0;
+	}
+
+	spin_lock_irqsave(&sachip->lock, flags);
+	sa1111_wake(sachip);
+
+	base = sachip->base;
+	sa1111_writel(save->skcr,     base + SA1111_SKCR);
+	sa1111_writel(save->skpcr,    base + SA1111_SKPCR);
+	sa1111_writel(save->skcdr,    base + SA1111_SKCDR);
+	sa1111_writel(save->skaud,    base + SA1111_SKAUD);
+	sa1111_writel(save->skpwm0,   base + SA1111_SKPWM0);
+	sa1111_writel(save->skpwm1,   base + SA1111_SKPWM1);
+
+	base = sachip->base + SA1111_INTC;
+	sa1111_writel(save->intpol0,  base + SA1111_INTPOL0);
+	sa1111_writel(save->intpol1,  base + SA1111_INTPOL1);
+	sa1111_writel(save->inten0,   base + SA1111_INTEN0);
+	sa1111_writel(save->inten1,   base + SA1111_INTEN1);
+	sa1111_writel(save->wakepol0, base + SA1111_WAKEPOL0);
+	sa1111_writel(save->wakepol1, base + SA1111_WAKEPOL1);
+	sa1111_writel(save->wakeen0,  base + SA1111_WAKEEN0);
+	sa1111_writel(save->wakeen1,  base + SA1111_WAKEEN1);
+	spin_unlock_irqrestore(&sachip->lock, flags);
+
+	kfree(save);
+
+	return 0;
+}
+
+static struct device_driver sa1111_device_driver = {
+	.suspend	= sa1111_suspend,
+	.resume		= sa1111_resume,
+};
+
+/*
+ *	Get the parent device driver (us) structure
+ *	from a child function device
+ */
+static inline struct sa1111 *sa1111_chip_driver(struct sa1111_dev *sadev)
+{
+	return (struct sa1111 *)sadev->dev.parent->driver_data;
+}
+
+/*
+ * The bits in the opdiv field are non-linear.
+ */
+static unsigned char opdiv_table[] = { 1, 4, 2, 8 };
+
+static unsigned int __sa1111_pll_clock(struct sa1111 *sachip)
+{
+	unsigned int skcdr, fbdiv, ipdiv, opdiv;
+
+	skcdr = sa1111_readl(sachip->base + SA1111_SKCDR);
+
+	fbdiv = (skcdr & 0x007f) + 2;
+	ipdiv = ((skcdr & 0x0f80) >> 7) + 2;
+	opdiv = opdiv_table[(skcdr & 0x3000) >> 12];
+
+	return 3686400 * fbdiv / (ipdiv * opdiv);
+}
+
+/**
+ *	sa1111_pll_clock - return the current PLL clock frequency.
+ *	@sadev: SA1111 function block
+ *
+ *	BUG: we should look at SKCR.  We also blindly believe that
+ *	the chip is being fed with the 3.6864MHz clock.
+ *
+ *	Returns the PLL clock in Hz.
+ */
+unsigned int sa1111_pll_clock(struct sa1111_dev *sadev)
+{
+	struct sa1111 *sachip = sa1111_chip_driver(sadev);
+
+	return __sa1111_pll_clock(sachip);
+}
+
+/**
+ *	sa1111_select_audio_mode - select I2S or AC link mode
+ *	@sadev: SA1111 function block
+ *	@mode: One of %SA1111_AUDIO_ACLINK or %SA1111_AUDIO_I2S
+ *
+ *	Frob the SKCR to select AC Link mode or I2S mode for
+ *	the audio block.
+ */
+void sa1111_select_audio_mode(struct sa1111_dev *sadev, int mode)
+{
+	struct sa1111 *sachip = sa1111_chip_driver(sadev);
+	unsigned long flags;
+	unsigned int val;
+
+	spin_lock_irqsave(&sachip->lock, flags);
+
+	val = sa1111_readl(sachip->base + SA1111_SKCR);
+	if (mode == SA1111_AUDIO_I2S) {
+		val &= ~SKCR_SELAC;
+	} else {
+		val |= SKCR_SELAC;
+	}
+	sa1111_writel(val, sachip->base + SA1111_SKCR);
+
+	spin_unlock_irqrestore(&sachip->lock, flags);
+}
+
+/**
+ *	sa1111_set_audio_rate - set the audio sample rate
+ *	@sadev: SA1111 SAC function block
+ *	@rate: sample rate to select
+ */
+int sa1111_set_audio_rate(struct sa1111_dev *sadev, int rate)
+{
+	struct sa1111 *sachip = sa1111_chip_driver(sadev);
+	unsigned int div;
+
+	if (sadev->devid != SA1111_DEVID_SAC)
+		return -EINVAL;
+
+	div = (__sa1111_pll_clock(sachip) / 256 + rate / 2) / rate;
+	if (div == 0)
+		div = 1;
+	if (div > 128)
+		div = 128;
+
+	sa1111_writel(div - 1, sachip->base + SA1111_SKAUD);
+
+	return 0;
+}
+
+/**
+ *	sa1111_get_audio_rate - get the audio sample rate
+ *	@sadev: SA1111 SAC function block device
+ */
+int sa1111_get_audio_rate(struct sa1111_dev *sadev)
+{
+	struct sa1111 *sachip = sa1111_chip_driver(sadev);
+	unsigned long div;
+
+	if (sadev->devid != SA1111_DEVID_SAC)
+		return -EINVAL;
+
+	div = sa1111_readl(sachip->base + SA1111_SKAUD) + 1;
+
+	return __sa1111_pll_clock(sachip) / (256 * div);
+}
+
+/*
+ * Individual device operations.
+ */
+
+/**
+ *	sa1111_enable_device - enable an on-chip SA1111 function block
+ *	@sadev: SA1111 function block device to enable
+ */
+void sa1111_enable_device(struct sa1111_dev *sadev)
+{
+	struct sa1111 *sachip = sa1111_chip_driver(sadev);
+	unsigned long flags;
+	unsigned int val;
+
+	spin_lock_irqsave(&sachip->lock, flags);
+	val = sa1111_readl(sachip->base + SA1111_SKPCR);
+	sa1111_writel(val | sadev->skpcr_mask, sachip->base + SA1111_SKPCR);
+	spin_unlock_irqrestore(&sachip->lock, flags);
+}
+
+/**
+ *	sa1111_disable_device - disable an on-chip SA1111 function block
+ *	@sadev: SA1111 function block device to disable
+ */
+void sa1111_disable_device(struct sa1111_dev *sadev)
+{
+	struct sa1111 *sachip = sa1111_chip_driver(sadev);
+	unsigned long flags;
+	unsigned int val;
+
+	spin_lock_irqsave(&sachip->lock, flags);
+	val = sa1111_readl(sachip->base + SA1111_SKPCR);
+	sa1111_writel(val & ~sadev->skpcr_mask, sachip->base + SA1111_SKPCR);
+	spin_unlock_irqrestore(&sachip->lock, flags);
+}
+
+/*
+ *	SA1111 "Register Access Bus."
+ *
+ *	We model this as a regular bus type, and hang devices directly
+ *	off this.
+ */
+static int sa1111_match(struct device *_dev, struct device_driver *_drv)
+{
+	struct sa1111_dev *dev = SA1111_DEV(_dev);
+	struct sa1111_driver *drv = SA1111_DRV(_drv);
+
+	return dev->devid == drv->devid;
+}
+
+struct bus_type sa1111_bus_type = {
+	.name	= "RAB",
+	.match	= sa1111_match,
+};
+
+static int sa1111_rab_bus_init(void)
+{
+	return bus_register(&sa1111_bus_type);
+}
+
+postcore_initcall(sa1111_rab_bus_init);
+
+EXPORT_SYMBOL(sa1111_check_dma_bug);
+EXPORT_SYMBOL(sa1111_select_audio_mode);
+EXPORT_SYMBOL(sa1111_set_audio_rate);
+EXPORT_SYMBOL(sa1111_get_audio_rate);
+EXPORT_SYMBOL(sa1111_enable_device);
+EXPORT_SYMBOL(sa1111_disable_device);
+EXPORT_SYMBOL(sa1111_pll_clock);
+EXPORT_SYMBOL(sa1111_bus_type);
diff -Nru a/arch/arm/mach-sa1100/sa1111.h b/arch/arm/mach-sa1100/sa1111.h
--- a/arch/arm/mach-sa1100/sa1111.h	Tue Oct  1 00:08:17 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,20 +0,0 @@
-/*
- * linux/arch/arm/mach-sa1100/sa1111.h
- */
-struct device;
-
-/*
- * Probe for a SA1111 chip.
- */
-extern int
-sa1111_init(struct device *parent, unsigned long phys, unsigned int irq);
-
-/*
- * Wake up a SA1111 chip.
- */
-extern void sa1111_wake(void);
-
-/*
- * Doze the SA1111 chip.
- */
-extern void sa1111_doze(void);
diff -Nru a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c
--- a/arch/arm/mach-sa1100/simpad.c	Tue Oct  1 00:08:15 2002
+++ b/arch/arm/mach-sa1100/simpad.c	Tue Oct  1 00:08:15 2002
@@ -131,7 +131,7 @@
 	return 0;
 }
  
-__initcall(cs3_init);
+arch_initcall(cs3_init);
 
 #endif // CONFIG_PROC_FS
 
diff -Nru a/arch/arm/mach-sa1100/stork.c b/arch/arm/mach-sa1100/stork.c
--- a/arch/arm/mach-sa1100/stork.c	Tue Oct  1 00:08:18 2002
+++ b/arch/arm/mach-sa1100/stork.c	Tue Oct  1 00:08:18 2002
@@ -284,25 +284,17 @@
     storkClockShortToDtoA(0x0A00);	/* turn on the brightness */
 }
 
-/* see asm-arm/keyboard.h - there are a bunch of basically virtual functions required */
-/* we have to fill in for them or else we can't call handle_scancode when we see a button pressed */
-
-static int
-stork_kbd_translate(unsigned char scancode, unsigned char *keycode, char rawmode)
-{
-    if (keycode)
-	*keycode = scancode;
-
-    return 1;
-}
-
-static char
-stork_kbd_unexpected_up(unsigned char code)
+static void stork_lcd_power(int on)
 {
-    return 0;
+	if (on) {
+		storkSetLCDCPLD(0, 1);
+		storkSetLatchA(STORK_LCD_BACKLIGHT_INVERTER_ON);
+	} else {
+		storkSetLCDCPLD(0, 0);
+		storkClearLatchA(STORK_LCD_BACKLIGHT_INVERTER_ON);
+	}
 }
 
-
 struct map_desc stork_io_desc[] __initdata = {
  /* virtual     physical    length      type */
   { STORK_VM_BASE_CS1, STORK_VM_OFF_CS1, 0x01000000, MT_DEVICE }, /* EGPIO 0 */
@@ -331,8 +323,7 @@
 
     storkInitTSandDtoA();
 
-    k_translate = stork_kbd_translate;
-    k_unexpected_up = stork_kbd_unexpected_up;
+    sa1100fb_lcd_power = stork_lcd_power;
 
     return 0;
 }
diff -Nru a/arch/arm/mach-sa1100/system3.c b/arch/arm/mach-sa1100/system3.c
--- a/arch/arm/mach-sa1100/system3.c	Tue Oct  1 00:08:19 2002
+++ b/arch/arm/mach-sa1100/system3.c	Tue Oct  1 00:08:19 2002
@@ -56,7 +56,6 @@
 #include <linux/serial_core.h>
 
 #include "generic.h"
-#include "sa1111.h"
 #include <asm/hardware/sa1111.h>
 
 #define DEBUG 1
@@ -401,7 +400,7 @@
 	/*
 	 * Probe for a SA1111.
 	 */
-	ret = sa1111_init(NULL, PT_SA1111_BASE, IRQ_SYSTEM3_SA1111);
+	ret = sa1111_init(PT_SA1111_BASE, IRQ_SYSTEM3_SA1111);
 	if (ret < 0) {
 		printk( KERN_WARNING"PT Digital Board: no SA1111 found!\n" );
 		goto DONE;
@@ -429,7 +428,7 @@
 /**********************************************************************
  *  kernel magic macros
  */
-__initcall(system3_init);
+arch_initcall(system3_init);
 
 MACHINE_START(PT_SYSTEM3, "PT System 3")
 	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
diff -Nru a/arch/arm/mach-sa1100/xp860.c b/arch/arm/mach-sa1100/xp860.c
--- a/arch/arm/mach-sa1100/xp860.c	Tue Oct  1 00:08:17 2002
+++ b/arch/arm/mach-sa1100/xp860.c	Tue Oct  1 00:08:17 2002
@@ -54,7 +54,7 @@
 	return 0;
 }
 
-__initcall(xp860_init);
+arch_initcall(xp860_init);
 
 static struct map_desc xp860_io_desc[] __initdata = {
  /* virtual     physical    length      type */
diff -Nru a/arch/arm/mach-sa1100/yopy.c b/arch/arm/mach-sa1100/yopy.c
--- a/arch/arm/mach-sa1100/yopy.c	Tue Oct  1 00:08:15 2002
+++ b/arch/arm/mach-sa1100/yopy.c	Tue Oct  1 00:08:15 2002
@@ -65,7 +65,7 @@
 	return 0;
 }
 
-__initcall(yopy_hw_init);
+arch_initcall(yopy_hw_init);
 
 
 static struct map_desc yopy_io_desc[] __initdata = {
diff -Nru a/arch/arm/mm/abort-lv4t.S b/arch/arm/mm/abort-lv4t.S
--- a/arch/arm/mm/abort-lv4t.S	Tue Oct  1 00:08:20 2002
+++ b/arch/arm/mm/abort-lv4t.S	Tue Oct  1 00:08:20 2002
@@ -21,9 +21,9 @@
 	tst	r3, #PSR_T_BIT			@ check for thumb mode
 	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
 	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
-	bic	r1, r1, #1 << 11 | 1 << 10	@ clear bits 11 and 10 of FSR
-	ldreq	r8, [r2]			@ read arm instruction
 	bne	.data_thumb_abort
+	ldr	r8, [r2]			@ read arm instruction
+	bic	r1, r1, #1 << 11 | 1 << 10	@ clear bits 11 and 10 of FSR
 	tst	r8, #1 << 20			@ L = 1 -> write?
 	orreq	r1, r1, #1 << 11		@ yes.
 	and	r7, r8, #15 << 24
@@ -203,7 +203,7 @@
 	ldr	r7, [sp, #13 << 2]
 	tst	r8, #1 << 11
 	addne	r7, r7, r6, lsl #2		@ increment SP if PUSH
-	subeq	r7, r7, r6, lsr #2		@ decrement SP if POP
+	subeq	r7, r7, r6, lsl #2		@ decrement SP if POP
 	str	r7, [sp, #13 << 2]
 	mov	pc, lr
 
diff -Nru a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
--- a/arch/arm/mm/alignment.c	Tue Oct  1 00:08:15 2002
+++ b/arch/arm/mm/alignment.c	Tue Oct  1 00:08:15 2002
@@ -611,4 +611,4 @@
 	return 0;
 }
 
-__initcall(alignment_init);
+fs_initcall(alignment_init);
diff -Nru a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c
--- a/arch/arm/mm/consistent.c	Tue Oct  1 00:08:16 2002
+++ b/arch/arm/mm/consistent.c	Tue Oct  1 00:08:16 2002
@@ -98,7 +98,8 @@
 {
 	int gfp = GFP_KERNEL;
 
-	if (hwdev == NULL || hwdev->dma_mask != 0xffffffff)
+	if (hwdev == NULL || dev_is_sa1111(hwdev) ||
+	    hwdev->dma_mask != 0xffffffff)
 		gfp |= GFP_DMA;
 
 	return consistent_alloc(gfp, size, handle);
diff -Nru a/arch/arm/mm/fault-common.c b/arch/arm/mm/fault-common.c
--- a/arch/arm/mm/fault-common.c	Tue Oct  1 00:08:15 2002
+++ b/arch/arm/mm/fault-common.c	Tue Oct  1 00:08:15 2002
@@ -35,7 +35,7 @@
 #else
 /*
  * "code" is actually the FSR register.  Bit 11 set means the
- * isntruction was performing a write.
+ * instruction was performing a write.
  */
 #define DO_COW(code)		((code) & (1 << 11))
 #define READ_FAULT(code)	(!DO_COW(code))
@@ -54,7 +54,7 @@
 
 	printk(KERN_ALERT "pgd = %p\n", mm->pgd);
 	pgd = pgd_offset(mm, addr);
-	printk(KERN_ALERT "*pgd=%08lx", pgd_val(*pgd));
+	printk(KERN_ALERT "[%08lx] *pgd=%08lx", addr, pgd_val(*pgd));
 
 	do {
 		pmd_t *pmd;
diff -Nru a/arch/arm/mm/init.c b/arch/arm/mm/init.c
--- a/arch/arm/mm/init.c	Tue Oct  1 00:08:15 2002
+++ b/arch/arm/mm/init.c	Tue Oct  1 00:08:15 2002
@@ -52,6 +52,8 @@
 
 extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
 extern char _stext, _text, _etext, _end, __init_begin, __init_end;
+extern unsigned long phys_initrd_start;
+extern unsigned long phys_initrd_size;
 
 /*
  * The sole use of this is to pass memory configuration
@@ -254,18 +256,17 @@
 static int __init check_initrd(struct meminfo *mi)
 {
 	int initrd_node = -2;
-
 #ifdef CONFIG_BLK_DEV_INITRD
+	unsigned long end = phys_initrd_start + phys_initrd_size;
+
 	/*
 	 * Make sure that the initrd is within a valid area of
 	 * memory.
 	 */
-	if (initrd_start) {
-		unsigned long phys_initrd_start, phys_initrd_end;
+	if (phys_initrd_size) {
 		unsigned int i;
 
-		phys_initrd_start = __pa(initrd_start);
-		phys_initrd_end   = __pa(initrd_end);
+		initrd_node = -1;
 
 		for (i = 0; i < mi->nr_banks; i++) {
 			unsigned long bank_end;
@@ -273,7 +274,7 @@
 			bank_end = mi->bank[i].start + mi->bank[i].size;
 
 			if (mi->bank[i].start <= phys_initrd_start &&
-			    phys_initrd_end <= bank_end)
+			    end <= bank_end)
 				initrd_node = mi->bank[i].node;
 		}
 	}
@@ -281,8 +282,8 @@
 	if (initrd_node == -1) {
 		printk(KERN_ERR "initrd (0x%08lx - 0x%08lx) extends beyond "
 		       "physical memory - disabling initrd\n",
-		       initrd_start, initrd_end);
-		initrd_start = initrd_end = 0;
+		       phys_initrd_start, end);
+		phys_initrd_start = phys_initrd_size = 0;
 	}
 #endif
 
@@ -423,9 +424,12 @@
 
 
 #ifdef CONFIG_BLK_DEV_INITRD
-	if (initrd_node >= 0)
-		reserve_bootmem_node(NODE_DATA(initrd_node), __pa(initrd_start),
-				     initrd_end - initrd_start);
+	if (phys_initrd_size && initrd_node >= 0) {
+		reserve_bootmem_node(NODE_DATA(initrd_node), phys_initrd_start,
+				     phys_initrd_size);
+		initrd_start = __phys_to_virt(phys_initrd_start);
+		initrd_end = initrd_start + phys_initrd_size;
+	}
 #endif
 
 	if (map_pg != bootmap_pfn + bootmap_pages)
diff -Nru a/arch/arm/mm/minicache.c b/arch/arm/mm/minicache.c
--- a/arch/arm/mm/minicache.c	Tue Oct  1 00:08:18 2002
+++ b/arch/arm/mm/minicache.c	Tue Oct  1 00:08:18 2002
@@ -65,4 +65,4 @@
 	return 0;
 }
 
-__initcall(minicache_init);
+core_initcall(minicache_init);
diff -Nru a/arch/arm/nwfpe/entry.S b/arch/arm/nwfpe/entry.S
--- a/arch/arm/nwfpe/entry.S	Tue Oct  1 00:08:14 2002
+++ b/arch/arm/nwfpe/entry.S	Tue Oct  1 00:08:15 2002
@@ -23,6 +23,8 @@
 /* This is the kernel's entry point into the floating point emulator.
 It is called from the kernel with code similar to this:
 
+	sub	r4, r5, #4
+	ldrt	r0, [r4]			@ r0  = instruction
 	adrsvc	al, r9, ret_from_exception	@ r9  = normal FP return
 	adrsvc	al, lr, fpundefinstr		@ lr  = undefined instr return
 
@@ -73,11 +75,7 @@
         mov r4, lr			@ save the failure-return addresses
 	mov sl, sp
 
-	bl FPA11_CheckInit		@ check to see if we are initialised
-
         ldr r5, [sp, #60]	 	@ get contents of PC;
-	sub r8, r5, #4
-.Lx2:	ldrt r0, [r8]			@ get actual instruction into r0
 emulate:
 	bl EmulateAll			@ emulate the instruction
    	cmp r0, #0			@ was emulation successful
@@ -118,5 +116,4 @@
 	.section __ex_table,"a"
 	.align	3
 	.long	.Lx1, .Lfix
-	.long	.Lx2, .Lfix
 	.previous
diff -Nru a/arch/arm/nwfpe/entry26.S b/arch/arm/nwfpe/entry26.S
--- a/arch/arm/nwfpe/entry26.S	Tue Oct  1 00:08:16 2002
+++ b/arch/arm/nwfpe/entry26.S	Tue Oct  1 00:08:16 2002
@@ -66,7 +66,6 @@
 	.globl	nwfpe_enter
 nwfpe_enter:
 	mov	sl, sp
-	bl	FPA11_CheckInit		@ check to see if we are initialised
 
 	ldr	r5, [sp, #60]		@ get contents of PC
 	bic	r5, r5, #0xfc000003
diff -Nru a/arch/arm/nwfpe/fpa11.c b/arch/arm/nwfpe/fpa11.c
--- a/arch/arm/nwfpe/fpa11.c	Tue Oct  1 00:08:16 2002
+++ b/arch/arm/nwfpe/fpa11.c	Tue Oct  1 00:08:16 2002
@@ -34,7 +34,7 @@
 unsigned int EmulateCPRT(const unsigned int);
 
 /* Reset the FPA11 chip.  Called to initialize and reset the emulator. */
-void resetFPA11(void)
+static void resetFPA11(void)
 {
   int i;
   FPA11 *fpa11 = GET_FPA11();
@@ -126,16 +126,14 @@
   }
 }
 
-void FPA11_CheckInit(void)
+void nwfpe_init(union fp_state *fp)
 {
-  FPA11 *fpa11 = GET_FPA11();
-  if (unlikely(fpa11->initflag == 0))
-  {
-    resetFPA11();
-    SetRoundingMode(ROUND_TO_NEAREST);
-    SetRoundingPrecision(ROUND_EXTENDED);
-    fpa11->initflag = 1;
-  }
+  FPA11 *fpa11 = (FPA11 *)fp;
+  memset(fpa11, 0, sizeof(FPA11));
+  resetFPA11();
+  SetRoundingMode(ROUND_TO_NEAREST);
+  SetRoundingPrecision(ROUND_EXTENDED);
+  fpa11->initflag = 1;
 }
 
 /* Emulate the instruction in the opcode. */
diff -Nru a/arch/arm/nwfpe/fpa11.h b/arch/arm/nwfpe/fpa11.h
--- a/arch/arm/nwfpe/fpa11.h	Tue Oct  1 00:08:17 2002
+++ b/arch/arm/nwfpe/fpa11.h	Tue Oct  1 00:08:17 2002
@@ -80,8 +80,8 @@
 					   initialised. */
 } FPA11;
 
-extern void resetFPA11(void);
 extern void SetRoundingMode(const unsigned int);
 extern void SetRoundingPrecision(const unsigned int);
+extern void nwfpe_init(union fp_state *fp);
 
 #endif
diff -Nru a/arch/arm/nwfpe/fpmodule.c b/arch/arm/nwfpe/fpmodule.c
--- a/arch/arm/nwfpe/fpmodule.c	Tue Oct  1 00:08:17 2002
+++ b/arch/arm/nwfpe/fpmodule.c	Tue Oct  1 00:08:17 2002
@@ -42,10 +42,8 @@
 #include "fpa11.inl"
 
 /* kernel symbols required for signal handling */
-typedef struct task_struct*	PTASK;
-
 #ifdef MODULE
-void fp_send_sig(unsigned long sig, PTASK p, int priv);
+void fp_send_sig(unsigned long sig, struct task_struct *p, int priv);
 #if LINUX_VERSION_CODE > 0x20115
 MODULE_AUTHOR("Scott Bambrough <scottb@rebel.com>");
 MODULE_DESCRIPTION("NWFPE floating point emulator");
@@ -63,9 +61,11 @@
 
 /* external declarations for saved kernel symbols */
 extern void (*kern_fp_enter)(void);
+extern void (*fp_init)(union fp_state *);
 
 /* Original value of fp_enter from kernel before patched by fpe_init. */ 
 static void (*orig_fp_enter)(void);
+static void (*orig_fp_init)(union fp_state *);
 
 /* forward declarations */
 extern void nwfpe_enter(void);
@@ -108,7 +108,9 @@
 
   /* Save pointer to the old FP handler and then patch ourselves in */
   orig_fp_enter = kern_fp_enter;
+  orig_fp_init = fp_init;
   kern_fp_enter = nwfpe_enter;
+  fp_init = nwfpe_init;
 
   return 0;
 }
@@ -117,6 +119,7 @@
 {
   /* Restore the values we saved earlier. */
   kern_fp_enter = orig_fp_enter;
+  fp_init = orig_fp_init;
 }
 
 /*
diff -Nru a/arch/arm/nwfpe/fpopcode.h b/arch/arm/nwfpe/fpopcode.h
--- a/arch/arm/nwfpe/fpopcode.h	Tue Oct  1 00:08:16 2002
+++ b/arch/arm/nwfpe/fpopcode.h	Tue Oct  1 00:08:16 2002
@@ -26,7 +26,7 @@
 ARM Floating Point Instruction Classes
 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 
 |c o n d|1 1 0 P|U|u|W|L|   Rn  |v|  Fd |0|0|0|1|  o f f s e t  | CPDT
-|c o n d|1 1 0 P|U|w|W|L|   Rn  |x|  Fd |0|0|0|1|  o f f s e t  | CPDT
+|c o n d|1 1 0 P|U|w|W|L|   Rn  |x|  Fd |0|0|1|0|  o f f s e t  | CPDT (copro 2)
 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 
 |c o n d|1 1 1 0|a|b|c|d|e|  Fn |j|  Fd |0|0|0|1|f|g|h|0|i|  Fm | CPDO
 |c o n d|1 1 1 0|a|b|c|L|e|  Fn |   Rd  |0|0|0|1|f|g|h|1|i|  Fm | CPRT
@@ -34,7 +34,7 @@
 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 
 
 CPDT		data transfer instructions
-		LDF, STF, LFM, SFM
+		LDF, STF, LFM (copro 2), SFM (copro 2)
 		
 CPDO		dyadic arithmetic instructions
 		ADF, MUF, SUF, RSF, DVF, RDF,
diff -Nru a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
--- a/arch/arm/tools/mach-types	Tue Oct  1 00:08:17 2002
+++ b/arch/arm/tools/mach-types	Tue Oct  1 00:08:17 2002
@@ -6,7 +6,7 @@
 # To add an entry into this database, please see Documentation/arm/README,
 # or contact rmk@arm.linux.org.uk
 #
-# Last update: Sat Jul 27 09:56:53 2002
+# Last update: Sat Sep 21 13:39:13 2002
 #
 # machine_is_xxx	CONFIG_xxxx		MACH_TYPE_xxx		number
 #
@@ -214,3 +214,31 @@
 h3900			ARCH_H3900		H3900			203
 pxa1			ARCH_PXA1		PXA1			204
 koan369			SA1100_KOAN369		KOAN369			205
+cogent			ARCH_COGENT		COGENT			206
+esl_simputer		ARCH_ESL_SIMPUTER	ESL_SIMPUTER		207
+esl_simputer_clr	ARCH_ESL_SIMPUTER_CLR	ESL_SIMPUTER_CLR	208
+esl_simputer_bw		ARCH_ESL_SIMPUTER_BW	ESL_SIMPUTER_BW		209
+hhp_cradle		ARCH_HHP_CRADLE		HHP_CRADLE		210
+he500			ARCH_HE500		HE500			211
+inhandelf2		SA1100_INHANDELF2	INHANDELF2		212
+inhandftip		SA1100_INHANDFTIP	INHANDFTIP		213
+dnp1110			SA1100_DNP1110		DNP1110			214
+pnp1110			SA1100_PNP1110		PNP1110			215
+csb226			ARCH_CSB226		CSB226			216
+arnold			SA1100_ARNOLD		ARNOLD			217
+psiboard		SA1100_PSIBOARD		PSIBOARD		218
+jz8028			ARCH_JZ8028		JZ8028			219
+ipaq3			ARCH_IPAQ3		IPAQ3			220
+forte			SA1100_FORTE		FORTE			221
+acam			SA1100_ACAM		ACAM			222
+abox			SA1100_ABOX		ABOX			223
+atmel			ARCH_ATMEL		ATMEL			224
+sitsang			ARCH_SITSANG		SITSANG			225
+cpu1110lcdnet		SA1100_CPU1110LCDNET	CPU1110LCDNET		226
+mpl_vcma9		ARCH_MPL_VCMA9		MPL_VCMA9		227
+opus_a1			ARCH_OPUS_A1		OPUS_A1			228
+daytona			ARCH_DAYTONA		DAYTONA			229
+killbear		SA1100_KILLBEAR		KILLBEAR		230
+yoho			ARCH_YOHO		YOHO			231
+jasper			ARCH_JASPER		JASPER			232
+dsc25			ARCH_DSC25		DSC25			233
diff -Nru a/arch/i386/Config.help b/arch/i386/Config.help
--- a/arch/i386/Config.help	Tue Oct  1 00:08:15 2002
+++ b/arch/i386/Config.help	Tue Oct  1 00:08:15 2002
@@ -839,7 +839,84 @@
 CONFIG_X86_MCE_P4THERMAL
   Enabling this feature will cause a message to be printed when the P4
   enters thermal throttling.
-				 
+
+CONFIG_CPU_FREQ
+  Clock scaling allows you to change the clock speed of CPUs on the
+  fly. This is a nice method to save battery power on notebooks,
+  because the lower the clock speed, the less power the CPU consumes.
+
+  For more information, take a look at linux/Documentation/cpufreq or
+  at <http://www.brodo.de/cpufreq/>
+
+  If in doubt, say N.
+
+CONFIG_CPU_FREQ_24_API
+  This enables the /proc/sys/cpu/ sysctl interface for controlling
+  CPUFreq, as known from the 2.4.-kernel patches for CPUFreq. Note
+  that some drivers do not support this interface or offer less
+  functionality. 
+
+  If you say N here, you'll be able to control CPUFreq using the
+  new /proc/cpufreq interface.
+
+  For details, take a look at linux/Documentation/cpufreq. 
+
+  If in doubt, say N.
+
+CONFIG_X86_POWERNOW_K6
+  This adds the CPUFreq driver for mobile AMD K6-2+ and mobile
+  AMD K6-3+ processors.
+
+  For details, take a look at linux/Documentation/cpufreq. 
+
+  If in doubt, say N.
+
+CONFIG_X86_P4_CLOCKMOD
+  This adds the CPUFreq driver for Intel Pentium 4 / XEON
+  processors.
+
+  For details, take a look at linux/Documentation/cpufreq. 
+
+  If in doubt, say N.
+
+CONFIG_ELAN_CPUFREQ
+  This adds the CPUFreq driver for AMD Elan SC400 and SC410
+  processors.
+
+  You need to specify the processor maximum speed as boot
+  parameter: elanfreq=maxspeed (in kHz) or as module
+  parameter "max_freq".
+
+  For details, take a look at linux/Documentation/cpufreq. 
+
+  If in doubt, say N.
+
+CONFIG_X86_LONGHAUL
+  This adds the CPUFreq driver for VIA Samuel/CyrixIII, 
+  VIA Cyrix Samuel/C3, VIA Cyrix Ezra and VIA Cyrix Ezra-T 
+  processors.
+
+  For details, take a look at linux/Documentation/cpufreq. 
+
+  If in doubt, say N.
+
+CONFIG_X86_SPEEDSTEP
+  This adds the CPUFreq driver for certain mobile Intel Pentium III
+  (Coppermine), all mobile Intel Pentium III-M (Tulatin) and all
+  mobile Intel Pentium 4 P4-Ms.
+
+  For details, take a look at linux/Documentation/cpufreq. 
+
+  If in doubt, say N.
+
+CONFIG_X86_LONGRUN
+  This adds the CPUFreq driver for Transmeta Crusoe processors which
+  support LongRun.
+
+  For details, take a look at linux/Documentation/cpufreq. 
+
+  If in doubt, say N.
+
 CONFIG_TOSHIBA
   This adds a driver to safely access the System Management Mode of
   the CPU on Toshiba portables with a genuine Toshiba BIOS. It does
diff -Nru a/arch/i386/config.in b/arch/i386/config.in
--- a/arch/i386/config.in	Tue Oct  1 00:08:16 2002
+++ b/arch/i386/config.in	Tue Oct  1 00:08:16 2002
@@ -190,6 +190,23 @@
 dep_bool 'Check for non-fatal errors on Athlon/Duron' CONFIG_X86_MCE_NONFATAL $CONFIG_X86_MCE
 dep_bool 'check for P4 thermal throttling interrupt.' CONFIG_X86_MCE_P4THERMAL $CONFIG_X86_MCE $CONFIG_X86_UP_APIC
 
+bool 'CPU Frequency scaling' CONFIG_CPU_FREQ
+if [ "$CONFIG_CPU_FREQ" = "y" ]; then
+   bool ' /proc/sys/cpu/ interface (2.4.)' CONFIG_CPU_FREQ_24_API
+   if [ "$CONFIG_CPU_FREQ_24_API" = "n" ]; then
+       define_bool CONFIG_CPU_FREQ_26_API y
+   fi
+   tristate ' AMD Mobile K6-2/K6-3 PowerNow!' CONFIG_X86_POWERNOW_K6
+   if [ "$CONFIG_MELAN" = "y" ]; then
+       tristate ' AMD Elan' CONFIG_ELAN_CPUFREQ
+   fi
+   tristate ' VIA Cyrix III Longhaul' CONFIG_X86_LONGHAUL
+   tristate ' Intel Speedstep' CONFIG_X86_SPEEDSTEP
+   tristate ' Intel Pentium 4 clock modulation' CONFIG_X86_P4_CLOCKMOD
+   if [ "$CONFIG_CPU_FREQ_24_API" = "n" ]; then
+       tristate ' Transmeta LongRun' CONFIG_X86_LONGRUN
+   fi
+fi
 
 tristate 'Toshiba Laptop support' CONFIG_TOSHIBA
 tristate 'Dell laptop support' CONFIG_I8K
diff -Nru a/arch/i386/kernel/cpu/Makefile b/arch/i386/kernel/cpu/Makefile
--- a/arch/i386/kernel/cpu/Makefile	Tue Oct  1 00:08:17 2002
+++ b/arch/i386/kernel/cpu/Makefile	Tue Oct  1 00:08:17 2002
@@ -13,6 +13,7 @@
 obj-y	+=	nexgen.o
 obj-y	+=	umc.o
 
-obj-$(CONFIG_MTRR)	+= mtrr/
+obj-$(CONFIG_MTRR)	+= 	mtrr/
+obj-$(CONFIG_CPU_FREQ)	+=	cpufreq/
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/i386/kernel/cpu/cpufreq/Makefile b/arch/i386/kernel/cpu/cpufreq/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/cpufreq/Makefile	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,8 @@
+obj-$(CONFIG_X86_POWERNOW_K6)	+= powernow-k6.o
+obj-$(CONFIG_X86_LONGHAUL)	+= longhaul.o
+obj-$(CONFIG_X86_SPEEDSTEP)	+= speedstep.o
+obj-$(CONFIG_X86_P4_CLOCKMOD)	+= p4-clockmod.o
+obj-$(CONFIG_ELAN_CPUFREQ)	+= elanfreq.o
+obj-$(CONFIG_X86_LONGRUN)	+= longrun.o  
+
+include $(TOPDIR)/Rules.make
diff -Nru a/arch/i386/kernel/cpu/cpufreq/elanfreq.c b/arch/i386/kernel/cpu/cpufreq/elanfreq.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/cpufreq/elanfreq.c	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,336 @@
+/*
+ * 	elanfreq: 	cpufreq driver for the AMD ELAN family
+ *
+ *	(c) Copyright 2002 Robert Schwebel <r.schwebel@pengutronix.de>
+ *
+ *	Parts of this code are (c) Sven Geggus <sven@geggus.net> 
+ *
+ *      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. 
+ *
+ *	2002-02-13: - initial revision for 2.4.18-pre9 by Robert Schwebel
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/cpufreq.h>
+
+#include <asm/msr.h>
+#include <asm/timex.h>
+#include <asm/io.h>
+
+#define REG_CSCIR 0x22 		/* Chip Setup and Control Index Register    */
+#define REG_CSCDR 0x23		/* Chip Setup and Control Data  Register    */
+
+#define SAFE_FREQ 33000		/* every Elan CPU can run at 33 MHz         */
+
+static struct cpufreq_driver *elanfreq_driver;
+
+/* Module parameter */
+static int max_freq;
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Robert Schwebel <r.schwebel@pengutronix.de>, Sven Geggus <sven@geggus.net>");
+MODULE_DESCRIPTION("cpufreq driver for AMD's Elan CPUs");
+
+struct s_elan_multiplier {
+	int clock;		/* frequency in kHz                         */
+	int val40h;		/* PMU Force Mode register                  */
+	int val80h;		/* CPU Clock Speed Register                 */
+};
+
+/*
+ * It is important that the frequencies 
+ * are listed in ascending order here!
+ */
+struct s_elan_multiplier elan_multiplier[] = {
+	{1000,	0x02,	0x18},
+	{2000,	0x02,	0x10},
+	{4000,	0x02,	0x08},
+	{8000,	0x00,	0x00},
+	{16000,	0x00,	0x02},
+	{33000,	0x00,	0x04},
+	{66000,	0x01,	0x04},
+	{99000,	0x01,	0x05}
+};
+
+
+/**
+ *	elanfreq_get_cpu_frequency: determine current cpu speed
+ *
+ *	Finds out at which frequency the CPU of the Elan SOC runs
+ *	at the moment. Frequencies from 1 to 33 MHz are generated 
+ *	the normal way, 66 and 99 MHz are called "Hyperspeed Mode"
+ *	and have the rest of the chip running with 33 MHz. 
+ */
+
+static unsigned int elanfreq_get_cpu_frequency(void)
+{
+        u8 clockspeed_reg;    /* Clock Speed Register */
+	
+	local_irq_disable();
+        outb_p(0x80,REG_CSCIR);
+        clockspeed_reg = inb_p(REG_CSCDR);
+	local_irq_enable();
+
+        if ((clockspeed_reg & 0xE0) == 0xE0) { return 0; }
+
+        /* Are we in CPU clock multiplied mode (66/99 MHz)? */
+        if ((clockspeed_reg & 0xE0) == 0xC0) {
+                if ((clockspeed_reg & 0x01) == 0) {
+			return 66000;
+		} else {
+			return 99000;             
+		}
+        }
+
+	/* 33 MHz is not 32 MHz... */
+	if ((clockspeed_reg & 0xE0)==0xA0)
+		return 33000;
+
+        return ((1<<((clockspeed_reg & 0xE0) >> 5)) * 1000);
+}
+
+
+/**
+ *      elanfreq_set_cpu_frequency: Change the CPU core frequency
+ * 	@cpu: cpu number
+ *	@freq: frequency in kHz
+ *
+ *      This function takes a frequency value and changes the CPU frequency 
+ *	according to this. Note that the frequency has to be checked by
+ *	elanfreq_validatespeed() for correctness!
+ *	
+ *	There is no return value. 
+ */
+
+static void elanfreq_set_cpu_state (unsigned int state) {
+
+	struct cpufreq_freqs    freqs;
+
+	if (!elanfreq_driver) {
+		printk(KERN_ERR "cpufreq: initialization problem or invalid target frequency\n");
+		return;
+	}
+
+	freqs.old = elanfreq_get_cpu_frequency();
+	freqs.new = elan_multiplier[state].clock;
+	freqs.cpu = CPUFREQ_ALL_CPUS; /* elanfreq.c is UP only driver */
+	
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	printk(KERN_INFO "elanfreq: attempting to set frequency to %i kHz\n",elan_multiplier[state].clock);
+
+
+	/* 
+	 * Access to the Elan's internal registers is indexed via    
+	 * 0x22: Chip Setup & Control Register Index Register (CSCI) 
+	 * 0x23: Chip Setup & Control Register Data  Register (CSCD) 
+	 *
+	 */
+
+	/* 
+	 * 0x40 is the Power Management Unit's Force Mode Register. 
+	 * Bit 6 enables Hyperspeed Mode (66/100 MHz core frequency)
+	 */
+
+	local_irq_disable();
+	outb_p(0x40,REG_CSCIR); 	/* Disable hyperspeed mode          */
+	outb_p(0x00,REG_CSCDR);
+	local_irq_enable();		/* wait till internal pipelines and */
+	udelay(1000);			/* buffers have cleaned up          */
+
+	local_irq_disable();
+
+	/* now, set the CPU clock speed register (0x80) */
+	outb_p(0x80,REG_CSCIR);
+	outb_p(elan_multiplier[state].val80h,REG_CSCDR);
+
+	/* now, the hyperspeed bit in PMU Force Mode Register (0x40) */
+	outb_p(0x40,REG_CSCIR);
+	outb_p(elan_multiplier[state].val40h,REG_CSCDR);
+	udelay(10000);
+	local_irq_enable();
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+};
+
+
+/**
+ *	elanfreq_validatespeed: test if frequency range is valid 
+ *
+ *	This function checks if a given frequency range in kHz is valid 
+ *      for the hardware supported by the driver. 
+ */
+
+static void elanfreq_verify (struct cpufreq_policy *policy)
+{
+	unsigned int    number_states = 0;
+	unsigned int    i;
+
+	if (!policy || !max_freq)
+		return;
+
+	policy->cpu = 0;
+
+	cpufreq_verify_within_limits(policy, 1000, max_freq);
+
+	for (i=(sizeof(elan_multiplier)/sizeof(struct s_elan_multiplier) - 1); i>=0; i--)
+		if ((elan_multiplier[i].clock >= policy->min) &&
+		    (elan_multiplier[i].clock <= policy->max))
+			number_states++;
+
+	if (number_states)
+		return;
+
+	for (i=(sizeof(elan_multiplier)/sizeof(struct s_elan_multiplier) - 1); i>=0; i--)
+		if (elan_multiplier[i].clock < policy->max)
+			break;
+
+	policy->max = elan_multiplier[i+1].clock;
+
+	return;
+}
+
+static void elanfreq_setpolicy (struct cpufreq_policy *policy)
+{
+	unsigned int    number_states = 0;
+	unsigned int    i, j=4;
+
+	if (!elanfreq_driver)
+		return;
+
+	for (i=(sizeof(elan_multiplier)/sizeof(struct s_elan_multiplier) - 1); i>=0; i--)
+		if ((elan_multiplier[i].clock >= policy->min) &&
+		    (elan_multiplier[i].clock <= policy->max))
+		{
+			number_states++;
+			j = i;
+		}
+
+	if (number_states == 1) {
+		elanfreq_set_cpu_state(j);
+		return;
+	}
+
+	switch (policy->policy) {
+	case CPUFREQ_POLICY_POWERSAVE:
+		for (i=(sizeof(elan_multiplier)/sizeof(struct s_elan_multiplier) - 1); i>=0; i--)
+			if ((elan_multiplier[i].clock >= policy->min) &&
+			    (elan_multiplier[i].clock <= policy->max))
+				j = i;
+		break;
+	case CPUFREQ_POLICY_PERFORMANCE:
+		for (i=0; i<(sizeof(elan_multiplier)/sizeof(struct s_elan_multiplier) - 1); i++)
+			if ((elan_multiplier[i].clock >= policy->min) &&
+			    (elan_multiplier[i].clock <= policy->max))
+				j = i;
+		break;
+	default:
+		return;
+	}
+
+	if (elan_multiplier[j].clock > max_freq)
+		BUG();
+
+	elanfreq_set_cpu_state(j);
+	return;
+}
+
+
+/*
+ *	Module init and exit code
+ */
+
+#ifndef MODULE
+/**
+ * elanfreq_setup - elanfreq command line parameter parsing
+ *
+ * elanfreq command line parameter.  Use:
+ *  elanfreq=66000
+ * to set the maximum CPU frequency to 66 MHz. Note that in
+ * case you do not give this boot parameter, the maximum
+ * frequency will fall back to _current_ CPU frequency which
+ * might be lower. If you build this as a module, use the
+ * max_freq module parameter instead.
+ */
+static int __init elanfreq_setup(char *str)
+{
+	max_freq = simple_strtoul(str, &str, 0);
+	return 1;
+}
+__setup("elanfreq=", elanfreq_setup);
+#endif
+
+static int __init elanfreq_init(void) 
+{	
+	struct cpuinfo_x86 *c = cpu_data;
+	struct cpufreq_driver *driver;
+	int ret;
+
+	/* Test if we have the right hardware */
+	if ((c->x86_vendor != X86_VENDOR_AMD) ||
+		(c->x86 != 4) || (c->x86_model!=10))
+	{
+		printk(KERN_INFO "elanfreq: error: no Elan processor found!\n");
+                return -ENODEV;
+	}
+	
+	driver = kmalloc(sizeof(struct cpufreq_driver) +
+			 NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL);
+	if (!driver)
+		return -ENOMEM;
+
+	driver->policy = (struct cpufreq_policy *) (driver + 1);
+
+	if (!max_freq)
+		max_freq = elanfreq_get_cpu_frequency();
+
+#ifdef CONFIG_CPU_FREQ_24_API
+	driver->cpu_min_freq    = 1000;
+	driver->cpu_cur_freq[0] = elanfreq_get_cpu_frequency();
+#endif
+
+	driver->verify        = &elanfreq_verify;
+	driver->setpolicy     = &elanfreq_setpolicy;
+
+	driver->policy[0].cpu    = 0;
+	driver->policy[0].min    = 1000;
+	driver->policy[0].max    = max_freq;
+	driver->policy[0].policy = CPUFREQ_POLICY_PERFORMANCE;
+	driver->policy[0].max_cpu_freq  = max_freq;
+
+	ret = cpufreq_register(driver);
+	if (ret) {
+		kfree(driver);
+		return ret;
+	}
+
+	elanfreq_driver = driver;
+
+	return 0;
+}
+
+
+static void __exit elanfreq_exit(void) 
+{
+	if (elanfreq_driver) {
+		cpufreq_unregister();
+		kfree(elanfreq_driver);
+	}
+}
+
+module_init(elanfreq_init);
+module_exit(elanfreq_exit);
+
+MODULE_PARM (max_freq, "i");
+
diff -Nru a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,820 @@
+/*
+ *  $Id: longhaul.c,v 1.72 2002/09/29 23:43:10 db Exp $
+ *
+ *  (C) 2001  Dave Jones. <davej@suse.de>
+ *  (C) 2002  Padraig Brady. <padraig@antefacto.com>
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *  Based upon datasheets & sample CPUs kindly provided by VIA.
+ *
+ *  VIA have currently 3 different versions of Longhaul.
+ *
+ *  +---------------------+----------+---------------------------------+
+ *  | Marketing name      | Codename | longhaul version / features.    |
+ *  +---------------------+----------+---------------------------------+
+ *  |  Samuel/CyrixIII    |   C5A    | v1 : multipliers only           |
+ *  |  Samuel2/C3         | C3E/C5B  | v1 : multiplier only            |
+ *  |  Ezra               |   C5C    | v2 : multipliers & voltage      |
+ *  |  Ezra-T             | C5M/C5N  | v3 : multipliers, voltage & FSB |
+ *  +---------------------+----------+---------------------------------+
+ *
+ *  BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h> 
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/slab.h>
+
+#include <asm/msr.h>
+#include <asm/timex.h>
+#include <asm/io.h>
+
+#define DEBUG
+
+#ifdef DEBUG
+#define dprintk(msg...) printk(msg)
+#else
+#define dprintk(msg...) do { } while(0);
+#endif
+
+static int numscales=16, numvscales;
+static int minvid, maxvid;
+static int can_scale_voltage;
+static int can_scale_fsb;
+static int vrmrev;
+
+
+/* Module parameters */
+static int dont_scale_voltage;
+static int dont_scale_fsb;
+static int current_fsb;
+
+#define __hlt()     __asm__ __volatile__("hlt": : :"memory")
+
+/*
+ * Clock ratio tables.
+ * The eblcr ones specify the ratio read from the CPU.
+ * The clock_ratio ones specify what to write to the CPU.
+ */
+
+/* VIA C3 Samuel 1  & Samuel 2 (stepping 0)*/
+static int __initdata longhaul1_clock_ratio[16] = {
+	-1, /* 0000 -> RESERVED */
+	30, /* 0001 ->  3.0x */
+	40, /* 0010 ->  4.0x */
+	-1, /* 0011 -> RESERVED */
+	-1, /* 0100 -> RESERVED */
+	35, /* 0101 ->  3.5x */
+	45, /* 0110 ->  4.5x */
+	55, /* 0111 ->  5.5x */
+	60, /* 1000 ->  6.0x */
+	70, /* 1001 ->  7.0x */
+	80, /* 1010 ->  8.0x */
+	50, /* 1011 ->  5.0x */
+	65, /* 1100 ->  6.5x */
+	75, /* 1101 ->  7.5x */
+	-1, /* 1110 -> RESERVED */
+	-1, /* 1111 -> RESERVED */
+};
+
+static int __initdata samuel1_eblcr[16] = {
+	50, /* 0000 -> RESERVED */
+	30, /* 0001 ->  3.0x */
+	40, /* 0010 ->  4.0x */
+	-1, /* 0011 -> RESERVED */
+	55, /* 0100 ->  5.5x */
+	35, /* 0101 ->  3.5x */
+	45, /* 0110 ->  4.5x */
+	-1, /* 0111 -> RESERVED */
+	-1, /* 1000 -> RESERVED */
+	70, /* 1001 ->  7.0x */
+	80, /* 1010 ->  8.0x */
+	60, /* 1011 ->  6.0x */
+	-1, /* 1100 -> RESERVED */
+	75, /* 1101 ->  7.5x */
+	-1, /* 1110 -> RESERVED */
+	65, /* 1111 ->  6.5x */
+};
+
+/* VIA C3 Samuel2 Stepping 1->15 & VIA C3 Ezra */
+static int __initdata longhaul2_clock_ratio[16] = {
+	100, /* 0000 -> 10.0x */
+	30,  /* 0001 ->  3.0x */
+	40,  /* 0010 ->  4.0x */
+	90,  /* 0011 ->  9.0x */
+	95,  /* 0100 ->  9.5x */
+	35,  /* 0101 ->  3.5x */
+	45,  /* 0110 ->  4.5x */
+	55,  /* 0111 ->  5.5x */
+	60,  /* 1000 ->  6.0x */
+	70,  /* 1001 ->  7.0x */
+	80,  /* 1010 ->  8.0x */
+	50,  /* 1011 ->  5.0x */
+	65,  /* 1100 ->  6.5x */
+	75,  /* 1101 ->  7.5x */
+	85,  /* 1110 ->  8.5x */
+	120, /* 1111 -> 12.0x */
+};
+
+static int __initdata samuel2_eblcr[16] = {
+	50,  /* 0000 ->  5.0x */
+	30,  /* 0001 ->  3.0x */
+	40,  /* 0010 ->  4.0x */
+	100, /* 0011 -> 10.0x */
+	55,  /* 0100 ->  5.5x */
+	35,  /* 0101 ->  3.5x */
+	45,  /* 0110 ->  4.5x */
+	110, /* 0111 -> 11.0x */
+	90,  /* 1000 ->  9.0x */
+	70,  /* 1001 ->  7.0x */
+	80,  /* 1010 ->  8.0x */
+	60,  /* 1011 ->  6.0x */
+	120, /* 1100 -> 12.0x */
+	75,  /* 1101 ->  7.5x */
+	130, /* 1110 -> 13.0x */
+	65,  /* 1111 ->  6.5x */
+};
+
+static int __initdata ezra_eblcr[16] = {
+	50,  /* 0000 ->  5.0x */
+	30,  /* 0001 ->  3.0x */
+	40,  /* 0010 ->  4.0x */
+	100, /* 0011 -> 10.0x */
+	55,  /* 0100 ->  5.5x */
+	35,  /* 0101 ->  3.5x */
+	45,  /* 0110 ->  4.5x */
+	95,  /* 0111 ->  9.5x */
+	90,  /* 1000 ->  9.0x */
+	70,  /* 1001 ->  7.0x */
+	80,  /* 1010 ->  8.0x */
+	60,  /* 1011 ->  6.0x */
+	120, /* 1100 -> 12.0x */
+	75,  /* 1101 ->  7.5x */
+	85,  /* 1110 ->  8.5x */
+	65,  /* 1111 ->  6.5x */
+};
+
+/* VIA C5M. */
+static int __initdata longhaul3_clock_ratio[32] = {
+	100, /* 0000 -> 10.0x */
+	30,  /* 0001 ->  3.0x */
+	40,  /* 0010 ->  4.0x */
+	90,  /* 0011 ->  9.0x */
+	95,  /* 0100 ->  9.5x */
+	35,  /* 0101 ->  3.5x */
+	45,  /* 0110 ->  4.5x */
+	55,  /* 0111 ->  5.5x */
+	60,  /* 1000 ->  6.0x */
+	70,  /* 1001 ->  7.0x */
+	80,  /* 1010 ->  8.0x */
+	50,  /* 1011 ->  5.0x */
+	65,  /* 1100 ->  6.5x */
+	75,  /* 1101 ->  7.5x */
+	85,  /* 1110 ->  8.5x */
+	120, /* 1111 ->  12.0x */
+
+	-1,  /* 0000 -> RESERVED (10.0x) */
+	110, /* 0001 -> 11.0x */
+	120, /* 0010 -> 12.0x */
+	-1,  /* 0011 -> RESERVED (9.0x)*/
+	105, /* 0100 -> 10.5x */
+	115, /* 0101 -> 11.5x */
+	125, /* 0110 -> 12.5x */
+	135, /* 0111 -> 13.5x */
+	140, /* 1000 -> 14.0x */
+	150, /* 1001 -> 15.0x */
+	160, /* 1010 -> 16.0x */
+	130, /* 1011 -> 13.0x */
+	145, /* 1100 -> 14.5x */
+	155, /* 1101 -> 15.5x */
+	-1,  /* 1110 -> RESERVED (13.0x) */
+	-1,  /* 1111 -> RESERVED (12.0x) */
+};
+
+static int __initdata c5m_eblcr[32] = {
+	50,  /* 0000 ->  5.0x */
+	30,  /* 0001 ->  3.0x */
+	40,  /* 0010 ->  4.0x */
+	100, /* 0011 -> 10.0x */
+	55,  /* 0100 ->  5.5x */
+	35,  /* 0101 ->  3.5x */
+	45,  /* 0110 ->  4.5x */
+	95,  /* 0111 ->  9.5x */
+	90,  /* 1000 ->  9.0x */
+	70,  /* 1001 ->  7.0x */
+	80,  /* 1010 ->  8.0x */
+	60,  /* 1011 ->  6.0x */
+	120, /* 1100 -> 12.0x */
+	75,  /* 1101 ->  7.5x */
+	85,  /* 1110 ->  8.5x */
+	65,  /* 1111 ->  6.5x */
+
+	-1,  /* 0000 -> RESERVED (9.0x) */
+	110, /* 0001 -> 11.0x */
+	120, /* 0010 -> 12.0x */
+	-1,  /* 0011 -> RESERVED (10.0x)*/
+	135, /* 0100 -> 13.5x */
+	115, /* 0101 -> 11.5x */
+	125, /* 0110 -> 12.5x */
+	105, /* 0111 -> 10.5x */
+	130, /* 1000 -> 13.0x */
+	150, /* 1001 -> 15.0x */
+	160, /* 1010 -> 16.0x */
+	140, /* 1011 -> 14.0x */
+	-1,  /* 1100 -> RESERVED (12.0x) */
+	155, /* 1101 -> 15.5x */
+	-1,  /* 1110 -> RESERVED (13.0x) */
+	145, /* 1111 -> 14.5x */
+};
+
+/* fsb values as defined in CPU */
+static unsigned int eblcr_fsb_table[] = { 66, 133, 100, -1 };
+/* fsb values to favour low fsb speed (lower power) */
+static unsigned int power_fsb_table[] = { 66, 100, 133, -1 };
+/* fsb values to favour high fsb speed (for e.g. if lowering CPU 
+   freq because of heat, but want to maintain highest performance possible) */
+static unsigned int perf_fsb_table[] = { 133, 100, 66, -1 };
+static unsigned int *fsb_search_table;
+
+/* Voltage scales. Div by 1000 to get actual voltage. */
+static int __initdata vrm85scales[32] = {
+	1250, 1200, 1150, 1100, 1050, 1800, 1750, 1700,
+	1650, 1600, 1550, 1500, 1450, 1400, 1350, 1300,
+	1275, 1225, 1175, 1125, 1075, 1825, 1775, 1725,
+	1675, 1625, 1575, 1525, 1475, 1425, 1375, 1325,
+};
+
+static int __initdata mobilevrmscales[32] = {
+	2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650,
+	1600, 1550, 1500, 1450, 1500, 1350, 1300, -1,
+	1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100,
+	1075, 1050, 1025, 1000, 975, 950, 925, -1,
+};
+
+/* Clock ratios multiplied by 10 */
+static int clock_ratio[32];
+static int eblcr_table[32];
+static int voltage_table[32];
+static int highest_speed, lowest_speed; /* kHz */
+static int longhaul; /* version. */
+static struct cpufreq_driver *longhaul_driver;
+
+
+static int longhaul_get_cpu_fsb (void)
+{
+	unsigned long invalue=0,lo, hi;
+
+	if (current_fsb == 0) {
+		rdmsr (MSR_IA32_EBL_CR_POWERON, lo, hi);
+		invalue = (lo & (1<<18|1<<19)) >>18;
+		return eblcr_fsb_table[invalue];
+	} else {
+		return current_fsb;
+	}
+}
+
+
+static int longhaul_get_cpu_mult (void)
+{
+	unsigned long invalue=0,lo, hi;
+
+	rdmsr (MSR_IA32_EBL_CR_POWERON, lo, hi);
+	invalue = (lo & (1<<22|1<<23|1<<24|1<<25)) >>22;
+	if (longhaul==3) {
+		if (lo & (1<<27))
+			invalue+=16;
+	}
+	return eblcr_table[invalue];
+}
+
+
+/**
+ * longhaul_set_cpu_frequency()
+ * @clock_ratio_index : index of clock_ratio[] for new frequency
+ * @newfsb: the new FSB
+ *
+ * Sets a new clock ratio, and -if applicable- a new Front Side Bus
+ */
+
+static void longhaul_setstate (unsigned int clock_ratio_index, unsigned int newfsb)
+{
+	unsigned long lo, hi;
+	unsigned int bits;
+	int revkey;
+	int vidindex, i;
+	struct cpufreq_freqs freqs;
+	
+	if (!newfsb || (clock_ratio[clock_ratio_index] == -1))
+		return;
+
+	if ((!can_scale_fsb) && (newfsb != current_fsb))
+		return;
+
+	freqs.old = longhaul_get_cpu_mult() * longhaul_get_cpu_fsb() * 100;
+	freqs.new = clock_ratio[clock_ratio_index] * newfsb * 100;
+	freqs.cpu = CPUFREQ_ALL_CPUS; /* longhaul.c is UP only driver */
+	
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	dprintk (KERN_INFO "longhaul: New FSB:%d Mult(x10):%d\n",
+				newfsb, clock_ratio[clock_ratio_index]);
+
+	bits = clock_ratio_index;
+	/* "bits" contains the bitpattern of the new multiplier.
+	   we now need to transform it to the desired format. */
+
+	switch (longhaul) {
+	case 1:
+		rdmsr (MSR_VIA_BCR2, lo, hi);
+		revkey = (lo & 0xf)<<4; /* Rev key. */
+		lo &= ~(1<<23|1<<24|1<<25|1<<26);
+		lo |= (1<<19);		/* Enable software clock multiplier */
+		lo |= (bits<<23);	/* desired multiplier */
+		lo |= revkey;
+		wrmsr (MSR_VIA_BCR2, lo, hi);
+
+		__hlt();
+
+		/* Disable software clock multiplier */
+		rdmsr (MSR_VIA_BCR2, lo, hi);
+		lo &= ~(1<<19);
+		lo |= revkey;
+		wrmsr (MSR_VIA_BCR2, lo, hi);
+		break;
+
+	case 2:
+		rdmsr (MSR_VIA_LONGHAUL, lo, hi);
+		revkey = (lo & 0xf)<<4;	/* Rev key. */
+		lo &= 0xfff0bf0f;	/* reset [19:16,14](bus ratio) and [7:4](rev key) to 0 */
+		lo |= (bits<<16);
+		lo |= (1<<8);	/* EnableSoftBusRatio */
+		lo |= revkey;
+
+		if (can_scale_voltage) {
+			if (can_scale_fsb==1) {
+				dprintk (KERN_INFO "longhaul: Voltage scaling + FSB scaling not done yet.\n");
+				goto bad_voltage;
+			} else {
+				/* PB: TODO fix this up */
+				vidindex = (((highest_speed-lowest_speed) / (newfsb/2)) -
+						((highest_speed-((clock_ratio[clock_ratio_index] * newfsb * 100)/1000)) / (newfsb/2)));
+			}
+			for (i=0;i<32;i++) {
+				dprintk (KERN_INFO "VID hunting. Looking for %d, found %d\n",
+						minvid+(vidindex*25), voltage_table[i]);
+				if (voltage_table[i]==(minvid + (vidindex * 25)))
+					break;
+			}
+			if (i==32)
+				goto bad_voltage;
+
+			dprintk (KERN_INFO "longhaul: Desired vid index=%d\n", i);
+#if 0
+			lo &= 0xfe0fffff;/* reset [24:20](voltage) to 0 */
+			lo |= (i<<20);   /* set voltage */
+			lo |= (1<<9);    /* EnableSoftVID */
+#endif
+		}
+
+bad_voltage:
+		wrmsr (MSR_VIA_LONGHAUL, lo, hi);
+		__hlt();
+
+		rdmsr (MSR_VIA_LONGHAUL, lo, hi);
+		lo &= ~(1<<8);
+		if (can_scale_voltage)
+			lo &= ~(1<<9);
+		lo |= revkey;
+		wrmsr (MSR_VIA_LONGHAUL, lo, hi);
+		break;
+
+	case 3:
+		rdmsr (MSR_VIA_LONGHAUL, lo, hi);
+		revkey = (lo & 0xf)<<4;	/* Rev key. */
+		lo &= 0xfff0bf0f;	/* reset longhaul[19:16,14] to 0 */
+		lo |= (bits<<16);
+		lo |= (1<<8);	/* EnableSoftBusRatio */
+		lo |= revkey;
+
+		/* Set FSB */
+		if (can_scale_fsb==1) {
+			lo &= ~(1<<28|1<<29);
+			switch (newfsb) {
+				case 66:	lo |= (1<<28|1<<29); /* 11 */
+							break;
+				case 100:	lo |= 1<<28;	/* 01 */
+							break;
+				case 133:	break;	/* 00*/
+			}
+		}
+		wrmsr (MSR_VIA_LONGHAUL, lo, hi);
+		__hlt();
+
+		rdmsr (MSR_VIA_LONGHAUL, lo, hi);
+		lo &= ~(1<<8);
+		lo |= revkey;
+		wrmsr (MSR_VIA_LONGHAUL, lo, hi);
+		break;
+	}
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+}
+
+
+static void __init longhaul_get_ranges (void)
+{
+	unsigned long lo, hi, invalue;
+	unsigned int minmult=0, maxmult=0, minfsb=0, maxfsb=0;
+	unsigned int multipliers[32]= {
+		50,30,40,100,55,35,45,95,90,70,80,60,120,75,85,65,
+		-1,110,120,-1,135,115,125,105,130,150,160,140,-1,155,-1,145 };
+	unsigned int fsb_table[4] = { 133, 100, -1, 66 };
+
+	switch (longhaul) {
+	case 1:
+		/* Ugh, Longhaul v1 didn't have the min/max MSRs.
+		   Assume max = whatever we booted at. */
+		maxmult = longhaul_get_cpu_mult();
+		break;
+
+	case 2 ... 3:
+		rdmsr (MSR_VIA_LONGHAUL, lo, hi);
+
+		invalue = (hi & (1<<0|1<<1|1<<2|1<<3));
+		if (hi & (1<<11))
+			invalue += 16;
+		maxmult=multipliers[invalue];
+
+#if 0	/* This is MaxMhz @ Min Voltage. Ignore for now */
+		invalue = (hi & (1<<16|1<<17|1<<18|1<<19)) >> 16;
+		if (hi & (1<<27))
+		invalue += 16;
+		minmult = multipliers[invalue];
+#else
+		minmult = 30; /* as per spec */
+#endif
+
+		if (can_scale_fsb==1) {
+			invalue = (hi & (1<<9|1<<10)) >> 9;
+			maxfsb = fsb_table[invalue];
+
+			invalue = (hi & (1<<25|1<<26)) >> 25;
+			minfsb = fsb_table[invalue];
+
+			dprintk (KERN_INFO "longhaul: Min FSB=%d Max FSB=%d\n",
+				minfsb, maxfsb);
+		} else {
+			minfsb = maxfsb = current_fsb;
+		}
+		break;
+	}
+
+	highest_speed = maxmult * maxfsb * 100;
+	lowest_speed = minmult * minfsb * 100;
+
+	dprintk (KERN_INFO "longhaul: MinMult(x10)=%d MaxMult(x10)=%d\n",
+		minmult, maxmult);
+	dprintk (KERN_INFO "longhaul: Lowestspeed=%d Highestspeed=%d\n",
+		lowest_speed, highest_speed);
+}
+
+
+static void __init longhaul_setup_voltagescaling (unsigned long lo, unsigned long hi)
+{
+	int revkey;
+
+	can_scale_voltage = 1;
+
+	minvid = (hi & (1<<20|1<<21|1<<22|1<<23|1<<24)) >> 20; /* 56:52 */
+	maxvid = (hi & (1<<4|1<<5|1<<6|1<<7|1<<8)) >> 4;       /* 40:36 */
+	vrmrev = (lo & (1<<15))>>15;
+
+	if (vrmrev==0) {
+		dprintk (KERN_INFO "longhaul: VRM 8.5 : ");
+		memcpy (voltage_table, vrm85scales, sizeof(voltage_table));
+		numvscales = (voltage_table[maxvid]-voltage_table[minvid])/25;
+	} else {
+		dprintk (KERN_INFO "longhaul: Mobile VRM : ");
+		memcpy (voltage_table, mobilevrmscales, sizeof(voltage_table));
+		numvscales = (voltage_table[maxvid]-voltage_table[minvid])/5;
+	}
+
+	/* Current voltage isn't readable at first, so we need to
+	   set it to a known value. The spec says to use maxvid */
+	revkey = (lo & 0xf)<<4;	/* Rev key. */
+	lo &= 0xfe0fff0f;	/* Mask unneeded bits */
+	lo |= (1<<9);		/* EnableSoftVID */
+	lo |= revkey;		/* Reinsert key */
+	lo |= maxvid << 20;
+	wrmsr (MSR_VIA_LONGHAUL, lo, hi);
+	minvid = voltage_table[minvid];
+	maxvid = voltage_table[maxvid];
+	dprintk ("Min VID=%d.%03d Max VID=%d.%03d, %d possible voltage scales\n",
+		maxvid/1000, maxvid%1000, minvid/1000, minvid%1000, numvscales);
+}
+
+
+static inline unsigned int longhaul_statecount_fsb(struct cpufreq_policy *policy, unsigned int fsb) {
+	unsigned int i, count = 0;
+
+	for(i=0; i<numscales; i++) {
+		if ((clock_ratio[i] != -1) &&
+		    ((clock_ratio[i] * fsb * 100) <= policy->max) &&
+		    ((clock_ratio[i] * fsb * 100) >= policy->min))
+			count++;
+	}
+
+	return count;
+}
+
+
+static void longhaul_verify(struct cpufreq_policy *policy)
+{
+	unsigned int    number_states = 0;
+	unsigned int    i;
+	unsigned int    fsb_index = 0;
+	unsigned int    tmpfreq = 0;
+	unsigned int    newmax = -1;
+
+	if (!policy || !longhaul_driver)
+		return;
+
+	policy->cpu = 0;
+	cpufreq_verify_within_limits(policy, lowest_speed, highest_speed);
+
+	if (can_scale_fsb==1) {
+		for (fsb_index=0; fsb_search_table[fsb_index]!=-1; fsb_index++)
+			number_states += longhaul_statecount_fsb(policy, fsb_search_table[fsb_index]);
+	} else
+		number_states = longhaul_statecount_fsb(policy, current_fsb);
+
+	if (number_states)
+		return;
+
+	/* get frequency closest above current policy->max */
+	if (can_scale_fsb==1) {
+		for (fsb_index=0; fsb_search_table[fsb_index] != -1; fsb_index++)
+			for(i=0; i<numscales; i++) {
+				if (clock_ratio[i] == -1)
+					continue;
+
+				tmpfreq = clock_ratio[i] * fsb_search_table[fsb_index];
+				if ((tmpfreq > policy->max) &&
+				    (tmpfreq < newmax))
+					newmax = tmpfreq;
+			}
+	} else {
+		for(i=0; i<numscales; i++) {
+			if (clock_ratio[i] == -1)
+				continue;
+
+			tmpfreq = clock_ratio[i] * current_fsb;
+			if ((tmpfreq > policy->max) &&
+			    (tmpfreq < newmax))
+				newmax = tmpfreq;
+			}
+	}
+
+	policy->max = newmax;
+}
+
+
+static void longhaul_setpolicy (struct cpufreq_policy *policy)
+{
+	unsigned int    number_states = 0;
+	unsigned int    i;
+	unsigned int    fsb_index = 0;
+	unsigned int    new_fsb = 0;
+	unsigned int    new_clock_ratio = 0;
+	unsigned int    best_freq = -1;
+
+	if (!longhaul_driver)
+		return;
+
+	if (policy->policy==CPUFREQ_POLICY_PERFORMANCE)
+		fsb_search_table = perf_fsb_table;
+	else
+		fsb_search_table = power_fsb_table;
+
+	if (can_scale_fsb==1) {
+		for (fsb_index=0; fsb_search_table[fsb_index]!=-1; fsb_index++) 
+		{
+			unsigned int tmpcount = longhaul_statecount_fsb(policy, fsb_search_table[fsb_index]);
+			if (tmpcount == 1)
+				new_fsb = fsb_search_table[fsb_index];
+			number_states += tmpcount;
+		}
+	} else {
+		number_states = longhaul_statecount_fsb(policy, current_fsb);
+		new_fsb = current_fsb;
+	}
+
+	if (!number_states)
+		return;
+	else if (number_states == 1) {
+		for(i=0; i<numscales; i++) {
+			if ((clock_ratio[i] != -1) &&
+			    ((clock_ratio[i] * new_fsb * 100) <= policy->max) &&
+			    ((clock_ratio[i] * new_fsb * 100) >= policy->min))
+				new_clock_ratio = i;
+		}
+		longhaul_setstate(new_clock_ratio, new_fsb);
+	}
+
+	switch (policy->policy) {
+	case CPUFREQ_POLICY_POWERSAVE:
+		best_freq = -1;
+		if (can_scale_fsb==1) {
+			for (fsb_index=0; fsb_search_table[fsb_index]!=-1; fsb_index++) 
+			{
+				for(i=0; i<numscales; i++) {
+					unsigned int tmpfreq = fsb_search_table[fsb_index] * clock_ratio[i] * 100;
+					if (clock_ratio[i] == -1)
+						continue;
+
+					if ((tmpfreq >= policy->min) &&
+					    (tmpfreq <= policy->max) &&
+					    (tmpfreq < best_freq)) {
+						new_clock_ratio = i;
+						new_fsb = fsb_search_table[fsb_index];
+					}
+				}
+			}
+		} else {
+			for(i=0; i<numscales; i++) {
+				unsigned int tmpfreq = current_fsb * clock_ratio[i] * 100;
+					if (clock_ratio[i] == -1)
+						continue;
+
+					if ((tmpfreq >= policy->min) &&
+					    (tmpfreq <= policy->max) &&
+					    (tmpfreq < best_freq)) {
+						new_clock_ratio = i;
+						new_fsb = current_fsb;
+					}
+				}
+		}
+		break;
+	case CPUFREQ_POLICY_PERFORMANCE:
+		best_freq = 0;
+		if (can_scale_fsb==1) {
+			for (fsb_index=0; fsb_search_table[fsb_index]!=-1; fsb_index++) 
+			{
+				for(i=0; i<numscales; i++) {
+					unsigned int tmpfreq = fsb_search_table[fsb_index] * clock_ratio[i] * 100;
+					if (clock_ratio[i] == -1)
+						continue;
+
+					if ((tmpfreq >= policy->min) &&
+					    (tmpfreq <= policy->max) &&
+					    (tmpfreq > best_freq)) {
+						new_clock_ratio = i;
+						new_fsb = fsb_search_table[fsb_index];
+					}
+				}
+			}
+		} else {
+			for(i=0; i<numscales; i++) {
+				unsigned int tmpfreq = current_fsb * clock_ratio[i] * 100;
+					if (clock_ratio[i] == -1)
+						continue;
+
+					if ((tmpfreq >= policy->min) &&
+					    (tmpfreq <= policy->max) &&
+					    (tmpfreq > best_freq)) {
+						new_clock_ratio = i;
+						new_fsb = current_fsb;
+					}
+				}
+		}
+		break;
+	default:
+		return;
+	}
+
+	longhaul_setstate(new_clock_ratio, new_fsb);
+	return;
+}
+
+
+static int __init longhaul_init (void)
+{
+	struct cpuinfo_x86 *c = cpu_data;
+	unsigned int currentspeed;
+	static int currentmult;
+	unsigned long lo, hi;
+	int ret;
+	struct cpufreq_driver *driver;
+
+	if ((c->x86_vendor != X86_VENDOR_CENTAUR) || (c->x86 !=6) )
+		return -ENODEV;
+
+	switch (c->x86_model) {
+	case 6:		/* VIA C3 Samuel C5A */
+		longhaul=1;
+		memcpy (clock_ratio, longhaul1_clock_ratio, sizeof(longhaul1_clock_ratio));
+		memcpy (eblcr_table, samuel1_eblcr, sizeof(samuel1_eblcr));
+		break;
+
+	case 7:		/* C5B / C5C */
+		switch (c->x86_mask) {
+		case 0:
+			longhaul=1;
+			memcpy (clock_ratio, longhaul1_clock_ratio, sizeof(longhaul1_clock_ratio));
+			memcpy (eblcr_table, samuel2_eblcr, sizeof(samuel2_eblcr));
+			break;
+		case 1 ... 15:
+			longhaul=2;
+			memcpy (clock_ratio, longhaul2_clock_ratio, sizeof(longhaul2_clock_ratio));
+			memcpy (eblcr_table, ezra_eblcr, sizeof(ezra_eblcr));
+			break;
+		}
+		break;
+
+	case 8:		/* C5M/C5N */
+		return -ENODEV; // Waiting on updated docs from VIA before this is usable
+		longhaul=3;
+		numscales=32;
+		memcpy (clock_ratio, longhaul3_clock_ratio, sizeof(longhaul3_clock_ratio));
+		memcpy (eblcr_table, c5m_eblcr, sizeof(c5m_eblcr));
+		break;
+
+	default:
+		printk (KERN_INFO "longhaul: Unknown VIA CPU. Contact davej@suse.de\n");
+		return -ENODEV;
+	}
+
+	printk (KERN_INFO "longhaul: VIA CPU detected. Longhaul version %d supported\n", longhaul);
+
+	current_fsb = longhaul_get_cpu_fsb();
+	currentmult = longhaul_get_cpu_mult();
+	currentspeed = currentmult * current_fsb * 100;
+
+	dprintk (KERN_INFO "longhaul: CPU currently at %dMHz (%d x %d.%d)\n",
+		(currentspeed/1000), current_fsb, currentmult/10, currentmult%10);
+
+	if (longhaul==2 || longhaul==3) {
+		rdmsr (MSR_VIA_LONGHAUL, lo, hi);
+		if ((lo & (1<<0)) && (dont_scale_voltage==0))
+			longhaul_setup_voltagescaling (lo, hi);
+
+		if ((lo & (1<<1)) && (dont_scale_fsb==0) && (current_fsb==0))
+			can_scale_fsb = 1;
+	}
+
+	longhaul_get_ranges();
+
+	driver = kmalloc(sizeof(struct cpufreq_driver) + 
+			 NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL);
+	if (!driver)
+		return -ENOMEM;
+
+	driver->policy = (struct cpufreq_policy *) (driver + 1);
+
+#ifdef CONFIG_CPU_FREQ_24_API
+	driver->cpu_min_freq    = (unsigned int) lowest_speed;
+	driver->cpu_cur_freq[0] = currentspeed;
+#endif
+
+	driver->verify    = &longhaul_verify;
+	driver->setpolicy = &longhaul_setpolicy;
+
+	driver->policy[0].cpu = 0;
+	driver->policy[0].min = (unsigned int) lowest_speed;
+	driver->policy[0].max = (unsigned int) highest_speed;
+	driver->policy[0].policy = CPUFREQ_POLICY_PERFORMANCE;
+	driver->policy[0].max_cpu_freq = (unsigned int) highest_speed;
+
+	ret = cpufreq_register(driver);
+
+	if (ret) {
+		kfree(driver);
+		return ret;
+	}
+
+	longhaul_driver = driver;
+	return 0;
+}
+
+
+static void __exit longhaul_exit (void)
+{
+	if (longhaul_driver) {
+		cpufreq_unregister();
+		kfree(longhaul_driver);
+	}
+}
+
+MODULE_PARM (dont_scale_fsb, "i");
+MODULE_PARM (dont_scale_voltage, "i");
+MODULE_PARM (current_fsb, "i");
+
+MODULE_AUTHOR ("Dave Jones <davej@suse.de>");
+MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors.");
+MODULE_LICENSE ("GPL");
+
+module_init(longhaul_init);
+module_exit(longhaul_exit);
+
diff -Nru a/arch/i386/kernel/cpu/cpufreq/longrun.c b/arch/i386/kernel/cpu/cpufreq/longrun.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/cpufreq/longrun.c	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,283 @@
+/*
+ *  $Id: longrun.c,v 1.12 2002/09/29 23:43:10 db Exp $
+ *
+ * (C) 2002  Dominik Brodowski <linux@brodo.de>
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ *  BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h> 
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/cpufreq.h>
+
+#include <asm/msr.h>
+#include <asm/processor.h>
+#include <asm/timex.h>
+
+static struct cpufreq_driver	*longrun_driver;
+
+/**
+ * longrun_{low,high}_freq is needed for the conversion of cpufreq kHz 
+ * values into per cent values. In TMTA microcode, the following is valid:
+ * performance_pctg = (current_freq - low_freq)/(high_freq - low_freq)
+ */
+static unsigned int longrun_low_freq, longrun_high_freq;
+
+
+/**
+ * longrun_get_policy - get the current LongRun policy
+ * @policy: struct cpufreq_policy where current policy is written into
+ *
+ * Reads the current LongRun policy by access to MSR_TMTA_LONGRUN_FLAGS
+ * and MSR_TMTA_LONGRUN_CTRL
+ */
+static void longrun_get_policy(struct cpufreq_policy *policy)
+{
+	u32 msr_lo, msr_hi;
+
+	if (!longrun_driver)
+		return;
+
+	rdmsr(MSR_TMTA_LONGRUN_FLAGS, msr_lo, msr_hi);
+	if (msr_lo & 0x01)
+		policy->policy = CPUFREQ_POLICY_PERFORMANCE;
+	else
+		policy->policy = CPUFREQ_POLICY_POWERSAVE;
+	
+	rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
+	msr_lo &= 0x0000007F;
+	msr_hi &= 0x0000007F;
+
+	policy->min = longrun_low_freq + msr_lo * 
+		((longrun_high_freq - longrun_low_freq) / 100);
+	policy->min = longrun_low_freq + msr_hi * 
+		((longrun_high_freq - longrun_low_freq) / 100);
+	policy->cpu = 0;
+}
+
+
+/**
+ * longrun_set_policy - sets a new CPUFreq policy
+ * @policy - new policy
+ *
+ * Sets a new CPUFreq policy on LongRun-capable processors. This function
+ * has to be called with cpufreq_driver locked.
+ */
+static void longrun_set_policy(struct cpufreq_policy *policy)
+{
+	u32 msr_lo, msr_hi;
+	u32 pctg_lo, pctg_hi;
+
+	if (!longrun_driver || !policy)
+		return;
+
+	pctg_lo = (policy->min - longrun_low_freq) / 
+		((longrun_high_freq - longrun_low_freq) / 100);
+	pctg_hi = (policy->max - longrun_low_freq) / 
+		((longrun_high_freq - longrun_low_freq) / 100);
+
+	if (pctg_hi > 100)
+		pctg_hi = 100;
+	if (pctg_lo > pctg_hi)
+		pctg_lo = pctg_hi;
+
+	/* performance or economy mode */
+	rdmsr(MSR_TMTA_LONGRUN_FLAGS, msr_lo, msr_hi);
+	msr_lo &= 0xFFFFFFFE;
+	switch (policy->policy) {
+	case CPUFREQ_POLICY_PERFORMANCE:
+		msr_lo |= 0x00000001;
+		break;
+	case CPUFREQ_POLICY_POWERSAVE:
+		break;
+	}
+	wrmsr(MSR_TMTA_LONGRUN_FLAGS, msr_lo, msr_hi);
+
+	/* lower and upper boundary */
+	rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
+	msr_lo &= 0xFFFFFF80;
+	msr_hi &= 0xFFFFFF80;
+	msr_lo |= pctg_lo;
+	msr_hi |= pctg_hi;
+	wrmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
+
+	return;
+}
+
+
+/**
+ * longrun_verify_poliy - verifies a new CPUFreq policy
+ *
+ * Validates a new CPUFreq policy. This function has to be called with 
+ * cpufreq_driver locked.
+ */
+static void longrun_verify_policy(struct cpufreq_policy *policy)
+{
+	if (!policy || !longrun_driver)
+		return;
+
+	policy->cpu = 0;
+	cpufreq_verify_within_limits(policy, 0, 
+		longrun_driver->policy[0].max_cpu_freq);
+
+	return;
+}
+
+
+/**
+ * longrun_determine_freqs - determines the lowest and highest possible core frequency
+ *
+ * Determines the lowest and highest possible core frequencies on this CPU.
+ * This is neccessary to calculate the performance percentage according to
+ * TMTA rules:
+ * performance_pctg = (target_freq - low_freq)/(high_freq - low_freq)
+ */
+static unsigned int __init longrun_determine_freqs(unsigned int *low_freq, 
+						   unsigned int *high_freq)
+{
+	u32 msr_lo, msr_hi;
+	u32 save_lo, save_hi;
+	u32 eax, ebx, ecx, edx;
+	struct cpuinfo_x86 *c = cpu_data;
+
+	if (!low_freq || !high_freq)
+		return -EINVAL;
+
+	if (cpu_has(c, X86_FEATURE_LRTI)) {
+		/* if the LongRun Table Interface is present, the
+		 * detection is a bit easier: 
+		 * For minimum frequency, read out the maximum
+		 * level (msr_hi), write that into "currently 
+		 * selected level", and read out the frequency.
+		 * For maximum frequency, read out level zero.
+		 */
+		/* minimum */
+		rdmsr(MSR_TMTA_LRTI_READOUT, msr_lo, msr_hi);
+		wrmsr(MSR_TMTA_LRTI_READOUT, msr_hi, msr_hi);
+		rdmsr(MSR_TMTA_LRTI_VOLT_MHZ, msr_lo, msr_hi);
+		*low_freq = msr_lo * 1000; /* to kHz */
+
+		/* maximum */
+		wrmsr(MSR_TMTA_LRTI_READOUT, 0, msr_hi);
+		rdmsr(MSR_TMTA_LRTI_VOLT_MHZ, msr_lo, msr_hi);
+		*high_freq = msr_lo * 1000; /* to kHz */
+
+		if (*low_freq > *high_freq)
+			*low_freq = *high_freq;
+		return 0;
+	}
+
+	/* set the upper border to the value determined during TSC init */
+	*high_freq = (cpu_khz / 1000);
+	*high_freq = *high_freq * 1000;
+
+	/* get current borders */
+	rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
+	save_lo = msr_lo & 0x0000007F;
+	save_hi = msr_hi & 0x0000007F;
+
+	/* if current perf_pctg is larger than 90%, we need to decrease the
+	 * upper limit to make the calculation more accurate.
+	 */
+	cpuid(0x80860007, &eax, &ebx, &ecx, &edx);
+	if (ecx > 90) {
+		/* set to 0 to 80 perf_pctg */
+		msr_lo &= 0xFFFFFF80;
+		msr_hi &= 0xFFFFFF80;
+		msr_lo |= 0;
+		msr_hi |= 80;
+		wrmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
+
+		/* read out current core MHz and current perf_pctg */
+		cpuid(0x80860007, &eax, &ebx, &ecx, &edx);
+
+		/* restore values */
+		wrmsr(MSR_TMTA_LONGRUN_CTRL, save_lo, save_hi);	
+	}
+
+	/* performance_pctg = (current_freq - low_freq)/(high_freq - low_freq)
+	 * eqals
+	 * low_freq * ( 1 - perf_pctg) = (cur_freq - high_freq * perf_pctg)
+	 *
+	 * high_freq * perf_pctg is stored tempoarily into "ebx".
+	 */
+	ebx = (((cpu_khz / 1000) * ecx) / 100); /* to MHz */
+
+	if ((ecx > 95) || (ecx == 0) || (eax < ebx))
+		return -EIO;
+
+	edx = (eax - ebx) / (100 - ecx); 
+	*low_freq = edx * 1000; /* back to kHz */
+
+	if (*low_freq > *high_freq)
+		*low_freq = *high_freq;
+
+	return 0;
+}
+
+
+/**
+ * longrun_init - initializes the Transmeta Crusoe LongRun CPUFreq driver
+ *
+ * Initializes the LongRun support.
+ */
+static int __init longrun_init(void)
+{
+	int                     result;
+	struct cpufreq_driver   *driver;
+	struct cpuinfo_x86 *c = cpu_data;
+
+	if (c->x86_vendor != X86_VENDOR_TRANSMETA || 
+	    !cpu_has(c, X86_FEATURE_LONGRUN))
+		return 0;
+
+	/* initialization of main "cpufreq" code*/
+	driver = kmalloc(sizeof(struct cpufreq_driver) + 
+			 NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL);
+	if (!driver)
+		return -ENOMEM;
+
+	driver->policy = (struct cpufreq_policy *) (driver + 1);
+
+	if (longrun_determine_freqs(&longrun_low_freq, &longrun_high_freq)) {
+		kfree(driver);
+		return -EIO;
+	}
+	driver->policy[0].max_cpu_freq  = longrun_high_freq;
+
+	longrun_get_policy(&driver->policy[0]);
+
+	driver->verify         = &longrun_verify_policy;
+	driver->setpolicy      = &longrun_set_policy;
+	result = cpufreq_register(driver);
+	if (result) {
+		kfree(driver);
+		return result;
+	}
+	longrun_driver = driver;
+
+	return 0;
+}
+
+
+/**
+ * longrun_exit - unregisters LongRun support
+ */
+static void __exit longrun_exit(void)
+{
+	if (longrun_driver) {
+		cpufreq_unregister();
+		kfree(longrun_driver);
+	}
+}
+
+
+MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>");
+MODULE_DESCRIPTION ("LongRun driver for Transmeta Crusoe processors.");
+MODULE_LICENSE ("GPL");
+module_init(longrun_init);
+module_exit(longrun_exit);
diff -Nru a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,285 @@
+/*
+ *	Pentium 4/Xeon CPU on demand clock modulation/speed scaling
+ *	(C) 2002 Zwane Mwaikambo <zwane@commfireservices.com>
+ *	(C) 2002 Arjan van de Ven <arjanv@redhat.com>
+ *	(C) 2002 Tora T. Engstad
+ *	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.
+ *
+ *      The author(s) of this software shall not be held liable for damages
+ *      of any nature resulting due to the use of this software. This
+ *      software is provided AS-IS with no warranties.
+ *	
+ *	Date		Errata			Description
+ *	20020525	N44, O17	12.5% or 25% DC causes lockup
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h> 
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/cpufreq.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+
+#include <asm/processor.h> 
+#include <asm/msr.h>
+#include <asm/timex.h>
+
+#define PFX	"cpufreq: "
+
+/*
+ * Duty Cycle (3bits), note DC_DISABLE is not specified in
+ * intel docs i just use it to mean disable
+ */
+enum {
+	DC_RESV, DC_DFLT, DC_25PT, DC_38PT, DC_50PT,
+	DC_64PT, DC_75PT, DC_88PT, DC_DISABLE
+};
+
+#define DC_ENTRIES	8
+
+
+static int has_N44_O17_errata;
+static int stock_freq;
+MODULE_PARM(stock_freq, "i");
+
+static struct cpufreq_driver *cpufreq_p4_driver;
+static unsigned int cpufreq_p4_old_state = 0;
+
+
+static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate)
+{
+	u32 l, h;
+	unsigned long cpus_allowed;
+	struct cpufreq_freqs    freqs;
+
+	if (!cpu_online(cpu) || (newstate > DC_DISABLE) || 
+		(newstate == DC_RESV))
+		return -EINVAL;
+	cpu = cpu >> 1; /* physical CPU #nr */
+
+	/* notifiers */
+	freqs.old = stock_freq * cpufreq_p4_old_state / 8;
+	freqs.new = stock_freq * newstate / 8;
+	freqs.cpu = 2*cpu;
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+	freqs.cpu++;
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	/* switch to physical CPU where state is to be changed*/
+	cpus_allowed = current->cpus_allowed;
+	set_cpus_allowed(current, 3 << (2 * cpu));
+	BUG_ON(cpu != (smp_processor_id() >> 1));
+
+	rdmsr(MSR_IA32_THERM_STATUS, l, h);
+	if (l & 0x01)
+		printk(KERN_DEBUG PFX "CPU#%d currently thermal throttled\n", cpu);
+
+	if (has_N44_O17_errata && (newstate == DC_25PT || newstate == DC_DFLT))
+		newstate = DC_38PT;
+
+	rdmsr(MSR_IA32_THERM_CONTROL, l, h);
+	if (newstate == DC_DISABLE) {
+		printk(KERN_INFO PFX "CPU#%d,%d disabling modulation\n", cpu, (cpu + 1));
+		wrmsr(MSR_IA32_THERM_CONTROL, l & ~(1<<4), h);
+	} else {
+		printk(KERN_INFO PFX "CPU#%d,%d setting duty cycle to %d%%\n", cpu, (cpu + 1), ((125 * newstate) / 10));
+		/* bits 63 - 5	: reserved 
+		 * bit  4	: enable/disable
+		 * bits 3-1	: duty cycle
+		 * bit  0	: reserved
+		 */
+		l = (l & ~14);
+		l = l | (1<<4) | ((newstate & 0x7)<<1);
+		wrmsr(MSR_IA32_THERM_CONTROL, l, h);
+	}
+
+	set_cpus_allowed(current, cpus_allowed);
+
+	/* notifiers */
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+	freqs.cpu--;
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+	cpufreq_p4_old_state = newstate;
+
+	return 0;
+}
+
+
+static void cpufreq_p4_setpolicy(struct cpufreq_policy *policy)
+{
+	unsigned int    i;
+	unsigned int    newstate = 0;
+	unsigned int    number_states = 0;
+
+	if (!cpufreq_p4_driver || !stock_freq || !policy)
+		return;
+
+	if (policy->policy == CPUFREQ_POLICY_POWERSAVE)
+	{
+		for (i=8; i>0; i++)
+			if ((policy->min <= ((stock_freq / 8) * i)) &&
+			    (policy->max >= ((stock_freq / 8) * i))) 
+			{
+				newstate = i;
+				number_states++;
+			}
+	} else {
+		for (i=0; i<=8; i--)
+			if ((policy->min <= ((stock_freq / 8) * i)) &&
+			    (policy->max >= ((stock_freq / 8) * i))) 
+			{
+				newstate = i;
+				number_states++;
+			}
+	}
+
+	/* if (number_states == 1) */
+	{
+		if (policy->cpu == CPUFREQ_ALL_CPUS) {
+			for (i=0; i<(NR_CPUS/2); i++)
+				if (cpu_online(2*i))
+					cpufreq_p4_setdc((2*i), newstate);
+		} else {
+			cpufreq_p4_setdc(policy->cpu, newstate);
+		}
+	}
+	/* else {
+		if (policy->policy == CPUFREQ_POLICY_POWERSAVE) {
+			min_state = newstate;
+			max_state = newstate + (number_states - 1);
+		} else {
+			max_state = newstate;
+			min_state = newstate - (number_states - 1);
+		}
+	} */
+}
+
+
+static void cpufreq_p4_verify(struct cpufreq_policy *policy)
+{
+	unsigned int    number_states = 0;
+	unsigned int    i;
+
+	if (!cpufreq_p4_driver || !stock_freq || !policy)
+		return;
+
+	if (!cpu_online(policy->cpu))
+		policy->cpu = CPUFREQ_ALL_CPUS;
+	cpufreq_verify_within_limits(policy, (stock_freq / 8), stock_freq);
+
+	/* is there at least one state within limit? */
+	for (i=1; i<=8; i++)
+		if ((policy->min <= ((stock_freq / 8) * i)) &&
+		    (policy->max >= ((stock_freq / 8) * i)))
+			number_states++;
+
+	if (number_states)
+		return;
+
+	policy->max = (stock_freq / 8) * (((unsigned int) ((policy->max * 8) / stock_freq)) + 1);
+	return;
+}
+
+
+int __init cpufreq_p4_init(void)
+{	
+	struct cpuinfo_x86 *c = cpu_data;
+	int cpuid;
+	int ret;
+	struct cpufreq_driver *driver;
+	unsigned int i;
+
+	/*
+	 * THERM_CONTROL is architectural for IA32 now, so 
+	 * we can rely on the capability checks
+	 */
+	if (c->x86_vendor != X86_VENDOR_INTEL)
+		return -ENODEV;
+
+	if (!test_bit(X86_FEATURE_ACPI, c->x86_capability) ||
+		!test_bit(X86_FEATURE_ACC, c->x86_capability))
+		return -ENODEV;
+
+	/* Errata workarounds */
+	cpuid = (c->x86 << 8) | (c->x86_model << 4) | c->x86_mask;
+	switch (cpuid) {
+		case 0x0f07:
+		case 0x0f0a:
+		case 0x0f11:
+		case 0x0f12:
+			has_N44_O17_errata = 1;
+		default:
+			break;
+	}
+
+	printk(KERN_INFO PFX "P4/Xeon(TM) CPU On-Demand Clock Modulation available\n");
+	driver = kmalloc(sizeof(struct cpufreq_driver) +
+			 NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL);
+	if (!driver)
+		return -ENOMEM;
+
+	driver->policy = (struct cpufreq_policy *) (driver + 1);
+
+	if (!stock_freq)
+		stock_freq = cpu_khz;
+
+#ifdef CONFIG_CPU_FREQ_24_API
+	driver->cpu_min_freq    = stock_freq / 8;
+	for (i=0;i<NR_CPUS;i++)
+		driver->cpu_cur_freq[i] = stock_freq;
+#endif
+	cpufreq_p4_old_state  = DC_DISABLE;
+
+	driver->verify        = &cpufreq_p4_verify;
+	driver->setpolicy     = &cpufreq_p4_setpolicy;
+
+	for (i=0;i<NR_CPUS;i++) {
+		if (has_N44_O17_errata)
+			driver->policy[i].min    = (stock_freq * 3) / 8;
+		else
+			driver->policy[i].min    = stock_freq / 8;
+		driver->policy[i].max    = stock_freq;
+		driver->policy[i].policy = CPUFREQ_POLICY_PERFORMANCE;
+		driver->policy[i].max_cpu_freq  = stock_freq;
+		driver->policy[i].cpu    = i;
+	}
+
+	ret = cpufreq_register(driver);
+	if (ret) {
+		kfree(driver);
+		return ret;
+	}
+
+	cpufreq_p4_driver = driver;
+	
+	return 0;
+}
+
+
+void __exit cpufreq_p4_exit(void)
+{
+	u32 l, h;
+
+	if (cpufreq_p4_driver) {
+		cpufreq_unregister();
+		/* return back to a non modulated state */
+		rdmsr(MSR_IA32_THERM_CONTROL, l, h);
+		wrmsr(MSR_IA32_THERM_CONTROL, l & ~(1<<4), h);
+		kfree(cpufreq_p4_driver);
+	}
+}
+
+MODULE_AUTHOR ("Zwane Mwaikambo <zwane@commfireservices.com>");
+MODULE_DESCRIPTION ("cpufreq driver for Pentium(TM) 4/Xeon(TM)");
+MODULE_LICENSE ("GPL");
+
+module_init(cpufreq_p4_init);
+module_exit(cpufreq_p4_exit);
+
diff -Nru a/arch/i386/kernel/cpu/cpufreq/powernow-k6.c b/arch/i386/kernel/cpu/cpufreq/powernow-k6.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k6.c	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,294 @@
+/*
+ *  $Id: powernow-k6.c,v 1.33 2002/09/29 23:43:11 db Exp $
+ *  This file was part of Powertweak Linux (http://powertweak.sf.net)
+ *  and is shared with the Linux Kernel module.
+ *
+ *  (C) 2000-2002  Dave Jones, Arjan van de Ven, Janne Pänkälä, Dominik Brodowski.
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ *  BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h> 
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+
+#include <asm/msr.h>
+#include <asm/timex.h>
+#include <asm/io.h>
+
+
+#define POWERNOW_IOPORT 0xfff0         /* it doesn't matter where, as long
+					  as it is unused */
+
+static struct cpufreq_driver		*powernow_driver;
+static unsigned int                     busfreq;   /* FSB, in 10 kHz */
+static unsigned int                     max_multiplier;
+
+
+/* Clock ratio multiplied by 10 - see table 27 in AMD#23446 */
+static int clock_ratio[8] = {
+	45,  /* 000 -> 4.5x */
+	50,  /* 001 -> 5.0x */
+	40,  /* 010 -> 4.0x */
+	55,  /* 011 -> 5.5x */
+	20,  /* 100 -> 2.0x */
+	30,  /* 101 -> 3.0x */
+	60,  /* 110 -> 6.0x */
+	35   /* 111 -> 3.5x */
+};
+
+
+/**
+ * powernow_k6_get_cpu_multiplier - returns the current FSB multiplier
+ *
+ *   Returns the current setting of the frequency multiplier. Core clock
+ * speed is frequency of the Front-Side Bus multiplied with this value.
+ */
+static int powernow_k6_get_cpu_multiplier(void)
+{
+	u64             invalue = 0;
+	u32             msrval;
+	
+	msrval = POWERNOW_IOPORT + 0x1;
+	wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */
+	invalue=inl(POWERNOW_IOPORT + 0x8);
+	msrval = POWERNOW_IOPORT + 0x0;
+	wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */
+
+	return clock_ratio[(invalue >> 5)&7];
+}
+
+
+/**
+ * powernow_k6_set_state - set the PowerNow! multiplier
+ * @best_i: clock_ratio[best_i] is the target multiplier
+ *
+ *   Tries to change the PowerNow! multiplier
+ */
+static void powernow_k6_set_state (unsigned int best_i)
+{
+	unsigned long           outvalue=0, invalue=0;
+	unsigned long           msrval;
+	struct cpufreq_freqs    freqs;
+
+	if (!powernow_driver) {
+		printk(KERN_ERR "cpufreq: initialization problem or invalid target frequency\n");
+		return;
+	}
+
+	freqs.old = busfreq * powernow_k6_get_cpu_multiplier();
+	freqs.new = busfreq * clock_ratio[best_i];
+	freqs.cpu = CPUFREQ_ALL_CPUS; /* powernow-k6.c is UP only driver */
+	
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	/* we now need to transform best_i to the BVC format, see AMD#23446 */
+
+	outvalue = (1<<12) | (1<<10) | (1<<9) | (best_i<<5);
+
+	msrval = POWERNOW_IOPORT + 0x1;
+	wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */
+	invalue=inl(POWERNOW_IOPORT + 0x8);
+	invalue = invalue & 0xf;
+	outvalue = outvalue | invalue;
+	outl(outvalue ,(POWERNOW_IOPORT + 0x8));
+	msrval = POWERNOW_IOPORT + 0x0;
+	wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+	return;
+}
+
+
+/**
+ * powernow_k6_verify - verifies a new CPUfreq policy
+ * @policy: new policy
+ *
+ * Policy must be within lowest and highest possible CPU Frequency,
+ * and at least one possible state must be within min and max.
+ */
+static void powernow_k6_verify(struct cpufreq_policy *policy)
+{
+	unsigned int    number_states = 0;
+	unsigned int    i, j;
+
+	if (!policy || !busfreq)
+		return;
+
+	policy->cpu = 0;
+	cpufreq_verify_within_limits(policy, (20 * busfreq),
+				     (max_multiplier * busfreq));
+
+	for (i=0; i<8; i++)
+		if ((policy->min <= (busfreq * clock_ratio[i])) &&
+		    (policy->max >= (busfreq * clock_ratio[i])))
+			number_states++;
+
+	if (number_states)
+		return;
+
+	/* no state is available within range -- find next larger state */
+
+	j = 6;
+
+	for (i=0; i<8; i++)
+		if (((clock_ratio[i] * busfreq) >= policy->min) &&
+		    (clock_ratio[i] < clock_ratio[j]))
+			j = i;
+
+	policy->max = clock_ratio[j] * busfreq;
+
+	return;
+}
+
+
+/**
+ * powernow_k6_setpolicy - sets a new CPUFreq policy
+ * @policy - new policy
+ *
+ * sets a new CPUFreq policy
+ */
+static void powernow_k6_setpolicy (struct cpufreq_policy *policy)
+{
+	unsigned int    number_states = 0;
+	unsigned int    i, j=4;
+
+	if (!powernow_driver)
+		return;
+
+	for (i=0; i<8; i++)
+		if ((policy->min <= (busfreq * clock_ratio[i])) &&
+		    (policy->max >= (busfreq * clock_ratio[i])))
+		{
+			number_states++;
+			j = i;
+		}
+
+	if (number_states == 1) {
+		/* if only one state is within the limit borders, it
+		   is easily detected and set */
+		powernow_k6_set_state(j);
+		return;
+	}
+
+	/* more than one state within limit */
+	switch (policy->policy) {
+	case CPUFREQ_POLICY_POWERSAVE:
+		j = 6;
+		for (i=0; i<8; i++)
+		if ((policy->min <= (busfreq * clock_ratio[i])) &&
+		    (policy->max >= (busfreq * clock_ratio[i])) &&
+			    (clock_ratio[i] < clock_ratio[j]))
+				j = i;
+		break;
+	case CPUFREQ_POLICY_PERFORMANCE:
+		j = 4;
+		for (i=0; i<8; i++)
+		if ((policy->min <= (busfreq * clock_ratio[i])) &&
+		    (policy->max >= (busfreq * clock_ratio[i])) &&
+			    (clock_ratio[i] > clock_ratio[j]))
+				j = i;
+		break;
+	default:
+		return;
+	}
+
+	if (clock_ratio[i] > max_multiplier)
+		BUG();
+
+	powernow_k6_set_state(j);
+	return;
+}
+
+
+/**
+ * powernow_k6_init - initializes the k6 PowerNow! CPUFreq driver
+ *
+ *   Initializes the K6 PowerNow! support. Returns -ENODEV on unsupported
+ * devices, -EINVAL or -ENOMEM on problems during initiatization, and zero
+ * on success.
+ */
+static int __init powernow_k6_init(void)
+{	
+	struct cpuinfo_x86      *c = cpu_data;
+	struct cpufreq_driver   *driver;
+	unsigned int            result;
+
+	if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 != 5) ||
+		((c->x86_model != 12) && (c->x86_model != 13)))
+		return -ENODEV;
+
+	max_multiplier = powernow_k6_get_cpu_multiplier();
+	busfreq = cpu_khz / max_multiplier;
+
+	if (!request_region(POWERNOW_IOPORT, 16, "PowerNow!")) {
+		printk("cpufreq: PowerNow IOPORT region already used.\n");
+		return -EIO;
+	}
+
+	/* initialization of main "cpufreq" code*/
+	driver = kmalloc(sizeof(struct cpufreq_driver) +
+			 NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL);
+	if (!driver) {
+		release_region (POWERNOW_IOPORT, 16);
+		return -ENOMEM;
+	}
+	driver->policy = (struct cpufreq_policy *) (driver + 1);
+
+#ifdef CONFIG_CPU_FREQ_24_API
+	driver->cpu_min_freq     = busfreq * 20;
+	driver->cpu_cur_freq[0]  = busfreq * max_multiplier;
+#endif
+
+	driver->verify        = &powernow_k6_verify;
+	driver->setpolicy     = &powernow_k6_setpolicy;
+
+	driver->policy[0].cpu    = 0;
+	driver->policy[0].min    = busfreq * 20;
+	driver->policy[0].max    = busfreq * max_multiplier;
+	driver->policy[0].policy = CPUFREQ_POLICY_PERFORMANCE;
+	driver->policy[0].max_cpu_freq  = busfreq * max_multiplier;
+
+
+	result = cpufreq_register(driver);
+	if (result) {
+		release_region (POWERNOW_IOPORT, 16);
+		kfree(driver);
+		return result;
+	}
+	powernow_driver = driver;
+
+	return 0;
+}
+
+
+/**
+ * powernow_k6_exit - unregisters AMD K6-2+/3+ PowerNow! support
+ *
+ *   Unregisters AMD K6-2+ / K6-3+ PowerNow! support.
+ */
+static void __exit powernow_k6_exit(void)
+{
+	unsigned int i;
+
+	if (powernow_driver) {
+		for (i=0;i<8;i++)
+			if (clock_ratio[i] == max_multiplier)
+				powernow_k6_set_state(i);		
+		cpufreq_unregister();
+		kfree(powernow_driver);
+	}
+}
+
+
+MODULE_AUTHOR ("Arjan van de Ven <arjanv@redhat.com>, Dave Jones <davej@suse.de>, Dominik Brodowski <linux@brodo.de>");
+MODULE_DESCRIPTION ("PowerNow! driver for AMD K6-2+ / K6-3+ processors.");
+MODULE_LICENSE ("GPL");
+module_init(powernow_k6_init);
+module_exit(powernow_k6_exit);
diff -Nru a/arch/i386/kernel/cpu/cpufreq/speedstep.c b/arch/i386/kernel/cpu/cpufreq/speedstep.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep.c	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,728 @@
+/*
+ *  $Id: speedstep.c,v 1.53 2002/09/29 23:43:11 db Exp $
+ *
+ * (C) 2001  Dave Jones, Arjan van de ven.
+ * (C) 2002  Dominik Brodowski <linux@brodo.de>
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *  Based upon reverse engineered information, and on Intel documentation
+ *  for chipsets ICH2-M and ICH3-M.
+ *
+ *  Many thanks to Ducrot Bruno for finding and fixing the last
+ *  "missing link" for ICH2-M/ICH3-M support, and to Thomas Winkler 
+ *  for extensive testing.
+ *
+ *  BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
+ */
+
+
+/*********************************************************************
+ *                        SPEEDSTEP - DEFINITIONS                    *
+ *********************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h> 
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include <asm/msr.h>
+
+
+static struct cpufreq_driver		*speedstep_driver;
+
+/* speedstep_chipset:
+ *   It is necessary to know which chipset is used. As accesses to 
+ * this device occur at various places in this module, we need a 
+ * static struct pci_dev * pointing to that device.
+ */
+static unsigned int                     speedstep_chipset;
+static struct pci_dev                   *speedstep_chipset_dev;
+
+#define SPEEDSTEP_CHIPSET_ICH2M         0x00000002
+#define SPEEDSTEP_CHIPSET_ICH3M         0x00000003
+
+
+/* speedstep_processor
+ */
+static unsigned int                     speedstep_processor;
+
+#define SPEEDSTEP_PROCESSOR_PIII_C      0x00000001  /* Coppermine core */
+#define SPEEDSTEP_PROCESSOR_PIII_T      0x00000002  /* Tualatin core */
+#define SPEEDSTEP_PROCESSOR_P4M         0x00000003  /* P4-M with 100 MHz FSB */
+
+
+/* speedstep_[low,high]_freq
+ *   There are only two frequency states for each processor. Values
+ * are in kHz for the time being.
+ */
+static unsigned int                     speedstep_low_freq;
+static unsigned int                     speedstep_high_freq;
+
+#define SPEEDSTEP_HIGH                  0x00000000
+#define SPEEDSTEP_LOW                   0x00000001
+
+
+/* DEBUG
+ *   Define it if you want verbose debug output, e.g. for bug reporting
+ */
+//#define SPEEDSTEP_DEBUG
+
+#ifdef SPEEDSTEP_DEBUG
+#define dprintk(msg...) printk(msg)
+#else
+#define dprintk(msg...) do { } while(0);
+#endif
+
+
+
+/*********************************************************************
+ *                    LOW LEVEL CHIPSET INTERFACE                    *
+ *********************************************************************/
+
+/**
+ * speedstep_get_state - read the current SpeedStep state
+ * @state: Speedstep state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH)
+ *
+ *   Tries to read the SpeedStep state. Returns -EIO when there has been
+ * trouble to read the status or write to the control register, -EINVAL
+ * on an unsupported chipset, and zero on success.
+ */
+static int speedstep_get_state (unsigned int *state)
+{
+	unsigned long   flags;
+	u32             pmbase;
+	u8              value;
+
+	if (!speedstep_chipset_dev || !state)
+		return -EINVAL;
+
+	switch (speedstep_chipset) {
+	case SPEEDSTEP_CHIPSET_ICH2M:
+	case SPEEDSTEP_CHIPSET_ICH3M:
+		/* get PMBASE */
+		pci_read_config_dword(speedstep_chipset_dev, 0x40, &pmbase);
+		if (!(pmbase & 0x01))
+			return -EIO;
+
+		pmbase &= 0xFFFFFFFE;
+		if (!pmbase) 
+			return -EIO;
+
+		/* read state */
+		local_irq_save(flags);
+		value = inb(pmbase + 0x50);
+		local_irq_restore(flags);
+
+		dprintk(KERN_DEBUG "cpufreq: read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value);
+
+		*state = value & 0x01;
+		return 0;
+
+	}
+
+	printk (KERN_ERR "cpufreq: setting CPU frequency on this chipset unsupported.\n");
+	return -EINVAL;
+}
+
+
+/**
+ * speedstep_set_state - set the SpeedStep state
+ * @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH)
+ *
+ *   Tries to change the SpeedStep state. 
+ */
+static void speedstep_set_state (unsigned int state, int notify)
+{
+	u32                     pmbase;
+	u8	                pm2_blk;
+	u8                      value;
+	unsigned long           flags;
+	unsigned int            oldstate;
+	struct cpufreq_freqs    freqs;
+
+	if (!speedstep_chipset_dev || (state > 0x1))
+		return;
+
+	if (speedstep_get_state(&oldstate))
+		return;
+
+	if (oldstate == state)
+		return;
+
+	freqs.old = (oldstate == SPEEDSTEP_HIGH) ? speedstep_high_freq : speedstep_low_freq;
+	freqs.new = (state == SPEEDSTEP_HIGH) ? speedstep_high_freq : speedstep_low_freq;
+	freqs.cpu = CPUFREQ_ALL_CPUS; /* speedstep.c is UP only driver */
+	
+	if (notify)
+		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	switch (speedstep_chipset) {
+	case SPEEDSTEP_CHIPSET_ICH2M:
+	case SPEEDSTEP_CHIPSET_ICH3M:
+		/* get PMBASE */
+		pci_read_config_dword(speedstep_chipset_dev, 0x40, &pmbase);
+		if (!(pmbase & 0x01))
+		{
+			printk(KERN_ERR "cpufreq: could not find speedstep register\n");
+			return;
+		}
+
+		pmbase &= 0xFFFFFFFE;
+		if (!pmbase) {
+			printk(KERN_ERR "cpufreq: could not find speedstep register\n");
+			return;
+		}
+
+		/* Disable IRQs */
+		local_irq_save(flags);
+
+		/* read state */
+		value = inb(pmbase + 0x50);
+
+		dprintk(KERN_DEBUG "cpufreq: read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value);
+
+		/* write new state */
+		value &= 0xFE;
+		value |= state;
+
+		dprintk(KERN_DEBUG "cpufreq: writing 0x%x to pmbase 0x%x + 0x50\n", value, pmbase);
+
+		/* Disable bus master arbitration */
+		pm2_blk = inb(pmbase + 0x20);
+		pm2_blk |= 0x01;
+		outb(pm2_blk, (pmbase + 0x20));
+
+		/* Actual transition */
+		outb(value, (pmbase + 0x50));
+
+		/* Restore bus master arbitration */
+		pm2_blk &= 0xfe;
+		outb(pm2_blk, (pmbase + 0x20));
+
+		/* check if transition was sucessful */
+		value = inb(pmbase + 0x50);
+
+		/* Enable IRQs */
+		local_irq_restore(flags);
+
+		dprintk(KERN_DEBUG "cpufreq: read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value);
+
+		if (state == (value & 0x1)) {
+			dprintk (KERN_INFO "cpufreq: change to %u MHz succeded\n", (freqs.new / 1000));
+		} else {
+			printk (KERN_ERR "cpufreq: change failed - I/O error\n");
+		}
+		break;
+	default:
+		printk (KERN_ERR "cpufreq: setting CPU frequency on this chipset unsupported.\n");
+	}
+
+	if (notify)
+		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+	return;
+}
+
+
+/**
+ * speedstep_activate - activate SpeedStep control in the chipset
+ *
+ *   Tries to activate the SpeedStep status and control registers.
+ * Returns -EINVAL on an unsupported chipset, and zero on success.
+ */
+static int speedstep_activate (void)
+{
+	if (!speedstep_chipset_dev)
+		return -EINVAL;
+
+	switch (speedstep_chipset) {
+	case SPEEDSTEP_CHIPSET_ICH2M:
+	case SPEEDSTEP_CHIPSET_ICH3M:
+	{
+		u16             value = 0;
+
+		pci_read_config_word(speedstep_chipset_dev, 
+				     0x00A0, &value);
+		if (!(value & 0x08)) {
+			value |= 0x08;
+			dprintk(KERN_DEBUG "cpufreq: activating SpeedStep (TM) registers\n");
+			pci_write_config_word(speedstep_chipset_dev, 
+					      0x00A0, value);
+		}
+
+		return 0;
+	}
+	}
+	
+	printk (KERN_ERR "cpufreq: SpeedStep (TM) on this chipset unsupported.\n");
+	return -EINVAL;
+}
+
+
+/**
+ * speedstep_detect_chipset - detect the Southbridge which contains SpeedStep logic
+ *
+ *   Detects PIIX4, ICH2-M and ICH3-M so far. The pci_dev points to 
+ * the LPC bridge / PM module which contains all power-management 
+ * functions. Returns the SPEEDSTEP_CHIPSET_-number for the detected
+ * chipset, or zero on failure.
+ */
+static unsigned int speedstep_detect_chipset (void)
+{
+	speedstep_chipset_dev = pci_find_subsys(PCI_VENDOR_ID_INTEL,
+			      PCI_DEVICE_ID_INTEL_82801CA_12, 
+			      PCI_ANY_ID,
+			      PCI_ANY_ID,
+			      NULL);
+	if (speedstep_chipset_dev)
+		return SPEEDSTEP_CHIPSET_ICH3M;
+
+
+	speedstep_chipset_dev = pci_find_subsys(PCI_VENDOR_ID_INTEL,
+			      PCI_DEVICE_ID_INTEL_82801BA_10,
+			      PCI_ANY_ID,
+			      PCI_ANY_ID,
+			      NULL);
+	if (speedstep_chipset_dev) {
+		/* speedstep.c causes lockups on Dell Inspirons 8000 and
+		 * 8100 which use a pretty old revision of the 82815 
+		 * host brige. Abort on these systems.
+		 */
+		static struct pci_dev   *hostbridge;
+		u8			rev = 0;
+
+		hostbridge  = pci_find_subsys(PCI_VENDOR_ID_INTEL,
+			      PCI_DEVICE_ID_INTEL_82815_MC,
+			      PCI_ANY_ID,
+			      PCI_ANY_ID,
+			      NULL);
+
+		if (!hostbridge)
+			return SPEEDSTEP_CHIPSET_ICH2M;
+			
+		pci_read_config_byte(hostbridge, PCI_REVISION_ID, &rev);
+		if (rev < 5) {
+			dprintk(KERN_INFO "cpufreq: hostbrige does not support speedstep\n");
+			speedstep_chipset_dev = NULL;
+			return 0;
+		}
+
+		return SPEEDSTEP_CHIPSET_ICH2M;
+	}
+
+	return 0;
+}
+
+
+
+/*********************************************************************
+ *                   LOW LEVEL PROCESSOR INTERFACE                   *
+ *********************************************************************/
+
+
+/**
+ * pentium3_get_frequency - get the core frequencies for PIIIs
+ *
+ *   Returns the core frequency of a Pentium III processor (in kHz)
+ */
+static unsigned int pentium3_get_frequency (void)
+{
+        /* See table 14 of p3_ds.pdf and table 22 of 29834003.pdf */
+	struct {
+		unsigned int ratio;	/* Frequency Multiplier (x10) */
+		u8 bitmap;	        /* power on configuration bits
+					   [27, 25:22] (in MSR 0x2a) */
+	} msr_decode_mult [] = {
+		{ 30, 0x01 },
+		{ 35, 0x05 },
+		{ 40, 0x02 },
+		{ 45, 0x06 },
+		{ 50, 0x00 },
+		{ 55, 0x04 },
+		{ 60, 0x0b },
+		{ 65, 0x0f },
+		{ 70, 0x09 },
+		{ 75, 0x0d },
+		{ 80, 0x0a },
+		{ 85, 0x26 },
+		{ 90, 0x20 },
+		{ 100, 0x2b },
+		{ 0, 0xff }     /* error or unknown value */
+	};
+	/* PIII(-M) FSB settings: see table b1-b of 24547206.pdf */
+	struct {
+		unsigned int value;     /* Front Side Bus speed in MHz */
+		u8 bitmap;              /* power on configuration bits [18: 19]
+					   (in MSR 0x2a) */
+	} msr_decode_fsb [] = {
+		{  66, 0x0 },
+		{ 100, 0x2 },
+		{ 133, 0x1 },
+		{   0, 0xff}
+	};
+	u32     msr_lo, msr_tmp;
+	int     i = 0, j = 0;
+	struct  cpuinfo_x86 *c = cpu_data;
+
+	/* read MSR 0x2a - we only need the low 32 bits */
+	rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp);
+	dprintk(KERN_DEBUG "cpufreq: P3 - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp);
+	msr_tmp = msr_lo;
+
+	/* decode the FSB */
+	msr_tmp &= 0x00c0000;
+	msr_tmp >>= 18;
+	while (msr_tmp != msr_decode_fsb[i].bitmap) {
+		if (msr_decode_fsb[i].bitmap == 0xff)
+			return -EINVAL;
+		i++;
+	}
+
+	/* decode the multiplier */
+	if ((c->x86_model == 0x08) && (c->x86_mask == 0x01)) 
+                /* different on early Coppermine PIII */
+		msr_lo &= 0x03c00000;
+	else
+		msr_lo &= 0x0bc00000;
+	msr_lo >>= 22;
+	while (msr_lo != msr_decode_mult[j].bitmap) {
+		if (msr_decode_mult[j].bitmap == 0xff)
+			return -EINVAL;
+		j++;
+	}
+
+	return (msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100);
+}
+
+
+/**
+ * pentium4_get_frequency - get the core frequency for P4-Ms
+ *
+ *   Should return the core frequency (in kHz) for P4-Ms. 
+ */
+static unsigned int pentium4_get_frequency(void)
+{
+	u32 msr_lo, msr_hi;
+
+	rdmsr(0x2c, msr_lo, msr_hi);
+
+	dprintk(KERN_DEBUG "cpufreq: P4 - MSR_EBC_FREQUENCY_ID: 0x%x 0x%x\n", msr_lo, msr_hi);
+
+	/* First 12 bits seem to change a lot (0x511, 0x410 and 0x30f seen 
+	 * yet). Next 12 bits always seem to be 0x300. If this is not true 
+	 * on this CPU, complain. Last 8 bits are frequency (in 100MHz).
+	 */
+	if (msr_hi || ((msr_lo & 0x00FFF000) != 0x300000)) {
+		printk(KERN_DEBUG "cpufreq: P4 - MSR_EBC_FREQUENCY_ID: 0x%x 0x%x\n", msr_lo, msr_hi);
+		printk(KERN_INFO "cpufreq: problem in initialization. Please contact Dominik Brodowski\n");
+		printk(KERN_INFO "cpufreq: <linux@brodo.de> and attach this dmesg. Thanks in advance\n");
+		return 0;
+	}
+
+	msr_lo >>= 24;
+	return (msr_lo * 100000);
+}
+
+
+/** 
+ * speedstep_detect_processor - detect Intel SpeedStep-capable processors.
+ *
+ *   Returns the SPEEDSTEP_PROCESSOR_-number for the detected chipset, 
+ * or zero on failure.
+ */
+static unsigned int speedstep_detect_processor (void)
+{
+	struct cpuinfo_x86 *c = cpu_data;
+	u32                     ebx;
+
+	if ((c->x86_vendor != X86_VENDOR_INTEL) || 
+	    ((c->x86 != 6) && (c->x86 != 0xF)))
+		return 0;
+
+	if (c->x86 == 0xF) {
+		/* Intel Pentium 4 Mobile P4-M */
+		if (c->x86_model != 2)
+			return 0;
+
+		if (c->x86_mask != 4)
+			return 0;
+
+		ebx = cpuid_ebx(0x00000001);
+		ebx &= 0x000000FF;
+		if ((ebx != 0x0e) && (ebx != 0x0f))
+			return 0;
+
+		return SPEEDSTEP_PROCESSOR_P4M;
+	}
+
+	switch (c->x86_model) {
+	case 0x0B: /* Intel PIII [Tualatin] */
+		/* cpuid_ebx(1) is 0x04 for desktop PIII, 
+		                   0x06 for mobile PIII-M */
+		ebx = cpuid_ebx(0x00000001);
+
+		ebx &= 0x000000FF;
+		if (ebx != 0x06)
+			return 0;
+
+		/* So far all PIII-M processors support SpeedStep. See
+		 * Intel's 24540633.pdf of August 2002 
+		 */
+
+		return SPEEDSTEP_PROCESSOR_PIII_T;
+
+	case 0x08: /* Intel PIII [Coppermine] */
+		/* based on reverse-engineering information and
+		 * some guessing. HANDLE WITH CARE! */
+ 	        {
+			u32     msr_lo, msr_hi;
+
+			/* all mobile PIII Coppermines have FSB 100 MHz
+			 * ==> sort out a few desktop PIIIs. */
+			rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_hi);
+			dprintk(KERN_DEBUG "cpufreq: Coppermine: MSR_IA32_EBL_Cr_POWERON is 0x%x, 0x%x\n", msr_lo, msr_hi);
+			msr_lo &= 0x00c0000;
+			if (msr_lo != 0x0080000)
+				return 0;
+
+			/* platform ID seems to be 0x00140000 */
+			rdmsr(MSR_IA32_PLATFORM_ID, msr_lo, msr_hi);
+			dprintk(KERN_DEBUG "cpufreq: Coppermine: MSR_IA32_PLATFORM ID is 0x%x, 0x%x\n", msr_lo, msr_hi);
+			msr_hi = msr_lo & 0x001c0000;
+			if (msr_hi != 0x00140000)
+				return 0;
+
+			/* and these bits seem to be either 00_b, 01_b or
+			 * 10_b but never 11_b */
+			msr_lo &= 0x00030000;
+			if (msr_lo == 0x0030000)
+				return 0;
+
+			/* let's hope this is correct... */
+			return SPEEDSTEP_PROCESSOR_PIII_C;
+		}
+
+	default:
+		return 0;
+	}
+}
+
+
+
+/*********************************************************************
+ *                        HIGH LEVEL FUNCTIONS                       *
+ *********************************************************************/
+
+/**
+ * speedstep_detect_speeds - detects low and high CPU frequencies.
+ *
+ *   Detects the low and high CPU frequencies in kHz. Returns 0 on
+ * success or -EINVAL / -EIO on problems. 
+ */
+static int speedstep_detect_speeds (void)
+{
+	unsigned long   flags;
+	unsigned int    state;
+	int             i, result;
+
+	/* Disable irqs for entire detection process */
+	local_irq_save(flags);
+
+	for (i=0; i<2; i++) {
+		/* read the current state */
+		result = speedstep_get_state(&state);
+		if (result)
+			return result;
+
+		/* save the correct value, and switch to other */
+		if (state == SPEEDSTEP_LOW) {
+			switch (speedstep_processor) {
+			case SPEEDSTEP_PROCESSOR_PIII_C:
+			case SPEEDSTEP_PROCESSOR_PIII_T:
+				speedstep_low_freq = pentium3_get_frequency();
+				break;
+			case SPEEDSTEP_PROCESSOR_P4M:
+				speedstep_low_freq = pentium4_get_frequency();
+			}
+			speedstep_set_state(SPEEDSTEP_HIGH, 0);
+		} else {
+			switch (speedstep_processor) {
+			case SPEEDSTEP_PROCESSOR_PIII_C:
+			case SPEEDSTEP_PROCESSOR_PIII_T:
+				speedstep_high_freq = pentium3_get_frequency();
+				break;
+			case SPEEDSTEP_PROCESSOR_P4M:
+				speedstep_high_freq = pentium4_get_frequency();
+			}
+			speedstep_set_state(SPEEDSTEP_LOW, 0);
+		}
+	}
+
+	local_irq_restore(flags);
+
+	if (!speedstep_low_freq || !speedstep_high_freq || 
+	    (speedstep_low_freq == speedstep_high_freq))
+		return -EIO;
+
+	return 0;
+}
+
+
+/**
+ * speedstep_setpolicy - set a new CPUFreq policy
+ * @policy: new policy
+ *
+ * Sets a new CPUFreq policy.
+ */
+static void speedstep_setpolicy (struct cpufreq_policy *policy)
+{
+	if (!speedstep_driver || !policy)
+		return;
+
+	if (policy->min > speedstep_low_freq) 
+		speedstep_set_state(SPEEDSTEP_HIGH, 1);
+	else {
+		if (policy->max < speedstep_high_freq)
+			speedstep_set_state(SPEEDSTEP_LOW, 1);
+		else {
+			/* both frequency states are allowed */
+			if (policy->policy == CPUFREQ_POLICY_POWERSAVE)
+				speedstep_set_state(SPEEDSTEP_LOW, 1);
+			else
+				speedstep_set_state(SPEEDSTEP_HIGH, 1);
+		}
+	}
+}
+
+
+/**
+ * speedstep_verify - verifies a new CPUFreq policy
+ * @freq: new policy
+ *
+ * Limit must be within speedstep_low_freq and speedstep_high_freq, with
+ * at least one border included.
+ */
+static void speedstep_verify (struct cpufreq_policy *policy)
+{
+	if (!policy || !speedstep_driver || 
+	    !speedstep_low_freq || !speedstep_high_freq)
+		return;
+
+	policy->cpu = 0; /* UP only */
+
+	cpufreq_verify_within_limits(policy, speedstep_low_freq, speedstep_high_freq);
+
+	if ((policy->min > speedstep_low_freq) && 
+	    (policy->max < speedstep_high_freq))
+		policy->max = speedstep_high_freq;
+	
+	return;
+}
+
+
+/**
+ * speedstep_init - initializes the SpeedStep CPUFreq driver
+ *
+ *   Initializes the SpeedStep support. Returns -ENODEV on unsupported
+ * devices, -EINVAL on problems during initiatization, and zero on
+ * success.
+ */
+static int __init speedstep_init(void)
+{
+	int                     result;
+	unsigned int            speed;
+	struct cpufreq_driver   *driver;
+
+
+	/* detect chipset */
+	speedstep_chipset = speedstep_detect_chipset();
+
+	/* detect chipset */
+	if (speedstep_chipset)
+		speedstep_processor = speedstep_detect_processor();
+
+	if ((!speedstep_chipset) || (!speedstep_processor)) {
+		dprintk(KERN_INFO "cpufreq: Intel(R) SpeedStep(TM) for this %s not (yet) available.\n", speedstep_processor ? "chipset" : "processor");
+		return -ENODEV;
+	}
+
+	dprintk(KERN_INFO "cpufreq: Intel(R) SpeedStep(TM) support $Revision: 1.53 $\n");
+	dprintk(KERN_DEBUG "cpufreq: chipset 0x%x - processor 0x%x\n", 
+	       speedstep_chipset, speedstep_processor);
+
+	/* activate speedstep support */
+	result = speedstep_activate();
+	if (result)
+		return result;
+
+	/* detect low and high frequency */
+	result = speedstep_detect_speeds();
+	if (result)
+		return result;
+
+	/* get current speed setting */
+	result = speedstep_get_state(&speed);
+	if (result)
+		return result;
+
+	speed = (speed == SPEEDSTEP_LOW) ? speedstep_low_freq : speedstep_high_freq;
+
+	dprintk(KERN_INFO "cpufreq: currently at %s speed setting - %i MHz\n", 
+	       (speed == speedstep_low_freq) ? "low" : "high",
+	       (speed / 1000));
+
+	/* initialization of main "cpufreq" code*/
+	driver = kmalloc(sizeof(struct cpufreq_driver) + 
+			 NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL);
+	if (!driver)
+		return -ENOMEM;
+
+	driver->policy = (struct cpufreq_policy *) (driver + 1);
+
+#ifdef CONFIG_CPU_FREQ_24_API
+	driver->cpu_min_freq    = speedstep_low_freq;
+	driver->cpu_cur_freq[0] = speed;
+#endif
+
+	driver->verify      = &speedstep_verify;
+	driver->setpolicy   = &speedstep_setpolicy;
+
+	driver->policy[0].cpu    = 0;
+	driver->policy[0].min    = speedstep_low_freq;
+	driver->policy[0].max    = speedstep_high_freq;
+	driver->policy[0].max_cpu_freq = speedstep_high_freq;
+	driver->policy[0].policy = (speed == speedstep_low_freq) ? 
+	    CPUFREQ_POLICY_POWERSAVE : CPUFREQ_POLICY_PERFORMANCE;
+
+	result = cpufreq_register(driver);
+	if (result) {
+		kfree(driver);
+		return result;
+	}
+	speedstep_driver = driver;
+
+	return 0;
+}
+
+
+/**
+ * speedstep_exit - unregisters SpeedStep support
+ *
+ *   Unregisters SpeedStep support.
+ */
+static void __exit speedstep_exit(void)
+{
+	if (speedstep_driver) {
+		cpufreq_unregister();
+		kfree(speedstep_driver);
+	}
+}
+
+
+MODULE_AUTHOR ("Dave Jones <davej@suse.de>, Dominik Brodowski <linux@brodo.de>");
+MODULE_DESCRIPTION ("Speedstep driver for Intel mobile processors.");
+MODULE_LICENSE ("GPL");
+module_init(speedstep_init);
+module_exit(speedstep_exit);
diff -Nru a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c
--- a/arch/i386/kernel/i386_ksyms.c	Tue Oct  1 00:08:17 2002
+++ b/arch/i386/kernel/i386_ksyms.c	Tue Oct  1 00:08:17 2002
@@ -50,6 +50,7 @@
 EXPORT_SYMBOL(drive_info);
 #endif
 
+extern unsigned long cpu_khz;
 extern unsigned long get_cmos_time(void);
 
 /* platform dependent support */
@@ -80,6 +81,7 @@
 EXPORT_SYMBOL(pm_idle);
 EXPORT_SYMBOL(pm_power_off);
 EXPORT_SYMBOL(get_cmos_time);
+EXPORT_SYMBOL(cpu_khz);
 EXPORT_SYMBOL(apm_info);
 
 #ifdef CONFIG_DEBUG_IOVIRT
diff -Nru a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
--- a/arch/i386/kernel/irq.c	Tue Oct  1 00:08:15 2002
+++ b/arch/i386/kernel/irq.c	Tue Oct  1 00:08:15 2002
@@ -455,7 +455,7 @@
 		return -EINVAL;
 
 	action = (struct irqaction *)
-			kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+			kmalloc(sizeof(struct irqaction), GFP_ATOMIC);
 	if (!action)
 		return -ENOMEM;
 
@@ -484,10 +484,7 @@
  *	does not return until any executing interrupts for this IRQ
  *	have completed.
  *
- *	This function may be called from interrupt context. 
- *
- *	Bugs: Attempting to free an irq in a handler for the same irq hangs
- *	      the machine.
+ *	This function must not be called from interrupt context. 
  */
  
 void free_irq(unsigned int irq, void *dev_id)
diff -Nru a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c
--- a/arch/i386/kernel/mpparse.c	Tue Oct  1 00:08:16 2002
+++ b/arch/i386/kernel/mpparse.c	Tue Oct  1 00:08:16 2002
@@ -1038,7 +1038,7 @@
 	status = acpi_get_firmware_table("APIC", 1, ACPI_LOGICAL_ADDRESSING,
 		(acpi_table_header **) &madt);
 	if (ACPI_SUCCESS(status)) {
-		madt_end = madt + madt->header.length;
+		madt_end = (unsigned long)madt + madt->header.length;
 
 		entry = (struct acpi_table_int_src_ovr *)
                 ((unsigned long) madt + sizeof(struct acpi_table_madt));
diff -Nru a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c
--- a/arch/i386/kernel/signal.c	Tue Oct  1 00:08:17 2002
+++ b/arch/i386/kernel/signal.c	Tue Oct  1 00:08:17 2002
@@ -37,11 +37,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->eax = -EINTR;
 	while (1) {
@@ -66,11 +66,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->eax = -EINTR;
 	while (1) {
@@ -224,10 +224,10 @@
 		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 (restore_sigcontext(regs, &frame->sc, &eax))
 		goto badframe;
@@ -252,10 +252,10 @@
 		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 (restore_sigcontext(regs, &frame->uc.uc_mcontext, &eax))
 		goto badframe;
@@ -532,11 +532,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);
 	}
 }
 
diff -Nru a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
--- a/arch/i386/kernel/time.c	Tue Oct  1 00:08:17 2002
+++ b/arch/i386/kernel/time.c	Tue Oct  1 00:08:17 2002
@@ -43,6 +43,7 @@
 #include <linux/smp.h>
 #include <linux/module.h>
 #include <linux/device.h>
+#include <linux/cpufreq.h>
 
 #include <asm/io.h>
 #include <asm/smp.h>
@@ -603,6 +604,52 @@
 
 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
@@ -665,6 +712,9 @@
 	                	"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 */
diff -Nru a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c
--- a/arch/i386/kernel/vm86.c	Tue Oct  1 00:08:15 2002
+++ b/arch/i386/kernel/vm86.c	Tue Oct  1 00:08:15 2002
@@ -440,10 +440,10 @@
 		return 1; /* we let this handle by the calling routine */
 	if (current->ptrace & PT_PTRACED) {
 		unsigned long flags;
-		spin_lock_irqsave(&current->sigmask_lock, flags);
+		spin_lock_irqsave(&current->sig->siglock, flags);
 		sigdelset(&current->blocked, SIGTRAP);
 		recalc_sigpending();
-		spin_unlock_irqrestore(&current->sigmask_lock, flags);
+		spin_unlock_irqrestore(&current->sig->siglock, flags);
 	}
 	send_sig(SIGTRAP, current, 1);
 	current->thread.trap_no = trapno;
diff -Nru a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
--- a/arch/i386/mm/fault.c	Tue Oct  1 00:08:14 2002
+++ b/arch/i386/mm/fault.c	Tue Oct  1 00:08:14 2002
@@ -99,18 +99,14 @@
 	goto bad_area;
 }
 
-extern spinlock_t timerlist_lock;
-
 /*
  * Unlock any spinlocks which will prevent us from getting the
- * message out (timerlist_lock is acquired through the
- * console unblank code)
+ * message out 
  */
 void bust_spinlocks(int yes)
 {
 	int loglevel_save = console_loglevel;
 
-	spin_lock_init(&timerlist_lock);
 	if (yes) {
 		oops_in_progress = 1;
 		return;
diff -Nru a/arch/m68k/atari/stram.c b/arch/m68k/atari/stram.c
--- a/arch/m68k/atari/stram.c	Tue Oct  1 00:08:15 2002
+++ b/arch/m68k/atari/stram.c	Tue Oct  1 00:08:15 2002
@@ -1051,7 +1051,7 @@
 	.first_minor = STRAM_MINOR,
 	.minor_shift = 0,
 	.fops = &stram_fops,
-	.major_name = "stram"
+	.disk_name = "stram"
 };
 
 int __init stram_device_init(void)
diff -Nru a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
--- a/arch/mips/kernel/time.c	Tue Oct  1 00:08:17 2002
+++ b/arch/mips/kernel/time.c	Tue Oct  1 00:08:17 2002
@@ -3,7 +3,7 @@
  * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
  *
  * Common time service routines for MIPS machines. See 
- * Documents/MIPS/README.txt. 
+ * Documentation/mips/time.README. 
  *
  * 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
diff -Nru a/arch/ppc/Makefile b/arch/ppc/Makefile
--- a/arch/ppc/Makefile	Tue Oct  1 00:08:15 2002
+++ b/arch/ppc/Makefile	Tue Oct  1 00:08:15 2002
@@ -53,8 +53,7 @@
   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_MATH_EMULATION)	+= arch/ppc/math-emu/
 core-$(CONFIG_XMON)		+= arch/ppc/xmon/
 core-$(CONFIG_APUS)		+= arch/ppc/amiga/
diff -Nru a/arch/sparc/Makefile b/arch/sparc/Makefile
--- a/arch/sparc/Makefile	Tue Oct  1 00:08:15 2002
+++ b/arch/sparc/Makefile	Tue Oct  1 00:08:15 2002
@@ -31,20 +31,21 @@
 endif
 
 #LDFLAGS_vmlinux = -N -Ttext 0xf0004000
+#  Since 2.5.40, the first stage is left not btfix-ed.
+#  Actual linking is done with "make image".
+LDFLAGS_vmlinux = -r
 
 HEAD := arch/sparc/kernel/head.o arch/sparc/kernel/init_task.o
 
 core-y += arch/sparc/kernel/ arch/sparc/mm/ arch/sparc/math-emu/
 libs-y += arch/sparc/prom/ arch/sparc/lib/
 
-# This one has to come last
-SUBDIRS += arch/sparc/boot
-CORE_FILES_NO_BTFIX := $(addsuffix built-in.o,$(core-y))
-CORE_FILES += arch/sparc/boot/btfix.o
-
 # Export what is needed by arch/sparc/boot/Makefile
-export	CORE_FILES_NO_BTFIX
+export CORE_FILES
 export INIT
+
+image: vmlinux
+	$(MAKE) -C arch/sparc/boot image
 
 archclean:
 	rm -f $(TOPDIR)/vmlinux.aout
diff -Nru a/arch/sparc/boot/Makefile b/arch/sparc/boot/Makefile
--- a/arch/sparc/boot/Makefile	Tue Oct  1 00:08:20 2002
+++ b/arch/sparc/boot/Makefile	Tue Oct  1 00:08:20 2002
@@ -20,25 +20,23 @@
 	$(HOSTCC) $(HOSTCFLAGS) -o btfixupprep btfixupprep.c
 
 clean:
-	rm -f btfixupprep piggyback tftpboot.img btfix.o btfix.s
+	rm -f btfixupprep piggyback tftpboot.img btfix.o btfix.s image
 
-#BTOBJS := $(HEAD) init/main.o init/version.o
 BTOBJS := $(HEAD) $(INIT)
-BTLIBS := $(CORE_FILES_NO_BTFIX) $(LIBS) \
+BTLIBS := $(CORE_FILES) $(LIBS) \
 	$(DRIVERS) $(NETWORKS)
 
-# I wanted to make this depend upon BTOBJS so that a parallel
-# build would work, but this fails because $(HEAD) cannot work
-# properly as it will cause head.o to be built with the implicit
-# rules not the ones in kernel/Makefile.  Someone please fix. --DaveM
-vmlinux.o: FORCE
-	$(LD) $(LDFLAGS) -r $(patsubst %,$(TOPDIR)/%,$(BTOBJS)) \
+# Actual linking
+image: btfix.o
+	$(LD) $(LDFLAGS) -T ../vmlinux.lds.s \
+		$(patsubst %,$(TOPDIR)/%,$(BTOBJS)) \
 		--start-group \
 		$(patsubst %,$(TOPDIR)/%,$(BTLIBS)) \
-		--end-group -o vmlinux.o
+		btfix.o \
+		--end-group -o image
 
-btfix.s: btfixupprep vmlinux.o
-	$(OBJDUMP) -x vmlinux.o | ./btfixupprep > btfix.s
+btfix.s: btfixupprep $(TOPDIR)/vmlinux
+	$(OBJDUMP) -x $(TOPDIR)/vmlinux | ./btfixupprep > btfix.s
 
 btfix.o: btfix.s
 	$(CC) -c -o btfix.o btfix.s
diff -Nru a/arch/sparc/config.in b/arch/sparc/config.in
--- a/arch/sparc/config.in	Tue Oct  1 00:08:15 2002
+++ b/arch/sparc/config.in	Tue Oct  1 00:08:15 2002
@@ -70,7 +70,6 @@
 source drivers/serial/Config.in
 if [ "$CONFIG_SUN4" != "y" ]; then
    source drivers/sbus/char/Config.in
-   source drivers/sbus/audio/Config.in
 fi
 
 mainmenu_option next_comment
@@ -223,9 +222,15 @@
 
 source fs/Config.in
 
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   source net/bluetooth/Config.in
+tristate 'Sound card support' CONFIG_SOUND
+if [ "$CONFIG_SOUND" != "n" ]; then
+   source sound/Config.in
 fi
+endmenu
+
+source drivers/usb/Config.in
+
+source net/bluetooth/Config.in
 
 mainmenu_option next_comment
 comment 'Watchdog'
diff -Nru a/arch/sparc/defconfig b/arch/sparc/defconfig
--- a/arch/sparc/defconfig	Tue Oct  1 00:08:18 2002
+++ b/arch/sparc/defconfig	Tue Oct  1 00:08:18 2002
@@ -105,14 +105,14 @@
 # Misc Linux/SPARC drivers
 #
 CONFIG_SUN_OPENPROMIO=m
-CONFIG_SUN_MOSTEK_RTC=y
+CONFIG_SUN_MOSTEK_RTC=m
 # CONFIG_SUN_BPP is not set
 # CONFIG_SUN_VIDEOPIX is not set
 # CONFIG_SUN_AURORA is not set
 # CONFIG_TADPOLE_TS102_UCTRL is not set
 # CONFIG_SUN_JSFLASH is not set
 CONFIG_APM_RTC_IS_GMT=y
-# CONFIG_RTC is not set
+CONFIG_RTC=m
 
 #
 # Linux/SPARC audio subsystem (EXPERIMENTAL)
@@ -243,6 +243,84 @@
 #
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=m
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_JOYDEV=m
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=m
+CONFIG_INPUT_EVBUG=m
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+# CONFIG_GAMEPORT_NS558 is not set
+# CONFIG_GAMEPORT_L4 is not set
+# CONFIG_GAMEPORT_EMU10K1 is not set
+# CONFIG_GAMEPORT_VORTEX is not set
+# CONFIG_GAMEPORT_FM801 is not set
+# CONFIG_GAMEPORT_CS461x is not set
+CONFIG_SERIO=m
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=m
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PARKBD is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=m
+CONFIG_KEYBOARD_SUNKBD=m
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=m
+CONFIG_MOUSE_SERIAL=m
+# CONFIG_MOUSE_INPORT is not set
+# CONFIG_MOUSE_LOGIBM is not set
+# CONFIG_MOUSE_PC110PAD is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_JOYSTICK_ANALOG is not set
+# CONFIG_JOYSTICK_A3D is not set
+# CONFIG_JOYSTICK_ADI is not set
+# CONFIG_JOYSTICK_COBRA is not set
+# CONFIG_JOYSTICK_GF2K is not set
+# CONFIG_JOYSTICK_GRIP is not set
+# CONFIG_JOYSTICK_GRIP_MP is not set
+# CONFIG_JOYSTICK_GUILLEMOT is not set
+# CONFIG_JOYSTICK_INTERACT is not set
+# CONFIG_JOYSTICK_SIDEWINDER is not set
+# CONFIG_JOYSTICK_TMDC is not set
+# CONFIG_JOYSTICK_IFORCE is not set
+# CONFIG_JOYSTICK_WARRIOR is not set
+# CONFIG_JOYSTICK_MAGELLAN is not set
+# CONFIG_JOYSTICK_SPACEORB is not set
+# CONFIG_JOYSTICK_SPACEBALL is not set
+# CONFIG_JOYSTICK_STINGER is not set
+# CONFIG_JOYSTICK_TWIDDLER is not set
+# CONFIG_JOYSTICK_DB9 is not set
+# CONFIG_JOYSTICK_GAMECON is not set
+# CONFIG_JOYSTICK_TURBOGRAFX is not set
+# CONFIG_INPUT_JOYDUMP is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_INPUT_MISC is not set
+# CONFIG_INPUT_PCSPKR is not set
+# CONFIG_INPUT_SPARCSPKR is not set
+# CONFIG_INPUT_UINPUT is not set
 
 #
 # File systems
diff -Nru a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
--- a/arch/sparc/kernel/irq.c	Tue Oct  1 00:08:15 2002
+++ b/arch/sparc/kernel/irq.c	Tue Oct  1 00:08:15 2002
@@ -75,7 +75,7 @@
     prom_halt();
 }
 
-void (*init_timers)(void (*)(int, void *,struct pt_regs *)) =
+void (*sparc_init_timers)(void (*)(int, void *,struct pt_regs *)) =
     (void (*)(void (*)(int, void *,struct pt_regs *))) irq_panic;
 
 /*
diff -Nru a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c
--- a/arch/sparc/kernel/signal.c	Tue Oct  1 00:08:18 2002
+++ b/arch/sparc/kernel/signal.c	Tue Oct  1 00:08:18 2002
@@ -136,11 +136,11 @@
 	sigset_t saveset;
 
 	set &= _BLOCKABLE;
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	saveset = current->blocked;
 	siginitset(&current->blocked, set);
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	regs->pc = regs->npc;
 	regs->npc += 4;
@@ -193,11 +193,11 @@
 	}
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	oldset = current->blocked;
 	current->blocked = set;
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	regs->pc = regs->npc;
 	regs->npc += 4;
@@ -299,10 +299,10 @@
 		goto segv_and_exit;
 
 	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);
 	return;
 
 segv_and_exit:
@@ -346,10 +346,10 @@
 		goto segv_and_exit;
 
 	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);
 
 	regs->pc = pc;
 	regs->npc = npc;
@@ -416,10 +416,10 @@
 	do_sigaltstack(&st, NULL, (unsigned long)sf);
 
 	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);
 	return;
 segv:
 	send_sig(SIGSEGV, current, 1);
@@ -999,10 +999,10 @@
 		set.sig[3] = setv.sigbits[3];
 	}
 	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);
 	regs->pc = pc;
 	regs->npc = npc | 1;
 	err |= __get_user(regs->y, &((*gr) [SVR4_Y]));
@@ -1039,11 +1039,11 @@
 	if(ka->sa.sa_flags & SA_ONESHOT)
 		ka->sa.sa_handler = SIG_DFL;
 	if(!(ka->sa.sa_flags & SA_NOMASK)) {
-		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);
 	}
 }
 
@@ -1102,9 +1102,9 @@
 			spin_unlock(&current->sig->siglock);
 		}
 		if (!signr) {
-			spin_lock(&current->sigmask_lock);
+			spin_lock(&current->sig->siglock);
 			signr = dequeue_signal(&current->pending, mask, &info);
-			spin_unlock(&current->sigmask_lock);
+			spin_unlock(&current->sig->siglock);
 		}
 		local_irq_enable();
 
diff -Nru a/arch/sparc/kernel/sun4c_irq.c b/arch/sparc/kernel/sun4c_irq.c
--- a/arch/sparc/kernel/sun4c_irq.c	Tue Oct  1 00:08:15 2002
+++ b/arch/sparc/kernel/sun4c_irq.c	Tue Oct  1 00:08:15 2002
@@ -221,7 +221,7 @@
 	BTFIXUPSET_CALL(clear_profile_irq, sun4c_clear_profile_irq, BTFIXUPCALL_NOP);
 	BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP);
 	BTFIXUPSET_CALL(__irq_itoa, sun4m_irq_itoa, BTFIXUPCALL_NORM);
-	init_timers = sun4c_init_timers;
+	sparc_init_timers = sun4c_init_timers;
 #ifdef CONFIG_SMP
 	BTFIXUPSET_CALL(set_cpu_int, sun4c_nop, BTFIXUPCALL_NOP);
 	BTFIXUPSET_CALL(clear_cpu_int, sun4c_nop, BTFIXUPCALL_NOP);
diff -Nru a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c
--- a/arch/sparc/kernel/sun4m_irq.c	Tue Oct  1 00:08:17 2002
+++ b/arch/sparc/kernel/sun4m_irq.c	Tue Oct  1 00:08:17 2002
@@ -374,7 +374,7 @@
 	BTFIXUPSET_CALL(clear_profile_irq, sun4m_clear_profile_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(__irq_itoa, sun4m_irq_itoa, BTFIXUPCALL_NORM);
-	init_timers = sun4m_init_timers;
+	sparc_init_timers = sun4m_init_timers;
 #ifdef CONFIG_SMP
 	BTFIXUPSET_CALL(set_cpu_int, sun4m_send_ipi, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM);
diff -Nru a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c
--- a/arch/sparc/kernel/sys_sunos.c	Tue Oct  1 00:08:17 2002
+++ b/arch/sparc/kernel/sys_sunos.c	Tue Oct  1 00:08:17 2002
@@ -279,11 +279,11 @@
 {
 	unsigned long old;
 
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	old = current->blocked.sig[0];
 	current->blocked.sig[0] |= (blk_mask & _BLOCKABLE);
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 	return old;
 }
 
@@ -291,11 +291,11 @@
 {
 	unsigned long retval;
 
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	retval = current->blocked.sig[0];
 	current->blocked.sig[0] = (newmask & _BLOCKABLE);
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 	return retval;
 }
 
diff -Nru a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c
--- a/arch/sparc/kernel/time.c	Tue Oct  1 00:08:17 2002
+++ b/arch/sparc/kernel/time.c	Tue Oct  1 00:08:17 2002
@@ -386,7 +386,7 @@
 	else
 		clock_probe();
 
-	init_timers(timer_interrupt);
+	sparc_init_timers(timer_interrupt);
 	
 #ifdef CONFIG_SUN4
 	if(idprom->id_machtype == (SM_SUN4 | SM_4_330)) {
diff -Nru a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
--- a/arch/sparc/mm/srmmu.c	Tue Oct  1 00:08:17 2002
+++ b/arch/sparc/mm/srmmu.c	Tue Oct  1 00:08:17 2002
@@ -387,13 +387,13 @@
 	int offset;
 
 	if (vaddr < SRMMU_NOCACHE_VADDR) {
-		printk("Vaddr %x is smaller than nocache base 0x%x\n",
-		    vaddr, SRMMU_NOCACHE_VADDR);
+		printk("Vaddr %lx is smaller than nocache base 0x%lx\n",
+		    vaddr, (unsigned long)SRMMU_NOCACHE_VADDR);
 		BUG();
 	}
 	if (vaddr >= SRMMU_NOCACHE_END) {
-		printk("Vaddr %x is bigger than nocache end 0x%x\n",
-		    vaddr, SRMMU_NOCACHE_END);
+		printk("Vaddr %lx is bigger than nocache end 0x%lx\n",
+		    vaddr, (unsigned long)SRMMU_NOCACHE_END);
 		BUG();
 	}
 	if (size & (size-1)) {
@@ -405,7 +405,7 @@
 		BUG();
 	}
 	if (vaddr & (size-1)) {
-		printk("Vaddr 0x%x is not aligned to size 0x%x\n", vaddr, size);
+		printk("Vaddr %lx is not aligned to size 0x%x\n", vaddr, size);
 		BUG();
 	}
 
@@ -1173,7 +1173,7 @@
 			 */
 			unsigned int x;	/* Index of HW PMD in soft cluster */
 			x = (start >> SRMMU_PMD_SHIFT) & 15;
-			*(ulong *)__nocache_fix(&pmdp->pmdv[x]) = prompte;
+			*(unsigned long *)__nocache_fix(&pmdp->pmdv[x]) = prompte;
 			start += SRMMU_PMD_SIZE;
 			continue;
 		}
diff -Nru a/arch/sparc64/config.in b/arch/sparc64/config.in
--- a/arch/sparc64/config.in	Tue Oct  1 00:08:16 2002
+++ b/arch/sparc64/config.in	Tue Oct  1 00:08:16 2002
@@ -78,7 +78,6 @@
 
 source drivers/serial/Config.in
 source drivers/sbus/char/Config.in
-source drivers/sbus/audio/Config.in
 source drivers/mtd/Config.in
 mainmenu_option next_comment
 comment 'Block devices'
diff -Nru a/arch/sparc64/defconfig b/arch/sparc64/defconfig
--- a/arch/sparc64/defconfig	Tue Oct  1 00:08:16 2002
+++ b/arch/sparc64/defconfig	Tue Oct  1 00:08:16 2002
@@ -160,13 +160,6 @@
 CONFIG_SUN_AURORA=m
 
 #
-# Linux/SPARC audio subsystem (EXPERIMENTAL)
-#
-CONFIG_SPARCAUDIO=m
-CONFIG_SPARCAUDIO_CS4231=m
-# CONFIG_SPARCAUDIO_DUMMY is not set
-
-#
 # Memory Technology Devices (MTD)
 #
 # CONFIG_MTD is not set
@@ -497,6 +490,7 @@
 CONFIG_SIS900=m
 CONFIG_EPIC100=m
 CONFIG_SUNDANCE=m
+CONFIG_SUNDANCE_MMIO=y
 # CONFIG_TLAN is not set
 CONFIG_VIA_RHINE=m
 # CONFIG_VIA_RHINE_MMIO is not set
@@ -842,7 +836,64 @@
 #
 # Advanced Linux Sound Architecture
 #
-# CONFIG_SND is not set
+CONFIG_SND=m
+CONFIG_SND_BIT32_EMUL=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_SEQUENCER_OSS=y
+# CONFIG_SND_RTCTIMER is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+# CONFIG_SND_DEBUG_MEMORY is not set
+# CONFIG_SND_DEBUG_DETECT is not set
+
+#
+# Generic devices
+#
+CONFIG_SND_DUMMY=m
+CONFIG_SND_VIRMIDI=m
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# PCI devices
+#
+CONFIG_SND_ALI5451=m
+CONFIG_SND_CS46XX=m
+CONFIG_SND_CS46XX_ACCEPT_VALID=y
+CONFIG_SND_CS4281=m
+CONFIG_SND_EMU10K1=m
+CONFIG_SND_KORG1212=m
+CONFIG_SND_NM256=m
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_HDSP is not set
+CONFIG_SND_TRIDENT=m
+CONFIG_SND_YMFPCI=m
+CONFIG_SND_ALS4000=m
+CONFIG_SND_CMIPCI=m
+CONFIG_SND_ENS1370=m
+CONFIG_SND_ENS1371=m
+CONFIG_SND_ES1938=m
+CONFIG_SND_ES1968=m
+CONFIG_SND_MAESTRO3=m
+CONFIG_SND_FM801=m
+CONFIG_SND_ICE1712=m
+CONFIG_SND_INTEL8X0=m
+CONFIG_SND_SONICVIBES=m
+CONFIG_SND_VIA686=m
+CONFIG_SND_VIA8233=m
+
+#
+# ALSA Sparc devices
+#
+CONFIG_SND_SUN_AMD7930=m
+CONFIG_SND_SUN_CS4231=m
 
 #
 # USB support
diff -Nru a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
--- a/arch/sparc64/kernel/Makefile	Tue Oct  1 00:08:15 2002
+++ b/arch/sparc64/kernel/Makefile	Tue Oct  1 00:08:15 2002
@@ -8,7 +8,7 @@
 
 EXTRA_TARGETS	:= head.o init_task.o
 
-export-objs	:= sparc64_ksyms.o
+export-objs	:= sparc64_ksyms.o ebus.o
 obj-y		:= process.o setup.o cpu.o idprom.o \
 		   traps.o devices.o auxio.o \
 		   irq.o ptrace.o time.o sys_sparc.o signal.o \
diff -Nru a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
--- a/arch/sparc64/kernel/ebus.c	Tue Oct  1 00:08:16 2002
+++ b/arch/sparc64/kernel/ebus.c	Tue Oct  1 00:08:16 2002
@@ -6,6 +6,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/init.h>
@@ -19,6 +20,220 @@
 #include <asm/oplib.h>
 #include <asm/bpp.h>
 #include <asm/irq.h>
+
+/* EBUS dma library. */
+
+#define EBDMA_CSR	0x00UL	/* Control/Status */
+#define EBDMA_ADDR	0x04UL	/* DMA Address */
+#define EBDMA_COUNT	0x08UL	/* DMA Count */
+
+#define EBDMA_CSR_INT_PEND	0x00000001
+#define EBDMA_CSR_ERR_PEND	0x00000002
+#define EBDMA_CSR_DRAIN		0x00000004
+#define EBDMA_CSR_INT_EN	0x00000010
+#define EBDMA_CSR_RESET		0x00000080
+#define EBDMA_CSR_WRITE		0x00000100
+#define EBDMA_CSR_EN_DMA	0x00000200
+#define EBDMA_CSR_CYC_PEND	0x00000400
+#define EBDMA_CSR_DIAG_RD_DONE	0x00000800
+#define EBDMA_CSR_DIAG_WR_DONE	0x00001000
+#define EBDMA_CSR_EN_CNT	0x00002000
+#define EBDMA_CSR_TC		0x00004000
+#define EBDMA_CSR_DIS_CSR_DRN	0x00010000
+#define EBDMA_CSR_BURST_SZ_MASK	0x000c0000
+#define EBDMA_CSR_BURST_SZ_1	0x00080000
+#define EBDMA_CSR_BURST_SZ_4	0x00000000
+#define EBDMA_CSR_BURST_SZ_8	0x00040000
+#define EBDMA_CSR_BURST_SZ_16	0x000c0000
+#define EBDMA_CSR_DIAG_EN	0x00100000
+#define EBDMA_CSR_DIS_ERR_PEND	0x00400000
+#define EBDMA_CSR_TCI_DIS	0x00800000
+#define EBDMA_CSR_EN_NEXT	0x01000000
+#define EBDMA_CSR_DMA_ON	0x02000000
+#define EBDMA_CSR_A_LOADED	0x04000000
+#define EBDMA_CSR_NA_LOADED	0x08000000
+#define EBDMA_CSR_DEV_ID_MASK	0xf0000000
+
+#define EBUS_DMA_RESET_TIMEOUT	10000
+
+static void __ebus_dma_reset(struct ebus_dma_info *p)
+{
+	int i;
+	u32 val = 0;
+
+	writel(EBDMA_CSR_RESET, p->regs + EBDMA_CSR);
+
+	for (i = EBUS_DMA_RESET_TIMEOUT; i > 0; i--) {
+		val = readl(p->regs + EBDMA_CSR);
+
+		if (!(val & (EBDMA_CSR_DRAIN | EBDMA_CSR_CYC_PEND)))
+			break;
+		udelay(10);
+	}
+}
+
+static void ebus_dma_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct ebus_dma_info *p = dev_id;
+	unsigned long flags;
+	u32 csr;
+
+	spin_lock_irqsave(&p->lock, flags);
+	csr = readl(p->regs + EBDMA_CSR);
+	writel(csr, p->regs + EBDMA_CSR);
+	spin_unlock_irqrestore(&p->lock, flags);
+
+	if (csr & EBDMA_CSR_ERR_PEND) {
+		printk(KERN_CRIT "ebus_dma(%s): DMA error!\n", p->name);
+		p->callback(p, EBUS_DMA_EVENT_ERROR, p->client_cookie);
+	} else if (csr & EBDMA_CSR_INT_PEND) {
+		p->callback(p,
+			    (csr & EBDMA_CSR_TC) ?
+			    EBUS_DMA_EVENT_DMA : EBUS_DMA_EVENT_DEVICE,
+			    p->client_cookie);
+	}
+}
+
+int ebus_dma_register(struct ebus_dma_info *p)
+{
+	if (!p->regs)
+		return -EINVAL;
+	if (p->flags & ~(EBUS_DMA_FLAG_USE_EBDMA_HANDLER))
+		return -EINVAL;
+	if ((p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) && !p->callback)
+		return -EINVAL;
+	if (!strlen(p->name))
+		return -EINVAL;
+
+	__ebus_dma_reset(p);
+
+	return 0;
+}
+EXPORT_SYMBOL(ebus_dma_register);
+
+int ebus_dma_irq_enable(struct ebus_dma_info *p, int on)
+{
+	unsigned long flags;
+	u32 csr;
+
+	if (on) {
+		if (p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) {
+			if (request_irq(p->irq, ebus_dma_irq, SA_SHIRQ, p->name, p))
+				return -EBUSY;
+		}
+
+		spin_lock_irqsave(&p->lock, flags);
+		csr = readl(p->regs + EBDMA_CSR);
+		csr |= EBDMA_CSR_INT_EN;
+		writel(csr, p->regs + EBDMA_CSR);
+		spin_unlock_irqrestore(&p->lock, flags);
+	} else {
+		spin_lock_irqsave(&p->lock, flags);
+		csr = readl(p->regs + EBDMA_CSR);
+		csr &= ~EBDMA_CSR_INT_EN;
+		writel(csr, p->regs + EBDMA_CSR);
+		spin_unlock_irqrestore(&p->lock, flags);
+
+		if (p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) {
+			free_irq(p->irq, p);
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(ebus_dma_irq_enable);
+
+void ebus_dma_unregister(struct ebus_dma_info *p)
+{
+	unsigned long flags;
+	u32 csr;
+	int irq_on = 0;
+
+	spin_lock_irqsave(&p->lock, flags);
+	csr = readl(p->regs + EBDMA_CSR);
+	if (csr & EBDMA_CSR_INT_EN) {
+		csr &= ~EBDMA_CSR_INT_EN;
+		writel(csr, p->regs + EBDMA_CSR);
+		irq_on = 1;
+	}
+	spin_unlock_irqrestore(&p->lock, flags);
+
+	if (irq_on)
+		free_irq(p->irq, p);
+}
+EXPORT_SYMBOL(ebus_dma_unregister);
+
+int ebus_dma_request(struct ebus_dma_info *p, dma_addr_t bus_addr, size_t len)
+{
+	unsigned long flags;
+	u32 csr;
+	int err;
+
+	if (len >= (1 << 24))
+		return -EINVAL;
+
+	spin_lock_irqsave(&p->lock, flags);
+	csr = readl(p->regs + EBDMA_CSR);
+	err = -EINVAL;
+	if (!(csr & EBDMA_CSR_EN_DMA))
+		goto out;
+	err = -EBUSY;
+	if (csr & EBDMA_CSR_NA_LOADED)
+		goto out;
+
+	writel(len,      p->regs + EBDMA_COUNT);
+	writel(bus_addr, p->regs + EBDMA_ADDR);
+	err = 0;
+
+out:
+	spin_unlock_irqrestore(&p->lock, flags);
+
+	return err;
+}
+EXPORT_SYMBOL(ebus_dma_request);
+
+void ebus_dma_prepare(struct ebus_dma_info *p, int write)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&p->lock, flags);
+	__ebus_dma_reset(p);
+	writel(EBDMA_CSR_INT_EN |
+	       ((write) ? EBDMA_CSR_WRITE : 0) |
+	       EBDMA_CSR_EN_CNT |
+	       EBDMA_CSR_BURST_SZ_16 |
+	       EBDMA_CSR_EN_NEXT, p->regs + EBDMA_CSR);
+	spin_unlock_irqrestore(&p->lock, flags);
+}
+EXPORT_SYMBOL(ebus_dma_prepare);
+
+unsigned int ebus_dma_residue(struct ebus_dma_info *p)
+{
+	return readl(p->regs + EBDMA_COUNT);
+}
+EXPORT_SYMBOL(ebus_dma_residue);
+
+unsigned int ebus_dma_addr(struct ebus_dma_info *p)
+{
+	return readl(p->regs + EBDMA_ADDR);
+}
+EXPORT_SYMBOL(ebus_dma_addr);
+
+void ebus_dma_enable(struct ebus_dma_info *p, int on)
+{
+	unsigned long flags;
+	u32 csr;
+
+	spin_lock_irqsave(&p->lock, flags);
+	csr = readl(p->regs + EBDMA_CSR);
+	if (on)
+		csr |= EBDMA_CSR_EN_DMA;
+	else
+		csr &= ~EBDMA_CSR_EN_DMA;
+	writel(csr, p->regs + EBDMA_CSR);
+	spin_unlock_irqrestore(&p->lock, flags);
+}
+EXPORT_SYMBOL(ebus_dma_enable);
 
 struct linux_ebus *ebus_chain = 0;
 
diff -Nru a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
--- a/arch/sparc64/kernel/irq.c	Tue Oct  1 00:08:16 2002
+++ b/arch/sparc64/kernel/irq.c	Tue Oct  1 00:08:16 2002
@@ -950,8 +950,8 @@
 }
 
 /* This is gets the master TICK_INT timer going. */
-void init_timers(void (*cfunc)(int, void *, struct pt_regs *),
-		 unsigned long *clock)
+void sparc64_init_timers(void (*cfunc)(int, void *, struct pt_regs *),
+			 unsigned long *clock)
 {
 	unsigned long pstate;
 	extern unsigned long timer_tick_offset;
diff -Nru a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c
--- a/arch/sparc64/kernel/pci_schizo.c	Tue Oct  1 00:08:18 2002
+++ b/arch/sparc64/kernel/pci_schizo.c	Tue Oct  1 00:08:18 2002
@@ -1071,7 +1071,7 @@
 	u64 tmp;
 
 	/* Build IRQs and register handlers. */
-	irq = schizo_irq_build(pbm_a, NULL, (portid << 6) | SCHIZO_UE_INO);
+	irq = schizo_irq_build(pbm_b, NULL, (portid << 6) | SCHIZO_UE_INO);
 	if (request_irq(irq, schizo_ue_intr,
 			SA_SHIRQ, "SCHIZO UE", p) < 0) {
 		prom_printf("SCHIZO%d: Cannot register UE interrupt.\n",
@@ -1082,7 +1082,7 @@
 	tmp = readl(bucket->imap);
 	upa_writel(tmp, (base + SCHIZO_PBM_B_REGS_OFF + schizo_imap_offset(SCHIZO_UE_INO) + 4));
 
-	irq = schizo_irq_build(pbm_a, NULL, (portid << 6) | SCHIZO_CE_INO);
+	irq = schizo_irq_build(pbm_b, NULL, (portid << 6) | SCHIZO_CE_INO);
 	if (request_irq(irq, schizo_ce_intr,
 			SA_SHIRQ, "SCHIZO CE", p) < 0) {
 		prom_printf("SCHIZO%d: Cannot register CE interrupt.\n",
@@ -1102,9 +1102,9 @@
 	}
 	bucket = __bucket(irq);
 	tmp = upa_readl(bucket->imap);
-	upa_writel(tmp, (base + SCHIZO_PBM_B_REGS_OFF + schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4));
+	upa_writel(tmp, (base + SCHIZO_PBM_A_REGS_OFF + schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4));
 
-	irq = schizo_irq_build(pbm_a, NULL, (portid << 6) | SCHIZO_PCIERR_B_INO);
+	irq = schizo_irq_build(pbm_b, NULL, (portid << 6) | SCHIZO_PCIERR_B_INO);
 	if (request_irq(irq, schizo_pcierr_intr,
 			SA_SHIRQ, "SCHIZO PCIERR", pbm_b) < 0) {
 		prom_printf("SCHIZO%d(PBMB): Cannot register PciERR interrupt.\n",
@@ -1115,7 +1115,7 @@
 	tmp = upa_readl(bucket->imap);
 	upa_writel(tmp, (base + SCHIZO_PBM_B_REGS_OFF + schizo_imap_offset(SCHIZO_PCIERR_B_INO) + 4));
 
-	irq = schizo_irq_build(pbm_a, NULL, (portid << 6) | SCHIZO_SERR_INO);
+	irq = schizo_irq_build(pbm_b, NULL, (portid << 6) | SCHIZO_SERR_INO);
 	if (request_irq(irq, schizo_safarierr_intr,
 			SA_SHIRQ, "SCHIZO SERR", p) < 0) {
 		prom_printf("SCHIZO%d(PBMB): Cannot register SafariERR interrupt.\n",
diff -Nru a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c
--- a/arch/sparc64/kernel/power.c	Tue Oct  1 00:08:19 2002
+++ b/arch/sparc64/kernel/power.c	Tue Oct  1 00:08:19 2002
@@ -69,9 +69,9 @@
 
 again:
 	while (button_pressed == 0) {
-		spin_lock_irq(&current->sigmask_lock);
+		spin_lock_irq(&current->sig->siglock);
 		flush_signals(current);
-		spin_unlock_irq(&current->sigmask_lock);
+		spin_unlock_irq(&current->sig->siglock);
 		interruptible_sleep_on(&powerd_wait);
 	}
 
diff -Nru a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
--- a/arch/sparc64/kernel/signal.c	Tue Oct  1 00:08:17 2002
+++ b/arch/sparc64/kernel/signal.c	Tue Oct  1 00:08:17 2002
@@ -99,10 +99,10 @@
 				goto do_sigsegv;
 		}
 		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 (test_thread_flag(TIF_32BIT)) {
 		pc &= 0xffffffff;
@@ -286,11 +286,11 @@
 	}
 #endif
 	set &= _BLOCKABLE;
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	saveset = current->blocked;
 	siginitset(&current->blocked, set);
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 	
 	if (test_thread_flag(TIF_32BIT)) {
 		regs->tpc = (regs->tnpc & 0xffffffff);
@@ -346,11 +346,11 @@
 	}
                                                                 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	oldset = current->blocked;
 	current->blocked = set;
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 	
 	if (test_thread_flag(TIF_32BIT)) {
 		regs->tpc = (regs->tnpc & 0xffffffff);
@@ -457,10 +457,10 @@
 	set_fs(old_fs);
 
 	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);
 	return;
 segv:
 	send_sig(SIGSEGV, current, 1);
@@ -593,11 +593,11 @@
 	if (ka->sa.sa_flags & SA_ONESHOT)
 		ka->sa.sa_handler = SIG_DFL;
 	if (!(ka->sa.sa_flags & SA_NOMASK)) {
-		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);
 	}
 }
 
@@ -652,9 +652,9 @@
 			spin_unlock(&current->sig->siglock);
 		}
 		if (!signr) {
-			spin_lock(&current->sigmask_lock);
+			spin_lock(&current->sig->siglock);
 			signr = dequeue_signal(&current->pending, mask, &info);
-			spin_unlock(&current->sigmask_lock);
+			spin_unlock(&current->sig->siglock);
 		}
 		local_irq_enable();
 		
diff -Nru a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
--- a/arch/sparc64/kernel/signal32.c	Tue Oct  1 00:08:13 2002
+++ b/arch/sparc64/kernel/signal32.c	Tue Oct  1 00:08:13 2002
@@ -143,11 +143,11 @@
 	sigset_t saveset;
 
 	set &= _BLOCKABLE;
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	saveset = current->blocked;
 	siginitset(&current->blocked, set);
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 	
 	regs->tpc = regs->tnpc;
 	regs->tnpc += 4;
@@ -198,11 +198,11 @@
 	case 1: set.sig[0] = set32.sig[0] + (((long)set32.sig[1]) << 32);
 	}
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	oldset = current->blocked;
 	current->blocked = set;
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 	
 	regs->tpc = regs->tnpc;
 	regs->tnpc += 4;
@@ -311,10 +311,10 @@
 		case 1: set.sig[0] = seta[0] + (((long)seta[1]) << 32);
 	}
 	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);
 	return;
 
 segv:
@@ -358,10 +358,10 @@
 		case 1: set.sig[0] = seta[0] + (((long)seta[1]) << 32);
 	}
 	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 (test_thread_flag(TIF_32BIT)) {
 		pc &= 0xffffffff;
@@ -460,10 +460,10 @@
 		case 1: set.sig[0] = seta.sig[0] + (((long)seta.sig[1]) << 32);
 	}
 	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);
 	return;
 segv:
 	do_exit(SIGSEGV);
@@ -1058,10 +1058,10 @@
 	set_fs(old_fs);
 	
 	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);
 	regs->tpc = pc;
 	regs->tnpc = npc | 1;
 	if (test_thread_flag(TIF_32BIT)) {
@@ -1240,11 +1240,11 @@
 	if (ka->sa.sa_flags & SA_ONESHOT)
 		ka->sa.sa_handler = SIG_DFL;
 	if (!(ka->sa.sa_flags & SA_NOMASK)) {
-		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);
 	}
 }
 
@@ -1291,9 +1291,9 @@
 			spin_unlock(&current->sig->siglock);
 		}
 		if (!signr) {
-			spin_lock(&current->sigmask_lock);
+			spin_lock(&current->sig->siglock);
 			signr = dequeue_signal(&current->pending, mask, &info);
-			spin_unlock(&current->sigmask_lock);
+			spin_unlock(&current->sig->siglock);
 		}
 		local_irq_enable();
 		
diff -Nru a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
--- a/arch/sparc64/kernel/sys_sparc32.c	Tue Oct  1 00:08:18 2002
+++ b/arch/sparc64/kernel/sys_sparc32.c	Tue Oct  1 00:08:18 2002
@@ -1972,7 +1972,7 @@
 	}
 
 	spin_lock_irq(&current->sig->siglock);
-	spin_lock(&current->sigmask_lock);
+	spin_lock(&current->sig->siglock);
 	sig = dequeue_signal(&current->sig->shared_pending, &these, &info);
 	if (!sig)
 		sig = dequeue_signal(&current->pending, &these, &info);
@@ -1989,14 +1989,14 @@
 			current->real_blocked = current->blocked;
 			sigandsets(&current->blocked, &current->blocked, &these);
 			recalc_sigpending();
-			spin_unlock(&current->sigmask_lock);
+			spin_unlock(&current->sig->siglock);
 			spin_unlock_irq(&current->sig->siglock);
 
 			current->state = TASK_INTERRUPTIBLE;
 			timeout = schedule_timeout(timeout);
 
 			spin_lock_irq(&current->sig->siglock);
-			spin_lock(&current->sigmask_lock);
+			spin_lock(&current->sig->siglock);
 			sig = dequeue_signal(&current->sig->shared_pending, &these, &info);
 			if (!sig)
 				sig = dequeue_signal(&current->pending, &these, &info);
@@ -2005,7 +2005,7 @@
 			recalc_sigpending();
 		}
 	}
-	spin_unlock(&current->sigmask_lock);
+	spin_unlock(&current->sig->siglock);
 	spin_unlock_irq(&current->sig->siglock);
 
 	if (sig) {
diff -Nru a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c
--- a/arch/sparc64/kernel/sys_sunos32.c	Tue Oct  1 00:08:17 2002
+++ b/arch/sparc64/kernel/sys_sunos32.c	Tue Oct  1 00:08:17 2002
@@ -234,11 +234,11 @@
 {
 	u32 old;
 
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	old = (u32) current->blocked.sig[0];
 	current->blocked.sig[0] |= (blk_mask & _BLOCKABLE);
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 	return old;
 }
 
@@ -246,11 +246,11 @@
 {
 	u32 retval;
 
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	retval = (u32) current->blocked.sig[0];
 	current->blocked.sig[0] = (newmask & _BLOCKABLE);
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 	return retval;
 }
 
diff -Nru a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
--- a/arch/sparc64/kernel/time.c	Tue Oct  1 00:08:17 2002
+++ b/arch/sparc64/kernel/time.c	Tue Oct  1 00:08:17 2002
@@ -617,9 +617,6 @@
 	local_irq_restore(flags);
 }
 
-extern void init_timers(void (*func)(int, void *, struct pt_regs *),
-			unsigned long *);
-
 void __init time_init(void)
 {
 	/* clock_probe() is now done at end of [se]bus_init on sparc64
@@ -628,7 +625,7 @@
 	 */
 	unsigned long clock;
 
-	init_timers(timer_interrupt, &clock);
+	sparc64_init_timers(timer_interrupt, &clock);
 	timer_ticks_per_usec_quotient = ((1UL<<32) / (clock / 1000020));
 }
 
diff -Nru a/arch/sparc64/solaris/signal.c b/arch/sparc64/solaris/signal.c
--- a/arch/sparc64/solaris/signal.c	Tue Oct  1 00:08:22 2002
+++ b/arch/sparc64/solaris/signal.c	Tue Oct  1 00:08:22 2002
@@ -99,16 +99,16 @@
 static long solaris_sigset(int sig, u32 arg)
 {
 	if (arg != 2) /* HOLD */ {
-		spin_lock_irq(&current->sigmask_lock);
+		spin_lock_irq(&current->sig->siglock);
 		sigdelsetmask(&current->blocked, _S(sig));
 		recalc_sigpending();
-		spin_unlock_irq(&current->sigmask_lock);
+		spin_unlock_irq(&current->sig->siglock);
 		return sig_handler (sig, arg, 0);
 	} else {
-		spin_lock_irq(&current->sigmask_lock);
+		spin_lock_irq(&current->sig->siglock);
 		sigaddsetmask(&current->blocked, (_S(sig) & ~_BLOCKABLE));
 		recalc_sigpending();
-		spin_unlock_irq(&current->sigmask_lock);
+		spin_unlock_irq(&current->sig->siglock);
 		return 0;
 	}
 }
@@ -120,10 +120,10 @@
 
 static inline long solaris_sigrelse(int sig)
 {
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	sigdelsetmask(&current->blocked, _S(sig));
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 	return 0;
 }
 
@@ -311,10 +311,10 @@
 	u32 tmp[4];
 	switch (which) {
 	case 1: /* sigpending */
-		spin_lock_irq(&current->sigmask_lock);
+		spin_lock_irq(&current->sig->siglock);
 		sigandsets(&s, &current->blocked, &current->pending.signal);
 		recalc_sigpending();
-		spin_unlock_irq(&current->sigmask_lock);
+		spin_unlock_irq(&current->sig->siglock);
 		break;
 	case 2: /* sigfillset - I just set signals which have linux equivalents */
 		sigfillset(&s);
diff -Nru a/arch/um/Makefile b/arch/um/Makefile
--- a/arch/um/Makefile	Tue Oct  1 00:08:15 2002
+++ b/arch/um/Makefile	Tue Oct  1 00:08:15 2002
@@ -36,9 +36,8 @@
 SUBDIRS += $(ARCH_SUBDIRS)
 
 core-y			+= $(ARCH_DIR)/kernel/		 \
-			+= $(ARCH_DIR)/drivers/          \
-			+= $(ARCH_DIR)/sys-$(SUBARCH)/	 \
-			+= $(ARCH_DIR)/os-$(OS)/
+			   $(ARCH_DIR)/drivers/          \
+			   $(ARCH_DIR)/sys-$(SUBARCH)/
 
 libs-$(CONFIG_PT_PROXY)	+= $(ARCH_DIR)/ptproxy/
 
@@ -53,15 +52,17 @@
 	-DSUBARCH=\"$(SUBARCH)\" -D_LARGEFILE64_SOURCE -I$(ARCH_INCLUDE) \
 	-Derrno=kernel_errno
 
-LDFLAGS += -r
-
 LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
 
 SIZE = (($(CONFIG_NEST_LEVEL) + $(CONFIG_KERNEL_HALF_GIGS)) * 0x20000000)
 
-$(ARCH_DIR)/link.ld: $(ARCH_DIR)/link.ld.in
-	m4 -DSTART=$$(($(TOP_ADDR) - $(SIZE))) -DELF_ARCH=$(ELF_ARCH) \
-		-DELF_FORMAT=$(ELF_FORMAT) $< > $@
+$(ARCH_DIR)/uml.lds.s : $(ARCH_DIR)/uml.lds.S
+	$(call if_changed_dep,as_s_S)
+
+AFLAGS_uml.lds.o = -U$(SUBARCH) -DSTART=$$(($(TOP_ADDR) - $(SIZE))) \
+	-DELF_ARCH=$(ELF_ARCH) -DELF_FORMAT=\"$(ELF_FORMAT)\" -P -C -Uum
+
+LDFLAGS_vmlinux = -r $(ARCH_DIR)/main.o
 
 SYMLINK_HEADERS = include/asm-um/archparam.h include/asm-um/system.h \
 	include/asm-um/sigcontext.h include/asm-um/processor.h \
@@ -72,11 +73,13 @@
 
 GEN_HEADERS = $(ARCH_DIR)/include/task.h
 
-linux: scripts $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS) $(ARCH_DIR)/main.o \
-	vmlinux $(ARCH_DIR)/link.ld
-	mv vmlinux vmlinux.o
-	$(CC) -Wl,-T,$(ARCH_DIR)/link.ld $(LINK_PROFILE) $(LINK_WRAPS) \
-		-o linux -static $(ARCH_DIR)/main.o vmlinux.o -L/usr/lib -lutil
+$(ARCH_DIR)/vmlinux.lds.S :
+	touch $@
+
+linux: scripts $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS) \
+	arch/um/uml.lds.s $(ARCH_DIR)/main.o vmlinux
+	$(CC) -Wl,-T,arch/um/uml.lds.s -o $@ $(LINK_PROFILE) \
+	$(LINK_WRAPS) -static vmlinux -L/usr/lib -lutil
 
 USER_CFLAGS := $(patsubst -I%,,$(CFLAGS))
 USER_CFLAGS := $(patsubst -Derrno=kernel_errno,,$(USER_CFLAGS))
diff -Nru a/arch/um/Makefile-os-Linux b/arch/um/Makefile-os-Linux
--- a/arch/um/Makefile-os-Linux	Tue Oct  1 00:08:17 2002
+++ b/arch/um/Makefile-os-Linux	Tue Oct  1 00:08:17 2002
@@ -3,5 +3,4 @@
 # Licensed under the GPL
 #
 
-SUBDIRS += $(ARCH_DIR)/os-$(OS)/drivers
-LIBS += $(ARCH_DIR)/os-$(OS)/drivers/drivers.o
+core-y		+= $(ARCH_DIR)/os-$(OS)/
diff -Nru a/arch/um/config.in b/arch/um/config.in
--- a/arch/um/config.in	Tue Oct  1 00:08:17 2002
+++ b/arch/um/config.in	Tue Oct  1 00:08:17 2002
@@ -32,6 +32,7 @@
 define_bool CONFIG_SMP $CONFIG_UML_SMP
 int 'Nesting level' CONFIG_NEST_LEVEL 0
 int 'Kernel address space size (in .5G units)' CONFIG_KERNEL_HALF_GIGS 1
+bool 'Highmem support' CONFIG_HIGHMEM
 endmenu
 
 mainmenu_option next_comment
diff -Nru a/arch/um/defconfig b/arch/um/defconfig
--- a/arch/um/defconfig	Tue Oct  1 00:08:18 2002
+++ b/arch/um/defconfig	Tue Oct  1 00:08:18 2002
@@ -31,6 +31,7 @@
 # CONFIG_SMP is not set
 CONFIG_NEST_LEVEL=0
 CONFIG_KERNEL_HALF_GIGS=1
+# CONFIG_HIGHMEM is not set
 
 #
 # Loadable module support
@@ -206,6 +207,9 @@
 # CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
 # CONFIG_UFS_FS_WRITE is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_QUOTA is not set
 
 #
 # Network File Systems
diff -Nru a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
--- a/arch/um/drivers/ubd_kern.c	Tue Oct  1 00:08:17 2002
+++ b/arch/um/drivers/ubd_kern.c	Tue Oct  1 00:08:17 2002
@@ -15,7 +15,6 @@
 #include "linux/blk.h"
 #include "linux/blkdev.h"
 #include "linux/hdreg.h"
-#include "linux/ide.h"
 #include "linux/init.h"
 #include "linux/devfs_fs_kernel.h"
 #include "linux/cdrom.h"
@@ -56,9 +55,6 @@
 
 #define DEVICE_NR(n) (minor(n) >> UBD_SHIFT)
 
-/* number of bytes per sector */
-static int hardsect_sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = 512 };
-
 static struct block_device_operations ubd_blops = {
         open:		ubd_open,
         release:	ubd_release,
@@ -66,29 +62,12 @@
         revalidate:	ubd_revalidate,
 };
 
-static struct hd_struct	ubd_part[MAX_MINOR] = 
-	{ [ 0 ... MAX_MINOR - 1 ] = { 0, 0, 0 } };
-
 static request_queue_t *ubd_queue;
 
 static int fake_major = 0;
-
-#define INIT_GENDISK(maj, name, parts, shift, blops) \
-{ \
-	major :		maj, \
-	major_name : 	name, \
-	minor_shift :	shift, \
-	part : 		parts, \
-	next : 		NULL, \
-	fops : 		blops, \
-	flags : 	0 \
-}
-
-static struct gendisk ubd_gendisk = INIT_GENDISK(MAJOR_NR, "ubd", ubd_part,
-						 UBD_SHIFT, &ubd_blops);
-static struct gendisk fake_gendisk = INIT_GENDISK(0, "ubd", ubd_part, 
-						  UBD_SHIFT, &ubd_blops);
-
+static struct gendisk ubd_gendisk[MAX_DEV];
+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 })
 #else
@@ -220,11 +199,12 @@
 {
 	struct openflags flags = global_openflags;
 	char *backing_file;
-	int n;
+	int i, n;
 
 	if(index_out) *index_out = -1;
 	n = *str++;
 	if(n == '='){
+		static int fake_major_allowed = 1;
 		char *end;
 		int major;
 
@@ -238,8 +218,15 @@
 			       "ubd_setup : didn't parse major number\n");
 			return(1);
 		}
-		fake_gendisk.major = major;
+
+		if(!fake_major_allowed){
+			printk(KERN_ERR "Can't assign a fake major twice\n");
+			return(1);
+		}
+
 		fake_major = major;
+		fake_major_allowed = 0;
+
 		printk(KERN_INFO "Setting extra ubd major number to %d\n",
 		       major);
 		return(0);
@@ -313,12 +300,13 @@
 "    to be written to disk on the host immediately.\n\n"
 );
 
+static int fakehd_set = 0;
 static int fakehd(char *str)
 {
 	printk(KERN_INFO 
-	       "fakehd : Changing ubd_gendisk.major_name to \"hd\".\n");
-	ubd_gendisk.major_name = "hd";
-	return(1);
+	       "fakehd : Changing ubd name to \"hd\".\n");
+	fakehd_set = 1;
+	return 1;
 }
 
 __setup("fakehd", fakehd);
@@ -394,32 +382,62 @@
 
 int sync = 0;
 
+static int ubd_file_size(struct ubd *dev, __u64 *size_out)
+{
+	char *file;
+
+	file = dev->cow.file ? dev->cow.file : dev->file;
+	return(os_file_size(file, size_out));
+}
+
 devfs_handle_t ubd_dir_handle;
 devfs_handle_t ubd_fake_dir_handle;
 
 static int ubd_add(int n)
 {
  	devfs_handle_t real, fake;
-	char name[sizeof("nnnnnn\0")], dev_name[sizeof("ubd0x")];
- 	int err;
+	char name[sizeof("nnnnnn\0")];
+	struct ubd *dev = &ubd_dev[n];
+	u64 size;
 
-	if(ubd_dev[n].file == NULL) return(-1);
- 
- 	err = ubd_revalidate(mk_kdev(MAJOR_NR, n << UBD_SHIFT));
- 	if(err)
- 		return(err);
+	if (!dev->file)
+		return -1;
+
+	ubd_gendisk[n].major = MAJOR_NR;
+	ubd_gendisk[n].first_minor = n << UBD_SHIFT;
+	ubd_gendisk[n].minor_shift = UBD_SHIFT;
+	ubd_gendisk[n].fops = &ubd_fops;
+	if (fakehd_set)
+		sprintf(ubd_gendisk[n].disk_name, "hd%c", n + 'a');
+	else
+		sprintf(ubd_gendisk[n].disk_name, "ubd%d", n);
+
+	if (fake_major) {
+		fake_gendisk[n].major = fake_major;
+		fake_gendisk[n].first_minor = n << UBD_SHIFT;
+		fake_gendisk[n].minor_shift = UBD_SHIFT;
+		fake_gendisk[n].fops = &ubd_fops;
+		sprintf(fake_gendisk[n].disk_name, "ubd%d", n);
+	}
+
+	if (!dev->is_dir && ubd_file_size(dev, &size) == 0) {
+		set_capacity(&ubd_gendisk[n], size/512);
+		set_capacity(&fake_gendisk[n], size/512);
+	}
  
 	sprintf(name, "%d", n);
 	real = devfs_register(ubd_dir_handle, name, DEVFS_FL_REMOVABLE, 
 			      MAJOR_NR, n << UBD_SHIFT,
 			      S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP |S_IWGRP,
 			      &ubd_blops, NULL);
-	if(fake_major != 0){
+	add_disk(&ubd_gendisk[n]);
+	if (fake_major) {
 		fake = devfs_register(ubd_fake_dir_handle, name, 
 				      DEVFS_FL_REMOVABLE, fake_major,
 				      n << UBD_SHIFT, 
 				      S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP |
 				      S_IWGRP, &ubd_blops, NULL);
+		add_disk(&fake_gendisk[n]);
  		if(fake == NULL) return(-1);
  		ubd_dev[n].fake = fake;
 	}
@@ -427,12 +445,7 @@
  	if(real == NULL) return(-1);
  	ubd_dev[n].real = real;
  
-	if(!strcmp(ubd_gendisk.major_name, "ubd"))
-		sprintf(dev_name, "%s%d", ubd_gendisk.major_name, n);
-	else sprintf(dev_name, "%s%c", ubd_gendisk.major_name, 
-		     n + 'a');
-
-	make_ide_entries(dev_name);
+	make_ide_entries(ubd_gendisk[n].name);
 	return(0);
 }
 
@@ -470,6 +483,9 @@
 	n = *str - '0';
 	if(n > MAX_DEV) return(-1);
 	dev = &ubd_dev[n];
+	del_gendisk(&ubd_gendisk[n]);
+	if (fake_major)
+		del_gendisk(&fake_gendisk[n]);
 	if(dev->file == NULL) return(0);
 	if(dev->count > 0) return(-1);
 	if(dev->real != NULL) devfs_unregister(dev->real);
@@ -509,8 +525,6 @@
 	ubd_queue = BLK_DEFAULT_QUEUE(MAJOR_NR);
 	INIT_QUEUE(ubd_queue, do_ubd_request, &ubd_lock);
 	INIT_ELV(ubd_queue, &ubd_queue->elevator);
-	INIT_HARDSECT(hardsect_size, MAJOR_NR, hardsect_sizes);
-        add_gendisk(&ubd_gendisk);
 	if(fake_major != 0){
 		char name[sizeof("ubd_nnn\0")];
 
@@ -522,10 +536,9 @@
 			return -1;
 		}
 		blk_dev[fake_major].queue = ubd_get_queue;
-		INIT_HARDSECT(hardsect_size, fake_major, hardsect_sizes);
-                add_gendisk(&fake_gendisk);
 	}
-	for(i=0;i<MAX_DEV;i++) ubd_add(i);
+	for(i = 0; i < MAX_DEV; i++) 
+		ubd_add(i);
 	return(0);
 }
 
@@ -617,14 +630,6 @@
 	return(err);
 }
 
-static int ubd_file_size(struct ubd *dev, __u64 *size_out)
-{
-	char *file;
-
-	file = dev->cow.file ? dev->cow.file : dev->file;
-	return(os_file_size(file, size_out));
-}
-
 static int ubd_open(struct inode *inode, struct file *filp)
 {
 	struct ubd *dev;
@@ -647,9 +652,7 @@
 			       "errno = %d\n", n, dev->file, -err);
 			return(err);
 		}
-		err = ubd_file_size(dev, &dev->size);
 		if(err) return(err);
-		ubd_part[offset].nr_sects = dev->size / hardsect_sizes[offset];
 	}
 	dev->count++;
 	if((filp->f_mode & FMODE_WRITE) && !dev->openflags.w){
@@ -667,10 +670,10 @@
 	offset = n << UBD_SHIFT;
 	if(n > MAX_DEV)
 		return -ENODEV;
-	if(--ubd_dev[n].count == 0){
+
+	if(--ubd_dev[n].count == 0)
 		ubd_close(&ubd_dev[n]);
-		ubd_part[offset].nr_sects = 0;
-	}
+
 	return(0);
 }
 
@@ -741,7 +744,6 @@
 		return(1);
 	}
 
-        req->sector += ubd_part[min].start_sect;
         block = req->sector;
         nsect = req->current_nr_sectors;
 
@@ -813,18 +815,9 @@
 		if(!loc) return(-EINVAL);
 		g.heads = 128;
 		g.sectors = 32;
-		g.cylinders = dev->size / (128 * 32 * hardsect_sizes[min]);
+		g.cylinders = dev->size / (128 * 32 * 512);
 		g.start = 2;
 		return(copy_to_user(loc, &g, sizeof(g)) ? -EFAULT : 0);
-	case BLKGETSIZE:   /* Return device size */
-		if(!arg) return(-EINVAL);
-		err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
-		if(err)
-			return(err);
-		put_user(ubd_part[min].nr_sects, (long *) arg);
-		return(0);
-	case BLKRRPART: /* Re-read partition tables */
-		return(ubd_revalidate(inode->i_rdev));
 
 	case HDIO_SET_UNMASKINTR:
 		if(!capable(CAP_SYS_ADMIN)) return(-EACCES);
@@ -853,7 +846,7 @@
 		return(0);
 
 	case HDIO_GET_IDENTITY:
-		ubd_id.cyls = dev->size / (128 * 32 * hardsect_sizes[min]);
+		ubd_id.cyls = dev->size / (128 * 32 * 512);
 		if(copy_to_user((char *) arg, (char *) &ubd_id, 
 				 sizeof(ubd_id)))
 			return(-EFAULT);
@@ -869,64 +862,29 @@
 		if(copy_to_user((char *) arg, &volume, sizeof(volume)))
 			return(-EFAULT);
 		return(0);
-
-	default:
-		return blk_ioctl(inode->i_bdev, cmd, arg);
 	}
 }
 
 static int ubd_revalidate(kdev_t rdev)
 {
-	int i, n, offset, err, pcount = 1 << UBD_SHIFT;
+	__u64 size;
+	int n, offset, err;
 	struct ubd *dev;
-	struct hd_struct *part;
 
 	n = minor(rdev) >> UBD_SHIFT;
-	offset = n << UBD_SHIFT;
 	dev = &ubd_dev[n];
 	if(dev->is_dir) 
 		return(0);
 	
-	part = &ubd_part[offset];
-
-	/* clear all old partition counts */
-	for(i = 1; i < pcount; i++) {
-		part[i].start_sect = 0;
-		part[i].nr_sects = 0;
-	}
-
-	/* If it already has been opened we can check the partitions 
-	 * directly 
-	 */
-	if(dev->count){
-		part->start_sect = 0;
-		register_disk(&ubd_gendisk, mk_kdev(MAJOR_NR, offset), pcount, 
-			      &ubd_blops, part->nr_sects);
-	} 
-	else if(dev->file){
-		err = ubd_open_dev(dev);
-		if(err){
-			printk(KERN_ERR "unable to open %s for validation\n",
-			       dev->file);
-			return(err);
-		}
+	err = ubd_file_size(dev, &size);
+	if (!err) {
+		set_capacity(&ubd_gendisk[n], size / 512);
+		if(fake_major != 0)
+			set_capacity(&fake_gendisk[n], size / 512);
+		dev->size = size;
+	}
 
-		/* have to recompute sizes since we opened it */
-		err = ubd_file_size(dev, &dev->size);
-		if(err) {
-			ubd_close(dev);
-			return(err);
-		}
-		part->start_sect = 0;
-		part->nr_sects = dev->size / hardsect_sizes[offset];
-		register_disk(&ubd_gendisk, mk_kdev(MAJOR_NR, offset), pcount, 
-			      &ubd_blops, part->nr_sects);
-
-		/* we are done so close it */
-		ubd_close(dev);
-	} 
-	else return(-ENODEV);
-	return(0);
+	return err;
 }
 
 /*
diff -Nru a/arch/um/include/mem_user.h b/arch/um/include/mem_user.h
--- a/arch/um/include/mem_user.h	Tue Oct  1 00:08:18 2002
+++ b/arch/um/include/mem_user.h	Tue Oct  1 00:08:18 2002
@@ -34,6 +34,7 @@
 
 struct mem_region {
 	char *driver;
+	unsigned long start_pfn;
 	unsigned long start;
 	unsigned long len;
 	void *mem_map;
@@ -51,8 +52,8 @@
 extern int init_mem_user(void);
 extern int create_mem_file(unsigned long len);
 extern void setup_range(int fd, char *driver, unsigned long start,
-			unsigned long total, struct mem_region *region,
-			void *reserved);
+			unsigned long pfn, unsigned long total, int need_vm, 
+			struct mem_region *region, void *reserved);
 extern void map(unsigned long virt, unsigned long p, unsigned long len, 
 		int r, int w, int x);
 extern int unmap(void *addr, int len);
@@ -62,8 +63,6 @@
 extern unsigned long find_iomem(char *driver, unsigned long *len_out);
 extern int init_maps(struct mem_region *region);
 extern int nregions(void);
-extern void setup_one_range(int n, int fd, char *driver, unsigned long start, 
-			    unsigned long len, struct mem_region *region);
 extern int reserve_vm(unsigned long start, unsigned long end, void *e);
 extern unsigned long get_vm(unsigned long len);
 extern void setup_physmem(unsigned long start, unsigned long usable,
diff -Nru a/arch/um/include/user_util.h b/arch/um/include/user_util.h
--- a/arch/um/include/user_util.h	Tue Oct  1 00:08:15 2002
+++ b/arch/um/include/user_util.h	Tue Oct  1 00:08:15 2002
@@ -27,6 +27,7 @@
 extern unsigned long uml_reserved;
 extern unsigned long end_vm;
 extern unsigned long start_vm;
+extern unsigned long highmem;
 
 extern int tracing_pid;
 extern int honeypot;
diff -Nru a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile
--- a/arch/um/kernel/Makefile	Tue Oct  1 00:08:18 2002
+++ b/arch/um/kernel/Makefile	Tue Oct  1 00:08:18 2002
@@ -10,7 +10,6 @@
 	umid.o user_util.o
 
 obj-$(CONFIG_BLK_DEV_INITRD) += initrd_kern.o initrd_user.o
-endif
 
 # user_syms.o not included here because Rules.make has its own ideas about
 # building anything in export-objs
diff -Nru a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
--- a/arch/um/kernel/mem.c	Tue Oct  1 00:08:17 2002
+++ b/arch/um/kernel/mem.c	Tue Oct  1 00:08:17 2002
@@ -1,5 +1,5 @@
 /* 
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
  * Licensed under the GPL
  */
 
@@ -27,13 +27,13 @@
 #include "init.h"
 
 unsigned long high_physmem;
-
 unsigned long low_physmem;
 
 unsigned long vm_start;
-
 unsigned long vm_end;
 
+unsigned long highmem;
+
 pgd_t swapper_pg_dir[1024];
 
 unsigned long *empty_zero_page = NULL;
@@ -71,7 +71,10 @@
 {
 	unsigned long start;
 
-	max_mapnr = num_physpages = max_low_pfn;
+	max_low_pfn = (high_physmem - uml_physmem) >> PAGE_SHIFT;
+#ifdef CONFIG_HIGHMEM
+	highmem_start_page = phys_page(__pa(high_physmem));
+#endif
 
         /* clear the zero-page */
         memset((void *) empty_zero_page, 0, PAGE_SIZE);
@@ -93,16 +96,189 @@
 	}
 
 	/* this will put all low memory onto the freelists */
-	totalram_pages += free_all_bootmem();
+	totalram_pages = free_all_bootmem();
+	totalhigh_pages = highmem >> PAGE_SHIFT;
+	totalram_pages += totalhigh_pages;
+	num_physpages = totalram_pages;
+	max_mapnr = totalram_pages;
+	max_pfn = totalram_pages;
 	printk(KERN_INFO "Memory: %luk available\n", 
 	       (unsigned long) nr_free_pages() << (PAGE_SHIFT-10));
 	kmalloc_ok = 1;
 }
 
+#if CONFIG_HIGHMEM
+pte_t *kmap_pte;
+pgprot_t kmap_prot;
+
+#define kmap_get_fixmap_pte(vaddr)					\
+	pte_offset_kernel(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr))
+
+void __init kmap_init(void)
+{
+	unsigned long kmap_vstart;
+
+	/* cache the first kmap pte */
+	kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);
+	kmap_pte = kmap_get_fixmap_pte(kmap_vstart);
+
+	kmap_prot = PAGE_KERNEL;
+}
+#endif /* CONFIG_HIGHMEM */
+
+static void __init fixrange_init(unsigned long start, unsigned long end, 
+				 pgd_t *pgd_base)
+{
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte;
+	int i, j;
+	unsigned long vaddr;
+
+	vaddr = start;
+	i = __pgd_offset(vaddr);
+	j = __pmd_offset(vaddr);
+	pgd = pgd_base + i;
+
+	for ( ; (i < PTRS_PER_PGD) && (vaddr < end); pgd++, i++) {
+		pmd = (pmd_t *)pgd;
+		for (; (j < PTRS_PER_PMD) && (vaddr != end); pmd++, j++) {
+			if (pmd_none(*pmd)) {
+				pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+				set_pmd(pmd, __pmd(_KERNPG_TABLE + 
+						   (unsigned long) __pa(pte)));
+				if (pte != pte_offset_kernel(pmd, 0))
+					BUG();
+			}
+			vaddr += PMD_SIZE;
+		}
+		j = 0;
+	}
+}
+
+int init_maps(struct mem_region *region)
+{
+	struct page *p, *map;
+	int i, n, len;
+
+	if(region == &physmem_region){
+		region->mem_map = mem_map;
+		return(0);
+	}
+	else if(region->mem_map != NULL) return(0);
+
+	n = region->len >> PAGE_SHIFT;
+	len = n * sizeof(struct page);
+	if(kmalloc_ok){
+		map = kmalloc(len, GFP_KERNEL);
+		if(map == NULL) map = vmalloc(len);
+	}
+	else map = alloc_bootmem_low_pages(len);
+
+	if(map == NULL)
+		return(-ENOMEM);
+	for(i = 0; i < n; i++){
+		p = &map[i];
+		set_page_count(p, 0);
+		SetPageReserved(p);
+		INIT_LIST_HEAD(&p->list);
+	}
+	region->mem_map = map;
+	return(0);
+}
+
+static int setup_one_range(int fd, char *driver, unsigned long start, 
+			   unsigned long pfn, int len, 
+			   struct mem_region *region)
+{
+	int i;
+
+	for(i = 0; i < NREGIONS; i++){
+		if(regions[i] == NULL) break;		
+	}
+	if(i == NREGIONS){
+		printk("setup_range : no free regions\n");
+		return(-1);
+	}
+
+	if(fd == -1)
+		fd = create_mem_file(len);
+
+	if(region == NULL){
+		region = alloc_bootmem_low_pages(sizeof(*region));
+		if(region == NULL)
+			panic("Failed to allocating mem_region");
+	}
+
+	*region = ((struct mem_region) { driver :	driver,
+					 start_pfn :	pfn,
+					 start :	start, 
+					 len :		len, 
+					 fd :		fd } );
+	regions[i] = region;
+	return(i);
+}
+
+#ifdef CONFIG_HIGHMEM
+static void init_highmem(void)
+{
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte;
+	unsigned long vaddr;
+
+	/*
+	 * Permanent kmaps:
+	 */
+	vaddr = PKMAP_BASE;
+	fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, swapper_pg_dir);
+
+	pgd = swapper_pg_dir + __pgd_offset(vaddr);
+	pmd = pmd_offset(pgd, vaddr);
+	pte = pte_offset_kernel(pmd, vaddr);
+	pkmap_page_table = pte;
+
+	kmap_init();
+}
+
+void setup_highmem(unsigned long len)
+{
+	struct mem_region *region;
+	struct page *page, *map;
+	unsigned long phys;
+	int i, cur, index;
+
+	phys = physmem_size;
+	do {
+		cur = min(len, (unsigned long) REGION_SIZE);
+		i = setup_one_range(-1, NULL, -1, phys >> PAGE_SHIFT, cur, 
+				    NULL);
+		if(i == -1){
+			printk("setup_highmem - setup_one_range failed\n");
+			return;
+		}
+		region = regions[i];
+		index = phys / PAGE_SIZE;
+		region->mem_map = &mem_map[index];
+
+		map = region->mem_map;
+		for(i = 0; i < (cur >> PAGE_SHIFT); i++){
+			page = &map[i];
+			ClearPageReserved(page);
+			set_bit(PG_highmem, &page->flags);
+			atomic_set(&page->count, 1);
+			__free_page(page);
+		}
+		phys += cur;
+		len -= cur;
+	} while(len > 0);
+}
+#endif
+
 void paging_init(void)
 {
 	struct mem_region *region;
-	unsigned long zones_size[MAX_NR_ZONES], start, end;
+	unsigned long zones_size[MAX_NR_ZONES], start, end, vaddr;
 	int i, index;
 
 	empty_zero_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
@@ -111,6 +287,7 @@
 		zones_size[i] = 0;
 	zones_size[0] = (high_physmem >> PAGE_SHIFT) - 
 		(uml_physmem >> PAGE_SHIFT);
+	zones_size[2] = highmem >> PAGE_SHIFT;
 	free_area_init(zones_size);
 	start = phys_region_index(__pa(uml_physmem));
 	end = phys_region_index(__pa(high_physmem - 1));
@@ -120,6 +297,18 @@
 		region->mem_map = &mem_map[index];
 		if(i > start) free_bootmem(__pa(region->start), region->len);
 	}
+
+	/*
+	 * Fixed mappings, only the page table structure has to be
+	 * created - mappings will be set by set_fixmap():
+	 */
+	vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
+	fixrange_init(vaddr, FIXADDR_TOP, swapper_pg_dir);
+
+#if CONFIG_HIGHMEM
+	init_highmem();
+	setup_highmem(highmem);
+#endif
 }
 
 pte_t __bad_page(void)
@@ -220,6 +409,8 @@
 
  again:
 	if(page == NULL) return(page);
+	if(PageHighMem(page)) return(page);
+
 	addr = (unsigned long) page_address(page);
 	for(i = 0; i < (1 << order); i++){
 		current->thread.fault_addr = (void *) addr;
@@ -233,7 +424,7 @@
 		addr += PAGE_SIZE;
 	}
 	if(i == (1 << order)) return(page);
-	page = _alloc_pages(mask, order);
+	page = alloc_pages(mask, order);
 	goto again;
 }
 
@@ -315,56 +506,24 @@
 	return(NREGIONS);
 }
 
-int init_maps(struct mem_region *region)
-{
-	struct page *p, *map;
-	int i, n;
-
-	if(region == &physmem_region){
-		region->mem_map = mem_map;
-		return(0);
-	}
-	else if(region->mem_map != NULL) return(0);
-
-	n = region->len >> PAGE_SHIFT;
-	map = kmalloc(n * sizeof(struct page), GFP_KERNEL);
-	if(map == NULL) map = vmalloc(n * sizeof(struct page));
-	if(map == NULL)
-		return(-ENOMEM);
-	for(i = 0; i < n; i++){
-		p = &map[i];
-		set_page_count(p, 0);
-		SetPageReserved(p);
-		INIT_LIST_HEAD(&p->list);
-	}
-	region->mem_map = map;
-	return(0);
-}
-
-void setup_range(int fd, char *driver, unsigned long start, 
-		 unsigned long len, struct mem_region *region, void *reserved)
+void setup_range(int fd, char *driver, unsigned long start, unsigned long pfn,
+		 unsigned long len, int need_vm, struct mem_region *region, 
+		 void *reserved)
 {
-	int i, incr;
+	int i, cur;
 
-	i = 0;
 	do {
-		for(; i < NREGIONS; i++){
-			if(regions[i] == NULL) break;		
-		}
-		if(i == NREGIONS){
-			printk("setup_range : no free regions\n");
-			return;
-		}
-		setup_one_range(i, fd, driver, start, len, region);
+		cur = min(len, (unsigned long) REGION_SIZE);
+		i = setup_one_range(fd, driver, start, pfn, cur, region);
 		region = regions[i];
-		if(setup_region(region, reserved)){
+		if(need_vm && setup_region(region, reserved)){
 			kfree(region);
 			regions[i] = NULL;
 			return;
 		}
-		incr = min(len, (unsigned long) REGION_SIZE);
-		start += incr;
-		len -= incr;
+		start += cur;
+		if(pfn != -1) pfn += cur;
+		len -= cur;
 	} while(len > 0);
 }
 
@@ -399,8 +558,8 @@
 
 	for(i = 0; i < num_iomem_regions; i++){
 		iomem = &iomem_regions[i];
-		setup_range(iomem->fd, iomem->name, -1, iomem->size, NULL, 
-			    NULL);
+		setup_range(iomem->fd, iomem->name, -1, -1, iomem->size, 1, 
+			    NULL, NULL);
 	}
 	return(0);
 }
@@ -418,7 +577,7 @@
 {
 	struct mem_region *region = &physmem_region;
 	struct vm_reserved *reserved = &physmem_reserved;
-	unsigned long cur;
+	unsigned long cur, pfn = 0;
 	int do_free = 1, bootmap_size;
 
 	do {
@@ -430,7 +589,7 @@
 		if((region == NULL) || (reserved == NULL))
 			panic("Couldn't allocate physmem region or vm "
 			      "reservation\n");
-		setup_range(-1, NULL, start, cur, region, reserved);
+		setup_range(-1, NULL, start, pfn, cur, 1, region, reserved);
 
 		if(do_free){
 			unsigned long reserve = reserve_end - start;
@@ -443,6 +602,7 @@
 			do_free = 0;
 		}
 		start += cur;
+		pfn += cur >> PAGE_SHIFT;
 		len -= cur;
 		region = NULL;
 		reserved = NULL;
@@ -492,6 +652,56 @@
 	return(NULL);
 }
 
+unsigned long page_to_pfn(struct page *page)
+{
+	struct mem_region *region = page_region(page, NULL);
+
+	return(region->start_pfn + (page - (struct page *) region->mem_map));
+}
+
+struct mem_region *pfn_to_region(unsigned long pfn, int *index_out)
+{
+	struct mem_region *region;
+	int i;
+
+	for(i = 0; i < NREGIONS; i++){
+		region = regions[i];
+		if(region == NULL)
+			continue;
+
+		if((region->start_pfn <= pfn) &&
+		   (region->start_pfn + (region->len >> PAGE_SHIFT) > pfn)){
+			if(index_out != NULL) 
+				*index_out = i;
+			return(region);
+		}
+	}
+	return(NULL);
+}
+
+struct page *pfn_to_page(unsigned long pfn)
+{
+	struct mem_region *region = pfn_to_region(pfn, NULL);
+	struct page *mem_map = (struct page *) region->mem_map;
+
+	return(&mem_map[pfn - region->start_pfn]);
+}
+
+unsigned long phys_to_pfn(unsigned long p)
+{
+	struct mem_region *region = regions[phys_region_index(p)];
+
+	return(region->start_pfn + (phys_addr(p) >> PAGE_SHIFT));
+}
+
+unsigned long pfn_to_phys(unsigned long pfn)
+{
+	int n;
+	struct mem_region *region = pfn_to_region(pfn, &n);
+
+	return(mk_phys((pfn - region->start_pfn) << PAGE_SHIFT, n));
+}
+
 struct page *page_mem_map(struct page *page)
 {
 	return((struct page *) page_region(page, NULL)->mem_map);
@@ -535,7 +745,7 @@
 	return(mem_map + (phys_offset(phys) >> PAGE_SHIFT));
 }
 
-int setup_mem_maps(void)
+static int setup_mem_maps(void)
 {
 	struct mem_region *region;
 	int i;
@@ -594,7 +804,7 @@
 	struct page *pte;
    
    	do {
-		pte = alloc_pages(GFP_KERNEL | __GFP_HIGHMEM, 0);
+		pte = alloc_pages(GFP_KERNEL, 0);
 		if (pte)
 			clear_highpage(pte);
 		else {
diff -Nru a/arch/um/kernel/mem_user.c b/arch/um/kernel/mem_user.c
--- a/arch/um/kernel/mem_user.c	Tue Oct  1 00:08:17 2002
+++ b/arch/um/kernel/mem_user.c	Tue Oct  1 00:08:17 2002
@@ -77,25 +77,6 @@
 	return(fd);
 }
 
-void setup_one_range(int n, int fd, char *driver, unsigned long start, 
-		     unsigned long len, struct mem_region *region)
-{
-	if(fd == -1)
-		fd = create_mem_file(len);
-	if(region == NULL){
-		region = malloc(sizeof(*region));
-		if(region == NULL){
-			perror("Allocating mem_region");
-			exit(1);
-		}
-	}
-	*region = ((struct mem_region) { driver :	driver, 
-					 start :	start, 
-					 len :		len, 
-					 fd :		fd } );
-	regions[n] = region;
-}
-
 int setup_region(struct mem_region *region, void *entry)
 {
 	void *loc, *start;
diff -Nru a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c
--- a/arch/um/kernel/process_kern.c	Tue Oct  1 00:08:17 2002
+++ b/arch/um/kernel/process_kern.c	Tue Oct  1 00:08:17 2002
@@ -48,7 +48,7 @@
 
         ret = NULL;
         read_lock(&tasklist_lock);
-        for_each_task(task){
+        for_each_process(task){
                 if(task->pid == pid){
                         ret = task;
                         break;
@@ -64,7 +64,7 @@
 	struct task_struct *task;
 
         read_lock(&tasklist_lock);
-        for_each_task(task){
+        for_each_process(task){
                 if(task->thread.extern_pid == pid){
 			read_unlock(&tasklist_lock);
 			return(1);
@@ -528,7 +528,7 @@
 
 char *current_cmd(void)
 {
-#ifdef CONFIG_SMP
+#if defined(CONFIG_SMP) || defined(CONFIG_HIGHMEM)
 	return("(Unknown)");
 #else
 	unsigned long addr = um_virt_to_phys(current, current->mm->arg_start);
diff -Nru a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c
--- a/arch/um/kernel/reboot.c	Tue Oct  1 00:08:13 2002
+++ b/arch/um/kernel/reboot.c	Tue Oct  1 00:08:13 2002
@@ -15,7 +15,7 @@
 	int me;
 
 	me = os_getpid();
-	for_each_task(p){
+	for_each_process(p){
 		if(p->thread.extern_pid != me) 
 			os_kill_process(p->thread.extern_pid);
 	}
diff -Nru a/arch/um/kernel/sys_call_table.c b/arch/um/kernel/sys_call_table.c
--- a/arch/um/kernel/sys_call_table.c	Tue Oct  1 00:08:19 2002
+++ b/arch/um/kernel/sys_call_table.c	Tue Oct  1 00:08:19 2002
@@ -223,6 +223,12 @@
 extern syscall_handler_t sys_futex;
 extern syscall_handler_t sys_sched_setaffinity;
 extern syscall_handler_t sys_sched_getaffinity;
+extern syscall_handler_t sys_io_setup;
+extern syscall_handler_t sys_io_destroy;
+extern syscall_handler_t sys_io_getevents;
+extern syscall_handler_t sys_io_submit;
+extern syscall_handler_t sys_io_cancel;
+extern syscall_handler_t sys_exit_group;
 
 #if CONFIG_NFSD
 #define NFSSERVCTL sys_nfsserctl
@@ -234,7 +240,7 @@
 extern syscall_handler_t um_time;
 extern syscall_handler_t um_stime;
 
-#define LAST_GENERIC_SYSCALL __NR_sched_getaffinity
+#define LAST_GENERIC_SYSCALL __NR_exit_group
 
 #if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL
 #define LAST_SYSCALL LAST_GENERIC_SYSCALL
@@ -465,6 +471,14 @@
 	[ __NR_futex ] = sys_futex,
 	[ __NR_sched_setaffinity ] = sys_sched_setaffinity,
 	[ __NR_sched_getaffinity ] = sys_sched_getaffinity,
+	[ __NR_io_setup ] = sys_io_setup,
+	[ __NR_io_destroy ] = sys_io_destroy,
+	[ __NR_io_getevents ] = sys_io_getevents,
+	[ __NR_io_submit ] = sys_io_submit,
+	[ __NR_io_cancel ] = sys_io_cancel,
+	[ __NR_alloc_hugepages ] = sys_ni_syscall,
+	[ __NR_free_hugepages ] = sys_ni_syscall,
+	[ __NR_exit_group ] = sys_exit_group,
 
 	ARCH_SYSCALLS
 	[ LAST_SYSCALL + 1 ... NR_syscalls ] = 
diff -Nru a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c
--- a/arch/um/kernel/tlb.c	Tue Oct  1 00:08:15 2002
+++ b/arch/um/kernel/tlb.c	Tue Oct  1 00:08:15 2002
@@ -178,6 +178,11 @@
 	flush_tlb_kernel_range(start_vm, end_vm);
 }
 
+void __flush_tlb_one(unsigned long addr)
+{
+	flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
+}
+  
 void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, 
 		     unsigned long end)
 {
diff -Nru a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
--- a/arch/um/kernel/um_arch.c	Tue Oct  1 00:08:19 2002
+++ b/arch/um/kernel/um_arch.c	Tue Oct  1 00:08:19 2002
@@ -4,6 +4,7 @@
  */
 
 #include "linux/config.h"
+#include "linux/kernel.h"
 #include "linux/sched.h"
 #include "linux/notifier.h"
 #include "linux/mm.h"
@@ -109,8 +110,6 @@
 	return(0);
 }
 
-extern unsigned long high_physmem;
-
 #ifdef CONFIG_HOST_2G_2G
 #define TOP 0x80000000
 #else
@@ -160,7 +159,7 @@
 
 	snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), " [%s]", cmd);
 	memset(argv1_begin + strlen(argv1_begin), '\0', 
-	       argv1_end - argv1_begin - strlen(argv1_begin));  
+	       argv1_end - argv1_begin - strlen(argv1_begin));
 }
 
 static char *usage_string = 
@@ -263,10 +262,12 @@
 
 static struct vm_reserved kernel_vm_reserved;
 
+#define MIN_VMALLOC (32 * 1024 * 1024)
+
 int linux_main(int argc, char **argv)
 {
 	unsigned long avail;
-	unsigned long virtmem_size;
+	unsigned long virtmem_size, max_physmem;
 	unsigned int i, add, err;
 	void *sp;
 
@@ -278,7 +279,7 @@
 	}
 	if(have_root == 0) add_arg(saved_command_line, DEFAULT_COMMAND_LINE);
 
-	if(!jail)
+	if(!jail || debug)
 		remap_data(ROUND_DOWN(&_stext), ROUND_UP(&_etext), 1);
 	remap_data(ROUND_DOWN(&_sdata), ROUND_UP(&_edata), 1);
 	brk_start = (unsigned long) sbrk(0);
@@ -295,20 +296,20 @@
 	argv1_end = &argv[1][strlen(argv[1])];
   
 	set_usable_vm(uml_physmem, get_kmem_end());
+
+	highmem = 0;
+	max_physmem = get_kmem_end() - uml_physmem - MIN_VMALLOC;
+	if(physmem_size > max_physmem){
+		highmem = physmem_size - max_physmem;
+		physmem_size -= highmem;
+	}
+
 	high_physmem = uml_physmem + physmem_size;
 	high_memory = (void *) high_physmem;
-	setup_physmem(uml_physmem, uml_reserved, physmem_size);
-
-	/* Kernel vm starts after physical memory and is either the size
-	 * of physical memory or the remaining space left in the kernel
-	 * area of the address space, whichever is smaller.
-	 */
 
 	start_vm = VMALLOC_START;
-	if(start_vm >= get_kmem_end())
-		panic("Physical memory too large to allow any kernel "
-		      "virtual memory");
 
+	setup_physmem(uml_physmem, uml_reserved, physmem_size);
 	virtmem_size = physmem_size;
 	avail = get_kmem_end() - start_vm;
 	if(physmem_size > avail) virtmem_size = avail;
diff -Nru a/arch/um/link.ld.in b/arch/um/link.ld.in
--- a/arch/um/link.ld.in	Tue Oct  1 00:08:17 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,143 +0,0 @@
-OUTPUT_FORMAT("ELF_FORMAT")
-OUTPUT_ARCH(ELF_ARCH)
-ENTRY(_start)
-jiffies = jiffies_64;
-
-SECTIONS
-{
-  . = START() + SIZEOF_HEADERS;
-
-  . = ALIGN(4096);
-  __binary_start = .;
-  .thread_private : {
-    __start_thread_private = .;
-    errno = .;
-    . += 4;
-    arch/um/kernel/unmap_fin.o (.data)
-    __end_thread_private = .;
-  }
-  . = ALIGN(4096);
-  .remap : { arch/um/kernel/unmap_fin.o (.text) }
-
-  . = ALIGN(4096);		/* Init code and data */
-  _stext = .;
-  __init_begin = .;
-  .text.init : { *(.text.init) }
-  . = ALIGN(4096);
-  .text      :
-  {
-    *(.text)
-    /* .gnu.warning sections are handled specially by elf32.em.  */
-    *(.gnu.warning)
-    *(.gnu.linkonce.t*)
-  }
-  .kstrtab : { *(.kstrtab) }
-
-  . = ALIGN(16);		/* Exception table */
-  __start___ex_table = .;
-  __ex_table : { *(__ex_table) }
-  __stop___ex_table = .;
-
-  __start___ksymtab = .;	/* Kernel symbol table */
-  __ksymtab : { *(__ksymtab) }
-  __stop___ksymtab = .;
-  .fini      : { *(.fini)    } =0x9090
-  .rodata    : { *(.rodata) *(.gnu.linkonce.r*) }
-  .rodata1   : { *(.rodata1) }
-  _etext = .;
-  PROVIDE (etext = .);
-
-  . = ALIGN(4096);
-  PROVIDE (_sdata = .);
-
-  .unprotected : { *(.unprotected) }
-  . = ALIGN(4096);
-  PROVIDE (_unprotected_end = .);
-
-  . = ALIGN(4096);
-  __uml_setup_start = .;
-  .uml.setup.init : { *(.uml.setup.init) }
-  __uml_setup_end = .;
-  __uml_help_start = .;
-  .uml.help.init : { *(.uml.help.init) }
-  __uml_help_end = .;
-  __uml_postsetup_start = .;
-  .uml.postsetup.init : { *(.uml.postsetup.init) }
-  __uml_postsetup_end = .;
-  __setup_start = .;
-  .setup.init : { *(.setup.init) }
-  __setup_end = .;
-  __initcall_start = .;
-  .initcall.init : {
-	*(.initcall1.init) 
-	*(.initcall2.init) 
-	*(.initcall3.init) 
-	*(.initcall4.init) 
-	*(.initcall5.init) 
-	*(.initcall6.init) 
-	*(.initcall7.init)
-  }
-  __initcall_end = .;
-  __uml_initcall_start = .;
-  .uml.initcall.init : { *(.uml.initcall.init) }
-  __uml_initcall_end = .;
-  __init_end = .;
-  __exitcall_begin = .;
-  .exitcall : { *(.exitcall.exit) }
-  __exitcall_end = .;
-  __uml_exitcall_begin = .;
-  .uml.exitcall : { *(.uml.exitcall.exit) }
-  __uml_exitcall_end = .;
-
-  .data.init : { *(.data.init) }
-  .data    :
-  {
-    . = ALIGN(16384);		/* init_task */
-    *(.data.init_task)
-    *(.data)
-    *(.gnu.linkonce.d*)
-    CONSTRUCTORS
-  }
-  .data1   : { *(.data1) }
-  .ctors         :
-  {
-    *(.ctors)
-  }
-  .dtors         :
-  {
-    *(.dtors)
-  }
-
-  .got           : { *(.got.plt) *(.got) }
-  .dynamic       : { *(.dynamic) }
-  /* We want the small data sections together, so single-instruction offsets
-     can access them all, and initialized data all before uninitialized, so
-     we can shorten the on-disk segment size.  */
-  .sdata     : { *(.sdata) }
-  _edata  =  .;
-  PROVIDE (edata = .);
-  . = ALIGN(0x1000);
-  .sbss      : 
-  {
-   __bss_start = .;
-   PROVIDE(_bss_start = .);
-   *(.sbss) 
-   *(.scommon) 
-  }
-  .bss       :
-  {
-   *(.dynbss)
-   *(.bss)
-   *(COMMON)
-  }
-  _end = . ;
-  PROVIDE (end = .);
-  /* Stabs debugging sections.  */
-  .stab 0 : { *(.stab) }
-  .stabstr 0 : { *(.stabstr) }
-  .stab.excl 0 : { *(.stab.excl) }
-  .stab.exclstr 0 : { *(.stab.exclstr) }
-  .stab.index 0 : { *(.stab.index) }
-  .stab.indexstr 0 : { *(.stab.indexstr) }
-  .comment 0 : { *(.comment) }
-}
diff -Nru a/arch/um/uml.lds.S b/arch/um/uml.lds.S
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/uml.lds.S	Tue Oct  1 00:08:17 2002
@@ -0,0 +1,143 @@
+OUTPUT_FORMAT(ELF_FORMAT)
+OUTPUT_ARCH(ELF_ARCH)
+ENTRY(_start)
+jiffies = jiffies_64;
+
+SECTIONS
+{
+  . = START + SIZEOF_HEADERS;
+
+  . = ALIGN(4096);
+  __binary_start = .;
+  .thread_private : {
+    __start_thread_private = .;
+    errno = .;
+    . += 4;
+    arch/um/kernel/unmap_fin.o (.data)
+    __end_thread_private = .;
+  }
+  . = ALIGN(4096);
+  .remap : { arch/um/kernel/unmap_fin.o (.text) }
+
+  . = ALIGN(4096);		/* Init code and data */
+  _stext = .;
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  . = ALIGN(4096);
+  .text      :
+  {
+    *(.text)
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+    *(.gnu.linkonce.t*)
+  }
+  .kstrtab : { *(.kstrtab) }
+
+  . = ALIGN(16);		/* Exception table */
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  __start___ksymtab = .;	/* Kernel symbol table */
+  __ksymtab : { *(__ksymtab) }
+  __stop___ksymtab = .;
+  .fini      : { *(.fini)    } =0x9090
+  .rodata    : { *(.rodata) *(.gnu.linkonce.r*) }
+  .rodata1   : { *(.rodata1) }
+  _etext = .;
+  PROVIDE (etext = .);
+
+  . = ALIGN(4096);
+  PROVIDE (_sdata = .);
+
+  .unprotected : { *(.unprotected) }
+  . = ALIGN(4096);
+  PROVIDE (_unprotected_end = .);
+
+  . = ALIGN(4096);
+  __uml_setup_start = .;
+  .uml.setup.init : { *(.uml.setup.init) }
+  __uml_setup_end = .;
+  __uml_help_start = .;
+  .uml.help.init : { *(.uml.help.init) }
+  __uml_help_end = .;
+  __uml_postsetup_start = .;
+  .uml.postsetup.init : { *(.uml.postsetup.init) }
+  __uml_postsetup_end = .;
+  __setup_start = .;
+  .setup.init : { *(.setup.init) }
+  __setup_end = .;
+  __initcall_start = .;
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
+  __initcall_end = .;
+  __uml_initcall_start = .;
+  .uml.initcall.init : { *(.uml.initcall.init) }
+  __uml_initcall_end = .;
+  __init_end = .;
+  __exitcall_begin = .;
+  .exitcall : { *(.exitcall.exit) }
+  __exitcall_end = .;
+  __uml_exitcall_begin = .;
+  .uml.exitcall : { *(.uml.exitcall.exit) }
+  __uml_exitcall_end = .;
+
+  .data.init : { *(.data.init) }
+  .data    :
+  {
+    . = ALIGN(16384);		/* init_task */
+    *(.data.init_task)
+    *(.data)
+    *(.gnu.linkonce.d*)
+    CONSTRUCTORS
+  }
+  .data1   : { *(.data1) }
+  .ctors         :
+  {
+    *(.ctors)
+  }
+  .dtors         :
+  {
+    *(.dtors)
+  }
+
+  .got           : { *(.got.plt) *(.got) }
+  .dynamic       : { *(.dynamic) }
+  /* We want the small data sections together, so single-instruction offsets
+     can access them all, and initialized data all before uninitialized, so
+     we can shorten the on-disk segment size.  */
+  .sdata     : { *(.sdata) }
+  _edata  =  .;
+  PROVIDE (edata = .);
+  . = ALIGN(0x1000);
+  .sbss      : 
+  {
+   __bss_start = .;
+   PROVIDE(_bss_start = .);
+   *(.sbss) 
+   *(.scommon) 
+  }
+  .bss       :
+  {
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+  }
+  _end = . ;
+  PROVIDE (end = .);
+  /* Stabs debugging sections.  */
+  .stab 0 : { *(.stab) }
+  .stabstr 0 : { *(.stabstr) }
+  .stab.excl 0 : { *(.stab.excl) }
+  .stab.exclstr 0 : { *(.stab.exclstr) }
+  .stab.index 0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment 0 : { *(.comment) }
+}
diff -Nru a/drivers/acorn/block/fd1772.c b/drivers/acorn/block/fd1772.c
--- a/drivers/acorn/block/fd1772.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/acorn/block/fd1772.c	Tue Oct  1 00:08:16 2002
@@ -204,7 +204,6 @@
 #define MAX_DISK_SIZE 720
 
 static struct gendisk disks[FD_MAX_UNIT];
-static char names[FD_MAX_UNIT][4];
 
 /* current info on each unit */
 static struct archy_floppy_struct {
@@ -1589,8 +1588,7 @@
 		disks[i].major = MAJOR_NR;
 		disks[i].first_minor = 0;
 		disks[i].fops = &floppy_fops;
-		sprintf(names[i], "fd%d", i);
-		disks[i].major_name = names[i];
+		sprintf(disks[i].disk_name, "fd%d", i);
 		set_capacity(&disks[i], MAX_DISK_SIZE * 2);
 	}
 	blk_set_probe(MAJOR_NR, floppy_find);
diff -Nru a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c
--- a/drivers/acorn/block/mfmhd.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/acorn/block/mfmhd.c	Tue Oct  1 00:08:15 2002
@@ -884,13 +884,13 @@
 {
 	.major		= MAJOR_NR,
 	.first_minor	= 0,
-	.major_name	= "mfma",
+	.disk_name	= "mfma",
 	.minor_shift	= 6,
 },
 {
 	.major		= MAJOR_NR,
 	.first_minor	= 64,
-	.major_name	= "mfmb",
+	.disk_name	= "mfmb",
 	.minor_shift	= 6,
 };
 
@@ -1020,7 +1020,7 @@
 	struct gendisk *disk = mfm_gendisk + drive;
 	if (p->cylinders)
 		printk ("%s: %dMB CHS=%d/%d/%d LCC=%d RECOMP=%d\n",
-			disk->major_name,
+			disk->disk_name,
 			p->cylinders * p->heads * p->sectors / 4096,
 			p->cylinders, p->heads, p->sectors,
 			p->lowcurrent, p->precomp);
diff -Nru a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c
--- a/drivers/atm/ambassador.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/atm/ambassador.c	Tue Oct  1 00:08:15 2002
@@ -516,7 +516,7 @@
 	  
 	  // VC layer stats
 	  atomic_inc(&atm_vcc->stats->rx);
-	  skb->stamp = xtime;
+	  do_gettimeofday(&skb->stamp);
 	  // end of our responsability
 	  atm_vcc->push (atm_vcc, skb);
 	  return;
diff -Nru a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c
--- a/drivers/atm/atmtcp.c	Tue Oct  1 00:08:18 2002
+++ b/drivers/atm/atmtcp.c	Tue Oct  1 00:08:18 2002
@@ -275,7 +275,7 @@
 		result = -ENOBUFS;
 		goto done;
 	}
-	new_skb->stamp = xtime;
+	do_gettimeofday(&new_skb->stamp);
 	memcpy(skb_put(new_skb,skb->len),skb->data,skb->len);
 	out_vcc->push(out_vcc,new_skb);
 	atomic_inc(&vcc->stats->tx);
diff -Nru a/drivers/atm/eni.c b/drivers/atm/eni.c
--- a/drivers/atm/eni.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/atm/eni.c	Tue Oct  1 00:08:16 2002
@@ -702,7 +702,7 @@
 			DPRINTK("Grr, servicing VCC %ld twice\n",vci);
 			continue;
 		}
-		ENI_VCC(vcc)->timestamp = xtime;
+		do_gettimeofday(&ENI_VCC(vcc)->timestamp);
 		ENI_VCC(vcc)->next = NULL;
 		if (vcc->qos.rxtp.traffic_class == ATM_CBR) {
 			if (eni_dev->fast)
diff -Nru a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
--- a/drivers/atm/fore200e.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/atm/fore200e.c	Tue Oct  1 00:08:17 2002
@@ -1134,7 +1134,8 @@
 	return;
     } 
 
-    skb->stamp = vcc->timestamp = xtime;
+	do_gettimeofday(&vcc->timestamp);
+    skb->stamp = vcc->timestamp;
     
 #ifdef FORE200E_52BYTE_AAL0_SDU
     if (cell_header) {
diff -Nru a/drivers/atm/horizon.c b/drivers/atm/horizon.c
--- a/drivers/atm/horizon.c	Tue Oct  1 00:08:13 2002
+++ b/drivers/atm/horizon.c	Tue Oct  1 00:08:14 2002
@@ -1049,7 +1049,7 @@
 	  struct atm_vcc * vcc = ATM_SKB(skb)->vcc;
 	  // VC layer stats
 	  atomic_inc(&vcc->stats->rx);
-	  skb->stamp = xtime;
+	  do_gettimeofday(&skb->stamp);
 	  // end of our responsability
 	  vcc->push (vcc, skb);
 	}
diff -Nru a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
--- a/drivers/atm/idt77252.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/atm/idt77252.c	Tue Oct  1 00:08:17 2002
@@ -1099,7 +1099,7 @@
 			       cell, ATM_CELL_PAYLOAD);
 
 			ATM_SKB(sb)->vcc = vcc;
-			sb->stamp = xtime;
+			do_gettimeofday(&sb->stamp);
 			vcc->push(vcc, sb);
 			atomic_inc(&vcc->stats->rx);
 
@@ -1177,7 +1177,7 @@
 
 			skb_trim(skb, len);
 			ATM_SKB(skb)->vcc = vcc;
-			skb->stamp = xtime;
+			do_gettimeofday(&skb->stamp);
 
 			vcc->push(vcc, skb);
 			atomic_inc(&vcc->stats->rx);
@@ -1199,7 +1199,7 @@
 
 		skb_trim(skb, len);
 		ATM_SKB(skb)->vcc = vcc;
-		skb->stamp = xtime;
+		do_gettimeofday(&skb->stamp);
 
 		vcc->push(vcc, skb);
 		atomic_inc(&vcc->stats->rx);
@@ -1337,7 +1337,7 @@
 		       ATM_CELL_PAYLOAD);
 
 		ATM_SKB(sb)->vcc = vcc;
-		sb->stamp = xtime;
+		do_gettimeofday(&sb->stamp);
 		vcc->push(vcc, sb);
 		atomic_inc(&vcc->stats->rx);
 
diff -Nru a/drivers/atm/lanai.c b/drivers/atm/lanai.c
--- a/drivers/atm/lanai.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/atm/lanai.c	Tue Oct  1 00:08:16 2002
@@ -1606,7 +1606,7 @@
 	}
 	skb_put(skb, size);
 	ATM_SKB(skb)->vcc = lvcc->rx.atmvcc;
-	skb->stamp = xtime;
+	do_gettimeofday(&skb->stamp);
 	vcc_rx_memcpy(skb->data, lvcc, size);
 	lvcc->rx.atmvcc->push(lvcc->rx.atmvcc, skb);
 	atomic_inc(&lvcc->rx.atmvcc->stats->rx);
diff -Nru a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c
--- a/drivers/atm/nicstar.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/atm/nicstar.c	Tue Oct  1 00:08:15 2002
@@ -2264,7 +2264,7 @@
          memcpy(sb->tail, cell, ATM_CELL_PAYLOAD);
          skb_put(sb, ATM_CELL_PAYLOAD);
          ATM_SKB(sb)->vcc = vcc;
-         sb->stamp = xtime;
+         do_gettimeofday(&sb->stamp);
          vcc->push(vcc, sb);
          atomic_inc(&vcc->stats->rx);
          cell += ATM_CELL_PAYLOAD;
@@ -2395,7 +2395,7 @@
             skb->destructor = ns_sb_destructor;
 #endif /* NS_USE_DESTRUCTORS */
             ATM_SKB(skb)->vcc = vcc;
-            skb->stamp = xtime;
+            do_gettimeofday(&skb->stamp);
             vcc->push(vcc, skb);
             atomic_inc(&vcc->stats->rx);
          }
@@ -2422,7 +2422,7 @@
                sb->destructor = ns_sb_destructor;
 #endif /* NS_USE_DESTRUCTORS */
                ATM_SKB(sb)->vcc = vcc;
-               sb->stamp = xtime;
+               do_gettimeofday(&sb->stamp);
                vcc->push(vcc, sb);
                atomic_inc(&vcc->stats->rx);
             }
@@ -2448,7 +2448,7 @@
                memcpy(skb->data, sb->data, NS_SMBUFSIZE);
                skb_put(skb, len - NS_SMBUFSIZE);
                ATM_SKB(skb)->vcc = vcc;
-               skb->stamp = xtime;
+               do_gettimeofday(&skb->stamp);
                vcc->push(vcc, skb);
                atomic_inc(&vcc->stats->rx);
             }
@@ -2554,7 +2554,7 @@
 #ifdef NS_USE_DESTRUCTORS
             hb->destructor = ns_hb_destructor;
 #endif /* NS_USE_DESTRUCTORS */
-            hb->stamp = xtime;
+            do_gettimeofday(&hb->stamp);
             vcc->push(vcc, hb);
             atomic_inc(&vcc->stats->rx);
          }
diff -Nru a/drivers/atm/zatm.c b/drivers/atm/zatm.c
--- a/drivers/atm/zatm.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/atm/zatm.c	Tue Oct  1 00:08:16 2002
@@ -584,7 +584,7 @@
 #ifdef CONFIG_ATM_ZATM_EXACT_TS
 		skb->stamp = exact_time(zatm_dev,here[1]);
 #else
-		skb->stamp = xtime;
+		do_gettimeofday(&skb->stamp);
 #endif
 #if 0
 printk("[-3..0] 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n",((unsigned *) skb->data)[-3],
diff -Nru a/drivers/base/hotplug.c b/drivers/base/hotplug.c
--- a/drivers/base/hotplug.c	Tue Oct  1 00:08:14 2002
+++ b/drivers/base/hotplug.c	Tue Oct  1 00:08:14 2002
@@ -18,6 +18,7 @@
 #include <linux/kmod.h>
 #include <linux/interrupt.h>
 #include "base.h"
+#include "fs/fs.h"
 
 /*
  * hotplugging invokes what /proc/sys/kernel/hotplug says (normally
@@ -32,14 +33,16 @@
 int dev_hotplug (struct device *dev, const char *action)
 {
 	char *argv [3], **envp, *buffer, *scratch;
+	char *dev_path;
 	int retval;
 	int i = 0;
+	int dev_length;
 
 	pr_debug ("%s\n", __FUNCTION__);
 	if (!dev)
 		return -ENODEV;
 
-	if (!dev->bus || !dev->bus->hotplug)
+	if (!dev->bus)
 		return -ENODEV;
 
 	if (!hotplug_path [0])
@@ -66,6 +69,18 @@
 		return -ENOMEM;
 	}
 
+	dev_length = get_devpath_length (dev);
+	dev_length += strlen("root");
+	dev_path = kmalloc (dev_length, GFP_KERNEL);
+	if (!dev_path) {
+		kfree (buffer);
+		kfree (envp);
+		return -ENOMEM;
+	}
+	memset (dev_path, 0x00, dev_length);
+	strcpy (dev_path, "root");
+	fill_devpath (dev, dev_path, dev_length);
+
 	/* only one standardized param to hotplug command: the bus name */
 	argv [0] = hotplug_path;
 	argv [1] = dev->bus->name;
@@ -77,26 +92,33 @@
 
 	scratch = buffer;
 
-	/* action:  add, remove */
 	envp [i++] = scratch;
 	scratch += sprintf (scratch, "ACTION=%s", action) + 1;
 
-	/* have the bus specific function set up the rest of the environment */
-	retval = dev->bus->hotplug (dev, &envp[i], NUM_ENVP - i,
-				    scratch, BUFFER_SIZE - (scratch - buffer));
-	if (retval) {
-		pr_debug ("%s - hotplug() returned %d\n", __FUNCTION__, retval);
-		goto exit;
+	envp [i++] = scratch;
+	scratch += sprintf (scratch, "DEVICE=%s", dev_path) + 1;
+	
+	if (dev->bus->hotplug) {
+		/* have the bus specific function add its stuff */
+		retval = dev->bus->hotplug (dev, &envp[i], NUM_ENVP - i,
+					    scratch,
+					    BUFFER_SIZE - (scratch - buffer));
+		if (retval) {
+			pr_debug ("%s - hotplug() returned %d\n",
+				  __FUNCTION__, retval);
+			goto exit;
+		}
 	}
 
 	pr_debug ("%s: %s %s %s %s %s %s\n", __FUNCTION__, argv [0], argv[1],
-		  action, envp[0], envp[1], envp[2]);
+		  envp[0], envp[1], envp[2], envp[3]);
 	retval = call_usermodehelper (argv [0], argv, envp);
 	if (retval)
 		pr_debug ("%s - call_usermodehelper returned %d\n",
 			  __FUNCTION__, retval);
 
 exit:
+	kfree (dev_path);
 	kfree (buffer);
 	kfree (envp);
 	return retval;
diff -Nru a/drivers/block/DAC960.c b/drivers/block/DAC960.c
--- a/drivers/block/DAC960.c	Tue Oct  1 00:08:18 2002
+++ b/drivers/block/DAC960.c	Tue Oct  1 00:08:18 2002
@@ -1930,16 +1930,10 @@
 static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller)
 {
   int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber;
-  char *names;
   RequestQueue_T *RequestQueue;
   int MinorNumber;
   int n;
 
-  names = kmalloc(9 * DAC960_MaxLogicalDrives, GFP_KERNEL);
-  if (!names) {
-      DAC960_Error("out of memory", Controller);
-      return false;
-  }
   /*
     Register the Block Device Major Number for this DAC960 Controller.
   */
@@ -1948,7 +1942,6 @@
     {
       DAC960_Error("UNABLE TO ACQUIRE MAJOR NUMBER %d - DETACHING\n",
 		   Controller, MajorNumber);
-      kfree(names);
       return false;
     }
   /*
@@ -1967,10 +1960,9 @@
   for (n = 0; n < DAC960_MaxLogicalDrives; n++) {
 	struct gendisk *disk = &Controller->disks[n];
 	memset(disk, 0, sizeof(struct gendisk));
-	sprintf(names + 9 * n, "rd/c%dd%d", Controller->ControllerNumber, n);
+	sprintf(disk->disk_name, "rd/c%dd%d", Controller->ControllerNumber, n);
 	disk->major = MajorNumber;
 	disk->first_minor = n << DAC960_MaxPartitionsBits;
-	disk->major_name = names + 9 * n;
 	disk->minor_shift = DAC960_MaxPartitionsBits;
 	disk->fops = &DAC960_BlockDeviceOperations;
    }
@@ -1990,10 +1982,8 @@
 {
   int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber;
   int disk;
-  for (disk = 0; disk < DAC960_MaxLogicalDrives; disk++) {
+  for (disk = 0; disk < DAC960_MaxLogicalDrives; disk++)
 	  del_gendisk(&Controller->disks[disk]);
-	  kfree(Controller->disks[0].major_name);
-  }
   /*
     Unregister the Block Device Major Number for this DAC960 Controller.
   */
diff -Nru a/drivers/block/acsi.c b/drivers/block/acsi.c
--- a/drivers/block/acsi.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/block/acsi.c	Tue Oct  1 00:08:17 2002
@@ -245,7 +245,6 @@
 unsigned long 	phys_acsi_buffer;
 
 static int NDevices;
-static char acsi_names[MAX_DEV*4];
 static int access_count[MAX_DEV];
 
 static int				CurrentNReq;
@@ -1692,10 +1691,9 @@
 					 
 	for( i = 0; i < NDevices; ++i ) {
 		struct gendisk *disk = acsi_gendisk + i;
-		sprintf(acsi_names + 4*i, "ad%c", 'a'+i);
+		sprintf(disk->disk_name, "ad%c", 'a'+i);
 		disk->major = MAJOR_NR;
 		disk->first_minor = i << 4;
-		disk->major_name = acsi_names + 4*i;
 		disk->minor_shift = (acsi_info[i].type==HARDDISK)?4:0;
 		disk->fops = &acsi_fops;
 		set_capacity(disk, acsi_info[i].size);
diff -Nru a/drivers/block/amiflop.c b/drivers/block/amiflop.c
--- a/drivers/block/amiflop.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/block/amiflop.c	Tue Oct  1 00:08:17 2002
@@ -151,7 +151,6 @@
 
 /* current info on each unit */
 static struct amiga_floppy_struct unit[FD_MAX_UNITS];
-static char names[FD_MAX_UNITS][4];
 
 static struct timer_list flush_track_timer[FD_MAX_UNITS];
 static struct timer_list post_write_timer;
@@ -1747,8 +1746,7 @@
 			disk->first_minor = drive;
 			disk->minor_shift = 0;
 			disk->fops = &floppy_fops;
-			sprintf(names[drive], "fd%d", drive);
-			disk->major_name = names[drive];
+			sprintf(disk->disk_name, "fd%d", drive);
 			set_capacity(disk, 880*2);
 			add_disk(disk);
 		}
diff -Nru a/drivers/block/ataflop.c b/drivers/block/ataflop.c
--- a/drivers/block/ataflop.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/block/ataflop.c	Tue Oct  1 00:08:15 2002
@@ -236,7 +236,6 @@
 				   disk change detection) */
 	int flags;		/* flags */
 	struct gendisk disk;
-	char name[4];
 } unit[FD_MAX_UNITS];
 
 #define	UD	unit[drive]
@@ -1976,8 +1975,7 @@
 		unit[i].flags = 0;
 		unit[i].disk.major = MAJOR_NR;
 		unit[i].disk.first_minor = i;
-		sprintf(unit[i].name, "fd%d", i);
-		unit[i].disk.major_name = names[drive];
+		sprintf(unit[i].disk.disk_name, "fd%d", i);
 		unit[i].disk.fops = &floppy_fops;
 		set_capacity(&unit[i].disk, MAX_DISK_SIZE * 2);
 		add_disk(&unit[i].disk);
diff -Nru a/drivers/block/blkpg.c b/drivers/block/blkpg.c
--- a/drivers/block/blkpg.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/block/blkpg.c	Tue Oct  1 00:08:15 2002
@@ -69,8 +69,7 @@
 	struct gendisk *g;
 	long long ppstart, pplength;
 	long pstart, plength;
-	int i;
-	kdev_t dev = to_kdev_t(bdev->bd_dev);
+	int part, i;
 
 	/* convert bytes to sectors, check for fit in a hd_struct */
 	ppstart = (p->start >> 9);
@@ -82,7 +81,7 @@
 		return -EINVAL;
 
 	/* find the drive major */
-	g = get_gendisk(dev);
+	g = get_gendisk(bdev->bd_dev, &part);
 	if (!g)
 		return -ENXIO;
 
@@ -91,6 +90,8 @@
 	/* drive and partition number OK? */
 	if (bdev != bdev->bd_contains)
 		return -EINVAL;
+	if (part)
+		BUG();
 	if (p->pno <= 0 || p->pno >= (1 << g->minor_shift))
 		return -EINVAL;
 
@@ -123,17 +124,19 @@
  */
 int del_partition(struct block_device *bdev, struct blkpg_partition *p)
 {
-	kdev_t dev = to_kdev_t(bdev->bd_dev);
 	struct gendisk *g;
 	struct block_device *bdevp;
+	int part;
 	int holder;
 
 	/* find the drive major */
-	g = get_gendisk(dev);
+	g = get_gendisk(bdev->bd_dev, &part);
 	if (!g)
 		return -ENXIO;
 	if (bdev != bdev->bd_contains)
 		return -EINVAL;
+	if (part)
+		BUG();
 	if (p->pno <= 0 || p->pno >= (1 << g->minor_shift))
   		return -EINVAL;
 
@@ -142,7 +145,7 @@
 		return -ENXIO;
 
 	/* partition in use? Incomplete check for now. */
-	bdevp = bdget(MKDEV(major(dev), minor(dev) + p->pno));
+	bdevp = bdget(MKDEV(g->major, g->first_minor + p->pno));
 	if (!bdevp)
 		return -ENOMEM;
 	if (bd_claim(bdevp, &holder) < 0) {
diff -Nru a/drivers/block/cciss.c b/drivers/block/cciss.c
--- a/drivers/block/cciss.c	Tue Oct  1 00:08:21 2002
+++ b/drivers/block/cciss.c	Tue Oct  1 00:08:21 2002
@@ -740,10 +740,8 @@
 
 	for(i=0; i< NWD; i++) {
 		struct gendisk *disk = &hba[ctlr]->gendisk[i];
-		if (disk->major_name) {
+		if (disk->part)
 			del_gendisk(disk);
-			disk->major_name = NULL;
-		}
 	}
 
         /*
@@ -768,7 +766,6 @@
 		if (!drv->nr_blocks)
 			continue;
 		(BLK_DEFAULT_QUEUE(MAJOR_NR + ctlr))->hardsect_size = drv->block_size;
-		disk->major_name = hba[ctlr]->names + 12 * i;
 		set_capacity(disk, drv->nr_blocks);
 		add_disk(disk);
 	}
@@ -795,10 +792,8 @@
 	spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
 
 	/* invalidate the devices and deregister the disk */ 
-	if (disk->major_name) {
+	if (disk->part)
 		del_gendisk(disk);
-		disk->major_name = NULL;
-	}
 	/* check to see if it was the last disk */
 	if (logvol == h->highest_lun) {
 		/* if so, find the new hightest lun */
@@ -1237,7 +1232,6 @@
 	++hba[ctlr]->num_luns;
 	/* setup partitions per disk */
         disk = &hba[ctlr]->gendisk[logvol];
-	disk->major_name = hba[ctlr]->names + 12 * logvol;
 	set_capacity(disk, hba[ctlr]->drv[logvol].nr_blocks);
 	add_disk(disk);
 	
@@ -2433,15 +2427,13 @@
 		drive_info_struct *drv = &(hba[i]->drv[j]);
 		struct gendisk *disk = hba[i]->gendisk + j;
 
-		sprintf(hba[i]->names + 12 * j, "cciss/c%dd%d", i, j);
+		sprintf(disk->disk_name, "cciss/c%dd%d", i, j);
 		disk->major = MAJOR_NR + i;
 		disk->first_minor = j << NWD_SHIFT;
-		disk->major_name = NULL;
 		disk->minor_shift = NWD_SHIFT;
 		if( !(drv->nr_blocks))
 			continue;
 		(BLK_DEFAULT_QUEUE(MAJOR_NR + i))->hardsect_size = drv->block_size;
-		disk->major_name = hba[i]->names + 12 * j;
 		set_capacity(disk, drv->nr_blocks);
 		add_disk(disk);
 	}
@@ -2491,10 +2483,8 @@
 	/* remove it from the disk list */
 	for (j = 0; j < NWD; j++) {
 		struct gendisk *disk = &hba[i]->gendisk[j];
-		if (disk->major_name) {
+		if (disk->part)
 			del_gendisk(disk);
-			disk->major_name = NULL;
-		}
 	}
 
 	pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof(CommandList_struct),
diff -Nru a/drivers/block/cciss.h b/drivers/block/cciss.h
--- a/drivers/block/cciss.h	Tue Oct  1 00:08:14 2002
+++ b/drivers/block/cciss.h	Tue Oct  1 00:08:14 2002
@@ -82,7 +82,6 @@
 
 	// Disk structures we need to pass back
 	struct gendisk   gendisk[NWD];
-	char names[12 * NWD];
 #ifdef CONFIG_CISS_SCSI_TAPE
 	void *scsi_ctlr; /* ptr to structure containing scsi related stuff */
 #endif
diff -Nru a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
--- a/drivers/block/cpqarray.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/block/cpqarray.c	Tue Oct  1 00:08:15 2002
@@ -102,7 +102,6 @@
 	{ 0x40580E11, "Smart Array 431",	&smart4_access },
 };
 
-static char *ida_names;
 static struct gendisk ida_gendisk[MAX_CTLR * NWD];
 
 static struct proc_dir_entry *proc_array;
@@ -313,13 +312,12 @@
 		kfree(hba[i]->cmd_pool_bits);
 
 		for (j = 0; j < NWD; j++) {
-			if (ida_gendisk[i*NWD+j].major_name)
+			if (ida_gendisk[i*NWD+j].part)
 				del_gendisk(&ida_gendisk[i*NWD+j]);
 		}
 	}
 	devfs_find_and_unregister(NULL, "ida", 0, 0, 0, 0);
 	remove_proc_entry("cpqarray", proc_root_driver);
-	kfree(ida_names);
 }
 #endif /* MODULE */
 
@@ -344,12 +342,6 @@
 	printk("Found %d controller(s)\n", nr_ctlr);
 
 	/* allocate space for disk structs */
-	ida_names = kmalloc(nr_ctlr*NWD*10, GFP_KERNEL);
-	if (!ida_names) {
-		printk( KERN_ERR "cpqarray: out of memory");
-		kfree(ida_names);
-		return(num_cntlrs_reg);
-	}
 	/* 
 	 * register block devices
 	 * Find disks and fill in structs
@@ -399,11 +391,6 @@
 			 *	init_module will fail, so clean up global 
 			 *	memory that clean_module would do.
 			*/	
-	
-			if (num_cntlrs_reg == 0) 
-			{
-				kfree(ida_names);
-			}
                 	return(num_cntlrs_reg);
 	
 		}
@@ -439,7 +426,7 @@
 		for(j=0; j<NWD; j++) {
 			struct gendisk *disk = ida_gendisk + i*NWD + j;
 			drv_info_t *drv = &hba[i]->drv[j];
-			sprintf(ida_names + (i*NWD+j)*10, "ida/c%dd%d", i, j);
+			sprintf(disk->disk_name, "ida/c%dd%d", i, j);
 			disk->major = MAJOR_NR + i;
 			disk->first_minor = j<<NWD_SHIFT;
 			disk->minor_shift = NWD_SHIFT;
@@ -447,7 +434,6 @@
 			disk->fops = &ida_fops; 
 			if (!drv->nr_blks)
 				continue;
-			disk->major_name = ida_names + (i*NWD+j)*10;
 			(BLK_DEFAULT_QUEUE(MAJOR_NR + i))->hardsect_size = drv->blk_size;
 			set_capacity(disk, drv->nr_blks);
 			add_disk(disk);
@@ -1449,10 +1435,8 @@
 	 */
 	for (i = 0; i < NWD; i++) {
 		struct gendisk *disk = ida_gendisk + ctlr*NWD + i;
-		if (!disk->major_name)
-			continue;
-		del_gendisk(disk);
-		disk->major_name = NULL;
+		if (disk->part)
+			del_gendisk(disk);
 	}
 	memset(hba[ctlr]->drv,            0, sizeof(drv_info_t)*NWD);
 
@@ -1471,7 +1455,6 @@
 		if (!drv->nr_blks)
 			continue;
 		(BLK_DEFAULT_QUEUE(MAJOR_NR + ctlr))->hardsect_size = drv->blk_size;
-		disk->major_name = ida_names + (ctlr*NWD+i)*10;
 		set_capacity(disk, drv->nr_blks);
 		add_disk(disk);
 	}
diff -Nru a/drivers/block/floppy.c b/drivers/block/floppy.c
--- a/drivers/block/floppy.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/block/floppy.c	Tue Oct  1 00:08:15 2002
@@ -777,7 +777,7 @@
 				DPRINT("Disk type is undefined after "
 				       "disk change\n");
 			current_type[drive] = NULL;
-			floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE;
+			floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE << 1;
 		}
 
 		/*USETF(FD_DISK_NEWCHANGE);*/
@@ -1009,8 +1009,7 @@
 static void schedule_bh( void (*handler)(void*) )
 {
 	floppy_tq.routine = (void *)(void *) handler;
-	queue_task(&floppy_tq, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
+	schedule_task(&floppy_tq);
 }
 
 static struct timer_list fd_timer;
@@ -2425,8 +2424,7 @@
 				return;
 			}
 			current_type[current_drive] = _floppy;
-			floppy_sizes[TOMINOR(current_drive) ]= 
-				(_floppy->size+1)>>1;
+			floppy_sizes[TOMINOR(current_drive) ]= _floppy->size;
 			break;
 	}
 
@@ -2435,7 +2433,7 @@
 			DPRINT("Auto-detected floppy type %s in fd%d\n",
 				_floppy->name,current_drive);
 		current_type[current_drive] = _floppy;
-		floppy_sizes[TOMINOR(current_drive)] = (_floppy->size+1) >> 1;
+		floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
 		probing = 0;
 	}
 
@@ -3344,7 +3342,7 @@
 		floppy_type[type].name="user format";
 		for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
 			floppy_sizes[cnt]= floppy_sizes[cnt+0x80]=
-				(floppy_type[type].size+1)>>1;
+				floppy_type[type].size+1;
 		process_fd_request();
 		for (cnt = 0; cnt < N_DRIVE; cnt++){
 			if (ITYPE(drive_state[cnt].fd_device) == type &&
@@ -3363,7 +3361,7 @@
 		if (buffer_drive == drive)
 			SUPBOUND(buffer_max, user_params[drive].sect);
 		current_type[drive] = &user_params[drive];
-		floppy_sizes[drive] = (user_params[drive].size+1) >> 1;
+		floppy_sizes[drive] = user_params[drive].size;
 		if (cmd == FDDEFPRM)
 			DRS->keep_data = -1;
 		else
@@ -3537,7 +3535,7 @@
 		case FDCLRPRM:
 			LOCK_FDC(drive,1);
 			current_type[drive] = NULL;
-			floppy_sizes[drive] = MAX_DISK_SIZE;
+			floppy_sizes[drive] = MAX_DISK_SIZE << 1;
 			UDRS->keep_data = 0;
 			return invalidate_drive(inode->i_bdev);
 		case FDSETPRM:
@@ -3711,11 +3709,6 @@
 	int try;
 	char *tmp;
 
-	if (!filp) {
-		DPRINT("Weird, open called with filp=0\n");
-		return -EIO;
-	}
-
 	filp->private_data = (void*) 0;
 
 	drive = DRIVE(inode->i_rdev);
@@ -3926,6 +3919,7 @@
 #define NO_GEOM (!current_type[drive] && !TYPE(dev))
 	int drive=DRIVE(dev);
 	int cf;
+	int res = 0;
 
 	if (UTESTF(FD_DISK_CHANGED) ||
 	    UTESTF(FD_VERIFY) ||
@@ -3951,14 +3945,15 @@
 			UDRS->generation++;
 		if (NO_GEOM){
 			/* auto-sensing */
-			return floppy_read_block_0(dev);
+			res = floppy_read_block_0(dev);
+		} else {
+			if (cf)
+				poll_drive(0, FD_RAW_NEED_DISK);
+			process_fd_request();
 		}
-		if (cf)
-			poll_drive(0, FD_RAW_NEED_DISK);
-		process_fd_request();
 	}
 	set_capacity(&disks[drive], floppy_sizes[minor(dev)]);
-	return 0;
+	return res;
 }
 
 static struct block_device_operations floppy_fops = {
@@ -4254,17 +4249,16 @@
 		disks[i].major = MAJOR_NR;
 		disks[i].first_minor = TOMINOR(i);
 		disks[i].fops = &floppy_fops;
-		sprintf(names[i], "fd%d", i);
-		disks[i].major_name = names[i];
+		sprintf(disks[i].disk_name, "fd%d", i);
 	}
 
 	blk_set_probe(MAJOR_NR, floppy_find);
 
 	for (i=0; i<256; i++)
 		if (ITYPE(i))
-			floppy_sizes[i] = (floppy_type[ITYPE(i)].size+1) >> 1;
+			floppy_sizes[i] = floppy_type[ITYPE(i)].size;
 		else
-			floppy_sizes[i] = MAX_DISK_SIZE;
+			floppy_sizes[i] = MAX_DISK_SIZE << 1;
 
 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_fd_request, &floppy_lock);
 	reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT);
@@ -4361,7 +4355,7 @@
 	if (have_no_fdc) 
 	{
 		DPRINT("no floppy controllers found\n");
-		run_task_queue(&tq_immediate);
+		flush_scheduled_tasks();
 		if (usage_count)
 			floppy_release_irq_and_dma();
 		blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
diff -Nru a/drivers/block/genhd.c b/drivers/block/genhd.c
--- a/drivers/block/genhd.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/block/genhd.c	Tue Oct  1 00:08:17 2002
@@ -31,7 +31,7 @@
 /*
  * Global kernel list of partitioning information.
  */
-static struct gendisk *gendisk_head;
+static LIST_HEAD(gendisk_list);
 
 /*
  *  TEMPORARY KLUDGE.
@@ -66,7 +66,7 @@
 		p = kmalloc(size, GFP_KERNEL);
 		if (!p) {
 			printk(KERN_ERR "out of memory; no partitions for %s\n",
-				gp->major_name);
+				gp->disk_name);
 			gp->minor_shift = 0;
 		} else
 			memset(p, 0, size);
@@ -75,16 +75,17 @@
 
 	write_lock(&gendisk_lock);
 	list_add(&gp->list, &gendisks[gp->major].list);
-	gp->next = gendisk_head;
-	gendisk_head = gp;
+	if (gp->minor_shift)
+		list_add_tail(&gp->full_list, &gendisk_list);
+	else
+		INIT_LIST_HEAD(&gp->full_list);
 	write_unlock(&gendisk_lock);
 }
 
 void add_disk(struct gendisk *disk)
 {
 	add_gendisk(disk);
-	register_disk(disk, mk_kdev(disk->major, disk->first_minor),
-			1<<disk->minor_shift, disk->fops, get_capacity(disk));
+	register_disk(disk);
 }
 
 EXPORT_SYMBOL(add_disk);
@@ -92,13 +93,8 @@
 
 void unlink_gendisk(struct gendisk *disk)
 {
-	struct gendisk **p;
 	write_lock(&gendisk_lock);
-	for (p = &gendisk_head; *p; p = &((*p)->next))
-		if (*p == disk)
-			break;
-	if (*p)
-		*p = (*p)->next;
+	list_del_init(&disk->full_list);
 	list_del_init(&disk->list);
 	write_unlock(&gendisk_lock);
 }
@@ -111,13 +107,14 @@
  * information for the given device @dev.
  */
 struct gendisk *
-get_gendisk(kdev_t dev)
+get_gendisk(dev_t dev, int *part)
 {
 	struct gendisk *disk;
 	struct list_head *p;
-	int major = major(dev);
-	int minor = minor(dev);
+	int major = MAJOR(dev);
+	int minor = MINOR(dev);
 
+	*part = 0;
 	read_lock(&gendisk_lock);
 	if (gendisks[major].get) {
 		disk = gendisks[major].get(minor);
@@ -131,6 +128,7 @@
 		if (disk->first_minor + (1<<disk->minor_shift) <= minor)
 			continue;
 		read_unlock(&gendisk_lock);
+		*part = minor - disk->first_minor;
 		return disk;
 	}
 	read_unlock(&gendisk_lock);
@@ -143,21 +141,21 @@
 /* iterator */
 static void *part_start(struct seq_file *part, loff_t *pos)
 {
-	loff_t k = *pos;
-	struct gendisk *sgp;
+	struct list_head *p;
+	loff_t l = *pos;
 
 	read_lock(&gendisk_lock);
-	for (sgp = gendisk_head; sgp; sgp = sgp->next) {
-		if (!k--)
-			return sgp;
-	}
+	list_for_each(p, &gendisk_list)
+		if (!l--)
+			return list_entry(p, struct gendisk, full_list);
 	return NULL;
 }
 
 static void *part_next(struct seq_file *part, void *v, loff_t *pos)
 {
+	struct list_head *p = ((struct gendisk *)v)->full_list.next;
 	++*pos;
-	return ((struct gendisk *)v)->next;
+	return p==&gendisk_list ? NULL : list_entry(p, struct gendisk, full_list);
 }
 
 static void part_stop(struct seq_file *part, void *v)
@@ -171,11 +169,11 @@
 	int n;
 	char buf[64];
 
-	if (sgp == gendisk_head)
+	if (&sgp->full_list == gendisk_list.next)
 		seq_puts(part, "major minor  #blocks  name\n\n");
 
 	/* Don't show non-partitionable devices or empty devices */
-	if (!sgp->minor_shift || !get_capacity(sgp))
+	if (!get_capacity(sgp))
 		return 0;
 
 	/* show the full disk and all non-0 size partitions of it */
@@ -238,3 +236,18 @@
 __initcall(device_init);
 
 EXPORT_SYMBOL(disk_devclass);
+
+struct gendisk *alloc_disk(void)
+{
+	struct gendisk *disk = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
+	if (disk)
+		memset(disk, 0, sizeof(struct gendisk));
+	return disk;
+}
+
+void put_disk(struct gendisk *disk)
+{
+	kfree(disk);
+}
+EXPORT_SYMBOL(alloc_disk);
+EXPORT_SYMBOL(put_disk);
diff -Nru a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
--- a/drivers/block/ll_rw_blk.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/block/ll_rw_blk.c	Tue Oct  1 00:08:15 2002
@@ -151,12 +151,42 @@
 	return ret;
 }
 
+/**
+ * blk_queue_prep_rq - set a prepare_request function for queue
+ * @q:		queue
+ * @pfn:	prepare_request function
+ *
+ * It's possible for a queue to register a prepare_request callback which
+ * is invoked before the request is handed to the request_fn. The goal of
+ * the function is to prepare a request for I/O, it can be used to build a
+ * cdb from the request data for instance.
+ *
+ */
 void blk_queue_prep_rq(request_queue_t *q, prep_rq_fn *pfn)
 {
 	q->prep_rq_fn = pfn;
 }
 
 /**
+ * blk_queue_merge_bvec - set a merge_bvec function for queue
+ * @q:		queue
+ * @mbfn:	merge_bvec_fn
+ *
+ * Usually queues have static limitations on the max sectors or segments that
+ * we can put in a request. Stacking drivers may have some settings that
+ * are dynamic, and thus we have to query the queue whether it is ok to
+ * add a new bio_vec to a bio at a given offset or not. If the block device
+ * has such limitations, it needs to register a merge_bvec_fn to control
+ * the size of bio's sent to it. Per default now merge_bvec_fn is defined for
+ * a queue, and only the fixed limits are honored.
+ *
+ */
+void blk_queue_merge_bvec(request_queue_t *q, merge_bvec_fn *mbfn)
+{
+	q->merge_bvec_fn = mbfn;
+}
+
+/**
  * blk_queue_make_request - define an alternate make_request function for a device
  * @q:  the request queue for the device to be affected
  * @mfn: the alternate make_request function
@@ -1796,7 +1826,11 @@
 			break;
 		}
 
-		BUG_ON(bio_sectors(bio) > q->max_sectors);
+		if (unlikely(bio_sectors(bio) > q->max_sectors)) {
+			printk("bio too big (%u > %u)\n", bio_sectors(bio),
+							q->max_sectors);
+			goto end_io;
+		}
 
 		/*
 		 * If this device has partitions, remap block n
@@ -1805,8 +1839,6 @@
 		blk_partition_remap(bio);
 
 		ret = q->make_request_fn(q, bio);
-		blk_put_queue(q);
-
 	} while (ret);
 }
 
@@ -2057,6 +2089,7 @@
 EXPORT_SYMBOL(blk_insert_request);
 
 EXPORT_SYMBOL(blk_queue_prep_rq);
+EXPORT_SYMBOL(blk_queue_merge_bvec);
 
 EXPORT_SYMBOL(blk_queue_find_tag);
 EXPORT_SYMBOL(blk_queue_init_tags);
diff -Nru a/drivers/block/loop.c b/drivers/block/loop.c
--- a/drivers/block/loop.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/block/loop.c	Tue Oct  1 00:08:17 2002
@@ -84,7 +84,6 @@
 static int max_loop = 8;
 static struct loop_device *loop_dev;
 static struct gendisk *disks;
-static char *names;
 static devfs_handle_t devfs_handle;      /*  For the directory */
 
 /*
@@ -500,15 +499,13 @@
 static int loop_make_request(request_queue_t *q, struct bio *old_bio)
 {
 	struct bio *new_bio = NULL;
-	struct loop_device *lo;
+	struct loop_device *lo = q->queuedata;
 	unsigned long IV;
 	int rw = bio_rw(old_bio);
-	int unit = minor(to_kdev_t(old_bio->bi_bdev->bd_dev));
 
-	if (unit >= max_loop)
+	if (!lo)
 		goto out;
 
-	lo = &loop_dev[unit];
 	spin_lock_irq(&lo->lo_lock);
 	if (lo->lo_state != Lo_bound)
 		goto inactive;
@@ -598,10 +595,10 @@
 					   hence, it mustn't be stopped at all because it could
 					   be indirectly used during suspension */
 
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	sigfillset(&current->blocked);
 	flush_signals(current);
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	set_user_nice(current, -20);
 
@@ -712,6 +709,29 @@
 	set_blocksize(bdev, block_size(lo_device));
 
 	lo->lo_bio = lo->lo_biotail = NULL;
+
+	/*
+	 * set queue make_request_fn, and add limits based on lower level
+	 * device
+	 */
+	blk_queue_make_request(&lo->lo_queue, loop_make_request);
+	blk_queue_bounce_limit(&lo->lo_queue, BLK_BOUNCE_HIGH);
+	lo->lo_queue.queuedata = lo;
+
+	/*
+	 * we remap to a block device, make sure we correctly stack limits
+	 */
+	if (S_ISBLK(inode->i_mode)) {
+		request_queue_t *q = bdev_get_queue(lo_device);
+
+		blk_queue_max_sectors(&lo->lo_queue, q->max_sectors);
+		blk_queue_max_phys_segments(&lo->lo_queue,q->max_phys_segments);
+		blk_queue_max_hw_segments(&lo->lo_queue, q->max_hw_segments);
+		blk_queue_max_segment_size(&lo->lo_queue, q->max_segment_size);
+		blk_queue_segment_boundary(&lo->lo_queue, q->seg_boundary_mask);
+		blk_queue_merge_bvec(&lo->lo_queue, q->merge_bvec_fn);
+	}
+
 	kernel_thread(loop_thread, lo, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
 	down(&lo->lo_sem);
 
@@ -785,6 +805,7 @@
 	lo->lo_offset = 0;
 	lo->lo_encrypt_key_size = 0;
 	lo->lo_flags = 0;
+	lo->lo_queue.queuedata = NULL;
 	memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE);
 	memset(lo->lo_name, 0, LO_NAME_SIZE);
 	invalidate_bdev(bdev, 0);
@@ -991,6 +1012,16 @@
 EXPORT_SYMBOL(loop_register_transfer);
 EXPORT_SYMBOL(loop_unregister_transfer);
 
+request_queue_t *loop_get_queue(kdev_t dev)
+{
+	int minor = minor(dev);
+
+	if (minor < max_loop)
+		return &loop_dev[minor].lo_queue;
+
+	return NULL;
+}
+
 int __init loop_init(void) 
 {
 	int	i;
@@ -1021,11 +1052,6 @@
 	if (!disks)
 		goto out_mem;
 
-	names = kmalloc(max_loop * 8, GFP_KERNEL);
-
-	blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), loop_make_request);
-	blk_queue_bounce_limit(BLK_DEFAULT_QUEUE(MAJOR_NR), BLK_BOUNCE_HIGH);
-
 	for (i = 0; i < max_loop; i++) {
 		struct loop_device *lo = &loop_dev[i];
 		struct gendisk *disk = disks + i;
@@ -1039,16 +1065,16 @@
 		disk->major = LOOP_MAJOR;
 		disk->first_minor = i;
 		disk->fops = &lo_fops;
-		sprintf(names + 8*i, "loop%d", i);
-		disk->major_name = names + 8 * i;
+		sprintf(disk->disk_name, "loop%d", i);
 		add_disk(disk);
 	}
 
+	blk_dev[LOOP_MAJOR].queue = loop_get_queue;
+
 	printk(KERN_INFO "loop: loaded (max %d devices)\n", max_loop);
 	return 0;
 
 out_mem:
-	kfree(names);
 	kfree(disks);
 	kfree(loop_dev);
 	printk(KERN_ERR "loop: ran out of memory\n");
@@ -1064,7 +1090,6 @@
 	if (unregister_blkdev(MAJOR_NR, "loop"))
 		printk(KERN_WARNING "loop: cannot unregister blkdev\n");
 
-	kfree(names);
 	kfree(disks);
 	kfree(loop_dev);
 }
diff -Nru a/drivers/block/nbd.c b/drivers/block/nbd.c
--- a/drivers/block/nbd.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/block/nbd.c	Tue Oct  1 00:08:16 2002
@@ -60,7 +60,6 @@
 static int nbd_blksizes[MAX_NBD];
 static int nbd_blksize_bits[MAX_NBD];
 static u64 nbd_bytesizes[MAX_NBD];
-static char nbd_names[MAX_NBD][7];
 
 static struct nbd_device nbd_dev[MAX_NBD];
 static devfs_handle_t devfs_handle;
@@ -101,11 +100,11 @@
 	oldfs = get_fs();
 	set_fs(get_ds());
 
-	spin_lock_irqsave(&current->sigmask_lock, flags);
+	spin_lock_irqsave(&current->sig->siglock, flags);
 	oldset = current->blocked;
 	sigfillset(&current->blocked);
 	recalc_sigpending();
-	spin_unlock_irqrestore(&current->sigmask_lock, flags);
+	spin_unlock_irqrestore(&current->sig->siglock, flags);
 
 
 	do {
@@ -137,10 +136,10 @@
 		buf += result;
 	} while (size > 0);
 
-	spin_lock_irqsave(&current->sigmask_lock, flags);
+	spin_lock_irqsave(&current->sig->siglock, flags);
 	current->blocked = oldset;
 	recalc_sigpending();
-	spin_unlock_irqrestore(&current->sigmask_lock, flags);
+	spin_unlock_irqrestore(&current->sig->siglock, flags);
 
 	set_fs(oldfs);
 	return result;
@@ -531,8 +530,7 @@
 		disk->first_minor = i;
 		disk->minor_shift = 0;
 		disk->fops = &nbd_fops;
-		sprintf(nbd_names[i], "nbd%d", i);
-		disk->major_name = nbd_names[i];
+		sprintf(disk->disk_name, "nbd%d", i);
 		set_capacity(disk, 0x3ffffe);
 		add_disk(disk);
 	}
diff -Nru a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c
--- a/drivers/block/paride/pcd.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/block/paride/pcd.c	Tue Oct  1 00:08:17 2002
@@ -301,7 +301,7 @@
 		disk->major = major;
 		disk->first_minor = unit;
 		disk->minor_shift = 0;
-		disk->major_name = cd->name;
+		strcpy(disk->disk_name, cd->name);	/* umm... */
 		disk->fops = &pcd_bdops;
 	}
 }
diff -Nru a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
--- a/drivers/block/paride/pd.c	Tue Oct  1 00:08:19 2002
+++ b/drivers/block/paride/pd.c	Tue Oct  1 00:08:19 2002
@@ -717,7 +717,7 @@
 	}
 	for (unit = 0, disk = pd; unit < PD_UNITS; unit++, disk++) {
 		if (disk->present) {
-			disk->gd.major_name = disk->name;
+			strcpy(disk->gd.disk_name, disk->name);
 			disk->gd.minor_shift = PD_BITS;
 			disk->gd.fops = &pd_fops;
 			disk->gd.major = major;
diff -Nru a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c
--- a/drivers/block/paride/pf.c	Tue Oct  1 00:08:18 2002
+++ b/drivers/block/paride/pf.c	Tue Oct  1 00:08:18 2002
@@ -316,7 +316,7 @@
 		snprintf(pf->name, PF_NAMELEN, "%s%d", name, unit);
 		disk->major = MAJOR_NR;
 		disk->first_minor = unit;
-		disk->major_name = pf->name;
+		strcpy(disk->disk_name, pf->name);
 		disk->minor_shift = 0;
 		disk->fops = &pf_fops;
 		if (!(*drives[unit])[D_PRT])
diff -Nru a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c
--- a/drivers/block/ps2esdi.c	Tue Oct  1 00:08:13 2002
+++ b/drivers/block/ps2esdi.c	Tue Oct  1 00:08:13 2002
@@ -148,14 +148,14 @@
 static struct gendisk ps2esdi_gendisk[2] = {
 {
 	major:		MAJOR_NR,
-	major_name:	"eda",
+	disk_name:	"eda",
 	first_minor:	0,
 	minor_shift:	6,
 	fops:		&ps2esdi_fops,
 },{
 	major:		MAJOR_NR,
 	first_minor:	64,
-	major_name:	"edb",
+	disk_name:	"edb",
 	minor_shift:	6,
 	fops:		&ps2esdi_fops,
 }
diff -Nru a/drivers/block/rd.c b/drivers/block/rd.c
--- a/drivers/block/rd.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/block/rd.c	Tue Oct  1 00:08:17 2002
@@ -78,7 +78,6 @@
 
 static unsigned long rd_length[NUM_RAMDISKS];	/* Size of RAM disks in bytes   */
 static struct gendisk rd_disks[NUM_RAMDISKS];
-static char rd_names[NUM_RAMDISKS][5];
 static devfs_handle_t devfs_handle;
 static struct block_device *rd_bdev[NUM_RAMDISKS];/* Protected device data */
 
@@ -316,7 +315,7 @@
 	.first_minor = INITRD_MINOR,
 	.minor_shift = 0,
 	.fops = &rd_bd_op,	
-	.major_name = "initrd"
+	.disk_name = "initrd"
 };
 
 static ssize_t initrd_read(struct file *file, char *buf,
@@ -447,8 +446,7 @@
 		disk->first_minor = 0;
 		disk->minor_shift = 0;
 		disk->fops = &rd_bd_op;
-		sprintf(rd_names[i], "rd%d", i);
-		disk->major_name = rd_names[i];
+		sprintf(disk->disk_name, "rd%d", i);
 		set_capacity(disk, rd_size * 2);
 	}
 	devfs_handle = devfs_mk_dir (NULL, "rd", NULL);
diff -Nru a/drivers/block/swim3.c b/drivers/block/swim3.c
--- a/drivers/block/swim3.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/block/swim3.c	Tue Oct  1 00:08:16 2002
@@ -39,7 +39,6 @@
 #include <linux/devfs_fs_kernel.h>
 
 static struct gendisk disks[2];
-static char names[2][4];
 
 #define MAX_FLOPPIES	2
 
@@ -1046,8 +1045,7 @@
 			disk->major = MAJOR_NR;
 			disk->first_minor = i;
 			disk->fops = &floppy_fops;
-			sprintf(names[i], "fd%d", i);
-			disk->major_name = names[i];
+			sprintf(disk->disk_name, "fd%d", i);
 			set_capacity(disk, 2880);
 			add_disk(disk);
 		}
diff -Nru a/drivers/block/swim_iop.c b/drivers/block/swim_iop.c
--- a/drivers/block/swim_iop.c	Tue Oct  1 00:08:14 2002
+++ b/drivers/block/swim_iop.c	Tue Oct  1 00:08:14 2002
@@ -84,7 +84,6 @@
 static struct floppy_state floppy_states[MAX_FLOPPIES];
 
 static struct gendisk disks[2];
-static char names[2][4];
 
 static spinlock_t swim_iop_lock = SPIN_LOCK_UNLOCKED;
 
@@ -197,8 +196,7 @@
 		disk->major = MAJOR_NR;
 		disk->first_minor = i;
 		disk->fops = &floppy_fops;
-		sprintf(names[i], "fd%d", i);
-		disk->major_name = names[i];
+		sprintf(disk->disk_name, "fd%d", i);
 		set_capacity(disk, 2880 * 2);
 		add_disk(disk);
 	}
diff -Nru a/drivers/block/umem.c b/drivers/block/umem.c
--- a/drivers/block/umem.c	Tue Oct  1 00:08:21 2002
+++ b/drivers/block/umem.c	Tue Oct  1 00:08:21 2002
@@ -162,7 +162,6 @@
 static int num_cards = 0;
 
 static struct gendisk mm_gendisk[MM_MAXCARDS];
-static char mm_names[MM_MAXCARDS * 6];
 
 static void check_batteries(struct cardinfo *card);
 
@@ -1192,11 +1191,10 @@
 	blk_dev[MAJOR_NR].queue = mm_queue_proc;
 	for (i = 0; i < num_cards; i++) {
 		struct gendisk *disk = mm_gendisk + i;
-		sprintf(mm_names + i*6, "umem%c", 'a'+i);
+		sprintf(disk->disk_name, "umem%c", 'a'+i);
 		spin_lock_init(&cards[i].lock);
 		disk->major = major_nr;
 		disk->first_minor  = i << MM_SHIFT;
-		disk->major_name = mm_names + i*6;
 		disk->minor_shift = MM_SHIFT;
 		disk->fops = &mm_fops;
 		set_capacity(disk, cards[i].mm_size << 1);
diff -Nru a/drivers/block/xd.c b/drivers/block/xd.c
--- a/drivers/block/xd.c	Tue Oct  1 00:08:19 2002
+++ b/drivers/block/xd.c	Tue Oct  1 00:08:19 2002
@@ -129,13 +129,13 @@
 {
 	.major =	MAJOR_NR,
 	.first_minor =	0,
-	.major_name =	"xda",
+	.disk_name =	"xda",
 	.minor_shift =	6,
 	.fops =		&xd_fops,
 },{
 	.major =	MAJOR_NR,
 	.first_minor =	64,
-	.major_name =	"xdb",
+	.disk_name =	"xdb",
 	.minor_shift =	6,
 	.fops =		&xd_fops,
 }
diff -Nru a/drivers/block/z2ram.c b/drivers/block/z2ram.c
--- a/drivers/block/z2ram.c	Tue Oct  1 00:08:18 2002
+++ b/drivers/block/z2ram.c	Tue Oct  1 00:08:18 2002
@@ -76,7 +76,7 @@
 	.first_minor = 0,
 	.minor_shift = 0,
 	.fops = &z2_fops,
-	.major_name = "z2ram"
+	.disk_name = "z2ram"
 };
 
 static void
diff -Nru a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
--- a/drivers/bluetooth/bt3c_cs.c	Tue Oct  1 00:08:21 2002
+++ b/drivers/bluetooth/bt3c_cs.c	Tue Oct  1 00:08:21 2002
@@ -528,19 +528,19 @@
 	}
 
 	/* Block signals, everything but SIGKILL/SIGSTOP */
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	tmpsig = current->blocked;
 	siginitsetinv(&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP));
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	result = waitpid(pid, NULL, __WCLONE);
 
 	/* Allow signals again */
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	current->blocked = tmpsig;
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	if (result != pid) {
 		printk(KERN_WARNING "bt3c_cs: Waiting for pid %d failed (errno=%d).\n", pid, -result);
diff -Nru a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c
--- a/drivers/bluetooth/hci_usb.c	Tue Oct  1 00:08:20 2002
+++ b/drivers/bluetooth/hci_usb.c	Tue Oct  1 00:08:20 2002
@@ -633,19 +633,19 @@
 	}
 
 	/* Block signals, everything but SIGKILL/SIGSTOP */
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	tmpsig = current->blocked;
 	siginitsetinv(&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP));
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	result = waitpid(pid, NULL, __WCLONE);
 
 	/* Allow signals again */
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	current->blocked = tmpsig;
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	if (result != pid) {
 		BT_ERR("waitpid failed pid %d errno %d\n", pid, -result);
diff -Nru a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c
--- a/drivers/cdrom/aztcd.c	Tue Oct  1 00:08:20 2002
+++ b/drivers/cdrom/aztcd.c	Tue Oct  1 00:08:20 2002
@@ -1695,7 +1695,7 @@
 	.first_minor = 0,
 	.minor_shift = 0,
 	.fops = &azt_fops,
-	.major_name = "aztcd"
+	.disk_name = "aztcd"
 };
 
 /*
diff -Nru a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c
--- a/drivers/cdrom/cdu31a.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/cdrom/cdu31a.c	Tue Oct  1 00:08:15 2002
@@ -3192,7 +3192,7 @@
 	.major		= MAJOR_NR,
 	.first_minor	= 0,
 	.minor_shift	= 0,
-	.major_name	= "cdu31a",
+	.disk_name	= "cdu31a",
 	.fops		= &scd_bdops,
 	.flags		= GENHD_FL_CD,
 };
diff -Nru a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c
--- a/drivers/cdrom/cm206.c	Tue Oct  1 00:08:20 2002
+++ b/drivers/cdrom/cm206.c	Tue Oct  1 00:08:20 2002
@@ -1361,7 +1361,7 @@
 	.major		= MAJOR_NR,
 	.first_minor	= 0,
 	.minor_shift	= 0,
-	.major_name	= "cm206",
+	.disk_name	= "cm206",
 	.fops		= &cm206_bdops,
 	.flags		= GENHD_FL_CD,
 };
diff -Nru a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c
--- a/drivers/cdrom/gscd.c	Tue Oct  1 00:08:14 2002
+++ b/drivers/cdrom/gscd.c	Tue Oct  1 00:08:14 2002
@@ -903,7 +903,7 @@
 	.first_minor = 0,
 	.minor_shift = 0,
 	.fops = &gscd_fops,
-	.major_name = "gscd"
+	.disk_name = "gscd"
 };
 
 static void __exit gscd_exit(void)
diff -Nru a/drivers/cdrom/mcd.c b/drivers/cdrom/mcd.c
--- a/drivers/cdrom/mcd.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/cdrom/mcd.c	Tue Oct  1 00:08:17 2002
@@ -225,7 +225,7 @@
 	.major		= MAJOR_NR,
 	.first_minor	= 0,
 	.minor_shift	= 0,
-	.major_name	= "mcd",
+	.disk_name	= "mcd",
 	.fops		= &mcd_bdops,
 	.flags		= GENHD_FL_CD,
 };
diff -Nru a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c
--- a/drivers/cdrom/mcdx.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/cdrom/mcdx.c	Tue Oct  1 00:08:17 2002
@@ -1210,7 +1210,7 @@
 	disk->major = MAJOR_NR;
 	disk->first_minor = drive;
 	disk->minor_shift = 0;
-	disk->major_name = stuffp->info.name;
+	strcpy(disk->disk_name, stuffp->info.name);
 	disk->fops = &mcdx_bdops;
 	disk->flags = GENHD_FL_CD;
 
diff -Nru a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c
--- a/drivers/cdrom/optcd.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/cdrom/optcd.c	Tue Oct  1 00:08:16 2002
@@ -2002,7 +2002,7 @@
 	.first_minor = 0,
 	.minor_shift = 0,
 	.fops = &opt_fops,
-	.major_name = "optcd"
+	.disk_name = "optcd"
 };
 
 /* Test for presence of drive and initialize it. Called at boot time
diff -Nru a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c
--- a/drivers/cdrom/sbpcd.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/cdrom/sbpcd.c	Tue Oct  1 00:08:15 2002
@@ -5835,7 +5835,7 @@
 		disk->first_minor = j;
 		disk->minor_shift = 0;
 		disk->fops = &sbpcd_bdops;
-		disk->major_name = sbpcd_infop->name;
+		strcpy(disk->disk_name, sbpcd_infop->name);
 		disk->flags = GENHD_FL_CD;
 		sprintf(nbuff, "c0t%d", p->drv_id);
 		disk->de = devfs_mk_dir(devfs_handle, nbuff, NULL);
diff -Nru a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c
--- a/drivers/cdrom/sjcd.c	Tue Oct  1 00:08:18 2002
+++ b/drivers/cdrom/sjcd.c	Tue Oct  1 00:08:18 2002
@@ -1670,7 +1670,7 @@
 	.first_minor = 0,
 	.minor_shift = 0,
 	.fops = &sjcd_fops,
-	.major_name = "sjcd"
+	.disk_name = "sjcd"
 };
 
 /*
diff -Nru a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c
--- a/drivers/cdrom/sonycd535.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/cdrom/sonycd535.c	Tue Oct  1 00:08:16 2002
@@ -1460,7 +1460,7 @@
 	.first_minor = 0,
 	.minor_shift = 0,
 	.fops = &cdu_fops,
-	.major_name = "cdu",
+	.disk_name = "cdu",
 };
 
 /*
diff -Nru a/drivers/char/drm/radeon_irq.c b/drivers/char/drm/radeon_irq.c
--- a/drivers/char/drm/radeon_irq.c	Tue Oct  1 00:08:20 2002
+++ b/drivers/char/drm/radeon_irq.c	Tue Oct  1 00:08:20 2002
@@ -69,8 +69,7 @@
 
 	atomic_inc(&dev_priv->irq_received);
 #ifdef __linux__
-	queue_task(&dev->tq, &tq_immediate);  
-	mark_bh(IMMEDIATE_BH);  
+	schedule_task(&dev->tq);
 #endif /* __linux__ */
 #ifdef __FreeBSD__
 	taskqueue_enqueue(taskqueue_swi, &dev->task);
diff -Nru a/drivers/char/ftape/lowlevel/fdc-io.c b/drivers/char/ftape/lowlevel/fdc-io.c
--- a/drivers/char/ftape/lowlevel/fdc-io.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/char/ftape/lowlevel/fdc-io.c	Tue Oct  1 00:08:16 2002
@@ -404,11 +404,11 @@
 	/* timeout time will be up to USPT microseconds too long ! */
 	timeout = (1000 * time + FT_USPT - 1) / FT_USPT;
 
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	old_sigmask = current->blocked;
 	sigfillset(&current->blocked);
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	current->state = TASK_INTERRUPTIBLE;
 	add_wait_queue(&ftape_wait_intr, &wait);
@@ -416,10 +416,10 @@
 		timeout = schedule_timeout(timeout);
         }
 
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	current->blocked = old_sigmask;
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 	
 	remove_wait_queue(&ftape_wait_intr, &wait);
 	/*  the following IS necessary. True: as well
diff -Nru a/drivers/char/i810-tco.c b/drivers/char/i810-tco.c
--- a/drivers/char/i810-tco.c	Tue Oct  1 00:08:14 2002
+++ b/drivers/char/i810-tco.c	Tue Oct  1 00:08:14 2002
@@ -1,5 +1,5 @@
 /*
- *	i810-tco 0.04:	TCO timer driver for i8xx chipsets
+ *	i810-tco 0.05:	TCO timer driver for i8xx chipsets
  *
  *	(c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved.
  *				http://www.kernelconcepts.de
@@ -9,9 +9,9 @@
  *	as published by the Free Software Foundation; either version
  *	2 of the License, or (at your option) any later version.
  *	
- *	Neither kernel concepts nor Nils Faerber admit liability nor provide 
- *	warranty for any of this software. This material is provided 
- *	"AS-IS" and at no charge.	
+ *	Neither kernel concepts nor Nils Faerber admit liability nor provide
+ *	warranty for any of this software. This material is provided
+ *	"AS-IS" and at no charge.
  *
  *	(c) Copyright 2000	kernel concepts <nils@kernelconcepts.de>
  *				developed for
@@ -24,18 +24,25 @@
  *	(See the intel documentation on http://developer.intel.com.)
  *	82801AA & 82801AB  chip : document number 290655-003, 290677-004,
  *	82801BA & 82801BAM chip : document number 290687-002, 298242-005,
- *	82801CA & 82801CAM chip : document number 290716-001, 290718-001
+ *	82801CA & 82801CAM chip : document number 290716-001, 290718-001,
+ *	82801DB & 82801E   chip : document number 290744-001, 273599-001
  *
  *  20000710 Nils Faerber
  *	Initial Version 0.01
  *  20000728 Nils Faerber
- *      0.02 Fix for SMI_EN->TCO_EN bit, some cleanups
+ *	0.02 Fix for SMI_EN->TCO_EN bit, some cleanups
  *  20011214 Matt Domsch <Matt_Domsch@dell.com>
  *	0.03 Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
  *	     Didn't add timeout option as i810_margin already exists.
  *  20020224 Joel Becker, Wim Van Sebroeck
  *	0.04 Support for 82801CA(M) chipset, timer margin needs to be > 3,
  *	     add support for WDIOC_SETTIMEOUT and WDIOC_GETTIMEOUT.
+ *  20020412 Rob Radez <rob@osinvestor.com>, Wim Van Sebroeck
+ *	0.05 Fix possible timer_alive race, add expect close support,
+ *	     clean up ioctls (WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS and
+ *	     WDIOC_SETOPTIONS), made i810tco_getdevice __init,
+ *	     removed boot_status, removed tco_timer_read,
+ *	     added support for 82801DB and 82801E chipset, general cleanup.
  */
  
 #include <linux/module.h>
@@ -55,9 +62,9 @@
 
 
 /* Module and version information */
-#define TCO_VERSION "0.04"
+#define TCO_VERSION "0.05"
 #define TCO_MODULE_NAME "i810 TCO timer"
-#define TCO_DRIVER_NAME   TCO_MODULE_NAME " , " TCO_VERSION
+#define TCO_DRIVER_NAME   TCO_MODULE_NAME ", v" TCO_VERSION
 
 /* Default expire timeout */
 #define TIMER_MARGIN	50	/* steps of 0.6sec, 3<n<64. Default is 30 seconds */
@@ -67,9 +74,8 @@
 
 static int i810_margin = TIMER_MARGIN;	/* steps of 0.6sec */
 
-MODULE_PARM (i810_margin, "i");
-MODULE_PARM_DESC(i810_margin, "Watchdog timeout in steps of 0.6sec, 3<n<64. Default = 50 (30 seconds)");
-
+MODULE_PARM(i810_margin, "i");
+MODULE_PARM_DESC(i810_margin, "i810-tco timeout in steps of 0.6sec, 3<n<64. Default = 50 (30 seconds)");
 
 #ifdef CONFIG_WATCHDOG_NOWAYOUT
 static int nowayout = 1;
@@ -85,8 +91,8 @@
  *	Timer active flag
  */
 
-static int timer_alive;
-static int boot_status;
+static unsigned long timer_alive;
+static char tco_expect_close;
 
 /*
  * Some TCO specific functions
@@ -170,32 +176,19 @@
 }
 
 /*
- * Read the current timer value
- */
-static unsigned char tco_timer_read (void)
-{
-	return (inb (TCO1_RLD));
-}
-
-
-/*
  *	Allow only one person to hold it open
  */
 
 static int i810tco_open (struct inode *inode, struct file *file)
 {
-	if (timer_alive)
+	if (test_and_set_bit(0, &timer_alive))
 		return -EBUSY;
 
-	if (nowayout) {
-		MOD_INC_USE_COUNT;
-	}
 	/*
 	 *      Reload and activate timer
 	 */
 	tco_timer_reload ();
 	tco_timer_start ();
-	timer_alive = 1;
 	return 0;
 }
 
@@ -204,10 +197,14 @@
 	/*
 	 *      Shut off the timer.
 	 */
-	if (nowayout) {
+	if (tco_expect_close == 42 && !nowayout) {
 		tco_timer_stop ();
-		timer_alive = 0;
+	} else {
+		tco_timer_reload ();
+		printk(KERN_CRIT TCO_MODULE_NAME ": Unexpected close, not stopping watchdog!\n");
 	}
+	clear_bit(0, &timer_alive);
+	tco_expect_close = 0;
 	return 0;
 }
 
@@ -218,10 +215,22 @@
 	if (ppos != &file->f_pos)
 		return -ESPIPE;
 
-	/*
-	 *      Refresh the timer.
-	 */
+	/* See if we got the magic character 'V' and reload the timer */
 	if (len) {
+		size_t i;
+
+		tco_expect_close = 0;
+
+		/* scan to see wether or not we got the magic character */
+		for (i = 0; i != len; i++) {
+			u8 c;
+			if(get_user(c, data+i))
+				return -EFAULT;
+			if (c == 'V')
+				tco_expect_close = 42;
+		}
+
+		/* someone wrote to us, we should reload the timer */
 		tco_timer_reload ();
 		return 1;
 	}
@@ -232,41 +241,53 @@
 			  unsigned int cmd, unsigned long arg)
 {
 	int new_margin, u_margin;
+	int options, retval = -EINVAL;
 
 	static struct watchdog_info ident = {
-		WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
-		0,
-		"i810 TCO timer"
+		options:		WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+		firmware_version:	0,
+		identity:		"i810 TCO timer",
 	};
 	switch (cmd) {
-	default:
-		return -ENOTTY;
-	case WDIOC_GETSUPPORT:
-		if (copy_to_user
-		    ((struct watchdog_info *) arg, &ident, sizeof (ident)))
-			return -EFAULT;
-		return 0;
-	case WDIOC_GETSTATUS:
-		return put_user (tco_timer_read (),
-				 (unsigned int *) (int) arg);
-	case WDIOC_GETBOOTSTATUS:
-		return put_user (boot_status, (int *) arg);
-	case WDIOC_KEEPALIVE:
-		tco_timer_reload ();
-		return 0;
-	case WDIOC_SETTIMEOUT:
-		if (get_user(u_margin, (int *) arg))
-			return -EFAULT;
-		new_margin = (u_margin * 10 + 5) / 6;
-		if ((new_margin < 4) || (new_margin > 63))
-			return -EINVAL;
-		if (tco_timer_settimer((unsigned char)new_margin))
-		    return -EINVAL;
-		i810_margin = new_margin;
-		tco_timer_reload();
-		/* Fall */
-	case WDIOC_GETTIMEOUT:
-		return put_user((int)(i810_margin * 6 / 10), (int *) arg);
+		default:
+			return -ENOTTY;
+		case WDIOC_GETSUPPORT:
+			if (copy_to_user
+			    ((struct watchdog_info *) arg, &ident, sizeof (ident)))
+				return -EFAULT;
+			return 0;
+		case WDIOC_GETSTATUS:
+		case WDIOC_GETBOOTSTATUS:
+			return put_user (0, (int *) arg);
+		case WDIOC_SETOPTIONS:
+			if (get_user (options, (int *) arg))
+				return -EFAULT;
+			if (options & WDIOS_DISABLECARD) {
+				tco_timer_stop ();
+				retval = 0;
+			}
+			if (options & WDIOS_ENABLECARD) {
+				tco_timer_reload ();
+				tco_timer_start ();
+				retval = 0;
+			}
+			return retval;
+		case WDIOC_KEEPALIVE:
+			tco_timer_reload ();
+			return 0;
+		case WDIOC_SETTIMEOUT:
+			if (get_user (u_margin, (int *) arg))
+				return -EFAULT;
+			new_margin = (u_margin * 10 + 5) / 6;
+			if ((new_margin < 4) || (new_margin > 63))
+				return -EINVAL;
+			if (tco_timer_settimer ((unsigned char) new_margin))
+			    return -EINVAL;
+			i810_margin = new_margin;
+			tco_timer_reload ();
+			/* Fall */
+		case WDIOC_GETTIMEOUT:
+			return put_user ((int)(i810_margin * 6 / 10), (int *) arg);
 	}
 }
 
@@ -285,13 +306,15 @@
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10,	PCI_ANY_ID, PCI_ANY_ID, },
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0,	PCI_ANY_ID, PCI_ANY_ID, },
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12,	PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0,	PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0,	PCI_ANY_ID, PCI_ANY_ID, },
 	{ 0, },
 };
 MODULE_DEVICE_TABLE (pci, i810tco_pci_tbl);
 
 static struct pci_dev *i810tco_pci;
 
-static unsigned char i810tco_getdevice (void)
+static unsigned char __init i810tco_getdevice (void)
 {
 	struct pci_dev *dev;
 	u8 val1, val2;
@@ -341,7 +364,6 @@
 		outb (val1, SMI_EN + 1);
 		/* Clear out the (probably old) status */
 		outb (0, TCO1_STS);
-		boot_status = (int) inb (TCO2_STS);
 		outb (3, TCO2_STS);
 		return 1;
 	}
@@ -357,9 +379,9 @@
 };
 
 static struct miscdevice i810tco_miscdev = {
-	WATCHDOG_MINOR,
-	"watchdog",
-	&i810tco_fops
+	minor:		WATCHDOG_MINOR,
+	name:		"watchdog",
+	fops:		&i810tco_fops,
 };
 
 static int __init watchdog_init (void)
@@ -382,8 +404,8 @@
 	tco_timer_reload ();
 
 	printk (KERN_INFO TCO_DRIVER_NAME
-		": timer margin: %d sec (0x%04x)\n",
-		(int) (i810_margin * 6 / 10), TCOBASE);
+		": timer margin: %d sec (0x%04x) (nowayout=%d)\n",
+		(int) (i810_margin * 6 / 10), TCOBASE, nowayout);
 	return 0;
 }
 
@@ -404,4 +426,6 @@
 module_init(watchdog_init);
 module_exit(watchdog_cleanup);
 
+MODULE_AUTHOR("Nils Faerber");
+MODULE_DESCRIPTION("TCO timer driver for i8xx chipsets");
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/char/i810-tco.h b/drivers/char/i810-tco.h
--- a/drivers/char/i810-tco.h	Tue Oct  1 00:08:15 2002
+++ b/drivers/char/i810-tco.h	Tue Oct  1 00:08:15 2002
@@ -1,5 +1,5 @@
 /*
- *	i810-tco 0.04:	TCO timer driver for i8xx chipsets
+ *	i810-tco 0.05:	TCO timer driver for i8xx chipsets
  *
  *	(c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved.
  *				http://www.kernelconcepts.de
@@ -9,9 +9,9 @@
  *	as published by the Free Software Foundation; either version
  *	2 of the License, or (at your option) any later version.
  *	
- *	Neither kernel concepts nor Nils Faerber admit liability nor provide 
- *	warranty for any of this software. This material is provided 
- *	"AS-IS" and at no charge.	
+ *	Neither kernel concepts nor Nils Faerber admit liability nor provide
+ *	warranty for any of this software. This material is provided
+ *	"AS-IS" and at no charge.
  *
  *	(c) Copyright 2000	kernel concepts <nils@kernelconcepts.de>
  *				developed for
@@ -20,13 +20,8 @@
  *	TCO timer driver for i8xx chipsets
  *	based on softdog.c by Alan Cox <alan@redhat.com>
  *
- *	The TCO timer is implemented in the following I/O controller hubs:
- *	(See the intel documentation on http://developer.intel.com.)
- *	82801AA & 82801AB  chip : document number 290655-003, 290677-004,
- *	82801BA & 82801BAM chip : document number 290687-002, 298242-005,
- *	82801CA & 82801CAM chip : document number 290716-001, 290718-001
- *
- *	For history see i810-tco.c
+ *	For history and the complete list of supported I/O Controller Hub's
+ *	see i810-tco.c
  */
 
 
diff -Nru a/drivers/char/random.c b/drivers/char/random.c
--- a/drivers/char/random.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/char/random.c	Tue Oct  1 00:08:15 2002
@@ -649,7 +649,7 @@
  * Changes to the entropy data is put into a queue rather than being added to
  * the entropy counts directly.  This is presumably to avoid doing heavy
  * hashing calculations during an interrupt in add_timer_randomness().
- * Instead, the entropy is only added to the pool once per timer tick.
+ * Instead, the entropy is only added to the pool by keventd.
  */
 void batch_entropy_store(u32 a, u32 b, int num)
 {
@@ -664,7 +664,8 @@
 
 	new = (batch_head+1) & (batch_max-1);
 	if (new != batch_tail) {
-		queue_task(&batch_tqueue, &tq_timer);
+		// FIXME: is this correct?
+		schedule_task(&batch_tqueue);
 		batch_head = new;
 	} else {
 		DEBUG_ENT("batch entropy buffer full\n");
diff -Nru a/drivers/char/toshiba.c b/drivers/char/toshiba.c
--- a/drivers/char/toshiba.c	Tue Oct  1 00:08:20 2002
+++ b/drivers/char/toshiba.c	Tue Oct  1 00:08:20 2002
@@ -84,8 +84,6 @@
 
 MODULE_PARM(tosh_fn, "i");
 
-MODULE_LICENSE("GPL");
-
 
 static int tosh_get_info(char *, char **, off_t, int);
 static int tosh_ioctl(struct inode *, struct file *, unsigned int,
@@ -517,3 +515,10 @@
 	misc_deregister(&tosh_device);
 }
 #endif
+
+MODULE_LICENSE("GPL");
+MODULE_PARM_DESC(tosh_fn, "User specified Fn key detection port");
+MODULE_AUTHOR("Jonathan Buzzard <jonathan@buzzard.org.uk>");
+MODULE_DESCRIPTION("Toshiba laptop SMM driver");
+MODULE_SUPPORTED_DEVICE("toshiba");
+
diff -Nru a/drivers/char/tty_io.c b/drivers/char/tty_io.c
--- a/drivers/char/tty_io.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/char/tty_io.c	Tue Oct  1 00:08:17 2002
@@ -1265,7 +1265,6 @@
 	/*
 	 * Make sure that the tty's task queue isn't activated. 
 	 */
-	run_task_queue(&tq_timer);
 	flush_scheduled_tasks();
 
 	/* 
@@ -1876,7 +1875,6 @@
 
 /*
  * The tq handling here is a little racy - tty->SAK_tq may already be queued.
- * But there's no mechanism to fix that without futzing with tqueue_lock.
  * Fortunately we don't need to worry, because if ->SAK_tq is already queued,
  * the values which we write to it will be identical to the values which it
  * already has. --akpm
@@ -1902,7 +1900,7 @@
 	unsigned long flags;
 
 	if (test_bit(TTY_DONT_FLIP, &tty->flags)) {
-		queue_task(&tty->flip.tqueue, &tq_timer);
+		schedule_task(&tty->flip.tqueue);
 		return;
 	}
 	if (tty->flip.buf_num) {
@@ -1979,7 +1977,7 @@
 	if (tty->low_latency)
 		flush_to_ldisc((void *) tty);
 	else
-		queue_task(&tty->flip.tqueue, &tq_timer);
+		schedule_task(&tty->flip.tqueue);
 }
 
 /*
diff -Nru a/drivers/ide/Config.help b/drivers/ide/Config.help
--- a/drivers/ide/Config.help	Tue Oct  1 00:08:19 2002
+++ b/drivers/ide/Config.help	Tue Oct  1 00:08:19 2002
@@ -292,7 +292,7 @@
   motherboard uses a VIA VP2 chipset, in which case you should say N.
 
 CONFIG_IDEDMA_IVB
-  There are unclear terms is ATA-4 and ATA-5 standards how certain
+  There are unclear terms in ATA-4 and ATA-5 standards how certain
   hardware (an 80c ribbon) should be detected. Different interpretations
   of the standards have been released in hardware. This causes problems:
   for example, a host with Ultra Mode 4 (or higher) will not run
diff -Nru a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
--- a/drivers/ide/ide-probe.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/ide/ide-probe.c	Tue Oct  1 00:08:17 2002
@@ -954,41 +954,35 @@
  */
 static void init_gendisk (ide_hwif_t *hwif)
 {
-	struct gendisk *gd;
-	unsigned int unit, units, minors;
+	unsigned int unit, units;
 	extern devfs_handle_t ide_devfs_handle;
-	char *names;
+	struct gendisk *disks[MAX_DRIVES];
 
 	units = MAX_DRIVES;
 
-	minors    = units * (1<<PARTN_BITS);
-	gd        = kmalloc(MAX_DRIVES * sizeof(struct gendisk), GFP_KERNEL);
-	if (!gd)
-		goto err_kmalloc_gd;
-	memset(gd, 0, MAX_DRIVES * sizeof(struct gendisk));
-
-	names = kmalloc(4 * MAX_DRIVES, GFP_KERNEL);
-	if (!names)
-		goto err_kmalloc_gd_names;
-	memset(names, 0, 4 * MAX_DRIVES);
+	for (unit = 0; unit < MAX_DRIVES; unit++) {
+		disks[unit] = alloc_disk();
+		if (!disks[unit])
+			goto err_kmalloc_gd;
+	}
 
 	for (unit = 0; unit < units; ++unit) {
-		gd[unit].major  = hwif->major;
-		gd[unit].first_minor = unit << PARTN_BITS;
-		sprintf(names + 4*unit, "hd%c",'a'+hwif->index*MAX_DRIVES+unit);
-		gd[unit].major_name = names + 4*unit;
-		gd[unit].minor_shift = PARTN_BITS; 
-		gd[unit].fops = ide_fops;
+		struct gendisk *disk = disks[unit];
+		disk->major  = hwif->major;
+		disk->first_minor = unit << PARTN_BITS;
+		sprintf(disk->disk_name,"hd%c",'a'+hwif->index*MAX_DRIVES+unit);
+		disk->minor_shift = PARTN_BITS; 
+		disk->fops = ide_fops;
 
-		snprintf(gd[unit].disk_dev.bus_id,BUS_ID_SIZE,"%u.%u",
+		snprintf(disk->disk_dev.bus_id,BUS_ID_SIZE,"%u.%u",
 			 hwif->index,unit);
-		snprintf(gd[unit].disk_dev.name,DEVICE_NAME_SIZE,
+		snprintf(disk->disk_dev.name,DEVICE_NAME_SIZE,
 			 "%s","IDE Drive");
-		gd[unit].disk_dev.parent = &hwif->gendev;
-		gd[unit].disk_dev.bus = &ide_bus_type;
-		device_register(&gd[unit].disk_dev);
+		disk->disk_dev.parent = &hwif->gendev;
+		disk->disk_dev.bus = &ide_bus_type;
+		device_register(&disk->disk_dev);
 
-		hwif->drives[unit].disk = gd + unit;
+		hwif->drives[unit].disk = disk;
 	}
 
 	for (unit = 0; unit < units; ++unit) {
@@ -1003,10 +997,10 @@
 	}
 	return;
 
-err_kmalloc_gd_names:
-	kfree(gd);
 err_kmalloc_gd:
 	printk(KERN_WARNING "(ide::init_gendisk) Out of memory\n");
+	while (unit--)
+		put_disk(disks[unit]);
 }
 
 EXPORT_SYMBOL(init_gendisk);
diff -Nru a/drivers/ide/ide.c b/drivers/ide/ide.c
--- a/drivers/ide/ide.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/ide/ide.c	Tue Oct  1 00:08:16 2002
@@ -1741,7 +1741,6 @@
 
 void ide_unregister (unsigned int index)
 {
-	struct gendisk *gd;
 	ide_drive_t *drive, *d;
 	ide_hwif_t *hwif, *g;
 	ide_hwgroup_t *hwgroup;
@@ -1863,12 +1862,10 @@
 	unregister_blkdev(hwif->major, hwif->name);
 	blk_dev[hwif->major].data = NULL;
 	blk_dev[hwif->major].queue = NULL;
-	gd = hwif->drives[0].disk;
-	if (gd) {
-		int i;
-		for (i = 0; i < MAX_DRIVES; i++)
-			hwif->drives[i].disk = NULL;
-		kfree(gd);
+	for (i = 0; i < MAX_DRIVES; i++) {
+		struct gendisk *disk = hwif->drives[i].disk;
+		hwif->drives[i].disk = NULL;
+		put_disk(disk);
 	}
 	old_hwif			= *hwif;
 	init_hwif_data(index);	/* restore hwif data to pristine status */
diff -Nru a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c
--- a/drivers/ide/legacy/hd.c	Tue Oct  1 00:08:13 2002
+++ b/drivers/ide/legacy/hd.c	Tue Oct  1 00:08:13 2002
@@ -695,13 +695,13 @@
 {
 	.major =	MAJOR_NR,
 	.first_minor =	0,
-	.major_name =	"hda",
+	.disk_name =	"hda",
 	.minor_shift =	6,
 	.fops =		&hd_fops,
 },{
 	.major =	MAJOR_NR,
 	.first_minor =	64,
-	.major_name =	"hdb",
+	.disk_name =	"hdb",
 	.minor_shift =	6,
 	.fops =		&hd_fops,
 }
@@ -810,7 +810,7 @@
 		sector_t size = hd_info[drive].head *
 			hd_info[drive].sect * hd_info[drive].cyl;
 		set_capacity(hd_gendisk + drive, size);
-		printk ("%s: %ldMB, CHS=%d/%d/%d\n", hd_gendisk[drive].major_name,
+		printk ("%s: %ldMB, CHS=%d/%d/%d\n", hd_gendisk[drive].disk_name,
 			size / 2048, hd_info[drive].cyl,
 			hd_info[drive].head, hd_info[drive].sect);
 	}
diff -Nru a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
--- a/drivers/ide/setup-pci.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/ide/setup-pci.c	Tue Oct  1 00:08:17 2002
@@ -331,6 +331,17 @@
 		} else
 			printk(KERN_WARNING "%s: Not fully BIOS configured!\n", d->name);
 	}
+
+	/*
+	 * assume all devices can do 32-bit dma for now. we can add a
+	 * dma mask field to the ide_pci_device_t if we need it (or let
+	 * lower level driver set the dma mask)
+	 */
+	if (pci_set_dma_mask(dev, 0xffffffff)) {
+		printk(KERN_ERR "%s: can't set dma mask\n", d->name);
+		return -EBUSY;
+	}
+	 
 	/* FIXME: Temporary - until we put in the hotplug interface logic
 	   Check that the bits we want are not in use by someone else */
 	if (pci_request_region(dev, 4, "ide_tmp"))
diff -Nru a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c
--- a/drivers/input/keyboard/sunkbd.c	Tue Oct  1 00:08:13 2002
+++ b/drivers/input/keyboard/sunkbd.c	Tue Oct  1 00:08:13 2002
@@ -106,8 +106,7 @@
 	switch (data) {
 
 		case SUNKBD_RET_RESET:
-			queue_task(&sunkbd->tq, &tq_immediate);
-			mark_bh(IMMEDIATE_BH);
+			schedule_task(&sunkbd->tq);
 			sunkbd->reset = -1;
 			return;
 
diff -Nru a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c
--- a/drivers/input/serio/sa1111ps2.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/input/serio/sa1111ps2.c	Tue Oct  1 00:08:17 2002
@@ -15,20 +15,26 @@
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
 
-#include <asm/hardware/sa1111.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/system.h>
 
+#include <asm/hardware/sa1111.h>
+
 extern struct pt_regs *kbd_pt_regs;
 
 struct ps2if {
-	struct serio	io;
-	struct resource	*res;
-	unsigned long	base;
-	unsigned int	irq;
-	unsigned int	skpcr_mask;
+	struct serio		io;
+	struct sa1111_dev	*dev;
+	unsigned long		base;
+	unsigned int		open;
+	spinlock_t		lock;
+	unsigned int		head;
+	unsigned int		tail;
+	unsigned char		buf[4];
 };
 
 /*
@@ -36,104 +42,150 @@
  * at the most one, but we loop for safety.  If there was a
  * framing error, we have to manually clear the status.
  */
-static void ps2_int(int irq, void *dev_id, struct pt_regs *regs)
+static void ps2_rxint(int irq, void *dev_id, struct pt_regs *regs)
 {
-	struct ps2if *sa = dev_id;
+	struct ps2if *ps2if = dev_id;
 	unsigned int scancode, flag, status;
 
 	kbd_pt_regs = regs;
 
-	status = sa1111_readl(sa->base + SA1111_PS2STAT);
+	status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
 	while (status & PS2STAT_RXF) {
 		if (status & PS2STAT_STP)
-			sa1111_writel(PS2STAT_STP, sa->base + SA1111_PS2STAT);
+			sa1111_writel(PS2STAT_STP, ps2if->base + SA1111_PS2STAT);
 
 		flag = (status & PS2STAT_STP ? SERIO_FRAME : 0) |
 		       (status & PS2STAT_RXP ? 0 : SERIO_PARITY);
 
-		scancode = sa1111_readl(sa->base + SA1111_PS2DATA) & 0xff;
+		scancode = sa1111_readl(ps2if->base + SA1111_PS2DATA) & 0xff;
 
 		if (hweight8(scancode) & 1)
 			flag ^= SERIO_PARITY;
 
-		serio_interrupt(&sa->io, scancode, flag);
+		serio_interrupt(&ps2if->io, scancode, flag);
 
-               	status = sa1111_readl(sa->base + SA1111_PS2STAT);
+               	status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
         }
 }
 
 /*
+ * Completion of ps2 write
+ */
+static void ps2_txint(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct ps2if *ps2if = dev_id;
+	unsigned int status;
+
+	spin_lock(&ps2if->lock);
+	status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
+	if (ps2if->head == ps2if->tail) {
+		disable_irq(irq);
+		/* done */
+	} else if (status & PS2STAT_TXE) {
+		sa1111_writel(ps2if->buf[ps2if->tail], ps2if->base + SA1111_PS2DATA);
+		ps2if->tail = (ps2if->tail + 1) & (sizeof(ps2if->buf) - 1);
+	}
+	spin_unlock(&ps2if->lock);
+}
+
+/*
  * Write a byte to the PS2 port.  We have to wait for the
  * port to indicate that the transmitter is empty.
  */
 static int ps2_write(struct serio *io, unsigned char val)
 {
-	struct ps2if *sa = io->driver;
-	unsigned int timeleft = 10000; /* timeout in 100ms */
+	struct ps2if *ps2if = io->driver;
+	unsigned long flags;
+	unsigned int head;
 
-	while ((sa1111_readl(sa->base + SA1111_PS2STAT) & PS2STAT_TXE) == 0 &&
-	       timeleft--)
-		udelay(10);
+	spin_lock_irqsave(&ps2if->lock, flags);
 
-	if (timeleft)
-		sa1111_writel(val, sa->base + SA1111_PS2DATA);
+	/*
+	 * If the TX register is empty, we can go straight out.
+	 */
+	if (sa1111_readl(ps2if->base + SA1111_PS2STAT) & PS2STAT_TXE) {
+		sa1111_writel(val, ps2if->base + SA1111_PS2DATA);
+	} else {
+		if (ps2if->head == ps2if->tail)
+			enable_irq(ps2if->dev->irq[1]);
+		head = (ps2if->head + 1) & (sizeof(ps2if->buf) - 1);
+		if (head != ps2if->tail) {
+			ps2if->buf[ps2if->head] = val;
+			ps2if->head = head;
+		}
+	}
 
-	return timeleft ? 0 : SERIO_TIMEOUT;
+	spin_unlock_irqrestore(&ps2if->lock, flags);
+	return 0;
 }
 
 static int ps2_open(struct serio *io)
 {
-	struct ps2if *sa = io->driver;
+	struct ps2if *ps2if = io->driver;
 	int ret;
 
-	sa1111_enable_device(sa->skpcr_mask);
+	sa1111_enable_device(ps2if->dev);
 
-	ret = request_irq(sa->irq, ps2_int, 0, "ps2", sa);
+	ret = request_irq(ps2if->dev->irq[0], ps2_rxint, 0,
+			  SA1111_DRIVER_NAME(ps2if->dev), ps2if);
 	if (ret) {
 		printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n",
-			sa->irq, ret);
+			ps2if->dev->irq[0], ret);
 		return ret;
 	}
 
-	sa1111_writel(PS2CR_ENA, sa->base + SA1111_PS2CR);
+	ret = request_irq(ps2if->dev->irq[1], ps2_txint, 0,
+			  SA1111_DRIVER_NAME(ps2if->dev), ps2if);
+	if (ret) {
+		printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n",
+			ps2if->dev->irq[1], ret);
+		free_irq(ps2if->dev->irq[0], ps2if);
+		return ret;
+	}
 
+	ps2if->open = 1;
+
+	sa1111_writel(PS2CR_ENA, ps2if->base + SA1111_PS2CR);
 	return 0;
 }
 
 static void ps2_close(struct serio *io)
 {
-	struct ps2if *sa = io->driver;
+	struct ps2if *ps2if = io->driver;
+
+	sa1111_writel(0, ps2if->base + SA1111_PS2CR);
 
-	sa1111_writel(0, sa->base + SA1111_PS2CR);
+	ps2if->open = 0;
 
-	free_irq(sa->irq, sa);
+	free_irq(ps2if->dev->irq[1], ps2if);
+	free_irq(ps2if->dev->irq[0], ps2if);
 
-	sa1111_disable_device(sa->skpcr_mask);
+	sa1111_disable_device(ps2if->dev);
 }
 
 /*
  * Clear the input buffer.
  */
-static void __init ps2_clear_input(struct ps2if *sa)
+static void __init ps2_clear_input(struct ps2if *ps2if)
 {
 	int maxread = 100;
 
 	while (maxread--) {
-		if ((sa1111_readl(sa->base + SA1111_PS2DATA) & 0xff) == 0xff)
+		if ((sa1111_readl(ps2if->base + SA1111_PS2DATA) & 0xff) == 0xff)
 			break;
 	}
 }
 
 static inline unsigned int
-ps2_test_one(struct ps2if *sa, unsigned int mask)
+ps2_test_one(struct ps2if *ps2if, unsigned int mask)
 {
 	unsigned int val;
 
-	sa1111_writel(PS2CR_ENA | mask, sa->base + SA1111_PS2CR);
+	sa1111_writel(PS2CR_ENA | mask, ps2if->base + SA1111_PS2CR);
 
 	udelay(2);
 
-	val = sa1111_readl(sa->base + SA1111_PS2STAT);
+	val = sa1111_readl(ps2if->base + SA1111_PS2STAT);
 	return val & (PS2STAT_KBC | PS2STAT_KBD);
 }
 
@@ -141,141 +193,168 @@
  * Test the keyboard interface.  We basically check to make sure that
  * we can drive each line to the keyboard independently of each other.
  */
-static int __init ps2_test(struct ps2if *sa)
+static int __init ps2_test(struct ps2if *ps2if)
 {
 	unsigned int stat;
 	int ret = 0;
 
-	stat = ps2_test_one(sa, PS2CR_FKC);
+	stat = ps2_test_one(ps2if, PS2CR_FKC);
 	if (stat != PS2STAT_KBD) {
-		printk("Keyboard interface test failed[1]: %02x\n", stat);
+		printk("PS/2 interface test failed[1]: %02x\n", stat);
 		ret = -ENODEV;
 	}
 
-	stat = ps2_test_one(sa, 0);
+	stat = ps2_test_one(ps2if, 0);
 	if (stat != (PS2STAT_KBC | PS2STAT_KBD)) {
-		printk("Keyboard interface test failed[2]: %02x\n", stat);
+		printk("PS/2 interface test failed[2]: %02x\n", stat);
 		ret = -ENODEV;
 	}
 
-	stat = ps2_test_one(sa, PS2CR_FKD);
+	stat = ps2_test_one(ps2if, PS2CR_FKD);
 	if (stat != PS2STAT_KBC) {
-		printk("Keyboard interface test failed[3]: %02x\n", stat);
+		printk("PS/2 interface test failed[3]: %02x\n", stat);
 		ret = -ENODEV;
 	}
 
-	sa1111_writel(0, sa->base + SA1111_PS2CR);
+	sa1111_writel(0, ps2if->base + SA1111_PS2CR);
 
 	return ret;
 }
 
 /*
- * Initialise one PS/2 port.
+ * Add one device to this driver.
  */
-static int __init ps2_init_one(struct sa1111_device *dev, struct ps2if *sa)
+static int ps2_probe(struct device *dev)
 {
+	struct sa1111_dev *sadev = SA1111_DEV(dev);
+	struct ps2if *ps2if;
 	int ret;
 
+	ps2if = kmalloc(sizeof(struct ps2if), GFP_KERNEL);
+	if (!ps2if) {
+		return -ENOMEM;
+	}
+
+	memset(ps2if, 0, sizeof(struct ps2if));
+
+	ps2if->io.type		= SERIO_8042;
+	ps2if->io.write		= ps2_write;
+	ps2if->io.open		= ps2_open;
+	ps2if->io.close		= ps2_close;
+	ps2if->io.name		= dev->name;
+	ps2if->io.phys		= dev->bus_id;
+	ps2if->io.driver	= ps2if;
+	ps2if->dev		= sadev;
+	dev->driver_data	= ps2if;
+
+	spin_lock_init(&ps2if->lock);
+
 	/*
 	 * Request the physical region for this PS2 port.
 	 */
-	sa->res = request_mem_region(_SA1111(sa->base), 512, "ps2");
-	if (!sa->res)
-		return -EBUSY;
+	if (!request_mem_region(sadev->res.start,
+				sadev->res.end - sadev->res.start + 1,
+				SA1111_DRIVER_NAME(sadev))) {
+		ret = -EBUSY;
+		goto free;
+	}
 
 	/*
-	 * Convert the chip offset to virtual address.
+	 * Our parent device has already mapped the region.
 	 */
-	sa->base += (unsigned long)dev->base;
+	ps2if->base = (unsigned long)sadev->mapbase;
 
-	sa1111_enable_device(sa->skpcr_mask);
+	sa1111_enable_device(ps2if->dev);
 
 	/* Incoming clock is 8MHz */
-	sa1111_writel(0, sa->base + SA1111_PS2CLKDIV);
-	sa1111_writel(127, sa->base + SA1111_PS2PRECNT);
+	sa1111_writel(0, ps2if->base + SA1111_PS2CLKDIV);
+	sa1111_writel(127, ps2if->base + SA1111_PS2PRECNT);
 
 	/*
 	 * Flush any pending input.
 	 */
-	ps2_clear_input(sa);
+	ps2_clear_input(ps2if);
 
 	/*
 	 * Test the keyboard interface.
 	 */
-	ret = ps2_test(sa);
+	ret = ps2_test(ps2if);
 	if (ret)
 		goto out;
 
 	/*
 	 * Flush any pending input.
 	 */
-	ps2_clear_input(sa);
-	sa1111_disable_device(sa->skpcr_mask);
+	ps2_clear_input(ps2if);
 
-	serio_register_port(&sa->io);
+	sa1111_disable_device(ps2if->dev);
+	serio_register_port(&ps2if->io);
 	return 0;
 
  out:
-	sa1111_disable_device(sa->skpcr_mask);
-	release_resource(sa->res);
+	sa1111_disable_device(ps2if->dev);
+	release_mem_region(sadev->res.start,
+			   sadev->res.end - sadev->res.start + 1);
+ free:
+	dev->driver_data = NULL;
+	kfree(ps2if);
 	return ret;
 }
 
 /*
- * Remove one PS/2 port.
+ * Remove one device from this driver.
  */
-static void __exit ps2_remove_one(struct ps2if *sa)
+static int ps2_remove(struct device *dev)
 {
-	serio_unregister_port(&sa->io);
- 	release_resource(sa->res);
+	struct ps2if *ps2if = dev->driver_data;
+	struct sa1111_dev *sadev = SA1111_DEV(dev);
+
+	serio_unregister_port(&ps2if->io);
+	release_mem_region(sadev->res.start,
+			   sadev->res.end - sadev->res.start + 1);
+	kfree(ps2if);
+
+	dev->driver_data = NULL;
+
+	return 0;
 }
 
-static struct ps2if ps2_kbd_port =
+/*
+ * We should probably do something here, but what?
+ */
+static int ps2_suspend(struct device *dev, u32 state, u32 level)
 {
-	io: {
-		type:		SERIO_8042,
-		write:		ps2_write,
-		open:		ps2_open,
-		close:		ps2_close,
-		name: 		"SA1111 PS/2 kbd port",
-		phys:		"sa1111/serio0",
-		driver:		&ps2_kbd_port,
-	},
-	base:		SA1111_KBD,
-	irq:		IRQ_TPRXINT,
-	skpcr_mask:	SKPCR_PTCLKEN,
-};
+	return 0;
+}
 
-static struct ps2if ps2_mse_port =
+static int ps2_resume(struct device *dev, u32 level)
 {
-	io: {
-		type:		SERIO_8042,
-		write:		ps2_write,
-		open:		ps2_open,
-		close:		ps2_close,
-		name: 		"SA1111 PS/2 mouse port",
-		phys:		"sa1111/serio1",
-		driver:		&ps2_mse_port,
+	return 0;
+}
+
+/*
+ * Our device driver structure
+ */
+static struct sa1111_driver ps2_driver = {
+	.drv = {
+		.name		= "SA1111 PS2",
+		.bus		= &sa1111_bus_type,
+		.probe		= ps2_probe,
+		.remove		= ps2_remove,
+		.suspend	= ps2_suspend,
+		.resume		= ps2_resume,
 	},
-	base:		SA1111_MSE,
-	irq:		IRQ_MSRXINT,
-	skpcr_mask:	SKPCR_PMCLKEN,
+	.devid			= SA1111_DEVID_PS2,
 };
 
 static int __init ps2_init(void)
 {
-	int ret = -ENODEV;
-
-	if (sa1111) {
-		ret = ps2_init_one(sa1111, &ps2_kbd_port);
-	}
-
-	return ret;
+	return driver_register(&ps2_driver.drv);
 }
 
 static void __exit ps2_exit(void)
 {
-	ps2_remove_one(&ps2_kbd_port);
+	remove_driver(&ps2_driver.drv);
 }
 
 module_init(ps2_init);
diff -Nru a/drivers/isdn/i4l/Makefile b/drivers/isdn/i4l/Makefile
--- a/drivers/isdn/i4l/Makefile	Tue Oct  1 00:08:16 2002
+++ b/drivers/isdn/i4l/Makefile	Tue Oct  1 00:08:16 2002
@@ -12,7 +12,8 @@
 # Multipart objects.
 
 isdn-objs				:= isdn_net.o isdn_tty.o \
-					   isdn_v110.o isdn_common.o
+					   isdn_v110.o isdn_common.o \
+					   isdn_ciscohdlck.o
 
 # Optional parts of multipart objects.
 
diff -Nru a/drivers/isdn/i4l/isdn_ciscohdlck.c b/drivers/isdn/i4l/isdn_ciscohdlck.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/i4l/isdn_ciscohdlck.c	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,406 @@
+/*
+ * Linux ISDN subsystem, CISCO HDLC network interfaces
+ *
+ * Copyright 1994-1998  by Fritz Elfert (fritz@isdn4linux.de)
+ *           1995,96    by Thinking Objects Software GmbH Wuerzburg
+ *           1995,96    by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
+ *           1999-2002  by Kai Germaschewski <kai@germaschewski.name>
+ *           2001       by Bjoern A. Zeeb <i4l@zabbadoz.net>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ * For info on the protocol, see http://i4l.zabbadoz.net/i4l/cisco-hdlc.txt
+ */
+
+#include "isdn_common.h"
+#include "isdn_net.h"
+#include "isdn_ciscohdlck.h"
+
+#include <linux/if_arp.h>
+#include <linux/inetdevice.h>
+
+/* 
+ * CISCO HDLC keepalive specific stuff
+ */
+static struct sk_buff*
+isdn_net_ciscohdlck_alloc_skb(isdn_net_local *lp, int len)
+{
+	isdn_net_dev *idev = lp->netdev;
+	unsigned short hl = isdn_slot_hdrlen(idev->isdn_slot);
+	struct sk_buff *skb;
+
+	skb = alloc_skb(hl + len, GFP_ATOMIC);
+	if (!skb) {
+		printk("isdn out of mem at %s:%d!\n", __FILE__, __LINE__);
+		return NULL;
+	}
+	skb_reserve(skb, hl);
+	return skb;
+}
+
+/* cisco hdlck device private ioctls */
+static int
+isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	isdn_net_local *lp = (isdn_net_local *) dev->priv;
+	isdn_net_dev *idev = lp->netdev;
+	unsigned long len = 0;
+	unsigned long expires = 0;
+	int tmp = 0;
+	int period = lp->cisco_keepalive_period;
+	char debserint = lp->cisco_debserint;
+	int rc = 0;
+
+	if (lp->p_encap != ISDN_NET_ENCAP_CISCOHDLCK)
+		return -EINVAL;
+
+	switch (cmd) {
+		/* get/set keepalive period */
+		case SIOCGKEEPPERIOD:
+			len = (unsigned long)sizeof(lp->cisco_keepalive_period);
+			if (copy_to_user((char *)ifr->ifr_ifru.ifru_data,
+				(int *)&lp->cisco_keepalive_period, len))
+				rc = -EFAULT;
+			break;
+		case SIOCSKEEPPERIOD:
+			tmp = lp->cisco_keepalive_period;
+			len = (unsigned long)sizeof(lp->cisco_keepalive_period);
+			if (copy_from_user((int *)&period,
+				(char *)ifr->ifr_ifru.ifru_data, len))
+				rc = -EFAULT;
+			if ((period > 0) && (period <= 32767))
+				lp->cisco_keepalive_period = period;
+			else
+				rc = -EINVAL;
+			if (!rc && (tmp != lp->cisco_keepalive_period)) {
+				expires = (unsigned long)(jiffies +
+					lp->cisco_keepalive_period * HZ);
+				mod_timer(&lp->cisco_timer, expires);
+				printk(KERN_INFO "%s: Keepalive period set "
+					"to %d seconds.\n",
+					idev->name, lp->cisco_keepalive_period);
+			}
+			break;
+
+		/* get/set debugging */
+		case SIOCGDEBSERINT:
+			len = (unsigned long)sizeof(lp->cisco_debserint);
+			if (copy_to_user((char *)ifr->ifr_ifru.ifru_data,
+				(char *)&lp->cisco_debserint, len))
+				rc = -EFAULT;
+			break;
+		case SIOCSDEBSERINT:
+			len = (unsigned long)sizeof(lp->cisco_debserint);
+			if (copy_from_user((char *)&debserint,
+				(char *)ifr->ifr_ifru.ifru_data, len))
+				rc = -EFAULT;
+			if ((debserint >= 0) && (debserint <= 64))
+				lp->cisco_debserint = debserint;
+			else
+				rc = -EINVAL;
+			break;
+
+		default:
+			rc = -EINVAL;
+			break;
+	}
+	return (rc);
+}
+
+/* called via cisco_timer.function */
+static void
+isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data)
+{
+	isdn_net_local *lp = (isdn_net_local *) data;
+	isdn_net_dev *idev = lp->netdev;
+	struct sk_buff *skb;
+	unsigned char *p;
+	unsigned long last_cisco_myseq = lp->cisco_myseq;
+	int myseq_diff = 0;
+
+	lp->cisco_myseq++;
+
+	myseq_diff = (lp->cisco_myseq - lp->cisco_mineseen);
+	if ((lp->cisco_line_state) && ((myseq_diff >= 3)||(myseq_diff <= -3))) {
+		/* line up -> down */
+		lp->cisco_line_state = 0;
+		printk (KERN_WARNING
+				"UPDOWN: Line protocol on Interface %s,"
+				" changed state to down\n", idev->name);
+		/* should stop routing higher-level data accross */
+	} else if ((!lp->cisco_line_state) &&
+		(myseq_diff >= 0) && (myseq_diff <= 2)) {
+		/* line down -> up */
+		lp->cisco_line_state = 1;
+		printk (KERN_WARNING
+				"UPDOWN: Line protocol on Interface %s,"
+				" changed state to up\n", idev->name);
+		/* restart routing higher-level data accross */
+	}
+
+	if (lp->cisco_debserint)
+		printk (KERN_DEBUG "%s: HDLC "
+			"myseq %lu, mineseen %lu%c, yourseen %lu, %s\n",
+			idev->name, last_cisco_myseq, lp->cisco_mineseen,
+			(last_cisco_myseq == lp->cisco_mineseen) ? '*' : 040,
+			lp->cisco_yourseq,
+			(lp->cisco_line_state) ? "line up" : "line down");
+
+	skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
+	if (!skb)
+		return;
+
+	p = skb_put(skb, 4 + 14);
+
+	/* cisco header */
+	p += put_u8 (p, CISCO_ADDR_UNICAST);
+	p += put_u8 (p, CISCO_CTRL);
+	p += put_u16(p, CISCO_TYPE_SLARP);
+
+	/* slarp keepalive */
+	p += put_u32(p, CISCO_SLARP_KEEPALIVE);
+	p += put_u32(p, lp->cisco_myseq);
+	p += put_u32(p, lp->cisco_yourseq);
+	p += put_u16(p, 0xffff); // reliablity, always 0xffff
+
+	isdn_net_write_super(lp, skb);
+
+	lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ;
+	
+	add_timer(&lp->cisco_timer);
+}
+
+static void
+isdn_net_ciscohdlck_slarp_send_request(isdn_net_local *lp)
+{
+	struct sk_buff *skb;
+	unsigned char *p;
+
+	skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
+	if (!skb)
+		return;
+
+	p = skb_put(skb, 4 + 14);
+
+	/* cisco header */
+	p += put_u8 (p, CISCO_ADDR_UNICAST);
+	p += put_u8 (p, CISCO_CTRL);
+	p += put_u16(p, CISCO_TYPE_SLARP);
+
+	/* slarp request */
+	p += put_u32(p, CISCO_SLARP_REQUEST);
+	p += put_u32(p, 0); // address
+	p += put_u32(p, 0); // netmask
+	p += put_u16(p, 0); // unused
+
+	isdn_net_write_super(lp, skb);
+}
+
+static void 
+isdn_ciscohdlck_connected(isdn_net_local *lp)
+{
+	lp->cisco_myseq = 0;
+	lp->cisco_mineseen = 0;
+	lp->cisco_yourseq = 0;
+	lp->cisco_keepalive_period = ISDN_TIMER_KEEPINT;
+	lp->cisco_last_slarp_in = 0;
+	lp->cisco_line_state = 0;
+	lp->cisco_debserint = 0;
+
+	if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK) {
+		/* send slarp request because interface/seq.no.s reset */
+		isdn_net_ciscohdlck_slarp_send_request(lp);
+
+		init_timer(&lp->cisco_timer);
+		lp->cisco_timer.data = (unsigned long) lp;
+		lp->cisco_timer.function = isdn_net_ciscohdlck_slarp_send_keepalive;
+		lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ;
+		add_timer(&lp->cisco_timer);
+	}
+	isdn_net_device_wake_queue(lp);
+}
+
+static void 
+isdn_ciscohdlck_disconnected(isdn_net_local *lp)
+{
+	if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK) {
+		del_timer(&lp->cisco_timer);
+	}
+}
+
+static void
+isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp)
+{
+	struct sk_buff *skb;
+	unsigned char *p;
+	struct in_device *in_dev = NULL;
+	u32 addr = 0;		/* local ipv4 address */
+	u32 mask = 0;		/* local netmask */
+
+	if ((in_dev = lp->netdev->dev.ip_ptr) != NULL) {
+		/* take primary(first) address of interface */
+		struct in_ifaddr *ifa = in_dev->ifa_list;
+		if (ifa != NULL) {
+			addr = ifa->ifa_local;
+			mask = ifa->ifa_mask;
+		}
+	}
+
+	skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
+	if (!skb)
+		return;
+
+	p = skb_put(skb, 4 + 14);
+
+	/* cisco header */
+	p += put_u8 (p, CISCO_ADDR_UNICAST);
+	p += put_u8 (p, CISCO_CTRL);
+	p += put_u16(p, CISCO_TYPE_SLARP);
+
+	/* slarp reply, send own ip/netmask; if values are nonsense remote
+	 * should think we are unable to provide it with an address via SLARP */
+	p += put_u32(p, CISCO_SLARP_REPLY);
+	p += put_u32(p, addr);	// address
+	p += put_u32(p, mask);	// netmask
+	p += put_u16(p, 0);	// unused
+
+	isdn_net_write_super(lp, skb);
+}
+
+static void
+isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb)
+{
+	isdn_net_dev *idev = lp->netdev;
+	unsigned char *p;
+	int period;
+	u32 code;
+	u32 my_seq, addr;
+	u32 your_seq, mask;
+	u32 local;
+	u16 unused;
+
+	if (skb->len < 14)
+		return;
+
+	p = skb->data;
+	p += get_u32(p, &code);
+	
+	switch (code) {
+	case CISCO_SLARP_REQUEST:
+		lp->cisco_yourseq = 0;
+		isdn_net_ciscohdlck_slarp_send_reply(lp);
+		break;
+	case CISCO_SLARP_REPLY:
+		addr = ntohl(*(u32 *)p);
+		mask = ntohl(*(u32 *)(p+4));
+		if (mask != 0xfffffffc)
+			goto slarp_reply_out;
+		if ((addr & 3) == 0 || (addr & 3) == 3)
+			goto slarp_reply_out;
+		local = addr ^ 3;
+		printk(KERN_INFO "%s: got slarp reply: "
+			"remote ip: %d.%d.%d.%d, "
+			"local ip: %d.%d.%d.%d "
+			"mask: %d.%d.%d.%d\n",
+		       idev->name,
+		       HIPQUAD(addr),
+		       HIPQUAD(local),
+		       HIPQUAD(mask));
+		break;
+  slarp_reply_out:
+		 printk(KERN_INFO "%s: got invalid slarp "
+				 "reply (%d.%d.%d.%d/%d.%d.%d.%d) "
+				 "- ignored\n", idev->name,
+				 HIPQUAD(addr), HIPQUAD(mask));
+		break;
+	case CISCO_SLARP_KEEPALIVE:
+		period = (int)((jiffies - lp->cisco_last_slarp_in
+				+ HZ/2 - 1) / HZ);
+		if (lp->cisco_debserint &&
+				(period != lp->cisco_keepalive_period) &&
+				lp->cisco_last_slarp_in) {
+			printk(KERN_DEBUG "%s: Keepalive period mismatch - "
+				"is %d but should be %d.\n",
+				idev->name, period, lp->cisco_keepalive_period);
+		}
+		lp->cisco_last_slarp_in = jiffies;
+		p += get_u32(p, &my_seq);
+		p += get_u32(p, &your_seq);
+		p += get_u16(p, &unused);
+		lp->cisco_yourseq = my_seq;
+		lp->cisco_mineseen = your_seq;
+		break;
+	}
+}
+
+static void 
+isdn_ciscohdlck_receive(isdn_net_dev *idev, isdn_net_local *olp,
+			struct sk_buff *skb)
+{
+	isdn_net_local *lp = &idev->local;
+	unsigned char *p;
+ 	u8 addr;
+ 	u8 ctrl;
+ 	u16 type;
+	
+	if (skb->len < 4)
+		goto out_free;
+
+	p = skb->data;
+	p += get_u8 (p, &addr);
+	p += get_u8 (p, &ctrl);
+	p += get_u16(p, &type);
+	skb_pull(skb, 4);
+	
+	if ((addr != CISCO_ADDR_UNICAST && addr != CISCO_ADDR_BROADCAST) ||
+	    ctrl != CISCO_CTRL) {
+		printk(KERN_DEBUG "%s: Unknown Cisco header %#02x %#02x\n",
+		       idev->name, addr, ctrl);
+		goto out_free;
+	}
+
+	switch (type) {
+	case CISCO_TYPE_SLARP:
+		isdn_net_ciscohdlck_slarp_in(lp, skb);
+		goto out_free;
+	case CISCO_TYPE_CDP:
+		if (lp->cisco_debserint)
+			printk(KERN_DEBUG "%s: Received CDP packet. use "
+				"\"no cdp enable\" on cisco.\n", idev->name);
+		goto out_free;
+	default:
+		/* no special cisco protocol */
+		isdn_net_reset_huptimer(idev, olp->netdev);
+		skb->protocol = htons(type);
+		netif_rx(skb);
+		return;
+	}
+
+ out_free:
+	kfree_skb(skb);
+}
+
+static int
+isdn_ciscohdlck_header(struct sk_buff *skb, struct net_device *dev, 
+		      unsigned short type,
+		      void *daddr, void *saddr, unsigned plen)
+{
+	unsigned char *p = skb_push(skb, 4);
+
+	p += put_u8 (p, CISCO_ADDR_UNICAST);
+	p += put_u8 (p, CISCO_CTRL);
+	p += put_u16(p, type);
+	
+	return 4;
+}
+
+struct isdn_netif_ops ciscohdlck_ops = {
+	.hard_header         = isdn_ciscohdlck_header,
+	.do_ioctl            = isdn_ciscohdlck_dev_ioctl,
+	.flags               = IFF_NOARP | IFF_POINTOPOINT,
+	.type                = ARPHRD_CISCO,
+	.receive             = isdn_ciscohdlck_receive,
+	.connected           = isdn_ciscohdlck_connected,
+	.disconnected        = isdn_ciscohdlck_disconnected,
+};
diff -Nru a/drivers/isdn/i4l/isdn_ciscohdlck.h b/drivers/isdn/i4l/isdn_ciscohdlck.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/i4l/isdn_ciscohdlck.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,16 @@
+/*
+ * Linux ISDN subsystem, CISCO HDLC network interfaces
+ *
+ * Copyright 1999-2002  by Kai Germaschewski <kai@germaschewski.name>
+ *           2001       by Bjoern A. Zeeb <i4l@zabbadoz.net>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#ifndef ISDN_CISCOHDLCK_H
+#define ISDN_CISCOHDLCK_H
+
+extern struct isdn_netif_ops ciscohdlck_ops;
+
+#endif
diff -Nru a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
--- a/drivers/isdn/i4l/isdn_common.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/isdn/i4l/isdn_common.c	Tue Oct  1 00:08:16 2002
@@ -507,7 +507,7 @@
 				case 1:
 					list_for_each(l, &isdn_net_devs) {
 						isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list);
-						if (p->local.isdn_slot == i) {
+						if (p->isdn_slot == i) {
 							strcpy(cmd.parm.setup.eazmsn, p->local.msn);
 							isdn_slot_command(i, ISDN_CMD_ACCEPTD, &cmd);
 							retval = 1;
@@ -611,11 +611,9 @@
 			dbg_statcallb("BHUP: %d\n", i);
 			dev->drv[di]->online &= ~(1 << (c->arg));
 			isdn_info_update();
-#ifdef CONFIG_ISDN_X25
 			/* Signal hangup to network-devices */
 			if (isdn_net_stat_callback(i, c))
 				break;
-#endif
 			isdn_v110_stat_callback(&slot[i].iv110, c);
 			if (isdn_tty_stat_callback(i, c))
 				break;
@@ -2251,6 +2249,21 @@
 	return slot[sl].st_netdev;
 }
 
+int
+isdn_hard_header_len(void)
+{
+	int drvidx;
+	int max = 0;
+	
+	for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) {
+		if (dev->drv[drvidx] && 
+		    max < dev->drv[drvidx]->interface->hl_hdrlen) {
+			max = dev->drv[drvidx]->interface->hl_hdrlen;
+		}
+	}
+	return max;
+}
+
 /*
  *****************************************************************************
  * And now the modules code.
@@ -2417,6 +2430,7 @@
 	printk("\n");
 #endif
 	isdn_info_update();
+	isdn_net_init_module();
 	return 0;
 
  err_tty_modem:
diff -Nru a/drivers/isdn/i4l/isdn_common.h b/drivers/isdn/i4l/isdn_common.h
--- a/drivers/isdn/i4l/isdn_common.h	Tue Oct  1 00:08:15 2002
+++ b/drivers/isdn/i4l/isdn_common.h	Tue Oct  1 00:08:15 2002
@@ -12,6 +12,8 @@
  *
  */
 
+#include <linux/isdn.h>
+
 #undef  ISDN_DEBUG_MODEM_OPEN
 #undef  ISDN_DEBUG_MODEM_IOCTL
 #undef  ISDN_DEBUG_MODEM_WAITSENT
@@ -102,4 +104,4 @@
 extern void  isdn_slot_set_st_netdev(int sl, isdn_net_dev *nd);
 extern isdn_net_dev *isdn_slot_rx_netdev(int sl);
 extern isdn_net_dev *isdn_slot_st_netdev(int sl);
-
+extern int   isdn_hard_header_len(void);
diff -Nru a/drivers/isdn/i4l/isdn_concap.c b/drivers/isdn/i4l/isdn_concap.c
--- a/drivers/isdn/i4l/isdn_concap.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/isdn/i4l/isdn_concap.c	Tue Oct  1 00:08:16 2002
@@ -106,3 +106,153 @@
 	}
 	return NULL;
 }
+
+static int
+isdn_x25_open(isdn_net_local *lp)
+{
+	struct net_device * dev = & lp -> netdev -> dev;
+	struct concap_proto * cprot = lp -> netdev -> cprot;
+	struct concap_proto * dops = lp -> dops;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();                  /* Avoid glitch on writes to CMD regs */
+	if( cprot -> pops && dops )
+		cprot -> pops -> restart ( cprot, dev, dops );
+	restore_flags(flags);
+	return 0;
+}
+
+static void
+isdn_x25_close(isdn_net_local *lp)
+{
+	struct concap_proto * cprot = lp -> netdev -> cprot;
+
+	if( cprot && cprot -> pops ) cprot -> pops -> close( cprot );
+}
+
+static void
+isdn_x25_connected(isdn_net_local *lp)
+{
+	struct concap_proto *cprot = lp -> netdev -> cprot;
+	struct concap_proto_ops *pops = cprot ? cprot -> pops : 0;
+
+	/* try if there are generic concap receiver routines */
+	if( pops )
+		if( pops->connect_ind)
+			pops->connect_ind(cprot);
+
+	isdn_net_device_wake_queue(lp);
+}
+
+static void
+isdn_x25_disconnected(isdn_net_local *lp)
+{
+	struct concap_proto *cprot = lp -> netdev -> cprot;
+	struct concap_proto_ops *pops = cprot ? cprot -> pops : 0;
+
+	/* try if there are generic encap protocol
+	   receiver routines and signal the closure of
+	   the link */
+	if( pops  &&  pops -> disconn_ind )
+		pops -> disconn_ind(cprot);
+}
+
+int
+isdn_x25_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+/* At this point hard_start_xmit() passes control to the encapsulation
+   protocol (if present).
+   For X.25 auto-dialing is completly bypassed because:
+   - It does not conform with the semantics of a reliable datalink
+     service as needed by X.25 PLP.
+   - I don't want that the interface starts dialing when the network layer
+     sends a message which requests to disconnect the lapb link (or if it
+     sends any other message not resulting in data transmission).
+   Instead, dialing will be initiated by the encapsulation protocol entity
+   when a dl_establish request is received from the upper layer.
+*/
+	isdn_net_local *lp = (isdn_net_local *) dev->priv;
+	struct concap_proto * cprot = lp -> netdev -> cprot;
+	int ret = cprot -> pops -> encap_and_xmit ( cprot , skb);
+
+	if (ret)
+		netif_stop_queue(dev);
+		
+	return ret;
+}
+
+static void 
+isdn_x25_receive(isdn_net_dev *p, isdn_net_local *olp, struct sk_buff *skb)
+{
+	isdn_net_local *lp = &p->local;
+	struct concap_proto *cprot = lp -> netdev -> cprot;
+
+	/* try if there are generic sync_device receiver routines */
+	if(cprot) 
+		if(cprot -> pops)
+			if( cprot -> pops -> data_ind) {
+				cprot -> pops -> data_ind(cprot,skb);
+				return;
+			}
+}
+
+static void
+isdn_x25_init(struct net_device *dev)
+{
+	unsigned long flags;
+
+	isdn_net_local *lp = dev->priv;
+
+	/* ... ,  prepare for configuration of new one ... */
+	switch ( lp->p_encap ){
+	case ISDN_NET_ENCAP_X25IFACE:
+		lp -> dops = &isdn_concap_reliable_dl_dops;
+	}
+	/* ... and allocate new one ... */
+	p -> cprot = isdn_concap_new( cfg -> p_encap );
+	/* p -> cprot == NULL now if p_encap is not supported
+	   by means of the concap_proto mechanism */
+	if (!p->cprot)
+		return -EINVAL;
+
+	return 0;
+}
+
+static void
+isdn_x25_cleanup(isdn_net_dev *p)
+{
+	isdn_net_local *lp = &p->local;
+	struct concap_proto * cprot = p -> cprot;
+	unsigned long flags;
+	
+	/* delete old encapsulation protocol if present ... */
+	save_flags(flags);
+	cli(); /* avoid races with incoming events trying to
+		  call cprot->pops methods */
+	if( cprot && cprot -> pops )
+		cprot -> pops -> proto_del ( cprot );
+	p -> cprot = NULL;
+	lp -> dops = NULL;
+	restore_flags(flags);
+}
+
+void isdn_x25_realrm(isdn_net_dev *p)
+{
+	if( p -> cprot && p -> cprot -> pops )
+		p -> cprot -> pops -> proto_del ( p -> cprot );
+}
+
+struct isdn_netif_ops isdn_x25_ops = {
+	.flags               = IFF_NOARP | IFF_POINTOPOINT,
+	.type                = ARPHRD_X25,
+	.receive             = isdn_x25_receive,
+	.connected           = isdn_x25_connected,
+	.disconnected        = isdn_x25_disconnected,
+	.init                = isdn_x25_init,
+	.cleanup             = isdn_x25_cleanup,
+	.open                = isdn_x25_open,
+	.close               = isdn_x25_close,
+};
+
+#endif /* CONFIG_ISDN_X25 */
diff -Nru a/drivers/isdn/i4l/isdn_concap.h b/drivers/isdn/i4l/isdn_concap.h
--- a/drivers/isdn/i4l/isdn_concap.h	Tue Oct  1 00:08:18 2002
+++ b/drivers/isdn/i4l/isdn_concap.h	Tue Oct  1 00:08:18 2002
@@ -9,6 +9,21 @@
 
 extern struct concap_device_ops isdn_concap_reliable_dl_dops;
 extern struct concap_device_ops isdn_concap_demand_dial_dops;
-extern struct concap_proto * isdn_concap_new( int );
 
+struct concap_proto *isdn_concap_new(int);
 
+#ifdef CONFIG_ISDN_X25
+
+extern struct isdn_netif_ops isdn_x25_ops;
+
+int  isdn_x25_start_xmit(struct sk_buff *skb, struct net_device *dev);
+
+#else
+
+static inline int
+isdn_x25_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	return 0;
+}
+
+#endif
diff -Nru a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
--- a/drivers/isdn/i4l/isdn_net.c	Tue Oct  1 00:08:21 2002
+++ b/drivers/isdn/i4l/isdn_net.c	Tue Oct  1 00:08:21 2002
@@ -3,8 +3,9 @@
  * Linux ISDN subsystem, network interfaces and related functions (linklevel).
  *
  * Copyright 1994-1998  by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1995,96    by Thinking Objects Software GmbH Wuerzburg
- * Copyright 1995,96    by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
+ *           1995,96    by Thinking Objects Software GmbH Wuerzburg
+ *           1995,96    by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
+ *           1999-2002  by Kai Germaschewski <kai@germaschewski.name>
  *
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
@@ -17,9 +18,6 @@
  *   'V'     - accept VOICE (DOV) only
  *   'B'     - accept BOTH DATA and DOV types
  *
- * Jan 2001: fix CISCO HDLC      Bjoern A. Zeeb <i4l@zabbadoz.net>
- *           for info on the protocol, see 
- *           http://i4l.zabbadoz.net/i4l/cisco-hdlc.txt
  */
 
 #include <linux/config.h>
@@ -30,13 +28,10 @@
 #include <linux/inetdevice.h>
 #include "isdn_common.h"
 #include "isdn_net.h"
-#ifdef CONFIG_ISDN_PPP
 #include "isdn_ppp.h"
-#endif
-#ifdef CONFIG_ISDN_X25
 #include <linux/concap.h>
 #include "isdn_concap.h"
-#endif
+#include "isdn_ciscohdlck.h"
 
 enum {
 	ST_NULL,
@@ -110,18 +105,6 @@
 }
 
 /*
- * wake up the network -> net_device queue.
- * For slaves, wake the corresponding master interface.
- */
-static __inline__ void isdn_net_device_wake_queue(isdn_net_local *lp)
-{
-	if (lp->master) 
-		netif_wake_queue(lp->master);
-	else
-		netif_wake_queue(&lp->netdev->dev);
-}
-
-/*
  * stop the network -> net_device queue.
  * For slaves, stop the corresponding master interface.
  */
@@ -202,15 +185,33 @@
 
 #define ISDN_NET_TX_TIMEOUT (20*HZ) 
 
+static struct isdn_netif_ops *netif_ops[ISDN_NET_ENCAP_NR];
+
+int
+register_isdn_netif(int encap, struct isdn_netif_ops *ops)
+{
+	if (encap < 0 || encap >= ISDN_NET_ENCAP_NR)
+		return -EINVAL;
+
+	if (netif_ops[encap])
+		return -EBUSY;
+
+	netif_ops[encap] = ops;
+
+	return 0;
+}
+
+int isdn_net_online(isdn_net_dev *idev)
+{
+	return idev->dialstate == ST_ACTIVE;
+}
+
 /* Prototypes */
 
-int isdn_net_force_dial_lp(isdn_net_local *);
+static int isdn_net_force_dial_lp(isdn_net_local *);
 static int isdn_net_start_xmit(struct sk_buff *, struct net_device *);
 static void do_dialout(isdn_net_local *lp);
-
-static void isdn_net_ciscohdlck_connected(isdn_net_local *lp);
-static void isdn_net_ciscohdlck_disconnected(isdn_net_local *lp);
-
+static int isdn_net_set_encap(isdn_net_dev *p, int encap);
 static int isdn_net_handle_event(isdn_net_local *lp, int pr, void *arg);
 
 char *isdn_net_revision = "$Revision: 1.140.6.11 $";
@@ -232,92 +233,42 @@
 	dst_link_failure(skb);
 }
 
-static void
-isdn_net_reset(struct net_device *dev)
-{
-#ifdef CONFIG_ISDN_X25
-	struct concap_device_ops * dops =
-		( (isdn_net_local *) dev->priv ) -> dops;
-	struct concap_proto * cprot =
-		( (isdn_net_local *) dev->priv ) -> netdev -> cprot;
-#endif
-	ulong flags;
-
-	/* not sure if the cli() is needed at all --KG */
-	save_flags(flags);
-	cli();                  /* Avoid glitch on writes to CMD regs */
-#ifdef CONFIG_ISDN_X25
-	if( cprot && cprot -> pops && dops )
-		cprot -> pops -> restart ( cprot, dev, dops );
-#endif
-	restore_flags(flags);
-}
-
 /* Open/initialize the board. */
 static int
 isdn_net_open(struct net_device *dev)
 {
-	int i;
-	struct net_device *p;
-	struct in_device *in_dev;
-
-	/* moved here from isdn_net_reset, because only the master has an
-	   interface associated which is supposed to be started. BTW:
-	   we need to call netif_start_queue, not netif_wake_queue here */
-	netif_start_queue(dev);
+	isdn_net_local *lp = dev->priv;
+	int retval = 0;
 
-	isdn_net_reset(dev);
-	/* Fill in the MAC-level header (not needed, but for compatibility... */
-	for (i = 0; i < ETH_ALEN - sizeof(u32); i++)
-		dev->dev_addr[i] = 0xfc;
-	if ((in_dev = dev->ip_ptr) != NULL) {
-		/*
-		 *      Any address will do - we take the first
-		 */
-		struct in_ifaddr *ifa = in_dev->ifa_list;
-		if (ifa != NULL)
-			memcpy(dev->dev_addr+2, &ifa->ifa_local, 4);
-	}
+	if (!lp->ops)
+		return -ENODEV;
 
-	/* If this interface has slaves, start them also */
+	if (lp->ops->open)
+		retval = lp->ops->open(lp);
 
-	if ((p = (((isdn_net_local *) dev->priv)->slave))) {
-		while (p) {
-			isdn_net_reset(p);
-			p = (((isdn_net_local *) p->priv)->slave);
-		}
-	}
+	if (!retval)
+		return retval;
+	
+	netif_start_queue(dev);
 	isdn_MOD_INC_USE_COUNT();
 	return 0;
 }
 
 /*
- * Assign an ISDN-channel to a net-interface
- */
-static void
-isdn_net_bind_channel(isdn_net_local * lp, int idx)
-{
-	ulong flags;
-
-	save_flags(flags);
-	cli();
-	lp->flags |= ISDN_NET_CONNECTED;
-	lp->isdn_slot = idx;
-	isdn_slot_set_rx_netdev(lp->isdn_slot, lp->netdev);
-	isdn_slot_set_st_netdev(lp->isdn_slot, lp->netdev);
-	restore_flags(flags);
-}
-
-/*
  * unbind a net-interface (resets interface after an error)
  */
 static void
 isdn_net_unbind_channel(isdn_net_local * lp)
 {
+	isdn_net_dev *idev = lp->netdev;
 	ulong flags;
 
 	save_flags(flags);
 	cli();
+
+	if (lp->ops->unbind)
+		lp->ops->unbind(lp);
+
 	skb_queue_purge(&lp->super_tx_queue);
 
 	if (!lp->master) {	/* reset only master device */
@@ -327,19 +278,45 @@
 		 */
 		qdisc_reset(lp->netdev->dev.qdisc);
 	}
-	lp->dialstate = ST_NULL;
-	if (lp->isdn_slot >= 0) {
-		isdn_slot_set_rx_netdev(lp->isdn_slot, NULL);
-		isdn_slot_set_st_netdev(lp->isdn_slot, NULL);
-		isdn_slot_free(lp->isdn_slot, ISDN_USAGE_NET);
+	idev->dialstate = ST_NULL;
+	if (idev->isdn_slot >= 0) {
+		isdn_slot_set_rx_netdev(idev->isdn_slot, NULL);
+		isdn_slot_set_st_netdev(idev->isdn_slot, NULL);
+		isdn_slot_free(idev->isdn_slot, ISDN_USAGE_NET);
 	}
-	lp->flags &= ~ISDN_NET_CONNECTED;
-	lp->isdn_slot = -1;
+	idev->isdn_slot = -1;
 
 	restore_flags(flags);
 }
 
 /*
+ * Assign an ISDN-channel to a net-interface
+ */
+static int
+isdn_net_bind_channel(isdn_net_local *lp, int idx)
+{
+	isdn_net_dev *idev = lp->netdev;
+	int retval = 0;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+
+	idev->isdn_slot = idx;
+	isdn_slot_set_rx_netdev(idev->isdn_slot, lp->netdev);
+	isdn_slot_set_st_netdev(idev->isdn_slot, lp->netdev);
+
+	if (lp->ops->bind)
+		retval = lp->ops->bind(lp);
+
+	if (retval < 0)
+		isdn_net_unbind_channel(lp);
+
+	restore_flags(flags);
+	return retval;
+}
+
+/*
  * Perform auto-hangup for net-interfaces.
  *
  * auto-hangup:
@@ -351,9 +328,10 @@
 
 static void isdn_net_hup_timer(unsigned long data)
 {
-	isdn_net_local *lp = (isdn_net_local *) data;
+	isdn_net_dev *idev = (isdn_net_dev *) data;
+	isdn_net_local *lp = &idev->local;
 
-	if (!(lp->flags & ISDN_NET_CONNECTED) || lp->dialstate != ST_ACTIVE) {
+	if (!isdn_net_online(idev)) {
 		isdn_BUG();
 		return;
 	}
@@ -361,41 +339,41 @@
 	dbg_net_dial("%s: huptimer %d, onhtime %d, chargetime %ld, chargeint %d\n",
 		     l->name, l->huptimer, l->onhtime, l->chargetime, l->chargeint);
 
-	if (!(lp->onhtime))
+	if (lp->onhtime == 0)
 		return;
 	
-	if (lp->huptimer++ <= lp->onhtime)
+	if (idev->huptimer++ <= lp->onhtime)
 		goto mod_timer;
 
-	if (lp->hupflags & ISDN_MANCHARGE && lp->hupflags & ISDN_CHARGEHUP) {
-		while (time_after(jiffies, lp->chargetime + lp->chargeint))
-			lp->chargetime += lp->chargeint;
+	if ((lp->hupflags & (ISDN_MANCHARGE | ISDN_CHARGEHUP)) == (ISDN_MANCHARGE | ISDN_CHARGEHUP)) {
+		while (time_after(jiffies, idev->chargetime + idev->chargeint))
+			idev->chargetime += idev->chargeint;
 		
-		if (time_after(jiffies, lp->chargetime + lp->chargeint - 2 * HZ)) {
-			if (lp->outgoing || lp->hupflags & ISDN_INHUP) {
-				isdn_net_hangup(lp);
+		if (time_after(jiffies, idev->chargetime + idev->chargeint - 2 * HZ)) {
+			if (idev->outgoing || lp->hupflags & ISDN_INHUP) {
+				isdn_net_hangup(idev);
 				return;
 			}
 		}
-	} else if (lp->outgoing) {
+	} else if (idev->outgoing) {
 		if (lp->hupflags & ISDN_CHARGEHUP) {
-			if (lp->charge_state != ST_CHARGE_HAVE_CINT) {
+			if (idev->charge_state != ST_CHARGE_HAVE_CINT) {
 				dbg_net_dial("%s: did not get CINT\n", lp->name);
-				isdn_net_hangup(lp);
+				isdn_net_hangup(idev);
 				return;
-			} else if (time_after(jiffies, lp->chargetime + lp->chargeint)) {
+			} else if (time_after(jiffies, idev->chargetime + idev->chargeint)) {
 				dbg_net_dial("%s: chtime = %lu, chint = %d\n",
 					     lp->name, lp->chargetime, lp->chargeint);
-				isdn_net_hangup(lp);
+				isdn_net_hangup(idev);
 				return;
 			}
 		}
 	} else if (lp->hupflags & ISDN_INHUP) {
-		isdn_net_hangup(lp);
+		isdn_net_hangup(idev);
 		return;
 	}
  mod_timer:
-	mod_timer(&lp->hup_timer, lp->hup_timer.expires + HZ);
+	mod_timer(&idev->hup_timer, idev->hup_timer.expires + HZ);
 }
 
 static void isdn_net_lp_disconnected(isdn_net_local *lp)
@@ -405,48 +383,35 @@
 
 static void isdn_net_connected(isdn_net_local *lp)
 {
-#ifdef CONFIG_ISDN_X25
-	struct concap_proto *cprot = lp -> netdev -> cprot;
-	struct concap_proto_ops *pops = cprot ? cprot -> pops : 0;
-#endif
-	lp->dialstate = ST_ACTIVE;
-	lp->hup_timer.expires = jiffies + HZ;
-	add_timer(&lp->hup_timer);
+	isdn_net_dev *idev = lp->netdev;
+
+	idev->dialstate = ST_ACTIVE;
+	idev->hup_timer.expires = jiffies + HZ;
+	add_timer(&idev->hup_timer);
 
-	if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK)
-		isdn_net_ciscohdlck_connected(lp);
 	if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) {
 		if (lp->master) { /* is lp a slave? */
 			isdn_net_dev *nd = ((isdn_net_local *)lp->master->priv)->netdev;
 			isdn_net_add_to_bundle(nd, lp);
 		}
 	}
-	printk(KERN_INFO "isdn_net: %s connected\n", lp->name);
+	printk(KERN_INFO "isdn_net: %s connected\n", idev->name);
 	/* If first Chargeinfo comes before B-Channel connect,
 	 * we correct the timestamp here.
 	 */
-	lp->chargetime = jiffies;
+	idev->chargetime = jiffies;
 	
 	/* reset dial-timeout */
-	lp->dialstarted = 0;
-	lp->dialwait_timer = 0;
+	idev->dialstarted = 0;
+	idev->dialwait_timer = 0;
 	
-	lp->transcount = 0;
-	lp->cps = 0;
-	lp->last_jiffies = jiffies;
+	idev->transcount = 0;
+	idev->cps = 0;
+	idev->last_jiffies = jiffies;
 
-#ifdef CONFIG_ISDN_PPP
-	if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
-		isdn_ppp_wakeup_daemon(lp);
-#endif
-#ifdef CONFIG_ISDN_X25
-	/* try if there are generic concap receiver routines */
-	if( pops )
-		if( pops->connect_ind)
-			pops->connect_ind(cprot);
-#endif /* CONFIG_ISDN_X25 */
-	/* ppp needs to do negotiations first */
-	if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
+	if (lp->ops->connected)
+		lp->ops->connected(lp);
+	else
 		isdn_net_device_wake_queue(lp);
 }
 
@@ -475,9 +440,9 @@
 static void
 isdn_net_dial_timer(unsigned long data)
 {
-	isdn_net_local *lp = (isdn_net_local *) data;
+	isdn_net_dev *idev = (isdn_net_dev *) data;
 
-	isdn_net_handle_event(lp, lp->dial_event, NULL);
+	isdn_net_handle_event(&idev->local, idev->dial_event, NULL);
 }
 
 /* Initiate dialout. Set phone-number-pointer to first number
@@ -486,13 +451,15 @@
 static void
 init_dialout(isdn_net_local *lp)
 {
-	lp->dial = 0;
+	isdn_net_dev *idev = lp->netdev;
+
+	idev->dial = 0;
 
 	if (lp->dialtimeout > 0 &&
-	    (lp->dialstarted == 0 || 
-	     time_after(jiffies, lp->dialstarted + lp->dialtimeout + lp->dialwait))) {
-		lp->dialstarted = jiffies;
-		lp->dialwait_timer = 0;
+	    (idev->dialstarted == 0 || 
+	     time_after(jiffies, idev->dialstarted + lp->dialtimeout + lp->dialwait))) {
+		idev->dialstarted = jiffies;
+		idev->dialwait_timer = 0;
 	}
 	lp->dialretry = 0;
 	do_dialout(lp);
@@ -505,6 +472,7 @@
 static void
 do_dialout(isdn_net_local *lp)
 {
+	isdn_net_dev *idev = lp->netdev;
 	int i;
 	unsigned long flags;
 	struct isdn_net_phone *phone;
@@ -526,55 +494,55 @@
 	}
 	i = 0;
 	list_for_each_entry(phone, &lp->phone[1], list) {
-		if (i++ == lp->dial)
+		if (i++ == idev->dial)
 			goto found;
 	}
 	/* otherwise start in front */
 	phone = list_entry(lp->phone[1].next, struct isdn_net_phone, list);
-	lp->dial = 0;
+	idev->dial = 0;
 	lp->dialretry++;
 	
  found:
-	lp->dial++;
+	idev->dial++;
 	dial.phone = phone->num;
 	spin_unlock_irqrestore(&lp->lock, flags);
 
 	if (lp->dialretry > lp->dialmax) {
 		if (lp->dialtimeout == 0) {
-			lp->dialwait_timer = jiffies + lp->dialwait;
-			lp->dialstarted = 0;
+			idev->dialwait_timer = jiffies + lp->dialwait;
+			idev->dialstarted = 0;
 		}
-		isdn_net_hangup(lp);
+		isdn_net_hangup(idev);
 		return;
 	}
 	if(lp->dialtimeout > 0 &&
-	   time_after(jiffies, lp->dialstarted + lp->dialtimeout)) {
-		lp->dialwait_timer = jiffies + lp->dialwait;
-		lp->dialstarted = 0;
-		isdn_net_hangup(lp);
+	   time_after(jiffies, idev->dialstarted + lp->dialtimeout)) {
+		idev->dialwait_timer = jiffies + lp->dialwait;
+		idev->dialstarted = 0;
+		isdn_net_hangup(idev);
 		return;
 	}
 	/*
 	 * Switch to next number or back to start if at end of list.
 	 */
-	isdn_slot_dial(lp->isdn_slot, &dial);
+	isdn_slot_dial(idev->isdn_slot, &dial);
 
-	lp->huptimer = 0;
-	lp->outgoing = 1;
-	if (lp->chargeint)
-		lp->charge_state = ST_CHARGE_HAVE_CINT;
+	idev->huptimer = 0;
+	idev->outgoing = 1;
+	if (idev->chargeint)
+		idev->charge_state = ST_CHARGE_HAVE_CINT;
 	else
-		lp->charge_state = ST_CHARGE_NULL;
+		idev->charge_state = ST_CHARGE_NULL;
 
 	if (lp->cbdelay && (lp->flags & ISDN_NET_CBOUT)) {
-		lp->dial_timer.expires = jiffies + lp->cbdelay;
-		lp->dial_event = EV_NET_TIMER_CB;
+		idev->dial_timer.expires = jiffies + lp->cbdelay;
+		idev->dial_event = EV_NET_TIMER_CB;
 	} else {
-		lp->dial_timer.expires = jiffies + 10 * HZ;
-		lp->dial_event = EV_NET_TIMER_OUT_DCONN;
+		idev->dial_timer.expires = jiffies + 10 * HZ;
+		idev->dial_event = EV_NET_TIMER_OUT_DCONN;
 	}
-	lp->dialstate = ST_OUT_WAIT_DCONN;
-	add_timer(&lp->dial_timer);
+	idev->dialstate = ST_OUT_WAIT_DCONN;
+	add_timer(&idev->dial_timer);
 }
 
 /* For EV_NET_DIAL, returns 1 if timer callback is needed 
@@ -583,86 +551,50 @@
 static int
 isdn_net_handle_event(isdn_net_local *lp, int pr, void *arg)
 {
-#ifdef CONFIG_ISDN_X25
-	struct concap_proto *cprot = lp -> netdev -> cprot;
-	struct concap_proto_ops *pops = cprot ? cprot -> pops : 0;
-#endif
-	isdn_net_dev *p = lp->netdev;
+	isdn_net_dev *idev = lp->netdev;
 	isdn_ctrl *c = arg;
 	isdn_ctrl cmd;
 
 	dbg_net_dial("%s: dialstate=%d pr=%#x\n", lp->name, lp->dialstate,pr);
 
-	switch (lp->dialstate) {
+	switch (idev->dialstate) {
 	case ST_ACTIVE:
 		switch (pr) {
 		case ISDN_STAT_BSENT:
 			/* A packet has successfully been sent out */
-			if (lp->flags & ISDN_NET_CONNECTED) {
-				isdn_net_dec_frame_cnt(lp);
-				lp->stats.tx_packets++;
-				lp->stats.tx_bytes += c->parm.length;
-				return 1;
-			}
-			break;
+			isdn_net_dec_frame_cnt(lp);
+			lp->stats.tx_packets++;
+			lp->stats.tx_bytes += c->parm.length;
+			return 1;
 		case ISDN_STAT_DHUP:
-			/* Either D-Channel-hangup or error during dialout */
-#ifdef CONFIG_ISDN_X25 // FIXME handle != ST_0?
-			/* If we are not connencted then dialing had
-			   failed. If there are generic encap protocol
-			   receiver routines signal the closure of
-			   the link*/
-			
-			if (!(lp->flags & ISDN_NET_CONNECTED)
-			    && pops && pops->disconn_ind)
-				pops -> disconn_ind(cprot);
-#endif /* CONFIG_ISDN_X25 */
-			if (lp->flags & ISDN_NET_CONNECTED) {
-				if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK)
-					isdn_net_ciscohdlck_disconnected(lp);
-#ifdef CONFIG_ISDN_PPP
-				if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
-					isdn_ppp_free(lp);
-#endif
-				isdn_net_lp_disconnected(lp);
-				isdn_slot_all_eaz(lp->isdn_slot);
-				printk(KERN_INFO "%s: remote hangup\n", lp->name);
-				printk(KERN_INFO "%s: Chargesum is %d\n", lp->name,
-				       lp->charge);
-				isdn_net_unbind_channel(lp);
-				return 1;
-			}
-			break;
-#ifdef CONFIG_ISDN_X25 // FIXME handle != ST_0?
-		case ISDN_STAT_BHUP:
-			/* B-Channel-hangup */
-			/* try if there are generic encap protocol
-			   receiver routines and signal the closure of
-			   the link */
-			if( pops  &&  pops -> disconn_ind ){
-				pops -> disconn_ind(cprot);
-				return 1;
-			}
-			break;
-#endif /* CONFIG_ISDN_X25 */
+			if (lp->ops->disconnected)
+				lp->ops->disconnected(lp);
+
+			isdn_net_lp_disconnected(lp);
+			isdn_slot_all_eaz(idev->isdn_slot);
+			printk(KERN_INFO "%s: remote hangup\n", idev->name);
+			printk(KERN_INFO "%s: Chargesum is %d\n", idev->name,
+			       idev->charge);
+			isdn_net_unbind_channel(lp);
+			return 1;
 		case ISDN_STAT_CINF:
 			/* Charge-info from TelCo. Calculate interval between
 			 * charge-infos and set timestamp for last info for
 			 * usage by isdn_net_autohup()
 			 */
-			lp->charge++;
-			switch (lp->charge_state) {
+			idev->charge++;
+			switch (idev->charge_state) {
 			case ST_CHARGE_NULL:
-				lp->charge_state = ST_CHARGE_GOT_CINF;
+				idev->charge_state = ST_CHARGE_GOT_CINF;
 				break;
 			case ST_CHARGE_GOT_CINF:
-				lp->charge_state = ST_CHARGE_HAVE_CINT;
+				idev->charge_state = ST_CHARGE_HAVE_CINT;
 				/* fall through */
 			case ST_CHARGE_HAVE_CINT:
-				lp->chargeint = jiffies - lp->chargetime - 2 * HZ;
+				idev->chargeint = jiffies - idev->chargetime - 2 * HZ;
 				break;
 			}
-			lp->chargetime = jiffies;
+			idev->chargetime = jiffies;
 			dbg_net_dial("%s: got CINF\n", lp->name);
 			return 1;
 		}
@@ -676,22 +608,22 @@
 		case EV_NET_TIMER_CB:
 			/* Remote does callback. Hangup after cbdelay, 
 			 * then wait for incoming call */
-			printk(KERN_INFO "%s: hangup waiting for callback ...\n", lp->name);
-			isdn_net_hangup(lp);
+			printk(KERN_INFO "%s: hangup waiting for callback ...\n", idev->name);
+			isdn_net_hangup(idev);
 			return 1;
 		case ISDN_STAT_DCONN:
 			/* Got D-Channel-Connect, send B-Channel-request */
-			del_timer(&lp->dial_timer);
-			lp->dialstate = ST_OUT_WAIT_BCONN;
-			isdn_slot_command(lp->isdn_slot, ISDN_CMD_ACCEPTB, &cmd);
-			lp->dial_timer.expires = jiffies + 10 * HZ;
-			lp->dial_event = EV_NET_TIMER_OUT_BCONN;
-			add_timer(&lp->dial_timer);
+			del_timer(&idev->dial_timer);
+			idev->dialstate = ST_OUT_WAIT_BCONN;
+			isdn_slot_command(idev->isdn_slot, ISDN_CMD_ACCEPTB, &cmd);
+			idev->dial_timer.expires = jiffies + 10 * HZ;
+			idev->dial_event = EV_NET_TIMER_OUT_BCONN;
+			add_timer(&idev->dial_timer);
 			return 1;
 		case ISDN_STAT_DHUP:
-			del_timer(&lp->dial_timer);
-			isdn_slot_all_eaz(lp->isdn_slot);
-			printk(KERN_INFO "%s: remote hangup\n", lp->name);
+			del_timer(&idev->dial_timer);
+			isdn_slot_all_eaz(idev->isdn_slot);
+			printk(KERN_INFO "%s: remote hangup\n", idev->name);
 			isdn_net_unbind_channel(lp);
 			return 1;
 		}
@@ -703,14 +635,14 @@
 			do_dialout(lp);
 			return 1;
 		case ISDN_STAT_BCONN:
-			del_timer(&lp->dial_timer);
-			isdn_slot_set_usage(lp->isdn_slot, isdn_slot_usage(lp->isdn_slot) | ISDN_USAGE_OUTGOING);
+			del_timer(&idev->dial_timer);
+			isdn_slot_set_usage(idev->isdn_slot, isdn_slot_usage(idev->isdn_slot) | ISDN_USAGE_OUTGOING);
 			isdn_net_connected(lp);
 			return 1;
 		case ISDN_STAT_DHUP:
-			del_timer(&lp->dial_timer);
-			isdn_slot_all_eaz(lp->isdn_slot);
-			printk(KERN_INFO "%s: remote hangup\n", lp->name);
+			del_timer(&idev->dial_timer);
+			isdn_slot_all_eaz(idev->isdn_slot);
+			printk(KERN_INFO "%s: remote hangup\n", idev->name);
 			isdn_net_unbind_channel(lp);
 			return 1;
 		}
@@ -718,20 +650,20 @@
 	case ST_IN_WAIT_DCONN:
 		switch (pr) {
 		case EV_NET_TIMER_IN_DCONN:
-			isdn_net_hangup(lp);
+			isdn_net_hangup(idev);
 			return 1;
 		case ISDN_STAT_DCONN:
-			del_timer(&lp->dial_timer);
-			lp->dialstate = ST_IN_WAIT_BCONN;
-			isdn_slot_command(lp->isdn_slot, ISDN_CMD_ACCEPTB, &cmd);
-			lp->dial_timer.expires = jiffies + 10 * HZ;
-			lp->dial_event = EV_NET_TIMER_IN_BCONN;
-			add_timer(&lp->dial_timer);
+			del_timer(&idev->dial_timer);
+			idev->dialstate = ST_IN_WAIT_BCONN;
+			isdn_slot_command(idev->isdn_slot, ISDN_CMD_ACCEPTB, &cmd);
+			idev->dial_timer.expires = jiffies + 10 * HZ;
+			idev->dial_event = EV_NET_TIMER_IN_BCONN;
+			add_timer(&idev->dial_timer);
 			return 1;
 		case ISDN_STAT_DHUP:
-			del_timer(&lp->dial_timer);
-			isdn_slot_all_eaz(lp->isdn_slot);
-			printk(KERN_INFO "%s: remote hangup\n", lp->name);
+			del_timer(&idev->dial_timer);
+			isdn_slot_all_eaz(idev->isdn_slot);
+			printk(KERN_INFO "%s: remote hangup\n", idev->name);
 			isdn_net_unbind_channel(lp);
 			return 1;
 		}
@@ -739,17 +671,17 @@
 	case ST_IN_WAIT_BCONN:
 		switch (pr) {
 		case EV_NET_TIMER_IN_BCONN:
-			isdn_net_hangup(lp);
+			isdn_net_hangup(idev);
 			break;
 		case ISDN_STAT_BCONN:
-			del_timer(&lp->dial_timer);
-			isdn_slot_set_rx_netdev(lp->isdn_slot, p);
+			del_timer(&idev->dial_timer);
+			isdn_slot_set_rx_netdev(idev->isdn_slot, idev);
 			isdn_net_connected(lp);
 			return 1;
 		case ISDN_STAT_DHUP:
-			del_timer(&lp->dial_timer);
-			isdn_slot_all_eaz(lp->isdn_slot);
-			printk(KERN_INFO "%s: remote hangup\n", lp->name);
+			del_timer(&idev->dial_timer);
+			isdn_slot_all_eaz(idev->isdn_slot);
+			printk(KERN_INFO "%s: remote hangup\n", idev->name);
 			isdn_net_unbind_channel(lp);
 			return 1;
 		}
@@ -774,43 +706,35 @@
  * Perform hangup for a net-interface.
  */
 void
-isdn_net_hangup(isdn_net_local *lp)
+isdn_net_hangup(isdn_net_dev *idev)
 {
+	isdn_net_local *lp = &idev->local;
 	isdn_ctrl cmd;
-#ifdef CONFIG_ISDN_X25
-	struct concap_proto *cprot = lp -> netdev -> cprot;
-	struct concap_proto_ops *pops = cprot ? cprot -> pops : 0;
-#endif
 
-	del_timer_sync(&lp->hup_timer);
-	if (lp->flags & ISDN_NET_CONNECTED) {
-		if (lp->slave != NULL) {
-			isdn_net_local *slp = (isdn_net_local *)lp->slave->priv;
-			if (slp->flags & ISDN_NET_CONNECTED) {
-				printk(KERN_INFO
-					"isdn_net: hang up slave %s before %s\n",
-					slp->name, lp->name);
-				isdn_net_hangup(slp);
-			}
+	del_timer_sync(&idev->hup_timer);
+	if (!isdn_net_bound(idev))
+		return;
+
+	// FIXME ugly and recursive
+	if (lp->slave != NULL) {
+		isdn_net_local *slp = (isdn_net_local *)lp->slave->priv;
+		isdn_net_dev *sidev = slp->netdev;
+		if (isdn_net_bound(sidev)) {
+			printk(KERN_INFO
+			       "isdn_net: hang up slave %s before %s\n",
+			       sidev->name, idev->name);
+			isdn_net_hangup(sidev);
 		}
-		printk(KERN_INFO "isdn_net: local hangup %s\n", lp->name);
-#ifdef CONFIG_ISDN_PPP
-		if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
-			isdn_ppp_free(lp);
-#endif
-		isdn_net_lp_disconnected(lp);
-#ifdef CONFIG_ISDN_X25
-		/* try if there are generic encap protocol
-		   receiver routines and signal the closure of
-		   the link */
-		if( pops && pops -> disconn_ind )
-		  pops -> disconn_ind(cprot);
-#endif /* CONFIG_ISDN_X25 */
-
-		isdn_slot_command(lp->isdn_slot, ISDN_CMD_HANGUP, &cmd);
-		printk(KERN_INFO "%s: Chargesum is %d\n", lp->name, lp->charge);
-		isdn_slot_all_eaz(lp->isdn_slot);
 	}
+	printk(KERN_INFO "isdn_net: local hangup %s\n", idev->name);
+	if (lp->ops->disconnected)
+		lp->ops->disconnected(lp);
+	
+	isdn_net_lp_disconnected(lp);
+	
+	isdn_slot_command(idev->isdn_slot, ISDN_CMD_HANGUP, &cmd);
+	printk(KERN_INFO "%s: Chargesum is %d\n", idev->name, idev->charge);
+	isdn_slot_all_eaz(idev->isdn_slot);
 	isdn_net_unbind_channel(lp);
 }
 
@@ -821,7 +745,7 @@
 
 	list_for_each(l, &isdn_net_devs) {
 		isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list);
-		isdn_net_hangup(&p->local);
+		isdn_net_hangup(p);
 	}
 }
 
@@ -833,6 +757,7 @@
 static void
 isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp)
 {
+	isdn_net_dev *idev = lp->netdev;
 	u_char *p = skb->nh.raw; /* hopefully, this was set correctly */
 	unsigned short proto = ntohs(skb->protocol);
 	int data_ofs;
@@ -845,7 +770,7 @@
 		/* fall back to old isdn_net_log_packet method() */
 		char * buf = skb->data;
 
-		printk(KERN_DEBUG "isdn_net: protocol %04x is buggy, dev %s\n", skb->protocol, lp->name);
+		printk(KERN_DEBUG "isdn_net: protocol %04x is buggy, dev %s\n", skb->protocol, idev->name);
 		p = buf;
 		proto = ETH_P_IP;
 		switch (lp->p_encap) {
@@ -861,12 +786,10 @@
 				proto = ntohs(*(unsigned short *) &buf[2]);
 				p = &buf[4];
 				break;
-#ifdef CONFIG_ISDN_PPP
 			case ISDN_NET_ENCAP_SYNCPPP:
 				proto = ntohs(skb->protocol);
 				p = &buf[IPPP_MAX_HEADER];
 				break;
-#endif
 		}
 	}
 	data_ofs = ((p[0] & 15) * 4);
@@ -967,6 +890,7 @@
  */
 void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb)
 {
+	isdn_net_dev *idev = lp->netdev;
 	int ret;
 	int len = skb->len;     /* save len */
 
@@ -977,25 +901,24 @@
 		goto error;
 	}
 
-	if (!(lp->flags & ISDN_NET_CONNECTED)) {
+	if (!isdn_net_online(idev)) {
 		isdn_BUG();
 		goto error;
 	}
-	ret = isdn_slot_write(lp->isdn_slot, skb);
+	ret = isdn_slot_write(idev->isdn_slot, skb);
 	if (ret != len) {
 		/* we should never get here */
-		printk(KERN_WARNING "%s: HL driver queue full\n", lp->name);
+		printk(KERN_WARNING "%s: HL driver queue full\n", idev->name);
 		goto error;
 	}
 	
-	lp->transcount += len;
+	idev->transcount += len;
 	isdn_net_inc_frame_cnt(lp);
 	return;
 
  error:
 	dev_kfree_skb(skb);
 	lp->stats.tx_errors++;
-
 }
 
 
@@ -1013,33 +936,32 @@
 static int
 isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb)
 {
-	isdn_net_dev *nd;
+	isdn_net_dev *nd, *idev;
 	isdn_net_local *slp;
-	isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+	isdn_net_local *lp = ndev->priv;
 	int retv = 0;
 
-	if (((isdn_net_local *) (ndev->priv))->master) {
+	if (lp->master) {
 		isdn_BUG();
 		dev_kfree_skb(skb);
 		return 0;
 	}
 
 	/* For the other encaps the header has already been built */
-#ifdef CONFIG_ISDN_PPP
 	if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
 		return isdn_ppp_xmit(skb, ndev);
 	}
-#endif
 	nd = ((isdn_net_local *) ndev->priv)->netdev;
 	lp = isdn_net_get_locked_lp(nd);
 	if (!lp) {
 		printk(KERN_WARNING "%s: all channels busy - requeuing!\n", ndev->name);
 		return 1;
 	}
+	idev = lp->netdev;
 	/* we have our lp locked from now on */
 
 	/* Reset hangup-timeout */
-	lp->huptimer = 0; // FIXME?
+	idev->huptimer = 0; // FIXME?
 	isdn_net_writebuf_skb(lp, skb);
 	spin_unlock_bh(&lp->xmit_lock);
 
@@ -1048,15 +970,15 @@
 	 * should move to userspace and get based on an overall cps
 	 * calculation
 	 */
-	if (jiffies != lp->last_jiffies) {
-		lp->cps = lp->transcount * HZ / (jiffies - lp->last_jiffies);
-		lp->last_jiffies = jiffies;
-		lp->transcount = 0;
+	if (jiffies != idev->last_jiffies) {
+		idev->cps = idev->transcount * HZ / (jiffies - idev->last_jiffies);
+		idev->last_jiffies = jiffies;
+		idev->transcount = 0;
 	}
 	if (dev->net_verbose > 3)
-		printk(KERN_DEBUG "%s: %d bogocps\n", lp->name, lp->cps);
+		printk(KERN_DEBUG "%s: %d bogocps\n", idev->name, idev->cps);
 
-	if (lp->cps > lp->triggercps) {
+	if (idev->cps > lp->triggercps) {
 		if (lp->slave) {
 			if (!lp->sqfull) {
 				/* First time overload: set timestamp only */
@@ -1066,7 +988,7 @@
 				/* subsequent overload: if slavedelay exceeded, start dialing */
 				if (time_after(jiffies, lp->sqfull_stamp + lp->slavedelay)) {
 					slp = lp->slave->priv;
-					if (!(slp->flags & ISDN_NET_CONNECTED)) {
+					if (!isdn_net_bound(slp->netdev)) {
 						isdn_net_force_dial_lp((isdn_net_local *) lp->slave->priv);
 					}
 				}
@@ -1087,7 +1009,7 @@
 static void
 isdn_net_adjust_hdr(struct sk_buff *skb, struct net_device *dev)
 {
-	isdn_net_local *lp = (isdn_net_local *) dev->priv;
+	isdn_net_local *lp = dev->priv;
 	if (!skb)
 		return;
 	if (lp->p_encap == ISDN_NET_ENCAP_ETHER) {
@@ -1102,32 +1024,52 @@
 
 void isdn_net_tx_timeout(struct net_device * ndev)
 {
-	isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+	isdn_net_local *lp = ndev->priv;
+	isdn_net_dev *idev = lp->netdev;
+
+	printk(KERN_WARNING "isdn_tx_timeout dev %s %d\n",
+	       ndev->name, idev->dialstate);
 
-	printk(KERN_WARNING "isdn_tx_timeout dev %s dialstate %d\n", ndev->name, lp->dialstate);
-	if (lp->dialstate == ST_ACTIVE){
-		lp->stats.tx_errors++;
-                /*
-		 * There is a certain probability that this currently
-		 * works at all because if we always wake up the interface,
-		 * then upper layer will try to send the next packet
-		 * immediately. And then, the old clean_up logic in the
-		 * driver will hopefully continue to work as it used to do.
-		 *
-		 * This is rather primitive right know, we better should
-		 * clean internal queues here, in particular for multilink and
-		 * ppp, and reset HL driver's channel, too.   --HE
-		 *
-		 * actually, this may not matter at all, because ISDN hardware
-		 * should not see transmitter hangs at all IMO
-		 * changed KERN_DEBUG to KERN_WARNING to find out if this is 
-		 * ever called   --KG
-		 */
-	}
-	ndev->trans_start = jiffies;
 	netif_wake_queue(ndev);
 }
 
+static int
+isdn_net_autodial(struct sk_buff *skb, struct net_device *ndev)
+{
+	isdn_net_local *lp = ndev->priv;
+	isdn_net_dev *idev = lp->netdev;
+
+	if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO))
+		goto discard;
+
+	if (idev->dialwait_timer <= 0)
+		if (idev->dialstarted > 0 && lp->dialtimeout > 0 && time_before(jiffies, idev->dialstarted + lp->dialtimeout + lp->dialwait))
+			idev->dialwait_timer = idev->dialstarted + lp->dialtimeout + lp->dialwait;
+		
+	if (idev->dialwait_timer > 0) {
+		if(time_before(jiffies, idev->dialwait_timer))
+			goto discard;
+
+		idev->dialwait_timer = 0;
+	}
+
+	if (isdn_net_force_dial_lp(lp) < 0)
+		goto discard;
+
+	/* Log packet, which triggered dialing */
+	if (dev->net_verbose)
+		isdn_net_log_skb(skb, lp);
+
+	netif_stop_queue(ndev);
+	return 1;
+
+ discard:
+	isdn_net_unreachable(ndev, skb, "dial rejected");
+	dev_kfree_skb(skb);
+	return 0;
+}
+
+
 /*
  * Try sending a packet.
  * If this interface isn't connected to a ISDN-Channel, find a free channel,
@@ -1136,123 +1078,33 @@
 static int
 isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
-	unsigned long flags;
-	isdn_net_local *lp = (isdn_net_local *) ndev->priv;
-#ifdef CONFIG_ISDN_X25
-	struct concap_proto * cprot = lp -> netdev -> cprot;
-#endif
-#ifdef CONFIG_ISDN_X25
-/* At this point hard_start_xmit() passes control to the encapsulation
-   protocol (if present).
-   For X.25 auto-dialing is completly bypassed because:
-   - It does not conform with the semantics of a reliable datalink
-     service as needed by X.25 PLP.
-   - I don't want that the interface starts dialing when the network layer
-     sends a message which requests to disconnect the lapb link (or if it
-     sends any other message not resulting in data transmission).
-   Instead, dialing will be initiated by the encapsulation protocol entity
-   when a dl_establish request is received from the upper layer.
-*/
-	if( cprot ) {
-		int ret = cprot -> pops -> encap_and_xmit ( cprot , skb);
-		if(ret) netif_stop_queue(ndev);
-		return ret;
-	} else
-#endif
+	isdn_net_local *lp = ndev->priv;
+	isdn_net_dev *idev = lp->netdev;
+	int retval;
+
+	if (lp->p_encap == ISDN_NET_ENCAP_X25IFACE)
+		return isdn_x25_start_xmit(skb, ndev);
+		
 	/* auto-dialing xmit function */
-	{
-		isdn_net_adjust_hdr(skb, ndev);
-		isdn_dumppkt("S:", skb->data, skb->len, 40);
-
-		if (!(lp->flags & ISDN_NET_CONNECTED)) {
-			int chi;
-			/* only do autodial if allowed by config */
-			if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) {
-				isdn_net_unreachable(ndev, skb, "dial rejected: interface not in dialmode `auto'");
-				dev_kfree_skb(skb);
-				return 0;
-			}
+	isdn_net_adjust_hdr(skb, ndev);
+	isdn_dumppkt("S:", skb->data, skb->len, 40);
+	
+	if (!isdn_net_bound(idev))
+		return isdn_net_autodial(skb, ndev);
 
-			save_flags(flags);
-			cli();
+	/* Device is bound to an ISDN channel */ 
+	ndev->trans_start = jiffies;
 
-			if(lp->dialwait_timer <= 0)
-				if(lp->dialstarted > 0 && lp->dialtimeout > 0 && time_before(jiffies, lp->dialstarted + lp->dialtimeout + lp->dialwait))
-					lp->dialwait_timer = lp->dialstarted + lp->dialtimeout + lp->dialwait;
-			
-			if(lp->dialwait_timer > 0) {
-				if(time_before(jiffies, lp->dialwait_timer)) {
-					isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached");
-					dev_kfree_skb(skb);
-					restore_flags(flags);
-					return 0;
-				} else
-					lp->dialwait_timer = 0;
-			}
-			/* Grab a free ISDN-Channel */
-			if (((chi =
-			      isdn_get_free_slot(
-				      ISDN_USAGE_NET,
-				      lp->l2_proto,
-				      lp->l3_proto,
-				      lp->pre_device,
-				      lp->pre_channel,
-				      lp->msn)
-				     ) < 0) &&
-			    ((chi =
-			      isdn_get_free_slot(
-				      ISDN_USAGE_NET,
-				      lp->l2_proto,
-				      lp->l3_proto,
-				      lp->pre_device,
-				      lp->pre_channel^1,
-				      lp->msn)
-				    ) < 0)) {
-				restore_flags(flags);
-				isdn_net_unreachable(ndev, skb,
-						     "No channel");
-				dev_kfree_skb(skb);
-				return 0;
-			}
-			/* Log packet, which triggered dialing */
-			if (dev->net_verbose)
-				isdn_net_log_skb(skb, lp);
-			/* Connect interface with channel */
-			isdn_net_bind_channel(lp, chi);
-#ifdef CONFIG_ISDN_PPP
-			if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
-				/* no 'first_skb' handling for syncPPP */
-				if (isdn_ppp_bind(lp) < 0) {
-					dev_kfree_skb(skb);
-					isdn_net_unbind_channel(lp);
-					restore_flags(flags);
-					return 0;	/* STN (skb to nirvana) ;) */
-				}
-				restore_flags(flags);
-				init_dialout(lp);
-				netif_stop_queue(ndev);
-				return 1;	/* let upper layer requeue skb packet */
-			}
-#endif
-			/* Initiate dialing */
-			restore_flags(flags);
-			init_dialout(lp);
-			isdn_net_device_stop_queue(lp);
-			return 1;
-		} else {
-			/* Device is connected to an ISDN channel */ 
-			ndev->trans_start = jiffies;
-			if (lp->dialstate == ST_ACTIVE) {
-				/* ISDN connection is established, try sending */
-				int ret;
-				ret = (isdn_net_xmit(ndev, skb));
-				if(ret) netif_stop_queue(ndev);
-				return ret;
-			} else
-				netif_stop_queue(ndev);
-		}
+	if (idev->dialstate != ST_ACTIVE) {
+		netif_stop_queue(ndev);
+		return 1;
 	}
-	return 1;
+	/* ISDN connection is established, try sending */
+	retval = isdn_net_xmit(ndev, skb);
+	if (retval)
+		netif_stop_queue(ndev);
+
+	return retval;
 }
 
 /*
@@ -1262,29 +1114,16 @@
 isdn_net_close(struct net_device *dev)
 {
 	struct net_device *p;
-#ifdef CONFIG_ISDN_X25
-	struct concap_proto * cprot =
-		( (isdn_net_local *) dev->priv ) -> netdev -> cprot;
-	/* printk(KERN_DEBUG "isdn_net_close %s\n" , dev-> name ); */
-#endif
+	isdn_net_local *lp = dev->priv;
+
+	if (lp->ops->close)
+		lp->ops->close(lp);
 
-#ifdef CONFIG_ISDN_X25
-	if( cprot && cprot -> pops ) cprot -> pops -> close( cprot );
-#endif
 	netif_stop_queue(dev);
-	if ((p = (((isdn_net_local *) dev->priv)->slave))) {
-		/* If this interface has slaves, stop them also */
-		while (p) {
-#ifdef CONFIG_ISDN_X25
-			cprot = ( (isdn_net_local *) p->priv )
-				-> netdev -> cprot;
-			if( cprot && cprot -> pops )
-				cprot -> pops -> close( cprot );
-#endif
-			isdn_net_hangup(p->priv);
-			p = (((isdn_net_local *) p->priv)->slave);
-		}
-	}
+	
+	for (p = lp->slave; p; p = ((isdn_net_local *) p->priv)->slave)
+		isdn_net_hangup(p->priv);
+
 	isdn_net_hangup(dev->priv);
 	isdn_MOD_DEC_USE_COUNT();
 	return 0;
@@ -1300,417 +1139,6 @@
 	return &lp->stats;
 }
 
-/*      This is simply a copy from std. eth.c EXCEPT we pull ETH_HLEN
- *      instead of dev->hard_header_len off. This is done because the
- *      lowlevel-driver has already pulled off its stuff when we get
- *      here and this routine only gets called with p_encap == ETHER.
- *      Determine the packet's protocol ID. The rule here is that we
- *      assume 802.3 if the type field is short enough to be a length.
- *      This is normal practice and works for any 'now in use' protocol.
- */
-
-static unsigned short
-isdn_net_type_trans(struct sk_buff *skb, struct net_device *dev)
-{
-	struct ethhdr *eth;
-	unsigned char *rawp;
-
-	skb->mac.raw = skb->data;
-	skb_pull(skb, ETH_HLEN);
-	eth = skb->mac.ethernet;
-
-	if (*eth->h_dest & 1) {
-		if (memcmp(eth->h_dest, dev->broadcast, ETH_ALEN) == 0)
-			skb->pkt_type = PACKET_BROADCAST;
-		else
-			skb->pkt_type = PACKET_MULTICAST;
-	}
-	/*
-	 *      This ALLMULTI check should be redundant by 1.4
-	 *      so don't forget to remove it.
-	 */
-
-	else if (dev->flags & (IFF_PROMISC /*| IFF_ALLMULTI*/)) {
-		if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN))
-			skb->pkt_type = PACKET_OTHERHOST;
-	}
-	if (ntohs(eth->h_proto) >= 1536)
-		return eth->h_proto;
-
-	rawp = skb->data;
-
-	/*
-	 *      This is a magic hack to spot IPX packets. Older Novell breaks
-	 *      the protocol design and runs IPX over 802.3 without an 802.2 LLC
-	 *      layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
-	 *      won't work for fault tolerant netware but does for the rest.
-	 */
-	if (*(unsigned short *) rawp == 0xFFFF)
-		return htons(ETH_P_802_3);
-	/*
-	 *      Real 802.2 LLC
-	 */
-	return htons(ETH_P_802_2);
-}
-
-
-/* 
- * CISCO HDLC keepalive specific stuff
- */
-static struct sk_buff*
-isdn_net_ciscohdlck_alloc_skb(isdn_net_local *lp, int len)
-{
-	unsigned short hl = isdn_slot_hdrlen(lp->isdn_slot);
-	struct sk_buff *skb;
-
-	skb = alloc_skb(hl + len, GFP_ATOMIC);
-	if (!skb) {
-		printk("isdn out of mem at %s:%d!\n", __FILE__, __LINE__);
-		return 0;
-	}
-	skb_reserve(skb, hl);
-	return skb;
-}
-
-/* cisco hdlck device private ioctls */
-int
-isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
-	isdn_net_local *lp = (isdn_net_local *) dev->priv;
-	unsigned long len = 0;
-	unsigned long expires = 0;
-	int tmp = 0;
-	int period = lp->cisco_keepalive_period;
-	char debserint = lp->cisco_debserint;
-	int rc = 0;
-
-	if (lp->p_encap != ISDN_NET_ENCAP_CISCOHDLCK)
-		return -EINVAL;
-
-	switch (cmd) {
-		/* get/set keepalive period */
-		case SIOCGKEEPPERIOD:
-			len = (unsigned long)sizeof(lp->cisco_keepalive_period);
-			if (copy_to_user((char *)ifr->ifr_ifru.ifru_data,
-				(int *)&lp->cisco_keepalive_period, len))
-				rc = -EFAULT;
-			break;
-		case SIOCSKEEPPERIOD:
-			tmp = lp->cisco_keepalive_period;
-			len = (unsigned long)sizeof(lp->cisco_keepalive_period);
-			if (copy_from_user((int *)&period,
-				(char *)ifr->ifr_ifru.ifru_data, len))
-				rc = -EFAULT;
-			if ((period > 0) && (period <= 32767))
-				lp->cisco_keepalive_period = period;
-			else
-				rc = -EINVAL;
-			if (!rc && (tmp != lp->cisco_keepalive_period)) {
-				expires = (unsigned long)(jiffies +
-					lp->cisco_keepalive_period * HZ);
-				mod_timer(&lp->cisco_timer, expires);
-				printk(KERN_INFO "%s: Keepalive period set "
-					"to %d seconds.\n",
-					lp->name, lp->cisco_keepalive_period);
-			}
-			break;
-
-		/* get/set debugging */
-		case SIOCGDEBSERINT:
-			len = (unsigned long)sizeof(lp->cisco_debserint);
-			if (copy_to_user((char *)ifr->ifr_ifru.ifru_data,
-				(char *)&lp->cisco_debserint, len))
-				rc = -EFAULT;
-			break;
-		case SIOCSDEBSERINT:
-			len = (unsigned long)sizeof(lp->cisco_debserint);
-			if (copy_from_user((char *)&debserint,
-				(char *)ifr->ifr_ifru.ifru_data, len))
-				rc = -EFAULT;
-			if ((debserint >= 0) && (debserint <= 64))
-				lp->cisco_debserint = debserint;
-			else
-				rc = -EINVAL;
-			break;
-
-		default:
-			rc = -EINVAL;
-			break;
-	}
-	return (rc);
-}
-
-/* called via cisco_timer.function */
-static void
-isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data)
-{
-	isdn_net_local *lp = (isdn_net_local *) data;
-	struct sk_buff *skb;
-	unsigned char *p;
-	unsigned long last_cisco_myseq = lp->cisco_myseq;
-	int myseq_diff = 0;
-
-	if (!(lp->flags & ISDN_NET_CONNECTED) || lp->dialstate != ST_ACTIVE) {
-		isdn_BUG();
-		return;
-	}
-	lp->cisco_myseq++;
-
-	myseq_diff = (lp->cisco_myseq - lp->cisco_mineseen);
-	if ((lp->cisco_line_state) && ((myseq_diff >= 3)||(myseq_diff <= -3))) {
-		/* line up -> down */
-		lp->cisco_line_state = 0;
-		printk (KERN_WARNING
-				"UPDOWN: Line protocol on Interface %s,"
-				" changed state to down\n", lp->name);
-		/* should stop routing higher-level data accross */
-	} else if ((!lp->cisco_line_state) &&
-		(myseq_diff >= 0) && (myseq_diff <= 2)) {
-		/* line down -> up */
-		lp->cisco_line_state = 1;
-		printk (KERN_WARNING
-				"UPDOWN: Line protocol on Interface %s,"
-				" changed state to up\n", lp->name);
-		/* restart routing higher-level data accross */
-	}
-
-	if (lp->cisco_debserint)
-		printk (KERN_DEBUG "%s: HDLC "
-			"myseq %lu, mineseen %lu%c, yourseen %lu, %s\n",
-			lp->name, last_cisco_myseq, lp->cisco_mineseen,
-			((last_cisco_myseq == lp->cisco_mineseen) ? '*' : 040),
-			lp->cisco_yourseq,
-			((lp->cisco_line_state) ? "line up" : "line down"));
-
-	skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
-	if (!skb)
-		return;
-
-	p = skb_put(skb, 4 + 14);
-
-	/* cisco header */
-	p += put_u8 (p, CISCO_ADDR_UNICAST);
-	p += put_u8 (p, CISCO_CTRL);
-	p += put_u16(p, CISCO_TYPE_SLARP);
-
-	/* slarp keepalive */
-	p += put_u32(p, CISCO_SLARP_KEEPALIVE);
-	p += put_u32(p, lp->cisco_myseq);
-	p += put_u32(p, lp->cisco_yourseq);
-	p += put_u16(p, 0xffff); // reliablity, always 0xffff
-
-	isdn_net_write_super(lp, skb);
-
-	lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ;
-	
-	add_timer(&lp->cisco_timer);
-}
-
-static void
-isdn_net_ciscohdlck_slarp_send_request(isdn_net_local *lp)
-{
-	struct sk_buff *skb;
-	unsigned char *p;
-
-	skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
-	if (!skb)
-		return;
-
-	p = skb_put(skb, 4 + 14);
-
-	/* cisco header */
-	p += put_u8 (p, CISCO_ADDR_UNICAST);
-	p += put_u8 (p, CISCO_CTRL);
-	p += put_u16(p, CISCO_TYPE_SLARP);
-
-	/* slarp request */
-	p += put_u32(p, CISCO_SLARP_REQUEST);
-	p += put_u32(p, 0); // address
-	p += put_u32(p, 0); // netmask
-	p += put_u16(p, 0); // unused
-
-	isdn_net_write_super(lp, skb);
-}
-
-static void 
-isdn_net_ciscohdlck_connected(isdn_net_local *lp)
-{
-	lp->cisco_myseq = 0;
-	lp->cisco_mineseen = 0;
-	lp->cisco_yourseq = 0;
-	lp->cisco_keepalive_period = ISDN_TIMER_KEEPINT;
-	lp->cisco_last_slarp_in = 0;
-	lp->cisco_line_state = 0;
-	lp->cisco_debserint = 0;
-
-	/* send slarp request because interface/seq.no.s reset */
-	isdn_net_ciscohdlck_slarp_send_request(lp);
-
-	init_timer(&lp->cisco_timer);
-	lp->cisco_timer.data = (unsigned long) lp;
-	lp->cisco_timer.function = isdn_net_ciscohdlck_slarp_send_keepalive;
-	lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ;
-	add_timer(&lp->cisco_timer);
-}
-
-static void 
-isdn_net_ciscohdlck_disconnected(isdn_net_local *lp)
-{
-	del_timer(&lp->cisco_timer);
-}
-
-static void
-isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp)
-{
-	struct sk_buff *skb;
-	unsigned char *p;
-	struct in_device *in_dev = NULL;
-	u32 addr = 0;		/* local ipv4 address */
-	u32 mask = 0;		/* local netmask */
-
-	if ((in_dev = lp->netdev->dev.ip_ptr) != NULL) {
-		/* take primary(first) address of interface */
-		struct in_ifaddr *ifa = in_dev->ifa_list;
-		if (ifa != NULL) {
-			addr = ifa->ifa_local;
-			mask = ifa->ifa_mask;
-		}
-	}
-
-	skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14);
-	if (!skb)
-		return;
-
-	p = skb_put(skb, 4 + 14);
-
-	/* cisco header */
-	p += put_u8 (p, CISCO_ADDR_UNICAST);
-	p += put_u8 (p, CISCO_CTRL);
-	p += put_u16(p, CISCO_TYPE_SLARP);
-
-	/* slarp reply, send own ip/netmask; if values are nonsense remote
-	 * should think we are unable to provide it with an address via SLARP */
-	p += put_u32(p, CISCO_SLARP_REPLY);
-	p += put_u32(p, addr);	// address
-	p += put_u32(p, mask);	// netmask
-	p += put_u16(p, 0);	// unused
-
-	isdn_net_write_super(lp, skb);
-}
-
-static void
-isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb)
-{
-	unsigned char *p;
-	int period;
-	u32 code;
-	u32 my_seq, addr;
-	u32 your_seq, mask;
-	u32 local;
-	u16 unused;
-
-	if (skb->len < 14)
-		return;
-
-	p = skb->data;
-	p += get_u32(p, &code);
-	
-	switch (code) {
-	case CISCO_SLARP_REQUEST:
-		lp->cisco_yourseq = 0;
-		isdn_net_ciscohdlck_slarp_send_reply(lp);
-		break;
-	case CISCO_SLARP_REPLY:
-		addr = ntohl(*(u32 *)p);
-		mask = ntohl(*(u32 *)(p+4));
-		if (mask != 0xfffffffc)
-			goto slarp_reply_out;
-		if ((addr & 3) == 0 || (addr & 3) == 3)
-			goto slarp_reply_out;
-		local = addr ^ 3;
-		printk(KERN_INFO "%s: got slarp reply: "
-			"remote ip: %d.%d.%d.%d, "
-			"local ip: %d.%d.%d.%d "
-			"mask: %d.%d.%d.%d\n",
-		       lp->name,
-		       HIPQUAD(addr),
-		       HIPQUAD(local),
-		       HIPQUAD(mask));
-		break;
-  slarp_reply_out:
-		 printk(KERN_INFO "%s: got invalid slarp "
-				 "reply (%d.%d.%d.%d/%d.%d.%d.%d) "
-				 "- ignored\n", lp->name,
-				 HIPQUAD(addr), HIPQUAD(mask));
-		break;
-	case CISCO_SLARP_KEEPALIVE:
-		period = (int)((jiffies - lp->cisco_last_slarp_in
-				+ HZ/2 - 1) / HZ);
-		if (lp->cisco_debserint &&
-				(period != lp->cisco_keepalive_period) &&
-				lp->cisco_last_slarp_in) {
-			printk(KERN_DEBUG "%s: Keepalive period mismatch - "
-				"is %d but should be %d.\n",
-				lp->name, period, lp->cisco_keepalive_period);
-		}
-		lp->cisco_last_slarp_in = jiffies;
-		p += get_u32(p, &my_seq);
-		p += get_u32(p, &your_seq);
-		p += get_u16(p, &unused);
-		lp->cisco_yourseq = my_seq;
-		lp->cisco_mineseen = your_seq;
-		break;
-	}
-}
-
-static void
-isdn_net_ciscohdlck_receive(isdn_net_local *lp, struct sk_buff *skb)
-{
-	unsigned char *p;
- 	u8 addr;
- 	u8 ctrl;
- 	u16 type;
-	
-	if (skb->len < 4)
-		goto out_free;
-
-	p = skb->data;
-	p += get_u8 (p, &addr);
-	p += get_u8 (p, &ctrl);
-	p += get_u16(p, &type);
-	skb_pull(skb, 4);
-	
-	if (addr != CISCO_ADDR_UNICAST && addr != CISCO_ADDR_BROADCAST) {
-		printk(KERN_WARNING "%s: Unknown Cisco addr 0x%02x\n",
-		       lp->name, addr);
-		goto out_free;
-	}
-	if (ctrl != CISCO_CTRL) {
-		printk(KERN_WARNING "%s: Unknown Cisco ctrl 0x%02x\n",
-		       lp->name, ctrl);
-		goto out_free;
-	}
-
-	switch (type) {
-	case CISCO_TYPE_SLARP:
-		isdn_net_ciscohdlck_slarp_in(lp, skb);
-		goto out_free;
-	case CISCO_TYPE_CDP:
-		if (lp->cisco_debserint)
-			printk(KERN_DEBUG "%s: Received CDP packet. use "
-				"\"no cdp enable\" on cisco.\n", lp->name);
-		goto out_free;
-	default:
-		/* no special cisco protocol */
-		skb->protocol = htons(type);
-		netif_rx(skb);
-		return;
-	}
-
- out_free:
-	kfree_skb(skb);
-}
-
 /*
  * Got a packet from ISDN-Channel.
  */
@@ -1718,14 +1146,10 @@
 isdn_net_receive(struct net_device *ndev, struct sk_buff *skb)
 {
 	isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+	isdn_net_dev *idev = lp->netdev;
 	isdn_net_local *olp = lp;	/* original 'lp' */
-#ifdef CONFIG_ISDN_PPP
-	int proto = PPP_PROTOCOL(skb->data);
-#endif
-#ifdef CONFIG_ISDN_X25
-	struct concap_proto *cprot = lp -> netdev -> cprot;
-#endif
-	lp->transcount += skb->len;
+
+	idev->transcount += skb->len;
 
 	lp->stats.rx_packets++;
 	lp->stats.rx_bytes += skb->len;
@@ -1742,72 +1166,8 @@
 	skb->pkt_type = PACKET_HOST;
 	skb->mac.raw = skb->data;
 	isdn_dumppkt("R:", skb->data, skb->len, 40);
-	switch (lp->p_encap) {
-		case ISDN_NET_ENCAP_ETHER:
-			/* Ethernet over ISDN */
-			olp->huptimer = 0;
-			lp->huptimer = 0;
-			skb->protocol = isdn_net_type_trans(skb, ndev);
-			break;
-		case ISDN_NET_ENCAP_UIHDLC:
-			/* HDLC with UI-frame (for ispa with -h1 option) */
-			olp->huptimer = 0;
-			lp->huptimer = 0;
-			skb_pull(skb, 2);
-			/* Fall through */
-		case ISDN_NET_ENCAP_RAWIP:
-			/* RAW-IP without MAC-Header */
-			olp->huptimer = 0;
-			lp->huptimer = 0;
-			skb->protocol = htons(ETH_P_IP);
-			break;
-		case ISDN_NET_ENCAP_CISCOHDLCK:
-			isdn_net_ciscohdlck_receive(lp, skb);
-			return;
-		case ISDN_NET_ENCAP_CISCOHDLC:
-			/* CISCO-HDLC IP with type field and  fake I-frame-header */
-			skb_pull(skb, 2);
-			/* Fall through */
-		case ISDN_NET_ENCAP_IPTYP:
-			/* IP with type field */
-			olp->huptimer = 0;
-			lp->huptimer = 0;
-			skb->protocol = *(unsigned short *) &(skb->data[0]);
-			skb_pull(skb, 2);
-			if (*(unsigned short *) skb->data == 0xFFFF)
-				skb->protocol = htons(ETH_P_802_3);
-			break;
-#ifdef CONFIG_ISDN_PPP
-		case ISDN_NET_ENCAP_SYNCPPP:
-			/*
-			 * If encapsulation is syncppp, don't reset
-			 * huptimer on LCP packets.
-			 */
-			if (proto != PPP_LCP) {
-				olp->huptimer = 0;
-				lp->huptimer = 0;
-			}
-			isdn_ppp_receive(lp->netdev, olp, skb);
-			return;
-#endif
-
-		default:
-#ifdef CONFIG_ISDN_X25
-		  /* try if there are generic sync_device receiver routines */
-			if(cprot) if(cprot -> pops)
-				if( cprot -> pops -> data_ind){
-					cprot -> pops -> data_ind(cprot,skb);
-					return;
-				};
-#endif /* CONFIG_ISDN_X25 */
-			printk(KERN_WARNING "%s: unknown encapsulation, dropping\n",
-			       lp->name);
-			kfree_skb(skb);
-			return;
-	}
 
-	netif_rx(skb);
-	return;
+	lp->ops->receive(lp->netdev, olp, skb);
 }
 
 /*
@@ -1818,149 +1178,16 @@
 int
 isdn_net_rcv_skb(int idx, struct sk_buff *skb)
 {
-	isdn_net_dev *p = isdn_slot_rx_netdev(idx);
-
-	if (p) {
-		isdn_net_local *lp = &p->local;
-		if ((lp->flags & ISDN_NET_CONNECTED) &&
-		    (lp->dialstate == ST_ACTIVE)) {
-			isdn_net_receive(&p->dev, skb);
-			return 1;
-		}
-	}
-	return 0;
-}
-
-static int
-my_eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
-	      void *daddr, void *saddr, unsigned len)
-{
-	struct ethhdr *eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
-
-	/*
-	 * Set the protocol type. For a packet of type ETH_P_802_3 we
-	 * put the length here instead. It is up to the 802.2 layer to
-	 * carry protocol information.
-	 */
-
-	if (type != ETH_P_802_3)
-		eth->h_proto = htons(type);
-	else
-		eth->h_proto = htons(len);
-
-	/*
-	 * Set the source hardware address.
-	 */
-	if (saddr)
-		memcpy(eth->h_source, saddr, dev->addr_len);
-	else
-		memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
-
-	/*
-	 * Anyway, the loopback-device should never use this function...
-	 */
+	isdn_net_dev *idev = isdn_slot_rx_netdev(idx);
 
-	if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
-		memset(eth->h_dest, 0, dev->addr_len);
-		return ETH_HLEN /*(dev->hard_header_len)*/;
-	}
-	if (daddr) {
-		memcpy(eth->h_dest, daddr, dev->addr_len);
-		return ETH_HLEN /*dev->hard_header_len*/;
-	}
-	return -ETH_HLEN /*dev->hard_header_len*/;
-}
-
-/*
- *  build an header
- *  depends on encaps that is being used.
- */
-
-static int
-isdn_net_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
-		void *daddr, void *saddr, unsigned plen)
-{
-	isdn_net_local *lp = dev->priv;
-	unsigned char *p;
-	ushort len = 0;
-
-	switch (lp->p_encap) {
-		case ISDN_NET_ENCAP_ETHER:
-			len = my_eth_header(skb, dev, type, daddr, saddr, plen);
-			break;
-#ifdef CONFIG_ISDN_PPP
-		case ISDN_NET_ENCAP_SYNCPPP:
-			/* stick on a fake header to keep fragmentation code happy. */
-			len = IPPP_MAX_HEADER;
-			skb_push(skb,len);
-			break;
-#endif
-		case ISDN_NET_ENCAP_RAWIP:
-			printk(KERN_WARNING "isdn_net_header called with RAW_IP!\n");
-			len = 0;
-			break;
-		case ISDN_NET_ENCAP_IPTYP:
-			/* ethernet type field */
-			*((ushort *) skb_push(skb, 2)) = htons(type);
-			len = 2;
-			break;
-		case ISDN_NET_ENCAP_UIHDLC:
-			/* HDLC with UI-Frames (for ispa with -h1 option) */
-			*((ushort *) skb_push(skb, 2)) = htons(0x0103);
-			len = 2;
-			break;
-		case ISDN_NET_ENCAP_CISCOHDLC:
-		case ISDN_NET_ENCAP_CISCOHDLCK:
-			p = skb_push(skb, 4);
-			p += put_u8 (p, CISCO_ADDR_UNICAST);
-			p += put_u8 (p, CISCO_CTRL);
-			p += put_u16(p, type);
-			len = 4;
-			break;
-#ifdef CONFIG_ISDN_X25
-		default:
-		  /* try if there are generic concap protocol routines */
-			if( lp-> netdev -> cprot ){
-				printk(KERN_WARNING "isdn_net_header called with concap_proto!\n");
-				len = 0;
-				break;
-			}
-			break;
-#endif /* CONFIG_ISDN_X25 */
-	}
-	return len;
-}
-
-/* We don't need to send arp, because we have point-to-point connections. */
-static int
-isdn_net_rebuild_header(struct sk_buff *skb)
-{
-	struct net_device *dev = skb->dev;
-	isdn_net_local *lp = dev->priv;
-	int ret = 0;
-
-	if (lp->p_encap == ISDN_NET_ENCAP_ETHER) {
-		struct ethhdr *eth = (struct ethhdr *) skb->data;
+	if (!idev)
+		return 0;
 
-		/*
-		 *      Only ARP/IP is currently supported
-		 */
+	if (!isdn_net_online(idev))
+		return 0;
 
-		if (eth->h_proto != htons(ETH_P_IP)) {
-			printk(KERN_WARNING
-			       "isdn_net: %s don't know how to resolve type %d addresses?\n",
-			       dev->name, (int) eth->h_proto);
-			memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
-			return 0;
-		}
-		/*
-		 *      Try to get ARP to resolve the header.
-		 */
-#ifdef CONFIG_INET
-		ret = arp_find(eth->h_dest, skb);
-#endif
-	}
-	return ret;
+	isdn_net_receive(&idev->dev, skb);
+	return 0;
 }
 
 /*
@@ -1969,83 +1196,56 @@
 static int
 isdn_net_init(struct net_device *ndev)
 {
-	ushort max_hlhdr_len = 0;
-	isdn_net_local *lp = (isdn_net_local *) ndev->priv;
-	int drvidx, i;
-
-	ether_setup(ndev);
-	lp->org_hhc = ndev->hard_header_cache;
-	lp->org_hcu = ndev->header_cache_update;
-
 	/* Setup the generic properties */
 
-	ndev->hard_header = NULL;
-	ndev->hard_header_cache = NULL;
-	ndev->header_cache_update = NULL;
 	ndev->mtu = 1500;
-	ndev->flags = IFF_NOARP|IFF_POINTOPOINT;
-	ndev->type = ARPHRD_ETHER;
-	ndev->addr_len = ETH_ALEN;
-
-	/* for clients with MPPP maybe higher values better */
-	ndev->tx_queue_len = 30;
-
-	for (i = 0; i < ETH_ALEN; i++)
-		ndev->broadcast[i] = 0xff;
-
-	/* The ISDN-specific entries in the device structure. */
+	ndev->tx_queue_len = 10;
 	ndev->open = &isdn_net_open;
 	ndev->hard_start_xmit = &isdn_net_start_xmit;
-
-	/*
-	 *  up till binding we ask the protocol layer to reserve as much
-	 *  as we might need for HL layer
-	 */
-
-	for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++)
-		if (dev->drv[drvidx])
-			if (max_hlhdr_len < dev->drv[drvidx]->interface->hl_hdrlen)
-				max_hlhdr_len = dev->drv[drvidx]->interface->hl_hdrlen;
-
-	ndev->hard_header_len = ETH_HLEN + max_hlhdr_len;
+	ndev->hard_header_len = ETH_HLEN + isdn_hard_header_len();
 	ndev->stop = &isdn_net_close;
 	ndev->get_stats = &isdn_net_get_stats;
-	ndev->rebuild_header = &isdn_net_rebuild_header;
-	ndev->do_ioctl = NULL;
+
 	return 0;
 }
 
-static void
-isdn_net_swapbind(int drvidx)
+static int
+isdn_net_do_callback(isdn_net_local *lp)
 {
-	struct list_head *l;
-
-	dbg_net_icall("n_fi: swapping ch of %d\n", drvidx);
-	list_for_each(l, &isdn_net_devs) {
-		isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list);
-		if (p->local.pre_device != drvidx)
-			continue;
-
-		switch (p->local.pre_channel) {
-		case 0:
-			p->local.pre_channel = 1;
-			break;
-		case 1:
-			p->local.pre_channel = 0;
-			break;
-		}
+	isdn_net_dev *idev = lp->netdev;
+	int slot;
+	/*
+	 * Is the state MANUAL?
+	 * If so, no callback can be made,
+	 * so reject actively.
+	 */
+	if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) {
+		printk(KERN_INFO "incoming call for callback, interface %s `off' -> 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, lp->l2_proto, lp->l3_proto,
+				  idev->pre_device, idev->pre_channel, lp->msn);
+	if (slot < 0)
+		goto err;
+
+	if (isdn_net_bind_channel(lp, slot) < 0)
+		goto err;
+
+	/* Setup dialstate. */
+	idev->dial_timer.expires = jiffies + lp->cbdelay;
+	idev->dial_event = EV_NET_TIMER_CB;
+	add_timer(&idev->dial_timer);
+	idev->dialstate = ST_WAIT_BEFORE_CB;
 
-static void
-isdn_net_swap_usage(int i1, int i2)
-{
-	int u1 = isdn_slot_usage(i1);
-	int u2 = isdn_slot_usage(i2);
+	/* Initiate dialing by returning 2 or 4 */
+	return (lp->flags & ISDN_NET_CBHUP) ? 2 : 4;
 
-	dbg_net_icall("n_fi: usage of %d and %d\n", i1, i2);
-	isdn_slot_set_usage(i1, (u1 & ~ISDN_USAGE_EXCLUSIVE) | (u2 & ISDN_USAGE_EXCLUSIVE));
-	isdn_slot_set_usage(i2, (u2 & ~ISDN_USAGE_EXCLUSIVE) | (u1 & ISDN_USAGE_EXCLUSIVE));
+ err:
+	return 0;
 }
 
 /*
@@ -2068,17 +1268,14 @@
 isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
 {
 	char *eaz;
-	int si1;
-	int si2;
-	int ematch;
-	int wret;
-	int swapped;
-	int sidx = 0;
+	unsigned char si1, si2;
+	int match_more = 0;
 	struct list_head *l;
 	struct isdn_net_phone *n;
 	ulong flags;
 	char nr[32];
 	char *my_eaz;
+	int retval;
 	isdn_ctrl cmd;
 
 	int slot = isdn_dc2minor(di, ch);
@@ -2089,15 +1286,17 @@
 		nr[0] = '0';
 		nr[1] = '\0';
 		printk(KERN_INFO "isdn_net: Incoming call without OAD, assuming '0'\n");
-	} else
+	} else {
 		strcpy(nr, setup->phone);
-	si1 = (int) setup->si1;
-	si2 = (int) setup->si2;
+	}
+	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
+	} 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
@@ -2110,274 +1309,147 @@
         }
 
 	n = NULL;
-	ematch = wret = swapped = 0;
 	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) {
-		int matchret;
-		isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list);
-		isdn_net_local *lp = &p->local;
+		isdn_net_dev *idev = list_entry(l, isdn_net_dev, global_list);
+		isdn_net_local *lp = &idev->local;
 
-		/* If last check has triggered as binding-swap, revert it */
-		switch (swapped) {
-			case 2:
-				isdn_net_swap_usage(idx, sidx);
-				/* fall through */
-			case 1:
-				isdn_net_swapbind(di);
-				break;
-		}
-		swapped = 0;
                 /* check acceptable call types for DOV */
+		dbg_net_icall("n_fi: if='%s', l.msn=%s, l.flags=%d, l.dstate=%d\n",
+			      lp->name, lp->msn, lp->flags, lp->dialstate);
+
                 my_eaz = isdn_slot_map_eaz2msn(slot, lp->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
-                                my_eaz = 0; /* force non match */
+                                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 */
                 }
-                if (my_eaz)
-                        matchret = isdn_msncmp(eaz, my_eaz);
-                else
-                        matchret = 1;
-                if (!matchret)
-                        ematch = 1;
-
-		/* Remember if more numbers eventually can match */
-		if (matchret > wret)
-			wret = matchret;
-		dbg_net_icall("n_fi: if='%s', l.msn=%s, l.flags=%d, l.dstate=%d\n",
-		       lp->name, lp->msn, lp->flags, lp->dialstate);
-		if ((!matchret) &&                                        /* EAZ is matching   */
-		    (((!(lp->flags & ISDN_NET_CONNECTED)) &&              /* but not connected */
-		      (USG_NONE(isdn_slot_usage(idx)))) ||                     /* and ch. unused or */
-		     ((((lp->dialstate == ST_OUT_WAIT_DCONN) || (lp->dialstate == ST_OUT_WAIT_DCONN)) && /* if dialing        */
-		       (!(lp->flags & ISDN_NET_CALLBACK)))                /* but no callback   */
-		     )))
-			 {
-			dbg_net_icall("n_fi: match1, pdev=%d pch=%d\n",
-			       lp->pre_device, lp->pre_channel);
-			if (isdn_slot_usage(idx) & ISDN_USAGE_EXCLUSIVE) {
-				if ((lp->pre_channel != ch) ||
-				    (lp->pre_device != di)) {
-					/* Here we got a problem:
-					 * If using an ICN-Card, an incoming call is always signaled on
-					 * on the first channel of the card, if both channels are
-					 * down. However this channel may be bound exclusive. If the
-					 * second channel is free, this call should be accepted.
-					 * The solution is horribly but it runs, so what:
-					 * We exchange the exclusive bindings of the two channels, the
-					 * corresponding variables in the interface-structs.
-					 */
-					if (ch == 0) {
-						sidx = isdn_dc2minor(di, 1);
-						dbg_net_icall("n_fi: ch is 0\n");
-						if (USG_NONE(isdn_slot_usage(sidx))) {
-							/* Second Channel is free, now see if it is bound
-							 * exclusive too. */
-							if (isdn_slot_usage(sidx) & ISDN_USAGE_EXCLUSIVE) {
-								dbg_net_icall("n_fi: 2nd channel is down and bound\n");
-								/* Yes, swap bindings only, if the original
-								 * binding is bound to channel 1 of this driver */
-								if ((lp->pre_device == di) &&
-								    (lp->pre_channel == 1)) {
-									isdn_net_swapbind(di);
-									swapped = 1;
-								} else {
-									/* ... else iterate next device */
-									continue;
-								}
-							} else {
-								dbg_net_icall("n_fi: 2nd channel is down and unbound\n");
-								/* No, swap always and swap excl-usage also */
-								isdn_net_swap_usage(idx, sidx);
-								isdn_net_swapbind(di);
-								swapped = 2;
-							}
-							/* Now check for exclusive binding again */
-							dbg_net_icall("n_fi: final check\n");
-							if ((isdn_slot_usage(idx) & ISDN_USAGE_EXCLUSIVE) &&
-							    ((lp->pre_channel != ch) ||
-							     (lp->pre_device != di))) {
-								dbg_net_icall("n_fi: final check failed\n");
-								continue;
-							}
-						}
-					} else {
-						/* We are already on the second channel, so nothing to do */
-						dbg_net_icall("n_fi: already on 2nd channel\n");
-					}
+
+		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",
+			      lp->pre_device, lp->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 (lp->flags & ISDN_NET_SECURE) {
+			spin_lock_irqsave(&lp->lock, flags);
+			list_for_each_entry(n, &lp->phone[0], list) {
+				if (!isdn_msncmp(nr, n->num)) {
+					spin_unlock_irqrestore(&lp->lock, flags);
+					goto found;
 				}
 			}
-			dbg_net_icall("n_fi: match2\n");
-			if (lp->flags & ISDN_NET_SECURE) {
-				spin_lock_irqsave(&lp->lock, flags);
-				list_for_each_entry(n, &lp->phone[0], list) {
-					if (!isdn_msncmp(nr, n->num)) {
-						spin_unlock_irqrestore(&lp->lock, flags);
+			spin_unlock_irqrestore(&lp->lock, flags);
+			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(*lp) == 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;
+		}
+		/* Interface is up, now see if it's a slave. If so, see if
+		 * it's master and parent slave is online. If not, reject the call.
+		 */
+		if (lp->master) {
+			isdn_net_local *mlp = (isdn_net_local *) lp->master->priv;
+			printk(KERN_DEBUG "ICALLslv: %s\n", idev->name);
+			printk(KERN_DEBUG "master=%s\n", mlp->netdev->name);
+			if (isdn_net_bound(mlp->netdev)) {
+				printk(KERN_DEBUG "master online\n");
+				/* Master is online, find parent-slave (master if first slave) */
+				while (mlp->slave) {
+					if ((isdn_net_local *) mlp->slave->priv == lp)
 						break;
-					}
+					mlp = (isdn_net_local *) mlp->slave->priv;
 				}
-				spin_unlock_irqrestore(&lp->lock, flags);
+			} else
+				printk(KERN_DEBUG "master offline\n");
+			/* Found parent, if it's offline iterate next device */
+			printk(KERN_DEBUG "mlpf: %d\n", isdn_net_bound(mlp->netdev));
+			if (!isdn_net_bound(mlp->netdev)) {
 				continue;
 			}
-			dbg_net_icall("n_fi: match3\n");
-			/* matching interface found */
+		} 
+		if (lp->flags & ISDN_NET_CALLBACK) {
+			retval = isdn_net_do_callback(lp);
+			restore_flags(flags);
+			return retval;
+		}
+		printk(KERN_DEBUG "%s: call from %s -> %s accepted\n", idev->name,
+		       nr, eaz);
 
-			/*
-			 * Is the state STOPPED?
-			 * If so, no dialin is allowed,
-			 * so reject actively.
-			 * */
-			if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) {
-				restore_flags(flags);
-				printk(KERN_INFO "incoming call, interface %s `stopped' -> rejected\n",
-				       lp->name);
-				return 3;
-			}
-			/*
-			 * Is the interface up?
-			 * If not, reject the call actively.
-			 */
-			if (!isdn_net_device_started(p)) {
-				restore_flags(flags);
-				printk(KERN_INFO "%s: incoming call, interface down -> rejected\n",
-				       lp->name);
-				return 3;
-			}
-			/* Interface is up, now see if it's a slave. If so, see if
-			 * it's master and parent slave is online. If not, reject the call.
-			 */
-			if (lp->master) {
-				isdn_net_local *mlp = (isdn_net_local *) lp->master->priv;
-				printk(KERN_DEBUG "ICALLslv: %s\n", lp->name);
-				printk(KERN_DEBUG "master=%s\n", mlp->name);
-				if (mlp->flags & ISDN_NET_CONNECTED) {
-					printk(KERN_DEBUG "master online\n");
-					/* Master is online, find parent-slave (master if first slave) */
-					while (mlp->slave) {
-						if ((isdn_net_local *) mlp->slave->priv == lp)
-							break;
-						mlp = (isdn_net_local *) mlp->slave->priv;
-					}
-				} else
-					printk(KERN_DEBUG "master offline\n");
-				/* Found parent, if it's offline iterate next device */
-				printk(KERN_DEBUG "mlpf: %d\n", mlp->flags & ISDN_NET_CONNECTED);
-				if (!(mlp->flags & ISDN_NET_CONNECTED)) {
-					continue;
-				}
-			} 
-			if (lp->flags & ISDN_NET_CALLBACK) {
-				int chi;
-				/*
-				 * Is the state MANUAL?
-				 * If so, no callback can be made,
-				 * so reject actively.
-				 * */
-				if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) {
-					restore_flags(flags);
-					printk(KERN_INFO "incoming call for callback, interface %s `off' -> rejected\n",
-					       lp->name);
-					return 3;
-				}
-				printk(KERN_DEBUG "%s: call from %s -> %s, start callback\n",
-				       lp->name, nr, eaz);
+		strcpy(isdn_slot_num(idx), nr);
+		isdn_slot_set_usage(idx, (isdn_slot_usage(idx) & ISDN_USAGE_EXCLUSIVE) | ISDN_USAGE_NET);
 
-				/* Grab a free ISDN-Channel */
-				if ((chi = 
-				     isdn_get_free_slot(
-					     ISDN_USAGE_NET,
-					     lp->l2_proto,
-					     lp->l3_proto,
-					     lp->pre_device,
-					     lp->pre_channel,
-					     lp->msn)
-					    ) < 0) {
-					
-					printk(KERN_WARNING "isdn_net_find_icall: No channel for %s\n", lp->name);
-					restore_flags(flags);
-					return 0;
-				}
-				/* Setup dialstate. */
-				lp->dial_timer.expires = jiffies + lp->cbdelay;
-				lp->dial_event = EV_NET_TIMER_CB;
-				add_timer(&lp->dial_timer);
-				
-				lp->dialstate = ST_WAIT_BEFORE_CB;
-				/* Connect interface with channel */
-				isdn_net_bind_channel(lp, chi);
-#ifdef CONFIG_ISDN_PPP
-				if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
-					if (isdn_ppp_bind(lp) < 0) {
-						isdn_net_unbind_channel(lp);
-						restore_flags(flags);
-						return 0;
-					}
-#endif
-				/* Initiate dialing by returning 2 or 4 */
-				restore_flags(flags);
-				return (lp->flags & ISDN_NET_CBHUP) ? 2 : 4;
-			} else {
-				printk(KERN_DEBUG "%s: call from %s -> %s accepted\n", lp->name, nr,
-				       eaz);
-				/* if this interface is dialing, it does it probably on a different
-				   device, so free this device */
-				if (lp->dialstate == ST_OUT_WAIT_DCONN) {
-#ifdef CONFIG_ISDN_PPP
-					if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
-						isdn_ppp_free(lp);
-#endif
-					isdn_net_lp_disconnected(lp);
-					isdn_slot_free(lp->isdn_slot,
-						       ISDN_USAGE_NET);
-				}
-				strcpy(isdn_slot_num(idx), nr);
-				isdn_slot_set_usage(idx, (isdn_slot_usage(idx) & ISDN_USAGE_EXCLUSIVE) | ISDN_USAGE_NET);
-				isdn_slot_set_st_netdev(idx, lp->netdev);
-				lp->isdn_slot = slot;
-				lp->ppp_slot = -1;
-				lp->flags |= ISDN_NET_CONNECTED;
-				
-				lp->outgoing = 0;
-				lp->huptimer = 0;
-				lp->charge_state = ST_CHARGE_NULL;
-				/* Got incoming Call, setup L2 and L3 protocols,
-				 * then wait for D-Channel-connect
-				 */
-				cmd.arg = lp->l2_proto << 8;
-				isdn_slot_command(lp->isdn_slot, ISDN_CMD_SETL2, &cmd);
-				cmd.arg = lp->l3_proto << 8;
-				isdn_slot_command(lp->isdn_slot, ISDN_CMD_SETL3, &cmd);
-				
-				lp->dial_timer.expires = jiffies + 15 * HZ;
-				lp->dial_event = EV_NET_TIMER_IN_DCONN;
-				add_timer(&lp->dial_timer);
-				lp->dialstate = ST_IN_WAIT_DCONN;
-				
-#ifdef CONFIG_ISDN_PPP
-				if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
-					if (isdn_ppp_bind(lp) < 0) {
-						isdn_net_unbind_channel(lp);
-						restore_flags(flags);
-						return 0;
-					}
-#endif
-				restore_flags(flags);
-				return 1;
-			}
-			 }
+		isdn_net_bind_channel(lp, idx);
+		
+		idev->outgoing = 0;
+		idev->huptimer = 0;
+		idev->charge_state = ST_CHARGE_NULL;
+		/* Got incoming Call, setup L2 and L3 protocols,
+		 * then wait for D-Channel-connect
+		 */
+		cmd.arg = lp->l2_proto << 8;
+		isdn_slot_command(idev->isdn_slot, ISDN_CMD_SETL2, &cmd);
+		cmd.arg = lp->l3_proto << 8;
+		isdn_slot_command(idev->isdn_slot, ISDN_CMD_SETL3, &cmd);
+		
+		idev->dial_timer.expires = jiffies + 15 * HZ;
+		idev->dial_event = EV_NET_TIMER_IN_DCONN;
+		add_timer(&idev->dial_timer);
+		idev->dialstate = ST_IN_WAIT_DCONN;
+		
+		restore_flags(flags);
+		return 1;
 	}
-	/* If none of configured EAZ/MSN matched and not verbose, be silent */
-	if (!ematch || dev->net_verbose)
+	if (dev->net_verbose)
 		printk(KERN_INFO "isdn_net: call from %s -> %d %s ignored\n", nr, slot, eaz);
 	restore_flags(flags);
-	return (wret == 2)?5:0;
+	return (match_more == 2) ? 5:0;
 }
 
 /*
@@ -2390,7 +1462,7 @@
 
 	list_for_each(l, &isdn_net_devs) {
 		isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list);
-		if (!strcmp(p->local.name, name))
+		if (!strcmp(p->name, name))
 			return p;
 	}
 	return NULL;
@@ -2401,41 +1473,40 @@
  * This is called from the userlevel-routine below or
  * from isdn_net_start_xmit().
  */
-int
-isdn_net_force_dial_lp(isdn_net_local * lp)
+static int
+isdn_net_force_dial_lp(isdn_net_local *lp)
 {
-	int chi;
+	isdn_net_dev *idev = lp->netdev;
+	int slot;
 	unsigned long flags;
 
-	if (lp->flags & ISDN_NET_CONNECTED || lp->dialstate != ST_NULL)
+	if (isdn_net_bound(idev))
 		return -EBUSY;
 
 	save_flags(flags);
 	cli();
-	
-	/* Grab a free ISDN-Channel */
-	chi = isdn_get_free_slot(ISDN_USAGE_NET, lp->l2_proto, lp->l3_proto,
-				 lp->pre_device, lp->pre_channel, lp->msn);
-	if (chi < 0) {
-		printk(KERN_WARNING "isdn_net_force_dial: No channel for %s\n", lp->name);
-		restore_flags(flags);
-		return -EAGAIN;
-	}
-	/* Connect interface with channel */
-	isdn_net_bind_channel(lp, chi);
-#ifdef CONFIG_ISDN_PPP
-	if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
-		if (isdn_ppp_bind(lp) < 0) {
-			isdn_net_unbind_channel(lp);
-			restore_flags(flags);
-			return -EAGAIN;
-		}
-#endif
+
+	if (idev->exclusive >= 0)
+		slot = idev->exclusive;
+	else
+		slot = isdn_get_free_slot(ISDN_USAGE_NET, lp->l2_proto,
+					  lp->l3_proto, idev->pre_device, 
+					  idev->pre_channel, lp->msn);
+	if (slot < 0)
+		goto err;
+
+	if (isdn_net_bind_channel(lp, slot) < 0)
+		goto err;;
+
 	/* Initiate dialing */
 	restore_flags(flags);
 	init_dialout(lp);
 
 	return 0;
+
+ err:
+	restore_flags(flags);
+	return -EAGAIN;
 }
 
 /*
@@ -2485,11 +1556,10 @@
 		return -ENOMEM;
 	}
 	memset(netdev, 0, sizeof(isdn_net_dev));
-	strcpy(netdev->local.name, name);
+	strcpy(netdev->name, name);
 	strcpy(netdev->dev.name, name);
 	netdev->dev.priv = &netdev->local;
 	netdev->dev.init = isdn_net_init;
-	netdev->local.p_encap = ISDN_NET_ENCAP_RAWIP;
 	if (master) {
 		/* Device shall be a slave */
 		struct net_device *p = (((isdn_net_local *) master->priv)->slave);
@@ -2530,12 +1600,15 @@
 	netdev->local.tqueue.data = &netdev->local;
 	spin_lock_init(&netdev->local.xmit_lock);
 
-	netdev->local.isdn_slot = -1;
-	netdev->local.pre_device = -1;
-	netdev->local.pre_channel = -1;
-	netdev->local.exclusive = -1;
-	netdev->local.ppp_slot = -1;
-	netdev->local.pppbind = -1;
+	netdev->isdn_slot = -1;
+	netdev->pre_device = -1;
+	netdev->pre_channel = -1;
+	netdev->exclusive = -1;
+
+	netdev->ppp_slot = -1;
+	netdev->pppbind = -1;
+
+	netdev->local.p_encap = -1;
 	skb_queue_head_init(&netdev->local.super_tx_queue);
 	netdev->local.l2_proto = ISDN_PROTO_L2_X75I;
 	netdev->local.l3_proto = ISDN_PROTO_L3_TRANS;
@@ -2549,18 +1622,19 @@
 	netdev->local.cbdelay = 5 * HZ;	/* Wait 5 secs before Callback */
 	netdev->local.dialtimeout = -1;  /* Infinite Dial-Timeout */
 	netdev->local.dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */
-	netdev->local.dialstarted = 0;   /* Jiffies of last dial-start */
-	netdev->local.dialwait_timer = 0;  /* Jiffies of earliest next dial-start */
+	netdev->dialstarted = 0;   /* Jiffies of last dial-start */
+	netdev->dialwait_timer = 0;  /* Jiffies of earliest next dial-start */
 
-	init_timer(&netdev->local.dial_timer);
-	netdev->local.dial_timer.data = (unsigned long) &netdev->local;
-	netdev->local.dial_timer.function = isdn_net_dial_timer;
-	init_timer(&netdev->local.hup_timer);
-	netdev->local.hup_timer.data = (unsigned long) &netdev->local;
-	netdev->local.hup_timer.function = isdn_net_hup_timer;
+	init_timer(&netdev->dial_timer);
+	netdev->dial_timer.data = (unsigned long) netdev;
+	netdev->dial_timer.function = isdn_net_dial_timer;
+	init_timer(&netdev->hup_timer);
+	netdev->hup_timer.data = (unsigned long) netdev;
+	netdev->hup_timer.function = isdn_net_hup_timer;
 	spin_lock_init(&netdev->local.lock);
 	INIT_LIST_HEAD(&netdev->local.phone[0]);
 	INIT_LIST_HEAD(&netdev->local.phone[1]);
+	isdn_net_set_encap(netdev, ISDN_NET_ENCAP_RAWIP);
 
 	/* Put into to netdev-chain */
 	list_add(&netdev->global_list, &isdn_net_devs);
@@ -2591,6 +1665,121 @@
 	return isdn_net_new(p+1, &m->dev);
 }
 
+static int
+isdn_net_set_encap(isdn_net_dev *p, int encap)
+{
+	isdn_net_local *lp = &p->local;
+	int retval = 0;
+
+	if (lp->p_encap == encap){
+		/* nothing to do */
+		retval = 0;
+		goto out;
+	}
+	if (isdn_net_device_started(p)) {
+		retval = -EBUSY;
+		goto out;
+	}
+	if (lp->ops && lp->ops->cleanup)
+		lp->ops->cleanup(lp);
+
+	if (encap < 0 || encap >= ISDN_NET_ENCAP_NR) {
+		lp->p_encap = -1;
+		lp->ops = NULL;
+		retval = -EINVAL;
+		goto out;
+	}
+
+	lp->p_encap = encap;
+	lp->ops = netif_ops[encap];
+
+	p->dev.hard_header         = lp->ops->hard_header;
+	p->dev.do_ioctl            = lp->ops->do_ioctl;
+	p->dev.flags               = lp->ops->flags;
+	p->dev.type                = lp->ops->type;
+	p->dev.addr_len            = lp->ops->addr_len;
+	if (lp->ops->init)
+		retval = lp->ops->init(lp);
+
+	if (retval != 0) {
+		lp->p_encap = -1;
+		lp->ops = NULL;
+	}
+ out:
+	return retval;
+}
+
+static int
+isdn_net_bind(isdn_net_dev *idev, isdn_net_ioctl_cfg *cfg)
+{
+	isdn_net_local *lp = &idev->local;
+	int i, retval;
+	int drvidx = -1;
+	int chidx = -1;
+	char drvid[25];
+
+	strncpy(drvid, cfg->drvid, 24);
+	drvid[24] = 0;
+
+	if (cfg->exclusive && !strlen(drvid)) {
+		/* If we want to bind exclusively, need to specify drv/chan */
+		retval = -ENODEV;
+		goto out;
+	}
+	if (strlen(drvid)) {
+		/* A bind has been requested ... */
+		char *c = strchr(drvid, ',');
+		if (!c) {
+			retval = -ENODEV;
+			goto out;
+		}
+		/* The channel-number is appended to the driver-Id with a comma */
+		*c = 0;
+		chidx = simple_strtol(c + 1, NULL, 10);
+
+		for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
+			/* Lookup driver-Id in array */
+			if (!strcmp(dev->drvid[i], drvid)) {
+				drvidx = i;
+				break;
+			}
+		}
+		if (drvidx == -1 || chidx == -1) {
+			/* Either driver-Id or channel-number invalid */
+			retval = -ENODEV;
+			goto out;
+		}
+	}
+	if (cfg->exclusive == (idev->exclusive >= 0) &&
+	    drvidx == idev->pre_device && chidx == idev->pre_channel) {
+		/* no change */
+		retval = 0;
+		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);
+		idev->exclusive = -1;
+	}
+	if (cfg->exclusive) {
+		/* If binding is exclusive, try to grab the channel */
+		idev->exclusive = isdn_get_free_slot(ISDN_USAGE_NET, lp->l2_proto, 
+						     lp->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;
+	retval = 0;
+ out:
+	return retval;
+}
+
 /*
  * Set interface-parameters.
  * Always set all parameters, so the user-level application is responsible
@@ -2598,237 +1787,102 @@
  * setup first, if only selected parameters are to be changed.
  */
 int
-isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
+isdn_net_setcfg(isdn_net_ioctl_cfg *cfg)
 {
-	isdn_net_dev *p = isdn_net_findif(cfg->name);
+	isdn_net_dev *idev = isdn_net_findif(cfg->name);
+	isdn_net_local *lp = &idev->local;
 	ulong features;
-	int i;
-	int drvidx;
-	int chidx;
-	char drvid[25];
-#ifdef CONFIG_ISDN_X25
-	ulong flags;
-#endif
-	if (p) {
-		isdn_net_local *lp = &p->local;
+	int i, retval;
 
-		/* See if any registered driver supports the features we want */
-		features = ((1 << cfg->l2_proto) << ISDN_FEATURE_L2_SHIFT) |
-			((1 << cfg->l3_proto) << ISDN_FEATURE_L3_SHIFT);
-		for (i = 0; i < ISDN_MAX_DRIVERS; i++)
-			if (dev->drv[i])
-				if ((dev->drv[i]->interface->features & features) == features)
-					break;
-		if (i == ISDN_MAX_DRIVERS) {
-			printk(KERN_WARNING "isdn_net: No driver with selected features\n");
-			return -ENODEV;
-		}
-		if (lp->p_encap != cfg->p_encap){
-#ifdef CONFIG_ISDN_X25
-			struct concap_proto * cprot = p -> cprot;
-#endif
-			if (isdn_net_device_started(p)) {
-				printk(KERN_WARNING "%s: cannot change encap when if is up\n",
-				       lp->name);
-				return -EBUSY;
-			}
-#ifdef CONFIG_ISDN_X25
-			/* delete old encapsulation protocol if present ... */
-			save_flags(flags);
-			cli(); /* avoid races with incoming events trying to
-				  call cprot->pops methods */
-			if( cprot && cprot -> pops )
-				cprot -> pops -> proto_del ( cprot );
-			p -> cprot = NULL;
-			lp -> dops = NULL;
-			restore_flags(flags);
-			/* ... ,  prepare for configuration of new one ... */
-			switch ( cfg -> p_encap ){
-			case ISDN_NET_ENCAP_X25IFACE:
-				lp -> dops = &isdn_concap_reliable_dl_dops;
-			}
-			/* ... and allocate new one ... */
-			p -> cprot = isdn_concap_new( cfg -> p_encap );
-			/* p -> cprot == NULL now if p_encap is not supported
-			   by means of the concap_proto mechanism */
-			/* the protocol is not configured yet; this will
-			   happen later when isdn_net_reset() is called */
-#endif
-		}
-		switch ( cfg->p_encap ) {
-		case ISDN_NET_ENCAP_SYNCPPP:
-#ifndef CONFIG_ISDN_PPP
-			printk(KERN_WARNING "%s: SyncPPP support not configured\n",
-			       lp->name);
-			return -EINVAL;
-#else
-			p->dev.type = ARPHRD_PPP;	/* change ARP type */
-			p->dev.addr_len = 0;
-			p->dev.do_ioctl = isdn_ppp_dev_ioctl;
-#endif
-			break;
-		case ISDN_NET_ENCAP_X25IFACE:
-#ifndef CONFIG_ISDN_X25
-			printk(KERN_WARNING "%s: isdn-x25 support not configured\n",
-			       p->local.name);
-			return -EINVAL;
-#else
-			p->dev.type = ARPHRD_X25;	/* change ARP type */
-			p->dev.addr_len = 0;
-#endif
-			break;
-		case ISDN_NET_ENCAP_CISCOHDLCK:
-			p->dev.do_ioctl = isdn_ciscohdlck_dev_ioctl;
-			break;
-		default:
-			if( cfg->p_encap >= 0 &&
-			    cfg->p_encap <= ISDN_NET_ENCAP_MAX_ENCAP )
-				break;
-			printk(KERN_WARNING
-			       "%s: encapsulation protocol %d not supported\n",
-			       p->local.name, cfg->p_encap);
-			return -EINVAL;
-		}
-		if (strlen(cfg->drvid)) {
-			/* A bind has been requested ... */
-			char *c,
-			*e;
-
-			drvidx = -1;
-			chidx = -1;
-			strcpy(drvid, cfg->drvid);
-			if ((c = strchr(drvid, ','))) {
-				/* The channel-number is appended to the driver-Id with a comma */
-				chidx = (int) simple_strtoul(c + 1, &e, 10);
-				if (e == c)
-					chidx = -1;
-				*c = '\0';
-			}
-			for (i = 0; i < ISDN_MAX_DRIVERS; i++)
-				/* Lookup driver-Id in array */
-				if (!(strcmp(dev->drvid[i], drvid))) {
-					drvidx = i;
-					break;
-				}
-			if ((drvidx == -1) || (chidx == -1))
-				/* Either driver-Id or channel-number invalid */
-				return -ENODEV;
-		} else {
-			/* Parameters are valid, so get them */
-			drvidx = lp->pre_device;
-			chidx = lp->pre_channel;
-		}
-		if (cfg->exclusive > 0) {
-			unsigned long flags;
-
-			/* If binding is exclusive, try to grab the channel */
-			save_flags(flags);
-			if ((i = isdn_get_free_slot(ISDN_USAGE_NET,
-				lp->l2_proto, lp->l3_proto, drvidx,
-				chidx, lp->msn)) < 0) {
-				/* Grab failed, because desired channel is in use */
-				lp->exclusive = -1;
-				restore_flags(flags);
-				return -EBUSY;
-			}
-			/* All went ok, so update isdninfo */
-			isdn_slot_set_usage(i, ISDN_USAGE_EXCLUSIVE);
-			restore_flags(flags);
-			lp->exclusive = i;
-		} else {
-			/* Non-exclusive binding or unbind. */
-			lp->exclusive = -1;
-			if ((lp->pre_device != -1) && (cfg->exclusive == -1)) {
-				isdn_unexclusive_channel(lp->pre_device, lp->pre_channel);
-				isdn_free_channel(lp->pre_device, lp->pre_channel, ISDN_USAGE_NET);
-				drvidx = -1;
-				chidx = -1;
-			}
-		}
-		strcpy(lp->msn, cfg->eaz);
-		lp->pre_device = drvidx;
-		lp->pre_channel = chidx;
-		lp->onhtime = cfg->onhtime;
-		lp->charge = cfg->charge;
-		lp->l2_proto = cfg->l2_proto;
-		lp->l3_proto = cfg->l3_proto;
-		lp->cbdelay = cfg->cbdelay * HZ / 5;
-		lp->dialmax = cfg->dialmax;
-		lp->triggercps = cfg->triggercps;
-		lp->slavedelay = cfg->slavedelay * HZ;
-		lp->pppbind = cfg->pppbind;
-		lp->dialtimeout = cfg->dialtimeout >= 0 ? cfg->dialtimeout * HZ : -1;
-		lp->dialwait = cfg->dialwait * HZ;
-		if (cfg->secure)
-			lp->flags |= ISDN_NET_SECURE;
-		else
-			lp->flags &= ~ISDN_NET_SECURE;
-		if (cfg->cbhup)
-			lp->flags |= ISDN_NET_CBHUP;
-		else
-			lp->flags &= ~ISDN_NET_CBHUP;
-		switch (cfg->callback) {
-			case 0:
-				lp->flags &= ~(ISDN_NET_CALLBACK | ISDN_NET_CBOUT);
-				break;
-			case 1:
-				lp->flags |= ISDN_NET_CALLBACK;
-				lp->flags &= ~ISDN_NET_CBOUT;
+	if (!idev) {
+		retval = -ENODEV;
+		goto out;
+	}
+	/* See if any registered driver supports the features we want */
+	features = ((1 << cfg->l2_proto) << ISDN_FEATURE_L2_SHIFT) |
+		   ((1 << cfg->l3_proto) << ISDN_FEATURE_L3_SHIFT);
+	for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+		if (dev->drv[i] &&
+		    (dev->drv[i]->interface->features & features) == features)
 				break;
-			case 2:
-				lp->flags |= ISDN_NET_CBOUT;
-				lp->flags &= ~ISDN_NET_CALLBACK;
-				break;
-		}
-		lp->flags &= ~ISDN_NET_DIALMODE_MASK;	/* first all bits off */
-		if (cfg->dialmode && !(cfg->dialmode & ISDN_NET_DIALMODE_MASK)) {
-			/* old isdnctrl version, where only 0 or 1 is given */
-			printk(KERN_WARNING
-			     "Old isdnctrl version detected! Please update.\n");
-			lp->flags |= ISDN_NET_DM_OFF; /* turn on `off' bit */
-		}
-		else {
-			lp->flags |= cfg->dialmode;  /* turn on selected bits */
-		}
-		if (lp->flags & ISDN_NET_DM_OFF)
-			isdn_net_hangup(lp);
 
-		if (cfg->chargehup)
-			lp->hupflags |= ISDN_CHARGEHUP;
-		else
-			lp->hupflags &= ~ISDN_CHARGEHUP;
-		if (cfg->ihup)
-			lp->hupflags |= ISDN_INHUP;
-		else
-			lp->hupflags &= ~ISDN_INHUP;
-		if (cfg->chargeint > 10) {
-			lp->chargeint = cfg->chargeint * HZ;
-			lp->charge_state = ST_CHARGE_HAVE_CINT;
-			lp->hupflags |= ISDN_MANCHARGE;
-		}
-		if (cfg->p_encap != lp->p_encap) {
-			if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) {
-				p->dev.hard_header = NULL;
-				p->dev.hard_header_cache = NULL;
-				p->dev.header_cache_update = NULL;
-				p->dev.flags = IFF_NOARP|IFF_POINTOPOINT;
-			} else {
-				p->dev.hard_header = isdn_net_header;
-				if (cfg->p_encap == ISDN_NET_ENCAP_ETHER) {
-					p->dev.hard_header_cache = lp->org_hhc;
-					p->dev.header_cache_update = lp->org_hcu;
-					p->dev.flags = IFF_BROADCAST | IFF_MULTICAST;
-				} else {
-					p->dev.hard_header_cache = NULL;
-					p->dev.header_cache_update = NULL;
-					p->dev.flags = IFF_NOARP|IFF_POINTOPOINT;
-				}
-			}
-		}
-		lp->p_encap = cfg->p_encap;
-		return 0;
+	if (i == ISDN_MAX_DRIVERS) {
+		printk(KERN_WARNING "isdn_net: No driver with selected features\n");
+		retval = -ENODEV;
+		goto out;
+	}
+
+	retval = isdn_net_set_encap(idev, cfg->p_encap);
+	if (retval)
+		goto out;
+
+	retval = isdn_net_bind(idev, cfg);
+	if (retval)
+		goto out;
+
+	strncpy(lp->msn, cfg->eaz, ISDN_MSNLEN-1);
+	lp->msn[ISDN_MSNLEN-1] = 0;
+	lp->onhtime = cfg->onhtime;
+	idev->charge = cfg->charge;
+	lp->l2_proto = cfg->l2_proto;
+	lp->l3_proto = cfg->l3_proto;
+	lp->cbdelay = cfg->cbdelay * HZ / 5;
+	lp->dialmax = cfg->dialmax;
+	lp->triggercps = cfg->triggercps;
+	lp->slavedelay = cfg->slavedelay * HZ;
+	idev->pppbind = cfg->pppbind;
+	lp->dialtimeout = cfg->dialtimeout >= 0 ? cfg->dialtimeout * HZ : -1;
+	lp->dialwait = cfg->dialwait * HZ;
+	if (cfg->secure)
+		lp->flags |= ISDN_NET_SECURE;
+	else
+		lp->flags &= ~ISDN_NET_SECURE;
+	if (cfg->cbhup)
+		lp->flags |= ISDN_NET_CBHUP;
+	else
+		lp->flags &= ~ISDN_NET_CBHUP;
+	switch (cfg->callback) {
+	case 0:
+		lp->flags &= ~(ISDN_NET_CALLBACK | ISDN_NET_CBOUT);
+		break;
+	case 1:
+		lp->flags |= ISDN_NET_CALLBACK;
+		lp->flags &= ~ISDN_NET_CBOUT;
+		break;
+	case 2:
+		lp->flags |= ISDN_NET_CBOUT;
+		lp->flags &= ~ISDN_NET_CALLBACK;
+		break;
 	}
-	return -ENODEV;
+	lp->flags &= ~ISDN_NET_DIALMODE_MASK;	/* first all bits off */
+	if (cfg->dialmode && !(cfg->dialmode & ISDN_NET_DIALMODE_MASK)) {
+		retval = -EINVAL;
+		goto out;
+	}
+
+	lp->flags |= cfg->dialmode;  /* turn on selected bits */
+	if (lp->flags & ISDN_NET_DM_OFF)
+		isdn_net_hangup(idev);
+
+	if (cfg->chargehup)
+		lp->hupflags |= ISDN_CHARGEHUP;
+	else
+		lp->hupflags &= ~ISDN_CHARGEHUP;
+
+	if (cfg->ihup)
+		lp->hupflags |= ISDN_INHUP;
+	else
+		lp->hupflags &= ~ISDN_INHUP;
+
+	if (cfg->chargeint > 10) {
+		idev->chargeint = cfg->chargeint * HZ;
+		idev->charge_state = ST_CHARGE_HAVE_CINT;
+		lp->hupflags |= ISDN_MANCHARGE;
+	}
+	retval = 0;
+
+ out:
+	return retval;
 }
 
 /*
@@ -2837,53 +1891,53 @@
 int
 isdn_net_getcfg(isdn_net_ioctl_cfg * cfg)
 {
-	isdn_net_dev *p = isdn_net_findif(cfg->name);
+	isdn_net_dev *idev = isdn_net_findif(cfg->name);
+	isdn_net_local *lp = &idev->local;
+		
+	if (!idev)
+		return -ENODEV;
 
-	if (p) {
-		isdn_net_local *lp = &p->local;
+	strcpy(cfg->eaz, lp->msn);
+	cfg->exclusive = idev->exclusive >= 0;
+	if (idev->pre_device >= 0) {
+		sprintf(cfg->drvid, "%s,%d", dev->drvid[idev->pre_device],
+			idev->pre_channel);
+	} else
+		cfg->drvid[0] = '\0';
+	cfg->onhtime = lp->onhtime;
+	cfg->charge = idev->charge;
+	cfg->l2_proto = lp->l2_proto;
+	cfg->l3_proto = lp->l3_proto;
+	cfg->p_encap = lp->p_encap;
+	cfg->secure = (lp->flags & ISDN_NET_SECURE) ? 1 : 0;
+	cfg->callback = 0;
+	if (lp->flags & ISDN_NET_CALLBACK)
+		cfg->callback = 1;
+	if (lp->flags & ISDN_NET_CBOUT)
+		cfg->callback = 2;
+	cfg->cbhup = (lp->flags & ISDN_NET_CBHUP) ? 1 : 0;
+	cfg->dialmode = lp->flags & ISDN_NET_DIALMODE_MASK;
+	cfg->chargehup = (lp->hupflags & ISDN_CHARGEHUP) ? 1 : 0;
+	cfg->ihup = (lp->hupflags & ISDN_INHUP) ? 1 : 0;
+	cfg->cbdelay = lp->cbdelay * 5 / HZ;
+	cfg->dialmax = lp->dialmax;
+	cfg->triggercps = lp->triggercps;
+	cfg->slavedelay = lp->slavedelay / HZ;
+	cfg->chargeint = (lp->hupflags & ISDN_CHARGEHUP) ?
+		(idev->chargeint / HZ) : 0;
+	cfg->pppbind = idev->pppbind;
+	cfg->dialtimeout = lp->dialtimeout >= 0 ? lp->dialtimeout / HZ : -1;
+	cfg->dialwait = lp->dialwait / HZ;
+	if (lp->slave)
+		strcpy(cfg->slave, ((isdn_net_local *) lp->slave->priv)->netdev->name);
+	else
+		cfg->slave[0] = '\0';
+	if (lp->master)
+		strcpy(cfg->master, ((isdn_net_local *) lp->master->priv)->netdev->name);
+	else
+		cfg->master[0] = '\0';
 
-		strcpy(cfg->eaz, lp->msn);
-		cfg->exclusive = lp->exclusive;
-		if (lp->pre_device >= 0) {
-			sprintf(cfg->drvid, "%s,%d", dev->drvid[lp->pre_device],
-				lp->pre_channel);
-		} else
-			cfg->drvid[0] = '\0';
-		cfg->onhtime = lp->onhtime;
-		cfg->charge = lp->charge;
-		cfg->l2_proto = lp->l2_proto;
-		cfg->l3_proto = lp->l3_proto;
-		cfg->p_encap = lp->p_encap;
-		cfg->secure = (lp->flags & ISDN_NET_SECURE) ? 1 : 0;
-		cfg->callback = 0;
-		if (lp->flags & ISDN_NET_CALLBACK)
-			cfg->callback = 1;
-		if (lp->flags & ISDN_NET_CBOUT)
-			cfg->callback = 2;
-		cfg->cbhup = (lp->flags & ISDN_NET_CBHUP) ? 1 : 0;
-		cfg->dialmode = lp->flags & ISDN_NET_DIALMODE_MASK;
-		cfg->chargehup = (lp->hupflags & 4) ? 1 : 0;
-		cfg->ihup = (lp->hupflags & 8) ? 1 : 0;
-		cfg->cbdelay = lp->cbdelay * 5 / HZ;
-		cfg->dialmax = lp->dialmax;
-		cfg->triggercps = lp->triggercps;
-		cfg->slavedelay = lp->slavedelay / HZ;
-		cfg->chargeint = (lp->hupflags & ISDN_CHARGEHUP) ?
-		    (lp->chargeint / HZ) : 0;
-		cfg->pppbind = lp->pppbind;
-		cfg->dialtimeout = lp->dialtimeout >= 0 ? lp->dialtimeout / HZ : -1;
-		cfg->dialwait = lp->dialwait / HZ;
-		if (lp->slave)
-			strcpy(cfg->slave, ((isdn_net_local *) lp->slave->priv)->name);
-		else
-			cfg->slave[0] = '\0';
-		if (lp->master)
-			strcpy(cfg->master, ((isdn_net_local *) lp->master->priv)->name);
-		else
-			cfg->master[0] = '\0';
-		return 0;
-	}
-	return -ENODEV;
+	return 0;
 }
 
 /*
@@ -2969,7 +2023,7 @@
          * in (partially) wrong number copied to user. This race
 	 * currently ignored.
 	 */
-	idx = p->local.isdn_slot;
+	idx = p->isdn_slot;
 	if (idx<0) return -ENOTCONN;
 	/* for pre-bound channels, we need this extra check */
 	if (strncmp(isdn_slot_num(idx),"???",3) == 0 ) return -ENOTCONN;
@@ -3035,22 +2089,23 @@
 int
 isdn_net_force_hangup(char *name)
 {
-	isdn_net_dev *p = isdn_net_findif(name);
+	isdn_net_dev *idev = isdn_net_findif(name);
 	struct net_device *q;
 
-	if (p) {
-		if (p->local.isdn_slot < 0)
-			return 1;
-		q = p->local.slave;
-		/* If this interface has slaves, do a hangup for them also. */
-		while (q) {
-			isdn_net_hangup(&p->local);
-			q = (((isdn_net_local *) q->priv)->slave);
-		}
-		isdn_net_hangup(&p->local);
-		return 0;
+	if (!idev)
+		return -ENODEV;
+
+	if (idev->isdn_slot < 0)
+		return -ENOTCONN;
+
+	q = idev->local.slave;
+	/* If this interface has slaves, do a hangup for them also. */
+	while (q) {
+		isdn_net_hangup(((isdn_net_local *) q->priv)->netdev);
+		q = (((isdn_net_local *) q->priv)->slave);
 	}
-	return -ENODEV;
+	isdn_net_hangup(idev);
+	return 0;
 }
 
 /*
@@ -3067,35 +2122,31 @@
 		restore_flags(flags);
 		return -EBUSY;
 	}
-#ifdef CONFIG_ISDN_X25
-	if( p -> cprot && p -> cprot -> pops )
-		p -> cprot -> pops -> proto_del ( p -> cprot );
-#endif
+	isdn_net_set_encap(p, -1);
+
 	/* Free all phone-entries */
 	isdn_net_rmallphone(p);
 	/* If interface is bound exclusive, free channel-usage */
-	if (p->local.exclusive != -1)
-		isdn_unexclusive_channel(p->local.pre_device, p->local.pre_channel);
+	if (p->exclusive >= 0)
+		isdn_unexclusive_channel(p->pre_device, p->pre_channel);
 	if (p->local.master) {
 		/* It's a slave-device, so update master's slave-pointer if necessary */
 		if (((isdn_net_local *) (p->local.master->priv))->slave == &p->dev)
 			((isdn_net_local *) (p->local.master->priv))->slave = p->local.slave;
 	} else {
 		/* Unregister only if it's a master-device */
-		p->dev.hard_header_cache = p->local.org_hhc;
-		p->dev.header_cache_update = p->local.org_hcu;
 		unregister_netdev(&p->dev);
 	}
 	/* Unlink device from chain */
 	list_del(&p->global_list);
 	if (p->local.slave) {
 		/* If this interface has a slave, remove it also */
-		char *slavename = ((isdn_net_local *) (p->local.slave->priv))->name;
+		char *slavename = ((isdn_net_local *) (p->local.slave->priv))->netdev->name;
 		struct list_head *l;
 
 		list_for_each(l, &isdn_net_devs) {
 			isdn_net_dev *n = list_entry(l, isdn_net_dev, global_list);
-			if (!strcmp(n->local.name, slavename)) {
+			if (!strcmp(n->name, slavename)) {
 				isdn_net_realrm(n);
 				break;
 			}
@@ -3118,7 +2169,7 @@
 	/* Search name in netdev-chain */
 	list_for_each(l, &isdn_net_devs) {
 		isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list);
-		if (!strcmp(p->local.name, name))
+		if (!strcmp(p->name, name))
 			return isdn_net_realrm(p);
 	}
 	return -ENODEV;
@@ -3149,4 +2200,210 @@
 	}
 	restore_flags(flags);
 	return 0;
+}
+
+// ISDN_NET_ENCAP_IPTYP
+// ethernet type field
+// ======================================================================
+
+static int
+isdn_iptyp_header(struct sk_buff *skb, struct net_device *dev,
+		   unsigned short type, void *daddr, void *saddr, 
+		   unsigned plen)
+{
+	put_u16(skb_push(skb, 2), type);
+	return 2;
+}
+
+static void
+isdn_iptyp_receive(isdn_net_dev *p, isdn_net_local *olp, 
+		   struct sk_buff *skb)
+{
+	isdn_net_reset_huptimer(p, olp->netdev);
+	get_u16(skb->data, &skb->protocol);
+	skb_pull(skb, 2);
+	netif_rx(skb);
+}
+
+static struct isdn_netif_ops iptyp_ops = {
+	.hard_header         = isdn_iptyp_header,
+	.flags               = IFF_NOARP | IFF_POINTOPOINT,
+	.type                = ARPHRD_PPP,
+	.addr_len            = 2,
+	.receive             = isdn_iptyp_receive,
+};
+
+// ISDN_NET_ENCAP_UIHDLC
+// HDLC with UI-Frames (for ispa with -h1 option) */
+// ======================================================================
+
+static int
+isdn_uihdlc_header(struct sk_buff *skb, struct net_device *dev,
+		   unsigned short type, void *daddr, void *saddr, 
+		   unsigned plen)
+{
+	put_u16(skb_push(skb, 2), 0x0103);
+	return 2;
+}
+
+static void
+isdn_uihdlc_receive(isdn_net_dev *p, isdn_net_local *olp, 
+		    struct sk_buff *skb)
+{
+	isdn_net_reset_huptimer(p, olp->netdev);
+	skb_pull(skb, 2);
+	skb->protocol = htons(ETH_P_IP);
+	netif_rx(skb);
+}
+
+static struct isdn_netif_ops uihdlc_ops = {
+	.hard_header         = isdn_uihdlc_header,
+	.flags               = IFF_NOARP | IFF_POINTOPOINT,
+	.type                = ARPHRD_HDLC,
+	.addr_len            = 2,
+	.receive             = isdn_uihdlc_receive,
+};
+
+// ISDN_NET_ENCAP_RAWIP
+// RAW-IP without MAC-Header
+// ======================================================================
+
+static void
+isdn_rawip_receive(isdn_net_dev *p, isdn_net_local *olp, 
+		   struct sk_buff *skb)
+{
+	isdn_net_reset_huptimer(p, olp->netdev);
+	skb->protocol = htons(ETH_P_IP);
+	netif_rx(skb);
+}
+
+static struct isdn_netif_ops rawip_ops = {
+	.flags               = IFF_NOARP | IFF_POINTOPOINT,
+	.type                = ARPHRD_PPP,
+	.receive             = isdn_rawip_receive,
+};
+
+// ISDN_NET_ENCAP_ETHER
+// Ethernet over ISDN
+// ======================================================================
+
+/*      This is simply a copy from std. eth.c EXCEPT we pull ETH_HLEN
+ *      instead of dev->hard_header_len off. This is done because the
+ *      lowlevel-driver has already pulled off its stuff when we get
+ *      here and this routine only gets called with p_encap == ETHER.
+ *      Determine the packet's protocol ID. The rule here is that we
+ *      assume 802.3 if the type field is short enough to be a length.
+ *      This is normal practice and works for any 'now in use' protocol.
+ *      FIXME
+ */
+
+static unsigned short
+isdn_eth_type_trans(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ethhdr *eth;
+	unsigned char *rawp;
+
+	skb->mac.raw = skb->data;
+	skb_pull(skb, ETH_HLEN);
+	eth = skb->mac.ethernet;
+
+	if (*eth->h_dest & 1) {
+		if (memcmp(eth->h_dest, dev->broadcast, ETH_ALEN) == 0)
+			skb->pkt_type = PACKET_BROADCAST;
+		else
+			skb->pkt_type = PACKET_MULTICAST;
+	}
+	/*
+	 *      This ALLMULTI check should be redundant by 1.4
+	 *      so don't forget to remove it.
+	 */
+
+	else if (dev->flags & (IFF_PROMISC /*| IFF_ALLMULTI*/)) {
+		if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN))
+			skb->pkt_type = PACKET_OTHERHOST;
+	}
+	if (ntohs(eth->h_proto) >= 1536)
+		return eth->h_proto;
+
+	rawp = skb->data;
+
+	/*
+	 *      This is a magic hack to spot IPX packets. Older Novell breaks
+	 *      the protocol design and runs IPX over 802.3 without an 802.2 LLC
+	 *      layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
+	 *      won't work for fault tolerant netware but does for the rest.
+	 */
+	if (*(unsigned short *) rawp == 0xFFFF)
+		return htons(ETH_P_802_3);
+	/*
+	 *      Real 802.2 LLC
+	 */
+	return htons(ETH_P_802_2);
+}
+
+static void
+isdn_ether_receive(isdn_net_dev *p, isdn_net_local *olp, 
+		   struct sk_buff *skb)
+{
+	isdn_net_reset_huptimer(p, olp->netdev);
+	skb->protocol = isdn_eth_type_trans(skb, skb->dev);
+	netif_rx(skb);
+}
+
+static int
+isdn_ether_open(isdn_net_local *lp)
+{
+	struct net_device *dev = &lp->netdev->dev;
+	struct in_device *in_dev;
+	int i;
+
+	/* Fill in the MAC-level header ... */
+	for (i = 0; i < ETH_ALEN; i++)
+		dev->dev_addr[i] = 0xfc;
+	in_dev = dev->ip_ptr;
+	if (in_dev) {
+		/* any address will do - we take the first */
+		struct in_ifaddr *ifa = in_dev->ifa_list;
+		if (ifa)
+			memcpy(dev->dev_addr+2, &ifa->ifa_local, 4);
+	}
+	return 0;
+}
+
+static int
+isdn_ether_init(isdn_net_local *lp)
+{
+	struct net_device *dev = &lp->netdev->dev;
+
+	ether_setup(dev);
+	dev->tx_queue_len = 10;
+	dev->hard_header_len += isdn_hard_header_len();
+
+	return 0;
+}
+
+static struct isdn_netif_ops ether_ops = {
+	.hard_header         = eth_header,
+	.receive             = isdn_ether_receive,
+	.init                = isdn_ether_init,
+	.open                = isdn_ether_open,
+};
+
+// ======================================================================
+
+void
+isdn_net_init_module(void)
+{
+	register_isdn_netif(ISDN_NET_ENCAP_ETHER,      &ether_ops);
+	register_isdn_netif(ISDN_NET_ENCAP_RAWIP,      &rawip_ops);
+	register_isdn_netif(ISDN_NET_ENCAP_IPTYP,      &iptyp_ops);
+	register_isdn_netif(ISDN_NET_ENCAP_UIHDLC,     &uihdlc_ops);
+	register_isdn_netif(ISDN_NET_ENCAP_CISCOHDLC,  &ciscohdlck_ops);
+	register_isdn_netif(ISDN_NET_ENCAP_CISCOHDLCK, &ciscohdlck_ops);
+#ifdef CONFIG_ISDN_X25
+	register_isdn_netif(ISDN_NET_ENCAP_X25IFACE,   &isdn_x25_ops);
+#endif
+#ifdef CONFIG_ISDN_PPP
+	register_isdn_netif(ISDN_NET_ENCAP_SYNCPPP,    &isdn_ppp_ops);
+#endif
 }
diff -Nru a/drivers/isdn/i4l/isdn_net.h b/drivers/isdn/i4l/isdn_net.h
--- a/drivers/isdn/i4l/isdn_net.h	Tue Oct  1 00:08:19 2002
+++ b/drivers/isdn/i4l/isdn_net.h	Tue Oct  1 00:08:19 2002
@@ -11,7 +11,10 @@
  *
  */
 
-			      /* Definitions for hupflags:                */
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/isdn.h>
+  			      /* Definitions for hupflags:                */
 #define ISDN_CHARGEHUP   4      /* We want to use the charge mechanism      */
 #define ISDN_INHUP       8      /* Even if incoming, close after huptimeout */
 #define ISDN_MANCHARGE  16      /* Charge Interval manually set             */
@@ -29,6 +32,8 @@
 #define CISCO_SLARP_REPLY     1
 #define CISCO_SLARP_KEEPALIVE 2
 
+extern void isdn_net_init_module(void);
+
 extern int isdn_net_new(char *, struct net_device *);
 extern int isdn_net_newslave(char *);
 extern int isdn_net_rm(char *);
@@ -41,7 +46,7 @@
 extern int isdn_net_getpeer(isdn_net_ioctl_phone *, isdn_net_ioctl_phone *);
 extern int isdn_net_delphone(isdn_net_ioctl_phone *);
 extern int isdn_net_find_icall(int, int, int, setup_parm *);
-extern void isdn_net_hangup(isdn_net_local *);
+extern void isdn_net_hangup(isdn_net_dev *);
 extern void isdn_net_hangup_all(void);
 extern int isdn_net_force_hangup(char *);
 extern int isdn_net_force_dial(char *);
@@ -50,6 +55,14 @@
 extern int isdn_net_dial_req(isdn_net_local *);
 extern void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb);
 extern void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb);
+extern int isdn_net_online(isdn_net_dev *idev);
+
+static inline void
+isdn_net_reset_huptimer(isdn_net_dev *idev, isdn_net_dev *idev2)
+{
+	idev->huptimer = 0;
+	idev2->huptimer = 0;
+}
 
 #define ISDN_NET_MAX_QUEUE_LENGTH 2
 
@@ -133,6 +146,23 @@
 	}
 	lp->next = lp->last = lp;	/* (re)set own pointers */
 	spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags);
+}
+
+/*
+ * wake up the network -> net_device queue.
+ * For slaves, wake the corresponding master interface.
+ */
+static inline void isdn_net_device_wake_queue(isdn_net_local *lp)
+{
+	if (lp->master) 
+		netif_wake_queue(lp->master);
+	else
+		netif_wake_queue(&lp->netdev->dev);
+}
+
+static inline int isdn_net_bound(isdn_net_dev *idev)
+{
+	return idev->isdn_slot >= 0;
 }
 
 static inline int
diff -Nru a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
--- a/drivers/isdn/i4l/isdn_ppp.c	Tue Oct  1 00:08:18 2002
+++ b/drivers/isdn/i4l/isdn_ppp.c	Tue Oct  1 00:08:18 2002
@@ -14,6 +14,7 @@
 #include <linux/smp_lock.h>
 #include <linux/poll.h>
 #include <linux/ppp-comp.h>
+#include <linux/if_arp.h>
 
 #include "isdn_common.h"
 #include "isdn_ppp.h"
@@ -98,16 +99,17 @@
  * note: it can happen, that we hangup/free the master before the slaves
  *       in this case we bind another lp to the master device
  */
-int
+static void
 isdn_ppp_free(isdn_net_local * lp)
 {
+	isdn_net_dev *idev = lp->netdev;
 	unsigned long flags;
 	struct ippp_struct *is;
 
-	if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
+	if (idev->ppp_slot < 0 || idev->ppp_slot > ISDN_MAX_CHANNELS) {
 		printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",
-		       __FUNCTION__ , lp->ppp_slot);
-		return 0;
+		       __FUNCTION__ , idev->ppp_slot);
+		return;
 	}
 
 	save_flags(flags);
@@ -124,26 +126,26 @@
 	lp->netdev->pb->ref_ct--;
 	spin_unlock(&lp->netdev->pb->lock);
 #endif /* CONFIG_ISDN_MPP */
-	if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
+	if (idev->ppp_slot < 0 || idev->ppp_slot > ISDN_MAX_CHANNELS) {
 		printk(KERN_ERR "%s: ppp_slot(%d) now invalid\n",
-		       __FUNCTION__ , lp->ppp_slot);
+		       __FUNCTION__ , idev->ppp_slot);
 		restore_flags(flags);
-		return 0;
+		return;
 	}
-	is = ippp_table[lp->ppp_slot];
+	is = ippp_table[idev->ppp_slot];
 	if ((is->state & IPPP_CONNECT))
-		isdn_ppp_closewait(lp->ppp_slot);	/* force wakeup on ippp device */
+		isdn_ppp_closewait(idev->ppp_slot);	/* force wakeup on ippp device */
 	else if (is->state & IPPP_ASSIGNED)
 		is->state = IPPP_OPEN;	/* fallback to 'OPEN but not ASSIGNED' state */
 
 	if (is->debug & 0x1)
-		printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_slot, (long) lp, (long) is->lp);
+		printk(KERN_DEBUG "isdn_ppp_free %d %p %p\n", idev->ppp_slot, lp, is->idev);
 
-	is->lp = NULL;          /* link is down .. set lp to NULL */
-	lp->ppp_slot = -1;      /* is this OK ?? */
+	is->idev = NULL;          /* link is down .. set lp to NULL */
+	idev->ppp_slot = -1;      /* is this OK ?? */
 
 	restore_flags(flags);
-	return 0;
+	return;
 }
 
 /*
@@ -152,6 +154,7 @@
 int
 isdn_ppp_bind(isdn_net_local * lp)
 {
+	isdn_net_dev *idev = lp->netdev;
 	int i;
 	int unit = 0;
 	long flags;
@@ -160,16 +163,15 @@
 
 	save_flags(flags);
 	cli();
-	if (lp->pppbind < 0) {  /* device bounded to ippp device ? */
+	if (idev->pppbind < 0) {  /* device bound to ippp device ? */
 		struct list_head *l;
 		char exclusive[ISDN_MAX_CHANNELS];	/* exclusive flags */
 		memset(exclusive, 0, ISDN_MAX_CHANNELS);
 		/* step through net devices to find exclusive minors */
 		list_for_each(l, &isdn_net_devs) {
 			isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list);
-			isdn_net_local *lp = &p->local;
-			if (lp->pppbind >= 0)
-				exclusive[lp->pppbind] = 1;
+			if (p->pppbind >= 0)
+				exclusive[p->pppbind] = 1;
 		}
 		/*
 		 * search a free device / slot
@@ -181,7 +183,7 @@
 		}
 	} else {
 		for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-			if (ippp_table[i]->minor == lp->pppbind &&
+			if (ippp_table[i]->minor == idev->pppbind &&
 			    (ippp_table[i]->state & IPPP_OPEN) == IPPP_OPEN)
 				break;
 		}
@@ -193,16 +195,16 @@
 		retval = -1;
 		goto out;
 	}
-	unit = isdn_ppp_if_get_unit(lp->name);	/* get unit number from interface name .. ugly! */
+	unit = isdn_ppp_if_get_unit(idev->name);	/* get unit number from interface name .. ugly! */
 	if (unit < 0) {
-		printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n", lp->name);
+		printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n", idev->name);
 		retval = -1;
 		goto out;
 	}
 	
-	lp->ppp_slot = i;
+	idev->ppp_slot = i;
 	is = ippp_table[i];
-	is->lp = lp;
+	is->idev = idev;
 	is->unit = unit;
 	is->state = IPPP_OPEN | IPPP_ASSIGNED;	/* assigned to a netdevice but not connected */
 #ifdef CONFIG_ISDN_MPP
@@ -211,7 +213,7 @@
 		goto out;
 #endif /* CONFIG_ISDN_MPP */
 
-	retval = lp->ppp_slot;
+	retval = idev->ppp_slot;
 
  out:
 	restore_flags(flags);
@@ -223,16 +225,18 @@
  * (wakes up daemon after B-channel connect)
  */
 
-void
-isdn_ppp_wakeup_daemon(isdn_net_local * lp)
+static void
+isdn_ppp_wakeup_daemon(isdn_net_local *lp)
 {
-	if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
+	isdn_net_dev *idev = lp->netdev;
+
+	if (idev->ppp_slot < 0 || idev->ppp_slot >= ISDN_MAX_CHANNELS) {
 		printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",
-		       __FUNCTION__, lp->ppp_slot);
+		       __FUNCTION__, idev->ppp_slot);
 		return;
 	}
-	ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK;
-	wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq);
+	ippp_table[idev->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK;
+	wake_up_interruptible(&ippp_table[idev->ppp_slot]->wq);
 }
 
 /*
@@ -300,7 +304,7 @@
 
 	is->reset = isdn_ppp_ccp_reset_alloc(is);
 
-	is->lp = NULL;
+	is->idev = NULL;
 	is->mp_seqno = 0;       /* MP sequence number */
 	is->pppcfg = 0;         /* ppp configuration */
 	is->mpppcfg = 0;        /* mppp configuration */
@@ -341,16 +345,16 @@
 	is = file->private_data;
 
 	if (is->debug & 0x1)
-		printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", minor, (long) is->lp);
+		printk(KERN_DEBUG "ippp: release, minor: %d %p\n", minor, is->idev);
 
-	if (is->lp) {           /* a lp address says: this link is still up */
+	if (is->idev) {           /* a lp address says: this link is still up */
 		/*
 		 * isdn_net_hangup() calls isdn_ppp_free()
 		 * isdn_ppp_free() sets is->lp to NULL and lp->ppp_slot to -1
 		 * removing the IPPP_CONNECT flag omits calling of isdn_ppp_wakeup_daemon()
 		 */
 		is->state &= ~IPPP_CONNECT;
-		isdn_net_hangup(is->lp);
+		isdn_net_hangup(is->idev);
 	}
 	for (i = 0; i < NUM_RCV_BUFFS; i++) {
 		if (is->rq[i].buf) {
@@ -424,14 +428,14 @@
 static int
 isdn_ppp_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned long arg)
 {
+	isdn_net_dev *idev;
 	unsigned long val;
 	int r,i,j;
 	struct ippp_struct *is;
-	isdn_net_local *lp;
 	struct isdn_ppp_comp_data data;
 
 	is = (struct ippp_struct *) file->private_data;
-	lp = is->lp;
+	idev = is->idev;
 
 	if (is->debug & 0x1)
 		printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", is->minor, cmd, is->state);
@@ -458,9 +462,9 @@
 				return r;
 			break;
 		case PPPIOCGIFNAME:
-			if(!lp)
+			if(!idev)
 				return -EINVAL;
-			if ((r = set_arg((void *) arg, lp->name, strlen(lp->name))))
+			if ((r = set_arg((void *) arg, idev->name, strlen(idev->name))))
 				return r;
 			break;
 		case PPPIOCGMPFLAGS:	/* get configuration flags */
@@ -481,17 +485,17 @@
 				return r;
 			}
 			if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) {
-				if (lp) {
+				if (idev) {
 					/* OK .. we are ready to send buffers */
-					netif_wake_queue(&lp->netdev->dev);
+					netif_wake_queue(&idev->dev);
 				}
 			}
 			is->pppcfg = val;
 			break;
 		case PPPIOCGIDLE:	/* get idle time information */
-			if (lp) {
+			if (idev) {
 				struct ppp_idle pidle;
-				pidle.xmit_idle = pidle.recv_idle = lp->huptimer;
+				pidle.xmit_idle = pidle.recv_idle = idev->huptimer;
 				if ((r = set_arg((void *) arg, &pidle,sizeof(struct ppp_idle))))
 					 return r;
 			}
@@ -562,21 +566,21 @@
 				struct pppcallinfo pci;
 				int i;
 				memset((char *) &pci,0,sizeof(struct pppcallinfo));
-				if(lp) {
-					strncpy(pci.local_num,lp->msn,63);
+				if(idev) {
+					strncpy(pci.local_num,idev->local.msn,63);
 					i = 0;
-					list_for_each_entry(phone, &lp->phone[1], list) {
-						if (i++ == lp->dial) {
+					list_for_each_entry(phone, &idev->local.phone[1], list) {
+						if (i++ == idev->dial) {
 							strncpy(pci.remote_num,phone->num,63);
 							break;
 						}
 					}
-					pci.charge_units = lp->charge;
-					if(lp->outgoing)
+					pci.charge_units = idev->charge;
+					if(idev->outgoing)
 						pci.calltype = CALLTYPE_OUTGOING;
 					else
 						pci.calltype = CALLTYPE_INCOMING;
-					if(lp->flags & ISDN_NET_CALLBACK)
+					if(idev->local.flags & ISDN_NET_CALLBACK)
 						pci.calltype |= CALLTYPE_CALLBACK;
 				}
 				return set_arg((void *)arg,&pci,sizeof(struct pppcallinfo));
@@ -760,7 +764,7 @@
 static ssize_t
 isdn_ppp_write(struct file *file, const char *buf, size_t count, loff_t *off)
 {
-	isdn_net_local *lp;
+	isdn_net_dev *idev;
 	struct ippp_struct *is;
 	int proto;
 	unsigned char protobuf[4];
@@ -778,12 +782,11 @@
 		goto out;
 	}
 
-	lp = is->lp;
-
 	/* -> push it directly to the lowlevel interface */
 
-	if (!lp)
-		printk(KERN_DEBUG "isdn_ppp_write: lp == NULL\n");
+	idev = is->idev;
+	if (!idev)
+		printk(KERN_DEBUG "isdn_ppp_write: idev == NULL\n");
 	else {
 		/*
 		 * Don't reset huptimer for
@@ -795,15 +798,14 @@
 		}
 		proto = PPP_PROTOCOL(protobuf);
 		if (proto != PPP_LCP)
-			lp->huptimer = 0;
+			idev->huptimer = 0;
 
-		if (lp->isdn_slot < 0) {
+		if (idev->isdn_slot < 0) {
 			retval = 0;
 			goto out;
 		}
-		if ((dev->drv[isdn_slot_driver(lp->isdn_slot)]->flags & DRV_FLAG_RUNNING) &&
-			lp->dialstate == 0 &&
-		    (lp->flags & ISDN_NET_CONNECTED)) {
+		if ((dev->drv[isdn_slot_driver(idev->isdn_slot)]->flags & DRV_FLAG_RUNNING) &&
+		    isdn_net_online(idev)) {
 			unsigned short hl;
 			struct sk_buff *skb;
 			/*
@@ -811,7 +813,7 @@
 			 * sk_buff. old call to dev_alloc_skb only reserved
 			 * 16 bytes, now we are looking what the driver want
 			 */
-			hl = isdn_slot_hdrlen(lp->isdn_slot);
+			hl = isdn_slot_hdrlen(idev->isdn_slot);
 			skb = alloc_skb(hl+count, GFP_ATOMIC);
 			if (!skb) {
 				printk(KERN_WARNING "isdn_ppp_write: out of memory!\n");
@@ -827,12 +829,12 @@
 			}
 			if (is->debug & 0x40) {
 				printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len);
-				isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,is->unit,lp->ppp_slot);
+				isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,is->unit,idev->ppp_slot);
 			}
 
-			isdn_ppp_send_ccp(lp->netdev,lp,skb); /* keeps CCP/compression states in sync */
+			isdn_ppp_send_ccp(idev,&idev->local,skb); /* keeps CCP/compression states in sync */
 
-			isdn_net_write_super(lp, skb);
+			isdn_net_write_super(&idev->local, skb);
 		}
 	}
 	retval = count;
@@ -961,28 +963,34 @@
 /*
  * handler for incoming packets on a syncPPP interface
  */
-void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb)
+static void isdn_ppp_receive(isdn_net_dev *net_dev, isdn_net_local *lp, 
+			     struct sk_buff *skb)
 {
+	isdn_net_dev *idev = lp->netdev;
 	struct ippp_struct *is;
 	int slot;
 	int proto;
 
-	if (net_dev->local.master)
-		BUG(); // we're called with the master device always
+	/*
+	 * If encapsulation is syncppp, don't reset
+	 * huptimer on LCP packets.
+	 */
+	if (PPP_PROTOCOL(skb->data) != PPP_LCP)
+		isdn_net_reset_huptimer(net_dev,lp->netdev);
 
-	slot = lp->ppp_slot;
+	slot = idev->ppp_slot;
 	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
 		printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot(%d)\n",
-			lp->ppp_slot);
+		       slot);
 		kfree_skb(skb);
 		return;
 	}
 	is = ippp_table[slot];
 
 	if (is->debug & 0x4) {
-		printk(KERN_DEBUG "ippp_receive: is:%08lx lp:%08lx slot:%d unit:%d len:%d\n",
-		       (long)is,(long)lp,lp->ppp_slot,is->unit,(int) skb->len);
-		isdn_ppp_frame_log("receive", skb->data, skb->len, 32,is->unit,lp->ppp_slot);
+		printk(KERN_DEBUG "ippp_receive: is:%p lp:%p slot:%d unit:%d len:%d\n",
+		       is,lp,idev->ppp_slot,is->unit,(int) skb->len);
+		isdn_ppp_frame_log("receive", skb->data, skb->len, 32,is->unit,idev->ppp_slot);
 	}
 
  	if (isdn_ppp_skip_ac(is, skb) < 0) {
@@ -1020,23 +1028,24 @@
 static void
 isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb, int proto)
 {
+	isdn_net_dev *idev = lp->netdev;
 	struct net_device *dev = &net_dev->dev;
  	struct ippp_struct *is, *mis;
 	int slot;
 
-	slot = lp->ppp_slot;
+	slot = idev->ppp_slot;
 	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
 		printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot(%d)\n",
-			lp->ppp_slot);
+		       slot);
 		goto drop_packet;
 	}
 	is = ippp_table[slot];
  	
  	if (lp->master) { // FIXME?
- 		slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot;
+ 		slot = ((isdn_net_local *) (lp->master->priv))->netdev->ppp_slot;
  		if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
  			printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot(%d)\n",
- 				lp->ppp_slot);
+			       slot);
 			goto drop_packet;
  		}
  	}
@@ -1044,7 +1053,7 @@
 
 	if (is->debug & 0x10) {
 		printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto);
-		isdn_ppp_frame_log("rpush", skb->data, skb->len, 32,is->unit,lp->ppp_slot);
+		isdn_ppp_frame_log("rpush", skb->data, skb->len, 32,is->unit,slot);
 	}
 	if (mis->compflags & SC_DECOMP_ON) {
 		skb = isdn_ppp_decompress(skb, is, mis, &proto);
@@ -1070,12 +1079,12 @@
 		case PPP_VJC_UNCOMP:
 			if (is->debug & 0x20)
 				printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
-			if (net_dev->local.ppp_slot < 0) {
-				printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n",
-				       __FUNCTION__ , net_dev->local.ppp_slot);
+			if (net_dev->ppp_slot < 0) {
+				printk(KERN_ERR "%s: net_dev->ppp_slot(%d) out of range\n",
+				       __FUNCTION__ , net_dev->ppp_slot);
 				goto drop_packet;
 			}
-			if (slhc_remember(ippp_table[net_dev->local.ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
+			if (slhc_remember(ippp_table[net_dev->ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
 				printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
 				goto drop_packet;
 			}
@@ -1096,12 +1105,12 @@
 				}
 				skb_put(skb, skb_old->len + 128);
 				memcpy(skb->data, skb_old->data, skb_old->len);
-				if (net_dev->local.ppp_slot < 0) {
-					printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n",
-					       __FUNCTION__ , net_dev->local.ppp_slot);
+				if (net_dev->ppp_slot < 0) {
+					printk(KERN_ERR "%s: net_dev->ppp_slot(%d) out of range\n",
+					       __FUNCTION__ , net_dev->ppp_slot);
 					goto drop_packet;
 				}
-				pkt_len = slhc_uncompress(ippp_table[net_dev->local.ppp_slot]->slcomp,
+				pkt_len = slhc_uncompress(ippp_table[net_dev->ppp_slot]->slcomp,
 						skb->data, skb_old->len);
 				kfree_skb(skb_old);
 				if (pkt_len < 0)
@@ -1122,13 +1131,13 @@
 				break;
 			/* fall through */
 		default:
-			isdn_ppp_fill_rq(skb->data, skb->len, proto, lp->ppp_slot);	/* push data to pppd device */
+			isdn_ppp_fill_rq(skb->data, skb->len, proto, idev->ppp_slot);	/* push data to pppd device */
 			kfree_skb(skb);
 			return;
 	}
 
  	/* Reset hangup-timer */
- 	lp->huptimer = 0;
+ 	idev->huptimer = 0;
 
 	skb->dev = dev;
 	skb->mac.raw = skb->data;
@@ -1179,6 +1188,7 @@
 isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
 	isdn_net_local *lp,*mlp;
+	isdn_net_dev *idev;
 	isdn_net_dev *nd;
 	unsigned int proto = PPP_IP;     /* 0x21 */
 	struct ippp_struct *ipt,*ipts;
@@ -1187,10 +1197,10 @@
 	mlp = (isdn_net_local *) (netdev->priv);
 	nd = mlp->netdev;       /* get master lp */
 
-	slot = mlp->ppp_slot;
+	slot = nd->ppp_slot;
 	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
 		printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
-			mlp->ppp_slot);
+		       slot);
 		kfree_skb(skb);
 		return 0;
 	}
@@ -1222,16 +1232,16 @@
 		return 1;
 	}
 	/* we have our lp locked from now on */
-
-	slot = lp->ppp_slot;
+	idev = lp->netdev;
+	slot = idev->ppp_slot;
 	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
 		printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
-			lp->ppp_slot);
+		       slot);
 		kfree_skb(skb);
 		return 0;
 	}
 	ipt = ippp_table[slot];
-	lp->huptimer = 0;
+	idev->huptimer = 0;
 
 	/*
 	 * after this line .. requeueing in the device queue is no longer allowed!!!
@@ -1245,7 +1255,7 @@
 	if (ipt->debug & 0x4)
 		printk(KERN_DEBUG "xmit skb, len %d\n", (int) skb->len);
         if (ipts->debug & 0x40)
-                isdn_ppp_frame_log("xmit0", skb->data, skb->len, 32,ipts->unit,lp->ppp_slot);
+                isdn_ppp_frame_log("xmit0", skb->data, skb->len, 32,ipts->unit,idev->ppp_slot);
 
 #ifdef CONFIG_ISDN_PPP_VJ
 	if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) {	/* ipts here? probably yes, but check this again */
@@ -1256,7 +1266,7 @@
 		 * sk_buff. old call to dev_alloc_skb only reserved
 		 * 16 bytes, now we are looking what the driver want.
 		 */
-		hl = isdn_slot_hdrlen(lp->isdn_slot) + IPPP_MAX_HEADER;;
+		hl = isdn_slot_hdrlen(idev->isdn_slot) + IPPP_MAX_HEADER;;
 		/* 
 		 * Note: hl might still be insufficient because the method
 		 * above does not account for a possibible MPPP slave channel
@@ -1372,7 +1382,7 @@
 
 	if (ipts->debug & 0x40) {
 		printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len);
-		isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,ipt->unit,lp->ppp_slot);
+		isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,ipt->unit,idev->ppp_slot);
 	}
 	
 	isdn_net_writebuf_skb(lp, skb);
@@ -1431,15 +1441,16 @@
 
 static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to )
 {
+	isdn_net_dev *idev = lp->netdev;
 	struct ippp_struct * is;
 
-	if (lp->ppp_slot < 0) {
-		printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
-		       __FUNCTION__ , lp->ppp_slot);
-		return(-EINVAL);
+	if (idev->ppp_slot < 0) {
+		printk(KERN_ERR "%s: >ppp_slot(%d) out of range\n",
+		       __FUNCTION__ , idev->ppp_slot);
+		return -EINVAL;
 	}
 
-	is = ippp_table[lp->ppp_slot];
+	is = ippp_table[idev->ppp_slot];
 	if (add_to) {
 		if( lp->netdev->pb )
 			lp->netdev->pb->ref_ct--;
@@ -1471,6 +1482,7 @@
 static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, 
 							struct sk_buff *skb)
 {
+	isdn_net_dev *idev = lp->netdev;
 	struct ippp_struct *is;
 	isdn_net_local * lpq;
 	ippp_bundle * mp;
@@ -1483,10 +1495,10 @@
 	spin_lock_irqsave(&net_dev->pb->lock, flags);
     	mp = net_dev->pb;
         stats = &mp->stats;
-	slot = lp->ppp_slot;
+	slot = idev->ppp_slot;
 	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
-		printk(KERN_ERR "%s: lp->ppp_slot(%d)\n",
-		       __FUNCTION__, lp->ppp_slot);
+		printk(KERN_ERR "%s: ppp_slot(%d)\n",
+		       __FUNCTION__, slot);
 		stats->frame_drops++;
 		dev_kfree_skb(skb);
 		spin_unlock_irqrestore(&mp->lock, flags);
@@ -1497,7 +1509,7 @@
 		stats->max_queue_len = mp->frames;
 	
 	if (is->debug & 0x8)
-		isdn_ppp_mp_print_recv_pkt(lp->ppp_slot, skb);
+		isdn_ppp_mp_print_recv_pkt(slot, skb);
 
 	newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ, 
 						skb, is->last_link_seqno);
@@ -1520,10 +1532,10 @@
 	/* find the minimum received sequence number over all links */
 	is->last_link_seqno = minseq = newseq;
 	for (lpq = net_dev->queue;;) {
-		slot = lpq->ppp_slot;
+		slot = lpq->netdev->ppp_slot;
 		if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
 			printk(KERN_ERR "%s: lpq->ppp_slot(%d)\n",
-			       __FUNCTION__ , lpq->ppp_slot);
+			       __FUNCTION__ ,slot);
 		} else {
 			u32 lls = ippp_table[slot]->last_link_seqno;
 			if (MP_LT(lls, minseq))
@@ -1750,18 +1762,19 @@
 void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,
 				struct sk_buff * from, struct sk_buff * to )
 {
+	isdn_net_dev *idev = lp->netdev;
 	ippp_bundle * mp = net_dev->pb;
 	int proto;
 	struct sk_buff * skb;
 	unsigned int tot_len;
 
-	if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
-		printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
-		       __FUNCTION__ , lp->ppp_slot);
+	if (idev->ppp_slot < 0 || idev->ppp_slot > ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",
+		       __FUNCTION__ , idev->ppp_slot);
 		return;
 	}
 	if( MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG) ) {
-		if( ippp_table[lp->ppp_slot]->debug & 0x40 )
+		if( ippp_table[idev->ppp_slot]->debug & 0x40 )
 			printk(KERN_DEBUG "isdn_mppp: reassembly: frame %d, "
 					"len %d\n", MP_SEQ(from), from->len );
 		skb = from;
@@ -1774,7 +1787,7 @@
 		for(tot_len=n=0, frag=from; frag != to; frag=frag->next, n++)
 			tot_len += frag->len - MP_HEADER_LEN;
 
-		if( ippp_table[lp->ppp_slot]->debug & 0x40 )
+		if( ippp_table[idev->ppp_slot]->debug & 0x40 )
 			printk(KERN_DEBUG"isdn_mppp: reassembling frames %d "
 				"to %d, len %d\n", MP_SEQ(from), 
 				(MP_SEQ(from)+n-1) & MP_LONGSEQ_MASK, tot_len );
@@ -1817,7 +1830,7 @@
 {
 	char ifn[IFNAMSIZ + 1];
 	isdn_net_dev *p;
-	isdn_net_local *lp, *nlp;
+	isdn_net_dev *idev, *nidev;
 	int rc;
 	unsigned long flags;
 
@@ -1830,27 +1843,27 @@
 
     	spin_lock_irqsave(&p->pb->lock, flags);
 
-	nlp = is->lp;
-	lp = p->queue;
-	if( nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ||
-		lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS ) {
+	nidev = is->idev;
+	idev = p->queue->netdev;
+	if( nidev->ppp_slot < 0 || nidev->ppp_slot >= ISDN_MAX_CHANNELS ||
+	    idev ->ppp_slot < 0 || idev ->ppp_slot >= ISDN_MAX_CHANNELS ) {
 		printk(KERN_ERR "ippp_bundle: binding to invalid slot %d\n",
-			nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ? 
-			nlp->ppp_slot : lp->ppp_slot );
+			nidev->ppp_slot < 0 || nidev->ppp_slot >= ISDN_MAX_CHANNELS ? 
+			nidev->ppp_slot : idev->ppp_slot );
 		rc = -EINVAL;
 		goto out;
  	}
 
-	isdn_net_add_to_bundle(p, nlp);
+	isdn_net_add_to_bundle(p, &nidev->local);
 
-	ippp_table[nlp->ppp_slot]->unit = ippp_table[lp->ppp_slot]->unit;
+	ippp_table[nidev->ppp_slot]->unit = ippp_table[idev->ppp_slot]->unit;
 
 	/* maybe also SC_CCP stuff */
-	ippp_table[nlp->ppp_slot]->pppcfg |= ippp_table[lp->ppp_slot]->pppcfg &
+	ippp_table[nidev->ppp_slot]->pppcfg |= ippp_table[idev->ppp_slot]->pppcfg &
 		(SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP);
-	ippp_table[nlp->ppp_slot]->mpppcfg |= ippp_table[lp->ppp_slot]->mpppcfg &
+	ippp_table[nidev->ppp_slot]->mpppcfg |= ippp_table[idev->ppp_slot]->mpppcfg &
 		(SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ);
-	rc = isdn_ppp_mp_init(nlp, p->pb);
+	rc = isdn_ppp_mp_init(&nidev->local, p->pb);
 out:
 	spin_unlock_irqrestore(&p->pb->lock, flags);
 	return rc;
@@ -1923,7 +1936,7 @@
 			if(copy_to_user(r, PPP_VERSION, len)) error = -EFAULT;
 			break;
 		case SIOCGPPPSTATS:
-			error = isdn_ppp_dev_ioctl_stats(lp->ppp_slot, ifr, dev);
+			error = isdn_ppp_dev_ioctl_stats(lp->netdev->ppp_slot, ifr, dev);
 			break;
 		default:
 			error = -EINVAL;
@@ -1963,20 +1976,22 @@
 isdn_ppp_dial_slave(char *name)
 {
 #ifdef CONFIG_ISDN_MPP
-	isdn_net_dev *ndev;
+	isdn_net_dev *idev;
 	isdn_net_local *lp;
 	struct net_device *sdev;
 
-	if (!(ndev = isdn_net_findif(name)))
+	idev = isdn_net_findif(name);
+	if (!idev)
 		return 1;
-	lp = &ndev->local;
-	if (!(lp->flags & ISDN_NET_CONNECTED))
+
+	lp = &idev->local;
+	if (!isdn_net_bound(idev))
 		return 5;
 
 	sdev = lp->slave;
 	while (sdev) {
 		isdn_net_local *mlp = (isdn_net_local *) sdev->priv;
-		if (!(mlp->flags & ISDN_NET_CONNECTED))
+		if (!isdn_net_bound(mlp->netdev))
 			break;
 		sdev = mlp->slave;
 	}
@@ -1994,14 +2009,15 @@
 isdn_ppp_hangup_slave(char *name)
 {
 #ifdef CONFIG_ISDN_MPP
-	isdn_net_dev *ndev;
+	isdn_net_dev *idev;
 	isdn_net_local *lp, *mlp = NULL;
 	struct net_device *sdev;
 
-	if (!(ndev = isdn_net_findif(name)))
+	idev = isdn_net_findif(name);
+	if (!idev)
 		return 1;
-	lp = &ndev->local;
-	if (!(lp->flags & ISDN_NET_CONNECTED))
+	lp = &idev->local;
+	if (!isdn_net_bound(idev))
 		return 5;
 
 	sdev = lp->slave;
@@ -2011,9 +2027,9 @@
 		if (mlp->slave) { /* find last connected link in chain */
 			isdn_net_local *nlp = (isdn_net_local *) mlp->slave->priv;
 
-			if (!(nlp->flags & ISDN_NET_CONNECTED))
+			if (!isdn_net_bound(nlp->netdev))
 				break;
-		} else if (mlp->flags & ISDN_NET_CONNECTED)
+		} else if (isdn_net_bound(mlp->netdev))
 			break;
 		
 		sdev = mlp->slave;
@@ -2021,7 +2037,7 @@
 	if (!sdev)
 		return 2;
 
-	isdn_net_hangup(mlp);
+	isdn_net_hangup(mlp->netdev);
 	return 0;
 #else
 	return -1;
@@ -2038,7 +2054,7 @@
 
 static void isdn_ppp_ccp_kickup(struct ippp_struct *is)
 {
-	isdn_ppp_fill_rq(NULL, 0, PPP_COMP, is->lp->ppp_slot);
+	isdn_ppp_fill_rq(NULL, 0, PPP_COMP, is->idev->ppp_slot);
 }
 
 /* In-kernel handling of CCP Reset-Request and Reset-Ack is necessary,
@@ -2084,10 +2100,10 @@
 	unsigned char *p;
 	int hl;
 	int cnt = 0;
-	isdn_net_local *lp = is->lp;
+	isdn_net_dev *idev = is->idev;
 
 	/* Alloc large enough skb */
-	hl = isdn_slot_hdrlen(lp->isdn_slot);
+	hl = isdn_slot_hdrlen(idev->isdn_slot);
 	skb = alloc_skb(len + hl + 16,GFP_ATOMIC);
 	if(!skb) {
 		printk(KERN_WARNING
@@ -2121,9 +2137,9 @@
 
 	/* skb is now ready for xmit */
 	printk(KERN_DEBUG "Sending CCP Frame:\n");
-	isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,lp->ppp_slot);
+	isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,idev->ppp_slot);
 
-	isdn_net_write_super(lp, skb);
+	isdn_net_write_super(&idev->local, skb);
 }
 
 /* Allocate the reset state vector */
@@ -2524,6 +2540,7 @@
 static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
 	 struct sk_buff *skb,int proto)
 {
+	isdn_net_dev *idev = lp->netdev;
 	struct ippp_struct *is;
 	struct ippp_struct *mis;
 	int len;
@@ -2531,17 +2548,17 @@
 	unsigned char rsdata[IPPP_RESET_MAXDATABYTES];	
 
 	printk(KERN_DEBUG "Received CCP frame from peer slot(%d)\n",
-		lp->ppp_slot);
-	if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
-		printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
-		       __FUNCTION__ , lp->ppp_slot);
+	       idev->ppp_slot);
+	if (idev->ppp_slot < 0 || idev->ppp_slot > ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",
+		       __FUNCTION__ , idev->ppp_slot);
 		return;
 	}
-	is = ippp_table[lp->ppp_slot];
-	isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit,lp->ppp_slot);
+	is = ippp_table[idev->ppp_slot];
+	isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit,idev->ppp_slot);
 
 	if(lp->master) {
-		int slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot;
+		int slot = ((isdn_net_local *) (lp->master->priv))->netdev->ppp_slot;
 		if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
 			printk(KERN_ERR "%s: slot(%d) out of range\n",
 			       __FUNCTION__ , slot);
@@ -2700,8 +2717,9 @@
 
 static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb)
 {
+	isdn_net_dev *idev = lp->netdev;
 	struct ippp_struct *mis,*is;
-	int proto, slot = lp->ppp_slot;
+	int proto, slot = idev->ppp_slot;
 	unsigned char *data;
 
 	if(!skb || skb->len < 3)
@@ -2725,10 +2743,10 @@
 		return;
 
 	printk(KERN_DEBUG "Received CCP frame from daemon:\n");
-	isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,lp->ppp_slot);
+	isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,idev->ppp_slot);
 
 	if (lp->master) {
-		slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot;
+		slot = ((isdn_net_local *) (lp->master->priv))->netdev->ppp_slot;
 		if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
 			printk(KERN_ERR "%s: slot(%d) out of range\n",
 			       __FUNCTION__ , slot);
@@ -2893,3 +2911,28 @@
 	}
 	return -EINVAL;
 }
+
+// ISDN_NET_ENCAP_SYNCPPP
+// ======================================================================
+
+static int
+isdn_ppp_header(struct sk_buff *skb, struct net_device *dev,
+		unsigned short type, void *daddr, void *saddr, 
+		unsigned plen)
+{
+	skb_push(skb, IPPP_MAX_HEADER);
+
+	return IPPP_MAX_HEADER;
+}
+
+struct isdn_netif_ops isdn_ppp_ops = {
+	.hard_header         = isdn_ppp_header,
+	.do_ioctl            = isdn_ppp_dev_ioctl,
+	.flags               = IFF_NOARP | IFF_POINTOPOINT,
+	.type                = ARPHRD_PPP,
+	.receive             = isdn_ppp_receive,
+	.connected           = isdn_ppp_wakeup_daemon,
+	.bind                = isdn_ppp_bind,
+	.unbind              = isdn_ppp_free,
+	
+};
diff -Nru a/drivers/isdn/i4l/isdn_ppp.h b/drivers/isdn/i4l/isdn_ppp.h
--- a/drivers/isdn/i4l/isdn_ppp.h	Tue Oct  1 00:08:16 2002
+++ b/drivers/isdn/i4l/isdn_ppp.h	Tue Oct  1 00:08:16 2002
@@ -13,19 +13,26 @@
 #include <linux/isdn_ppp.h>	/* for isdn_ppp info */
 
 extern struct file_operations isdn_ppp_fops;
+extern struct isdn_netif_ops isdn_ppp_ops;
 
 extern int isdn_ppp_init(void);
 extern void isdn_ppp_cleanup(void);
-extern int isdn_ppp_free(isdn_net_local *);
-extern int isdn_ppp_bind(isdn_net_local *);
-extern int isdn_ppp_xmit(struct sk_buff *, struct net_device *);
-extern void isdn_ppp_receive(isdn_net_dev *, isdn_net_local *, struct sk_buff *);
-extern int isdn_ppp_dev_ioctl(struct net_device *, struct ifreq *, int);
 extern int isdn_ppp_dial_slave(char *);
-extern void isdn_ppp_wakeup_daemon(isdn_net_local *);
+extern int isdn_ppp_hangup_slave(char *);
 
-extern int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc);
-extern int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc);
+#ifdef CONFIG_ISDN_PPP
+
+int  isdn_ppp_xmit(struct sk_buff *, struct net_device *);
+
+#else
+
+static inline int
+isdn_ppp_xmit(struct sk_buff *, struct net_device *);
+{
+	return 0;
+}
+
+#endif
 
 #define IPPP_OPEN	0x01
 #define IPPP_CONNECT	0x02
diff -Nru a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
--- a/drivers/macintosh/adb.c	Tue Oct  1 00:08:21 2002
+++ b/drivers/macintosh/adb.c	Tue Oct  1 00:08:21 2002
@@ -233,10 +233,10 @@
 {
 	strcpy(current->comm, "kadbprobe");
 	
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	sigfillset(&current->blocked);
 	flush_signals(current);
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	printk(KERN_INFO "adb: starting probe task...\n");
 	do_adb_reset_bus();
diff -Nru a/drivers/md/md.c b/drivers/md/md.c
--- a/drivers/md/md.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/md/md.c	Tue Oct  1 00:08:16 2002
@@ -1287,8 +1287,6 @@
 	struct list_head *tmp;
 	mdk_rdev_t *rdev;
 	struct gendisk *disk;
-	char *major_name;
-
 
 	if (list_empty(&mddev->disks)) {
 		MD_BUG();
@@ -1395,16 +1393,10 @@
 	if (!disk)
 		return -ENOMEM;
 	memset(disk, 0, sizeof(struct gendisk));
-	major_name = kmalloc(6, GFP_KERNEL);
-	if (!major_name) {
-		kfree(disk);
-		return -ENOMEM;
-	}
 	disk->major = MD_MAJOR;
 	disk->first_minor = mdidx(mddev);
 	disk->minor_shift = 0;
-	sprintf(major_name, "md%d", mdidx(mddev));
-	disk->major_name = major_name;
+	sprintf(disk->disk_name, "md%d", mdidx(mddev));
 	disk->fops = &md_fops;
 
 	mddev->pers = pers[pnum];
@@ -1416,7 +1408,6 @@
 	if (err) {
 		printk(KERN_ERR "md: pers->run() failed ...\n");
 		mddev->pers = NULL;
-		kfree(disk->major_name);
 		kfree(disk);
 		return -EINVAL;
 	}
@@ -1547,7 +1538,6 @@
 
 		if (disk) {
 			del_gendisk(disk);
-			kfree(disk->major_name);
 			kfree(disk);
 		}
 
@@ -2417,9 +2407,9 @@
 
 static inline void flush_curr_signals(void)
 {
-	spin_lock(&current->sigmask_lock);
+	spin_lock(&current->sig->siglock);
 	flush_signals(current);
-	spin_unlock(&current->sigmask_lock);
+	spin_unlock(&current->sig->siglock);
 }
 
 int md_thread(void * arg)
diff -Nru a/drivers/md/raid5.c b/drivers/md/raid5.c
--- a/drivers/md/raid5.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/md/raid5.c	Tue Oct  1 00:08:15 2002
@@ -1181,7 +1181,7 @@
 				PRINTK("for %ld schedule op %ld on disc %d\n", sh->sector, bi->bi_rw, i);
 				atomic_inc(&sh->count);
 				bi->bi_sector = sh->sector;
-				bi->bi_flags = 0;
+				bi->bi_flags = 1 << BIO_UPTODATE;
 				bi->bi_vcnt = 1;	
 				bi->bi_idx = 0;
 				bi->bi_io_vec = &sh->dev[i].vec;
diff -Nru a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
--- a/drivers/media/video/saa5249.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/media/video/saa5249.c	Tue Oct  1 00:08:15 2002
@@ -280,17 +280,17 @@
 {
 	sigset_t oldblocked = current->blocked;
 
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	sigfillset(&current->blocked);
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 	current->state = TASK_INTERRUPTIBLE;
 	schedule_timeout(delay);
 
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	current->blocked = oldblocked;
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 }
 
 
diff -Nru a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c
--- a/drivers/message/i2o/i2o_block.c	Tue Oct  1 00:08:18 2002
+++ b/drivers/message/i2o/i2o_block.c	Tue Oct  1 00:08:18 2002
@@ -187,7 +187,6 @@
 static struct i2ob_device i2ob_dev[MAX_I2OB<<4];
 static int i2ob_dev_count = 0;
 static struct gendisk i2o_disk[MAX_I2OB];
-static char i2o_names[MAX_I2OB * 8];
 
 /*
  * Mutex and spin lock for event handling synchronization
@@ -1254,7 +1253,7 @@
 	}
 
 
-	strcpy(d->dev_name, i2o_disk[unit>>4].major_name);
+	strcpy(d->dev_name, i2o_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);
@@ -1757,8 +1756,7 @@
 		disk->first_minor = i<<4;
 		disk->minor_shift = 4;
 		disk->fops = &i2ob_fops;
-		disk->major_name = i2o_names + i*8;
-		sprintf(disk->major_name, "i2o/hd%c", 'a' + i);
+		sprintf(disk->disk_name, "i2o/hd%c", 'a' + i);
 	}
 	
 	/*
diff -Nru a/drivers/mtd/devices/blkmtd.c b/drivers/mtd/devices/blkmtd.c
--- a/drivers/mtd/devices/blkmtd.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/mtd/devices/blkmtd.c	Tue Oct  1 00:08:15 2002
@@ -304,10 +304,10 @@
   DEBUG(1, "blkmtd: writetask: starting (pid = %d)\n", tsk->pid);
   daemonize();
   strcpy(tsk->comm, "blkmtdd");
-  spin_lock_irq(&tsk->sigmask_lock);
+  spin_lock_irq(&tsk->sig->siglock);
   sigfillset(&tsk->blocked);
   recalc_sigpending();
-  spin_unlock_irq(&tsk->sigmask_lock);
+  spin_unlock_irq(&tsk->sig->siglock);
 
   if(alloc_kiovec(1, &iobuf)) {
     printk("blkmtd: write_queue_task cant allocate kiobuf\n");
diff -Nru a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c
--- a/drivers/mtd/ftl.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/mtd/ftl.c	Tue Oct  1 00:08:16 2002
@@ -1211,7 +1211,6 @@
 {
 	partition_t *partition;
 	struct gendisk *disk;
-	char *name;
 	int device;
 
 	for (device=0; device < MAX_MTD_DEVICES && myparts[device]; device++)
@@ -1225,23 +1224,20 @@
 
 	partition = kmalloc(sizeof(partition_t), GFP_KERNEL);
 	disk = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
-	name = kmalloc(4, GFP_KERNEL);
 		
-	if (!partition||!disk||!name) {
+	if (!partition||!disk) {
 		printk(KERN_WARNING "No memory to scan for FTL on %s\n",
 			mtd->name);
 		kfree(partition);
 		kfree(disk);
-		kfree(name);
 		return;
 	}    
 
 	memset(partition, 0, sizeof(partition_t));
 	memset(disk, 0, sizeof(struct gendisk));
-	sprintf(name, "ftl%c", 'a' + device);
+	sprintf(disk->disk_name, "ftl%c", 'a' + device);
 	disk->major = FTL_MAJOR;
 	disk->first_minor = device << 4;
-	disk->major_name = name;
 	disk->minor_shift = PART_BITS;
 	disk->fops = &ftl_blk_fops;
 	partition->mtd = mtd;
@@ -1260,7 +1256,6 @@
 	} else {
 		kfree(partition);
 		kfree(disk);
-		kfree(name);
 	}
 }
 
@@ -1286,7 +1281,6 @@
 			
 			myparts[i]->state = 0;
 			del_gendisk(myparts[i]->disk);
-			kfree(myparts[i]->disk->major_name);
 			kfree(myparts[i]->disk);
 			kfree(myparts[i]);
 			myparts[i] = NULL;
diff -Nru a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c
--- a/drivers/mtd/mtdblock.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/mtd/mtdblock.c	Tue Oct  1 00:08:16 2002
@@ -43,7 +43,6 @@
 	unsigned int cache_size;
 	enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state;
 	struct gendisk disk;
-	char name[7];
 } *mtdblks[MAX_MTD_DEVICES];
 
 static spinlock_t mtdblks_lock;
@@ -319,8 +318,7 @@
 	mtdblk->disk.first_minor = dev;
 	mtdblk->disk.minor_shift = 0;
 	mtdblk->disk.fops = &mtd_fops;
-	mtdblk->disk.major_name = mtdblk->name;
-	sprintf(mtdblk->name, "mtd%d", dev);
+	sprintf(mtdblk->disk.disk_name, "mtd%d", dev);
 
 	/* OK, we've created a new one. Add it to the list. */
 
@@ -468,10 +466,10 @@
 	/* we might get involved when memory gets low, so use PF_MEMALLOC */
 	tsk->flags |= PF_MEMALLOC;
 	strcpy(tsk->comm, "mtdblockd");
-	spin_lock_irq(&tsk->sigmask_lock);
+	spin_lock_irq(&tsk->sig->siglock);
 	sigfillset(&tsk->blocked);
 	recalc_sigpending();
-	spin_unlock_irq(&tsk->sigmask_lock);
+	spin_unlock_irq(&tsk->sig->siglock);
 	daemonize();
 
 	while (!leaving) {
diff -Nru a/drivers/mtd/mtdblock_ro.c b/drivers/mtd/mtdblock_ro.c
--- a/drivers/mtd/mtdblock_ro.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/mtd/mtdblock_ro.c	Tue Oct  1 00:08:17 2002
@@ -30,7 +30,6 @@
 #endif
 
 static struct gendisk mtd_disks[MAX_MTD_DEVICES];
-static char names names[MAX_MTD_DEVICES][11];
 
 static int mtdblock_open(struct inode *inode, struct file *file)
 {
@@ -233,8 +232,7 @@
 		struct gendisk *disk = mtd_disks + i;
 		disk->major = MAJOR_NR;
 		disk->first_minor = i;
-		sprintf(names[i], "mtdblock%d", i);
-		disk->major_name = names[i];
+		sprintf(disk->disk_name, "mtdblock%d", i);
 		disk->fops = &mtd_fops;
 	}
 	return 0;
diff -Nru a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c
--- a/drivers/mtd/nand/nand_ecc.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/mtd/nand/nand_ecc.c	Tue Oct  1 00:08:16 2002
@@ -209,3 +209,5 @@
 EXPORT_SYMBOL(nand_correct_data);
 
 MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Steven J. Hill <sjhill@cotw.com>");
+MODULE_DESCRIPTION("Generic NAND ECC support");
diff -Nru a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
--- a/drivers/mtd/nftlcore.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/mtd/nftlcore.c	Tue Oct  1 00:08:15 2002
@@ -56,7 +56,6 @@
 	unsigned long temp;
 	int firstfree = -1;
 	struct gendisk *gd;
-	char *name;
 
 	DEBUG(MTD_DEBUG_LEVEL1,"NFTL_setup\n");
 
@@ -76,11 +75,9 @@
 
 	nftl = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
 	gd = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
-	name = kmalloc(6, GFP_KERNEL);
-	if (!nftl || !gd || !name) {
+	if (!nftl || !gd) {
 		kfree(nftl);
 		kfree(gd);
-		kfree(name);
 		printk(KERN_WARNING "Out of memory for NFTL data structures\n");
 		return;
 	}
@@ -96,7 +93,6 @@
 		printk(KERN_WARNING "Could not mount NFTL device\n");
 		kfree(nftl);
 		kfree(gd);
-		kfree(name);
 		return;
         }
 
@@ -134,11 +130,10 @@
 	}
 	NFTLs[firstfree] = nftl;
 	memset(gd, 0, sizeof(struct gendisk));
-	sprintf(name, "nftl%c", 'a' + firstfree);
+	sprintf(gd->disk_name, "nftl%c", 'a' + firstfree);
 	gd->major = MAJOR_NR;
 	gd->first_minor = firstfree << NFTL_PARTN_BITS;
 	gd->minor_shift = NFTL_PARTN_BITS;
-	gd->major_name = name;
 	set_capacity(gd, nftl->nr_sects);
 	nftl->disk = gd;
 	add_disk(gd);
@@ -157,7 +152,6 @@
 	if (nftl->EUNtable)
 		kfree(nftl->EUNtable);
 	del_gendisk(nftl->disk);
-	kfree(nftl->disk->major_name);
 	kfree(nftl->disk);
 	kfree(nftl);
 }
diff -Nru a/drivers/net/3c505.c b/drivers/net/3c505.c
--- a/drivers/net/3c505.c	Tue Oct  1 00:08:21 2002
+++ b/drivers/net/3c505.c	Tue Oct  1 00:08:21 2002
@@ -1396,7 +1396,7 @@
 	int timeout;
 	int addr = dev->base_addr;
 	const char *name = dev->name;
-       unsigned long flags;
+	unsigned long flags;
 	byte orig_HSR;
 
 	if (!request_region(addr, ELP_IO_EXTENT, "3c505"))
diff -Nru a/drivers/net/3c509.c b/drivers/net/3c509.c
--- a/drivers/net/3c509.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/net/3c509.c	Tue Oct  1 00:08:15 2002
@@ -47,8 +47,8 @@
 			- ethtool support
 		v1.18b 1Mar2002 Zwane Mwaikambo <zwane@commfireservices.com>
 			- Power Management support
-                v1.18c 1Mar2002 David Ruggiero <jdr@farfalle.com>
-                        - Full duplex support
+		v1.18c 1Mar2002 David Ruggiero <jdr@farfalle.com>
+			- Full duplex support
 */
 
 #define DRV_NAME	"3c509"
@@ -500,10 +500,10 @@
 	memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr));
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
-        
+
 	if (dev->mem_start & 0x05) { /* xcvr codes 1/3/4/12 */
 		dev->if_port = (dev->mem_start & 0x0f);
-        } else { /* xcvr codes 0/8 */
+	} else { /* xcvr codes 0/8 */
 		/* use eeprom value, but save user's full-duplex selection */
 		dev->if_port = (if_port | (dev->mem_start & 0x08) );
 	}
diff -Nru a/drivers/net/8139cp.c b/drivers/net/8139cp.c
--- a/drivers/net/8139cp.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/net/8139cp.c	Tue Oct  1 00:08:17 2002
@@ -27,8 +27,6 @@
 	TODO, in rough priority order:
 	* Test Tx checksumming thoroughly
 	* dev->tx_timeout
-	* Support forcing media type with a module parameter,
-	  like dl2k.c/sundance.c
 	* Constants (module parms?) for Rx work limit
 	* Complete reset on PciErr
 	* Consider Rx interrupt mitigation using TimerIntr
@@ -49,8 +47,8 @@
  */
 
 #define DRV_NAME		"8139cp"
-#define DRV_VERSION		"0.2.1"
-#define DRV_RELDATE		"Aug 9, 2002"
+#define DRV_VERSION		"0.3.0"
+#define DRV_RELDATE		"Sep 29, 2002"
 
 
 #include <linux/config.h>
@@ -107,6 +105,11 @@
 
 #define PFX			DRV_NAME ": "
 
+#ifndef TRUE
+#define FALSE 0
+#define TRUE (!FALSE)
+#endif
+
 #define CP_DEF_MSG_ENABLE	(NETIF_MSG_DRV		| \
 				 NETIF_MSG_PROBE 	| \
 				 NETIF_MSG_LINK)
@@ -678,7 +681,7 @@
 	if (status & (TxOK | TxErr | TxEmpty | SWInt))
 		cp_tx(cp);
 	if (status & LinkChg)
-		mii_check_media(&cp->mii_if, netif_msg_link(cp));
+		mii_check_media(&cp->mii_if, netif_msg_link(cp), FALSE);
 
 	if (status & PciErr) {
 		u16 pci_status;
@@ -1001,6 +1004,10 @@
 
 	cp->rx_tail = 0;
 	cp->tx_head = cp->tx_tail = 0;
+
+	(void) dev; /* avoid compiler warning when synchronize_irq()
+		     * disappears during !CONFIG_SMP
+		     */
 }
 
 static void cp_reset_hw (struct cp_private *cp)
@@ -1195,7 +1202,7 @@
 		goto err_out_hw;
 
 	netif_carrier_off(dev);
-	mii_check_media(&cp->mii_if, netif_msg_link(cp));
+	mii_check_media(&cp->mii_if, netif_msg_link(cp), TRUE);
 	netif_start_queue(dev);
 
 	return 0;
@@ -1654,33 +1661,18 @@
 static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct cp_private *cp = dev->priv;
-	struct mii_ioctl_data *mii;
-	int rc = 0;
+	struct mii_ioctl_data *mii = (struct mii_ioctl_data *) &rq->ifr_data;
+	int rc;
 
-	mii = (struct mii_ioctl_data *) &rq->ifr_data;
 	if (!netif_running(dev))
 		return -EINVAL;
 
-	if (cmd != SIOCETHTOOL) 
-		mii->reg_num &= 0x1f;
-	
-	switch (cmd) {
-	case SIOCETHTOOL:
+	if (cmd == SIOCETHTOOL)
 		return cp_ethtool_ioctl(cp, (void *) rq->ifr_data);
-		
- 	case SIOCGMIIPHY:	/* Get the address of the PHY in use. */
-		mii->phy_id = CP_INTERNAL_PHY;
-		/* Fall Through */
-
-	case SIOCGMIIREG:	/* Read the specified MII register. */
-		mii->val_out = mdio_read (dev, CP_INTERNAL_PHY, mii->reg_num);
-		break;
-
-	default:
-		rc = -EOPNOTSUPP;
-		break;
-	}
 
+	spin_lock_irq(&cp->lock);
+	rc = generic_mii_ioctl(&cp->mii_if, mii, cmd, NULL);
+	spin_unlock_irq(&cp->lock);
 	return rc;
 }
 
@@ -1818,6 +1810,8 @@
 	cp->mii_if.mdio_read = mdio_read;
 	cp->mii_if.mdio_write = mdio_write;
 	cp->mii_if.phy_id = CP_INTERNAL_PHY;
+	cp->mii_if.phy_id_mask = 0x1f;
+	cp->mii_if.reg_num_mask = 0x1f;
 	cp_set_rxbufsize(cp);
 
 	rc = pci_enable_device(pdev);
diff -Nru a/drivers/net/8139too.c b/drivers/net/8139too.c
--- a/drivers/net/8139too.c	Tue Oct  1 00:08:13 2002
+++ b/drivers/net/8139too.c	Tue Oct  1 00:08:13 2002
@@ -578,7 +578,6 @@
 	signed char phys[4];		/* MII device addresses. */
 	char twistie, twist_row, twist_col;	/* Twister tune state. */
 	unsigned int default_port:4;	/* Last dev->if_port value. */
-	unsigned int medialock:1;	/* Don't sense media type. */
 	spinlock_t lock;
 	chip_t chipset;
 	pid_t thr_pid;
@@ -986,6 +985,8 @@
 	tp->mii.dev = dev;
 	tp->mii.mdio_read = mdio_read;
 	tp->mii.mdio_write = mdio_write;
+	tp->mii.phy_id_mask = 0x3f;
+	tp->mii.reg_num_mask = 0x1f;
 
 	/* dev is fully set up and ready to use now */
 	DPRINTK("about to register device named %s (%p)...\n", dev->name, dev);
@@ -1041,7 +1042,7 @@
 		tp->mii.full_duplex = (option & 0x210) ? 1 : 0;
 		tp->default_port = option & 0xFF;
 		if (tp->default_port)
-			tp->medialock = 1;
+			tp->mii.force_media = 1;
 	}
 	if (board_idx < MAX_UNITS  &&  full_duplex[board_idx] > 0)
 		tp->mii.full_duplex = full_duplex[board_idx];
@@ -1049,7 +1050,7 @@
 		printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);
 		/* Changing the MII-advertised media because might prevent
 		   re-connection. */
-		tp->mii.duplex_lock = 1;
+		tp->mii.force_media = 1;
 	}
 	if (tp->default_port) {
 		printk(KERN_INFO "  Forcing %dMbps %s-duplex operation.\n",
@@ -1306,7 +1307,7 @@
 
 	}
 
-	tp->mii.full_duplex = tp->mii.duplex_lock;
+	tp->mii.full_duplex = tp->mii.force_media;
 	tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000;
 	tp->twistie = (tp->chipset == CH_8139_K) ? 1 : 0;
 	tp->time_to_die = 0;
@@ -1537,7 +1538,7 @@
 
 	mii_lpa = mdio_read (dev, tp->phys[0], MII_LPA);
 
-	if (!tp->mii.duplex_lock && mii_lpa != 0xffff) {
+	if (!tp->mii.force_media && mii_lpa != 0xffff) {
 		int duplex = (mii_lpa & LPA_100FULL)
 		    || (mii_lpa & 0x01C0) == 0x0040;
 		if (tp->mii.full_duplex != duplex) {
@@ -1583,10 +1584,10 @@
 	unsigned long timeout;
 
 	daemonize();
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	sigemptyset(&current->blocked);
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	strncpy (current->comm, dev->name, sizeof(current->comm) - 1);
 	current->comm[sizeof(current->comm) - 1] = '\0';
@@ -1598,9 +1599,9 @@
 		} while (!signal_pending (current) && (timeout > 0));
 
 		if (signal_pending (current)) {
-			spin_lock_irq(&current->sigmask_lock);
+			spin_lock_irq(&current->sig->siglock);
 			flush_signals(current);
-			spin_unlock_irq(&current->sigmask_lock);
+			spin_unlock_irq(&current->sig->siglock);
 		}
 
 		if (tp->time_to_die)
@@ -1995,7 +1996,7 @@
 		/* Really link-change on new chips. */
 		int lpar = RTL_R16 (NWayLPAR);
 		int duplex = (lpar & LPA_100FULL) || (lpar & 0x01C0) == 0x0040
-				|| tp->mii.duplex_lock;
+				|| tp->mii.force_media;
 		if (tp->mii.full_duplex != duplex) {
 			tp->mii.full_duplex = duplex;
 #if 0
@@ -2439,58 +2440,22 @@
 }
 
 
-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)
 {
-	struct rtl8139_private *tp = dev->priv;
-	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data;
-	int rc = 0;
-	int phy = tp->phys[0] & 0x3f;
+	struct rtl8139_private *np = dev->priv;
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
+	int rc;
 
 	if (!netif_running(dev))
 		return -EINVAL;
 
-	if (cmd != SIOCETHTOOL) {
-		/* With SIOCETHTOOL, this would corrupt the pointer.  */
-		data->phy_id &= 0x3f;
-		data->reg_num &= 0x1f;
-	}
-
-	switch (cmd) {
-	case SIOCETHTOOL:
-		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-
-	case SIOCGMIIPHY:	/* Get the address of the PHY in use. */
-		data->phy_id = phy;
-		/* Fall Through */
-
-	case SIOCGMIIREG:	/* Read the specified MII register. */
-		data->val_out = mdio_read (dev, data->phy_id, data->reg_num);
-		break;
-
-	case SIOCSMIIREG:	/* Write the specified MII register */
-		if (!capable (CAP_NET_ADMIN)) {
-			rc = -EPERM;
-			break;
-		}
-
-		if (data->phy_id == phy) {
-			u16 value = data->val_in;
-			switch (data->reg_num) {
-			case 0:
-				/* Check for autonegotiation on or reset. */
-				tp->medialock = (value & 0x9000) ? 0 : 1;
-				if (tp->medialock)
-					tp->mii.full_duplex = (value & 0x0100) ? 1 : 0;
-				break;
-			case 4: tp->mii.advertising = value; break;
-			}
-		}
-		mdio_write(dev, data->phy_id, data->reg_num, data->val_in);
-		break;
+	if (cmd == SIOCETHTOOL)
+		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
 
-	default:
-		rc = -EOPNOTSUPP;
-		break;
+	else {
+		spin_lock_irq(&np->lock);
+		rc = generic_mii_ioctl(&np->mii, data, cmd, NULL);
+		spin_unlock_irq(&np->lock);
 	}
 
 	return rc;
diff -Nru a/drivers/net/Makefile b/drivers/net/Makefile
--- a/drivers/net/Makefile	Tue Oct  1 00:08:16 2002
+++ b/drivers/net/Makefile	Tue Oct  1 00:08:16 2002
@@ -57,7 +57,7 @@
 obj-$(CONFIG_SK98LIN) += sk98lin/
 obj-$(CONFIG_SKFP) += skfp/
 obj-$(CONFIG_VIA_RHINE) += via-rhine.o mii.o
-obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o
+obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o mii.o
 
 #
 # end link order section
@@ -71,7 +71,7 @@
 
 obj-$(CONFIG_WINBOND_840) += mii.o
 obj-$(CONFIG_SUNDANCE) += sundance.o mii.o
-obj-$(CONFIG_HAMACHI) += hamachi.o
+obj-$(CONFIG_HAMACHI) += hamachi.o mii.o
 obj-$(CONFIG_NET) += Space.o setup.o net_init.o loopback.o
 obj-$(CONFIG_SEEQ8005) += seeq8005.o
 obj-$(CONFIG_ETHERTAP) += ethertap.o
@@ -194,5 +194,3 @@
 
 include $(TOPDIR)/Rules.make
 
-clean:
-	rm -f core *.o *.a *.s
diff -Nru a/drivers/net/acenic.h b/drivers/net/acenic.h
--- a/drivers/net/acenic.h	Tue Oct  1 00:08:17 2002
+++ b/drivers/net/acenic.h	Tue Oct  1 00:08:17 2002
@@ -770,7 +770,7 @@
 	if (ACE_IS_TIGON_I(ap))
 		writel(0, &regs->MaskInt);
 	else
-		writel(readl(&regs->HostCtrl) &= ~MASK_INTS, &regs->HostCtrl);
+		writel(readl(&regs->HostCtrl) & ~MASK_INTS, &regs->HostCtrl);
 }
 
 
diff -Nru a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c
--- a/drivers/net/arcnet/arcnet.c	Tue Oct  1 00:08:18 2002
+++ b/drivers/net/arcnet/arcnet.c	Tue Oct  1 00:08:18 2002
@@ -186,7 +186,7 @@
 void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc)
 {
 	int i;
-       unsigned long flags;
+	unsigned long flags;
 
 	save_flags(flags);
 	cli();
@@ -212,7 +212,7 @@
 {
 	struct arcnet_local *lp = (struct arcnet_local *) dev->priv;
 	int i, length;
-       unsigned long flags;
+	unsigned long flags;
 	static uint8_t buf[512];
 
 	save_flags(flags);
diff -Nru a/drivers/net/at1700.c b/drivers/net/at1700.c
--- a/drivers/net/at1700.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/net/at1700.c	Tue Oct  1 00:08:16 2002
@@ -808,7 +808,7 @@
 	int ioaddr = dev->base_addr;
 	struct net_local *lp = (struct net_local *)dev->priv;
 	unsigned char mc_filter[8];		 /* Multicast hash filter */
-       unsigned long flags;
+	unsigned long flags;
 	int i;
 
 	if (dev->flags & IFF_PROMISC) {
diff -Nru a/drivers/net/eepro100.c b/drivers/net/eepro100.c
--- a/drivers/net/eepro100.c	Tue Oct  1 00:08:18 2002
+++ b/drivers/net/eepro100.c	Tue Oct  1 00:08:18 2002
@@ -1210,9 +1210,6 @@
 	/* We must continue to monitor the media. */
 	sp->timer.expires = RUN_AT(2*HZ); 			/* 2.0 sec. */
 	add_timer(&sp->timer);
-#if defined(timer_exit)
-	timer_exit(&sp->timer);
-#endif
 }
 
 static void speedo_show_state(struct net_device *dev)
diff -Nru a/drivers/net/epic100.c b/drivers/net/epic100.c
--- a/drivers/net/epic100.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/net/epic100.c	Tue Oct  1 00:08:17 2002
@@ -429,6 +429,8 @@
 	ep->mii.dev = dev;
 	ep->mii.mdio_read = mdio_read;
 	ep->mii.mdio_write = mdio_write;
+	ep->mii.phy_id_mask = 0x1f;
+	ep->mii.reg_num_mask = 0x1f;
 
 	ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma);
 	if (!ring_space)
@@ -523,7 +525,7 @@
 
 	/* The lower four bits are the media type. */
 	if (duplex) {
-		ep->mii.duplex_lock = ep->mii.full_duplex = 1;
+		ep->mii.force_media = ep->mii.full_duplex = 1;
 		printk(KERN_INFO DRV_NAME "(%s):  Forced full duplex operation requested.\n",
 		       pdev->slot_name);
 	}
@@ -854,7 +856,7 @@
 	int negotiated = mii_lpa & ep->mii.advertising;
 	int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
 
-	if (ep->mii.duplex_lock)
+	if (ep->mii.force_media)
 		return;
 	if (mii_lpa == 0xffff)		/* Bogus read */
 		return;
@@ -1426,63 +1428,34 @@
 
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	struct epic_private *ep = dev->priv;
+	struct epic_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data;
+	int rc;
 
-	switch(cmd) {
-	case SIOCETHTOOL:
-		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-
-	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
-		data->phy_id = ep->phys[0] & 0x1f;
-		/* Fall Through */
-
-	case SIOCGMIIREG:		/* Read MII PHY register. */
-		if (! netif_running(dev)) {
-			outl(0x0200, ioaddr + GENCTL);
-			outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
-		}
-		data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
-#if 0					/* Just leave on if the ioctl() is ever used. */
-		if (! netif_running(dev)) {
-			outl(0x0008, ioaddr + GENCTL);
-			outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);
-		}
-#endif
-		return 0;
+	/* power-up, if interface is down */
+	if (! netif_running(dev)) {
+		outl(0x0200, ioaddr + GENCTL);
+		outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
+	}
 
-	case SIOCSMIIREG:		/* Write MII PHY register. */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		if (! netif_running(dev)) {
-			outl(0x0200, ioaddr + GENCTL);
-			outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
-		}
-		if (data->phy_id == ep->phys[0]) {
-			u16 value = data->val_in;
-			switch (data->reg_num) {
-			case 0:
-				/* Check for autonegotiation on or reset. */
-				ep->mii.duplex_lock = (value & 0x9000) ? 0 : 1;
-				if (ep->mii.duplex_lock)
-					ep->mii.full_duplex = (value & 0x0100) ? 1 : 0;
-				break;
-			case 4: ep->mii.advertising = value; break;
-			}
-			/* Perhaps check_duplex(dev), depending on chip semantics. */
-		}
-		mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
-#if 0					/* Leave on if the ioctl() is used. */
-		if (! netif_running(dev)) {
-			outl(0x0008, ioaddr + GENCTL);
-			outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);
-		}
-#endif
-		return 0;
-	default:
-		return -EOPNOTSUPP;
+	/* ethtool commands */
+	if (cmd == SIOCETHTOOL)
+		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+
+	/* all other ioctls (the SIOC[GS]MIIxxx ioctls) */
+	else {
+		spin_lock_irq(&np->lock);
+		rc = generic_mii_ioctl(&np->mii, data, cmd, NULL);
+		spin_unlock_irq(&np->lock);
+	}
+
+	/* power-down, if interface is down */
+	if (! netif_running(dev)) {
+		outl(0x0008, ioaddr + GENCTL);
+		outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);
 	}
+	return rc;
 }
 
 
diff -Nru a/drivers/net/ethertap.c b/drivers/net/ethertap.c
--- a/drivers/net/ethertap.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/net/ethertap.c	Tue Oct  1 00:08:16 2002
@@ -340,10 +340,8 @@
 
 static struct net_device dev_ethertap =
 {
-	" ",
-	0, 0, 0, 0,
-	1, 5,
-	0, 0, 0, NULL, ethertap_probe
+	.name		=	" ",
+	.init		=	 ethertap_probe
 };
 
 int init_module(void)
diff -Nru a/drivers/net/fealnx.c b/drivers/net/fealnx.c
--- a/drivers/net/fealnx.c	Tue Oct  1 00:08:18 2002
+++ b/drivers/net/fealnx.c	Tue Oct  1 00:08:18 2002
@@ -559,6 +559,8 @@
 	np->mii.dev = dev;
 	np->mii.mdio_read = mdio_read;
 	np->mii.mdio_write = mdio_write;
+	np->mii.phy_id_mask = 0x1f;
+	np->mii.reg_num_mask = 0x1f;
 
 	ring_space = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma);
 	if (!ring_space) {
@@ -654,7 +656,7 @@
 			mdio_write(dev, np->phys[0], MII_ADVERTISE, ADVERTISE_FULL);
 		else
 			writel(ADVERTISE_FULL, dev->base_addr + ANARANLPAR);
-		np->mii.duplex_lock = 1;
+		np->mii.force_media = 1;
 	}
 
 	/* The chip-specific entries in the device structure. */
@@ -956,7 +958,7 @@
 // 89/9/1 modify,
 //   np->crvalue = 0x00e40001;    /* tx store and forward, tx/rx enable */
 	np->crvalue |= 0x00e40001;	/* tx store and forward, tx/rx enable */
-	np->mii.full_duplex = np->mii.duplex_lock;
+	np->mii.full_duplex = np->mii.force_media;
 	getlinkstatus(dev);
 	if (np->linkok)
 		getlinktype(dev);
@@ -1833,28 +1835,23 @@
 
 static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
+	struct netdev_private *np = dev->priv;
 	struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
+	int rc;
 
-	switch (cmd) {
-	case SIOCETHTOOL:
-		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-
-	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
-		data->phy_id = ((struct netdev_private *) dev->priv)->phys[0] & 0x1f;
-		/* Fall Through */
+	if (!netif_running(dev))
+		return -EINVAL;
 
-	case SIOCGMIIREG:		/* Read MII PHY register. */
-		data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
-		return 0;
+	if (cmd == SIOCETHTOOL)
+		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
 
-	case SIOCSMIIREG:		/* Write MII PHY register. */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
-		return 0;
-	default:
-		return -EOPNOTSUPP;
+	else {
+		spin_lock_irq(&np->lock);
+		rc = generic_mii_ioctl(&np->mii, data, cmd, NULL);
+		spin_unlock_irq(&np->lock);
 	}
+
+	return rc;
 }
 
 
diff -Nru a/drivers/net/hamachi.c b/drivers/net/hamachi.c
--- a/drivers/net/hamachi.c	Tue Oct  1 00:08:21 2002
+++ b/drivers/net/hamachi.c	Tue Oct  1 00:08:21 2002
@@ -505,13 +505,11 @@
 	unsigned int cur_tx, dirty_tx;
 	unsigned int rx_buf_sz;			/* Based on MTU+slack. */
 	unsigned int tx_full:1;			/* The Tx queue is full. */
-	unsigned int full_duplex:1;		/* Full-duplex operation requested. */
 	unsigned int duplex_lock:1;
-	unsigned int medialock:1;		/* Do not sense media. */
 	unsigned int default_port:4;		/* Last dev->if_port value. */
 	/* MII transceiver section. */
 	int mii_cnt;								/* MII device addresses. */
-	u16 advertising;							/* NWay media advertisement */
+	struct mii_if_info mii_if;		/* MII lib hooks/info */
 	unsigned char phys[MII_CNT];		/* MII device addresses, only first one used. */
 	u32 rx_int_var, tx_int_var;	/* interrupt control variables */
 	u32 option;							/* Hold on to a copy of the options */
@@ -554,8 +552,8 @@
 MODULE_PARM_DESC(force32, "GNIC-II: Bit 0: 32 bit PCI, bit 1: disable parity, bit 2: 64 bit PCI (all boards)");
                                                                         
 static int read_eeprom(long ioaddr, int location);
-static int mdio_read(long ioaddr, int phy_id, int location);
-static void mdio_write(long ioaddr, int phy_id, int location, int value);
+static int mdio_read(struct net_device *dev, int phy_id, int location);
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
 static int hamachi_open(struct net_device *dev);
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static void hamachi_timer(unsigned long data);
@@ -637,6 +635,12 @@
 	hmp = dev->priv;
 	spin_lock_init(&hmp->lock);
 
+	hmp->mii_if.dev = dev;
+	hmp->mii_if.mdio_read = mdio_read;
+	hmp->mii_if.mdio_write = mdio_write;
+	hmp->mii_if.phy_id_mask = 0x1f;
+	hmp->mii_if.reg_num_mask = 0x1f;
+
 	ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma);
 	if (!ring_space)
 		goto err_out_cleardev;
@@ -685,18 +689,18 @@
 	if (option > 0) {
 		hmp->option = option;
 		if (option & 0x200)
-			hmp->full_duplex = 1;
+			hmp->mii_if.full_duplex = 1;
 		else if (option & 0x080)
-			hmp->full_duplex = 0;
+			hmp->mii_if.full_duplex = 0;
 		hmp->default_port = option & 15;
 		if (hmp->default_port)
-			hmp->medialock = 1;
+			hmp->mii_if.force_media = 1;
 	}
 	if (card_idx < MAX_UNITS  &&  full_duplex[card_idx] > 0)
-		hmp->full_duplex = 1;
+		hmp->mii_if.full_duplex = 1;
 
 	/* lock the duplex mode if someone specified a value */
-	if (hmp->full_duplex || (option & 0x080))
+	if (hmp->mii_if.full_duplex || (option & 0x080))
 		hmp->duplex_lock = 1;
 
 	/* Set interrupt tuning parameters */
@@ -749,17 +753,21 @@
 	if (chip_tbl[hmp->chip_id].flags & CanHaveMII) {
 		int phy, phy_idx = 0;
 		for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) {
-			int mii_status = mdio_read(ioaddr, phy, 1);
+			int mii_status = mdio_read(dev, phy, MII_BMSR);
 			if (mii_status != 0xffff  &&
 				mii_status != 0x0000) {
 				hmp->phys[phy_idx++] = phy;
-				hmp->advertising = mdio_read(ioaddr, phy, 4);
+				hmp->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE);
 				printk(KERN_INFO "%s: MII PHY found at address %d, status "
 					   "0x%4.4x advertising %4.4x.\n",
-					   dev->name, phy, mii_status, hmp->advertising);
+					   dev->name, phy, mii_status, hmp->mii_if.advertising);
 			}
 		}
 		hmp->mii_cnt = phy_idx;
+		if (hmp->mii_cnt > 0)
+			hmp->mii_if.phy_id = hmp->phys[0];
+		else
+			memset(&hmp->mii_if, 0, sizeof(hmp->mii_if));
 	}
 	/* Configure gigabit autonegotiation. */
 	writew(0x0400, ioaddr + ANXchngCtrl);	/* Enable legacy links. */
@@ -805,8 +813,9 @@
    These routines assume the MDIO controller is idle, and do not exit until
    the command is finished. */
 
-static int mdio_read(long ioaddr, int phy_id, int location)
+static int mdio_read(struct net_device *dev, int phy_id, int location)
 {
+	long ioaddr = dev->base_addr;
 	int i;
 
 	/* We should check busy first - per docs -KDU */
@@ -821,8 +830,9 @@
 	return readw(ioaddr + MII_Rd_Data);
 }
 
-static void mdio_write(long ioaddr, int phy_id, int location, int value)
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
 {
+	long ioaddr = dev->base_addr;
 	int i;
 
 	/* We should check busy first - per docs -KDU */
@@ -912,7 +922,7 @@
 	/* Setting the Rx mode will start the Rx process. */
 	/* If someone didn't choose a duplex, default to full-duplex */ 
 	if (hmp->duplex_lock != 1)
-		hmp->full_duplex = 1;
+		hmp->mii_if.full_duplex = 1;
 
 	/* always 1, takes no more time to do it */
 	writew(0x0001, ioaddr + RxChecksum);
@@ -1909,7 +1919,7 @@
 
 static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
 {
-	struct hamachi_private *hmp = dev->priv;
+	struct hamachi_private *np = dev->priv;
 	u32 ethcmd;
 		
 	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
@@ -1920,12 +1930,53 @@
 		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
 		strcpy(info.driver, DRV_NAME);
 		strcpy(info.version, DRV_VERSION);
-		strcpy(info.bus_info, hmp->pci_dev->slot_name);
+		strcpy(info.bus_info, np->pci_dev->slot_name);
 		if (copy_to_user(useraddr, &info, sizeof(info)))
 			return -EFAULT;
 		return 0;
 	}
 
+	/* get settings */
+	case ETHTOOL_GSET: {
+		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+		if (!(chip_tbl[np->chip_id].flags & CanHaveMII))
+			return -EINVAL;
+		spin_lock_irq(&np->lock);
+		mii_ethtool_gset(&np->mii_if, &ecmd);
+		spin_unlock_irq(&np->lock);
+		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set settings */
+	case ETHTOOL_SSET: {
+		int r;
+		struct ethtool_cmd ecmd;
+		if (!(chip_tbl[np->chip_id].flags & CanHaveMII))
+			return -EINVAL;
+		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+			return -EFAULT;
+		spin_lock_irq(&np->lock);
+		r = mii_ethtool_sset(&np->mii_if, &ecmd);
+		spin_unlock_irq(&np->lock);
+		return r;
+	}
+	/* restart autonegotiation */
+	case ETHTOOL_NWAY_RST: {
+		if (!(chip_tbl[np->chip_id].flags & CanHaveMII))
+			return -EINVAL;
+		return mii_nway_restart(&np->mii_if);
+	}
+	/* get link status */
+	case ETHTOOL_GLINK: {
+		struct ethtool_value edata = {ETHTOOL_GLINK};
+		if (!(chip_tbl[np->chip_id].flags & CanHaveMII))
+			return -EINVAL;
+		edata.data = mii_link_ok(&np->mii_if);
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
         }
 	
 	return -EOPNOTSUPP;
@@ -1933,29 +1984,17 @@
 
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	long ioaddr = dev->base_addr;
-	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data;
+	struct hamachi_private *np = dev->priv;
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
+	int rc;
 
-	switch(cmd) {
-	case SIOCETHTOOL:
-		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
-		data->phy_id = ((struct hamachi_private *)dev->priv)->phys[0] & 0x1f;
-		/* Fall Through */
+	if (!netif_running(dev))
+		return -EINVAL;
 
-	case SIOCGMIIREG:		/* Read MII PHY register. */
-		data->val_out = mdio_read(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f);
-		return 0;
+	if (cmd == SIOCETHTOOL)
+		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
 
-	case SIOCSMIIREG:		/* Write MII PHY register. */
-		/* TODO: Check the sequencing of this.  Might need to stop and
-		 * restart Rx and Tx engines. -KDU
-		 */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		mdio_write(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
-		return 0;
-	case SIOCDEVPRIVATE+3: { /* set rx,tx intr params */
+	else if (cmd == (SIOCDEVPRIVATE+3)) { /* set rx,tx intr params */
 		u32 *d = (u32 *)&rq->ifr_data;
 		/* Should add this check here or an ordinary user can do nasty
 		 * things. -KDU
@@ -1969,11 +2008,16 @@
 		printk(KERN_NOTICE "%s: tx %08x, rx %08x intr\n", dev->name,
 		  (u32) readl(dev->base_addr + TxIntrCtrl),
 		  (u32) readl(dev->base_addr + RxIntrCtrl));
-		return 0;
-	    }
-	default:
-		return -EOPNOTSUPP;
+		rc = 0;
+	}
+
+	else {
+		spin_lock_irq(&np->lock);
+		rc = generic_mii_ioctl(&np->mii_if, data, cmd, NULL);
+		spin_unlock_irq(&np->lock);
 	}
+
+	return rc;
 }
 
 
diff -Nru a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
--- a/drivers/net/hamradio/scc.c	Tue Oct  1 00:08:19 2002
+++ b/drivers/net/hamradio/scc.c	Tue Oct  1 00:08:19 2002
@@ -2129,7 +2129,7 @@
 
 static void __exit scc_cleanup_driver(void)
 {
-       unsigned long flags;
+	unsigned long flags;
 	io_port ctrl;
 	int k;
 	struct scc_channel *scc;
diff -Nru a/drivers/net/mii.c b/drivers/net/mii.c
--- a/drivers/net/mii.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/net/mii.c	Tue Oct  1 00:08:16 2002
@@ -3,7 +3,27 @@
 	mii.c: MII interface library
 
 	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
-	Copyright 2001 Jeff Garzik
+	Copyright 2001,2002 Jeff Garzik
+
+	Various code came from myson803.c and other files by
+	Donald Becker.  Copyright:
+
+		Written 1998-2002 by Donald Becker.
+
+		This software may be used and distributed according
+		to the terms of the GNU General Public License (GPL),
+		incorporated herein by reference.  Drivers based on
+		or derived from this code fall under the GPL and must
+		retain the authorship, copyright and license notice.
+		This file is not a complete program and may only be
+		used when the entire operating system is licensed
+		under the GPL.
+
+		The author may be reached as becker@scyld.com, or C/O
+		Scyld Computing Corporation
+		410 Severn Ave., Suite 210
+		Annapolis MD 21403
+
 
  */
 
@@ -122,7 +142,7 @@
 		bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
 		mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
 
-		mii->duplex_lock = 0;
+		mii->force_media = 0;
 	} else {
 		u32 bmcr, tmp;
 
@@ -130,16 +150,16 @@
 		bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
 		tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX);
 		if (ecmd->speed == SPEED_100)
-			bmcr |= BMCR_SPEED100;
+			tmp |= BMCR_SPEED100;
 		if (ecmd->duplex == DUPLEX_FULL) {
-			bmcr |= BMCR_FULLDPLX;
+			tmp |= BMCR_FULLDPLX;
 			mii->full_duplex = 1;
 		} else
 			mii->full_duplex = 0;
 		if (bmcr != tmp)
-			mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
+			mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp);
 
-		mii->duplex_lock = 1;
+		mii->force_media = 1;
 	}
 	return 0;
 }
@@ -178,13 +198,15 @@
 		netif_carrier_off(mii->dev);
 }
 
-unsigned int mii_check_media (struct mii_if_info *mii, unsigned int ok_to_print)
+unsigned int mii_check_media (struct mii_if_info *mii,
+			      unsigned int ok_to_print,
+			      unsigned int init_media)
 {
 	unsigned int old_carrier, new_carrier;
 	int advertise, lpa, media, duplex;
 
 	/* if forced media, go no further */
-	if (mii->duplex_lock)
+	if (mii->force_media)
 		return 0; /* duplex did not change */
 
 	/* check current and old link status */
@@ -194,7 +216,7 @@
 	/* if carrier state did not change, this is a "bounce",
 	 * just exit as everything is already set correctly
 	 */
-	if (old_carrier == new_carrier)
+	if ((!init_media) && (old_carrier == new_carrier))
 		return 0; /* duplex did not change */
 
 	/* no carrier, nothing much to do */
@@ -211,7 +233,7 @@
 	netif_carrier_on(mii->dev);
 
 	/* get MII advertise and LPA values */
-	if (mii->advertising)
+	if ((!init_media) && (mii->advertising))
 		advertise = mii->advertising;
 	else {
 		advertise = mii->mdio_read(mii->dev, mii->phy_id, MII_ADVERTISE);
@@ -231,7 +253,7 @@
 		       duplex ? "full" : "half",
 		       lpa);
 
-	if (mii->full_duplex != duplex) {
+	if ((init_media) || (mii->full_duplex != duplex)) {
 		mii->full_duplex = duplex;
 		return 1; /* duplex changed */
 	}
@@ -239,6 +261,78 @@
 	return 0; /* duplex did not change */
 }
 
+int generic_mii_ioctl(struct mii_if_info *mii_if,
+		      struct mii_ioctl_data *mii_data, int cmd,
+		      unsigned int *duplex_chg_out)
+{
+	int rc = 0;
+	unsigned int duplex_changed = 0;
+
+	if (duplex_chg_out)
+		*duplex_chg_out = 0;
+
+	mii_data->phy_id &= mii_if->phy_id_mask;
+	mii_data->reg_num &= mii_if->reg_num_mask;
+
+	switch(cmd) {
+	case SIOCGMIIPHY:
+		mii_data->phy_id = mii_if->phy_id;
+		/* fall through */
+
+	case SIOCGMIIREG:
+		mii_data->val_out =
+			mii_if->mdio_read(mii_if->dev, mii_data->phy_id,
+					  mii_data->reg_num);
+		break;
+
+	case SIOCSMIIREG: {
+		u16 val = mii_data->val_in;
+
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		if (mii_data->phy_id == mii_if->phy_id) {
+			switch(mii_data->reg_num) {
+			case MII_BMCR: {
+				unsigned int new_duplex = 0;
+				if (val & (BMCR_RESET|BMCR_ANENABLE))
+					mii_if->force_media = 1;
+				else
+					mii_if->force_media = 0;
+				if (mii_if->force_media &&
+				    (val & BMCR_FULLDPLX))
+					new_duplex = 1;
+				if (mii_if->full_duplex != new_duplex) {
+					duplex_changed = 1;
+					mii_if->full_duplex = new_duplex;
+				}
+				break;
+			}
+			case MII_ADVERTISE:
+				mii_if->advertising = val;
+				break;
+			default:
+				/* do nothing */
+				break;
+			}
+		}
+
+		mii_if->mdio_write(mii_if->dev, mii_data->phy_id,
+				   mii_data->reg_num, val);
+		break;
+	}
+
+	default:
+		rc = -EOPNOTSUPP;
+		break;
+	}
+
+	if ((rc == 0) && (duplex_chg_out) && (duplex_changed))
+		*duplex_chg_out = 1;
+
+	return rc;
+}
+
 MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>");
 MODULE_DESCRIPTION ("MII hardware support library");
 MODULE_LICENSE("GPL");
@@ -249,4 +343,5 @@
 EXPORT_SYMBOL(mii_ethtool_sset);
 EXPORT_SYMBOL(mii_check_link);
 EXPORT_SYMBOL(mii_check_media);
+EXPORT_SYMBOL(generic_mii_ioctl);
 
diff -Nru a/drivers/net/ni65.c b/drivers/net/ni65.c
--- a/drivers/net/ni65.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/net/ni65.c	Tue Oct  1 00:08:16 2002
@@ -1108,7 +1108,7 @@
 	{
 		short len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 		struct tmd *tmdp;
-               unsigned long flags;
+		unsigned long flags;
 
 #ifdef XMT_VIA_SKB
 		if( (unsigned long) (skb->data + skb->len) > 0x1000000) {
diff -Nru a/drivers/net/pcmcia/aironet4500_cs.c b/drivers/net/pcmcia/aironet4500_cs.c
--- a/drivers/net/pcmcia/aironet4500_cs.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/net/pcmcia/aironet4500_cs.c	Tue Oct  1 00:08:15 2002
@@ -347,7 +347,7 @@
 static void awc_detach(dev_link_t *link)
 {
 	dev_link_t **linkp;
-       unsigned long flags;
+	unsigned long flags;
 	int i=0;
 
 	DEBUG(0, "awc_detach(0x%p)\n", link);
diff -Nru a/drivers/net/sis900.c b/drivers/net/sis900.c
--- a/drivers/net/sis900.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/net/sis900.c	Tue Oct  1 00:08:17 2002
@@ -1,6 +1,6 @@
 /* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux.
    Copyright 1999 Silicon Integrated System Corporation 
-   Revision:	1.08.04	Apr. 25 2002
+   Revision:	1.08.06 Sep. 24 2002
    
    Modified from the driver which is originally written by Donald Becker.
    
@@ -18,6 +18,8 @@
    preliminary Rev. 1.0 Jan. 18, 1998
    http://www.sis.com.tw/support/databook.htm
 
+   Rev 1.08.06 Sep. 24 2002 Mufasa Yang bug fix for Tx timeout & add SiS963 support
+   Rev 1.08.05 Jun. 6 2002 Mufasa Yang bug fix for read_eeprom & Tx descriptor over-boundary 
    Rev 1.08.04 Apr. 25 2002 Mufasa Yang <mufasa@sis.com.tw> added SiS962 support
    Rev 1.08.03 Feb. 1 2002 Matt Domsch <Matt_Domsch@dell.com> update to use library crc32 function
    Rev 1.08.02 Nov. 30 2001 Hui-Fen Hsu workaround for EDB & bug fix for dhcp problem
@@ -72,7 +74,7 @@
 #include "sis900.h"
 
 #define SIS900_MODULE_NAME "sis900"
-#define SIS900_DRV_VERSION "v1.08.04 4/25/2002"
+#define SIS900_DRV_VERSION "v1.08.06 9/24/2002"
 
 static char version[] __devinitdata =
 KERN_INFO "sis900.c: " SIS900_DRV_VERSION "\n";
@@ -309,31 +311,38 @@
 }
 
 /**
- *	sis962_get_mac_addr: - Get MAC address for SiS962 model
+ *	sis96x_get_mac_addr: - Get MAC address for SiS962 or SiS963 model
  *	@pci_dev: the sis900 pci device
  *	@net_dev: the net device to get address for 
  *
- *	SiS962 model, use EEPROM to store MAC address. And EEPROM is shared by
+ *	SiS962 or SiS963 model, use EEPROM to store MAC address. And EEPROM 
+ *	is shared by
  *	LAN and 1394. When access EEPROM, send EEREQ signal to hardware first 
  *	and wait for EEGNT. If EEGNT is ON, EEPROM is permitted to be access 
  *	by LAN, otherwise is not. After MAC address is read from EEPROM, send
  *	EEDONE signal to refuse EEPROM access by LAN. 
+ *	The EEPROM map of SiS962 or SiS963 is different to SiS900. 
+ *	The signature field in SiS962 or SiS963 spec is meaningless. 
  *	MAC address is read into @net_dev->dev_addr.
  */
 
-static int __devinit sis962_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev)
+static int __devinit sis96x_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev)
 {
 	long ioaddr = net_dev->base_addr;
 	long ee_addr = ioaddr + mear;
 	u32 waittime = 0;
-	int ret = 0;
+	int i;
 	
 	outl(EEREQ, ee_addr);
 	while(waittime < 2000) {
 		if(inl(ee_addr) & EEGNT) {
-			ret = sis900_get_mac_addr(pci_dev, net_dev);
+
+			/* get MAC address from EEPROM */
+			for (i = 0; i < 3; i++)
+			        ((u16 *)(net_dev->dev_addr))[i] = read_eeprom(ioaddr, i+EEPROMMACAddr);
+
 			outl(EEDONE, ee_addr);
-			return(ret);
+			return 1;
 		} else {
 			udelay(1);	
 			waittime ++;
@@ -443,8 +452,8 @@
 		ret = sis630e_get_mac_addr(pci_dev, net_dev);
 	else if ((revision > 0x81) && (revision <= 0x90) )
 		ret = sis635_get_mac_addr(pci_dev, net_dev);
-	else if (revision == SIS962_900_REV)
-		ret = sis962_get_mac_addr(pci_dev, net_dev);
+	else if (revision == SIS96x_900_REV)
+		ret = sis96x_get_mac_addr(pci_dev, net_dev);
 	else
 		ret = sis900_get_mac_addr(pci_dev, net_dev);
 
@@ -702,7 +711,7 @@
 
 	outl(0, ee_addr);
 	eeprom_delay();
-	outl(EECLK, ee_addr);
+	outl(EECS, ee_addr);
 	eeprom_delay();
 
 	/* Shift the read command (9) bits out. */
@@ -713,7 +722,7 @@
 		outl(dataval | EECLK, ee_addr);
 		eeprom_delay();
 	}
-	outb(EECS, ee_addr);
+	outl(EECS, ee_addr);
 	eeprom_delay();
 
 	/* read the 16-bits data in */
@@ -729,7 +738,6 @@
 	/* Terminate the EEPROM access. */
 	outl(0, ee_addr);
 	eeprom_delay();
-	outl(EECLK, ee_addr);
 
 	return (retval);
 }
@@ -1432,8 +1440,8 @@
 
 	net_dev->trans_start = jiffies;
 
-	/* FIXME: Should we restart the transmission thread here  ?? */
-	outl(TxENA | inl(ioaddr + cr), ioaddr + cr);
+	/* load Transmit Descriptor Register */
+	outl(sis_priv->tx_ring_dma, ioaddr + txdp);
 
 	/* Enable all known interrupts by setting the interrupt mask. */
 	outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr);
@@ -1457,6 +1465,8 @@
 	long ioaddr = net_dev->base_addr;
 	unsigned int  entry;
 	unsigned long flags;
+	unsigned int  index_cur_tx, index_dirty_tx;
+	unsigned int  count_dirty_tx;
 
 	/* Don't transmit data before the complete of auto-negotiation */
 	if(!sis_priv->autong_complete){
@@ -1476,7 +1486,18 @@
 	sis_priv->tx_ring[entry].cmdsts = (OWN | skb->len);
 	outl(TxENA | inl(ioaddr + cr), ioaddr + cr);
 
-	if (++sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC) {
+	sis_priv->cur_tx ++;
+	index_cur_tx = sis_priv->cur_tx;
+	index_dirty_tx = sis_priv->dirty_tx;
+
+	for (count_dirty_tx = 0; index_cur_tx != index_dirty_tx; index_dirty_tx++)
+		count_dirty_tx ++;
+
+	if (index_cur_tx == index_dirty_tx) {
+		/* dirty_tx is met in the cycle of cur_tx, buffer full */
+		sis_priv->tx_full = 1;
+		netif_stop_queue(net_dev);
+	} else if (count_dirty_tx < NUM_TX_DESC) { 
 		/* Typical path, tell upper layer that more transmission is possible */
 		netif_start_queue(net_dev);
 	} else {
@@ -1709,7 +1730,7 @@
 {
 	struct sis900_private *sis_priv = net_dev->priv;
 
-	for (; sis_priv->dirty_tx < sis_priv->cur_tx; sis_priv->dirty_tx++) {
+	for (; sis_priv->dirty_tx != sis_priv->cur_tx; sis_priv->dirty_tx++) {
 		struct sk_buff *skb;
 		unsigned int entry;
 		u32 tx_status;
diff -Nru a/drivers/net/sis900.h b/drivers/net/sis900.h
--- a/drivers/net/sis900.h	Tue Oct  1 00:08:15 2002
+++ b/drivers/net/sis900.h	Tue Oct  1 00:08:15 2002
@@ -135,8 +135,8 @@
 	EEaddrMask = 0x013F, EEcmdShift = 16
 };
 
-/* For SiS962, request the eeprom software access */
-enum sis962_eeprom_command {
+/* For SiS962 or SiS963, request the eeprom software access */
+enum sis96x_eeprom_command {
 	EEREQ = 0x00000400, EEDONE = 0x00000200, EEGNT = 0x00000100
 };
 
@@ -245,7 +245,7 @@
 	SIS630A_900_REV = 0x80,		SIS630E_900_REV = 0x81,
 	SIS630S_900_REV = 0x82,		SIS630EA1_900_REV = 0x83,
 	SIS630ET_900_REV = 0x84,	SIS635A_900_REV = 0x90,
-	SIS962_900_REV = 0X91,		SIS900B_900_REV = 0x03
+	SIS96x_900_REV = 0X91,		SIS900B_900_REV = 0x03
 };
 
 enum sis630_revision_id {
diff -Nru a/drivers/net/sk98lin/Makefile b/drivers/net/sk98lin/Makefile
--- a/drivers/net/sk98lin/Makefile	Tue Oct  1 00:08:13 2002
+++ b/drivers/net/sk98lin/Makefile	Tue Oct  1 00:08:13 2002
@@ -59,11 +59,3 @@
 
 include $(TOPDIR)/Rules.make
 
-clean:
-	rm -f core *.o *.a *.s
-
-
-
-
-
-
diff -Nru a/drivers/net/skfp/Makefile b/drivers/net/skfp/Makefile
--- a/drivers/net/skfp/Makefile	Tue Oct  1 00:08:19 2002
+++ b/drivers/net/skfp/Makefile	Tue Oct  1 00:08:19 2002
@@ -21,8 +21,3 @@
 
 include $(TOPDIR)/Rules.make
 
-clean:
-	rm -f core *.o *.a *.s
-
-
-
diff -Nru a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c
--- a/drivers/net/skfp/skfddi.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/net/skfp/skfddi.c	Tue Oct  1 00:08:15 2002
@@ -188,6 +188,7 @@
 };
 MODULE_DEVICE_TABLE(pci, skfddi_pci_tbl);
 MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mirko Lindner <mlindner@syskonnect.de>");
 
 // Define module-wide (static) variables
 
diff -Nru a/drivers/net/starfire.c b/drivers/net/starfire.c
--- a/drivers/net/starfire.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/net/starfire.c	Tue Oct  1 00:08:16 2002
@@ -571,19 +571,18 @@
 	struct net_device_stats stats;
 	struct pci_dev *pci_dev;
 	/* Frequently used values: keep some adjacent for cache effect. */
+	spinlock_t lock;
 	unsigned int cur_rx, dirty_rx;	/* Producer/consumer ring indices */
 	unsigned int cur_tx, dirty_tx;
 	unsigned int rx_buf_sz;		/* Based on MTU+slack. */
 	unsigned int tx_full:1,		/* The Tx queue is full. */
 	/* These values keep track of the transceiver/media in use. */
-		autoneg:1,		/* Autonegotiation allowed. */
-		full_duplex:1,		/* Full-duplex operation. */
 		speed100:1;		/* Set if speed == 100MBit. */
 	unsigned int intr_mitigation;
 	u32 tx_mode;
 	u8 tx_threshold;
 	/* MII transceiver section. */
-	u16 advertising;		/* NWay media advertisement */
+	struct mii_if_info mii_if;		/* MII lib hooks/info */
 	int phy_cnt;			/* MII device addresses. */
 	unsigned char phys[PHY_CNT];	/* MII device addresses. */
 };
@@ -726,9 +725,17 @@
 	dev->irq = irq;
 
 	np = dev->priv;
+	spin_lock_init(&np->lock);
 	pci_set_drvdata(pdev, dev);
 
 	np->pci_dev = pdev;
+
+	np->mii_if.dev = dev;
+	np->mii_if.mdio_read = mdio_read;
+	np->mii_if.mdio_write = mdio_write;
+	np->mii_if.phy_id_mask = 0x1f;
+	np->mii_if.reg_num_mask = 0x1f;
+
 	drv_flags = netdrv_tbl[chip_idx].drv_flags;
 
 	option = card_idx < MAX_UNITS ? options[card_idx] : 0;
@@ -737,15 +744,15 @@
 
 	/* The lower four bits are the media type. */
 	if (option & 0x200)
-		np->full_duplex = 1;
+		np->mii_if.full_duplex = 1;
 
 	if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0)
-		np->full_duplex = 1;
+		np->mii_if.full_duplex = 1;
 
-	if (np->full_duplex)
-		np->autoneg = 0;
+	if (np->mii_if.full_duplex)
+		np->mii_if.force_media = 0;
 	else
-		np->autoneg = 1;
+		np->mii_if.force_media = 1;
 	np->speed100 = 1;
 
 	/* The chip-specific entries in the device structure. */
@@ -787,15 +794,19 @@
 			mii_status = mdio_read(dev, phy, MII_BMSR);
 			if (mii_status != 0) {
 				np->phys[phy_idx++] = phy;
-				np->advertising = mdio_read(dev, phy, MII_ADVERTISE);
+				np->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE);
 				printk(KERN_INFO "%s: MII PHY found at address %d, status "
 					   "0x%4.4x advertising %4.4x.\n",
-					   dev->name, phy, mii_status, np->advertising);
+					   dev->name, phy, mii_status, np->mii_if.advertising);
 				/* there can be only one PHY on-board */
 				break;
 			}
 		}
 		np->phy_cnt = phy_idx;
+		if (np->phy_cnt > 0)
+			np->mii_if.phy_id = np->phys[0];
+		else
+			memset(&np->mii_if, 0, sizeof(np->mii_if));
 	}
 
 #ifdef ZEROCOPY
@@ -842,7 +853,6 @@
 	long mdio_addr = dev->base_addr + MIICtrl + (phy_id<<7) + (location<<2);
 	writel(value, mdio_addr);
 	/* The busy-wait will occur before a read. */
-	return;
 }
 
 
@@ -985,7 +995,7 @@
 		printk(KERN_DEBUG "%s: Setting the Rx and Tx modes.\n", dev->name);
 	set_rx_mode(dev);
 
-	np->advertising = mdio_read(dev, np->phys[0], MII_ADVERTISE);
+	np->mii_if.advertising = mdio_read(dev, np->phys[0], MII_ADVERTISE);
 	check_duplex(dev);
 
 	/* Enable GPIO interrupts on link change */
@@ -1026,25 +1036,25 @@
 	struct netdev_private *np = dev->priv;
 	u16 reg0;
 
-	mdio_write(dev, np->phys[0], MII_ADVERTISE, np->advertising);
+	mdio_write(dev, np->phys[0], MII_ADVERTISE, np->mii_if.advertising);
 	mdio_write(dev, np->phys[0], MII_BMCR, BMCR_RESET);
 	udelay(500);
 	while (mdio_read(dev, np->phys[0], MII_BMCR) & BMCR_RESET);
 
 	reg0 = mdio_read(dev, np->phys[0], MII_BMCR);
 
-	if (np->autoneg) {
+	if (!np->mii_if.force_media) {
 		reg0 |= BMCR_ANENABLE | BMCR_ANRESTART;
 	} else {
 		reg0 &= ~(BMCR_ANENABLE | BMCR_ANRESTART);
 		if (np->speed100)
 			reg0 |= BMCR_SPEED100;
-		if (np->full_duplex)
+		if (np->mii_if.full_duplex)
 			reg0 |= BMCR_FULLDPLX;
 		printk(KERN_DEBUG "%s: Link forced to %sMbit %s-duplex\n",
 		       dev->name,
 		       np->speed100 ? "100" : "10",
-		       np->full_duplex ? "full" : "half");
+		       np->mii_if.full_duplex ? "full" : "half");
 	}
 	mdio_write(dev, np->phys[0], MII_BMCR, reg0);
 }
@@ -1555,16 +1565,16 @@
 			reg5 = mdio_read(dev, np->phys[0], MII_LPA);
 			if (reg4 & ADVERTISE_100FULL && reg5 & LPA_100FULL) {
 				np->speed100 = 1;
-				np->full_duplex = 1;
+				np->mii_if.full_duplex = 1;
 			} else if (reg4 & ADVERTISE_100HALF && reg5 & LPA_100HALF) {
 				np->speed100 = 1;
-				np->full_duplex = 0;
+				np->mii_if.full_duplex = 0;
 			} else if (reg4 & ADVERTISE_10FULL && reg5 & LPA_10FULL) {
 				np->speed100 = 0;
-				np->full_duplex = 1;
+				np->mii_if.full_duplex = 1;
 			} else {
 				np->speed100 = 0;
-				np->full_duplex = 0;
+				np->mii_if.full_duplex = 0;
 			}
 		} else {
 			/* autonegotiation is disabled */
@@ -1573,17 +1583,17 @@
 			else
 				np->speed100 = 0;
 			if (reg0 & BMCR_FULLDPLX)
-				np->full_duplex = 1;
+				np->mii_if.full_duplex = 1;
 			else
-				np->full_duplex = 0;
+				np->mii_if.full_duplex = 0;
 		}
 		printk(KERN_DEBUG "%s: Link is up, running at %sMbit %s-duplex\n",
 		       dev->name,
 		       np->speed100 ? "100" : "10",
-		       np->full_duplex ? "full" : "half");
+		       np->mii_if.full_duplex ? "full" : "half");
 
 		new_tx_mode = np->tx_mode & ~0x2;	/* duplex setting */
-		if (np->full_duplex)
+		if (np->mii_if.full_duplex)
 			new_tx_mode |= 2;
 		if (np->tx_mode != new_tx_mode) {
 			np->tx_mode = new_tx_mode;
@@ -1718,77 +1728,6 @@
 		return -EFAULT;
 
 	switch (ecmd.cmd) {
-	case ETHTOOL_GSET:
-		ecmd.supported =
-			SUPPORTED_10baseT_Half |
-			SUPPORTED_10baseT_Full |
-			SUPPORTED_100baseT_Half |
-			SUPPORTED_100baseT_Full |
-			SUPPORTED_Autoneg |
-			SUPPORTED_MII;
-
-		ecmd.advertising = ADVERTISED_MII;
-		if (np->advertising & ADVERTISE_10HALF)
-			ecmd.advertising |= ADVERTISED_10baseT_Half;
-		if (np->advertising & ADVERTISE_10FULL)
-			ecmd.advertising |= ADVERTISED_10baseT_Full;
-		if (np->advertising & ADVERTISE_100HALF)
-			ecmd.advertising |= ADVERTISED_100baseT_Half;
-		if (np->advertising & ADVERTISE_100FULL)
-			ecmd.advertising |= ADVERTISED_100baseT_Full;
-		if (np->autoneg) {
-			ecmd.advertising |= ADVERTISED_Autoneg;
-			ecmd.autoneg = AUTONEG_ENABLE;
-		} else
-			ecmd.autoneg = AUTONEG_DISABLE;
-
-		ecmd.port = PORT_MII;
-		ecmd.transceiver = XCVR_INTERNAL;
-		ecmd.phy_address = np->phys[0];
-		ecmd.speed = np->speed100 ? SPEED_100 : SPEED_10;
-		ecmd.duplex = np->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
-		ecmd.maxtxpkt = TX_RING_SIZE;
-		ecmd.maxrxpkt = np->intr_mitigation; /* not 100% accurate */
-
-
-		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
-			return -EFAULT;
-		return 0;
-
-	case ETHTOOL_SSET: {
-		u16 autoneg, speed100, full_duplex;
-
-		autoneg = (ecmd.autoneg == AUTONEG_ENABLE);
-		speed100 = (ecmd.speed == SPEED_100);
-		full_duplex = (ecmd.duplex == DUPLEX_FULL);
-
-		np->autoneg = autoneg;
-		if (speed100 != np->speed100 ||
-		    full_duplex != np->full_duplex) {
-			np->speed100 = speed100;
-			np->full_duplex = full_duplex;
-			/* change advertising bits */
-			np->advertising &= ~(ADVERTISE_10HALF |
-					     ADVERTISE_10FULL |
-					     ADVERTISE_100HALF |
-					     ADVERTISE_100FULL |
-					     ADVERTISE_100BASE4);
-			if (speed100) {
-				if (full_duplex)
-					np->advertising |= ADVERTISE_100FULL;
-				else
-					np->advertising |= ADVERTISE_100HALF;
-			} else {
-				if (full_duplex)
-					np->advertising |= ADVERTISE_10FULL;
-				else
-					np->advertising |= ADVERTISE_10HALF;
-			}
-		}
-		check_duplex(dev);
-		return 0;
-	}
-
 	case ETHTOOL_GDRVINFO: {
 		struct ethtool_drvinfo info;
 		memset(&info, 0, sizeof(info));
@@ -1802,26 +1741,35 @@
 		return 0;
 	}
 
+	/* get settings */
+	case ETHTOOL_GSET: {
+		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+		spin_lock_irq(&np->lock);
+		mii_ethtool_gset(&np->mii_if, &ecmd);
+		spin_unlock_irq(&np->lock);
+		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set settings */
+	case ETHTOOL_SSET: {
+		int r;
+		struct ethtool_cmd ecmd;
+		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+			return -EFAULT;
+		spin_lock_irq(&np->lock);
+		r = mii_ethtool_sset(&np->mii_if, &ecmd);
+		spin_unlock_irq(&np->lock);
+		return r;
+	}
 	/* restart autonegotiation */
 	case ETHTOOL_NWAY_RST: {
-		int tmp;
-		int r = -EINVAL;
-		/* if autoneg is off, it's an error */
-		tmp = mdio_read(dev, np->phys[0], MII_BMCR);
-		if (tmp & BMCR_ANENABLE) {
-			tmp |= (BMCR_ANRESTART);
-			mdio_write(dev, np->phys[0], MII_BMCR, tmp);
-			r = 0;
-		}
-		return r;
+		return mii_nway_restart(&np->mii_if);
 	}
 	/* get link status */
 	case ETHTOOL_GLINK: {
 		struct ethtool_value edata = {ETHTOOL_GLINK};
-		if (mdio_read(dev, np->phys[0], MII_BMSR) & BMSR_LSTATUS)
-			edata.data = 1;
-		else
-			edata.data = 0;
+		edata.data = mii_link_ok(&np->mii_if);
 		if (copy_to_user(useraddr, &edata, sizeof(edata)))
 			return -EFAULT;
 		return 0;
@@ -1852,47 +1800,25 @@
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct netdev_private *np = dev->priv;
-	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data;
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
+	int rc;
 
-	switch(cmd) {
-	case SIOCETHTOOL:
-		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-
-	/* Legacy mii-diag interface */
-	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
-		data->phy_id = np->phys[0] & 0x1f;
-		/* Fall Through */
+	if (!netif_running(dev))
+		return -EINVAL;
 
-	case SIOCGMIIREG:		/* Read MII PHY register. */
-		data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
-		return 0;
+	if (cmd == SIOCETHTOOL)
+		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
 
-	case SIOCSMIIREG:		/* Write MII PHY register. */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		if (data->phy_id == np->phys[0]) {
-			u16 value = data->val_in;
-			switch (data->reg_num) {
-			case 0:
-				if (value & (BMCR_RESET | BMCR_ANENABLE))
-					/* Autonegotiation. */
-					np->autoneg = 1;
-				else {
-					np->full_duplex = (value & BMCR_FULLDPLX) ? 1 : 0;
-					np->autoneg = 0;
-				}
-				break;
-			case 4:
-				np->advertising = value;
-				break;
-			}
+	else {
+		spin_lock_irq(&np->lock);
+		rc = generic_mii_ioctl(&np->mii_if, data, cmd, NULL);
+		spin_unlock_irq(&np->lock);
+		
+		if ((cmd == SIOCSMIIREG) && (data->phy_id == np->phys[0]))
 			check_duplex(dev);
-		}
-		mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
-		return 0;
-	default:
-		return -EOPNOTSUPP;
 	}
+
+	return rc;
 }
 
 static int netdev_close(struct net_device *dev)
diff -Nru a/drivers/net/sundance.c b/drivers/net/sundance.c
--- a/drivers/net/sundance.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/net/sundance.c	Tue Oct  1 00:08:17 2002
@@ -62,11 +62,15 @@
 	- Add CONFIG_SUNDANCE_MMIO config option (jgarzik)
 	- Better rx buf size calculation (Donald Becker)
 
+	Version LK1.05 (D-Link):
+	- fix DFE-580TX packet drop issue
+	- fix reset_tx logic
+
 */
 
 #define DRV_NAME	"sundance"
-#define DRV_VERSION	"1.01+LK1.04d"
-#define DRV_RELDATE	"19-Sep-2002"
+#define DRV_VERSION	"1.01+LK1.05"
+#define DRV_RELDATE	"28-Sep-2002"
 
 
 /* The user-configurable values.
@@ -146,18 +150,21 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/init.h>
-#include <linux/ethtool.h>
-#include <linux/mii.h>
 #include <asm/uaccess.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
-#ifndef _LOCAL_CRC32
+#ifndef _COMPAT_WITH_OLD_KERNEL
 #include <linux/crc32.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
 #else
 #include "crc32.h"
+#include "ethtool.h"
+#include "mii.h"
+#include "compat.h"
 #endif
 
 /* These identify the driver base version and may not be removed. */
@@ -319,6 +326,8 @@
 	TxDMAPollPeriod = 0x0a,
 	RxDMAStatus = 0x0c,
 	RxListPtr = 0x10,
+	DebugCtrl0 = 0x1a,
+	DebugCtrl1 = 0x1c,
 	RxDMABurstThresh = 0x14,
 	RxDMAUrgentThresh = 0x15,
 	RxDMAPollPeriod = 0x16,
@@ -477,7 +486,7 @@
 static void tx_timeout(struct net_device *dev);
 static void init_ring(struct net_device *dev);
 static int  start_tx(struct sk_buff *skb, struct net_device *dev);
-static int reset_tx (struct net_device *dev, int irq);
+static int reset_tx (struct net_device *dev);
 static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
 static void rx_poll(unsigned long data);
 static void refill_rx (struct net_device *dev);
@@ -564,6 +573,8 @@
 	np->mii_if.dev = dev;
 	np->mii_if.mdio_read = mdio_read;
 	np->mii_if.mdio_write = mdio_write;
+	np->mii_if.phy_id_mask = 0x1f;
+	np->mii_if.reg_num_mask = 0x1f;
 
 	/* The chip-specific entries in the device structure. */
 	dev->open = &netdev_open;
@@ -855,6 +866,8 @@
 	/* Set the chip to poll every N*320nsec. */
 	writeb(100, ioaddr + RxDMAPollPeriod);
 	writeb(127, ioaddr + TxDMAPollPeriod);
+	/* Fix DFE-580TX packet drop issue */
+	writeb(0x01, ioaddr + DebugCtrl1);
 	netif_start_queue(dev);
 
 	writew(StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1);
@@ -931,6 +944,7 @@
 	long ioaddr = dev->base_addr;
 	long flag;
 
+	writew(0, ioaddr + IntrEnable);
 	printk(KERN_WARNING "%s: Transmit timed out, TxStatus %2.2x "
 		   "TxFrameId %2.2x,"
 		   " resetting...\n", dev->name, readb(ioaddr + TxStatus),
@@ -945,9 +959,11 @@
 		for (i = 0; i < TX_RING_SIZE; i++)
 			printk(" %8.8x", np->tx_ring[i].status);
 		printk("\n");
+		printk(KERN_DEBUG "cur_tx=%d dirty_tx=%d\n", np->cur_tx, np->dirty_tx);
+		printk(KERN_DEBUG "cur_rx=%d dirty_rx=%d\n", np->cur_rx, np->dirty_rx);
 	}
 	spin_lock_irqsave(&np->lock, flag);
-	reset_tx(dev, 0);
+	reset_tx(dev);
 	spin_unlock_irqrestore(&np->lock, flag);
 
 	/* Perhaps we should reinitialize the hardware here. */
@@ -959,7 +975,6 @@
 
 	dev->trans_start = jiffies;
 	np->stats.tx_errors++;
-
 	if (!netif_queue_stopped(dev))
 		netif_wake_queue(dev);
 }
@@ -1064,15 +1079,18 @@
 		writel (1000, ioaddr + DownCounter);
 	return 0;
 }
+/* Reset hardware tx and reset TxListPtr to TxFrameId */
 static int
-reset_tx (struct net_device *dev, int irq)
+reset_tx (struct net_device *dev)
 {
 	struct netdev_private *np = (struct netdev_private*) dev->priv;
 	long ioaddr = dev->base_addr;
+	struct sk_buff *skb;
 	int i;
-	int frame_id;
-
-	frame_id = readb(ioaddr + TxFrameId);
+	int irq = in_interrupt();
+	
+	/* reset tx logic */
+	writel (0, dev->base_addr + TxListPtr);
 	writew (TxReset | DMAReset | FIFOReset | NetworkReset,
 			ioaddr + ASICCtrl + 2);
 	for (i=50; i > 0; i--) {
@@ -1080,25 +1098,22 @@
 			break;
 		mdelay(1);
 	}
-	for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
-		int entry = np->dirty_tx % TX_RING_SIZE;
-		struct sk_buff *skb;
-		if (!(np->tx_ring[entry].status & 0x00010000))
-			break;
-		skb = np->tx_skbuff[entry];
-		/* Free the original skb. */
-		pci_unmap_single(np->pci_dev,
-			np->tx_ring[entry].frag[0].addr,
-			skb->len, PCI_DMA_TODEVICE);
-		if (irq)
-			dev_kfree_skb_irq (np->tx_skbuff[entry]);
-		else
-			dev_kfree_skb (np->tx_skbuff[entry]);
-
-		np->tx_skbuff[entry] = 0;
+	/* free all tx skbuff */
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		skb = np->tx_skbuff[i];
+		if (skb) {
+			pci_unmap_single(np->pci_dev, 
+				np->tx_ring[i].frag[0].addr, skb->len,
+				PCI_DMA_TODEVICE);
+			if (irq)
+				dev_kfree_skb_irq (skb);
+			else
+				dev_kfree_skb (skb);
+			np->tx_skbuff[i] = 0;
+			np->stats.tx_dropped++;
+		}
 	}
-	writel (np->tx_ring_dma + frame_id * sizeof(*np->tx_ring),
-			dev->base_addr + TxListPtr);
+	np->cur_tx = np->dirty_tx = 0;
 	return 0;
 }
 
@@ -1110,6 +1125,7 @@
 	struct netdev_private *np;
 	long ioaddr;
 	int boguscnt = max_interrupt_work;
+	int hw_frame_id;
 
 	ioaddr = dev->base_addr;
 	np = dev->priv;
@@ -1153,7 +1169,7 @@
 					if (tx_status & 0x10) {	/* Reset the Tx. */
 						np->stats.tx_fifo_errors++;
 						spin_lock(&np->lock);
-						reset_tx(dev, 1);
+						reset_tx(dev);
 						spin_unlock(&np->lock);
 					}
 					if (tx_status & 0x1e)	/* Restart the Tx. */
@@ -1168,10 +1184,14 @@
 			}
 		}
 		spin_lock(&np->lock);
+		hw_frame_id = readb(ioaddr + TxFrameId);
 		for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
 			int entry = np->dirty_tx % TX_RING_SIZE;
 			struct sk_buff *skb;
-			if (!(np->tx_ring[entry].status & 0x00010000))
+			int sw_frame_id;
+			sw_frame_id = (np->tx_ring[entry].status >> 2) & 0xff;
+			
+			if (sw_frame_id == hw_frame_id)
 				break;
 			skb = np->tx_skbuff[entry];
 			/* Free the original skb. */
@@ -1532,27 +1552,23 @@
 
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data;
+	struct netdev_private *np = dev->priv;
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
+	int rc;
 
-	switch(cmd) {
-	case SIOCETHTOOL:
-		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
-		data->phy_id = ((struct netdev_private *)dev->priv)->phys[0] & 0x1f;
-		/* Fall Through */
-
-	case SIOCGMIIREG:		/* Read MII PHY register. */
-		data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
-		return 0;
-
-	case SIOCSMIIREG:		/* Write MII PHY register. */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
-		return 0;
-	default:
-		return -EOPNOTSUPP;
+	if (!netif_running(dev))
+		return -EINVAL;
+
+	if (cmd == SIOCETHTOOL)
+		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+
+	else {
+		spin_lock_irq(&np->lock);
+		rc = generic_mii_ioctl(&np->mii_if, data, cmd, NULL);
+		spin_unlock_irq(&np->lock);
 	}
+
+	return rc;
 }
 
 static int netdev_close(struct net_device *dev)
diff -Nru a/drivers/net/tc35815.c b/drivers/net/tc35815.c
--- a/drivers/net/tc35815.c	Tue Oct  1 00:08:14 2002
+++ b/drivers/net/tc35815.c	Tue Oct  1 00:08:14 2002
@@ -40,7 +40,7 @@
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/string.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
diff -Nru a/drivers/net/tlan.c b/drivers/net/tlan.c
--- a/drivers/net/tlan.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/net/tlan.c	Tue Oct  1 00:08:15 2002
@@ -1707,10 +1707,9 @@
 		printk( "TLAN:  %s: Adaptor Error = 0x%x\n", dev->name, error );
 		TLan_ReadAndClearStats( dev, TLAN_RECORD );
 		outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD );
-		
-		queue_task(&priv->tlan_tqueue, &tq_immediate);
-		mark_bh(IMMEDIATE_BH);
-		
+
+		schedule_task(&priv->tlan_tqueue);
+
 		netif_wake_queue(dev);
 		ack = 0;
 	} else {
diff -Nru a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c
--- a/drivers/net/tokenring/olympic.c	Tue Oct  1 00:08:18 2002
+++ b/drivers/net/tokenring/olympic.c	Tue Oct  1 00:08:19 2002
@@ -128,7 +128,7 @@
 /* Module paramters */
 
 MODULE_AUTHOR("Mike Phillips <mikep@linuxtr.net>") ; 
-MODULE_DESCRIPTION("Olympic PCI/Cardbus Chipset Driver \n") ; 
+MODULE_DESCRIPTION("Olympic PCI/Cardbus Chipset Driver") ; 
 
 /* Ring Speed 0,4,16,100 
  * 0 = Autosense         
diff -Nru a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
--- a/drivers/net/tulip/winbond-840.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/net/tulip/winbond-840.c	Tue Oct  1 00:08:15 2002
@@ -473,7 +473,7 @@
 		np->mii_if.full_duplex = 1;
 
 	if (np->mii_if.full_duplex)
-		np->mii_if.duplex_lock = 1;
+		np->mii_if.force_media = 1;
 
 	/* The chip-specific entries in the device structure. */
 	dev->open = &netdev_open;
@@ -773,7 +773,7 @@
 		duplex = (negotiated & LPA_100FULL) || ((negotiated & 0x02C0) == LPA_10FULL);
 		fasteth = negotiated & 0x380;
 	}
-	duplex |= np->mii_if.duplex_lock;
+	duplex |= np->mii_if.force_media;
 	/* remove fastether and fullduplex */
 	result = np->csr6 & ~0x20000200;
 	if (duplex)
diff -Nru a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
--- a/drivers/net/via-rhine.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/net/via-rhine.c	Tue Oct  1 00:08:17 2002
@@ -516,7 +516,7 @@
 static void via_rhine_error(struct net_device *dev, int intr_status);
 static void via_rhine_set_rx_mode(struct net_device *dev);
 static struct net_device_stats *via_rhine_get_stats(struct net_device *dev);
-static int via_rhine_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static int  via_rhine_close(struct net_device *dev);
 static inline void clear_tally_counters(long ioaddr);
 
@@ -715,6 +715,8 @@
 	np->mii_if.dev = dev;
 	np->mii_if.mdio_read = mdio_read;
 	np->mii_if.mdio_write = mdio_write;
+	np->mii_if.phy_id_mask = 0x1f;
+	np->mii_if.reg_num_mask = 0x1f;
 
 	if (dev->mem_start)
 		option = dev->mem_start;
@@ -731,7 +733,7 @@
 	if (np->mii_if.full_duplex) {
 		printk(KERN_INFO "%s: Set to forced full duplex, autonegotiation"
 			   " disabled.\n", dev->name);
-		np->mii_if.duplex_lock = 1;
+		np->mii_if.force_media = 1;
 	}
 
 	/* The chip-specific entries in the device structure. */
@@ -740,7 +742,7 @@
 	dev->stop = via_rhine_close;
 	dev->get_stats = via_rhine_get_stats;
 	dev->set_multicast_list = via_rhine_set_rx_mode;
-	dev->do_ioctl = via_rhine_ioctl;
+	dev->do_ioctl = netdev_ioctl;
 	dev->tx_timeout = via_rhine_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 	if (np->drv_flags & ReqTxAlign)
@@ -1001,7 +1003,7 @@
 		   ioaddr + IntrEnable);
 
 	np->chip_cmd = CmdStart|CmdTxOn|CmdRxOn|CmdNoTxPoll;
-	if (np->mii_if.duplex_lock)
+	if (np->mii_if.force_media)
 		np->chip_cmd |= CmdFDuplex;
 	writew(np->chip_cmd, ioaddr + ChipCmd);
 
@@ -1043,7 +1045,7 @@
 		switch (regnum) {
 		case MII_BMCR:					/* Is user forcing speed/duplex? */
 			if (value & 0x9000)			/* Autonegotiation. */
-				np->mii_if.duplex_lock = 0;
+				np->mii_if.force_media = 0;
 			else
 				np->mii_if.full_duplex = (value & 0x0100) ? 1 : 0;
 			break;
@@ -1114,7 +1116,7 @@
 	int negotiated = mii_lpa & np->mii_if.advertising;
 	int duplex;
 
-	if (np->mii_if.duplex_lock  ||  mii_lpa == 0xffff)
+	if (np->mii_if.force_media  ||  mii_lpa == 0xffff)
 		return;
 	duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
 	if (np->mii_if.full_duplex != duplex) {
@@ -1586,7 +1588,7 @@
 	writeb(np->rx_thresh | rx_mode, ioaddr + RxConfig);
 }
 
-static int via_rhine_ethtool_ioctl (struct net_device *dev, void *useraddr)
+static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
 {
 	struct netdev_private *np = dev->priv;
 	u32 ethcmd;
@@ -1669,41 +1671,26 @@
 
 	return -EOPNOTSUPP;
 }
-static int via_rhine_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct netdev_private *np = dev->priv;
-	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data;
-	unsigned long flags;
-	int retval;
-
-	if (cmd == SIOCETHTOOL)
-		return via_rhine_ethtool_ioctl(dev, (void *) rq->ifr_data);
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
+	int rc;
 
-	spin_lock_irqsave(&np->lock, flags);
-	retval = 0;
-
-	switch(cmd) {
-	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
-		data->phy_id = np->phys[0] & 0x1f;
-		/* Fall Through */
+	if (!netif_running(dev))
+		return -EINVAL;
 
-	case SIOCGMIIREG:		/* Read MII PHY register. */
-		data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
-		break;
+	if (cmd == SIOCETHTOOL)
+		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
 
-	case SIOCSMIIREG:		/* Write MII PHY register. */
-		if (!capable(CAP_NET_ADMIN)) {
-			retval = -EPERM;
-			break;
-		}
-		mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
-		break;
-	default:
-		retval = -EOPNOTSUPP;
+	else {
+		spin_lock_irq(&np->lock);
+		rc = generic_mii_ioctl(&np->mii_if, data, cmd, NULL);
+		spin_unlock_irq(&np->lock);
 	}
 
-	spin_unlock_irqrestore(&np->lock, flags);
-	return retval;
+	return rc;
 }
 
 static int via_rhine_close(struct net_device *dev)
diff -Nru a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c
--- a/drivers/net/wan/lapbether.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/net/wan/lapbether.c	Tue Oct  1 00:08:16 2002
@@ -44,42 +44,63 @@
 #include <linux/lapb.h>
 #include <linux/init.h>
 
-static char bcast_addr[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
+static char bcast_addr[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
 
 /* If this number is made larger, check that the temporary string buffer
  * in lapbeth_new_device is large enough to store the probe device name.*/
 #define MAXLAPBDEV 100
 
-static struct lapbethdev {
-	struct lapbethdev *next;
-	char   ethname[14];		/* ether device name */
-	struct net_device *ethdev;		/* link to ethernet device */
-	struct net_device axdev;		/* lapbeth device (lapb#) */
-	struct net_device_stats stats;	/* some statistics */
-} *lapbeth_devices /* = NULL initially */;
+struct lapbethdev {
+	struct list_head	node;
+	char			ethname[14];	/* ether device name */
+	struct net_device	*ethdev;	/* link to ethernet device */
+	struct net_device	axdev;		/* lapbeth device (lapb#) */
+	struct net_device_stats stats;		/* some statistics */
+	atomic_t		refcnt;
+};
+
+static struct list_head lapbeth_devices = LIST_HEAD_INIT(lapbeth_devices);
+static rwlock_t lapbeth_devices_lock = RW_LOCK_UNLOCKED;
 
+static __inline__ void lapbeth_hold(struct lapbethdev *lapbeth)
+{
+	atomic_inc(&lapbeth->refcnt);
+}
+
+static __inline__ void lapbeth_put(struct lapbethdev *lapbeth)
+{
+	if (atomic_dec_and_test(&lapbeth->refcnt))
+		kfree(lapbeth);
+}
 /* ------------------------------------------------------------------------ */
 
 /*
  *	Get the LAPB device for the ethernet device
  */
-static inline struct net_device *lapbeth_get_x25_dev(struct net_device *dev)
+static __inline__ struct lapbethdev *lapbeth_get_x25_dev(struct net_device *dev)
 {
-	struct lapbethdev *lapbeth;
+	struct list_head *entry;
+	struct lapbethdev *lapbeth, *use = NULL;
+
+	read_lock(&lapbeth_devices_lock);
 
-	for (lapbeth = lapbeth_devices; lapbeth != NULL; lapbeth = lapbeth->next)
-		if (lapbeth->ethdev == dev)
-			return &lapbeth->axdev;
+	list_for_each(entry, &lapbeth_devices) {
+		lapbeth = list_entry(entry, struct lapbethdev, node);
+		if (lapbeth->ethdev == dev) {
+			use = lapbeth;
+			break;
+		}
+	}
+	if (use)
+		lapbeth_hold(use);
 
-	return NULL;
+	read_unlock(&lapbeth_devices_lock);
+	return use;
 }
 
-static inline int dev_is_ethdev(struct net_device *dev)
+static __inline__ int dev_is_ethdev(struct net_device *dev)
 {
-	return (
-			dev->type == ARPHRD_ETHER
-			&& strncmp(dev->name, "dummy", 5)
-	);
+	return dev->type == ARPHRD_ETHER && strncmp(dev->name, "dummy", 5);
 }
 
 /*
@@ -88,35 +109,26 @@
  */
 static int lapbeth_check_devices(struct net_device *dev)
 {
-	struct lapbethdev *lapbeth, *lapbeth_prev, *lapbeth_next;
+	struct lapbethdev *lapbeth;
+	struct list_head *entry, *tmp;
 	int result = 0;
-	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	write_lock(&lapbeth_devices_lock);
 
-	lapbeth_prev = NULL;
+	list_for_each_safe(entry, tmp, &lapbeth_devices) {
+		lapbeth = list_entry(entry, struct lapbethdev, node);
 
-	for (lapbeth = lapbeth_devices; lapbeth != NULL; lapbeth = lapbeth_next) {
-		lapbeth_next = lapbeth->next;
 		if (!dev_get(lapbeth->ethname)) {
-			if (lapbeth_prev)
-				lapbeth_prev->next = lapbeth->next;
-			else
-				lapbeth_devices = lapbeth->next;
-
 			if (&lapbeth->axdev == dev)
 				result = 1;
 
 			unregister_netdev(&lapbeth->axdev);
 			dev_put(lapbeth->ethdev);
-			kfree(lapbeth);
+			list_del(&lapbeth->node);
+			lapbeth_put(lapbeth);
 		}
-		else
-			lapbeth_prev = lapbeth;
 	}
-
-	restore_flags(flags);
+	write_unlock(&lapbeth_devices_lock);
 
 	return result;
 }
@@ -133,14 +145,12 @@
 
 	skb->sk = NULL;		/* Initially we don't know who it's for */
 
-	dev = lapbeth_get_x25_dev(dev);
+	lapbeth = lapbeth_get_x25_dev(dev);
 
-	if (dev == NULL || !netif_running(dev)) {
-		kfree_skb(skb);
-		return 0;
-	}
-
-	lapbeth = (struct lapbethdev *) dev->priv;
+	if (!lapbeth)
+		goto drop;
+	if (!netif_running(&lapbeth->axdev))
+		goto put_drop;
 
 	lapbeth->stats.rx_packets++;
 
@@ -150,16 +160,22 @@
 	skb_trim(skb, len);	/* Set the length of the data */
 
 	if ((err = lapb_data_received(lapbeth, skb)) != LAPB_OK) {
-		kfree_skb(skb);
 		printk(KERN_DEBUG "lapbether: lapb_data_received err - %d\n", err);
+		goto put_drop;
 	}
-
+	lapbeth_put(lapbeth);
+out:
 	return 0;
+put_drop:
+	lapbeth_put(lapbeth);
+drop:
+	kfree_skb(skb);
+	goto out;
 }
 
 static int lapbeth_data_indication(void *token, struct sk_buff *skb)
 {
-	struct lapbethdev *lapbeth = (struct lapbethdev *) token;
+	struct lapbethdev *lapbeth = (struct lapbethdev *)token;
 	unsigned char *ptr;
 
 	ptr  = skb_push(skb, 1);
@@ -178,8 +194,8 @@
  */
 static int lapbeth_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct lapbethdev *lapbeth = (struct lapbethdev *) dev->priv;
-	int err;
+	struct lapbethdev *lapbeth = (struct lapbethdev *)dev->priv;
+	int err = -ENODEV;
 
 	/*
 	 * Just to be *really* sure not to send anything if the interface
@@ -187,50 +203,53 @@
 	 */
 	if (!netif_running(dev)) {
 		lapbeth_check_devices(dev);
-		kfree_skb(skb);
-		return -ENODEV;
+		goto drop;
 	}
 
 	switch (skb->data[0]) {
-		case 0x00:
-			break;
-		case 0x01:
-			if ((err = lapb_connect_request(lapbeth)) != LAPB_OK)
-				printk(KERN_ERR "lapbeth: lapb_connect_request error - %d\n", err);
-			kfree_skb(skb);
-			return 0;
-		case 0x02:
-			if ((err = lapb_disconnect_request(lapbeth)) != LAPB_OK)
-				printk(KERN_ERR "lapbeth: lapb_disconnect_request err - %d\n", err);
-			kfree_skb(skb);
-			return 0;
-		default:
-			kfree_skb(skb);
-			return 0;
+	case 0x00:
+		err = 0;
+		break;
+	case 0x01:
+		if ((err = lapb_connect_request(lapbeth)) != LAPB_OK)
+			printk(KERN_ERR "lapbeth: lapb_connect_request "
+			       "error: %d\n", err);
+		goto drop_ok;
+	case 0x02:
+		if ((err = lapb_disconnect_request(lapbeth)) != LAPB_OK)
+			printk(KERN_ERR "lapbeth: lapb_disconnect_request "
+			       "err: %d\n", err);
+		/* Fall thru */
+	default:
+		goto drop_ok;
 	}
 
 	skb_pull(skb, 1);
 
 	if ((err = lapb_data_request(lapbeth, skb)) != LAPB_OK) {
 		printk(KERN_ERR "lapbeth: lapb_data_request error - %d\n", err);
-		kfree_skb(skb);
-		return -ENOMEM;
+		err = -ENOMEM;
+		goto drop;
 	}
-
-	return 0;
+	err = 0;
+out:
+	return err;
+drop_ok:
+	err = 0;
+drop:
+	kfree_skb(skb);
+	goto out;
 }
 
 static void lapbeth_data_transmit(void *token, struct sk_buff *skb)
 {
-	struct lapbethdev *lapbeth = (struct lapbethdev *) token;
+	struct lapbethdev *lapbeth = (struct lapbethdev *)token;
 	unsigned char *ptr;
 	struct net_device *dev;
-	int size;
+	int size = skb->len;
 
 	skb->protocol = htons(ETH_P_X25);
 
-	size = skb->len;
-
 	ptr = skb_push(skb, 2);
 
 	*ptr++ = size % 256;
@@ -247,11 +266,11 @@
 
 static void lapbeth_connected(void *token, int reason)
 {
-	struct lapbethdev *lapbeth = (struct lapbethdev *) token;
-	struct sk_buff *skb;
+	struct lapbethdev *lapbeth = (struct lapbethdev *)token;
 	unsigned char *ptr;
+	struct sk_buff *skb = dev_alloc_skb(1);
 
-	if ((skb = dev_alloc_skb(1)) == NULL) {
+	if (!skb) {
 		printk(KERN_ERR "lapbeth: out of memory\n");
 		return;
 	}
@@ -269,11 +288,11 @@
 
 static void lapbeth_disconnected(void *token, int reason)
 {
-	struct lapbethdev *lapbeth = (struct lapbethdev *) token;
-	struct sk_buff *skb;
+	struct lapbethdev *lapbeth = (struct lapbethdev *)token;
 	unsigned char *ptr;
+	struct sk_buff *skb = dev_alloc_skb(1);
 
-	if ((skb = dev_alloc_skb(1)) == NULL) {
+	if (!skb) {
 		printk(KERN_ERR "lapbeth: out of memory\n");
 		return;
 	}
@@ -294,7 +313,7 @@
  */
 static struct net_device_stats *lapbeth_get_stats(struct net_device *dev)
 {
-	struct lapbethdev *lapbeth = (struct lapbethdev *) dev->priv;
+	struct lapbethdev *lapbeth = (struct lapbethdev *)dev->priv;
 	return &lapbeth->stats;
 }
 
@@ -303,9 +322,9 @@
  */
 static int lapbeth_set_mac_address(struct net_device *dev, void *addr)
 {
-    struct sockaddr *sa = (struct sockaddr *) addr;
-    memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
-    return 0;
+	struct sockaddr *sa = (struct sockaddr *)addr;
+	memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
+	return 0;
 }
 
 /*
@@ -320,7 +339,7 @@
 	if (lapbeth_check_devices(dev))
 		return -ENODEV;		/* oops, it's gone */
 
-	lapbeth = (struct lapbethdev *) dev->priv;
+	lapbeth = (struct lapbethdev *)dev->priv;
 
 	lapbeth_callbacks.connect_confirmation    = lapbeth_connected;
 	lapbeth_callbacks.connect_indication      = lapbeth_connected;
@@ -340,7 +359,7 @@
 
 static int lapbeth_close(struct net_device *dev)
 {
-	struct lapbethdev *lapbeth = (struct lapbethdev *) dev->priv;
+	struct lapbethdev *lapbeth = (struct lapbethdev *)dev->priv;
 	int err;
 
 	netif_stop_queue(dev);
@@ -358,20 +377,21 @@
  */
 static int lapbeth_new_device(struct net_device *dev)
 {
-	int k;
 	unsigned char buf[14];
-	struct lapbethdev *lapbeth, *lapbeth2;
+	struct lapbethdev *lapbeth;
+	int k, rc = -ENOMEM;
 
-	if ((lapbeth = kmalloc(sizeof(struct lapbethdev), GFP_KERNEL)) == NULL)
-		return -ENOMEM;
+	if ((lapbeth = kmalloc(sizeof(struct lapbethdev), GFP_ATOMIC)) == NULL)
+		goto out;
 
 	memset(lapbeth, 0, sizeof(struct lapbethdev));
 
 	dev_hold(dev);
 	lapbeth->ethdev = dev;
 
-	lapbeth->ethname[sizeof(lapbeth->ethname)-1] = '\0';
-	strncpy(lapbeth->ethname, dev->name, sizeof(lapbeth->ethname)-1);
+	strncpy(lapbeth->ethname, dev->name, sizeof(lapbeth->ethname) - 1);
+	lapbeth->ethname[sizeof(lapbeth->ethname) - 1] = '\0';
+	atomic_set(&lapbeth->refcnt, 1);
 
 	dev = &lapbeth->axdev;
 	SET_MODULE_OWNER(dev);
@@ -381,24 +401,21 @@
 
 		sprintf(buf, "lapb%d", k);
 
-		if ((odev = __dev_get_by_name(buf)) == NULL || lapbeth_check_devices(odev))
+		if ((odev = __dev_get_by_name(buf)) == NULL ||
+		    lapbeth_check_devices(odev))
 			break;
 	}
 
-	if (k == MAXLAPBDEV) {
-		dev_put(dev);
-		kfree(lapbeth);
-		return -ENODEV;
-	}
+	rc = -ENODEV;
+	if (k == MAXLAPBDEV)
+		goto fail;
 
 	dev->priv = (void *)lapbeth;	/* pointer back */
 	strcpy(dev->name, buf);
 
-	if (register_netdev(dev) != 0) {
-		dev_put(dev);
-		kfree(lapbeth);
-                return -EIO;
-        }
+	rc = -EIO;
+	if (register_netdev(dev))
+		goto fail;
 
 	dev->hard_start_xmit = lapbeth_xmit;
 	dev->open	     = lapbeth_open;
@@ -410,26 +427,27 @@
 	dev->mtu             = 1000;
 	dev->addr_len        = 0;
 
-	cli();
-
-	if (lapbeth_devices == NULL) {
-		lapbeth_devices = lapbeth;
-	} else {
-		for (lapbeth2 = lapbeth_devices; lapbeth2->next != NULL; lapbeth2 = lapbeth2->next);
-		lapbeth2->next = lapbeth;
-	}
-
-	sti();
-
-	return 0;
+	write_lock(&lapbeth_devices_lock);
+	list_add(&lapbeth->node, &lapbeth_devices);
+	lapbeth_hold(lapbeth);
+	write_unlock(&lapbeth_devices_lock);
+	rc = 0;
+out:
+	return rc;
+fail:
+	dev_put(dev);
+	kfree(lapbeth);
+	goto out;
 }
 
 /*
  *	Handle device status changes.
  */
-static int lapbeth_device_event(struct notifier_block *this, unsigned long event, void *ptr)
+static int lapbeth_device_event(struct notifier_block *this,
+				unsigned long event, void *ptr)
 {
-	struct net_device *dev = (struct net_device *) ptr;
+	struct lapbethdev *lapbeth;
+	struct net_device *dev = (struct net_device *)ptr;
 
 	if (!dev_is_ethdev(dev))
 		return NOTIFY_DONE;
@@ -437,19 +455,26 @@
 	lapbeth_check_devices(NULL);
 
 	switch (event) {
-		case NETDEV_UP:		/* new ethernet device -> new LAPB interface */
-			if (lapbeth_get_x25_dev(dev) == NULL)
-				lapbeth_new_device(dev);
-			break;
+	case NETDEV_UP:
+		/*
+		 * New ethernet device -> new LAPB interface
+		 */
+		lapbeth = lapbeth_get_x25_dev(dev);
 
-		case NETDEV_GOING_DOWN:
-		case NETDEV_DOWN:	/* ethernet device closed -> close LAPB interface */
-			if ((dev = lapbeth_get_x25_dev(dev)) != NULL)
-				dev_close(dev);
-			break;
-
-		default:
-			break;
+		if (lapbeth)
+			lapbeth_put(lapbeth);
+		else
+			lapbeth_new_device(dev);
+		break;
+	case NETDEV_GOING_DOWN:
+	case NETDEV_DOWN:	/* ethernet device closed -> close LAPB interface */
+		lapbeth = lapbeth_get_x25_dev(dev);
+
+		if (lapbeth) {
+			dev_close(lapbeth->ethdev);
+			lapbeth_put(lapbeth);
+		}
+		break;
 	}
 
 	return NOTIFY_DONE;
@@ -458,15 +483,15 @@
 /* ------------------------------------------------------------------------ */
 
 static struct packet_type lapbeth_packet_type = {
-	.type		= __constant_htons(ETH_P_DEC),
-	.func		= lapbeth_rcv,
+	.type = __constant_htons(ETH_P_DEC),
+	.func = lapbeth_rcv,
 };
 
 static struct notifier_block lapbeth_dev_notifier = {
 	.notifier_call = lapbeth_device_event,
 };
 
-static char banner[] __initdata = KERN_INFO "LAPB Ethernet driver version 0.01\n";
+static char banner[] __initdata = KERN_INFO "LAPB Ethernet driver version 0.02\n";
 
 static int __init lapbeth_init_driver(void)
 {
@@ -479,7 +504,7 @@
 	printk(banner);
 
 	read_lock_bh(&dev_base_lock);
-	for (dev = dev_base; dev != NULL; dev = dev->next) {
+	for (dev = dev_base; dev; dev = dev->next) {
 		if (dev_is_ethdev(dev)) {
 			read_unlock_bh(&dev_base_lock);
 			lapbeth_new_device(dev);
@@ -495,18 +520,24 @@
 static void __exit lapbeth_cleanup_driver(void)
 {
 	struct lapbethdev *lapbeth;
+	struct list_head *entry, *tmp;
 
 	dev_remove_pack(&lapbeth_packet_type);
-
 	unregister_netdevice_notifier(&lapbeth_dev_notifier);
 
-	for (lapbeth = lapbeth_devices; lapbeth != NULL; lapbeth = lapbeth->next)
+	write_lock(&lapbeth_devices_lock);
+
+	list_for_each_safe(entry, tmp, &lapbeth_devices) {
+		lapbeth = list_entry(entry, struct lapbethdev, node);
 		unregister_netdev(&lapbeth->axdev);
+		list_del(&lapbeth->node);
+		lapbeth_put(lapbeth);
+	}
+
+	write_unlock(&lapbeth_devices_lock);
 }
 module_exit(lapbeth_cleanup_driver);
 
 MODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>");
 MODULE_DESCRIPTION("The unofficial LAPB over Ethernet driver");
 MODULE_LICENSE("GPL");
-
-
diff -Nru a/drivers/net/wan/lmc/Makefile b/drivers/net/wan/lmc/Makefile
--- a/drivers/net/wan/lmc/Makefile	Tue Oct  1 00:08:15 2002
+++ b/drivers/net/wan/lmc/Makefile	Tue Oct  1 00:08:15 2002
@@ -18,6 +18,3 @@
 
 include $(TOPDIR)/Rules.make
 
-clean:
-	rm -f core *.o *.a *.s
-
diff -Nru a/drivers/net/wan/lmc/lmc_var.h b/drivers/net/wan/lmc/lmc_var.h
--- a/drivers/net/wan/lmc/lmc_var.h	Tue Oct  1 00:08:17 2002
+++ b/drivers/net/wan/lmc/lmc_var.h	Tue Oct  1 00:08:17 2002
@@ -87,7 +87,7 @@
 		lmc_delay(); \
 		LMC_CSR_WRITE((sc), csr_9, 0x30000); \
                 lmc_delay(); \
-		n--; }} while(0);
+		n--; }} while(0)
 
 struct lmc_regfile_t {
     lmc_csrptr_t csr_busmode;                  /* CSR0 */
diff -Nru a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
--- a/drivers/net/wireless/airo.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/net/wireless/airo.c	Tue Oct  1 00:08:15 2002
@@ -80,6 +80,14 @@
 #include <linux/delay.h>
 #endif
 
+/* Support Cisco MIC feature */
+/* As this feature requires the AES encryption algorithm, it is not included
+   in the kernel tree. If you want to enable it, you need to download the
+   aes.h, aestab.h and mic.h files from the CVS at
+   http://sf.net/projects/airo-linux/ Put the files in the same directory
+   as airo.c and compile normally */
+#undef MICSUPPORT
+
 /* Hack to do some power saving */
 #define POWER_ON_DOWN
 
@@ -276,42 +284,41 @@
 #define NO_PACKET -2
 
 /* Commands */
-#define NOP2 0x00    
-#define MAC_ENABLE 0x01
-#define MAC_ENABLETX 0x101
-#define CMD_ENABLEAUX 0x111
-#define MAC_ENABLERX 0x201   
-#define MAC_DISABLE 0x02    
-#define CMD_LOSE_SYNC 0x03    
-#define CMD_LOSE_SYNC_BSS 0x103
-#define CMD_SOFTRESET 0x04    
-#define HOSTSLEEP 0x05    
-#define CMD_MAGICPACKET 0x06
-#define CMD_SETWAKEMASK 0x07
-#define CMD_SAVECONFIG 0x108   
-#define CMD_READCONFIG 0x08
-#define CMD_SETMODE 0x09    
-#define CMD_ALLOCATETX 0x0A
-#define CMD_TRANSMIT 0x0B    
-#define CMD_DEALLOC 0x0C
-#define CMD_LISTBSS 0x103
-#define NOP 0x10    
-#define CMD_WORKAROUND 0x11
-#define CMD_ACCESS 0x21
-#define CMD_WRITERID 0x121
-#define CMD_PCIBAP 0x22
-#define CMD_PCIAUX 0x23
-#define CMD_ALLOCTLV 0x28
-#define CMD_GETTLV 0x29
-#define CMD_PUTTLV 0x2A
-#define CMD_DELTLV 0x2B    
-#define CMD_FINDNEXTTLV 0x2C    
-#define CMD_SETPHYREG 0x3E
-#define CMD_TXTEST 0x3F    
-#define CMD_NOPSPNODES 0x30    
-#define CMD_USEPSPNODES 0x130
-#define CMD_SETCW 0x31    
-#define CMD_SETPCF 0x32    
+#define NOP2		0x0000
+#define MAC_ENABLE	0x0001
+#define MAC_DISABLE	0x0002
+#define CMD_LOSE_SYNC	0x0003 /* Not sure what this does... */
+#define CMD_SOFTRESET	0x0004
+#define HOSTSLEEP	0x0005
+#define CMD_MAGIC_PKT	0x0006
+#define CMD_SETWAKEMASK	0x0007
+#define CMD_READCFG	0x0008
+#define CMD_SETMODE	0x0009
+#define CMD_ALLOCATETX	0x000a
+#define CMD_TRANSMIT	0x000b
+#define CMD_DEALLOCATETX 0x000c
+#define NOP		0x0010
+#define CMD_WORKAROUND	0x0011
+#define CMD_ACCESS	0x0021
+#define CMD_PCIBAP	0x0022
+#define CMD_PCIAUX	0x0023
+#define CMD_ALLOCBUF	0x0028
+#define CMD_GETTLV	0x0029
+#define CMD_PUTTLV	0x002a
+#define CMD_DELTLV	0x002b
+#define CMD_FINDNEXTTLV	0x002c
+#define CMD_PSPNODES	0x0030
+#define CMD_SETCW	0x0031    
+#define CMD_SETPCF	0x0032    
+#define CMD_SETPHYREG	0x003e
+#define CMD_TXTEST	0x003f
+#define MAC_ENABLETX	0x0101
+#define CMD_LISTBSS	0x0103
+#define CMD_SAVECFG	0x0108
+#define CMD_ENABLEAUX	0x0111
+#define CMD_WRITERID	0x0121
+#define CMD_USEPSPNODES	0x0130
+#define MAC_ENABLERX	0x0201
 
 /* Command errors */
 #define ERROR_QUALIF 0x00
@@ -398,10 +405,10 @@
 #define EV_AWAKE 0x100
 #define EV_UNKNOWN 0x800
 #define EV_MIC 0x1000 /* Message Integrity Check Interrupt */
-#define STATUS_INTS ( EV_AWAKE | EV_LINK | EV_TXEXC | EV_TX | EV_RX)
+#define STATUS_INTS ( EV_AWAKE | EV_LINK | EV_TXEXC | EV_TX | EV_RX | EV_MIC )
 
 #ifdef CHECK_UNKNOWN_INTS
-#define IGNORE_INTS ( EV_MIC | EV_CMD | EV_UNKNOWN)
+#define IGNORE_INTS ( EV_CMD | EV_UNKNOWN)
 #else
 #define IGNORE_INTS (~STATUS_INTS)
 #endif
@@ -433,6 +440,7 @@
 #define RID_UNKNOWN54  0xFF54
 #define RID_UNKNOWN55  0xFF55
 #define RID_UNKNOWN56  0xFF56
+#define RID_MIC        0xFF57
 #define RID_STATS16    0xFF60
 #define RID_STATS16DELTA 0xFF61
 #define RID_STATS16DELTACLEAR 0xFF62
@@ -511,6 +519,7 @@
 #define MODE_ETHER_LLC (1<<12) /* enable ethernet LLC */
 #define MODE_LEAF_NODE (1<<13) /* enable leaf node bridge */
 #define MODE_CF_POLLABLE (1<<14) /* enable CF pollable */
+#define MODE_MIC (1<<15) /* enable MIC */
 	u16 rmode; /* receive mode */
 #define RXMODE_BC_MC_ADDR 0
 #define RXMODE_BC_ADDR 1 /* ignore multicasts */
@@ -682,6 +691,7 @@
 	u16 softCap;
 	u16 bootBlockVer;
 	u16 requiredHard;
+	u16 extSoftCap;
 } CapabilityRid;
 
 typedef struct {
@@ -724,6 +734,37 @@
   tdsRssiEntry x[256];
 } tdsRssiRid;
 
+typedef struct {
+	u16 len;
+	u16 state;
+	u16 multicastValid;
+	u8  multicast[16];
+	u16 unicastValid;
+	u8  unicast[16];
+} MICRid;
+
+typedef struct {
+	u16 typelen;
+
+	union {
+	    u8 snap[8];
+	    struct {
+		u8 dsap;
+		u8 ssap;
+		u8 control;
+		u8 orgcode[3];
+		u8 fieldtype[2];
+	    } llc;
+	} u;
+	u32 mic;
+	u32 seq;
+} MICBuffer;
+
+typedef struct {
+	u8 da[ETH_ALEN];
+	u8 sa[ETH_ALEN];
+} etherHead;
+
 #pragma pack()
 
 #define TXCTL_TXOK (1<<1) /* report if tx is ok */
@@ -768,10 +809,13 @@
 #define AIROGSTAT		8
 #define AIROGSTATSC32		9
 #define AIROGSTATSD32		10
+#define AIROGMICRID		11
+#define AIROGMICSTATS		12
+#define AIROGFLAGS		13
 
 /* Leave gap of 40 commands after AIROGSTATSD32 for future */
 
-#define AIROPCAP		AIROGSTATSD32 + 40
+#define AIROPCAP               	AIROGSTATSD32 + 40
 #define AIROPVLIST              AIROPCAP      + 1
 #define AIROPSLIST		AIROPVLIST    + 1
 #define AIROPCFG		AIROPSLIST    + 1
@@ -803,6 +847,45 @@
 } aironet_ioctl;
 #endif /* CISCO_EXT */
 
+#define NUM_MODULES       2
+#define MIC_MSGLEN_MAX    2400
+#define EMMH32_MSGLEN_MAX MIC_MSGLEN_MAX
+
+typedef struct {
+	u32   size;            // size
+	u8    enabled;         // MIC enabled or not
+	u32   rxSuccess;       // successful packets received
+	u32   rxIncorrectMIC;  // pkts dropped due to incorrect MIC comparison
+	u32   rxNotMICed;      // pkts dropped due to not being MIC'd
+	u32   rxMICPlummed;    // pkts dropped due to not having a MIC plummed
+	u32   rxWrongSequence; // pkts dropped due to sequence number violation
+	u32   reserve[32];
+} mic_statistics;
+
+typedef struct {
+	u32 coeff[((EMMH32_MSGLEN_MAX)+3)>>2];
+	u64 accum;	// accumulated mic, reduced to u32 in final()
+	int position;	// current position (byte offset) in message
+	union {
+		u8  d8[4];
+		u32 d32;
+	} part;	// saves partial message word across update() calls
+} emmh32_context;
+
+typedef struct {
+	emmh32_context seed;	    // Context - the seed
+	u32		 rx;	    // Received sequence number
+	u32		 tx;	    // Tx sequence number
+	u32		 window;    // Start of window
+	u8		 valid;	    // Flag to say if context is valid or not
+	u8		 key[16];
+} miccntx;
+
+typedef struct {
+	miccntx mCtx;		// Multicast context
+	miccntx uCtx;		// Unicast context
+} mic_module;
+
 #ifdef WIRELESS_EXT
 // Frequency list (map channels to frequencies)
 const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
@@ -832,7 +915,7 @@
 #endif	/* WIRELESS_EXT > 12 */
 #endif /* WIRELESS_EXT */
 
-static const char version[] = "airo.c 0.5 (Ben Reed & Javier Achirica)";
+static const char version[] = "airo.c 0.6 (Ben Reed & Javier Achirica)";
 
 struct airo_info;
 
@@ -875,6 +958,12 @@
 static int writerids(struct net_device *dev, aironet_ioctl *comp);
 int flashcard(struct net_device *dev, aironet_ioctl *comp);
 #endif /* CISCO_EXT */
+#ifdef MICSUPPORT
+static void micinit(struct airo_info *ai, MICRid *micr);
+static void micsetup(struct airo_info *ai);
+static int encapsulate(struct airo_info *ai, etherHead *pPacket, MICBuffer *buffer, int len);
+static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *pPacket, u16 payLen);
+#endif
 
 struct airo_info {
 	struct net_device_stats	stats;
@@ -899,6 +988,10 @@
 #define FLAG_RADIO_DOWN 0x08		/* ifup/ifdown disabling of MAC */
 #define FLAG_LOCKED    2		/* 0x04 - use as a bit offset */
 #define FLAG_FLASHING  0x10
+#define FLAG_ADHOC        0x01 /* Needed by MIC */
+#define FLAG_MIC_CAPABLE  0x20
+#define FLAG_UPDATE_MULTI 0x40
+#define FLAG_UPDATE_UNI   0x80
 #define FLAG_802_11    0x200
 	int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen,
 			int whichbap);
@@ -923,6 +1016,10 @@
 	struct iw_quality	spy_stat[IW_MAX_SPY];
 #endif /* WIRELESS_SPY */
 #endif /* WIRELESS_EXT */
+	/* MIC stuff */
+	mic_module		mod[2];
+	mic_statistics		micstats;
+	struct tq_struct 	mic_task;
 };
 
 static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen,
@@ -935,6 +1032,10 @@
 static int takedown_proc_entry( struct net_device *dev,
 				struct airo_info *apriv );
 
+#ifdef MICSUPPORT
+#include "mic.h"
+#endif
+
 static int readBSSListRid(struct airo_info *ai, int first,
 		      BSSListRid *list) {
 	int rc;
@@ -1065,6 +1166,11 @@
 
 	ai->need_commit = 0;
 	checkThrottle(ai);
+	if ((cfgr.opmode & 0xFF) == MODE_STA_IBSS)
+		ai->flags |= FLAG_ADHOC;
+	else
+		ai->flags &= ~FLAG_ADHOC;
+
 	cfgr = ai->config;
 
 	for(s = &cfgr.len; s <= &cfgr.rtsThres; s++) *s = cpu_to_le16(*s);
@@ -1713,6 +1819,24 @@
 }
 #endif
 
+static void airo_read_mic(struct airo_info *ai) {
+	MICRid mic_rid;
+
+	if (down_trylock(&ai->sem) == 0) {
+		__set_bit(FLAG_LOCKED, &ai->flags);
+		PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid));
+		clear_bit(FLAG_LOCKED, &ai->flags);
+		up(&ai->sem);
+#ifdef MICSUPPORT
+		micinit (ai, &mic_rid);
+#endif
+	} else {
+		ai->mic_task.routine = (void (*)(void *))airo_read_mic;
+		ai->mic_task.data = (void *)ai;
+		schedule_task(&ai->mic_task);
+	}
+}
+
 static void airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) {
 	struct net_device *dev = (struct net_device *)dev_id;
 	u16 status;
@@ -1737,6 +1861,10 @@
 			OUT4500( apriv, EVINTEN, 0 );
 		}
 
+		if ( status & EV_MIC ) {
+			OUT4500( apriv, EVACK, EV_MIC );
+			airo_read_mic( apriv );
+		}
 		if ( status & EV_LINK ) {
 #if WIRELESS_EXT > 13
 			union iwreq_data	wrqu;
@@ -1785,6 +1913,7 @@
 				struct task_struct *task = apriv->task;
 				if (task)
 					wake_up_process (task);
+				apriv->flags|=FLAG_UPDATE_UNI|FLAG_UPDATE_MULTI;
 			}
 #if WIRELESS_EXT > 13
 			/* Question : is ASSOCIATED the only status
@@ -1902,7 +2031,26 @@
 
 					bap_read (apriv, buffer + hdrlen/2, len, BAP0);
 				} else {
-					bap_read (apriv, buffer,len + hdrlen,BAP0);
+					MICBuffer micbuf;
+					bap_read (apriv, buffer, ETH_ALEN*2, BAP0);
+					if (apriv->micstats.enabled) {
+						bap_read (apriv,(u16*)&micbuf,sizeof(micbuf),BAP0);
+						if (ntohs(micbuf.typelen) > 0x05DC)
+							bap_setup (apriv, fid, 0x44, BAP0);
+						else {
+							len -= sizeof(micbuf);
+							if (len < 48)
+								len = 48;
+							skb_trim (skb, len + hdrlen);
+						}
+					}
+					bap_read(apriv,buffer+ETH_ALEN,len,BAP0);
+#ifdef MICSUPPORT
+					if (decapsulate(apriv,&micbuf,(etherHead*)buffer,len)) {
+						dev_kfree_skb_irq (skb);
+						len = 0;
+					}
+#endif
 				}
 			}
 			if (len) {
@@ -2122,30 +2270,40 @@
 	up(&ai->sem);
 	if (ai->config.len == 0) {
 		tdsRssiRid rssi_rid;
+		CapabilityRid cap_rid;
 
 		// general configuration (read/modify/write)
 		status = readConfigRid(ai);
 		if ( status != SUCCESS ) return ERROR;
 
+		status = readCapabilityRid(ai, &cap_rid);
+		if ( status != SUCCESS ) return ERROR;
+
 		status = PC4500_readrid(ai,RID_RSSI,&rssi_rid,sizeof(rssi_rid));
 		if ( status == SUCCESS ) {
 			if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL)
 				memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512);
 		}
 		else {
-			CapabilityRid cap_rid;
 			if (ai->rssi) {
 				kfree(ai->rssi);
 				ai->rssi = NULL;
 			}
-			status = readCapabilityRid(ai, &cap_rid);
-			if ((status == SUCCESS) && (cap_rid.softCap & 8))
+			if (cap_rid.softCap & 8)
 				ai->config.rmode |= RXMODE_NORMALIZED_RSSI;
 			else
 				printk(KERN_WARNING "airo: unknown received signal level scale\n");
 		}
 		ai->config.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS;
 
+#ifdef MICSUPPORT
+		if ((cap_rid.len==sizeof(cap_rid)) && (cap_rid.extSoftCap&1)) {
+			ai->config.opmode |= MODE_MIC;
+			ai->flags |= FLAG_MIC_CAPABLE;
+			micsetup(ai);
+		}
+#endif
+
 		/* Save off the MAC */
 		for( i = 0; i < ETH_ALEN; i++ ) {
 			mac[i] = ai->config.macAddr[i];
@@ -2170,8 +2328,6 @@
 				}
 			}
 		}
-		if (auto_wep)
-			ai->config.authType = AUTH_SHAREDKEY;
 		ai->need_commit = 1;
 	}
 
@@ -2539,22 +2695,38 @@
 	u16 payloadLen;
 	Cmd cmd;
 	Resp rsp;
+	int miclen = 0;
 	u16 txFid = len;
+	MICBuffer pMic;
+
 	len >>= 16;
 
 	if (len < ETH_ALEN * 2) {
 		printk( KERN_WARNING "Short packet %d\n", len );
 		return ERROR;
 	}
+	len -= ETH_ALEN * 2;
+
+#ifdef MICSUPPORT
+	if ((ai->flags & FLAG_MIC_CAPABLE) && ai->micstats.enabled && 
+	    (ntohs(((u16 *)pPacket)[6]) != 0x888E)) {
+		if (encapsulate(ai,(etherHead *)pPacket,&pMic,len) != SUCCESS)
+			return ERROR;
+		miclen = sizeof(pMic);
+	}
+#endif
 
 	// packet is destination[6], source[6], payload[len-12]
 	// write the payload length and dst/src/payload
 	if (bap_setup(ai, txFid, 0x0036, BAP1) != SUCCESS) return ERROR;
 	/* The hardware addresses aren't counted as part of the payload, so
 	 * we have to subtract the 12 bytes for the addresses off */
-	payloadLen = cpu_to_le16(len-12);
+	payloadLen = cpu_to_le16(len + miclen);
 	bap_write(ai, &payloadLen, sizeof(payloadLen),BAP1);
-	bap_write(ai, (const u16*)pPacket, len, BAP1);
+	bap_write(ai, (const u16*)pPacket, sizeof(etherHead), BAP1);
+	if (miclen)
+		bap_write(ai, (const u16*)&pMic, miclen, BAP1);
+	bap_write(ai, (const u16*)(pPacket + sizeof(etherHead)), len, BAP1);
 	// issue the transmit command
 	memset( &cmd, 0, sizeof( cmd ) );
 	cmd.cmd = CMD_TRANSMIT;
@@ -3037,10 +3209,11 @@
 					need_reset = 1;
 			ai->config.rmode &= 0xfe00;
 			ai->flags &= ~FLAG_802_11;
+			ai->config.opmode &= 0xFF00;
 			if ( line[0] == 'a' ) {
-				ai->config.opmode = 0;
+				ai->config.opmode |= 0;
 			} else {
-				ai->config.opmode = 1;
+				ai->config.opmode |= 1;
 				if ( line[0] == 'r' ) {
 					ai->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER;
 					ai->flags |= FLAG_802_11;
@@ -3274,10 +3447,10 @@
 		     "DataRates: %d %d %d %d %d %d %d %d\n"
 		     "Channel: %d\n"
 		     "XmitPower: %d\n",
-		     ai->config.opmode == 0 ? "adhoc" :
-		     ai->config.opmode == 1 ? get_rmode(ai->config.rmode):
-		     ai->config.opmode == 2 ? "AP" :
-		     ai->config.opmode == 3 ? "AP RPTR" : "Error",
+		     (ai->config.opmode & 0xFF) == 0 ? "adhoc" :
+		     (ai->config.opmode & 0xFF) == 1 ? get_rmode(ai->config.rmode):
+		     (ai->config.opmode & 0xFF) == 2 ? "AP" :
+		     (ai->config.opmode & 0xFF) == 3 ? "AP RPTR" : "Error",
 		     ai->flags&FLAG_RADIO_OFF ? "off" : "on",
 		     ai->config.nodeName,
 		     ai->config.powerSaveMode == 0 ? "CAM" :
@@ -4335,16 +4508,20 @@
 
 	switch(*uwrq) {
 		case IW_MODE_ADHOC:
-			local->config.opmode = MODE_STA_IBSS;
+			local->config.opmode &= 0xFF00;
+			local->config.opmode |= MODE_STA_IBSS;
 			break;
 		case IW_MODE_INFRA:
-			local->config.opmode = MODE_STA_ESS;
+			local->config.opmode &= 0xFF00;
+			local->config.opmode |= MODE_STA_ESS;
 			break;
 		case IW_MODE_MASTER:
-			local->config.opmode = MODE_AP;
+			local->config.opmode &= 0xFF00;
+			local->config.opmode |= MODE_AP;
 			break;
 		case IW_MODE_REPEAT:
-			local->config.opmode = MODE_AP_RPTR;
+			local->config.opmode &= 0xFF00;
+			local->config.opmode |= MODE_AP_RPTR;
 			break;
 		default:
 			return -EINVAL;
@@ -5637,7 +5814,7 @@
 
 		/* Seperate R/W functions bracket legality here
 		 */
-		if ( com.command <= AIROGSTATSD32 )
+		if ( com.command <= AIROGMICSTATS )
 			rc = readrids(dev,&com);
 		else if ( com.command >= AIROPCAP && com.command <= AIROPLEAPUSR )
 			rc = writerids(dev,&com);
@@ -5730,8 +5907,7 @@
 	switch(comp->command)
 	{
 	case AIROGCAP:      ridcode = RID_CAPABILITIES; break;
-	case AIROGCFG:      ridcode = RID_CONFIG;       break;
-	case AIROPCFG: writeConfigRid ((struct airo_info *)dev->priv);
+	case AIROGCFG: writeConfigRid (ai);
 			    ridcode = RID_CONFIG;       break;
 	case AIROGSLIST:    ridcode = RID_SSID;         break;
 	case AIROGVLIST:    ridcode = RID_APLIST;       break;
@@ -5750,12 +5926,17 @@
 	case AIROGSTAT:     ridcode = RID_STATUS;       break;
 	case AIROGSTATSD32: ridcode = RID_STATSDELTA;   break;
 	case AIROGSTATSC32: ridcode = RID_STATS;        break;
+	case AIROGMICSTATS:
+		if (copy_to_user(comp->data, &ai->micstats,
+				 min((int)comp->len,(int)sizeof(ai->micstats))))
+			return -EFAULT;
+		return 0;
 	default:
 		return -EINVAL;
 		break;
 	}
 
-	PC4500_readrid((struct airo_info *)dev->priv,ridcode,iobuf,sizeof(iobuf));
+	PC4500_readrid(ai,ridcode,iobuf,sizeof(iobuf));
 	/* get the count of bytes in the rid  docs say 1st 2 bytes is it.
 	 * then return it to the user
 	 * 9/22/2000 Honor user given length
@@ -5773,7 +5954,7 @@
 
 static int writerids(struct net_device *dev, aironet_ioctl *comp) {
 	struct airo_info *ai = dev->priv;
-	int  ridcode;
+	int  ridcode, enabled;
 	Resp      rsp;
 	static int (* writer)(struct airo_info *, u16 rid, const void *, int);
 	unsigned char iobuf[2048];
@@ -5793,7 +5974,7 @@
 	case AIROPSIDS:     ridcode = RID_SSID;         break;
 	case AIROPCAP:      ridcode = RID_CAPABILITIES; break;
 	case AIROPAPLIST:   ridcode = RID_APLIST;       break;
-	case AIROPCFG: ((struct airo_info *)dev->priv)->config.len = 0;
+	case AIROPCFG: ai->config.len = 0;
 			    ridcode = RID_CONFIG;       break;
 	case AIROPWEPKEYNV: ridcode = RID_WEP_PERM;     break;
 	case AIROPLEAPUSR:  ridcode = RID_LEAPUSERNAME; break;
@@ -5805,7 +5986,7 @@
 		 * same with MAC off
 		 */
 	case AIROPMACON:
-		if (enable_MAC(dev->priv, &rsp) != 0)
+		if (enable_MAC(ai, &rsp) != 0)
 			return -EIO;
 		return 0;
 
@@ -5814,7 +5995,7 @@
 		 * as disable_MAC. it's probably so short the compiler does not gen one.
 		 */
 	case AIROPMACOFF:
-		disable_MAC(dev->priv);
+		disable_MAC(ai);
 		return 0;
 
 		/* This command merely clears the counts does not actually store any data
@@ -5822,9 +6003,11 @@
 		 * writerid routines.
 		 */
 	case AIROPSTCLR:
-		ridcode = RID_STATSDELTACLEAR;
+		PC4500_readrid(ai,RID_STATSDELTACLEAR,iobuf,sizeof(iobuf));
 
-		PC4500_readrid(dev->priv,ridcode,iobuf,sizeof(iobuf));
+		enabled = ai->micstats.enabled;
+		memset(&ai->micstats,0,sizeof(ai->micstats));
+		ai->micstats.enabled = enabled;
 
 		if (copy_to_user(comp->data, iobuf,
 				 min((int)comp->len, (int)sizeof(iobuf))))
@@ -5839,7 +6022,20 @@
 
 	if (copy_from_user(iobuf,comp->data,comp->len))
 		return -EFAULT;
-	if((*writer)((struct airo_info *)dev->priv, ridcode, iobuf,comp->len))
+
+	if (comp->command == AIROPCFG) {
+		ConfigRid *cfg = (ConfigRid *)iobuf;
+
+		if (ai->flags & FLAG_MIC_CAPABLE)
+			cfg->opmode |= MODE_MIC;
+
+		if ((cfg->opmode & 0xFF) == MODE_STA_IBSS)
+			ai->flags |= FLAG_ADHOC;
+		else
+			ai->flags &= ~FLAG_ADHOC;
+	}
+
+	if((*writer)(ai, ridcode, iobuf,comp->len))
 		return -EIO;
 	return 0;
 }
diff -Nru a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c
--- a/drivers/net/wireless/airport.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/net/wireless/airport.c	Tue Oct  1 00:08:17 2002
@@ -1,4 +1,4 @@
-/* airport.c 0.13
+/* airport.c 0.13a
  *
  * A driver for "Hermes" chipset based Apple Airport wireless
  * card.
@@ -264,7 +264,7 @@
 	kfree(dev);
 }				/* airport_detach */
 
-static char version[] __initdata = "airport.c 0.13 (Benjamin Herrenschmidt <benh@kernel.crashing.org>)";
+static char version[] __initdata = "airport.c 0.13a (Benjamin Herrenschmidt <benh@kernel.crashing.org>)";
 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
 MODULE_DESCRIPTION("Driver for the Apple Airport wireless card.");
 MODULE_LICENSE("Dual MPL/GPL");
diff -Nru a/drivers/net/wireless/hermes.h b/drivers/net/wireless/hermes.h
--- a/drivers/net/wireless/hermes.h	Tue Oct  1 00:08:15 2002
+++ b/drivers/net/wireless/hermes.h	Tue Oct  1 00:08:15 2002
@@ -251,6 +251,18 @@
 	struct hermes_scan_apinfo aps[35];        /* Scan result */
 } __attribute__ ((packed));
 
+#define HERMES_LINKSTATUS_NOT_CONNECTED   (0x0000)  
+#define HERMES_LINKSTATUS_CONNECTED       (0x0001)
+#define HERMES_LINKSTATUS_DISCONNECTED    (0x0002)
+#define HERMES_LINKSTATUS_AP_CHANGE       (0x0003)
+#define HERMES_LINKSTATUS_AP_OUT_OF_RANGE (0x0004)
+#define HERMES_LINKSTATUS_AP_IN_RANGE     (0x0005)
+#define HERMES_LINKSTATUS_ASSOC_FAILED    (0x0006)
+  
+struct hermes_linkstatus {
+	u16 linkstatus;         /* Link status */
+} __attribute__ ((packed));
+
 // #define HERMES_DEBUG_BUFFER 1
 #define HERMES_DEBUG_BUFSIZE 4096
 struct hermes_debug_entry {
diff -Nru a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
--- a/drivers/net/wireless/orinoco.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/net/wireless/orinoco.c	Tue Oct  1 00:08:17 2002
@@ -1,4 +1,4 @@
-/* orinoco.c 0.13	- (formerly known as dldwd_cs.c and orinoco_cs.c)
+/* orinoco.c 0.13a	- (formerly known as dldwd_cs.c and orinoco_cs.c)
  *
  * A driver for Hermes or Prism 2 chipset based PCMCIA wireless
  * adaptors, with Lucent/Agere, Intersil or Symbol firmware.
@@ -316,16 +316,22 @@
  *	o No longer ignore the hard_reset argument to
  *	  alloc_orinocodev().  Oops.
  *
- * v0.12c -> v0.13 - 13 Sep 2002 - David Gibson
+ * v0.12c -> v0.13beta1 - 13 Sep 2002 - David Gibson
  *	o Revert the broken 0.12* locking scheme and go to a new yet
  *	  simpler scheme.
  *	o Do firmware resets only in orinoco_init() and when waking
  *	  the card from hard sleep.
  *
- * v0.13 -> v0.13 - 27 Sep 2002 - David Gibson
+ * v0.13beta1 -> v0.13 - 27 Sep 2002 - David Gibson
  *	o Re-introduced full resets (via schedule_task()) on Tx
  *	  timeout.
  *
+ * v0.13 -> v0.13a - 30 Sep 2002 - David Gibson
+ *	o Minor cleanups to info frame handling.  Add basic support
+ *	  for linkstatus info frames.
+ *	o Include required kernel headers in orinoco.h, to avoid
+ *	  compile problems.
+ *
  * TODO
  *	o New wireless extensions API (patch forthcoming from Moustafa
  *	  Youssef).
@@ -372,6 +378,7 @@
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
 #include <linux/wireless.h>
+#include <linux/tqueue.h>
 
 #include "hermes.h"
 #include "hermes_rid.h"
@@ -1424,6 +1431,7 @@
 		u16 len;
 		u16 type;
 	} __attribute__ ((packed)) info;
+	int len, type;
 	int err;
 
 	/* This is an answer to an INQUIRE command that we did earlier,
@@ -1441,25 +1449,29 @@
 		return;
 	}
 	
-	switch (le16_to_cpu(info.type)) {
+	len = HERMES_RECLEN_TO_BYTES(le16_to_cpu(info.len));
+	type = le16_to_cpu(info.type);
+
+	switch (type) {
 	case HERMES_INQ_TALLIES: {
 		struct hermes_tallies_frame tallies;
 		struct iw_statistics *wstats = &priv->wstats;
-		int len = le16_to_cpu(info.len) - 1;
 		
-		if (len > (sizeof(tallies) / 2)) {
-			DEBUG(1, "%s: tallies frame too long.\n", dev->name);
-			len = sizeof(tallies) / 2;
+		if (len > sizeof(tallies)) {
+			printk(KERN_WARNING "%s: Tallies frame too long (%d bytes)\n",
+			       dev->name, len);
+			len = sizeof(tallies);
 		}
 		
 		/* Read directly the data (no seek) */
-		hermes_read_words(hw, HERMES_DATA1, (void *) &tallies, len);
+		hermes_read_words(hw, HERMES_DATA1, (void *) &tallies,
+				  len / 2); /* FIXME: blech! */
 		
 		/* Increment our various counters */
 		/* wstats->discard.nwid - no wrong BSSID stuff */
 		wstats->discard.code +=
 			le16_to_cpu(tallies.RxWEPUndecryptable);
-		if (len == (sizeof(tallies) / 2))  
+		if (len == sizeof(tallies))  
 			wstats->discard.code +=
 				le16_to_cpu(tallies.RxDiscards_WEPICVError) +
 				le16_to_cpu(tallies.RxDiscards_WEPExcluded);
@@ -1474,9 +1486,54 @@
 #endif /* WIRELESS_EXT > 11 */
 	}
 	break;
+	case HERMES_INQ_LINKSTATUS: {
+		struct hermes_linkstatus linkstatus;
+		u16 newstatus;
+		const char *s;
+		
+		if (len != sizeof(linkstatus)) {
+			printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n",
+			       dev->name, len);
+			break;
+		}
+
+		hermes_read_words(hw, HERMES_DATA1, (void *) &linkstatus,
+				  len / 2);
+		newstatus = le16_to_cpu(linkstatus.linkstatus);
+
+		switch (newstatus) {
+		case HERMES_LINKSTATUS_NOT_CONNECTED:
+			s = "Not Connected";
+                       break;
+               case HERMES_LINKSTATUS_CONNECTED:
+		       s = "Connected";
+                       break;
+               case HERMES_LINKSTATUS_DISCONNECTED:
+		       s = "Disconnected";
+                       break;
+               case HERMES_LINKSTATUS_AP_CHANGE:
+		       s = "AP Changed";
+                       break;
+               case HERMES_LINKSTATUS_AP_OUT_OF_RANGE:
+		       s = "AP Out of Range";
+                       break;
+               case HERMES_LINKSTATUS_AP_IN_RANGE:
+		       s = "AP In Range";
+                       break;
+               case HERMES_LINKSTATUS_ASSOC_FAILED:
+		       s = "Association Failed";
+		       break;
+		default:
+			s = "UNKNOWN";
+		}
+
+		printk(KERN_INFO "%s: New link status: %s (%04x)\n",
+		       dev->name, s, newstatus);
+	}
+	break;
 	default:
-		DEBUG(1, "%s: Unknown information frame received (type %04x).\n",
-		      priv->ndev->name, le16_to_cpu(info.type));
+		printk(KERN_DEBUG "%s: Unknown information frame received (type %04x).\n",
+		      dev->name, type);
 		/* We don't actually do anything about it */
 		break;
 	}
@@ -4206,7 +4263,7 @@
 
 /* Can't be declared "const" or the whole __initdata section will
  * become const */
-static char version[] __initdata = "orinoco.c 0.13 (David Gibson <hermes@gibson.dropbear.id.au> and others)";
+static char version[] __initdata = "orinoco.c 0.13a (David Gibson <hermes@gibson.dropbear.id.au> and others)";
 
 static int __init init_orinoco(void)
 {
diff -Nru a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h
--- a/drivers/net/wireless/orinoco.h	Tue Oct  1 00:08:16 2002
+++ b/drivers/net/wireless/orinoco.h	Tue Oct  1 00:08:16 2002
@@ -7,6 +7,11 @@
 #ifndef _ORINOCO_H
 #define _ORINOCO_H
 
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/tqueue.h>
 #include "hermes.h"
 
 /* To enable debug messages */
diff -Nru a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c
--- a/drivers/net/wireless/orinoco_cs.c	Tue Oct  1 00:08:19 2002
+++ b/drivers/net/wireless/orinoco_cs.c	Tue Oct  1 00:08:19 2002
@@ -1,4 +1,4 @@
-/* orinoco_cs.c 0.13	- (formerly known as dldwd_cs.c)
+/* orinoco_cs.c 0.13a	- (formerly known as dldwd_cs.c)
  *
  * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
  * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/
@@ -32,6 +32,7 @@
 #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>
@@ -693,7 +694,7 @@
 
 /* Can't be declared "const" or the whole __initdata section will
  * become const */
-static char version[] __initdata = "orinoco_cs.c 0.13 (David Gibson <hermes@gibson.dropbear.id.au> and others)";
+static char version[] __initdata = "orinoco_cs.c 0.13a (David Gibson <hermes@gibson.dropbear.id.au> and others)";
 
 static int __init
 init_orinoco_cs(void)
diff -Nru a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c
--- a/drivers/net/wireless/orinoco_pci.c	Tue Oct  1 00:08:18 2002
+++ b/drivers/net/wireless/orinoco_pci.c	Tue Oct  1 00:08:18 2002
@@ -1,4 +1,4 @@
-/* orinoco_pci.c 0.01
+/* orinoco_pci.c 0.13a
  * 
  * Driver for Prism II devices that have a direct PCI interface
  * (i.e., not in a Pcmcia or PLX bridge)
@@ -122,41 +122,6 @@
 #define HERMES_PCI_COR_OFFT	(500)		/* ms */
 #define HERMES_PCI_COR_BUSYT	(500)		/* ms */
 
-MODULE_AUTHOR("Jean Tourrilhes <jt@hpl.hp.com>");
-MODULE_DESCRIPTION("Driver for wireless LAN cards using direct PCI interface");
-MODULE_LICENSE("Dual MPL/GPL");
-
-static int orinoco_pci_open(struct net_device *dev)
-{
-	struct orinoco_private *priv = (struct orinoco_private *) dev->priv;
-	int err;
-
-	netif_device_attach(dev);
-
-	err = orinoco_reset(priv);
-	if (err)
-		printk(KERN_ERR "%s: orinoco_reset failed in orinoco_pci_open()",
-		       dev->name);
-	else
-		netif_start_queue(dev);
-
-	return err;
-}
-
-static int orinoco_pci_stop(struct net_device *dev)
-{
-	struct orinoco_private *priv = (struct orinoco_private *) dev->priv;
-	netif_stop_queue(dev);
-	orinoco_shutdown(priv);
-	return 0;
-}
-
-static void
-orinoco_pci_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	orinoco_interrupt(irq, (struct orinoco_private *)dev_id, regs);
-}
-
 /*
  * Do a soft reset of the PCI card using the Configuration Option Register
  * We need this to get going...
@@ -179,7 +144,6 @@
 
 	TRACE_ENTER(priv->ndev->name);
 
-
 	/* Assert the reset until the card notice */
 	hermes_write_regn(hw, PCI_COR, HERMES_PCI_COR_MASK);
 	printk(KERN_NOTICE "Reset done");
@@ -235,8 +199,6 @@
 	struct net_device *dev = NULL;
 	int netdev_registered = 0;
 
-	TRACE_ENTER("orinoco_pci");
-
 	err = pci_enable_device(pdev);
 	if (err)
 		return -EIO;
@@ -249,7 +211,7 @@
 		goto fail;
 
 	/* Usual setup of structures */
-	dev = alloc_orinocodev(0);
+	dev = alloc_orinocodev(0, NULL);
 	if (! dev) {
 		err = -ENOMEM;
 		goto fail;
@@ -259,9 +221,6 @@
 	dev->base_addr = (int) pci_ioaddr;
         dev->mem_start = (unsigned long) pci_iorange;
         dev->mem_end = ((unsigned long) pci_iorange) + pci_iolen - 1;
-	dev->open = orinoco_pci_open;
-	dev->stop = orinoco_pci_stop;
-/*  	priv->card_reset_handler = orinoco_pci_cor_reset; */
 
 	SET_MODULE_OWNER(dev);
 
@@ -270,9 +229,9 @@
 	       pdev->slot_name, dev->mem_start, dev->mem_end, pci_ioaddr, pdev->irq);
 
 	hermes_struct_init(&(priv->hw), dev->base_addr, HERMES_MEM, HERMES_32BIT_REGSPACING);
-	pci_set_drvdata(pdev, priv);
+	pci_set_drvdata(pdev, dev);
 
-	err = request_irq(pdev->irq, orinoco_pci_interrupt, SA_SHIRQ, dev->name, priv);
+	err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, dev->name, priv);
 	if (err) {
 		printk(KERN_ERR "orinoco_pci: Error allocating IRQ %d.\n", pdev->irq);
 		err = -EBUSY;
@@ -291,32 +250,30 @@
 	priv->firmware_type = FIRMWARE_TYPE_INTERSIL;
 
 	err = register_netdev(dev);
-	if (err)
+	if (err) {
+		printk(KERN_ERR "%s: Failed to register net device\n", dev->name);
 		goto fail;
+	}
 	netdev_registered = 1;
 
-	err = orinoco_proc_dev_init(priv);
+	err = orinoco_proc_dev_init(dev);
 	if (err) {
 		printk(KERN_ERR "%s: Failed to create /proc node\n", dev->name);
 		err = -EIO;
 		goto fail;
 	}
 
-	TRACE_EXIT("orinoco_pci");
-
         return 0;               /* succeeded */
  fail:
-	printk(KERN_DEBUG "orinoco_pci: init_one(), FAIL!\n");
-
-	if (priv) {
-		orinoco_proc_dev_cleanup(priv);
+	if (dev) {
+		orinoco_proc_dev_cleanup(dev);
 		if (netdev_registered)
 			unregister_netdev(dev);
 
 		if (dev->irq)
 			free_irq(dev->irq, priv);
 
-		kfree(priv);
+		kfree(dev);
 	}
 
 	if (pci_ioaddr)
@@ -327,15 +284,13 @@
 
 static void __devexit orinoco_pci_remove_one(struct pci_dev *pdev)
 {
-	struct orinoco_private *priv = pci_get_drvdata(pdev);
-	struct net_device *dev = priv->ndev;
-
-	TRACE_ENTER("orinoco_pci");
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct orinoco_private *priv = dev->priv;
 
-	if (!priv)
+	if (! dev)
 		BUG();
 
-	orinoco_proc_dev_cleanup(priv);
+	orinoco_proc_dev_cleanup(dev);
 
 	unregister_netdev(dev);
 
@@ -345,14 +300,11 @@
 	if (priv->hw.iobase)
 		iounmap((unsigned char *) priv->hw.iobase);
 
-	kfree(priv);
+	kfree(dev);
 
 	pci_disable_device(pdev);
-
-	TRACE_EXIT("orinoco_pci");
 }
 
-
 static struct pci_device_id orinoco_pci_pci_id_table[] __devinitdata = {
 	{0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,},
 	{0,},
@@ -365,10 +317,18 @@
 	.id_table	= orinoco_pci_pci_id_table,
 	.probe		= orinoco_pci_init_one,
 	.remove		= __devexit_p(orinoco_pci_remove_one),
+	.suspend	= 0,
+	.resume		= 0
 };
 
+static char version[] __initdata = "orinoco_pci.c 0.13a (Jean Tourrilhes <jt@hpl.hp.com>)";
+MODULE_AUTHOR("Jean Tourrilhes <jt@hpl.hp.com>");
+MODULE_DESCRIPTION("Driver for wireless LAN cards using direct PCI interface");
+MODULE_LICENSE("Dual MPL/GPL");
+
 static int __init orinoco_pci_init(void)
 {
+	printk(KERN_DEBUG "%s\n", version);
 	return pci_module_init(&orinoco_pci_driver);
 }
 
diff -Nru a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c
--- a/drivers/net/wireless/orinoco_plx.c	Tue Oct  1 00:08:21 2002
+++ b/drivers/net/wireless/orinoco_plx.c	Tue Oct  1 00:08:21 2002
@@ -1,4 +1,4 @@
-/* orinoco_plx.c 0.13
+/* orinoco_plx.c 0.13a
  * 
  * Driver for Prism II devices which would usually be driven by orinoco_cs,
  * but are connected to the PCI bus by a PLX9052. 
@@ -341,7 +341,7 @@
 	.resume		= 0,
 };
 
-static char version[] __initdata = "orinoco_plx.c 0.13 (Daniel Barlow <dan@telent.net>, David Gibson <hermes@gibson.dropbear.id.au>)";
+static char version[] __initdata = "orinoco_plx.c 0.13a (Daniel Barlow <dan@telent.net>, David Gibson <hermes@gibson.dropbear.id.au>)";
 MODULE_AUTHOR("Daniel Barlow <dan@telent.net>");
 MODULE_DESCRIPTION("Driver for wireless LAN cards using the PLX9052 PCI bridge");
 #ifdef MODULE_LICENSE
diff -Nru a/drivers/pci/pool.c b/drivers/pci/pool.c
--- a/drivers/pci/pool.c	Tue Oct  1 00:08:20 2002
+++ b/drivers/pci/pool.c	Tue Oct  1 00:08:20 2002
@@ -139,12 +139,14 @@
 	retval->dev = pdev;
 
 	if (pdev) {
+		int	do_add;
 		spin_lock_irqsave (&pools_lock, flags);
+		do_add = list_empty (&pdev->pools);
 		/* note:  not currently insisting "name" be unique */
-		if (list_empty (&pdev->pools))
-			device_create_file (&pdev->dev, &dev_attr_pools);
 		list_add (&retval->pools, &pdev->pools);
 		spin_unlock_irqrestore (&pools_lock, flags);
+		if (do_add)
+			device_create_file (&pdev->dev, &dev_attr_pools);
 	} else
 		INIT_LIST_HEAD (&retval->pools);
 
diff -Nru a/drivers/pci/quirks.c b/drivers/pci/quirks.c
--- a/drivers/pci/quirks.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/pci/quirks.c	Tue Oct  1 00:08:15 2002
@@ -90,7 +90,7 @@
  *	VIA Apollo KT133 needs PCI latency patch
  *	Made according to a windows driver based patch by George E. Breese
  *	see PCI Latency Adjust on http://www.viahardware.com/download/viatweak.shtm
- *      Also see http://home.tiscalinet.de/au-ja/review-kt133a-1-en.html for
+ *      Also see http://www.au-ja.org/review-kt133a-1-en.phtml for
  *      the info on which Mr Breese based his work.
  *
  *	Updated based on further information from the site and also on
diff -Nru a/drivers/pcmcia/Config.in b/drivers/pcmcia/Config.in
--- a/drivers/pcmcia/Config.in	Tue Oct  1 00:08:17 2002
+++ b/drivers/pcmcia/Config.in	Tue Oct  1 00:08:17 2002
@@ -20,6 +20,7 @@
    fi
    if [ "$CONFIG_ARM" = "y" ]; then
       dep_tristate '  SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA
+      dep_tristate '  SA1111 support' CONFIG_PCMCIA_SA1111 $CONFIG_PCMCIA_SA1100 $CONFIG_SA1111 $CONFIG_PCMCIA
    fi
 fi
 
diff -Nru a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
--- a/drivers/pcmcia/Makefile	Tue Oct  1 00:08:16 2002
+++ b/drivers/pcmcia/Makefile	Tue Oct  1 00:08:16 2002
@@ -14,6 +14,7 @@
 obj-$(CONFIG_TCIC)			+= tcic.o
 obj-$(CONFIG_HD64465_PCMCIA)		+= hd64465_ss.o
 obj-$(CONFIG_PCMCIA_SA1100)		+= sa1100_cs.o
+obj-$(CONFIG_PCMCIA_SA1111)		+= sa1111_cs.o
 
 yenta_socket-objs				:= pci_socket.o yenta.o
 
@@ -21,26 +22,29 @@
 pcmcia_core-objs-$(CONFIG_CARDBUS)		+= cardbus.o
 pcmcia_core-objs				:= $(pcmcia_core-objs-y)
 
+sa1111_cs-objs-y				:= sa1111_generic.o
+sa1111_cs-objs-$(CONFIG_SA1100_ADSBITSY)	+= sa1100_adsbitsy.o
+sa1111_cs-objs-$(CONFIG_ASSABET_NEPONSET)	+= sa1100_neponset.o
+sa1111_cs-objs-$(CONFIG_SA1100_BADGE4)		+= sa1100_badge4.o
+sa1111_cs-objs-$(CONFIG_SA1100_GRAPHICSMASTER)	+= sa1100_graphicsmaster.o
+sa1111_cs-objs-$(CONFIG_SA1100_JORNADA720)	+= sa1100_jornada720.o
+sa1111_cs-objs-$(CONFIG_SA1100_PFS168)		+= sa1100_pfs168.o
+sa1111_cs-objs-$(CONFIG_SA1100_PT_SYSTEM3)	+= sa1100_system3.o
+sa1111_cs-objs-$(CONFIG_SA1100_XP860)		+= sa1100_xp860.o
+sa1111_cs-objs					:= $(sa1111_cs-objs-y)
+
 sa1100_cs-objs-y				:= sa1100_generic.o
-sa1100_cs-objs-$(CONFIG_SA1100_ADSBITSY)	+= sa1100_adsbitsy.o sa1111_generic.o
 sa1100_cs-objs-$(CONFIG_SA1100_ASSABET)		+= sa1100_assabet.o
-sa1100_cs-objs-$(CONFIG_ASSABET_NEPONSET)	+= sa1100_neponset.o sa1111_generic.o
-sa1100_cs-objs-$(CONFIG_SA1100_BADGE4)		+= sa1100_badge4.o sa1111_generic.o
 sa1100_cs-objs-$(CONFIG_SA1100_CERF)		+= sa1100_cerf.o
 sa1100_cs-objs-$(CONFIG_SA1100_FLEXANET)	+= sa1100_flexanet.o
 sa1100_cs-objs-$(CONFIG_SA1100_FREEBIRD)	+= sa1100_freebird.o
-sa1100_cs-objs-$(CONFIG_SA1100_GRAPHICSMASTER)	+= sa1100_graphicsmaster.o sa1111_generic.o
 sa1100_cs-objs-$(CONFIG_SA1100_GRAPHICSCLIENT)	+= sa1100_graphicsclient.o
 sa1100_cs-objs-$(CONFIG_SA1100_H3600)		+= sa1100_h3600.o
-sa1100_cs-objs-$(CONFIG_SA1100_JORNADA720)	+= sa1100_jornada720.o sa1111_generic.o
 sa1100_cs-objs-$(CONFIG_SA1100_PANGOLIN)	+= sa1100_pangolin.o
-sa1100_cs-objs-$(CONFIG_SA1100_PFS168)		+= sa1100_pfs168.o sa1111_generic.o
-sa1100_cs-objs-$(CONFIG_SA1100_PT_SYSTEM3)	+= sa1100_system3.o sa1111_generic.o
 sa1100_cs-objs-$(CONFIG_SA1100_SHANNON)		+= sa1100_shannon.o
 sa1100_cs-objs-$(CONFIG_SA1100_SIMPAD)		+= sa1100_simpad.o
 sa1100_cs-objs-$(CONFIG_SA1100_STORK)		+= sa1100_stork.o
 sa1100_cs-objs-$(CONFIG_SA1100_TRIZEPS) 	+= sa1100_trizeps.o
-sa1100_cs-objs-$(CONFIG_SA1100_XP860)		+= sa1100_xp860.o sa1111_generic.o
 sa1100_cs-objs-$(CONFIG_SA1100_YOPY)		+= sa1100_yopy.o
 sa1100_cs-objs					:= $(sa1100_cs-objs-y)
 
diff -Nru a/drivers/pcmcia/sa1100_adsbitsy.c b/drivers/pcmcia/sa1100_adsbitsy.c
--- a/drivers/pcmcia/sa1100_adsbitsy.c	Tue Oct  1 00:08:21 2002
+++ b/drivers/pcmcia/sa1100_adsbitsy.c	Tue Oct  1 00:08:21 2002
@@ -14,6 +14,7 @@
 #include <linux/init.h>
 
 #include <asm/hardware.h>
+#include <asm/mach-types.h>
 
 #include "sa1100_generic.h"
 #include "sa1111_generic.h"
diff -Nru a/drivers/pcmcia/sa1100_badge4.c b/drivers/pcmcia/sa1100_badge4.c
--- a/drivers/pcmcia/sa1100_badge4.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/pcmcia/sa1100_badge4.c	Tue Oct  1 00:08:15 2002
@@ -19,6 +19,7 @@
 #include <linux/init.h>
 
 #include <asm/hardware.h>
+#include <asm/mach-types.h>
 #include <asm/arch/badge4.h>
 #include <asm/hardware/sa1111.h>
 
diff -Nru a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c
--- a/drivers/pcmcia/sa1100_generic.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/pcmcia/sa1100_generic.c	Tue Oct  1 00:08:17 2002
@@ -110,12 +110,11 @@
  * Call board specific BS value calculation to allow boards
  * to tweak the BS values.
  */
-static int sa1100_pcmcia_set_mecr(int sock)
+static int sa1100_pcmcia_set_mecr(int sock, unsigned int cpu_clock)
 {
 	struct sa1100_pcmcia_socket *skt;
 	u32 mecr;
-	int clock;
-	long flags;
+	unsigned long flags;
 	unsigned int bs;
 
 	if (sock < 0 || sock > SA1100_PCMCIA_MAX_SOCK)
@@ -125,8 +124,7 @@
 
 	local_irq_save(flags);
 
-	clock = cpufreq_get(0);
-	bs = pcmcia_low_level->socket_get_timing(sock, clock, skt->speed_io);
+	bs = pcmcia_low_level->socket_get_timing(sock, cpu_clock, skt->speed_io);
 
 	mecr = MECR;
 	MECR_FAST_SET(mecr, sock, 0);
@@ -652,7 +650,7 @@
     if ( map->speed == 0)
        map->speed = SA1100_PCMCIA_IO_ACCESS;
 
-	sa1100_pcmcia_set_mecr( sock );
+	sa1100_pcmcia_set_mecr(sock, cpufreq_get(0));
   }
 
   if (map->stop == 1)
@@ -741,7 +739,7 @@
 			  map->speed = SA1100_PCMCIA_5V_MEM_ACCESS;
 	  }
 
-	  sa1100_pcmcia_set_mecr( sock );
+	  sa1100_pcmcia_set_mecr(sock, cpufreq_get(0));
 
   }
 
@@ -885,9 +883,8 @@
 {
 	unsigned int sock;
 
-	for (sock = 0; sock < SA1100_PCMCIA_MAX_SOCK; ++sock) {
-		sa1100_pcmcia_set_mecr(sock);
-	}
+	for (sock = 0; sock < SA1100_PCMCIA_MAX_SOCK; ++sock)
+		sa1100_pcmcia_set_mecr(sock, clock);
 }
 
 /* sa1100_pcmcia_notifier()
@@ -904,31 +901,31 @@
 sa1100_pcmcia_notifier(struct notifier_block *nb, unsigned long val,
 		       void *data)
 {
-  struct cpufreq_info *ci = data;
+	struct cpufreq_freqs *freqs = data;
 
-  switch (val) {
-  case CPUFREQ_PRECHANGE:
-    if (ci->new_freq > ci->old_freq) {
-      DEBUG(2, "%s(): new frequency %u.%uMHz > %u.%uMHz, pre-updating\n",
-	    __FUNCTION__,
-	    ci->new_freq / 1000, (ci->new_freq / 100) % 10,
-	    ci->old_freq / 1000, (ci->old_freq / 100) % 10);
-      sa1100_pcmcia_update_mecr(ci->new_freq);
-    }
-    break;
+	switch (val) {
+	case CPUFREQ_PRECHANGE:
+		if (freqs->new > freqs->old) {
+			DEBUG(2, "%s(): new frequency %u.%uMHz > %u.%uMHz, "
+				"pre-updating\n", __FUNCTION__,
+			    freqs->new / 1000, (freqs->new / 100) % 10,
+			    freqs->old / 1000, (freqs->old / 100) % 10);
+			sa1100_pcmcia_update_mecr(freqs->new);
+		}
+		break;
 
-  case CPUFREQ_POSTCHANGE:
-    if (ci->new_freq < ci->old_freq) {
-      DEBUG(2, "%s(): new frequency %u.%uMHz < %u.%uMHz, post-updating\n",
-	    __FUNCTION__,
-	    ci->new_freq / 1000, (ci->new_freq / 100) % 10,
-	    ci->old_freq / 1000, (ci->old_freq / 100) % 10);
-      sa1100_pcmcia_update_mecr(ci->new_freq);
-    }
-    break;
-  }
+	case CPUFREQ_POSTCHANGE:
+		if (freqs->new < freqs->old) {
+			DEBUG(2, "%s(): new frequency %u.%uMHz < %u.%uMHz, "
+				"post-updating\n", __FUNCTION__,
+			    freqs->new / 1000, (freqs->new / 100) % 10,
+			    freqs->old / 1000, (freqs->old / 100) % 10);
+			sa1100_pcmcia_update_mecr(freqs->new);
+		}
+		break;
+	}
 
-  return 0;
+	return 0;
 }
 
 static struct notifier_block sa1100_pcmcia_notifier_block = {
@@ -946,7 +943,7 @@
 	struct pcmcia_init pcmcia_init;
 	struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK];
 	struct pcmcia_state_array state_array;
-	unsigned int i;
+	unsigned int i, cpu_clock;
 	int ret;
 
 	/*
@@ -986,6 +983,8 @@
 		goto shutdown;
 	}
 
+	cpu_clock = cpufreq_get(0);
+
 	/*
 	 * We initialize the MECR to default values here, because we are
 	 * not guaranteed to see a SetIOMap operation at runtime.
@@ -1019,7 +1018,7 @@
 			goto out_err;
 		}
 
-		sa1100_pcmcia_set_mecr( i );
+		sa1100_pcmcia_set_mecr(i, cpu_clock);
 	}
 
 
@@ -1110,7 +1109,7 @@
 	servinfo_t info;
 	int ret, i;
 
-	printk(KERN_INFO "SA-1100 PCMCIA (CS release %s)\n", CS_RELEASE);
+	printk(KERN_INFO "SA11x0 PCMCIA (CS release %s)\n", CS_RELEASE);
 
 	CardServices(GetCardServicesInfo, &info);
 	if (info.Revision != CS_RELEASE_CODE) {
@@ -1127,7 +1126,8 @@
 	}
 
 #ifdef CONFIG_CPU_FREQ
-	ret = cpufreq_register_notifier(&sa1100_pcmcia_notifier_block);
+	ret = cpufreq_register_notifier(&sa1100_pcmcia_notifier_block,
+					CPUFREQ_TRANSITION_NOTIFIER);
 	if (ret < 0) {
 		printk(KERN_ERR "Unable to register CPU frequency change "
 			"notifier (%d)\n", ret);
@@ -1135,15 +1135,9 @@
 	}
 #endif
 
-#ifdef CONFIG_SA1100_ADSBITSY
-	pcmcia_adsbitsy_init();
-#endif
 #ifdef CONFIG_SA1100_ASSABET
 	pcmcia_assabet_init();
 #endif
-#ifdef CONFIG_SA1100_BADGE4
-	pcmcia_badge4_init();
-#endif
 #ifdef CONFIG_SA1100_CERF
 	pcmcia_cerf_init();
 #endif
@@ -1156,24 +1150,9 @@
 #ifdef CONFIG_SA1100_GRAPHICSCLIENT
 	pcmcia_gcplus_init();
 #endif
-#ifdef CONFIG_SA1100_GRAPHICSMASTER
-	pcmcia_graphicsmaster_init();
-#endif
-#ifdef CONFIG_SA1100_JORNADA720
-	pcmcia_jornada720_init();
-#endif
-#ifdef CONFIG_ASSABET_NEPONSET
-	pcmcia_neponset_init();
-#endif
 #ifdef CONFIG_SA1100_PANGOLIN
 	pcmcia_pangolin_init();
 #endif
-#ifdef CONFIG_SA1100_PFS168
-	pcmcia_pfs_init();
-#endif
-#ifdef CONFIG_SA1100_PT_SYSTEM3
-	pcmcia_system3_init();
-#endif
 #ifdef CONFIG_SA1100_SHANNON
 	pcmcia_shannon_init();
 #endif
@@ -1186,9 +1165,6 @@
 #ifdef CONFIG_SA1100_TRIZEPS
 	pcmcia_trizeps_init();
 #endif
-#ifdef CONFIG_SA1100_XP860
-	pcmcia_xp860_init();
-#endif
 #ifdef CONFIG_SA1100_YOPY
 	pcmcia_yopy_init();
 #endif
@@ -1203,15 +1179,9 @@
  */
 static void __exit sa1100_pcmcia_exit(void)
 {
-#ifdef CONFIG_SA1100_ADSBITSY
-	pcmcia_adsbitsy_exit();
-#endif
 #ifdef CONFIG_SA1100_ASSABET
 	pcmcia_assabet_exit();
 #endif
-#ifdef CONFIG_SA1100_BADGE4
-	pcmcia_badge4_exit();
-#endif
 #ifdef CONFIG_SA1100_CERF
 	pcmcia_cerf_exit();
 #endif
@@ -1224,21 +1194,9 @@
 #ifdef CONFIG_SA1100_GRAPHICSCLIENT
 	pcmcia_gcplus_exit();
 #endif
-#ifdef CONFIG_SA1100_GRAPHICSMASTER
-	pcmcia_graphicsmaster_exit();
-#endif
-#ifdef CONFIG_SA1100_JORNADA720
-	pcmcia_jornada720_exit();
-#endif
-#ifdef CONFIG_ASSABET_NEPONSET
-	pcmcia_neponset_exit();
-#endif
 #ifdef CONFIG_SA1100_PANGOLIN
 	pcmcia_pangolin_exit();
 #endif
-#ifdef CONFIG_SA1100_PFS168
-	pcmcia_pfs_exit();
-#endif
 #ifdef CONFIG_SA1100_SHANNON
 	pcmcia_shannon_exit();
 #endif
@@ -1248,9 +1206,6 @@
 #ifdef CONFIG_SA1100_STORK
 	pcmcia_stork_exit();
 #endif
-#ifdef CONFIG_SA1100_XP860
-	pcmcia_xp860_exit();
-#endif
 #ifdef CONFIG_SA1100_YOPY
 	pcmcia_yopy_exit();
 #endif
@@ -1261,7 +1216,7 @@
 	}
 
 #ifdef CONFIG_CPU_FREQ
-	cpufreq_unregister_notifier(&sa1100_pcmcia_notifier_block);
+	cpufreq_unregister_notifier(&sa1100_pcmcia_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
 #endif
 }
 
diff -Nru a/drivers/pcmcia/sa1100_graphicsmaster.c b/drivers/pcmcia/sa1100_graphicsmaster.c
--- a/drivers/pcmcia/sa1100_graphicsmaster.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/pcmcia/sa1100_graphicsmaster.c	Tue Oct  1 00:08:15 2002
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 
 #include <asm/hardware.h>
+#include <asm/mach-types.h>
 
 #include "sa1100_generic.h"
 #include "sa1111_generic.h"
diff -Nru a/drivers/pcmcia/sa1100_jornada720.c b/drivers/pcmcia/sa1100_jornada720.c
--- a/drivers/pcmcia/sa1100_jornada720.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/pcmcia/sa1100_jornada720.c	Tue Oct  1 00:08:17 2002
@@ -9,6 +9,7 @@
 #include <linux/init.h>
 
 #include <asm/hardware.h>
+#include <asm/mach-types.h>
 
 #include "sa1100_generic.h"
 #include "sa1111_generic.h"
diff -Nru a/drivers/pcmcia/sa1100_neponset.c b/drivers/pcmcia/sa1100_neponset.c
--- a/drivers/pcmcia/sa1100_neponset.c	Tue Oct  1 00:08:20 2002
+++ b/drivers/pcmcia/sa1100_neponset.c	Tue Oct  1 00:08:20 2002
@@ -10,21 +10,50 @@
 #include <linux/init.h>
 
 #include <asm/hardware.h>
-#include <asm/arch/assabet.h>
+#include <asm/mach-types.h>
+#include <asm/arch/neponset.h>
 #include <asm/hardware/sa1111.h>
 
 #include "sa1100_generic.h"
 #include "sa1111_generic.h"
 
+/*
+ * Neponset uses the Maxim MAX1600, with the following connections:
+ *
+ *   MAX1600      Neponset
+ *
+ *    A0VCC        SA-1111 GPIO A<1>
+ *    A1VCC        SA-1111 GPIO A<0>
+ *    A0VPP        CPLD NCR A0VPP
+ *    A1VPP        CPLD NCR A1VPP
+ *    B0VCC        SA-1111 GPIO A<2>
+ *    B1VCC        SA-1111 GPIO A<3>
+ *    B0VPP        ground (slot B is CF)
+ *    B1VPP        ground (slot B is CF)
+ *
+ *     VX          VCC (5V)
+ *     VY          VCC3_3 (3.3V)
+ *     12INA       12V
+ *     12INB       ground (slot B is CF)
+ *
+ * The MAX1600 CODE pin is tied to ground, placing the device in 
+ * "Standard Intel code" mode. Refer to the Maxim data sheet for
+ * the corresponding truth table.
+ */
+
 static int neponset_pcmcia_init(struct pcmcia_init *init)
 {
-	/* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
-	PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
-
-	/* MAX1600 to standby mode: */
-	PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
 	NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP);
 
+	/*
+	 * Set GPIO_A<3:0> to be outputs for the MAX1600,
+	 * and switch to standby mode.
+	 */
+	PA_DDR = 0;
+	PA_SDR = 0;
+	PA_DWR = 0;
+	PA_SSR = 0;
+
 	return sa1111_pcmcia_init(init);
 }
 
@@ -35,29 +64,6 @@
 	unsigned int ncr_set, pa_dwr_set;
 	int ret;
 
-	/* Neponset uses the Maxim MAX1600, with the following connections:
-
-	 *   MAX1600      Neponset
-	 *
-	 *    A0VCC        SA-1111 GPIO A<1>
-	 *    A1VCC        SA-1111 GPIO A<0>
-	 *    A0VPP        CPLD NCR A0VPP
-	 *    A1VPP        CPLD NCR A1VPP
-	 *    B0VCC        SA-1111 GPIO A<2>
-	 *    B1VCC        SA-1111 GPIO A<3>
-	 *    B0VPP        ground (slot B is CF)
-	 *    B1VPP        ground (slot B is CF)
-	 *
-	 *     VX          VCC (5V)
-	 *     VY          VCC3_3 (3.3V)
-	 *     12INA       12V
-	 *     12INB       ground (slot B is CF)
-	 *
-	 * The MAX1600 CODE pin is tied to ground, placing the device in 
-	 * "Standard Intel code" mode. Refer to the Maxim data sheet for
-	 * the corresponding truth table.
-	 */
-
 	switch (conf->sock) {
 	case 0:
 		pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
@@ -135,13 +141,13 @@
 {
 	int ret = -ENODEV;
 
-	if (machine_is_assabet() && sa1111)
+	if (machine_is_assabet())
 		ret = sa1100_register_pcmcia(&neponset_pcmcia_ops);
 
 	return ret;
 }
 
-void __exit pcmcia_neponset_exit(void)
+void __devexit pcmcia_neponset_exit(void)
 {
 	sa1100_unregister_pcmcia(&neponset_pcmcia_ops);
 }
diff -Nru a/drivers/pcmcia/sa1100_pfs168.c b/drivers/pcmcia/sa1100_pfs168.c
--- a/drivers/pcmcia/sa1100_pfs168.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/pcmcia/sa1100_pfs168.c	Tue Oct  1 00:08:16 2002
@@ -7,10 +7,11 @@
  */
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/delay.h>
 #include <linux/init.h>
 
-#include <asm/delay.h>
 #include <asm/hardware.h>
+#include <asm/mach-types.h>
 #include <asm/irq.h>
 
 #include "sa1100_generic.h"
diff -Nru a/drivers/pcmcia/sa1100_system3.c b/drivers/pcmcia/sa1100_system3.c
--- a/drivers/pcmcia/sa1100_system3.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/pcmcia/sa1100_system3.c	Tue Oct  1 00:08:17 2002
@@ -31,6 +31,7 @@
 #include <linux/ioport.h>
 
 #include <asm/hardware.h>
+#include <asm/mach-types.h>
 #include <asm/irq.h>
 #include <asm/hardware/sa1111.h>
 
diff -Nru a/drivers/pcmcia/sa1100_xp860.c b/drivers/pcmcia/sa1100_xp860.c
--- a/drivers/pcmcia/sa1100_xp860.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/pcmcia/sa1100_xp860.c	Tue Oct  1 00:08:16 2002
@@ -10,6 +10,7 @@
 #include <linux/init.h>
 
 #include <asm/hardware.h>
+#include <asm/mach-types.h>
 #include <asm/irq.h>
 #include "sa1100_generic.h"
 
diff -Nru a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c
--- a/drivers/pcmcia/sa1111_generic.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/pcmcia/sa1111_generic.c	Tue Oct  1 00:08:16 2002
@@ -5,10 +5,12 @@
  * basically means we handle everything except controlling the
  * power.  Power is machine specific...
  */
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/ioport.h>
 #include <linux/device.h>
+#include <linux/init.h>
 
 #include <asm/hardware.h>
 #include <asm/hardware/sa1111.h>
@@ -21,19 +23,18 @@
 	int irq;
 	const char *str;
 } irqs[] = {
-	{ S0_CD_VALID,    "SA1111 PCMCIA card detect" },
-	{ S0_BVD1_STSCHG, "SA1111 PCMCIA BVD1"        },
-	{ S1_CD_VALID,    "SA1111 CF card detect"     },
-	{ S1_BVD1_STSCHG, "SA1111 CF BVD1"            },
+	{ IRQ_S0_CD_VALID,    "SA1111 PCMCIA card detect" },
+	{ IRQ_S0_BVD1_STSCHG, "SA1111 PCMCIA BVD1"        },
+	{ IRQ_S1_CD_VALID,    "SA1111 CF card detect"     },
+	{ IRQ_S1_BVD1_STSCHG, "SA1111 CF BVD1"            },
 };
 
+static struct sa1111_dev *pcmcia;
+
 int sa1111_pcmcia_init(struct pcmcia_init *init)
 {
 	int i, ret;
 
-	if (!request_mem_region(_PCCR, 512, "PCMCIA"))
-		return -1;
-
 	for (i = ret = 0; i < ARRAY_SIZE(irqs); i++) {
 		set_irq_type(irqs[i].irq, IRQT_FALLING);
 		ret = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
@@ -47,8 +48,6 @@
 			irqs[i].irq, ret);
 		while (i--)
 			free_irq(irqs[i].irq, NULL);
-
-		release_mem_region(_PCCR, 16);
 	}
 
 	return ret ? -1 : 2;
@@ -61,8 +60,6 @@
 	for (i = 0; i < ARRAY_SIZE(irqs); i++)
 		free_irq(irqs[i].irq, NULL);
 
-	release_mem_region(_PCCR, 512);
-
 	return 0;
 }
 
@@ -73,7 +70,7 @@
 	if (state->size < 2)
 		return -1;
 
-	status = PCSR;
+	status = sa1111_readl(pcmcia->mapbase + SA1111_PCSR);
 
 	state->state[0].detect = status & PCSR_S0_DETECT ? 0 : 1;
 	state->state[0].ready  = status & PCSR_S0_READY  ? 1 : 0;
@@ -99,8 +96,8 @@
 	int ret = 0;
 
 	switch (info->sock) {
-	case 0:	info->irq = S0_READY_NINT;	break;
-	case 1: info->irq = S1_READY_NINT;	break;
+	case 0:	info->irq = IRQ_S0_READY_NINT;	break;
+	case 1: info->irq = IRQ_S1_READY_NINT;	break;
 	default: ret = 1;
 	}
 
@@ -109,7 +106,7 @@
 
 int sa1111_pcmcia_configure_socket(const struct pcmcia_configure *conf)
 {
-	unsigned int rst, flt, wait, pse, irq, pccr_mask;
+	unsigned int rst, flt, wait, pse, irq, pccr_mask, val;
 	unsigned long flags;
 
 	switch (conf->sock) {
@@ -118,7 +115,7 @@
 		flt = PCCR_S0_FLT;
 		wait = PCCR_S0_PWAITEN;
 		pse = PCCR_S0_PSE;
-		irq = S0_READY_NINT;
+		irq = IRQ_S0_READY_NINT;
 		break;
 
 	case 1:
@@ -126,7 +123,7 @@
 		flt = PCCR_S1_FLT;
 		wait = PCCR_S1_PWAITEN;
 		pse = PCCR_S1_PSE;
-		irq = S1_READY_NINT;
+		irq = IRQ_S1_READY_NINT;
 		break;
 
 	default:
@@ -159,7 +156,9 @@
 		pccr_mask |= flt;
 
 	local_irq_save(flags);
-	PCCR = (PCCR & ~(pse | flt | wait | rst)) | pccr_mask;
+	val = sa1111_readl(pcmcia->mapbase + SA1111_PCCR);
+	val = (val & ~(pse | flt | wait | rst)) | pccr_mask;
+	sa1111_writel(val, pcmcia->mapbase + SA1111_PCCR);
 	local_irq_restore(flags);
 
 	if (conf->irq)
@@ -179,3 +178,130 @@
 {
 	return 0;
 }
+
+static int pcmcia_probe(struct device *dev)
+{
+	struct sa1111_dev *sadev = SA1111_DEV(dev);
+	unsigned long flags;
+	char *base;
+
+	local_irq_save(flags);
+	if (pcmcia) {
+		local_irq_restore(flags);
+		return -EBUSY;
+	}
+
+	pcmcia = sadev;
+	local_irq_restore(flags);
+
+	if (!request_mem_region(sadev->res.start, 512,
+				SA1111_DRIVER_NAME(sadev)))
+		return -EBUSY;
+
+	base = sadev->mapbase;
+
+	/*
+	 * Initialise the suspend state.
+	 */
+	sa1111_writel(PCSSR_S0_SLEEP | PCSSR_S1_SLEEP, base + SA1111_PCSSR);
+	sa1111_writel(PCCR_S0_FLT | PCCR_S1_FLT, base + SA1111_PCCR);
+
+#ifdef CONFIG_SA1100_ADSBITSY
+	pcmcia_adsbitsy_init();
+#endif
+#ifdef CONFIG_SA1100_BADGE4
+	pcmcia_badge4_init();
+#endif
+#ifdef CONFIG_SA1100_GRAPHICSMASTER
+	pcmcia_graphicsmaster_init();
+#endif
+#ifdef CONFIG_SA1100_JORNADA720
+	pcmcia_jornada720_init();
+#endif
+#ifdef CONFIG_ASSABET_NEPONSET
+	pcmcia_neponset_init();
+#endif
+#ifdef CONFIG_SA1100_PFS168
+	pcmcia_pfs_init();
+#endif
+#ifdef CONFIG_SA1100_PT_SYSTEM3
+	pcmcia_system3_init();
+#endif
+#ifdef CONFIG_SA1100_XP860
+	pcmcia_xp860_init();
+#endif
+	return 0;
+}
+
+static int __devexit pcmcia_remove(struct device *dev)
+{
+	struct sa1111_dev *sadev = SA1111_DEV(dev);
+
+#ifdef CONFIG_SA1100_ADSBITSY
+	pcmcia_adsbitsy_exit();
+#endif
+#ifdef CONFIG_SA1100_BADGE4
+	pcmcia_badge4_exit();
+#endif
+#ifdef CONFIG_SA1100_GRAPHICSMASTER
+	pcmcia_graphicsmaster_exit();
+#endif
+#ifdef CONFIG_SA1100_JORNADA720
+	pcmcia_jornada720_exit();
+#endif
+#ifdef CONFIG_ASSABET_NEPONSET
+	pcmcia_neponset_exit();
+#endif
+#ifdef CONFIG_SA1100_PFS168
+	pcmcia_pfs_exit();
+#endif
+#ifdef CONFIG_SA1100_PT_SYSTEM3
+	pcmcia_system3_exit();
+#endif
+#ifdef CONFIG_SA1100_XP860
+	pcmcia_xp860_exit();
+#endif
+
+	release_mem_region(sadev->res.start, 512);
+	pcmcia = NULL;
+
+	return 0;
+}
+
+static int pcmcia_suspend(struct device *dev, u32 state, u32 level)
+{
+	return 0;
+}
+
+static int pcmcia_resume(struct device *dev, u32 level)
+{
+	return 0;
+}
+
+static struct sa1111_driver pcmcia_driver = {
+	.drv = {
+		.name		= "SA1111 PCMCIA",
+		.bus		= &sa1111_bus_type,
+		.probe		= pcmcia_probe,
+		.remove		= __devexit_p(pcmcia_remove),
+		.suspend	= pcmcia_suspend,
+		.resume		= pcmcia_resume,
+	},
+	.devid			= SA1111_DEVID_PCMCIA,
+};
+
+static int __init sa1111_drv_pcmcia_init(void)
+{
+	return driver_register(&pcmcia_driver.drv);
+}
+
+static void __exit sa1111_drv_pcmcia_exit(void)
+{
+	remove_driver(&pcmcia_driver.drv);
+}
+
+module_init(sa1111_drv_pcmcia_init);
+module_exit(sa1111_drv_pcmcia_exit);
+
+MODULE_DESCRIPTION("SA1111 PCMCIA card socket driver");
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/pnp/isapnp.c b/drivers/pnp/isapnp.c
--- a/drivers/pnp/isapnp.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/pnp/isapnp.c	Tue Oct  1 00:08:17 2002
@@ -2281,7 +2281,9 @@
 EXPORT_SYMBOL(isapnp_register_driver);
 EXPORT_SYMBOL(isapnp_unregister_driver);
 
-static struct device_driver isapnp_device_driver = {};
+static struct device_driver isapnp_device_driver = {
+	.devices = LIST_HEAD_INIT(isapnp_device_driver.devices),
+};
 
 static inline int isapnp_init_device_tree(void)
 {
diff -Nru a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
--- a/drivers/s390/block/dasd.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/s390/block/dasd.c	Tue Oct  1 00:08:17 2002
@@ -292,7 +292,7 @@
 		return -ENODEV;
 	/* Set kdev and the device name. */
 	device->kdev = mk_kdev(gdp->major, gdp->first_minor);
-	strcpy(device->name, gdp->major_name);
+	strcpy(device->name, gdp->disk_name);
 
 	/* Find a discipline for the device. */
 	rc = dasd_find_disc(device);
diff -Nru a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c
--- a/drivers/s390/block/dasd_genhd.c	Tue Oct  1 00:08:18 2002
+++ b/drivers/s390/block/dasd_genhd.c	Tue Oct  1 00:08:18 2002
@@ -34,7 +34,6 @@
 	struct list_head list;
 	int major;
 	struct gendisk disks[DASD_PER_MAJOR];
-	char names[DASD_PER_MAJOR * 8];
 };
 
 /*
@@ -115,8 +114,7 @@
 	list_for_each(l, &dasd_major_info)
 		index += DASD_PER_MAJOR;
 	for (i = 0; i < DASD_PER_MAJOR; i++, index++) {
-		char *name = mi->names + i * 8;
-		mi->disks[i].major_name = name;
+		name = mi->disks[i].disk_name;
 		sprintf(name, "dasd");
 		name += 4;
 		if (index > 701)
diff -Nru a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
--- a/drivers/s390/block/dasd_proc.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/s390/block/dasd_proc.c	Tue Oct  1 00:08:15 2002
@@ -173,7 +173,7 @@
 	minor = devmap->devindex % DASD_PER_MAJOR;
 	len += sprintf(str + len, " at (%3d:%3d)", gdp->major, minor);
 	/* Print device name. */
-	len += sprintf(str + len, " is %-7s", gdp->major_name);
+	len += sprintf(str + len, " is %-7s", gdp->disk_name);
 	/* Print devices features. */
 	substr = (devmap->features & DASD_FEATURE_READONLY) ? "(ro)" : " ";
 	len += sprintf(str + len, "%4s: ", substr);
diff -Nru a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c
--- a/drivers/s390/block/xpram.c	Tue Oct  1 00:08:18 2002
+++ b/drivers/s390/block/xpram.c	Tue Oct  1 00:08:18 2002
@@ -60,7 +60,6 @@
 static xpram_device_t xpram_devices[XPRAM_MAX_DEVS];
 static int xpram_sizes[XPRAM_MAX_DEVS];
 static struct gendisk xpram_disks[XPRAM_MAX_DEVS];
-static char xpram_names[XPRAM_MAX_DEV][8];
 static unsigned long xpram_pages;
 static int xpram_devs;
 static devfs_handle_t xpram_devfs_handle;
@@ -475,8 +474,7 @@
 		disk->first_minor = i;
 		disk->minor_shift = 0;
 		disk->fops = &xpram_devops;
-		sprintf(xpram_names[i], "slram%d", i);
-		disk->major_name = xpram_names[i];
+		sprintf(disk->disk_name, "slram%d", i);
 		set_capacity(disk, xpram_sizes[i] << 1);
 		add_disk(disk);
 	}
diff -Nru a/drivers/sbus/audio/Config.help b/drivers/sbus/audio/Config.help
--- a/drivers/sbus/audio/Config.help	Tue Oct  1 00:08:16 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,24 +0,0 @@
-CONFIG_SPARCAUDIO
-  This driver provides support for the build-in sound devices on most
-  Sun machines. If you want to be able to use this, select this option
-  and one or more of the lowlevel drivers below. See
-  <http://www.dementia.org/~shadow/sparcaudio.html> for more
-  information.
-
-CONFIG_SPARCAUDIO_AMD7930
-  This driver supports the AMD 7930 chip found on sun4c, 4/6xx, and
-  SparcClassic systems.
-
-CONFIG_SPARCAUDIO_CS4231
-  This driver supports the Crystal Semiconductor CS4231 chip found on
-  the SS4, SS5, and Ultras.
-
-CONFIG_SPARCAUDIO_DBRI
-  This driver supports the DBRI audio interface found on the SS10,
-  SS20, Sparcbook 3, and Voyager systems.
-
-CONFIG_SPARCAUDIO_DUMMY
-  This is a pseudo-driver used for debugging and testing the
-  sparcaudio subsystem. Say N unless you want to work on this
-  subsystem.
-
diff -Nru a/drivers/sbus/audio/Config.in b/drivers/sbus/audio/Config.in
--- a/drivers/sbus/audio/Config.in	Tue Oct  1 00:08:19 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,18 +0,0 @@
-#
-# Configuration script for sparcaudio subsystem
-#
-
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-
-   mainmenu_option next_comment
-   comment 'Linux/SPARC audio subsystem (EXPERIMENTAL)'
-
-   tristate 'Audio support (EXPERIMENTAL)' CONFIG_SPARCAUDIO
-   if [ "$CONFIG_SPARC64" != "y" ]; then
-     dep_tristate '  AMD7930 Lowlevel Driver' CONFIG_SPARCAUDIO_AMD7930 $CONFIG_SPARCAUDIO
-     dep_tristate '  DBRI Lowlevel Driver' CONFIG_SPARCAUDIO_DBRI $CONFIG_SPARCAUDIO
-   fi
-   dep_tristate '  CS4231 Lowlevel Driver' CONFIG_SPARCAUDIO_CS4231 $CONFIG_SPARCAUDIO
-   dep_tristate '  Dummy Lowlevel Driver' CONFIG_SPARCAUDIO_DUMMY $CONFIG_SPARCAUDIO
-   endmenu
-fi
diff -Nru a/drivers/sbus/audio/Makefile b/drivers/sbus/audio/Makefile
--- a/drivers/sbus/audio/Makefile	Tue Oct  1 00:08:19 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,16 +0,0 @@
-#
-# Makefile for the kernel SPARC audio drivers.
-#
-# 7 October 2000, Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
-# Rewritten to use lists instead of if-statements.
-#
-
-export-objs	:= audio.o amd7930.o dbri.o
-
-obj-$(CONFIG_SPARCAUDIO)		+= audio.o
-obj-$(CONFIG_SPARCAUDIO_AMD7930)	+= amd7930.o
-obj-$(CONFIG_SPARCAUDIO_DBRI)		+= dbri.o
-obj-$(CONFIG_SPARCAUDIO_CS4231)		+= cs4231.o
-obj-$(CONFIG_SPARCAUDIO_DUMMY)		+= dmy.o
-
-include $(TOPDIR)/Rules.make
diff -Nru a/drivers/sbus/audio/amd7930.c b/drivers/sbus/audio/amd7930.c
--- a/drivers/sbus/audio/amd7930.c	Tue Oct  1 00:08:20 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,1889 +0,0 @@
-/* $Id: amd7930.c,v 1.28 2001/10/13 01:47:29 davem Exp $
- * drivers/sbus/audio/amd7930.c
- *
- * Copyright (C) 1996,1997 Thomas K. Dyas (tdyas@eden.rutgers.edu)
- *
- * This is the lowlevel driver for the AMD7930 audio chip found on all
- * sun4c machines and some sun4m machines.
- *
- * The amd7930 is actually an ISDN chip which has a very simple
- * integrated audio encoder/decoder. When Sun decided on what chip to
- * use for audio, they had the brilliant idea of using the amd7930 and
- * only connecting the audio encoder/decoder pins.
- *
- * Thanks to the AMD engineer who was able to get us the AMD79C30
- * databook which has all the programming information and gain tables.
- *
- * Advanced Micro Devices' Am79C30A is an ISDN/audio chip used in the
- * SparcStation 1+.  The chip provides microphone and speaker interfaces
- * which provide mono-channel audio at 8K samples per second via either
- * 8-bit A-law or 8-bit mu-law encoding.  Also, the chip features an
- * ISDN BRI Line Interface Unit (LIU), I.430 S/T physical interface,
- * which performs basic D channel LAPD processing and provides raw
- * B channel data.  The digital audio channel, the two ISDN B channels,
- * and two 64 Kbps channels to the microprocessor are all interconnected
- * via a multiplexer.
- *
- * This driver interfaces to the Linux HiSax ISDN driver, which performs
- * all high-level Q.921 and Q.931 ISDN functions.  The file is not
- * itself a hardware driver; rather it uses functions exported by
- * the AMD7930 driver in the sparcaudio subsystem (drivers/sbus/audio),
- * allowing the chip to be simultaneously used for both audio and ISDN data.
- * The hardware driver does _no_ buffering, but provides several callbacks
- * which are called during interrupt service and should therefore run quickly.
- *
- * D channel transmission is performed by passing the hardware driver the
- * address and size of an skb's data area, then waiting for a callback
- * to signal successful transmission of the packet.  A task is then
- * queued to notify the HiSax driver that another packet may be transmitted.
- *
- * D channel reception is quite simple, mainly because of:
- *   1) the slow speed of the D channel - 16 kbps, and
- *   2) the presence of an 8- or 32-byte (depending on chip version) FIFO
- *      to buffer the D channel data on the chip
- * Worst case scenario of back-to-back packets with the 8 byte buffer
- * at 16 kbps yields an service time of 4 ms - long enough to preclude
- * the need for fancy buffering.  We queue a background task that copies
- * data out of the receive buffer into an skb, and the hardware driver
- * simply does nothing until we're done with the receive buffer and
- * reset it for a new packet.
- *
- * B channel processing is more complex, because of:
- *   1) the faster speed - 64 kbps,
- *   2) the lack of any on-chip buffering (it interrupts for every byte), and
- *   3) the lack of any chip support for HDLC encapsulation
- *
- * The HiSax driver can put each B channel into one of three modes -
- * L1_MODE_NULL (channel disabled), L1_MODE_TRANS (transparent data relay),
- * and L1_MODE_HDLC (HDLC encapsulation by low-level driver).
- * L1_MODE_HDLC is the most common, used for almost all "pure" digital
- * data sessions.  L1_MODE_TRANS is used for ISDN audio.
- *
- * HDLC B channel transmission is performed via a large buffer into
- * which the skb is copied while performing HDLC bit-stuffing.  A CRC
- * is computed and attached to the end of the buffer, which is then
- * passed to the low-level routines for raw transmission.  Once
- * transmission is complete, the hardware driver is set to enter HDLC
- * idle by successive transmission of mark (all 1) bytes, waiting for
- * the ISDN driver to prepare another packet for transmission and
- * deliver it.
- *
- * HDLC B channel reception is performed via an X-byte ring buffer
- * divided into N sections of X/N bytes each.  Defaults: X=256 bytes, N=4.
- * As the hardware driver notifies us that each section is full, we
- * hand it the next section and schedule a background task to peruse
- * the received section, bit-by-bit, with an HDLC decoder.  As
- * packets are detected, they are copied into a large buffer while
- * decoding HDLC bit-stuffing.  The ending CRC is verified, and if
- * it is correct, we alloc a new skb of the correct length (which we
- * now know), copy the packet into it, and hand it to the upper layers.
- * Optimization: for large packets, we hand the buffer (which also
- * happens to be an skb) directly to the upper layer after an skb_trim,
- * and alloc a new large buffer for future packets, thus avoiding a copy.
- * Then we return to HDLC processing; state is saved between calls.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/version.h>
-#include <linux/soundcard.h>
-#include <asm/openprom.h>
-#include <asm/oplib.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/sbus.h>
-
-#include <asm/audioio.h>
-#include "amd7930.h"
-
-static __u8  bilinear2mulaw(__u8 data);
-static __u8  mulaw2bilinear(__u8 data);
-static __u8  linear2mulaw(__u16 data);
-static __u16 mulaw2linear(__u8 data);
-
-#if defined (AMD79C30_ISDN)
-#include "../../isdn/hisax/hisax.h"
-#include "../../isdn/hisax/isdnl1.h"
-#include "../../isdn/hisax/foreign.h"
-#endif
-
-#define MAX_DRIVERS 1
-
-static struct sparcaudio_driver drivers[MAX_DRIVERS];
-static int num_drivers;
-
-/* Each amd7930 chip has two bi-directional B channels and a D
- * channel available to the uproc.  This structure handles all
- * the buffering needed to transmit and receive via a single channel.
- */
-
-#define CHANNEL_AVAILABLE	0x00
-#define CHANNEL_INUSE_AUDIO_IN	0x01
-#define CHANNEL_INUSE_AUDIO_OUT	0x02
-#define CHANNEL_INUSE_ISDN_B1	0x04
-#define CHANNEL_INUSE_ISDN_B2	0x08
-#define CHANNEL_INUSE		0xff
-
-struct amd7930_channel {
-	/* Channel status */
-	u8 channel_status;
-
-	/* Current buffer that the driver is playing on channel */
-	volatile __u8 * output_ptr;
-	volatile u32 output_count;
-	u8 xmit_idle_char;
-
-	/* Callback routine (and argument) when output is done on */
-	void (*output_callback)(void *, unsigned char);
-	void * output_callback_arg;
-
-	/* Current buffer that the driver is recording on channel */
-	volatile __u8 * input_ptr;
-	volatile u32 input_count;
-	volatile u32 input_limit;
-
-	/* Callback routine (and argument) when input is done on */
-	void (*input_callback)(void *, unsigned char, unsigned long);
-	void * input_callback_arg;
-
-	int input_format;
-	int output_format;
-};
-
-/* Private information we store for each amd7930 chip. */
-struct amd7930_info {
-	struct amd7930_channel D;
-	struct amd7930_channel Bb;
-	struct amd7930_channel Bc;
-
-	/* Pointers to which B channels are being used for what
-	 * These three fields (Baudio, Bisdn[0], and Bisdn[1]) will either
-	 * be NULL or point to one of the Bb/Bc structures above.
-	 */
-	struct amd7930_channel *Baudio;
-	struct amd7930_channel *Bisdn[2];
-
-	/* Device registers information. */
-	unsigned long regs;
-	unsigned long regs_size;
-	struct amd7930_map map;
-
-	/* Volume information. */
-	int pgain, rgain, mgain;
-
-	/* Device interrupt information. */
-	int irq;
-	volatile int ints_on;
-
-	/* Format type */
-	int format_type;
-
-	/* Someone to signal when the ISDN LIU state changes */
-	int liu_state;
-	void (*liu_callback)(void *);
-	void *liu_callback_arg;
-};
-
-/* Output a 16-bit quantity in the order that the amd7930 expects. */
-static __inline__ void amd7930_out16(unsigned long regs, u16 val)
-{
-	sbus_writeb(val & 0xff, regs + DR);
-	sbus_writeb(val >> 8, regs + DR);
-}
-
-/* gx, gr & stg gains.  this table must contain 256 elements with
- * the 0th being "infinity" (the magic value 9008).  The remaining
- * elements match sun's gain curve (but with higher resolution):
- * -18 to 0dB in .16dB steps then 0 to 12dB in .08dB steps.
- */
-static __const__ __u16 gx_coeff[256] = {
-	0x9008, 0x8b7c, 0x8b51, 0x8b45, 0x8b42, 0x8b3b, 0x8b36, 0x8b33,
-	0x8b32, 0x8b2a, 0x8b2b, 0x8b2c, 0x8b25, 0x8b23, 0x8b22, 0x8b22,
-	0x9122, 0x8b1a, 0x8aa3, 0x8aa3, 0x8b1c, 0x8aa6, 0x912d, 0x912b,
-	0x8aab, 0x8b12, 0x8aaa, 0x8ab2, 0x9132, 0x8ab4, 0x913c, 0x8abb,
-	0x9142, 0x9144, 0x9151, 0x8ad5, 0x8aeb, 0x8a79, 0x8a5a, 0x8a4a,
-	0x8b03, 0x91c2, 0x91bb, 0x8a3f, 0x8a33, 0x91b2, 0x9212, 0x9213,
-	0x8a2c, 0x921d, 0x8a23, 0x921a, 0x9222, 0x9223, 0x922d, 0x9231,
-	0x9234, 0x9242, 0x925b, 0x92dd, 0x92c1, 0x92b3, 0x92ab, 0x92a4,
-	0x92a2, 0x932b, 0x9341, 0x93d3, 0x93b2, 0x93a2, 0x943c, 0x94b2,
-	0x953a, 0x9653, 0x9782, 0x9e21, 0x9d23, 0x9cd2, 0x9c23, 0x9baa,
-	0x9bde, 0x9b33, 0x9b22, 0x9b1d, 0x9ab2, 0xa142, 0xa1e5, 0x9a3b,
-	0xa213, 0xa1a2, 0xa231, 0xa2eb, 0xa313, 0xa334, 0xa421, 0xa54b,
-	0xada4, 0xac23, 0xab3b, 0xaaab, 0xaa5c, 0xb1a3, 0xb2ca, 0xb3bd,
-	0xbe24, 0xbb2b, 0xba33, 0xc32b, 0xcb5a, 0xd2a2, 0xe31d, 0x0808,
-	0x72ba, 0x62c2, 0x5c32, 0x52db, 0x513e, 0x4cce, 0x43b2, 0x4243,
-	0x41b4, 0x3b12, 0x3bc3, 0x3df2, 0x34bd, 0x3334, 0x32c2, 0x3224,
-	0x31aa, 0x2a7b, 0x2aaa, 0x2b23, 0x2bba, 0x2c42, 0x2e23, 0x25bb,
-	0x242b, 0x240f, 0x231a, 0x22bb, 0x2241, 0x2223, 0x221f, 0x1a33,
-	0x1a4a, 0x1acd, 0x2132, 0x1b1b, 0x1b2c, 0x1b62, 0x1c12, 0x1c32,
-	0x1d1b, 0x1e71, 0x16b1, 0x1522, 0x1434, 0x1412, 0x1352, 0x1323,
-	0x1315, 0x12bc, 0x127a, 0x1235, 0x1226, 0x11a2, 0x1216, 0x0a2a,
-	0x11bc, 0x11d1, 0x1163, 0x0ac2, 0x0ab2, 0x0aab, 0x0b1b, 0x0b23,
-	0x0b33, 0x0c0f, 0x0bb3, 0x0c1b, 0x0c3e, 0x0cb1, 0x0d4c, 0x0ec1,
-	0x079a, 0x0614, 0x0521, 0x047c, 0x0422, 0x03b1, 0x03e3, 0x0333,
-	0x0322, 0x031c, 0x02aa, 0x02ba, 0x02f2, 0x0242, 0x0232, 0x0227,
-	0x0222, 0x021b, 0x01ad, 0x0212, 0x01b2, 0x01bb, 0x01cb, 0x01f6,
-	0x0152, 0x013a, 0x0133, 0x0131, 0x012c, 0x0123, 0x0122, 0x00a2,
-	0x011b, 0x011e, 0x0114, 0x00b1, 0x00aa, 0x00b3, 0x00bd, 0x00ba,
-	0x00c5, 0x00d3, 0x00f3, 0x0062, 0x0051, 0x0042, 0x003b, 0x0033,
-	0x0032, 0x002a, 0x002c, 0x0025, 0x0023, 0x0022, 0x001a, 0x0021,
-	0x001b, 0x001b, 0x001d, 0x0015, 0x0013, 0x0013, 0x0012, 0x0012,
-	0x000a, 0x000a, 0x0011, 0x0011, 0x000b, 0x000b, 0x000c, 0x000e,
-};
-
-static __const__ __u16 ger_coeff[] = {
-	0x431f, /* 5. dB */
-	0x331f, /* 5.5 dB */
-	0x40dd, /* 6. dB */
-	0x11dd, /* 6.5 dB */
-	0x440f, /* 7. dB */
-	0x411f, /* 7.5 dB */
-	0x311f, /* 8. dB */
-	0x5520, /* 8.5 dB */
-	0x10dd, /* 9. dB */
-	0x4211, /* 9.5 dB */
-	0x410f, /* 10. dB */
-	0x111f, /* 10.5 dB */
-	0x600b, /* 11. dB */
-	0x00dd, /* 11.5 dB */
-	0x4210, /* 12. dB */
-	0x110f, /* 13. dB */
-	0x7200, /* 14. dB */
-	0x2110, /* 15. dB */
-	0x2200, /* 15.9 dB */
-	0x000b, /* 16.9 dB */
-	0x000f  /* 18. dB */
-};
-#define NR_GER_COEFFS (sizeof(ger_coeff) / sizeof(ger_coeff[0]))
-
-/* Enable amd7930 interrupts atomically. */
-static void amd7930_enable_ints(struct amd7930_info *info)
-{
-	unsigned long flags;
-
-	save_and_cli(flags);
-	if (!info->ints_on) {
-		sbus_writeb(AMR_INIT, info->regs + CR);
-		sbus_writeb(AM_INIT_ACTIVE, info->regs + DR);
-		info->ints_on = 1;
-	}
-	restore_flags(flags);
-}
-
-/* Disable amd7930 interrupts atomically. */
-static __inline__ void amd7930_disable_ints(struct amd7930_info *info)
-{
-	unsigned long flags;
-
-	save_and_cli(flags);
-	if (info->ints_on) {
-		sbus_writeb(AMR_INIT, info->regs + CR);
-		sbus_writeb(AM_INIT_ACTIVE | AM_INIT_DISABLE_INTS,
-			    info->regs + DR);
-		info->ints_on = 0;
-	}
-	restore_flags(flags);
-
-}  
-
-/* Idle amd7930 (no interrupts, no audio, no data) */
-static __inline__ void amd7930_idle(struct amd7930_info *info)
-{
-	unsigned long flags;
-
-	save_and_cli(flags);
-	if (info->ints_on) {
-		sbus_writeb(AMR_INIT, info->regs + CR);
-		sbus_writeb(0, info->regs + DR);
-		info->ints_on = 0;
-	}
-	restore_flags(flags);
-}  
-
-/* Commit the local copy of the MAP registers to the amd7930. */
-static void amd7930_write_map(struct sparcaudio_driver *drv)
-{
-	struct amd7930_info *info = (struct amd7930_info *) drv->private;
-	unsigned long        regs = info->regs;
-	struct amd7930_map  *map  = &info->map;
-	unsigned long flags;
-
-	save_and_cli(flags);
-
-	sbus_writeb(AMR_MAP_GX, regs + CR);
-	amd7930_out16(regs, map->gx);
-
-	sbus_writeb(AMR_MAP_GR, regs + CR);
-	amd7930_out16(regs, map->gr);
-
-	sbus_writeb(AMR_MAP_STGR, regs + CR);
-	amd7930_out16(regs, map->stgr);
-
-	sbus_writeb(AMR_MAP_GER, regs + CR);
-	amd7930_out16(regs, map->ger);
-
-	sbus_writeb(AMR_MAP_MMR1, regs + CR);
-	sbus_writeb(map->mmr1, regs + DR);
-
-	sbus_writeb(AMR_MAP_MMR2, regs + CR);
-	sbus_writeb(map->mmr2, regs + DR);
-
-	restore_flags(flags);
-}
-
-/* Update the MAP registers with new settings. */
-static void amd7930_update_map(struct sparcaudio_driver *drv)
-{
-	struct amd7930_info *info = (struct amd7930_info *) drv->private;
-	struct amd7930_map  *map  = &info->map;
-	int level;
-
-	map->gx = gx_coeff[info->rgain];
-	map->stgr = gx_coeff[info->mgain];
-
-	level = (info->pgain * (256 + NR_GER_COEFFS)) >> 8;
-	if (level >= 256) {
-		map->ger = ger_coeff[level - 256];
-		map->gr = gx_coeff[255];
-	} else {
-		map->ger = ger_coeff[0];
-		map->gr = gx_coeff[level];
-	}
-
-	amd7930_write_map(drv);
-}
-
-/* Bit of a hack here - if the HISAX ISDN driver has got INTSTAT debugging
- * turned on, we send debugging characters to the ISDN driver:
- *
- *   i# - Interrupt received - number from 0 to 7 is low three bits of IR
- *   >  - Loaded a single char into the Dchan xmit FIFO
- *   +  - Finished loading an xmit packet into the Dchan xmit FIFO
- *   <  - Read a single char from the Dchan recv FIFO
- *   !  - Finished reading a packet from the Dchan recv FIFO
- *
- * This code needs to be removed if anything other than HISAX uses the ISDN
- * driver, since D.output_callback_arg is assumed to be a certain struct ptr
- */
-
-#ifdef L2FRAME_DEBUG
-
-inline void debug_info(struct amd7930_info *info, char c)
-{
-	struct IsdnCardState *cs;
-
-	if (!info || !info->D.output_callback_arg)
-		return;
-
-	cs = (struct IsdnCardState *) info->D.output_callback_arg;
-
-	if (!cs || !cs->status_write)
-		return;
-
-	if (cs->debug & L1_DEB_INTSTAT) {
-		*(cs->status_write++) = c;
-		if (cs->status_write > cs->status_end)
-			cs->status_write = cs->status_buf;
-	}
-}
-
-#else
-
-#define debug_info(info,c)
-
-#endif
-
-static void fill_D_xmit_fifo(struct amd7930_info *info)
-{
-	/* Send next byte(s) of outgoing data. */
-	while (info->D.output_ptr && info->D.output_count > 0 &&
-               (sbus_readb(info->regs + DSR2) & AMR_DSR2_TBE)) {
-		u8 byte = *(info->D.output_ptr);
-
-		/* Send the next byte and advance buffer pointer. */
-		sbus_writeb(byte, info->regs + DCTB);
-		info->D.output_ptr++;
-		info->D.output_count--;
-
-		debug_info(info, '>');
-        }
-}
-
-static void transceive_Dchannel(struct amd7930_info *info)
-{
-	__u8 dummy;
-
-#define D_XMIT_ERRORS (AMR_DER_COLLISION | AMR_DER_UNRN)
-#define D_RECV_ERRORS (AMR_DER_RABRT | AMR_DER_RFRAME | AMR_DER_FCS | \
-			AMR_DER_OVFL | AMR_DER_UNFL | AMR_DER_OVRN)
-
-	/* Transmit if we can */
-	fill_D_xmit_fifo(info);
-
-	/* Done with the xmit buffer? Notify the midlevel driver. */
-	if (info->D.output_ptr != NULL && info->D.output_count == 0) {
-		info->D.output_ptr = NULL;
-		info->D.output_count = 0;
-		debug_info(info, '+');
-		if (info->D.output_callback)
-			(*info->D.output_callback)
-				(info->D.output_callback_arg,
-				 sbus_readb(info->regs + DER));
-				 /* sbus_readb(info->regs + DER) & D_XMIT_ERRORS); */
-	}
-
-	/* Read the next byte(s) of incoming data. */
-
-	while (sbus_readb(info->regs + DSR2) & AMR_DSR2_RBA) {
-		if (info->D.input_ptr &&
-		    (info->D.input_count < info->D.input_limit)) {
-			/* Get the next byte and advance buffer pointer. */
-			*(info->D.input_ptr) = sbus_readb(info->regs + DCRB);
-			info->D.input_ptr++;
-			info->D.input_count++;
-		} else {
-			/* Overflow - should be detected by chip via RBLR
-			 * so we'll just consume data until we see LBRP
-			 */
-			dummy = sbus_readb(info->regs + DCRB);
-		}
-
-		debug_info(info, '<');
-
-		if (sbus_readb(info->regs + DSR2) & AMR_DSR2_LBRP) {
-			__u8 der;
-
-			/* End of recv packet? Notify the midlevel driver. */
-			debug_info(info, '!');
-			info->D.input_ptr = NULL;
-			der = sbus_readb(info->regs + DER) & D_RECV_ERRORS;
-
-			/* Read receive byte count - advances FIFOs */
-			sbus_writeb(AMR_DLC_DRCR, info->regs + CR);
-			dummy = sbus_readb(info->regs + DR);
-			dummy = sbus_readb(info->regs + DR);
-
-			if (info->D.input_callback)
-				(*info->D.input_callback)
-					(info->D.input_callback_arg, der,
-					 info->D.input_count);
-		}
-
-	}
-}
-
-long amd7930_xmit_idles = 0;
-
-static void transceive_Bchannel(struct amd7930_channel *channel,
-				unsigned long reg)
-{
-	/* Send the next byte of outgoing data. */
-	if (channel->output_ptr && channel->output_count > 0) {
-		u8 byte;
-
-		/* Send the next byte and advance buffer pointer. */
-		switch(channel->output_format) {
-		case AUDIO_ENCODING_ULAW:
-		case AUDIO_ENCODING_ALAW:
-			byte = *(channel->output_ptr);
-			sbus_writeb(byte, reg);
-			break;
-		case AUDIO_ENCODING_LINEAR8:
-			byte = bilinear2mulaw(*(channel->output_ptr));
-			sbus_writeb(byte, reg);
-			break;
-		case AUDIO_ENCODING_LINEAR:
-			if (channel->output_count >= 2) {
-				u16 val = channel->output_ptr[0] << 8;
-
-				val |= channel->output_ptr[1];
-				byte = linear2mulaw(val);
-				sbus_writeb(byte, reg);
-				channel->output_ptr++;
-				channel->output_count--;
-			};
-		};
-		channel->output_ptr++;
-		channel->output_count--;
-
-
-		/* Done with the buffer? Notify the midlevel driver. */
-		if (channel->output_count == 0) {
-			channel->output_ptr = NULL;
-			channel->output_count = 0;
-			if (channel->output_callback)
-				(*channel->output_callback)
-					(channel->output_callback_arg,1);
-		}
-	} else {
-		sbus_writeb(channel->xmit_idle_char, reg);
-		amd7930_xmit_idles++;
-        }
-
-	/* Read the next byte of incoming data. */
-	if (channel->input_ptr && channel->input_count > 0) {
-		/* Get the next byte and advance buffer pointer. */
-		switch(channel->input_format) {
-		case AUDIO_ENCODING_ULAW:
-		case AUDIO_ENCODING_ALAW:
-			*(channel->input_ptr) = sbus_readb(reg);
-			break;
-		case AUDIO_ENCODING_LINEAR8:
-			*(channel->input_ptr) = mulaw2bilinear(sbus_readb(reg));
-			break;
-		case AUDIO_ENCODING_LINEAR:
-			if (channel->input_count >= 2) {
-				u16 val = mulaw2linear(sbus_readb(reg));
-				channel->input_ptr[0] = val >> 8;
-				channel->input_ptr[1] = val & 0xff;
-				channel->input_ptr++;
-				channel->input_count--;
-			} else {
-				*(channel->input_ptr) = 0;
-			}
-		};
-		channel->input_ptr++;
-		channel->input_count--;
-
-		/* Done with the buffer? Notify the midlevel driver. */
-		if (channel->input_count == 0) {
-			channel->input_ptr = NULL;
-			channel->input_count = 0;
-			if (channel->input_callback)
-				(*channel->input_callback)
-					(channel->input_callback_arg, 1, 0);
-		}
-	}
-}
-
-/* Interrupt handler (The chip takes only one byte per interrupt. Grrr!) */
-static void amd7930_interrupt(int irq, void *dev_id, struct pt_regs *intr_regs)
-{
-	struct sparcaudio_driver *drv = (struct sparcaudio_driver *) dev_id;
-	struct amd7930_info *info = (struct amd7930_info *) drv->private;
-	unsigned long regs = info->regs;
-	__u8 ir;
-
-	/* Clear the interrupt. */
-	ir = sbus_readb(regs + IR);
-
-	if (ir & AMR_IR_BBUF) {
-		if (info->Bb.channel_status == CHANNEL_INUSE)
-			transceive_Bchannel(&info->Bb, info->regs + BBTB);
-		if (info->Bc.channel_status == CHANNEL_INUSE)
-			transceive_Bchannel(&info->Bc, info->regs + BCTB);
-	}
-
-	if (ir & (AMR_IR_DRTHRSH | AMR_IR_DTTHRSH | AMR_IR_DSRI)) {
-		debug_info(info, 'i');
-		debug_info(info, '0' + (ir&7));
-		transceive_Dchannel(info);
-	}
-
-	if (ir & AMR_IR_LSRI) {
-		__u8 lsr;
-
-		sbus_writeb(AMR_LIU_LSR, regs + CR);
-		lsr = sbus_readb(regs + DR);
-
-                info->liu_state = (lsr & 0x7) + 2;
-
-                if (info->liu_callback)
-			(*info->liu_callback)(info->liu_callback_arg);
-        }
-}
-
-static int amd7930_open(struct inode * inode, struct file * file,
-			struct sparcaudio_driver *drv)
-{
-	struct amd7930_info *info = (struct amd7930_info *) drv->private;
-
-	switch(MINOR(inode->i_rdev) & 0xf) {
-	case SPARCAUDIO_AUDIO_MINOR:
-		info->format_type = AUDIO_ENCODING_ULAW;
-		break;
-	case SPARCAUDIO_DSP_MINOR:
-		info->format_type = AUDIO_ENCODING_LINEAR8;
-		break;
-	case SPARCAUDIO_DSP16_MINOR:
-		info->format_type = AUDIO_ENCODING_LINEAR;
-		break;
-	};
-
-	MOD_INC_USE_COUNT;
-	return 0;
-}
-
-static void amd7930_release(struct inode * inode, struct file * file,
-			    struct sparcaudio_driver *drv)
-{
-	/* amd7930_disable_ints(drv->private); */
-	MOD_DEC_USE_COUNT;
-}
-
-static void request_Baudio(struct amd7930_info *info)
-{
-	if (info->Bb.channel_status == CHANNEL_AVAILABLE) {
-		info->Bb.channel_status = CHANNEL_INUSE;
-		info->Baudio = &info->Bb;
-
-		/* Multiplexor map - audio (Ba) to Bb */
-		sbus_writeb(AMR_MUX_MCR1, info->regs + CR);
-		sbus_writeb(AM_MUX_CHANNEL_Ba | (AM_MUX_CHANNEL_Bb << 4),
-			    info->regs + DR);
-
-		/* Enable B channel interrupts */
-		sbus_writeb(AMR_MUX_MCR4, info->regs + CR);
-		sbus_writeb(AM_MUX_MCR4_ENABLE_INTS, info->regs + DR);
-	} else if (info->Bc.channel_status == CHANNEL_AVAILABLE) {
-		info->Bc.channel_status = CHANNEL_INUSE;
-		info->Baudio = &info->Bc;
-
-		/* Multiplexor map - audio (Ba) to Bc */
-		sbus_writeb(AMR_MUX_MCR1, info->regs + CR);
-		sbus_writeb(AM_MUX_CHANNEL_Ba | (AM_MUX_CHANNEL_Bc << 4),
-			    info->regs + DR);
-
-		/* Enable B channel interrupts */
-		sbus_writeb(AMR_MUX_MCR4, info->regs + CR);
-		sbus_writeb(AM_MUX_MCR4_ENABLE_INTS, info->regs + DR);
-	}
-}
-
-static void release_Baudio(struct amd7930_info *info)
-{
-	if (info->Baudio) {
-		info->Baudio->channel_status = CHANNEL_AVAILABLE;
-		sbus_writeb(AMR_MUX_MCR1, info->regs + CR);
-		sbus_writeb(0, info->regs + DR);
-		info->Baudio = NULL;
-
-		if (info->Bb.channel_status == CHANNEL_AVAILABLE &&
-		    info->Bc.channel_status == CHANNEL_AVAILABLE) {
-			/* Disable B channel interrupts */
-			sbus_writeb(AMR_MUX_MCR4, info->regs + CR);
-			sbus_writeb(0, info->regs + DR);
-		}
-	}
-}
-
-static void amd7930_start_output(struct sparcaudio_driver *drv,
-				 __u8 * buffer, unsigned long count)
-{
-	struct amd7930_info *info = (struct amd7930_info *) drv->private;
-
-	if (! info->Baudio)
-		request_Baudio(info);
-
-	if (info->Baudio) {
-		info->Baudio->output_ptr = buffer;
-		info->Baudio->output_count = count;
-		info->Baudio->output_format = info->format_type;
-		info->Baudio->output_callback = (void *) &sparcaudio_output_done;
-		info->Baudio->output_callback_arg = (void *) drv;
-		info->Baudio->xmit_idle_char = 0;
-	}
-}
-
-static void amd7930_stop_output(struct sparcaudio_driver *drv)
-{
-	struct amd7930_info *info = (struct amd7930_info *) drv->private;
-
-	if (info->Baudio) {
-		info->Baudio->output_ptr = NULL;
-		info->Baudio->output_count = 0;
-		if (! info->Baudio->input_ptr)
-			release_Baudio(info);
-	}
-}
-
-static void amd7930_start_input(struct sparcaudio_driver *drv,
-				__u8 * buffer, unsigned long count)
-{
-	struct amd7930_info *info = (struct amd7930_info *) drv->private;
-
-	if (! info->Baudio)
-		request_Baudio(info);
-
-	if (info->Baudio) {
-		info->Baudio->input_ptr = buffer;
-		info->Baudio->input_count = count;
-		info->Baudio->input_format = info->format_type;
-		info->Baudio->input_callback = (void *) &sparcaudio_input_done;
-		info->Baudio->input_callback_arg = (void *) drv;
-	}
-}
-
-static void amd7930_stop_input(struct sparcaudio_driver *drv)
-{
-	struct amd7930_info *info = (struct amd7930_info *) drv->private;
-
-	if (info->Baudio) {
-		info->Baudio->input_ptr = NULL;
-		info->Baudio->input_count = 0;
-		if (! info->Baudio->output_ptr)
-			release_Baudio(info);
-	}
-
-}
-
-static void amd7930_sunaudio_getdev(struct sparcaudio_driver *drv,
-				 audio_device_t * audinfo)
-{
-	strncpy(audinfo->name, "SUNW,am79c30", sizeof(audinfo->name) - 1);
-	strncpy(audinfo->version, "a", sizeof(audinfo->version) - 1);
-	strncpy(audinfo->config, "onboard1", sizeof(audinfo->config) - 1);
-}
-
-static int amd7930_sunaudio_getdev_sunos(struct sparcaudio_driver *drv)
-{
-	return AUDIO_DEV_AMD;
-}
-
-static int amd7930_get_formats(struct sparcaudio_driver *drv)
-{
-      return (AFMT_MU_LAW | AFMT_A_LAW | AFMT_U8 | AFMT_S16_BE);
-}
-
-static int amd7930_get_output_ports(struct sparcaudio_driver *drv)
-{
-      return (AUDIO_SPEAKER | AUDIO_HEADPHONE);
-}
-
-static int amd7930_get_input_ports(struct sparcaudio_driver *drv)
-{
-      return (AUDIO_MICROPHONE);
-}
-
-static int amd7930_set_output_volume(struct sparcaudio_driver *drv, int vol)
-{
-	struct amd7930_info *info = (struct amd7930_info *) drv->private;
-
-	info->pgain = vol;
-	amd7930_update_map(drv);
-	return 0;
-}
-
-static int amd7930_get_output_volume(struct sparcaudio_driver *drv)
-{
-	struct amd7930_info *info = (struct amd7930_info *) drv->private;
-
-	return info->pgain;
-}
-
-static int amd7930_set_input_volume(struct sparcaudio_driver *drv, int vol)
-{
-	struct amd7930_info *info = (struct amd7930_info *) drv->private;
-
-	info->rgain = vol;
-	amd7930_update_map(drv);
-	return 0;
-}
-
-static int amd7930_get_input_volume(struct sparcaudio_driver *drv)
-{
-	struct amd7930_info *info = (struct amd7930_info *) drv->private;
-
-	return info->rgain;
-}
-
-static int amd7930_set_monitor_volume(struct sparcaudio_driver *drv, int vol)
-{
-	struct amd7930_info *info = (struct amd7930_info *) drv->private;
-
-	info->mgain = vol;
-	amd7930_update_map(drv);
-	return 0;
-}
-
-static int amd7930_get_monitor_volume(struct sparcaudio_driver *drv)
-{
-      struct amd7930_info *info = (struct amd7930_info *) drv->private;
-
-      return info->mgain;
-}
-
-/* Cheats. The amd has the minimum capabilities we support */
-static int amd7930_get_output_balance(struct sparcaudio_driver *drv)
-{
-	return AUDIO_MID_BALANCE;
-}
-
-static int amd7930_get_input_balance(struct sparcaudio_driver *drv)
-{
-	return AUDIO_MID_BALANCE;
-}
-
-static int amd7930_get_output_channels(struct sparcaudio_driver *drv)
-{
-	return AUDIO_MIN_PLAY_CHANNELS;
-}
-
-static int amd7930_set_output_channels(struct sparcaudio_driver *drv, 
-				       int value)
-{
-  return (value == AUDIO_MIN_PLAY_CHANNELS) ? 0 : -EINVAL;
-}
-
-static int amd7930_get_input_channels(struct sparcaudio_driver *drv)
-{
-	return AUDIO_MIN_REC_CHANNELS;
-}
-
-static int 
-amd7930_set_input_channels(struct sparcaudio_driver *drv, int value)
-{
-	return (value == AUDIO_MIN_REC_CHANNELS) ? 0 : -EINVAL;
-}
-
-static int amd7930_get_output_precision(struct sparcaudio_driver *drv)
-{
-	return AUDIO_MIN_PLAY_PRECISION;
-}
-
-static int 
-amd7930_set_output_precision(struct sparcaudio_driver *drv, int value)
-{
-	return (value == AUDIO_MIN_PLAY_PRECISION) ? 0 : -EINVAL;
-}
-
-static int amd7930_get_input_precision(struct sparcaudio_driver *drv)
-{
-	return AUDIO_MIN_REC_PRECISION;
-}
-
-static int 
-amd7930_set_input_precision(struct sparcaudio_driver *drv, int value)
-{
-	return (value == AUDIO_MIN_REC_PRECISION) ? 0 : -EINVAL;
-}
-
-static int amd7930_get_output_port(struct sparcaudio_driver *drv)
-{
-	struct amd7930_info *info = (struct amd7930_info *) drv->private;
-
-	if (info->map.mmr2 & AM_MAP_MMR2_LS)
-		return AUDIO_SPEAKER; 
-
-	return AUDIO_HEADPHONE;
-}
-
-static int amd7930_set_output_port(struct sparcaudio_driver *drv, int value)
-{
-	struct amd7930_info *info = (struct amd7930_info *) drv->private;
-
-	switch (value) {
-	case AUDIO_HEADPHONE:
-		info->map.mmr2 &= ~AM_MAP_MMR2_LS;
-		break;
-	case AUDIO_SPEAKER:
-		info->map.mmr2 |= AM_MAP_MMR2_LS;
-		break;
-	default:
-		return -EINVAL;
-	};
-
-	amd7930_update_map(drv);
-	return 0;
-}
-
-/* Only a microphone here, so no troubles */
-static int amd7930_get_input_port(struct sparcaudio_driver *drv)
-{
-	return AUDIO_MICROPHONE;
-}
-
-static int amd7930_get_encoding(struct sparcaudio_driver *drv)
-{
-	struct amd7930_info *info = (struct amd7930_info *) drv->private;
-
-	if ((info->map.mmr1 & AM_MAP_MMR1_ALAW) && 
-	    (info->format_type == AUDIO_ENCODING_ALAW))
-		return AUDIO_ENCODING_ALAW;
-
-	return info->format_type;
-}
-
-static int 
-amd7930_set_encoding(struct sparcaudio_driver *drv, int value)
-{
-	struct amd7930_info *info = (struct amd7930_info *) drv->private;
-
-	switch (value) {
-	case AUDIO_ENCODING_ALAW:
-		info->map.mmr1 |= AM_MAP_MMR1_ALAW;
-		break;
-	case AUDIO_ENCODING_LINEAR8:
-	case AUDIO_ENCODING_LINEAR:
-	case AUDIO_ENCODING_ULAW:
-		info->map.mmr1 &= ~AM_MAP_MMR1_ALAW;
-		break;
-	default:
-		return -EINVAL;
-	};
-
-	info->format_type = value;
-
-	amd7930_update_map(drv);
-	return 0;
-}
-
-/* This is what you get. Take it or leave it */
-static int amd7930_get_output_rate(struct sparcaudio_driver *drv)
-{
-	return AMD7930_RATE;
-}
-
-static int 
-amd7930_set_output_rate(struct sparcaudio_driver *drv, int value)
-{
-	return (value == AMD7930_RATE) ? 0 : -EINVAL;
-}
-
-static int amd7930_get_input_rate(struct sparcaudio_driver *drv)
-{
-	return AMD7930_RATE;
-}
-
-static int
-amd7930_set_input_rate(struct sparcaudio_driver *drv, int value)
-{
-	return (value == AMD7930_RATE) ? 0 : -EINVAL;
-}
-
-static int amd7930_get_output_muted(struct sparcaudio_driver *drv)
-{
-      return 0;
-}
-
-static void amd7930_loopback(struct sparcaudio_driver *drv, unsigned int value)
-{
-	struct amd7930_info *info = (struct amd7930_info *) drv->private;
-
-	if (value)
-		info->map.mmr1 |= AM_MAP_MMR1_LOOPBACK;
-	else
-		info->map.mmr1 &= ~AM_MAP_MMR1_LOOPBACK;
-	amd7930_update_map(drv);
-}
-
-static int amd7930_ioctl(struct inode * inode, struct file * file,
-                         unsigned int cmd, unsigned long arg, 
-                         struct sparcaudio_driver *drv)
-{
-	int retval = 0;
-  
-	switch (cmd) {
-	case AUDIO_DIAG_LOOPBACK:
-		amd7930_loopback(drv, (unsigned int)arg);
-		break;
-	default:
-		retval = -EINVAL;
-	};
-
-	return retval;
-}
-
-
-/*
- *       ISDN operations
- *
- * Many of these routines take an "int dev" argument, which is simply
- * an index into the drivers[] array.  Currently, we only support a
- * single AMD 7930 chip, so the value should always be 0.  B channel
- * operations require an "int chan", which should be 0 for channel B1
- * and 1 for channel B2
- *
- * int amd7930_get_irqnum(int dev)
- *
- *   returns the interrupt number being used by the chip.  ISDN4linux
- *   uses this number to watch the interrupt during initialization and
- *   make sure something is happening.
- *
- * int amd7930_get_liu_state(int dev)
- *
- *   returns the current state of the ISDN Line Interface Unit (LIU)
- *   as a number between 2 (state F2) and 7 (state F7).  0 may also be
- *   returned if the chip doesn't exist or the LIU hasn't been
- *   activated.  The meanings of the states are defined in I.430, ISDN
- *   BRI Physical Layer Interface.  The most important two states are
- *   F3 (shutdown) and F7 (syncronized).
- *
- * void amd7930_liu_init(int dev, void (*callback)(), void *callback_arg)
- *
- *   initializes the LIU and optionally registers a callback to be
- *   signaled upon a change of LIU state.  The callback will be called
- *   with a single opaque callback_arg Once the callback has been
- *   triggered, amd7930_get_liu_state can be used to determine the LIU
- *   current state.
- *
- * void amd7930_liu_activate(int dev, int priority)
- *
- *   requests LIU activation at a given D-channel priority.
- *   Successful activatation is achieved upon entering state F7, which
- *   will trigger any callback previously registered with
- *   amd7930_liu_init.
- *
- * void amd7930_liu_deactivate(int dev)
- *
- *   deactivates LIU.  Outstanding D and B channel transactions are
- *   terminated rudely and without callback notification.  LIU change
- *   of state callback will be triggered, however.
- *
- * void amd7930_dxmit(int dev, __u8 *buffer, unsigned int count,
- *               void (*callback)(void *, int), void *callback_arg)
- *
- *   transmits a packet - specified with buffer, count - over the D-channel
- *   interface.  Buffer should begin with the LAPD address field and
- *   end with the information field.  FCS and flag sequences should not
- *   be included, nor is bit-stuffing required - all these functions are
- *   performed by the chip.  The callback function will be called
- *   DURING THE TOP HALF OF AN INTERRUPT HANDLER and will be passed
- *   both the arbitrary callback_arg and an integer error indication:
- *
- *       0 - successful transmission; ready for next packet
- *   non-0 - error value from chip's DER (D-Channel Error Register):
- *       4 - collision detect
- *     128 - underrun; irq routine didn't service chip fast enough
- *
- *   The callback routine should defer any time-consuming operations
- *   to a bottom-half handler; however, amd7930_dxmit may be called
- *   from within the callback to request back-to-back transmission of
- *   a second packet (without repeating the priority/collision mechanism)
- *
- *   A comment about the "collision detect" error, which is signalled
- *   whenever the echoed D-channel data didn't match the transmitted
- *   data.  This is part of ISDN's normal multi-drop T-interface
- *   operation, indicating that another device has attempted simultaneous
- *   transmission, but can also result from line noise.  An immediate
- *   requeue via amd7930_dxmit is suggested, but repeated collision
- *   errors may indicate a more serious problem.
- *
- * void amd7930_drecv(int dev, __u8 *buffer, unsigned int size,
- *               void (*callback)(void *, int, unsigned int),
- *               void *callback_arg)
- *
- *   register a buffer - buffer, size - into which a D-channel packet
- *   can be received.  The callback function will be called DURING
- *   THE TOP HALF OF AN INTERRUPT HANDLER and will be passed an
- *   arbitrary callback_arg, an integer error indication and the length
- *   of the received packet, which will start with the address field,
- *   end with the information field, and not contain flag or FCS
- *   bytes.  Bit-stuffing will already have been corrected for.
- *   Possible values of second callback argument "error":
- *
- *       0 - successful reception
- *   non-0 - error value from chip's DER (D-Channel Error Register):
- *       1 - received packet abort
- *       2 - framing error; non-integer number of bytes received
- *       8 - FCS error; CRC sequence indicated corrupted data
- *      16 - overflow error; packet exceeded size of buffer
- *      32 - underflow error; packet smaller than required five bytes
- *      64 - overrun error; irq routine didn't service chip fast enough
- *
- * int amd7930_bopen(int dev, int chan, u_char xmit_idle_char)
- *
- *   This function should be called before any other operations on a B
- *   channel.  In addition to arranging for interrupt handling and
- *   channel multiplexing, it sets the xmit_idle_char which is
- *   transmitted on the interface when no data buffer is available.
- *   Suggested values are: 0 for ISDN audio; FF for HDLC mark idle; 7E
- *   for HDLC flag idle.  Returns 0 on a successful open; -1 on error,
- *   which is quite possible if audio and the other ISDN channel are
- *   already in use, since the Am7930 can only send two of the three
- *   channels to the processor
- *
- * void amd7930_bclose(int dev, int chan)
- *
- *   Shuts down a B channel when no longer in use.
- *
- * void amd7930_bxmit(int dev, int chan, __u8 *buffer, unsigned int count,
- *               void (*callback)(void *), void *callback_arg)
- *
- *   transmits a raw data block - specified with buffer, count - over
- *   the B channel interface specified by dev/chan.  The callback
- *   function will be called DURING THE TOP HALF OF AN INTERRUPT
- *   HANDLER and will be passed the arbitrary callback_arg
- *
- *   The callback routine should defer any time-consuming operations
- *   to a bottom-half handler; however, amd7930_bxmit may be called
- *   from within the callback to request back-to-back transmission of
- *   another data block
- *
- * void amd7930_brecv(int dev, int chan, __u8 *buffer, unsigned int size,
- *               void (*callback)(void *), void *callback_arg)
- *
- *   receive a raw data block - specified with buffer, size - over the
- *   B channel interface specified by dev/chan.  The callback function
- *   will be called DURING THE TOP HALF OF AN INTERRUPT HANDLER and
- *   will be passed the arbitrary callback_arg
- *
- *   The callback routine should defer any time-consuming operations
- *   to a bottom-half handler; however, amd7930_brecv may be called
- *   from within the callback to register another buffer and ensure
- *   continuous B channel reception without loss of data
- *
- */
-
-#if defined (AMD79C30_ISDN)
-static int amd7930_get_irqnum(int dev)
-{
-	struct amd7930_info *info;
-
-	if (dev > num_drivers)
-		return(0);
-
-	info = (struct amd7930_info *) drivers[dev].private;
-
-	return info->irq;
-}
-
-static int amd7930_get_liu_state(int dev)
-{
-	struct amd7930_info *info;
-
-	if (dev > num_drivers)
-		return(0);
-
-	info = (struct amd7930_info *) drivers[dev].private;
-
-	return info->liu_state;
-}
-
-static void amd7930_liu_init(int dev, void (*callback)(), void *callback_arg)
-{
-	struct amd7930_info *info;
-	unsigned long flags;
-
-	if (dev > num_drivers)
-		return;
-
-	info = (struct amd7930_info *) drivers[dev].private;
-
-	save_and_cli(flags);
-
-	/* Set callback for LIU state change */
-        info->liu_callback = callback;
-	info->liu_callback_arg = callback_arg;
-
-	/* De-activate the ISDN Line Interface Unit (LIU) */
-	sbus_writeb(AMR_LIU_LMR1, info->regs + CR);
-	sbus_writeb(0, info->regs + DR);
-
-	/* Request interrupt when LIU changes state from/to F3/F7/F8 */
-	sbus_writeb(AMR_LIU_LMR2, info->regs + CR);
-	sbus_writeb(AM_LIU_LMR2_EN_F3_INT |
-		    AM_LIU_LMR2_EN_F7_INT |
-		    AM_LIU_LMR2_EN_F8_INT,
-		    info->regs + DR);
-
-	/* amd7930_enable_ints(info); */
-
-	/* Activate the ISDN Line Interface Unit (LIU) */
-	sbus_writeb(AMR_LIU_LMR1, info->regs + CR);
-	sbus_writeb(AM_LIU_LMR1_LIU_ENABL, info->regs + DR);
-
-	restore_flags(flags);
-}
-
-static void amd7930_liu_activate(int dev, int priority)
-{
-	struct amd7930_info *info;
-	unsigned long flags;
-
-	if (dev > num_drivers)
-		return;
-
-	info = (struct amd7930_info *) drivers[dev].private;
-
-	save_and_cli(flags);
-
-        /* Set D-channel access priority
-         *
-         * I.430 defines a priority mechanism based on counting 1s
-         * in the echo channel before transmitting
-         *
-         * Priority 0 is eight 1s; priority 1 is ten 1s; etc
-         */
-        sbus_writeb(AMR_LIU_LPR, info->regs + CR);
-        sbus_writeb(priority & 0x0f, info->regs + DR);
-
-	/* request LIU activation */
-	sbus_writeb(AMR_LIU_LMR1, info->regs + CR);
-	sbus_writeb(AM_LIU_LMR1_LIU_ENABL | AM_LIU_LMR1_REQ_ACTIV,
-		    info->regs + DR);
-
-	restore_flags(flags);
-}
-
-static void amd7930_liu_deactivate(int dev)
-{
-	struct amd7930_info *info;
-	unsigned long flags;
-
-	if (dev > num_drivers)
-		return;
-
-	info = (struct amd7930_info *) drivers[dev].private;
-
-	save_and_cli(flags);
-
-	/* deactivate LIU */
-	sbus_writeb(AMR_LIU_LMR1, info->regs + CR);
-	sbus_writeb(0, info->regs + DR);
-
-	restore_flags(flags);
-}
-
-static void amd7930_dxmit(int dev, __u8 *buffer, unsigned int count,
-			  void (*callback)(void *, int), void *callback_arg)
-{
-	struct amd7930_info *info;
-	unsigned long flags;
-	__u8 dmr1;
-
-	if (dev > num_drivers)
-		return;
-
-	info = (struct amd7930_info *) drivers[dev].private;
-
-	save_and_cli(flags);
-
-	if (info->D.output_ptr) {
-		restore_flags(flags);
-		printk("amd7930_dxmit: transmitter in use\n");
-		return;
-	}
-
-	info->D.output_ptr = buffer;
-	info->D.output_count = count;
-	info->D.output_callback = callback;
-	info->D.output_callback_arg = callback_arg;
-
-	/* Enable D-channel Transmit Threshold interrupt; disable addressing */
-	sbus_writeb(AMR_DLC_DMR1, info->regs + CR);
-	dmr1 = sbus_readb(info->regs + DR);
-	dmr1 |= AMR_DLC_DMR1_DTTHRSH_INT;
-	dmr1 &= ~AMR_DLC_DMR1_EN_ADDRS;
-	sbus_writeb(dmr1, info->regs + DR);
-
-	/* Begin xmit by setting D-channel Transmit Byte Count Reg (DTCR) */
-	sbus_writeb(AMR_DLC_DTCR, info->regs + CR);
-	sbus_writeb(count & 0xff, info->regs + DR);
-	sbus_writeb((count >> 8) & 0xff, info->regs + DR);
-
-	/* Prime xmit FIFO */
-	/* fill_D_xmit_fifo(info); */
-	transceive_Dchannel(info);
-
-	restore_flags(flags);
-}
-
-static void amd7930_drecv(int dev, __u8 *buffer, unsigned int size,
-			  void (*callback)(void *, int, unsigned int),
-			  void *callback_arg)
-{
-	struct amd7930_info *info;
-	unsigned long flags;
-	__u8 dmr1;
-
-	if (dev > num_drivers)
-		return;
-
-	info = (struct amd7930_info *) drivers[dev].private;
-
-	save_and_cli(flags);
-
-	if (info->D.input_ptr) {
-		restore_flags(flags);
-		printk("amd7930_drecv: receiver already has buffer!\n");
-		return;
-	}
-
-	info->D.input_ptr = buffer;
-	info->D.input_count = 0;
-	info->D.input_limit = size;
-	info->D.input_callback = callback;
-	info->D.input_callback_arg = callback_arg;
-
-	/* Enable D-channel Receive Threshold interrupt;
-	 * Enable D-channel End of Receive Packet interrupt;
-	 * Disable address recognition
-	 */
-	sbus_writeb(AMR_DLC_DMR1, info->regs + CR);
-	dmr1 = sbus_readb(info->regs + DR);
-	dmr1 |= AMR_DLC_DMR1_DRTHRSH_INT | AMR_DLC_DMR1_EORP_INT;
-	dmr1 &= ~AMR_DLC_DMR1_EN_ADDRS;
-	sbus_writeb(dmr1, info->regs + DR);
-
-	/* Set D-channel Receive Byte Count Limit Register */
-	sbus_writeb(AMR_DLC_DRCR, info->regs + CR);
-	sbus_writeb(size & 0xff, info->regs + DR);
-	sbus_writeb((size >> 8) & 0xff, info->regs + DR);
-
-	restore_flags(flags);
-}
-
-static int amd7930_bopen(int dev, unsigned int chan, 
-                         int mode, u_char xmit_idle_char)
-{
-	struct amd7930_info *info;
-	unsigned long flags;
-	u8 tmp;
-
-	if (dev > num_drivers || chan<0 || chan>1)
-		return -1;
-
-	if (mode == L1_MODE_HDLC)
-		return -1;
- 
-	info = (struct amd7930_info *) drivers[dev].private;
-
-	save_and_cli(flags);
-
-	if (info->Bb.channel_status == CHANNEL_AVAILABLE) {
-		info->Bb.channel_status = CHANNEL_INUSE;
-		info->Bb.xmit_idle_char = xmit_idle_char;
-		info->Bisdn[chan] = &info->Bb;
-
-		/* Multiplexor map - isdn (B1/2) to Bb */
-		sbus_writeb(AMR_MUX_MCR2 + chan, info->regs + CR);
-		sbus_writeb((AM_MUX_CHANNEL_B1 + chan) |
-			    (AM_MUX_CHANNEL_Bb << 4),
-			    info->regs + DR);
-	} else if (info->Bc.channel_status == CHANNEL_AVAILABLE) {
-		info->Bc.channel_status = CHANNEL_INUSE;
-		info->Bc.xmit_idle_char = xmit_idle_char;
-		info->Bisdn[chan] = &info->Bc;
-
-		/* Multiplexor map - isdn (B1/2) to Bc */
-		sbus_writeb(AMR_MUX_MCR2 + chan, info->regs + CR);
-		sbus_writeb((AM_MUX_CHANNEL_B1 + chan) |
-			    (AM_MUX_CHANNEL_Bc << 4),
-			    info->regs + DR);
-	} else {
-		restore_flags(flags);
-		return (-1);
-	}
-
-	/* Enable B channel transmit */
-	sbus_writeb(AMR_LIU_LMR1, info->regs + CR);
-	tmp = sbus_readb(info->regs + DR);
-	tmp |= AM_LIU_LMR1_B1_ENABL + chan;
-	sbus_writeb(tmp, info->regs + DR);
-
-	/* Enable B channel interrupts */
-	sbus_writeb(AMR_MUX_MCR4, info->regs + CR);
-	sbus_writeb(AM_MUX_MCR4_ENABLE_INTS |
-		    AM_MUX_MCR4_REVERSE_Bb |
-		    AM_MUX_MCR4_REVERSE_Bc,
-		    info->regs + DR);
-
-	restore_flags(flags);
-	return 0;
-}
-
-static void amd7930_bclose(int dev, unsigned int chan)
-{
-	struct amd7930_info *info;
-	unsigned long flags;
-
-	if (dev > num_drivers || chan<0 || chan>1)
-		return;
-
-	info = (struct amd7930_info *) drivers[dev].private;
-
-	save_and_cli(flags);
-
-	if (info->Bisdn[chan]) {
-		u8 tmp;
-
-		info->Bisdn[chan]->channel_status = CHANNEL_AVAILABLE;
-
-		sbus_writeb(AMR_MUX_MCR2 + chan, info->regs + CR);
-		sbus_writeb(0, info->regs + DR);
-
-		info->Bisdn[chan] = NULL;
-
-		/* Disable B channel transmit */
-		sbus_writeb(AMR_LIU_LMR1, info->regs + CR);
-		tmp = sbus_readb(info->regs + DR);
-		tmp &= ~(AM_LIU_LMR1_B1_ENABL + chan);
-		sbus_writeb(tmp, info->regs + DR);
-
-		if (info->Bb.channel_status == CHANNEL_AVAILABLE &&
-		    info->Bc.channel_status == CHANNEL_AVAILABLE) {
-			/* Disable B channel interrupts */
-			sbus_writeb(AMR_MUX_MCR4, info->regs + CR);
-			sbus_writeb(0, info->regs + DR);
-		}
-	}
-
-	restore_flags(flags);
-}
-
-static void amd7930_bxmit(int dev, unsigned int chan,
-                          __u8 * buffer, unsigned long count,
-			  void (*callback)(void *, int), void *callback_arg)
-{
-	struct amd7930_info *info;
-	struct amd7930_channel *Bchan;
-	unsigned long flags;
-
-	if (dev > num_drivers)
-		return;
-
-	info = (struct amd7930_info *) drivers[dev].private;
-	Bchan = info->Bisdn[chan];
-
-	if (Bchan) {
-		save_and_cli(flags);
-
-		Bchan->output_ptr = buffer;
-		Bchan->output_count = count;
-		Bchan->output_format = AUDIO_ENCODING_ULAW;
-	        Bchan->output_callback = (void *) callback;
-        	Bchan->output_callback_arg = callback_arg;
-
-		restore_flags(flags);
-	}
-}
-
-static void amd7930_brecv(int dev, unsigned int chan, 
-                          __u8 * buffer, unsigned long size,
-                          void (*callback)(void *, int, unsigned int),
-                          void *callback_arg)
-{
-	struct amd7930_info *info;
-	struct amd7930_channel *Bchan;
-	unsigned long flags;
-
-	if (dev > num_drivers)
-		return;
-
-	info = (struct amd7930_info *) drivers[dev].private;
-	Bchan = info->Bisdn[chan];
-
-	if (Bchan) {
-		save_and_cli(flags);
-
-		Bchan->input_ptr = buffer;
-		Bchan->input_count = size;
-		Bchan->input_format = AUDIO_ENCODING_ULAW;
-		Bchan->input_callback = (void *) callback;
-		Bchan->input_callback_arg = callback_arg;
-
-		restore_flags(flags);
-	}
-}
-
-struct foreign_interface amd7930_foreign_interface = {
-        amd7930_get_irqnum,
-        amd7930_get_liu_state,
-        amd7930_liu_init,
-        amd7930_liu_activate,
-        amd7930_liu_deactivate,
-        amd7930_dxmit,
-        amd7930_drecv,
-        amd7930_bopen,
-        amd7930_bclose,
-        amd7930_bxmit,
-        amd7930_brecv
-};
-EXPORT_SYMBOL(amd7930_foreign_interface);
-#endif
-
-
-/*
- *	Device detection and initialization.
- */
-
-static struct sparcaudio_operations amd7930_ops = {
-	amd7930_open,
-	amd7930_release,
-	amd7930_ioctl,
-	amd7930_start_output,
-	amd7930_stop_output,
-	amd7930_start_input,
-	amd7930_stop_input,
-	amd7930_sunaudio_getdev,
-	amd7930_set_output_volume,
-	amd7930_get_output_volume,
-	amd7930_set_input_volume,
-	amd7930_get_input_volume,
-	amd7930_set_monitor_volume,
-	amd7930_get_monitor_volume,
-	NULL,			/* amd7930_set_output_balance */
-	amd7930_get_output_balance,
-	NULL,			/* amd7930_set_input_balance */
-	amd7930_get_input_balance,
-	amd7930_set_output_channels,
-	amd7930_get_output_channels,
-	amd7930_set_input_channels,
-	amd7930_get_input_channels,
-	amd7930_set_output_precision,
-	amd7930_get_output_precision,
-	amd7930_set_input_precision,
-	amd7930_get_input_precision,
-	amd7930_set_output_port,
-	amd7930_get_output_port,
-	NULL,			/* amd7930_set_input_port */
-	amd7930_get_input_port,
-	amd7930_set_encoding,
-	amd7930_get_encoding,
-	amd7930_set_encoding,
-	amd7930_get_encoding,
-	amd7930_set_output_rate,
-	amd7930_get_output_rate,
-	amd7930_set_input_rate,
-	amd7930_get_input_rate,
-	amd7930_sunaudio_getdev_sunos,
-	amd7930_get_output_ports,
-	amd7930_get_input_ports,
-	NULL,                    /* amd7930_set_output_muted */
-	amd7930_get_output_muted,
-        NULL,                   /* amd7930_set_output_pause */
-        NULL,                   /* amd7930_get_output_pause */
-        NULL,                   /* amd7930_set_input_pause */
-        NULL,                   /* amd7930_get_input_pause */
-        NULL,                   /* amd7930_set_output_samples */
-        NULL,                   /* amd7930_get_output_samples */
-        NULL,                   /* amd7930_set_input_samples */
-        NULL,                   /* amd7930_get_input_samples */
-        NULL,                   /* amd7930_set_output_error */
-        NULL,                   /* amd7930_get_output_error */
-        NULL,                   /* amd7930_set_input_error */
-        NULL,                   /* amd7930_get_input_error */
-        amd7930_get_formats,
-};
-
-/* Attach to an amd7930 chip given its PROM node. */
-static int amd7930_attach(struct sparcaudio_driver *drv, int node,
-			  struct sbus_bus *sbus, struct sbus_dev *sdev)
-{
-	struct linux_prom_registers regs;
-	struct linux_prom_irqs irq;
-	struct resource res, *resp;
-	struct amd7930_info *info;
-	int err;
-
-	/* Allocate our private information structure. */
-	drv->private = kmalloc(sizeof(struct amd7930_info), GFP_KERNEL);
-	if (drv->private == NULL)
-		return -ENOMEM;
-
-	/* Point at the information structure and initialize it. */
-	drv->ops = &amd7930_ops;
-	info = (struct amd7930_info *)drv->private;
-	memset(info, 0, sizeof(*info));
-	info->ints_on = 1; /* force disable below */
-
-	drv->dev = sdev;
-
-	/* Map the registers into memory. */
-	prom_getproperty(node, "reg", (char *)&regs, sizeof(regs));
-	if (sbus && sdev) {
-		resp = &sdev->resource[0];
-	} else {
-		resp = &res;
-		res.start = regs.phys_addr;
-		res.end = res.start + regs.reg_size - 1;
-		res.flags = IORESOURCE_IO | (regs.which_io & 0xff);
-	}
-	info->regs_size = regs.reg_size;
-	info->regs = sbus_ioremap(resp, 0, regs.reg_size, "amd7930");
-	if (!info->regs) {
-		printk(KERN_ERR "amd7930: could not remap registers\n");
-		kfree(drv->private);
-		return -EIO;
-	}
-
-	/* Put amd7930 in idle mode (interrupts disabled) */
-	amd7930_idle(info);
-
-	/* Enable extended FIFO operation on D-channel */
-	sbus_writeb(AMR_DLC_EFCR, info->regs + CR);
-	sbus_writeb(AMR_DLC_EFCR_EXTEND_FIFO, info->regs + DR);
-	sbus_writeb(AMR_DLC_DMR4, info->regs + CR);
-	sbus_writeb(/* AMR_DLC_DMR4_RCV_30 | */ AMR_DLC_DMR4_XMT_14,
-		    info->regs + DR);
-
-	/* Attach the interrupt handler to the audio interrupt. */
-	prom_getproperty(node, "intr", (char *)&irq, sizeof(irq));
-	info->irq = irq.pri;
-	request_irq(info->irq, amd7930_interrupt,
-		    SA_INTERRUPT, "amd7930", drv);
-	amd7930_enable_ints(info);
-
-	/* Initalize the local copy of the MAP registers. */
-	memset(&info->map, 0, sizeof(info->map));
-	info->map.mmr1 = AM_MAP_MMR1_GX | AM_MAP_MMR1_GER |
-			 AM_MAP_MMR1_GR | AM_MAP_MMR1_STG;
-        /* Start out with speaker, microphone */
-        info->map.mmr2 |= (AM_MAP_MMR2_LS | AM_MAP_MMR2_AINB);
-
-	/* Set the default audio parameters. */
-	info->rgain = 128;
-	info->pgain = 200;
-	info->mgain = 0;
-	info->format_type = AUDIO_ENCODING_ULAW;
-	info->Bb.input_format = AUDIO_ENCODING_ULAW;
-	info->Bb.output_format = AUDIO_ENCODING_ULAW;
-	info->Bc.input_format = AUDIO_ENCODING_ULAW;
-	info->Bc.output_format = AUDIO_ENCODING_ULAW;
-	amd7930_update_map(drv);
-
-	/* Register the amd7930 with the midlevel audio driver. */
-	err = register_sparcaudio_driver(drv, 1);
-	if (err < 0) {
-		printk(KERN_ERR "amd7930: unable to register\n");
-		free_irq(info->irq, drv);
-		sbus_iounmap(info->regs, info->regs_size);
-		kfree(drv->private);
-		return -EIO;
-	}
-
-	/* Announce the hardware to the user. */
-	printk(KERN_INFO "amd7930 at %lx irq %d\n",
-	       info->regs, info->irq);
-
-	/* Success! */
-	return 0;
-}
-
-/* Detach from an amd7930 chip given the device structure. */
-static void __exit amd7930_detach(struct sparcaudio_driver *drv)
-{
-	struct amd7930_info *info = (struct amd7930_info *)drv->private;
-
-	unregister_sparcaudio_driver(drv, 1);
-	amd7930_idle(info);
-	free_irq(info->irq, drv);
-	sbus_iounmap(info->regs, info->regs_size);
-	kfree(drv->private);
-}
-
-/* Probe for the amd7930 chip and then attach the driver. */
-static int __init amd7930_init(void)
-{
-	struct sbus_bus *sbus;
-	struct sbus_dev *sdev;
-	int node;
-
-	/* Try to find the sun4c "audio" node first. */
-	node = prom_getchild(prom_root_node);
-	node = prom_searchsiblings(node, "audio");
-	if (node && amd7930_attach(&drivers[0], node, NULL, NULL) == 0)
-		num_drivers = 1;
-	else
-		num_drivers = 0;
-
-	/* Probe each SBUS for amd7930 chips. */
-	for_all_sbusdev(sdev, sbus) {
-		if (!strcmp(sdev->prom_name, "audio")) {
-			/* Don't go over the max number of drivers. */
-			if (num_drivers >= MAX_DRIVERS)
-				continue;
-
-			if (amd7930_attach(&drivers[num_drivers],
-					   sdev->prom_node, sdev->bus, sdev) == 0)
-				num_drivers++;
-		}
-	}
-
-	/* Only return success if we found some amd7930 chips. */
-	return (num_drivers > 0) ? 0 : -EIO;
-}
-
-static void __exit amd7930_exit(void)
-{
-	register int i;
-
-	for (i = 0; i < num_drivers; i++) {
-		amd7930_detach(&drivers[i]);
-		num_drivers--;
-	}
-}
-
-module_init(amd7930_init);
-module_exit(amd7930_exit);
-MODULE_LICENSE("GPL");
-
-/*************************************************************/
-/*                 Audio format conversion                   */
-/*************************************************************/
-
-/* Translation tables */
-
-static unsigned char ulaw[] = {
-    3,   7,  11,  15,  19,  23,  27,  31, 
-   35,  39,  43,  47,  51,  55,  59,  63, 
-   66,  68,  70,  72,  74,  76,  78,  80, 
-   82,  84,  86,  88,  90,  92,  94,  96, 
-   98,  99, 100, 101, 102, 103, 104, 105, 
-  106, 107, 108, 109, 110, 111, 112, 113, 
-  113, 114, 114, 115, 115, 116, 116, 117, 
-  117, 118, 118, 119, 119, 120, 120, 121, 
-  121, 121, 122, 122, 122, 122, 123, 123, 
-  123, 123, 124, 124, 124, 124, 125, 125, 
-  125, 125, 125, 125, 126, 126, 126, 126, 
-  126, 126, 126, 126, 127, 127, 127, 127, 
-  127, 127, 127, 127, 127, 127, 127, 127, 
-  128, 128, 128, 128, 128, 128, 128, 128, 
-  128, 128, 128, 128, 128, 128, 128, 128, 
-  128, 128, 128, 128, 128, 128, 128, 128, 
-  253, 249, 245, 241, 237, 233, 229, 225, 
-  221, 217, 213, 209, 205, 201, 197, 193, 
-  190, 188, 186, 184, 182, 180, 178, 176, 
-  174, 172, 170, 168, 166, 164, 162, 160, 
-  158, 157, 156, 155, 154, 153, 152, 151, 
-  150, 149, 148, 147, 146, 145, 144, 143, 
-  143, 142, 142, 141, 141, 140, 140, 139, 
-  139, 138, 138, 137, 137, 136, 136, 135, 
-  135, 135, 134, 134, 134, 134, 133, 133, 
-  133, 133, 132, 132, 132, 132, 131, 131, 
-  131, 131, 131, 131, 130, 130, 130, 130, 
-  130, 130, 130, 130, 129, 129, 129, 129, 
-  129, 129, 129, 129, 129, 129, 129, 129, 
-  128, 128, 128, 128, 128, 128, 128, 128, 
-  128, 128, 128, 128, 128, 128, 128, 128, 
-  128, 128, 128, 128, 128, 128, 128, 128
-};
-
-static __u8 mulaw2bilinear(__u8 data)
-{
-	return ulaw[data];
-}
-
-static unsigned char linear[] = {
-     0,    0,    0,    0,    0,    0,    0,    1,
-     0,    0,    0,    2,    0,    0,    0,    3,
-     0,    0,    0,    4,    0,    0,    0,    5,
-     0,    0,    0,    6,    0,    0,    0,    7,
-     0,    0,    0,    8,    0,    0,    0,    9,
-     0,    0,    0,   10,    0,    0,    0,   11,
-     0,    0,    0,   12,    0,    0,    0,   13,
-     0,    0,    0,   14,    0,    0,    0,   15,
-     0,    0,   16,    0,   17,    0,   18,    0,
-    19,    0,   20,    0,   21,    0,   22,    0,
-    23,    0,   24,    0,   25,    0,   26,    0,
-    27,    0,   28,    0,   29,    0,   30,    0,
-    31,    0,   32,   33,   34,   35,   36,   37,
-    38,   39,   40,   41,   42,   43,   44,   45,
-    46,   48,   50,   52,   54,   56,   58,   60,
-    62,   65,   69,   73,   77,   83,   91,  103,
-   255,  231,  219,  211,  205,  201,  197,  193,
-   190,  188,  186,  184,  182,  180,  178,  176,
-   174,  173,  172,  171,  170,  169,  168,  167,
-   166,  165,  164,  163,  162,  161,  160,    0,
-   159,    0,  158,    0,  157,    0,  156,    0,
-   155,    0,  154,    0,  153,    0,  152,    0,
-   151,    0,  150,    0,  149,    0,  148,    0,
-   147,    0,  146,    0,  145,    0,  144,    0,
-     0,  143,    0,    0,    0,  142,    0,    0,
-     0,  141,    0,    0,    0,  140,    0,    0,
-     0,  139,    0,    0,    0,  138,    0,    0,
-     0,  137,    0,    0,    0,  136,    0,    0,
-     0,  135,    0,    0,    0,  134,    0,    0,
-     0,  133,    0,    0,    0,  132,    0,    0,
-     0,  131,    0,    0,    0,  130,    0,    0,
-     0,  129,    0,    0,    0,  128,    0,    0
-};
-
-static __u8 bilinear2mulaw(__u8 data)
-{
-	return linear[data];
-}
-
-static int exp_lut[256] = {
-	0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
-	5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-	6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
-	6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
-	7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
-	7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
-	7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
-	7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
-};
-
-#define BIAS 0x84
-#define CLIP 32635
-
-#define SWAP_ENDIAN(x) ((x >> 8) | ((x & 0xff) << 8))
-
-static __u8  linear2mulaw(__u16 data)
-{
-	static int sign, exponent, mantissa;
-
-	/* not really sure, if swapping is ok - comment next line to disable it */
-	data = SWAP_ENDIAN(data);
-	
-	sign = (data >> 8) & 0x80;
-	if (sign != 0) data = -data;
-
-	if (data > CLIP) data = CLIP;
-	data += BIAS;
-	exponent = exp_lut[(data >> 7) & 0xFF];
-	mantissa = (data >> (exponent + 3)) & 0x0F;
-
-	return (~(sign | (exponent << 4) | mantissa));
-}
-
-static __u16 mulaw2linear(__u8 data)
-{
-	/* this conversion is not working */
-	return data;
-}
-
-#if 0
-#define INOUT(x,y) (((x) << 16) | (y))
-static int convert_audio(int in_format, int out_format, __u8* buffer, int count)
-{
-	static int i,sign,exponent;
-	static __u16 data;
-
-	if (in_format == out_format) return count;
-
-	switch(INOUT(in_format, out_format)) {
-	case INOUT(AUDIO_ENCODING_ULAW, AUDIO_ENCODING_LINEAR8):
-		for (i = 0;i < count; i++) {
-			buffer[i] = ulaw[buffer[i]];
-		};
-		break;
-	case INOUT(AUDIO_ENCODING_ULAW, AUDIO_ENCODING_LINEAR):
-		break;
-	case INOUT(AUDIO_ENCODING_LINEAR, AUDIO_ENCODING_ULAW):
-		/* buffer is two-byte => convert to first */
-		for (i = 0; i < count/2; i++) {
-			data = ((__u16*)buffer)[i];
-			sign = (data >> 8) & 0x80;
-			if (data > CLIP) data = CLIP;
-			data += BIAS;
-			exponent = exp_lut[(data >> 7) & 0xFF];
-			buffer[i] = ~(sign | (exponent << 4) | 
-						  ((data >> (exponent + 3)) & 0x0F));
-		};
-		break;
-	case INOUT(AUDIO_ENCODING_LINEAR8, AUDIO_ENCODING_ULAW):
-		for (i = 0; i < count; i++) {
-			buffer[i] = linear[buffer[i]];
-		};
-		break;
-	default:
-		return 0;
-	};
-
-	return count;
-}
-#undef INOUT
-#endif
-
-#undef BIAS
-#undef CLIP
-#undef SWAP_ENDIAN
diff -Nru a/drivers/sbus/audio/amd7930.h b/drivers/sbus/audio/amd7930.h
--- a/drivers/sbus/audio/amd7930.h	Tue Oct  1 00:08:15 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,270 +0,0 @@
-/* $Id: amd7930.h,v 1.8 1999/09/21 14:37:10 davem Exp $
- * drivers/sbus/audio/amd7930.h
- *
- * Copyright (C) 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu)
- *
- * Definitions for the AMD79C30 Digital Subscriber Controller which is
- * used as an audio chip in sun4c architecture machines. The
- * information in this file is based on Advanced Micro Devices
- * Publication 09893, Rev G, Amendment /0, Final (a.k.a. the data
- * sheet).
- */
-
-#ifndef _AMD7930_H_
-#define _AMD7930_H_
-
-#include <linux/types.h>
-#include <linux/version.h>
-
-/* Register interface presented to the CPU by the amd7930. */
-#define CR	0x00UL		/* Command Register (W) */
-#define IR	CR		/* Interrupt Register (R) */
-#define DR	0x01UL		/* Data Register (R/W) */
-#define DSR1	0x02UL		/* D-channel Status Register 1 (R) */
-#define DER	0x03UL		/* D-channel Error Register (R) */
-#define DCTB	0x04UL		/* D-channel Transmit Buffer (W) */
-#define DCRB	DCTB		/* D-channel Receive Buffer (R) */
-#define BBTB	0x05UL		/* Bb-channel Transmit Buffer (W) */
-#define BBRB	BBTB		/* Bb-channel Receive Buffer (R) */
-#define BCTB	0x06UL		/* Bc-channel Transmit Buffer (W) */
-#define BCRB	BCTB		/* Bc-channel Receive Buffer (R) */
-#define DSR2	0x07UL		/* D-channel Status Register 2 (R) */
-
-/* Indirect registers in the Main Audio Processor. */
-struct amd7930_map {
-	__u16	x[8];
-	__u16	r[8];
-	__u16	gx;
-	__u16	gr;
-	__u16	ger;
-	__u16	stgr;
-	__u16	ftgr;
-	__u16	atgr;
-	__u8	mmr1;
-	__u8	mmr2;
-};
-
-
-/* After an amd7930 interrupt, reading the Interrupt Register (ir)
- * clears the interrupt and returns a bitmask indicated which
- * interrupt source(s) require service
- */
-
-#define AMR_IR_DTTHRSH			0x01 /* D-channel xmit threshold */
-#define AMR_IR_DRTHRSH			0x02 /* D-channel recv threshold */
-#define AMR_IR_DSRI			0x04 /* D-channel packet status */
-#define AMR_IR_DERI			0x08 /* D-channel error */
-#define AMR_IR_BBUF			0x10 /* B-channel data xfer */
-#define AMR_IR_LSRI			0x20 /* LIU status */
-#define AMR_IR_DSR2I			0x40 /* D-channel buffer status */
-#define AMR_IR_MLTFRMI			0x80 /* multiframe or PP */
-
-/* The amd7930 has "indirect registers" which are accessed by writing
- * the register number into the Command Register and then reading or
- * writing values from the Data Register as appropriate. We define the
- * AMR_* macros to be the indirect register numbers and AM_* macros to
- * be bits in whatever register is referred to.
- */
-
-/* Initialization */
-#define	AMR_INIT			0x21
-#define		AM_INIT_ACTIVE			0x01
-#define		AM_INIT_DATAONLY		0x02
-#define		AM_INIT_POWERDOWN		0x03
-#define		AM_INIT_DISABLE_INTS		0x04
-#define AMR_INIT2			0x20
-#define		AM_INIT2_ENABLE_POWERDOWN	0x20
-#define		AM_INIT2_ENABLE_MULTIFRAME	0x10
-
-/* Line Interface Unit */
-#define	AMR_LIU_LSR			0xA1
-#define		AM_LIU_LSR_STATE		0x07
-#define		AM_LIU_LSR_F3			0x08
-#define		AM_LIU_LSR_F7			0x10
-#define		AM_LIU_LSR_F8			0x20
-#define		AM_LIU_LSR_HSW			0x40
-#define		AM_LIU_LSR_HSW_CHG		0x80
-#define	AMR_LIU_LPR			0xA2
-#define	AMR_LIU_LMR1			0xA3
-#define		AM_LIU_LMR1_B1_ENABL		0x01
-#define		AM_LIU_LMR1_B2_ENABL		0x02
-#define		AM_LIU_LMR1_F_DISABL		0x04
-#define		AM_LIU_LMR1_FA_DISABL		0x08
-#define		AM_LIU_LMR1_REQ_ACTIV		0x10
-#define		AM_LIU_LMR1_F8_F3		0x20
-#define		AM_LIU_LMR1_LIU_ENABL		0x40
-#define	AMR_LIU_LMR2			0xA4
-#define		AM_LIU_LMR2_DECHO		0x01
-#define		AM_LIU_LMR2_DLOOP		0x02
-#define		AM_LIU_LMR2_DBACKOFF		0x04
-#define		AM_LIU_LMR2_EN_F3_INT		0x08
-#define		AM_LIU_LMR2_EN_F8_INT		0x10
-#define		AM_LIU_LMR2_EN_HSW_INT		0x20
-#define		AM_LIU_LMR2_EN_F7_INT		0x40
-#define	AMR_LIU_2_4			0xA5
-#define	AMR_LIU_MF			0xA6
-#define	AMR_LIU_MFSB			0xA7
-#define	AMR_LIU_MFQB			0xA8
-
-/* Multiplexor */
-#define	AMR_MUX_MCR1			0x41
-#define	AMR_MUX_MCR2			0x42
-#define	AMR_MUX_MCR3			0x43
-#define		AM_MUX_CHANNEL_B1		0x01
-#define		AM_MUX_CHANNEL_B2		0x02
-#define		AM_MUX_CHANNEL_Ba		0x03
-#define		AM_MUX_CHANNEL_Bb		0x04
-#define		AM_MUX_CHANNEL_Bc		0x05
-#define		AM_MUX_CHANNEL_Bd		0x06
-#define		AM_MUX_CHANNEL_Be		0x07
-#define		AM_MUX_CHANNEL_Bf		0x08
-#define	AMR_MUX_MCR4			0x44
-#define		AM_MUX_MCR4_ENABLE_INTS		0x08
-#define		AM_MUX_MCR4_REVERSE_Bb		0x10
-#define		AM_MUX_MCR4_REVERSE_Bc		0x20
-#define	AMR_MUX_1_4			0x45
-
-/* Main Audio Processor */
-#define	AMR_MAP_X			0x61
-#define	AMR_MAP_R			0x62
-#define	AMR_MAP_GX			0x63
-#define	AMR_MAP_GR			0x64
-#define	AMR_MAP_GER			0x65
-#define	AMR_MAP_STGR			0x66
-#define	AMR_MAP_FTGR_1_2		0x67
-#define	AMR_MAP_ATGR_1_2		0x68
-#define	AMR_MAP_MMR1			0x69
-#define		AM_MAP_MMR1_ALAW		0x01
-#define		AM_MAP_MMR1_GX			0x02
-#define		AM_MAP_MMR1_GR			0x04
-#define		AM_MAP_MMR1_GER			0x08
-#define		AM_MAP_MMR1_X			0x10
-#define		AM_MAP_MMR1_R			0x20
-#define		AM_MAP_MMR1_STG			0x40
-#define		AM_MAP_MMR1_LOOPBACK		0x80
-#define	AMR_MAP_MMR2			0x6A
-#define		AM_MAP_MMR2_AINB		0x01
-#define		AM_MAP_MMR2_LS			0x02
-#define		AM_MAP_MMR2_ENABLE_DTMF		0x04
-#define		AM_MAP_MMR2_ENABLE_TONEGEN	0x08
-#define		AM_MAP_MMR2_ENABLE_TONERING	0x10
-#define		AM_MAP_MMR2_DISABLE_HIGHPASS	0x20
-#define		AM_MAP_MMR2_DISABLE_AUTOZERO	0x40
-#define	AMR_MAP_1_10			0x6B
-#define	AMR_MAP_MMR3			0x6C
-#define	AMR_MAP_STRA			0x6D
-#define	AMR_MAP_STRF			0x6E
-#define	AMR_MAP_PEAKX			0x70
-#define	AMR_MAP_PEAKR			0x71
-#define	AMR_MAP_15_16			0x72
-
-/* Data Link Controller */
-#define	AMR_DLC_FRAR_1_2_3		0x81
-#define	AMR_DLC_SRAR_1_2_3		0x82
-#define	AMR_DLC_TAR			0x83
-#define	AMR_DLC_DRLR			0x84
-#define	AMR_DLC_DTCR			0x85
-#define	AMR_DLC_DMR1			0x86
-#define		AMR_DLC_DMR1_DTTHRSH_INT	0x01
-#define		AMR_DLC_DMR1_DRTHRSH_INT	0x02
-#define		AMR_DLC_DMR1_TAR_ENABL		0x04
-#define		AMR_DLC_DMR1_EORP_INT		0x08
-#define		AMR_DLC_DMR1_EN_ADDR1		0x10
-#define		AMR_DLC_DMR1_EN_ADDR2		0x20
-#define		AMR_DLC_DMR1_EN_ADDR3		0x40
-#define		AMR_DLC_DMR1_EN_ADDR4		0x80
-#define		AMR_DLC_DMR1_EN_ADDRS		0xf0
-#define	AMR_DLC_DMR2			0x87
-#define		AMR_DLC_DMR2_RABRT_INT		0x01
-#define		AMR_DLC_DMR2_RESID_INT		0x02
-#define		AMR_DLC_DMR2_COLL_INT		0x04
-#define		AMR_DLC_DMR2_FCS_INT		0x08
-#define		AMR_DLC_DMR2_OVFL_INT		0x10
-#define		AMR_DLC_DMR2_UNFL_INT		0x20
-#define		AMR_DLC_DMR2_OVRN_INT		0x40
-#define		AMR_DLC_DMR2_UNRN_INT		0x80
-#define	AMR_DLC_1_7			0x88
-#define	AMR_DLC_DRCR			0x89
-#define	AMR_DLC_RNGR1			0x8A
-#define	AMR_DLC_RNGR2			0x8B
-#define	AMR_DLC_FRAR4			0x8C
-#define	AMR_DLC_SRAR4			0x8D
-#define	AMR_DLC_DMR3			0x8E
-#define		AMR_DLC_DMR3_VA_INT		0x01
-#define		AMR_DLC_DMR3_EOTP_INT		0x02
-#define		AMR_DLC_DMR3_LBRP_INT		0x04
-#define		AMR_DLC_DMR3_RBA_INT		0x08
-#define		AMR_DLC_DMR3_LBT_INT		0x10
-#define		AMR_DLC_DMR3_TBE_INT		0x20
-#define		AMR_DLC_DMR3_RPLOST_INT		0x40
-#define		AMR_DLC_DMR3_KEEP_FCS		0x80
-#define	AMR_DLC_DMR4			0x8F
-#define		AMR_DLC_DMR4_RCV_1		0x00
-#define		AMR_DLC_DMR4_RCV_2		0x01
-#define		AMR_DLC_DMR4_RCV_4		0x02
-#define		AMR_DLC_DMR4_RCV_8		0x03
-#define		AMR_DLC_DMR4_RCV_16		0x01
-#define		AMR_DLC_DMR4_RCV_24		0x02
-#define		AMR_DLC_DMR4_RCV_30		0x03
-#define		AMR_DLC_DMR4_XMT_1		0x00
-#define		AMR_DLC_DMR4_XMT_2		0x04
-#define		AMR_DLC_DMR4_XMT_4		0x08
-#define		AMR_DLC_DMR4_XMT_8		0x0c
-#define		AMR_DLC_DMR4_XMT_10		0x08
-#define		AMR_DLC_DMR4_XMT_14		0x0c
-#define		AMR_DLC_DMR4_IDLE_MARK		0x00
-#define		AMR_DLC_DMR4_IDLE_FLAG		0x10
-#define		AMR_DLC_DMR4_ADDR_BOTH		0x00
-#define		AMR_DLC_DMR4_ADDR_1ST		0x20
-#define		AMR_DLC_DMR4_ADDR_2ND		0xa0
-#define		AMR_DLC_DMR4_CR_ENABLE		0x40
-#define	AMR_DLC_12_15			0x90
-#define	AMR_DLC_ASR			0x91
-#define	AMR_DLC_EFCR			0x92
-#define		AMR_DLC_EFCR_EXTEND_FIFO	0x01
-#define		AMR_DLC_EFCR_SEC_PKT_INT	0x02
-
-#define AMR_DSR1_VADDR			0x01
-#define AMR_DSR1_EORP			0x02
-#define AMR_DSR1_PKT_IP			0x04
-#define AMR_DSR1_DECHO_ON		0x08
-#define AMR_DSR1_DLOOP_ON		0x10
-#define AMR_DSR1_DBACK_OFF		0x20
-#define AMR_DSR1_EOTP			0x40
-#define AMR_DSR1_CXMT_ABRT		0x80
-
-#define AMR_DSR2_LBRP			0x01
-#define AMR_DSR2_RBA			0x02
-#define AMR_DSR2_RPLOST			0x04
-#define AMR_DSR2_LAST_BYTE		0x08
-#define AMR_DSR2_TBE			0x10
-#define AMR_DSR2_MARK_IDLE		0x20
-#define AMR_DSR2_FLAG_IDLE		0x40
-#define AMR_DSR2_SECOND_PKT		0x80
-
-#define AMR_DER_RABRT			0x01
-#define AMR_DER_RFRAME			0x02
-#define AMR_DER_COLLISION		0x04
-#define AMR_DER_FCS			0x08
-#define AMR_DER_OVFL			0x10
-#define AMR_DER_UNFL			0x20
-#define AMR_DER_OVRN			0x40
-#define AMR_DER_UNRN			0x80
-
-/* Peripheral Port */
-#define	AMR_PP_PPCR1			0xC0
-#define	AMR_PP_PPSR			0xC1
-#define	AMR_PP_PPIER			0xC2
-#define	AMR_PP_MTDR			0xC3
-#define	AMR_PP_MRDR			0xC3
-#define	AMR_PP_CITDR0			0xC4
-#define	AMR_PP_CIRDR0			0xC4
-#define	AMR_PP_CITDR1			0xC5
-#define	AMR_PP_CIRDR1			0xC5
-#define	AMR_PP_PPCR2			0xC8
-#define	AMR_PP_PPCR3			0xC9
-
-/* Give this chip a "default" sample rate */
-#define AMD7930_RATE                    (8000)
-
-#endif /* _AMD7930_H_ */
diff -Nru a/drivers/sbus/audio/audio.c b/drivers/sbus/audio/audio.c
--- a/drivers/sbus/audio/audio.c	Tue Oct  1 00:08:13 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,2304 +0,0 @@
-/* $Id: audio.c,v 1.63 2002/01/08 16:00:21 davem Exp $
- * drivers/sbus/audio/audio.c
- *
- * Copyright 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu)
- * Copyright 1997,1998,1999 Derrick J. Brashear (shadow@dementia.org)
- * Copyright 1997 Brent Baccala (baccala@freesoft.org)
- * 
- * Mixer code adapted from code contributed by and
- * Copyright 1998 Michael Mraka (michael@fi.muni.cz)
- * and with fixes from Michael Shuey (shuey@ecn.purdue.edu)
- * The mixer code cheats; Sparc hardware doesn't generally allow independent
- * line control, and this fakes it badly.
- *
- * SNDCTL_DSP_SETFMT based on code contributed by
- * Ion Badulescu (ionut@moisil.cs.columbia.edu)
- *
- * This is the audio midlayer that sits between the VFS character
- * devices and the low-level audio hardware device drivers.
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/mm.h>
-#include <linux/tqueue.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/soundcard.h>
-#include <linux/devfs_fs_kernel.h>
-#include <linux/delay.h>
-#include <linux/poll.h>
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-
-#include <asm/audioio.h>
-
-#undef __AUDIO_DEBUG
-#define __AUDIO_ERROR
-#undef __AUDIO_TRACE
-#undef __AUDIO_OSSDEBUG
-#ifdef __AUDIO_DEBUG
-#define dprintk(x) printk x
-#else
-#define dprintk(x)
-#endif
-#ifdef __AUDIO_OSSDEBUG
-#define oprintk(x) printk x
-#else
-#define oprintk(x)
-#endif
-#ifdef __AUDIO_ERROR
-#define eprintk(x) printk x
-#else
-#define eprintk(x)
-#endif
-#ifdef __AUDIO_TRACE
-#define tprintk(x) printk x
-#else
-#define tprintk(x)
-#endif
-
-static short lis_get_elist_ent( strevent_t *list, pid_t pid );
-static int lis_add_to_elist( strevent_t **list, pid_t pid, short events );
-static int lis_del_from_elist( strevent_t **list, pid_t pid, short events );
-static void lis_free_elist( strevent_t **list);
-static void kill_procs( struct strevent *elist, int sig, short e);
-
-static struct sparcaudio_driver *drivers[SPARCAUDIO_MAX_DEVICES];
-static devfs_handle_t devfs_handle;
- 
-
-void sparcaudio_output_done(struct sparcaudio_driver * drv, int status)
-{
-        /* If !status, just restart current output.
-         * If status & 1, a buffer is finished; make it available again.
-         * If status & 2, a buffer was claimed for DMA and is still in use.
-         *
-         * The playing_count for non-DMA hardware should never be non-zero.
-         * Value of status for non-DMA hardware should always be 1.
-         */
-        if (status & 1) {
-                if (drv->playing_count) {
-                        drv->playing_count--;
-                } else {
-                        drv->output_count--;
-                        drv->output_size -= drv->output_sizes[drv->output_front];
-                        if (drv->output_notify[drv->output_front] == 1) {
-                                drv->output_eof++;
-                                drv->output_notify[drv->output_front] = 0;
-                                kill_procs(drv->sd_siglist,SIGPOLL,S_MSG);
-                        }
-                        drv->output_front = (drv->output_front + 1) % 
-                                drv->num_output_buffers;
-                }
-        }
-    
-        if (status & 2) {
-                drv->output_count--;
-                drv->playing_count++;
-                drv->output_size -= drv->output_sizes[drv->output_front];
-                if (drv->output_notify[drv->output_front] == 1) {
-                        drv->output_eof++;
-                        drv->output_notify[drv->output_front] = 0;
-                        kill_procs(drv->sd_siglist,SIGPOLL,S_MSG);
-                }
-                drv->output_front = (drv->output_front + 1) % 
-                        drv->num_output_buffers;
-        }
-
-        /* If we've played everything go inactive. */
-        if ((drv->output_count < 1) && (drv->playing_count < 1)) 
-                drv->output_active = 0;
-
-        /* If we got back a buffer, see if anyone wants to write to it */
-        if ((status & 1) || ((drv->output_count + drv->playing_count) 
-                             < drv->num_output_buffers)) {
-                wake_up_interruptible(&drv->output_write_wait);
-        }
-
-        /* If the output queue is empty, shut down the driver. */
-        if ((drv->output_count < 1) && (drv->playing_count < 1)) {
-                kill_procs(drv->sd_siglist,SIGPOLL,S_MSG);
-
-                /* Stop the lowlevel driver from outputing. */
-                /* drv->ops->stop_output(drv); Should not be necessary  -- DJB 5/25/98 */
-                drv->output_active = 0;
-		  
-                /* Wake up any waiting writers or syncers and return. */
-                wake_up_interruptible(&drv->output_write_wait);
-                wake_up_interruptible(&drv->output_drain_wait);
-                return;
-        }
-
-        /* Start next block of output if we have it */
-        if (drv->output_count > 0) {
-                drv->ops->start_output(drv, drv->output_buffers[drv->output_front],
-                                       drv->output_sizes[drv->output_front]);
-                drv->output_active = 1;
-        } else {
-                drv->output_active = 0;
-        }
-}
-
-void sparcaudio_input_done(struct sparcaudio_driver * drv, int status)
-{
-        /* Deal with the weird case here */
-        if (drv->duplex == 2) {
-                if (drv->input_count < drv->num_input_buffers)
-                        drv->input_count++;
-                drv->ops->start_input(drv, drv->input_buffers[drv->input_front],
-                                      drv->input_buffer_size);
-                wake_up_interruptible(&drv->input_read_wait);
-                return;
-        } 
-
-        /* If status % 2, they filled a buffer for us. 
-         * If status & 2, they took a buffer from us.
-         */
-        if ((status % 2) == 1) {
-                drv->input_count++;
-                drv->recording_count--;
-                drv->input_size+=drv->input_buffer_size;
-        }
-
-        if (status > 1) {
-                drv->recording_count++;
-                drv->input_front = (drv->input_front + 1) % drv->num_input_buffers;
-        }
-
-        dprintk(("f%d r%d c%d u%d\n",
-                 drv->input_front, drv->input_rear,
-                 drv->input_count, drv->recording_count));
-
-        /* If the input queue is full, shutdown the driver. */
-        if ((drv->input_count + drv->recording_count) == drv->num_input_buffers) {
-                kill_procs(drv->sd_siglist,SIGPOLL,S_MSG);
-
-                /* Stop the lowlevel driver from inputing. */
-                drv->ops->stop_input(drv);
-                drv->input_active = 0;
-        } else {
-                /* Otherwise, give the driver the next buffer. */
-                drv->ops->start_input(drv, drv->input_buffers[drv->input_front],
-                                      drv->input_buffer_size);
-        }
-
-        /* Wake up any tasks that are waiting. */
-        wake_up_interruptible(&drv->input_read_wait);
-}
-
-/*
- *	VFS layer interface
- */
-
-static unsigned int sparcaudio_poll(struct file *file, poll_table * wait)
-{
-        unsigned int mask = 0;
-        struct inode *inode = file->f_dentry->d_inode;
-        struct sparcaudio_driver *drv = drivers[(minor(inode->i_rdev) >>
-                                                 SPARCAUDIO_DEVICE_SHIFT)];
-
-        poll_wait(file, &drv->input_read_wait, wait);
-        poll_wait(file, &drv->output_write_wait, wait);
-        if (((!file->f_flags & O_NONBLOCK) && drv->input_count) ||
-            (drv->input_size > drv->buffer_size)) {
-                mask |= POLLIN | POLLRDNORM;
-        }
-        if ((drv->output_count + drv->playing_count) < (drv->num_output_buffers)) {
-                mask |= POLLOUT | POLLWRNORM;
-        }
-        return mask;
-}
-
-static ssize_t sparcaudio_read(struct file * file, char *buf, 
-                               size_t count, loff_t *ppos)
-{
-        struct inode *inode = file->f_dentry->d_inode;
-        struct sparcaudio_driver *drv = drivers[(minor(inode->i_rdev) >>
-                                                 SPARCAUDIO_DEVICE_SHIFT)];
-        int bytes_to_copy, bytes_read = 0, err;
-
-        if (! (file->f_mode & FMODE_READ))
-                return -EINVAL;
-
-        if ((file->f_flags & O_NONBLOCK) && (drv->input_size < count))
-                return -EAGAIN;
-    
-        while (count > 0) {
-                if (drv->input_count == 0) {
-                        /* This *should* never happen. */
-                        if (file->f_flags & O_NONBLOCK) {
-                                printk("Warning: audio input leak!\n");
-                                return -EAGAIN;
-                        }
-                        interruptible_sleep_on(&drv->input_read_wait);
-                        if (signal_pending(current))
-                                return -EINTR;
-                }
-  
-                bytes_to_copy = drv->input_buffer_size - drv->input_offset;
-                if (bytes_to_copy > count)
-                        bytes_to_copy = count;
-
-                err = verify_area(VERIFY_WRITE, buf, bytes_to_copy);
-                if (err)
-                        return err;
-
-                copy_to_user(buf, drv->input_buffers[drv->input_rear]+drv->input_offset, 
-                             bytes_to_copy);
-
-                drv->input_offset += bytes_to_copy;
-                drv->input_size -= bytes_to_copy;
-                buf += bytes_to_copy;
-                count -= bytes_to_copy;
-                bytes_read += bytes_to_copy;
-
-                if (drv->input_offset >= drv->input_buffer_size) {
-                        drv->input_rear = (drv->input_rear + 1) % 
-                                drv->num_input_buffers;
-                        drv->input_count--;
-                        drv->input_offset = 0;
-                }
-
-                /* If we're in "loop audio" mode, try waking up the other side
-                 * in case they're waiting for us to eat a block. 
-                 */
-                if (drv->duplex == 2)
-                        wake_up_interruptible(&drv->output_write_wait);
-        }
-
-        return bytes_read;
-}
-
-static void sparcaudio_sync_output(struct sparcaudio_driver * drv)
-{
-        unsigned long flags;
-
-        /* If the low-level driver is not active, activate it. */
-        save_and_cli(flags);
-        if ((!drv->output_active) && (drv->output_count > 0)) {
-                drv->ops->start_output(drv, 
-                                       drv->output_buffers[drv->output_front],
-                                       drv->output_sizes[drv->output_front]);
-                drv->output_active = 1;
-        }
-        restore_flags(flags);
-}
-
-static ssize_t sparcaudio_write(struct file * file, const char *buf,
-                                size_t count, loff_t *ppos)
-{
-        struct inode *inode = file->f_dentry->d_inode;
-        struct sparcaudio_driver *drv = drivers[(minor(inode->i_rdev) >>
-                                                 SPARCAUDIO_DEVICE_SHIFT)];
-        int bytes_written = 0, bytes_to_copy, err;
-  
-        if (! (file->f_mode & FMODE_WRITE))
-                return -EINVAL;
-
-        /* A signal they want notification when this is processed. Too bad
-         * sys_write doesn't tell us unless you patch it, in 2.0 kernels.
-         */
-        if (count == 0) {
-#ifndef notdef
-                drv->output_eof++;
-                kill_procs(drv->sd_siglist,SIGPOLL,S_MSG);
-#else
-                /* Nice code, but the world isn't ready yet... */
-                drv->output_notify[drv->output_rear] = 1;
-#endif
-        }
-
-        /* Loop until all output is written to device. */
-        while (count > 0) {
-                /* Check to make sure that an output buffer is available. */
-                if (drv->num_output_buffers == (drv->output_count+drv->playing_count)) {
-                        /* We need buffers, so... */
-                        sparcaudio_sync_output(drv);
-                        if (file->f_flags & O_NONBLOCK)
-                                return -EAGAIN;
-
-                        interruptible_sleep_on(&drv->output_write_wait);
-                        if (signal_pending(current))
-                                return bytes_written > 0 ? bytes_written : -EINTR;
-                }
-
-                /* No buffers were freed. Go back to sleep */
-                if (drv->num_output_buffers == (drv->output_count+drv->playing_count)) 
-                        continue;
-
-                /* Deal with the weird case of a reader in the write area by trying to
-                 * let them keep ahead of us... Go to sleep until they start servicing.
-                 */
-                if ((drv->duplex == 2) && (drv->flags & SDF_OPEN_READ) &&
-                    (drv->output_rear == drv->input_rear) && (drv->input_count > 0)) {
-                        if (file->f_flags & O_NONBLOCK)
-                                return -EAGAIN;
-
-                        interruptible_sleep_on(&drv->output_write_wait);
-                        if (signal_pending(current))
-                                return bytes_written > 0 ? bytes_written : -EINTR;
-                }
-
-                /* Determine how much we can copy in this iteration. */
-                bytes_to_copy = count;
-                if (bytes_to_copy > drv->output_buffer_size - drv->output_offset)
-                        bytes_to_copy = drv->output_buffer_size - drv->output_offset;
-    
-                err = verify_area(VERIFY_READ, buf, bytes_to_copy);
-                if (err)
-                        return err;
-
-                copy_from_user(drv->output_buffers[drv->output_rear]+drv->output_offset,
-                               buf, bytes_to_copy);
-    
-                /* Update the queue pointers. */
-                buf += bytes_to_copy;
-                count -= bytes_to_copy;
-                bytes_written += bytes_to_copy;
-
-                /* A block can get orphaned in a flush and not cleaned up. */
-                if (drv->output_offset)
-                        drv->output_sizes[drv->output_rear] += bytes_to_copy;
-                else
-                        drv->output_sizes[drv->output_rear] = bytes_to_copy;
-
-                drv->output_notify[drv->output_rear] = 0;
-
-                if (drv->output_sizes[drv->output_rear] == drv->output_buffer_size) {
-                        drv->output_rear = (drv->output_rear + 1) 
-                                % drv->num_output_buffers;
-                        drv->output_count++;
-                        drv->output_offset = 0;
-                } else {
-                        drv->output_offset += bytes_to_copy;
-                }
-
-                drv->output_size += bytes_to_copy;
-        }
-
-        sparcaudio_sync_output(drv);
-  
-        /* Return the number of bytes written to the caller. */
-        return bytes_written;
-}
-
-/* Add these in as new devices are supported. Belongs in audioio.h, actually */
-#define MONO_DEVICES (SOUND_MASK_SPEAKER | SOUND_MASK_MIC)
-
-static int sparcaudio_mixer_ioctl(struct inode * inode, struct file * file,
-                                  unsigned int cmd, unsigned int *arg)
-{
-        struct sparcaudio_driver *drv = drivers[(minor(inode->i_rdev) >>
-                                                 SPARCAUDIO_DEVICE_SHIFT)];
-        unsigned long i = 0, j = 0, l = 0, m = 0;
-        unsigned int k = 0;
-
-        if (_SIOC_DIR(cmd) & _SIOC_WRITE)
-                drv->mixer_modify_counter++;
-
-        if(cmd == SOUND_MIXER_INFO) {
-                audio_device_t tmp;
-                mixer_info info;
-                int retval = -EINVAL;
-
-                if(drv->ops->sunaudio_getdev) {
-                        drv->ops->sunaudio_getdev(drv, &tmp);
-                        memset(&info, 0, sizeof(info));
-                        strncpy(info.id, tmp.name, sizeof(info.id));
-                        strncpy(info.name, "Sparc Audio", sizeof(info.name));
-                        info.modify_counter = drv->mixer_modify_counter;
-
-                        if(copy_to_user((char *)arg, &info, sizeof(info)))
-                                retval = -EFAULT;
-                        else
-                                retval = 0;
-                }
-                return retval;
-  }
-
-        switch (cmd) {
-        case SOUND_MIXER_WRITE_RECLEV:
-                if (get_user(k, (int *)arg))
-                        return -EFAULT;
-        iretry:
-                oprintk(("setting input volume (0x%x)", k));
-                if (drv->ops->get_input_channels)
-                        j = drv->ops->get_input_channels(drv);
-                if (drv->ops->get_input_volume)
-                        l = drv->ops->get_input_volume(drv);
-                if (drv->ops->get_input_balance)
-                        m = drv->ops->get_input_balance(drv);
-                i = OSS_TO_GAIN(k);
-                j = OSS_TO_BAL(k);
-                oprintk((" for stereo to do %d (bal %d):", i, j));
-                if (drv->ops->set_input_volume)
-                        drv->ops->set_input_volume(drv, i);
-                if (drv->ops->set_input_balance)
-                        drv->ops->set_input_balance(drv, j);
-        case SOUND_MIXER_READ_RECLEV:
-                if (drv->ops->get_input_volume)
-                        i = drv->ops->get_input_volume(drv);
-                if (drv->ops->get_input_balance)
-                        j = drv->ops->get_input_balance(drv);
-                oprintk((" got (0x%x)\n", BAL_TO_OSS(i,j)));
-                i = BAL_TO_OSS(i,j);
-                /* Try to be reasonable about volume changes */
-                if ((cmd == SOUND_MIXER_WRITE_RECLEV) && (i != k) && 
-                    (i == BAL_TO_OSS(l,m))) {
-                        k += (OSS_LEFT(k) > OSS_LEFT(i)) ? 256 : -256;
-                        k += (OSS_RIGHT(k) > OSS_RIGHT(i)) ? 1 : -1;
-                        oprintk((" try 0x%x\n", k));
-                        goto iretry;
-                }
-                return put_user(i, (int *)arg);
-        case SOUND_MIXER_WRITE_VOLUME:
-                if (get_user(k, (int *)arg))
-                        return -EFAULT;
-                if (drv->ops->get_output_muted && drv->ops->set_output_muted) {
-                        i = drv->ops->get_output_muted(drv);
-                        if ((k == 0) || ((i == 0) && (OSS_LEFT(k) < 100)))
-                                drv->ops->set_output_muted(drv, 1);
-                        else
-                                drv->ops->set_output_muted(drv, 0);
-                }
-        case SOUND_MIXER_READ_VOLUME:
-                if (drv->ops->get_output_muted) 
-                        i = drv->ops->get_output_muted(drv);
-                k = 0x6464 * (1 - i);
-                return put_user(k, (int *)arg);
-        case SOUND_MIXER_WRITE_PCM:
-                if (get_user(k, (int *)arg))
-                        return -EFAULT;
-        oretry:
-                oprintk(("setting output volume (0x%x)\n", k));
-                if (drv->ops->get_output_channels)
-                        j = drv->ops->get_output_channels(drv);
-                if (drv->ops->get_output_volume)
-                        l = drv->ops->get_output_volume(drv);
-                if (drv->ops->get_output_balance)
-                        m = drv->ops->get_output_balance(drv);
-                oprintk((" started as (0x%x)\n", BAL_TO_OSS(l,m)));
-                i = OSS_TO_GAIN(k);
-                j = OSS_TO_BAL(k);
-                oprintk((" for stereo to %d (bal %d)\n", i, j));
-                if (drv->ops->set_output_volume)
-                        drv->ops->set_output_volume(drv, i);
-                if (drv->ops->set_output_balance)
-                        drv->ops->set_output_balance(drv, j);
-        case SOUND_MIXER_READ_PCM:
-                if (drv->ops->get_output_volume)
-                        i = drv->ops->get_output_volume(drv);
-                if (drv->ops->get_output_balance)
-                        j = drv->ops->get_output_balance(drv);
-                oprintk((" got 0x%x\n", BAL_TO_OSS(i,j)));
-                i = BAL_TO_OSS(i,j);
-
-                /* Try to be reasonable about volume changes */
-                if ((cmd == SOUND_MIXER_WRITE_PCM) && (i != k) && 
-                    (i == BAL_TO_OSS(l,m))) {
-                        k += (OSS_LEFT(k) > OSS_LEFT(i)) ? 256 : -256;
-                        k += (OSS_RIGHT(k) > OSS_RIGHT(i)) ? 1 : -1;
-                        oprintk((" try 0x%x\n", k));
-                        goto oretry;
-                }
-                return put_user(i, (int *)arg);
-        case SOUND_MIXER_READ_SPEAKER:
-                k = OSS_PORT_AUDIO(drv, AUDIO_SPEAKER);
-                return put_user(k, (int *)arg);
-        case SOUND_MIXER_READ_MIC:
-                k = OSS_IPORT_AUDIO(drv, AUDIO_MICROPHONE);
-                return put_user(k, (int *)arg);
-        case SOUND_MIXER_READ_CD:
-                k = OSS_IPORT_AUDIO(drv, AUDIO_CD);
-                return put_user(k, (int *)arg);
-        case SOUND_MIXER_READ_LINE:
-                k = OSS_IPORT_AUDIO(drv, AUDIO_LINE_IN);
-                return put_user(k, (int *)arg);
-        case SOUND_MIXER_READ_LINE1:
-                k = OSS_PORT_AUDIO(drv, AUDIO_HEADPHONE);
-                return put_user(k, (int *)arg);
-        case SOUND_MIXER_READ_LINE2:
-                k = OSS_PORT_AUDIO(drv, AUDIO_LINE_OUT);
-                return put_user(k, (int *)arg);
-
-        case SOUND_MIXER_WRITE_MIC:
-        case SOUND_MIXER_WRITE_CD:
-        case SOUND_MIXER_WRITE_LINE:
-        case SOUND_MIXER_WRITE_LINE1:
-        case SOUND_MIXER_WRITE_LINE2:
-        case SOUND_MIXER_WRITE_SPEAKER:
-                if (get_user(k, (int *)arg))
-                        return -EFAULT;
-                OSS_TWIDDLE_IPORT(drv, cmd, SOUND_MIXER_WRITE_LINE, AUDIO_LINE_IN, k);
-                OSS_TWIDDLE_IPORT(drv, cmd, SOUND_MIXER_WRITE_MIC, AUDIO_MICROPHONE, k);
-                OSS_TWIDDLE_IPORT(drv, cmd, SOUND_MIXER_WRITE_CD, AUDIO_CD, k);
-
-                OSS_TWIDDLE_PORT(drv, cmd, SOUND_MIXER_WRITE_SPEAKER, AUDIO_SPEAKER, k);
-                OSS_TWIDDLE_PORT(drv, cmd, SOUND_MIXER_WRITE_LINE1, AUDIO_HEADPHONE, k);
-                OSS_TWIDDLE_PORT(drv, cmd, SOUND_MIXER_WRITE_LINE2, AUDIO_LINE_OUT, k);
-                return put_user(k, (int *)arg);
-        case SOUND_MIXER_READ_RECSRC: 
-                if (drv->ops->get_input_port)
-                        i = drv->ops->get_input_port(drv);
-
-                /* only one should ever be selected */
-                if (i & AUDIO_CD) j = SOUND_MASK_CD;
-                if (i & AUDIO_LINE_IN) j = SOUND_MASK_LINE;
-                if (i & AUDIO_MICROPHONE) j = SOUND_MASK_MIC;
-    
-                return put_user(j, (int *)arg);
-  case SOUND_MIXER_WRITE_RECSRC: 
-          if (!drv->ops->set_input_port)
-                  return -EINVAL;
-          if (get_user(k, (int *)arg))
-                  return -EFAULT;
-
-          /* only one should ever be selected */
-          if (k & SOUND_MASK_CD) j = AUDIO_CD;
-          if (k & SOUND_MASK_LINE) j = AUDIO_LINE_IN;
-          if (k & SOUND_MASK_MIC) j = AUDIO_MICROPHONE;
-          oprintk(("setting inport to %d\n", j));
-          i = drv->ops->set_input_port(drv, j);
-    
-          return put_user(i, (int *)arg);
-        case SOUND_MIXER_READ_RECMASK: 
-                if (drv->ops->get_input_ports)
-                        i = drv->ops->get_input_ports(drv);
-                /* what do we support? */
-                if (i & AUDIO_MICROPHONE) j |= SOUND_MASK_MIC;
-                if (i & AUDIO_LINE_IN) j |= SOUND_MASK_LINE;
-                if (i & AUDIO_CD) j |= SOUND_MASK_CD;
-    
-                return put_user(j, (int *)arg);
-        case SOUND_MIXER_READ_CAPS: /* mixer capabilities */
-                i = SOUND_CAP_EXCL_INPUT;
-                return put_user(i, (int *)arg);
-
-        case SOUND_MIXER_READ_DEVMASK: /* all supported devices */
-                if (drv->ops->get_input_ports)
-                        i = drv->ops->get_input_ports(drv);
-                /* what do we support? */
-                if (i & AUDIO_MICROPHONE) j |= SOUND_MASK_MIC;
-                if (i & AUDIO_LINE_IN) j |= SOUND_MASK_LINE;
-                if (i & AUDIO_CD) j |= SOUND_MASK_CD;
-    
-                if (drv->ops->get_output_ports)
-                        i = drv->ops->get_output_ports(drv);
-                if (i & AUDIO_SPEAKER) j |= SOUND_MASK_SPEAKER;
-                if (i & AUDIO_HEADPHONE) j |= SOUND_MASK_LINE1;
-                if (i & AUDIO_LINE_OUT) j |= SOUND_MASK_LINE2;
-
-                j |= SOUND_MASK_VOLUME;
-
-        case SOUND_MIXER_READ_STEREODEVS: /* what supports stereo */
-                j |= SOUND_MASK_PCM|SOUND_MASK_RECLEV;
-
-                if (cmd == SOUND_MIXER_READ_STEREODEVS)
-                        j &= ~(MONO_DEVICES);
-                return put_user(j, (int *)arg);
-        default:
-                return -EINVAL;
-        };
-}
-
-/* AUDIO_SETINFO uses these to set values if possible. */
-static __inline__ int 
-__sparcaudio_if_set_do(struct sparcaudio_driver *drv, 
-		       int (*set_function)(struct sparcaudio_driver *, int), 
-		       int (*get_function)(struct sparcaudio_driver *), 
-		       unsigned int value)
-{
-        if (set_function && Modify(value))
-                return (int) set_function(drv, value);
-        else if (get_function)
-                return (int) get_function(drv);
-        else 
-                return 0;
-}
-
-static __inline__ int 
-__sparcaudio_if_setc_do(struct sparcaudio_driver *drv, 
-			int (*set_function)(struct sparcaudio_driver *, int), 
-			int (*get_function)(struct sparcaudio_driver *), 
-			unsigned char value)
-{
-        if (set_function && Modifyc(value))
-                return (char) set_function(drv, (int)value);
-        else if (get_function)
-                return (char) get_function(drv);
-        else 
-                return 0;
-}
-
-/* I_FLUSH, I_{G,S}ETSIG, I_NREAD provided for SunOS compatibility
- *
- * I must admit I'm quite ashamed of the state of the ioctl handling,
- * but I do have several optimizations which I'm planning. -- DJB
- */
-static int sparcaudio_ioctl(struct inode * inode, struct file * file,
-			    unsigned int cmd, unsigned long arg)
-{
-	int retval = 0, i, j, k;
-	int minor = minor(inode->i_rdev);
-	struct audio_info ainfo;
-	audio_buf_info binfo;
-	count_info cinfo;
-	struct sparcaudio_driver *drv = 
-                drivers[(minor >> SPARCAUDIO_DEVICE_SHIFT)];
-
-	switch (minor & 0xf) {
-	case SPARCAUDIO_MIXER_MINOR:
-                return sparcaudio_mixer_ioctl(inode, file, cmd, (unsigned int *)arg);
-	case SPARCAUDIO_DSP16_MINOR:
-        case SPARCAUDIO_DSP_MINOR:
-	case SPARCAUDIO_AUDIO_MINOR:
-	case SPARCAUDIO_AUDIOCTL_MINOR:
-                /* According to the OSS prog int, you can mixer ioctl /dev/dsp */
-                if (_IOC_TYPE(cmd) == 'M')
-                        return sparcaudio_mixer_ioctl(inode, 
-                                                      file, cmd, (unsigned int *)arg);
-                switch (cmd) {
-                case I_GETSIG:
-                case I_GETSIG_SOLARIS:
-                        j = (int) lis_get_elist_ent(drv->sd_siglist,current->pid);
-                        put_user(j, (int *)arg);
-                        retval = drv->input_count;
-                        break;
-
-                case I_SETSIG:
-                case I_SETSIG_SOLARIS:
-                        if ((minor & 0xf) == SPARCAUDIO_AUDIOCTL_MINOR) {
-                                if (!arg) {
-                                        if (lis_del_from_elist(&(drv->sd_siglist),
-                                                               current->pid,S_ALL)) {
-                                                retval = -EINVAL;
-                                        } else if (!drv->sd_siglist) {
-                                                drv->sd_sigflags=0;
-                                        }
-                                } else if (lis_add_to_elist(&(drv->sd_siglist),
-                                                            current->pid,
-                                                            (short)arg)) {
-                                        retval = -EAGAIN;
-                                } else {
-                                        ((drv->sd_sigflags) |= (arg));
-                                }
-                        }
-                        break;
-                case I_NREAD:
-                case I_NREAD_SOLARIS:
-                        /* According to the Solaris man page, this copies out
-                         * the size of the first streams buffer and returns 
-                         * the number of streams messages on the read queue as
-                         * as its retval. (streamio(7I)) This should work.
-                         */
-                        j = (drv->input_count > 0) ? drv->input_buffer_size : 0;
-                        put_user(j, (int *)arg);
-                        retval = drv->input_count;
-                        break;
-
-                        /* A poor substitute until we do true resizable buffers. */
-                case SNDCTL_DSP_GETISPACE:
-                        binfo.fragstotal = drv->num_input_buffers;
-                        binfo.fragments = drv->num_input_buffers - 
-                                (drv->input_count + drv->recording_count);
-                        binfo.fragsize = drv->input_buffer_size;
-                        binfo.bytes = binfo.fragments*binfo.fragsize;
-	    
-                        retval = verify_area(VERIFY_WRITE, (int *)arg, sizeof(binfo));
-                        if (retval)
-                                break;
-                        copy_to_user(&((char *)arg)[0], (char *)&binfo, sizeof(binfo));
-                        break;
-                case SNDCTL_DSP_GETOSPACE:
-                        binfo.fragstotal = drv->num_output_buffers;
-                        binfo.fragments = drv->num_output_buffers - 
-                                (drv->output_count + drv->playing_count + 
-                                 (drv->output_offset ? 1 : 0));
-                        binfo.fragsize = drv->output_buffer_size;
-                        binfo.bytes = binfo.fragments*binfo.fragsize + 
-                                (drv->output_buffer_size - drv->output_offset);
-	    
-                        retval = verify_area(VERIFY_WRITE, (int *)arg, sizeof(binfo));
-                        if (retval)
-                                break;
-                        copy_to_user(&((char *)arg)[0], (char *)&binfo, sizeof(binfo));
-                        break;
-                case SNDCTL_DSP_GETIPTR:
-                case SNDCTL_DSP_GETOPTR:
-                        /* int bytes (number of bytes read/written since last)
-                         * int blocks (number of frags read/wrote since last call)
-                         * int ptr (current position of dma in buffer)
-                         */
-                        retval = 0;
-                        cinfo.bytes = 0;
-                        cinfo.ptr = 0;
-                        cinfo.blocks = 0;
-                        cinfo.bytes += cinfo.ptr;
-	    
-                        retval = verify_area(VERIFY_WRITE, (int *)arg, sizeof(cinfo));
-                        if (retval)
-                                break;
-                        copy_to_user(&((char *)arg)[0], (char *)&cinfo, sizeof(cinfo));
-                        break;
-                case SNDCTL_DSP_SETFRAGMENT:
-                        /* XXX Small hack to get ESD/Enlightenment to work.  --DaveM */
-                        retval = 0;
-                        break;
-
-                case SNDCTL_DSP_SUBDIVIDE:
-                        /* I don't understand what I need to do yet. */
-                        retval = -EINVAL;
-                        break;
-                case SNDCTL_DSP_SETTRIGGER:
-                        /* This may not be 100% correct */
-                        if ((arg & PCM_ENABLE_INPUT) && drv->ops->get_input_pause &&
-                            drv->ops->set_input_pause) {
-                                if (drv->ops->get_input_pause(drv))
-                                        drv->ops->set_input_pause(drv, 0);
-                        } else {
-                                if (!drv->ops->get_input_pause(drv))
-                                        drv->ops->set_input_pause(drv, 1);
-                        }
-                        if ((arg & PCM_ENABLE_OUTPUT) && drv->ops->get_output_pause &&
-                            drv->ops->set_output_pause) {
-                                if (drv->ops->get_output_pause(drv))
-                                        drv->ops->set_output_pause(drv, 0);
-                        } else {
-                                if (!drv->ops->get_output_pause(drv))
-                                        drv->ops->set_output_pause(drv, 1);
-                        }
-                        break;
-                case SNDCTL_DSP_GETTRIGGER:
-                        j = 0;
-                        if (drv->ops->get_input_pause) {
-                                if (drv->ops->get_input_pause(drv))
-                                        j = PCM_ENABLE_INPUT;
-                        }
-                        if (drv->ops->get_output_pause) {
-                                if (drv->ops->get_output_pause(drv))
-                                        j |= PCM_ENABLE_OUTPUT;
-                        }
-                        put_user(j, (int *)arg);
-                        break;
-                case SNDCTL_DSP_GETBLKSIZE:
-                        j = drv->input_buffer_size;
-                        put_user(j, (int *)arg);
-                        break;
-                case SNDCTL_DSP_SPEED:
-                        if ((!drv->ops->set_output_rate) && 
-                            (!drv->ops->set_input_rate)) {
-                                retval = -EINVAL;
-                                break;
-                        }
-                        get_user(i, (int *)arg)
-                        tprintk(("setting speed to %d\n", i));
-                        drv->ops->set_input_rate(drv, i);
-                        drv->ops->set_output_rate(drv, i);
-                        j = drv->ops->get_output_rate(drv);
-                        put_user(j, (int *)arg);
-                        break;
-                case SNDCTL_DSP_GETCAPS:
-                        /* All Sparc audio hardware is full duplex.
-                         * 4231 supports DMA pointer reading, 7930 is byte at a time.
-                         * Pause functionality emulates trigger
-                         */
-                        j = DSP_CAP_DUPLEX | DSP_CAP_TRIGGER | DSP_CAP_REALTIME;
-                        put_user(j, (int *)arg);
-                        break;
-                case SNDCTL_DSP_GETFMTS:
-                        if (drv->ops->get_formats) {
-                                j = drv->ops->get_formats(drv);
-                                put_user(j, (int *)arg);
-                        } else {
-                                retval = -EINVAL;
-                        }
-                        break;
-                case SNDCTL_DSP_SETFMT:
-                        /* need to decode into encoding, precision */
-                        get_user(i, (int *)arg);
-	    
-                        /* handle special case here */
-                        if (i == AFMT_QUERY) {
-                                j = drv->ops->get_output_encoding(drv);
-                                k = drv->ops->get_output_precision(drv);
-                                if (j == AUDIO_ENCODING_DVI) {
-                                        i = AFMT_IMA_ADPCM;
-                                } else if (k == 8) {
-                                        switch (j) {
-                                        case AUDIO_ENCODING_ULAW:
-                                                i = AFMT_MU_LAW;
-                                                break;
-                                        case AUDIO_ENCODING_ALAW:
-                                                i = AFMT_A_LAW;
-                                                break;
-                                        case AUDIO_ENCODING_LINEAR8:
-                                                i = AFMT_U8;
-                                                break;
-                                        };
-                                } else if (k == 16) {
-                                        switch (j) {
-                                        case AUDIO_ENCODING_LINEAR:
-                                                i = AFMT_S16_BE;
-                                                break;
-                                        case AUDIO_ENCODING_LINEARLE:
-                                                i = AFMT_S16_LE;
-                                                break;
-                                        };
-                                } 
-                                put_user(i, (int *)arg);
-                                break;
-                        }
-
-                        /* Without these there's no point in trying */
-                        if (!drv->ops->set_input_precision ||
-                            !drv->ops->set_input_encoding ||
-                            !drv->ops->set_output_precision ||
-                            !drv->ops->set_output_encoding) {
-                                eprintk(("missing set routines: failed\n"));
-                                retval = -EINVAL;
-                                break;
-                        }
-
-                        if (drv->ops->get_formats) {
-                                if (!(drv->ops->get_formats(drv) & i)) {
-                                        dprintk(("format not supported\n"));
-                                        return -EINVAL;
-                                }
-                        }
-                        switch (i) {
-                        case AFMT_S16_LE:
-                                ainfo.record.precision = ainfo.play.precision = 16;
-                                ainfo.record.encoding = ainfo.play.encoding =
-                                        AUDIO_ENCODING_LINEARLE;
-                                break;
-                        case AFMT_S16_BE:
-                                ainfo.record.precision = ainfo.play.precision = 16;
-                                ainfo.record.encoding = ainfo.play.encoding =
-                                        AUDIO_ENCODING_LINEAR;
-                                break;
-                        case AFMT_MU_LAW:
-                                ainfo.record.precision = ainfo.play.precision = 8;
-                                ainfo.record.encoding = ainfo.play.encoding =
-                                        AUDIO_ENCODING_ULAW;
-                                break;
-                        case AFMT_A_LAW:
-                                ainfo.record.precision = ainfo.play.precision = 8;
-                                ainfo.record.encoding = ainfo.play.encoding =
-                                        AUDIO_ENCODING_ALAW;
-                                break;
-                        case AFMT_U8:
-                                ainfo.record.precision = ainfo.play.precision = 8;
-                                ainfo.record.encoding = ainfo.play.encoding =
-                                        AUDIO_ENCODING_LINEAR8;
-                                break;
-                        };
-                        tprintk(("setting fmt to enc %d pr %d\n",
-                                 ainfo.play.encoding,
-                                 ainfo.play.precision));
-                        if ((drv->ops->set_input_precision(drv,
-                                                           ainfo.record.precision) 
-                             < 0) ||
-                            (drv->ops->set_output_precision(drv,
-                                                            ainfo.play.precision)  
-                             < 0) ||
-                            (drv->ops->set_input_encoding(drv,
-                                                          ainfo.record.encoding)
-                             < 0) ||
-                            (drv->ops->set_output_encoding(drv,
-                                                           ainfo.play.encoding)
-                             < 0)) {
-                                dprintk(("setting format: failed\n"));
-                                return -EINVAL;
-                        }
-                        put_user(i, (int *)arg);
-                        break;
-                case SNDCTL_DSP_CHANNELS:
-                        if ((!drv->ops->set_output_channels) && 
-                            (!drv->ops->set_input_channels)) {
-                                retval = -EINVAL;
-                                break;
-                        }
-                        get_user(i, (int *)arg);
-                        drv->ops->set_input_channels(drv, i);
-                        drv->ops->set_output_channels(drv, i);
-                        i = drv->ops->get_output_channels(drv);
-                        put_user(i, (int *)arg);
-                        break;
-                case SNDCTL_DSP_STEREO:
-                        if ((!drv->ops->set_output_channels) && 
-                            (!drv->ops->set_input_channels)) {
-                                retval = -EINVAL;
-                                break;
-                        }
-                        get_user(i, (int *)arg);
-                        drv->ops->set_input_channels(drv, (i + 1));
-                        drv->ops->set_output_channels(drv, (i + 1));
-                        i = ((drv->ops->get_output_channels(drv)) - 1);
-                        put_user(i, (int *)arg);
-                        break;
-                case SNDCTL_DSP_POST:
-                case SNDCTL_DSP_SYNC:
-                case AUDIO_DRAIN:
-                        /* Deal with weirdness so we can fill buffers */
-                        if (drv->output_offset) {
-                                drv->output_offset = 0;
-                                drv->output_rear = (drv->output_rear + 1)
-                                        % drv->num_output_buffers;
-                                drv->output_count++;
-                        }
-                        if (drv->output_count > 0) {
-                                sparcaudio_sync_output(drv);
-                                /* Only pause for DRAIN/SYNC, not POST */
-                                if (cmd != SNDCTL_DSP_POST) {
-                                        interruptible_sleep_on(&drv->output_drain_wait);
-                                        retval = (signal_pending(current)) ? -EINTR : 0;
-                                }
-                        }
-                        break;
-                case I_FLUSH:
-                case I_FLUSH_SOLARIS:
-                        if (((unsigned int)arg == FLUSHW) || 
-                            ((unsigned int)arg == FLUSHRW)) {
-                                if (file->f_mode & FMODE_WRITE) {
-                                        sparcaudio_sync_output(drv);
-                                        if (drv->output_active) {
-                                                wake_up_interruptible(&drv->output_write_wait);
-                                                drv->ops->stop_output(drv);
-                                        }
-                                        drv->output_offset = 0;
-                                        drv->output_active = 0;
-                                        drv->output_front = 0;
-                                        drv->output_rear = 0;
-                                        drv->output_count = 0;
-                                        drv->output_size = 0;
-                                        drv->playing_count = 0;
-                                        drv->output_eof = 0;
-                                }
-                        }
-                        if (((unsigned int)arg == FLUSHR) || 
-                            ((unsigned int)arg == FLUSHRW)) {
-                                if (drv->input_active && (file->f_mode & FMODE_READ)) {
-                                        wake_up_interruptible(&drv->input_read_wait);
-                                        drv->ops->stop_input(drv);
-                                        drv->input_active = 0;
-                                        drv->input_front = 0;
-                                        drv->input_rear = 0;
-                                        drv->input_count = 0;
-                                        drv->input_size = 0;
-                                        drv->input_offset = 0;
-                                        drv->recording_count = 0;
-                                }
-                                if ((file->f_mode & FMODE_READ) && 
-                                    (drv->flags & SDF_OPEN_READ)) {
-                                        if (drv->duplex == 2)
-                                                drv->input_count = drv->output_count;
-                                        drv->ops->start_input(drv, 
-                                                              drv->input_buffers[drv->input_front],
-                                                              drv->input_buffer_size);
-                                        drv->input_active = 1;
-                                }
-                        }
-                        if (((unsigned int)arg == FLUSHW) || 
-                            ((unsigned int)arg == FLUSHRW)) {
-                                if ((file->f_mode & FMODE_WRITE) && 
-                                    !(drv->flags & SDF_OPEN_WRITE)) {
-                                        kill_procs(drv->sd_siglist,SIGPOLL,S_MSG);
-                                        sparcaudio_sync_output(drv);
-                                }
-                        }
-                        break;
-                case SNDCTL_DSP_RESET:
-                case AUDIO_FLUSH:
-                        if (drv->output_active && (file->f_mode & FMODE_WRITE)) {
-                                wake_up_interruptible(&drv->output_write_wait);
-                                drv->ops->stop_output(drv);
-                                drv->output_active = 0;
-                                drv->output_front = 0;
-                                drv->output_rear = 0;
-                                drv->output_count = 0;
-                                drv->output_size = 0;
-                                drv->playing_count = 0;
-                                drv->output_offset = 0;
-                                drv->output_eof = 0;
-                        }
-                        if (drv->input_active && (file->f_mode & FMODE_READ)) {
-                                wake_up_interruptible(&drv->input_read_wait);
-                                drv->ops->stop_input(drv);
-                                drv->input_active = 0;
-                                drv->input_front = 0;
-                                drv->input_rear = 0;
-                                drv->input_count = 0;
-                                drv->input_size = 0;
-                                drv->input_offset = 0;
-                                drv->recording_count = 0;
-                        }
-                        if ((file->f_mode & FMODE_READ) && 
-                            !(drv->flags & SDF_OPEN_READ)) {
-                                drv->ops->start_input(drv, 
-                                                      drv->input_buffers[drv->input_front],
-                                                      drv->input_buffer_size);
-                                drv->input_active = 1;
-                        }
-                        if ((file->f_mode & FMODE_WRITE) && 
-                            !(drv->flags & SDF_OPEN_WRITE)) {
-                                sparcaudio_sync_output(drv);
-                        }
-                        break;
-                case AUDIO_GETDEV:
-                        if (drv->ops->sunaudio_getdev) {
-                                audio_device_t tmp;
-	      
-                                retval = verify_area(VERIFY_WRITE, (void *)arg, 
-                                                     sizeof(audio_device_t));
-                                if (!retval)
-                                        drv->ops->sunaudio_getdev(drv, &tmp);
-                                copy_to_user((audio_device_t *)arg, &tmp, sizeof(tmp));
-                        } else {
-                                retval = -EINVAL;
-                        }
-                        break;
-                case AUDIO_GETDEV_SUNOS:
-                        if (drv->ops->sunaudio_getdev_sunos) {
-                                int tmp = drv->ops->sunaudio_getdev_sunos(drv);
-
-                                retval = verify_area(VERIFY_WRITE, (void *)arg, sizeof(int));
-                                if (!retval)
-                                        copy_to_user((int *)arg, &tmp, sizeof(tmp));
-                        } else {
-                                retval = -EINVAL;
-                        }
-                        break;
-                case AUDIO_GETINFO:
-                        AUDIO_INITINFO(&ainfo);
-
-                        if (drv->ops->get_input_rate)
-                                ainfo.record.sample_rate =
-                                        drv->ops->get_input_rate(drv);
-                        else
-                                ainfo.record.sample_rate = (8000);
-                        if (drv->ops->get_input_channels)
-                                ainfo.record.channels =
-                                        drv->ops->get_input_channels(drv);
-                        else
-                                ainfo.record.channels = (1);
-                        if (drv->ops->get_input_precision)
-                                ainfo.record.precision =
-                                        drv->ops->get_input_precision(drv);
-                        else
-                                ainfo.record.precision = (8);
-                        if (drv->ops->get_input_encoding)
-                                ainfo.record.encoding =
-                                        drv->ops->get_input_encoding(drv);
-                        else
-                                ainfo.record.encoding = (AUDIO_ENCODING_ULAW);
-                        if (drv->ops->get_input_volume)
-                                ainfo.record.gain =
-                                        drv->ops->get_input_volume(drv);
-                        else
-                                ainfo.record.gain = (0);
-                        if (drv->ops->get_input_port)
-                                ainfo.record.port =
-                                        drv->ops->get_input_port(drv);
-                        else
-                                ainfo.record.port = (0);
-                        if (drv->ops->get_input_ports)
-                                ainfo.record.avail_ports = 
-                                        drv->ops->get_input_ports(drv);
-                        else
-                                ainfo.record.avail_ports = (0);
-
-                        /* To make e.g. vat happy, we let them think they control this */
-                        ainfo.record.buffer_size = drv->buffer_size;
-                        if (drv->ops->get_input_samples)
-                                ainfo.record.samples = drv->ops->get_input_samples(drv);
-                        else
-                                ainfo.record.samples = 0;
-
-                        /* This is undefined in the record context in Solaris */
-                        ainfo.record.eof = 0;
-                        if (drv->ops->get_input_pause)
-                                ainfo.record.pause =
-                                        drv->ops->get_input_pause(drv);
-                        else
-                                ainfo.record.pause = 0;
-                        if (drv->ops->get_input_error)
-                                ainfo.record.error = 
-                                        (unsigned char) drv->ops->get_input_error(drv);
-                        else
-                                ainfo.record.error = 0;
-                        ainfo.record.waiting = 0;
-                        if (drv->ops->get_input_balance)
-                                ainfo.record.balance =
-                                        (unsigned char) drv->ops->get_input_balance(drv);
-                        else
-                                ainfo.record.balance = (unsigned char)(AUDIO_MID_BALANCE);
-                        ainfo.record.minordev = 4 + (minor << SPARCAUDIO_DEVICE_SHIFT);
-                        ainfo.record.open = (drv->flags & SDF_OPEN_READ);
-                        ainfo.record.active = 0;
-
-                        if (drv->ops->get_output_rate)
-                                ainfo.play.sample_rate =
-                                        drv->ops->get_output_rate(drv);
-                        else
-                                ainfo.play.sample_rate = (8000);
-                        if (drv->ops->get_output_channels)
-                                ainfo.play.channels =
-                                        drv->ops->get_output_channels(drv);
-                        else
-                                ainfo.play.channels = (1);
-                        if (drv->ops->get_output_precision)
-                                ainfo.play.precision =
-                                        drv->ops->get_output_precision(drv);
-                        else
-                                ainfo.play.precision = (8);
-                        if (drv->ops->get_output_encoding)
-                                ainfo.play.encoding =
-                                        drv->ops->get_output_encoding(drv);
-                        else
-                                ainfo.play.encoding = (AUDIO_ENCODING_ULAW);
-                        if (drv->ops->get_output_volume)
-                                ainfo.play.gain =
-                                        drv->ops->get_output_volume(drv);
-                        else
-                                ainfo.play.gain = (0);
-                        if (drv->ops->get_output_port)
-                                ainfo.play.port =
-                                        drv->ops->get_output_port(drv);
-                        else
-                                ainfo.play.port = (0);
-                        if (drv->ops->get_output_ports)
-                                ainfo.play.avail_ports = 
-                                        drv->ops->get_output_ports(drv);
-                        else
-                                ainfo.play.avail_ports = (0);
-
-                        /* This is not defined in the play context in Solaris */
-                        ainfo.play.buffer_size = 0;
-                        if (drv->ops->get_output_samples)
-                                ainfo.play.samples = drv->ops->get_output_samples(drv);
-                        else
-                                ainfo.play.samples = 0;
-                        ainfo.play.eof = drv->output_eof;
-                        if (drv->ops->get_output_pause)
-                                ainfo.play.pause =
-                                        drv->ops->get_output_pause(drv);
-                        else
-                                ainfo.play.pause = 0;
-                        if (drv->ops->get_output_error)
-                                ainfo.play.error =
-                                        (unsigned char)drv->ops->get_output_error(drv);
-                        else
-                                ainfo.play.error = 0;
-                        ainfo.play.waiting = waitqueue_active(&drv->open_wait);
-                        if (drv->ops->get_output_balance)
-                                ainfo.play.balance =
-                                        (unsigned char)drv->ops->get_output_balance(drv);
-                        else
-                                ainfo.play.balance = (unsigned char)(AUDIO_MID_BALANCE);
-                        ainfo.play.minordev = 4 + (minor << SPARCAUDIO_DEVICE_SHIFT);
-                        ainfo.play.open = (drv->flags & SDF_OPEN_WRITE);
-                        ainfo.play.active = drv->output_active;
-	    
-                        if (drv->ops->get_monitor_volume)
-                                ainfo.monitor_gain =
-                                        drv->ops->get_monitor_volume(drv);
-                        else
-                                ainfo.monitor_gain = (0);
-
-                        if (drv->ops->get_output_muted)
-                                ainfo.output_muted = 
-                                        (unsigned char)drv->ops->get_output_muted(drv);
-                        else
-                                ainfo.output_muted = (unsigned char)(0);
-
-                        retval = verify_area(VERIFY_WRITE, (void *)arg,
-                                             sizeof(struct audio_info));
-                        if (retval < 0)
-                                break;
-
-                        copy_to_user((struct audio_info *)arg, &ainfo, sizeof(ainfo));
-                        break;
-                case AUDIO_SETINFO:
-                {
-                        audio_info_t curinfo, newinfo;
-	      
-                        if (verify_area(VERIFY_READ, (audio_info_t *)arg, 
-                                        sizeof(audio_info_t))) {
-                                dprintk(("verify_area failed\n"));
-                                return -EINVAL;
-                        }
-                        copy_from_user(&ainfo, (audio_info_t *)arg, sizeof(audio_info_t));
-
-                        /* Without these there's no point in trying */
-                        if (!drv->ops->get_input_precision ||
-                            !drv->ops->get_input_channels ||
-                            !drv->ops->get_input_rate ||
-                            !drv->ops->get_input_encoding ||
-                            !drv->ops->get_output_precision ||
-                            !drv->ops->get_output_channels ||
-                            !drv->ops->get_output_rate ||
-                            !drv->ops->get_output_encoding) {
-                                eprintk(("missing get routines: failed\n"));
-                                retval = -EINVAL;
-                                break;
-                        }
-
-                        /* Do bounds checking for things which always apply.
-                         * Follow with enforcement of basic tenets of certain
-                         * encodings. Everything over and above generic is
-                         * enforced by the driver, which can assume that
-                         * Martian cases are taken care of here.
-                         */
-                        if (Modify(ainfo.play.gain) && 
-                            ((ainfo.play.gain > AUDIO_MAX_GAIN) || 
-                             (ainfo.play.gain < AUDIO_MIN_GAIN))) {
-                                /* Need to differentiate this from e.g. the above error */
-                                eprintk(("play gain bounds: failed %d\n", ainfo.play.gain));
-                                retval = -EINVAL;
-                                break;
-                        }
-                        if (Modify(ainfo.record.gain) &&
-                            ((ainfo.record.gain > AUDIO_MAX_GAIN) ||
-                             (ainfo.record.gain < AUDIO_MIN_GAIN))) {
-                                eprintk(("rec gain bounds: failed %d\n", ainfo.record.gain));
-                                retval = -EINVAL;
-                                break;
-                        }
-                        if (Modify(ainfo.monitor_gain) &&
-                            ((ainfo.monitor_gain > AUDIO_MAX_GAIN) ||
-                             (ainfo.monitor_gain < AUDIO_MIN_GAIN))) {
-                                eprintk(("monitor gain bounds: failed\n"));
-                                retval = -EINVAL;
-                                break;
-                        }
-
-                        /* Don't need to check less than zero on these */
-                        if (Modifyc(ainfo.play.balance) &&
-                            (ainfo.play.balance > AUDIO_RIGHT_BALANCE)) {
-                                eprintk(("play balance bounds: %d failed\n", 
-                                         (int)ainfo.play.balance));
-                                retval = -EINVAL;
-                                break;
-                        }
-                        if (Modifyc(ainfo.record.balance) &&
-                            (ainfo.record.balance > AUDIO_RIGHT_BALANCE)) {
-                                eprintk(("rec balance bounds: failed\n"));
-                                retval = -EINVAL;
-                                break;
-                        }
-	      
-                        /* If any of these changed, record them all, then make
-                         * changes atomically. If something fails, back it all out.
-                         */
-                        if (Modify(ainfo.record.precision) || 
-                            Modify(ainfo.record.sample_rate) ||
-                            Modify(ainfo.record.channels) ||
-                            Modify(ainfo.record.encoding) || 
-                            Modify(ainfo.play.precision) || 
-                            Modify(ainfo.play.sample_rate) ||
-                            Modify(ainfo.play.channels) ||
-                            Modify(ainfo.play.encoding)) {
-                                /* If they're trying to change something we
-                                 * have no routine for, they lose.
-                                 */
-                                if ((!drv->ops->set_input_encoding && 
-                                     Modify(ainfo.record.encoding)) ||
-                                    (!drv->ops->set_input_rate && 
-                                     Modify(ainfo.record.sample_rate)) ||
-                                    (!drv->ops->set_input_precision && 
-                                     Modify(ainfo.record.precision)) ||
-                                    (!drv->ops->set_input_channels && 
-                                     Modify(ainfo.record.channels))) {
-                                        eprintk(("rec set no routines: failed\n"));
-                                        retval = -EINVAL;
-                                        break;
-                                }		  
-		  
-                                curinfo.record.encoding = 
-                                        drv->ops->get_input_encoding(drv);
-                                curinfo.record.sample_rate = 
-                                        drv->ops->get_input_rate(drv);	   
-                                curinfo.record.precision = 
-                                        drv->ops->get_input_precision(drv);	   
-                                curinfo.record.channels = 
-                                        drv->ops->get_input_channels(drv);	   
-                                newinfo.record.encoding =
-                                        Modify(ainfo.record.encoding) ? 
-                                        ainfo.record.encoding :
-                                        curinfo.record.encoding;
-                                newinfo.record.sample_rate =
-                                        Modify(ainfo.record.sample_rate) ?
-                                        ainfo.record.sample_rate :
-                                        curinfo.record.sample_rate;
-                                newinfo.record.precision =
-                                        Modify(ainfo.record.precision) ? 
-                                        ainfo.record.precision :
-                                        curinfo.record.precision;
-                                newinfo.record.channels =
-                                        Modify(ainfo.record.channels) ? 
-                                        ainfo.record.channels :
-                                        curinfo.record.channels;
-		    
-                                switch (newinfo.record.encoding) {
-                                case AUDIO_ENCODING_ALAW:
-                                case AUDIO_ENCODING_ULAW:
-                                        if (newinfo.record.precision != 8) {
-                                                eprintk(("rec law precision bounds: "
-                                                         "failed\n"));
-                                                retval = -EINVAL;
-                                                break;
-                                        }
-                                        if (newinfo.record.channels != 1) {
-                                                eprintk(("rec law channel bounds: "
-                                                         "failed\n"));
-                                                retval = -EINVAL;
-                                                break;
-                                        }
-                                        break;
-                                case AUDIO_ENCODING_LINEAR:
-                                case AUDIO_ENCODING_LINEARLE:
-                                        if (newinfo.record.precision != 16) {
-                                                eprintk(("rec lin precision bounds: "
-                                                         "failed\n"));
-                                                retval = -EINVAL;
-                                                break;
-                                        }
-                                        if (newinfo.record.channels != 1 &&
-                                            newinfo.record.channels != 2) {
-                                                eprintk(("rec lin channel bounds: "
-                                                         "failed\n"));
-                                                retval = -EINVAL;
-                                                break;
-                                        }
-                                        break;
-                                case AUDIO_ENCODING_LINEAR8:
-                                        if (newinfo.record.precision != 8) {
-                                                eprintk(("rec lin8 precision bounds: "
-                                                         "failed\n"));
-                                                retval = -EINVAL;
-                                                break;
-                                        }
-                                        if (newinfo.record.channels != 1 && 
-                                            newinfo.record.channels != 2) {
-                                                eprintk(("rec lin8 channel bounds: "
-                                                         "failed\n"));
-                                                retval = -EINVAL;
-                                                break;
-                                        }
-                                };
-		  
-                                if (retval < 0)
-                                        break;
-		  
-                                /* If they're trying to change something we
-                                 * have no routine for, they lose.
-                                 */
-                                if ((!drv->ops->set_output_encoding && 
-                                     Modify(ainfo.play.encoding)) ||
-                                    (!drv->ops->set_output_rate && 
-                                     Modify(ainfo.play.sample_rate)) ||
-                                    (!drv->ops->set_output_precision && 
-                                     Modify(ainfo.play.precision)) ||
-                                    (!drv->ops->set_output_channels && 
-                                     Modify(ainfo.play.channels))) {
-                                        eprintk(("play set no routine: failed\n"));
-                                        retval = -EINVAL;
-                                        break;
-                                }		  
-		  
-                                curinfo.play.encoding = 
-                                        drv->ops->get_output_encoding(drv);
-                                curinfo.play.sample_rate = 
-                                        drv->ops->get_output_rate(drv);	   
-                                curinfo.play.precision = 
-                                        drv->ops->get_output_precision(drv);	   
-                                curinfo.play.channels = 
-                                        drv->ops->get_output_channels(drv);	   
-                                newinfo.play.encoding =
-                                        Modify(ainfo.play.encoding) ? 
-                                        ainfo.play.encoding :
-                                                curinfo.play.encoding;
-                                newinfo.play.sample_rate =
-                                        Modify(ainfo.play.sample_rate) ? 
-                                        ainfo.play.sample_rate :
-                                                curinfo.play.sample_rate;
-                                newinfo.play.precision =
-                                        Modify(ainfo.play.precision) ? 
-                                        ainfo.play.precision :
-                                                curinfo.play.precision;
-                                newinfo.play.channels =
-                                        Modify(ainfo.play.channels) ? 
-                                        ainfo.play.channels :
-                                                curinfo.play.channels;
-		  
-                                switch (newinfo.play.encoding) {
-                                case AUDIO_ENCODING_ALAW:
-                                case AUDIO_ENCODING_ULAW:
-                                        if (newinfo.play.precision != 8) {
-                                                eprintk(("play law precision bounds: "
-                                                         "failed\n"));
-                                                retval = -EINVAL;
-                                                break;
-                                        }
-                                        if (newinfo.play.channels != 1) {
-                                                eprintk(("play law channel bounds: "
-                                                         "failed\n"));
-                                                retval = -EINVAL;
-                                                break;
-                                        }
-                                        break;
-                                case AUDIO_ENCODING_LINEAR:
-                                case AUDIO_ENCODING_LINEARLE:
-                                        if (newinfo.play.precision != 16) {
-                                                eprintk(("play lin precision bounds: "
-                                                         "failed\n"));
-                                                retval = -EINVAL;
-                                                break;
-                                        }
-                                        if (newinfo.play.channels != 1 && 
-                                            newinfo.play.channels != 2) {
-                                                eprintk(("play lin channel bounds: "
-                                                         "failed\n"));
-                                                retval = -EINVAL;
-                                                break;
-                                        }
-                                        break;
-                                case AUDIO_ENCODING_LINEAR8:
-                                        if (newinfo.play.precision != 8) {
-                                                eprintk(("play lin8 precision bounds: "
-                                                         "failed\n"));
-                                                retval = -EINVAL;
-                                                break;
-                                        }
-                                        if (newinfo.play.channels != 1 && 
-                                            newinfo.play.channels != 2) {
-                                                eprintk(("play lin8 channel bounds: "
-                                                         "failed\n"));
-                                                retval = -EINVAL;
-                                                break;
-                                        }
-                                };
-		  
-                                if (retval < 0)
-                                        break;
-		  
-                                /* If we got this far, we're at least sane with
-                                 * respect to generics. Try the changes.
-                                 */
-                                if ((drv->ops->set_input_channels &&
-                                     (drv->ops->set_input_channels(drv, 
-                                                                   newinfo.record.channels)
-                                      < 0)) ||
-                                    (drv->ops->set_output_channels &&
-                                     (drv->ops->set_output_channels(drv, 
-                                                                    newinfo.play.channels)
-                                      < 0)) ||
-                                    (drv->ops->set_input_rate &&
-                                     (drv->ops->set_input_rate(drv, 
-                                                               newinfo.record.sample_rate) 
-                                      < 0)) ||
-                                    (drv->ops->set_output_rate &&
-                                     (drv->ops->set_output_rate(drv, 
-                                                                newinfo.play.sample_rate) 
-                                      < 0)) ||
-                                    (drv->ops->set_input_precision &&
-                                     (drv->ops->set_input_precision(drv, 
-                                                                    newinfo.record.precision)
-                                      < 0)) ||
-                                    (drv->ops->set_output_precision &&
-                                     (drv->ops->set_output_precision(drv, 
-                                                                     newinfo.play.precision)
-                                      < 0)) ||
-                                    (drv->ops->set_input_encoding &&
-                                     (drv->ops->set_input_encoding(drv, 
-                                                                   newinfo.record.encoding)
-                                      < 0)) ||
-                                    (drv->ops->set_output_encoding &&
-                                     (drv->ops->set_output_encoding(drv, 
-                                                                    newinfo.play.encoding)
-                                      < 0))) 
-                                {
-                                        dprintk(("setting format: failed\n"));
-                                        /* Pray we can set it all back. If not, uh... */
-                                        if (drv->ops->set_input_channels)
-                                                drv->ops->set_input_channels(drv, 
-						     curinfo.record.channels);
-                                        if (drv->ops->set_output_channels)
-                                                drv->ops->set_output_channels(drv, 
-                                                                              curinfo.play.channels);
-                                        if (drv->ops->set_input_rate)
-                                                drv->ops->set_input_rate(drv, 
-                                                                         curinfo.record.sample_rate);
-                                        if (drv->ops->set_output_rate)
-                                                drv->ops->set_output_rate(drv, 
-                                                                          curinfo.play.sample_rate);
-                                        if (drv->ops->set_input_precision)
-                                                drv->ops->set_input_precision(drv, 
-                                                                              curinfo.record.precision);
-                                        if (drv->ops->set_output_precision)
-                                                drv->ops->set_output_precision(drv, 
-                                                                               curinfo.play.precision);
-                                        if (drv->ops->set_input_encoding)
-                                                drv->ops->set_input_encoding(drv, 
-                                                                             curinfo.record.encoding);
-                                        if (drv->ops->set_output_encoding)
-                                                drv->ops->set_output_encoding(drv, 
-                                                                              curinfo.play.encoding);
-                                        retval = -EINVAL;
-                                        break;
-                                }
-                        }
-                        
-                        if (retval < 0)
-                                break;
-                        
-                        newinfo.record.balance =
-                                __sparcaudio_if_setc_do(drv, 
-                                                        drv->ops->set_input_balance, 
-                                                        drv->ops->get_input_balance,
-                                                        ainfo.record.balance);
-                        newinfo.play.balance =
-                                __sparcaudio_if_setc_do(drv, 
-                                                        drv->ops->set_output_balance, 
-                                                        drv->ops->get_output_balance,
-                                                        ainfo.play.balance);
-                        newinfo.record.error =
-                                __sparcaudio_if_setc_do(drv, 
-                                                        drv->ops->set_input_error, 
-                                                        drv->ops->get_input_error,
-                                                        ainfo.record.error);
-                        newinfo.play.error =
-                                __sparcaudio_if_setc_do(drv, 
-                                                        drv->ops->set_output_error, 
-                                                        drv->ops->get_output_error,
-                                                        ainfo.play.error);
-                        newinfo.output_muted =
-                                __sparcaudio_if_setc_do(drv, 
-                                                        drv->ops->set_output_muted, 
-                                                        drv->ops->get_output_muted,
-                                                        ainfo.output_muted);
-                        newinfo.record.gain =
-                                __sparcaudio_if_set_do(drv, 
-                                                       drv->ops->set_input_volume, 
-                                                       drv->ops->get_input_volume,
-                                                       ainfo.record.gain);
-                        newinfo.play.gain =
-                                __sparcaudio_if_set_do(drv, 
-                                                       drv->ops->set_output_volume, 
-                                                       drv->ops->get_output_volume,
-                                                       ainfo.play.gain);
-                        newinfo.record.port =
-                                __sparcaudio_if_set_do(drv, 
-                                                       drv->ops->set_input_port, 
-                                                       drv->ops->get_input_port,
-                                                       ainfo.record.port);
-                        newinfo.play.port =
-                                __sparcaudio_if_set_do(drv, 
-                                                       drv->ops->set_output_port, 
-                                                       drv->ops->get_output_port,
-                                                       ainfo.play.port);
-                        newinfo.record.samples =
-                                __sparcaudio_if_set_do(drv, 
-                                                       drv->ops->set_input_samples, 
-                                                       drv->ops->get_input_samples,
-                                                       ainfo.record.samples);
-                        newinfo.play.samples =
-                                __sparcaudio_if_set_do(drv, 
-                                                       drv->ops->set_output_samples, 
-                                                       drv->ops->get_output_samples,
-                                                       ainfo.play.samples);
-                        newinfo.monitor_gain =
-                                __sparcaudio_if_set_do(drv, 
-                                                       drv->ops->set_monitor_volume, 
-                                                       drv->ops->get_monitor_volume,
-                                                       ainfo.monitor_gain);
-
-                        if (Modify(ainfo.record.buffer_size)) {
-                                /* Should sanity check this */
-                                newinfo.record.buffer_size = ainfo.record.buffer_size;
-                                drv->buffer_size = ainfo.record.buffer_size;
-                        } else {
-                                newinfo.record.buffer_size = drv->buffer_size;
-                        }
-
-                        if (Modify(ainfo.play.eof)) {
-                                ainfo.play.eof = newinfo.play.eof;
-                                newinfo.play.eof = drv->output_eof;
-                                drv->output_eof = ainfo.play.eof;
-                        } else {
-                                newinfo.play.eof = drv->output_eof;
-                        }		
-
-                        if (drv->flags & SDF_OPEN_READ) {
-                                newinfo.record.pause =
-                                        __sparcaudio_if_setc_do(drv, 
-                                                                drv->ops->set_input_pause, 
-                                                                drv->ops->get_input_pause,
-                                                                ainfo.record.pause);
-                        } else if (drv->ops->get_input_pause) {
-                                newinfo.record.pause = drv->ops->get_input_pause(drv);
-                        } else {
-                                newinfo.record.pause = 0;
-                        }
-
-                        if (drv->flags & SDF_OPEN_WRITE) {
-                                newinfo.play.pause =
-                                        __sparcaudio_if_setc_do(drv, 
-                                                                drv->ops->set_output_pause, 
-                                                                drv->ops->get_output_pause,
-                                                                ainfo.play.pause);
-                        } else if (drv->ops->get_output_pause) {
-                                newinfo.play.pause = drv->ops->get_output_pause(drv);
-                        } else {
-                                newinfo.play.pause = 0;
-                        }
-	      
-                        retval = verify_area(VERIFY_WRITE, (void *)arg,
-                                             sizeof(struct audio_info));
-
-                        /* Even if we fail, if we made changes let's try notification */
-                        if (!retval) 
-                                copy_to_user((struct audio_info *)arg, &newinfo, 
-                                             sizeof(newinfo));
-	    
-#ifdef REAL_AUDIO_SIGNALS
-                        kill_procs(drv->sd_siglist,SIGPOLL,S_MSG);
-#endif
-                        break;
-                }
-	  
-                default:
-                        if (drv->ops->ioctl)
-                                retval = drv->ops->ioctl(inode,file,cmd,arg,drv);
-                        else
-                                retval = -EINVAL;
-                };
-                break;
-	case SPARCAUDIO_STATUS_MINOR:
-                eprintk(("status minor not yet implemented\n"));
-                retval = -EINVAL;
-	default:
-                eprintk(("unknown minor device number\n"));
-                retval = -EINVAL;
-	}
-	
-	return retval;
-}
-
-static struct file_operations sparcaudioctl_fops = {
-	.owner =	THIS_MODULE,
-	.poll =		sparcaudio_poll,
-	.ioctl =	sparcaudio_ioctl,
-};
-
-static int sparcaudio_open(struct inode * inode, struct file * file)
-{
-        int minor = minor(inode->i_rdev);
-	struct sparcaudio_driver *drv = 
-                drivers[(minor >> SPARCAUDIO_DEVICE_SHIFT)];
-	int err;
-
-	/* A low-level audio driver must exist. */
-	if (!drv)
-		return -ENODEV;
-
-#ifdef S_ZERO_WR
-        /* This is how 2.0 ended up dealing with 0 len writes */
-        inode->i_flags |= S_ZERO_WR;
-#endif
-
-	switch (minor & 0xf) {
-	case SPARCAUDIO_AUDIOCTL_MINOR:
-                file->f_op = &sparcaudioctl_fops;
-                break;
-	case SPARCAUDIO_DSP16_MINOR:
-	case SPARCAUDIO_DSP_MINOR:
-	case SPARCAUDIO_AUDIO_MINOR:
-                /* If the driver is busy, then wait to get through. */
-        retry_open:
-        	if (file->f_mode & FMODE_READ && drv->flags & SDF_OPEN_READ) {
-                        if (file->f_flags & O_NONBLOCK)
-                                return -EBUSY;
-
-                        /* If something is now waiting, signal control device */
-                        kill_procs(drv->sd_siglist,SIGPOLL,S_MSG);
-
-                        interruptible_sleep_on(&drv->open_wait);
-                        if (signal_pending(current))
-                                return -EINTR;
-                        goto retry_open;
-                }
-                if (file->f_mode & FMODE_WRITE && drv->flags & SDF_OPEN_WRITE) {
-                        if (file->f_flags & O_NONBLOCK)
-                                return -EBUSY;
-	    
-                        /* If something is now waiting, signal control device */
-                        kill_procs(drv->sd_siglist,SIGPOLL,S_MSG);
-
-                        interruptible_sleep_on(&drv->open_wait);
-                        if (signal_pending(current))
-                                return -EINTR;
-                        goto retry_open;
-                }
-
-                /* Allow the low-level driver to initialize itself. */
-                if (drv->ops->open) {
-                        err = drv->ops->open(inode,file,drv);
-                        if (err < 0)
-                                return err;
-                }
-
-                /* Mark the driver as locked for read and/or write. */
-                if (file->f_mode & FMODE_READ) {
-                        drv->input_offset = 0;
-                        drv->input_front = 0;
-                        drv->input_rear = 0;
-                        drv->input_count = 0;
-                        drv->input_size = 0;
-                        drv->recording_count = 0;
-
-                        /* Clear pause */
-                        if (drv->ops->set_input_pause)
-                                drv->ops->set_input_pause(drv, 0); 
-                        drv->ops->start_input(drv, drv->input_buffers[drv->input_front],
-                                              drv->input_buffer_size);
-                        drv->input_active = 1;
-                        drv->flags |= SDF_OPEN_READ;
-                }
-
-                if (file->f_mode & FMODE_WRITE) {
-                        drv->output_offset = 0;
-                        drv->output_eof = 0;
-                        drv->playing_count = 0;
-                        drv->output_size = 0;
-                        drv->output_front = 0;
-                        drv->output_rear = 0;
-                        drv->output_count = 0;
-                        drv->output_active = 0;
-
-                        /* Clear pause */
-                        if (drv->ops->set_output_pause)
-                                drv->ops->set_output_pause(drv, 0); 
-                        drv->flags |= SDF_OPEN_WRITE;
-                }  
-
-                break;
-	case SPARCAUDIO_MIXER_MINOR:     
-                file->f_op = &sparcaudioctl_fops;
-                break;
-
-	default:
-                return -ENXIO;
-	};
-
-        /* From the dbri driver:
-         * SunOS 5.5.1 audio(7I) man page says:
-         * "Upon the initial open() of the audio device, the driver
-         *  will reset the data format of the device to the default
-         *  state of 8-bit, 8KHz, mono u-law data."
-         *
-         * Of course, we only do this for /dev/audio, and assume
-         * OSS semantics on /dev/dsp
-         */
-
-	if ((minor & 0xf) == SPARCAUDIO_AUDIO_MINOR) {
-                if (file->f_mode & FMODE_WRITE) {
-                        if (drv->ops->set_output_channels)
-                                drv->ops->set_output_channels(drv, 1);
-                        if (drv->ops->set_output_encoding)
-                                drv->ops->set_output_encoding(drv, AUDIO_ENCODING_ULAW);
-                        if (drv->ops->set_output_rate)
-                                drv->ops->set_output_rate(drv, 8000);
-                }          
-
-                if (file->f_mode & FMODE_READ) {
-                        if (drv->ops->set_input_channels)
-                                drv->ops->set_input_channels(drv, 1);
-                        if (drv->ops->set_input_encoding)
-                                drv->ops->set_input_encoding(drv, AUDIO_ENCODING_ULAW);
-                        if (drv->ops->set_input_rate)
-                                drv->ops->set_input_rate(drv, 8000);
-                }          
-        }
-
-	/* Success! */
-	return 0;
-}
-
-static int sparcaudio_release(struct inode * inode, struct file * file)
-{
-        struct sparcaudio_driver *drv = drivers[(minor(inode->i_rdev) >>
-                                                 SPARCAUDIO_DEVICE_SHIFT)];
-
-	lock_kernel();
-        if (file->f_mode & FMODE_READ) {
-                /* Stop input */
-                drv->ops->stop_input(drv);
-                drv->input_active = 0;
-        }
-
-        if (file->f_mode & FMODE_WRITE) {
-                /* Anything in the queue? */
-                if (drv->output_offset) {
-                        drv->output_offset = 0;
-                        drv->output_rear = (drv->output_rear + 1)
-                                % drv->num_output_buffers;
-                        drv->output_count++;
-                }
-                sparcaudio_sync_output(drv);
-
-                /* Wait for any output still in the queue to be played. */
-                if ((drv->output_count > 0) || (drv->playing_count > 0))
-                        interruptible_sleep_on(&drv->output_drain_wait);
-
-                /* Force any output to be stopped. */
-                drv->ops->stop_output(drv);
-                drv->output_active = 0;
-                drv->playing_count = 0;
-                drv->output_eof = 0;
-        }
-
-        /* Let the low-level driver do any release processing. */
-        if (drv->ops->release)
-                drv->ops->release(inode,file,drv);
-
-        if (file->f_mode & FMODE_READ)
-                drv->flags &= ~(SDF_OPEN_READ);
-
-        if (file->f_mode & FMODE_WRITE) 
-                drv->flags &= ~(SDF_OPEN_WRITE);
-
-        /* Status changed. Signal control device */
-        kill_procs(drv->sd_siglist,SIGPOLL,S_MSG);
-
-        wake_up_interruptible(&drv->open_wait);
-	unlock_kernel();
-
-        return 0;
-}
-
-static struct file_operations sparcaudio_fops = {
-	.owner =	THIS_MODULE,
-	.llseek =	no_llseek,
-	.read =		sparcaudio_read,
-	.write =	sparcaudio_write,
-	.poll =		sparcaudio_poll,
-	.ioctl =	sparcaudio_ioctl,
-	.open =		sparcaudio_open,
-	.release =	sparcaudio_release,
-};
-
-static struct {
-	unsigned short minor;
-	char *name;
-	umode_t mode;
-} dev_list[] = {
-	{ SPARCAUDIO_MIXER_MINOR, "mixer", S_IWUSR | S_IRUGO },
-	{ SPARCAUDIO_DSP_MINOR, "dsp", S_IWUGO | S_IRUSR | S_IRGRP },
-	{ SPARCAUDIO_AUDIO_MINOR, "audio", S_IWUGO | S_IRUSR | S_IRGRP },
-	{ SPARCAUDIO_DSP16_MINOR, "dspW", S_IWUGO | S_IRUSR | S_IRGRP },
-	{ SPARCAUDIO_STATUS_MINOR, "status", S_IRUGO },
-	{ SPARCAUDIO_AUDIOCTL_MINOR, "audioctl", S_IRUGO }
-};
-
-static void sparcaudio_mkname (char *buf, char *name, int dev)
-{
-        if (dev)
-                sprintf (buf, "%s%d", name, dev);
-        else
-                sprintf (buf, "%s", name);
-}
-
-int register_sparcaudio_driver(struct sparcaudio_driver *drv, int duplex)
-{
-	int i, dev;
-	unsigned short minor;
-	char name_buf[32];
-
-	/* If we've used up SPARCAUDIO_MAX_DEVICES, fail */
-	for (dev = 0; dev < SPARCAUDIO_MAX_DEVICES; dev++) {
-                if (drivers[dev] == NULL)
-                        break;
-	}
-
-	if (drivers[dev])
-                return -EIO;
-
-	/* Ensure that the driver has a proper operations structure. */
-	if (!drv->ops || !drv->ops->start_output || !drv->ops->stop_output ||
-	    !drv->ops->start_input || !drv->ops->stop_input)
-		return -EINVAL;
-
-        /* Register ourselves with devfs */
-	for (i=0; i < sizeof (dev_list) / sizeof (*dev_list); i++) {
-		sparcaudio_mkname (name_buf, dev_list[i].name, dev);
-		minor = (dev << SPARCAUDIO_DEVICE_SHIFT) | dev_list[i].minor;
-		devfs_register (devfs_handle, name_buf, DEVFS_FL_NONE,
-				SOUND_MAJOR, minor, S_IFCHR | dev_list[i].mode,
-				&sparcaudio_fops, NULL);
-	}
-
-        /* Setup the circular queues of output and input buffers
-         *
-         * Each buffer is a single page, but output buffers might
-         * be partially filled (by a write with count < output_buffer_size),
-         * so each output buffer also has a paired output size.
-         *
-         * Input buffers, on the other hand, always fill completely,
-         * so we don't need input counts - each contains input_buffer_size
-         * bytes of audio data.
-         *
-         * TODO: Make number of input/output buffers tunable parameters
-         */
-
-        init_waitqueue_head(&drv->open_wait);
-        init_waitqueue_head(&drv->output_write_wait);
-        init_waitqueue_head(&drv->output_drain_wait);
-        init_waitqueue_head(&drv->input_read_wait);
-
-        drv->num_output_buffers = 8;
-	drv->output_buffer_size = (4096 * 2);
-	drv->playing_count = 0;
-	drv->output_offset = 0;
-	drv->output_eof = 0;
-        drv->output_front = 0;
-        drv->output_rear = 0;
-        drv->output_count = 0;
-        drv->output_active = 0;
-        drv->output_buffers = kmalloc(drv->num_output_buffers * 
-				      sizeof(__u8 *), GFP_KERNEL);
-        drv->output_sizes = kmalloc(drv->num_output_buffers * 
-				    sizeof(size_t), GFP_KERNEL);
-        drv->output_notify = kmalloc(drv->num_output_buffers * 
-				    sizeof(char), GFP_KERNEL);
-        if (!drv->output_buffers || !drv->output_sizes || !drv->output_notify)
-                goto kmalloc_failed1;
-
-	drv->output_buffer = kmalloc((drv->output_buffer_size * 
-                                      drv->num_output_buffers),
-                                     GFP_KERNEL);
-	if (!drv->output_buffer)
-                goto kmalloc_failed2;
-
-        /* Allocate the pages for each output buffer. */
-        for (i = 0; i < drv->num_output_buffers; i++) {
-	        drv->output_buffers[i] = (void *)(drv->output_buffer + 
-                                                  (i * drv->output_buffer_size));
-		drv->output_sizes[i] = 0;
-		drv->output_notify[i] = 0;
-        }
-
-        /* Setup the circular queue of input buffers. */
-        drv->num_input_buffers = 8;
-	drv->input_buffer_size = (4096 * 2);
-	drv->recording_count = 0;
-        drv->input_front = 0;
-        drv->input_rear = 0;
-        drv->input_count = 0;
-	drv->input_offset = 0;
-        drv->input_size = 0;
-        drv->input_active = 0;
-        drv->input_buffers = kmalloc(drv->num_input_buffers * sizeof(__u8 *),
-				     GFP_KERNEL);
-        drv->input_sizes = kmalloc(drv->num_input_buffers * 
-                                   sizeof(size_t), GFP_KERNEL);
-        if (!drv->input_buffers || !drv->input_sizes)
-                goto kmalloc_failed3;
-
-        /* Allocate the pages for each input buffer. */
-	if (duplex == 1) {
-                drv->input_buffer = kmalloc((drv->input_buffer_size * 
-                                             drv->num_input_buffers), 
-                                            GFP_DMA);
-                if (!drv->input_buffer)
-                        goto kmalloc_failed4;
-
-                for (i = 0; i < drv->num_input_buffers; i++)
-                        drv->input_buffers[i] = (void *)(drv->input_buffer + 
-                                                         (i * drv->input_buffer_size));
-	} else {
-                if (duplex == 2) {
-                        drv->input_buffer = drv->output_buffer;
-                        drv->input_buffer_size = drv->output_buffer_size;
-                        drv->num_input_buffers = drv->num_output_buffers;
-                        for (i = 0; i < drv->num_input_buffers; i++) 
-                                drv->input_buffers[i] = drv->output_buffers[i];
-                } else {
-                        for (i = 0; i < drv->num_input_buffers; i++) 
-                                drv->input_buffers[i] = NULL;
-                }
-	}
-
-	/* Take note of our duplexity */
-	drv->duplex = duplex;
-
-	/* Ensure that the driver is marked as not being open. */
-	drv->flags = 0;
-
-	MOD_INC_USE_COUNT;
-
-	/* Take driver slot, note which we took */
-	drv->index = dev;
-	drivers[dev] = drv;
-
-	return 0;
-
-kmalloc_failed4:
-	kfree(drv->input_buffer);
-
-kmalloc_failed3:
-        if (drv->input_sizes)
-                kfree(drv->input_sizes);
-        if (drv->input_buffers)
-                kfree(drv->input_buffers);
-        i = drv->num_output_buffers;
-
-kmalloc_failed2:
-	kfree(drv->output_buffer);
-
-kmalloc_failed1:
-        if (drv->output_buffers)
-                kfree(drv->output_buffers);
-        if (drv->output_sizes)
-                kfree(drv->output_sizes);
-        if (drv->output_notify)
-                kfree(drv->output_notify);
-
-        return -ENOMEM;
-}
-
-int unregister_sparcaudio_driver(struct sparcaudio_driver *drv, int duplex)
-{
-	int i;
-	char name_buf[32];
-
-	/* Figure out which driver is unregistering */
-	if (drivers[drv->index] != drv)
-		return -EIO;
-
-	/* Deallocate the queue of output buffers. */
-	kfree(drv->output_buffer);
-	kfree(drv->output_buffers);
-	kfree(drv->output_sizes);
-	kfree(drv->output_notify);
-
-	/* Deallocate the queue of input buffers. */
-	if (duplex == 1) {
-                kfree(drv->input_buffer);
-                kfree(drv->input_sizes);
-	}
-	kfree(drv->input_buffers);
-
-	if (&(drv->sd_siglist) != NULL)
-                lis_free_elist( &(drv->sd_siglist) );
-
-	/* Unregister ourselves with devfs */
-	for (i=0; i < sizeof (dev_list) / sizeof (*dev_list); i++) {
-		sparcaudio_mkname (name_buf, dev_list[i].name, drv->index);
-		devfs_find_and_unregister(devfs_handle, name_buf, 0, 0,
-                                          DEVFS_SPECIAL_CHR, 0);
-	}
-
-	MOD_DEC_USE_COUNT;
-
-	/* Null the appropriate driver */
-	drivers[drv->index] = NULL;
-
-	return 0;
-}
-
-EXPORT_SYMBOL(register_sparcaudio_driver);
-EXPORT_SYMBOL(unregister_sparcaudio_driver);
-EXPORT_SYMBOL(sparcaudio_output_done);
-EXPORT_SYMBOL(sparcaudio_input_done);
-
-static int __init sparcaudio_init(void)
-{
-	/* Register our character device driver with the VFS. */
-	if (register_chrdev(SOUND_MAJOR, "sparcaudio", &sparcaudio_fops))
-		return -EIO;
-
-	devfs_handle = devfs_mk_dir (NULL, "sound", NULL);
-	return 0;
-}
-
-static void __exit sparcaudio_exit(void)
-{
-	unregister_chrdev(SOUND_MAJOR, "sparcaudio");
-	devfs_unregister (devfs_handle);
-}
-
-module_init(sparcaudio_init);
-module_exit(sparcaudio_exit);
-MODULE_LICENSE("GPL");
-
-/*
- * Code from Linux Streams, Copyright 1995 by
- * Graham Wheeler, Francisco J. Ballesteros, Denis Froschauer
- * and available under GPL 
- */
-
-static int
-lis_add_to_elist( strevent_t **list, pid_t pid, short events )
-{
-        strevent_t *ev = NULL;
-
-        if (*list != NULL) {
-                for (ev = (*list)->se_next;
-                     ev != *list && ev->se_pid < pid;
-                     ev = ev->se_next)
-                        ;
-        }
-
-        if (ev == NULL || ev == *list) {             /* no slot for pid in list */
-                ev = (strevent_t *) kmalloc(sizeof(strevent_t), GFP_KERNEL);
-                if (ev == NULL)
-                        return(-ENOMEM);
-
-                if (!*list) {                   /* create dummy head node */
-                        strevent_t *hd;
-
-                        hd = (strevent_t *) kmalloc(sizeof(strevent_t), GFP_KERNEL);
-                        if (hd == NULL) {
-                                kfree(ev);
-                                return(-ENOMEM);
-                        }
-                        (*list = hd)->se_pid = 0;
-                        hd->se_next = hd->se_prev = hd;         /* empty list */
-                }
-
-                /* link node last in the list */
-                ev->se_prev = (*list)->se_prev;
-                (*list)->se_prev->se_next = ev;
-                ((*list)->se_prev = ev)->se_next = *list;
-
-                ev->se_pid = pid;
-                ev->se_evs = 0;
-        } else if (ev->se_pid != pid) {  /* link node in the middle of the list */
-                strevent_t *new;
-
-                new = (strevent_t *) kmalloc(sizeof(strevent_t), GFP_KERNEL);
-                if (new == NULL)
-                        return -ENOMEM;
-
-                new->se_prev = ev->se_prev;
-                new->se_next = ev;
-                ev->se_prev->se_next = new;
-                ev->se_prev = new;
-                ev = new;                              /* use new element */
-                ev->se_pid = pid;
-                ev->se_evs = 0;
-        }
-
-        ev->se_evs |= events;
-        return 0;
-}
-
-static int
-lis_del_from_elist( strevent_t **list, pid_t pid, short events )
-{
-        strevent_t *ev = NULL;     
-
-        if (*list != NULL) {
-                for (ev = (*list)->se_next;
-                     ev != *list && ev->se_pid < pid;
-                     ev = ev->se_next)
-                        ;
-        }
-
-        if (ev == NULL || ev == *list || ev->se_pid != pid)
-                return 1;
-
-        if ((ev->se_evs &= ~events) == 0) {        /* unlink */
-                if (ev->se_next)                        /* should always be true */
-                        ev->se_next->se_prev = ev->se_prev;
-                if (ev->se_prev)                        /* should always be true */
-                        ev->se_prev->se_next = ev->se_next;
-                kfree(ev);
-        }
-        return 0;
-}
-
-static void
-lis_free_elist( strevent_t **list )
-{
-        strevent_t  *ev;     
-        strevent_t  *nxt;
-
-        for (ev = *list; ev != NULL; ) {
-                nxt = ev->se_next;
-                kfree(ev);
-                ev = nxt;
-                if (ev == *list)
-                        break;                /* all done */
-        }
-
-        *list = NULL;
-}
-
-static short
-lis_get_elist_ent( strevent_t *list, pid_t pid )
-{
-        strevent_t *ev = NULL;
-
-        if (list == NULL)
-                return 0;
-
-        for(ev = list->se_next ; ev != list && ev->se_pid < pid; ev = ev->se_next)
-                ;
-        if (ev != list && ev->se_pid == pid)
-                return ev->se_evs;
-        else
-                return 0;
-}
-
-static void 
-kill_procs( struct strevent *elist, int sig, short e)
-{
-        strevent_t *ev;
-        int res;
-
-        if (elist) {
-                for(ev = elist->se_next ; ev != elist; ev = ev->se_next)
-                        if ((ev->se_evs & e) != 0) {
-                                res = kill_proc(ev->se_pid, SIGPOLL, 1);
-
-                                if (res < 0) {
-                                        if (res == -3) {
-                                                lis_del_from_elist(&elist,
-                                                                   ev->se_pid,
-                                                                   S_ALL);
-                                                continue;
-                                        }
-                                        dprintk(("kill_proc: errno %d\n",res));
-                                }
-                        }
-        }
-}
-
-/*
- * 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-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
diff -Nru a/drivers/sbus/audio/cs4215.h b/drivers/sbus/audio/cs4215.h
--- a/drivers/sbus/audio/cs4215.h	Tue Oct  1 00:08:20 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,120 +0,0 @@
-/* $Id: cs4215.h,v 1.8 2000/10/27 07:01:38 uzi Exp $
- * drivers/sbus/audio/cs4215.h
- *
- * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de)
- * Used with dbri.h
- */
-
-#ifndef _CS4215_H_
-#define _CS4215_H_
-
-struct cs4215 {
-	__u8	data[4];	/* Data mode: Time slots 5-8 */
-	__u8	ctrl[4];	/* Ctrl mode: Time slots 1-4 */
-	__u8	onboard;
-	__u8	offset;		/* Bit offset from frame sync to time slot 1 */
-	volatile __u32	status;
-	volatile __u32	version;
-};
-
-
-/*
- * Control mode first 
- */
-
-/* Time Slot 1, Status register */
-#define CS4215_CLB	(1<<2)	/* Control Latch Bit */
-#define CS4215_OLB	(1<<3)	/* 1: line: 2.0V, speaker 4V */
-				/* 0: line: 2.8V, speaker 8V */
-#define CS4215_MLB	(1<<4)	/* 1: Microphone: 20dB gain disabled */
-#define CS4215_RSRVD_1  (1<<5)
-
-
-/* Time Slot 2, Data Format Register */
-#define CS4215_DFR_LINEAR16	0
-#define CS4215_DFR_ULAW		1
-#define CS4215_DFR_ALAW		2
-#define CS4215_DFR_LINEAR8	3
-#define CS4215_DFR_STEREO	(1<<2)
-static struct {
-	unsigned short freq;
-	unsigned char  xtal;
-	unsigned char  csval;
-} CS4215_FREQ[] = {
-	{	 8000,	(1<<4),	(0<<3)	},
-	{	16000,	(1<<4),	(1<<3)	},
-	{	27429,	(1<<4),	(2<<3)	},	/* Actually 24428.57 */
-	{	32000,	(1<<4),	(3<<3)	},
-	/* {	 NA,	(1<<4),	(4<<3)	}, */
-	/* {	 NA,	(1<<4),	(5<<3)	}, */
-	{	48000,	(1<<4),	(6<<3)	},
-	{	 9600,	(1<<4),	(7<<3)	},
-	{	 5513,	(2<<4),	(0<<3)	},	/* Actually 5512.5 */
-	{	11025,	(2<<4),	(1<<3)	},
-	{	18900,	(2<<4),	(2<<3)	},
-	{	22050,	(2<<4),	(3<<3)	},
-	{	37800,	(2<<4),	(4<<3)	},
-	{	44100,	(2<<4),	(5<<3)	},
-	{	33075,	(2<<4),	(6<<3)	},
-	{	 6615,	(2<<4),	(7<<3)	},
-	{	    0,	0,	0	}
-};
-#define CS4215_HPF	(1<<7)	/* High Pass Filter, 1: Enabled */
-
-#define CS4215_12_MASK	0xfcbf	/* Mask off reserved bits in slot 1 & 2 */
-
-/* Time Slot 3, Serial Port Control register */
-#define CS4215_XEN	(1<<0)	/* 0: Enable serial output */
-#define CS4215_XCLK	(1<<1)	/* 1: Master mode: Generate SCLK */
-#define CS4215_BSEL_64	(0<<2)	/* Bitrate: 64 bits per frame */
-#define CS4215_BSEL_128	(1<<2)
-#define CS4215_BSEL_256	(2<<2)
-#define CS4215_MCK_MAST (0<<4)	/* Master clock */
-#define CS4215_MCK_XTL1 (1<<4)	/* 24.576 MHz clock source */
-#define CS4215_MCK_XTL2 (2<<4)	/* 16.9344 MHz clock source */
-#define CS4215_MCK_CLK1 (3<<4)	/* Clockin, 256 x Fs */
-#define CS4215_MCK_CLK2 (4<<4)	/* Clockin, see DFR */
-
-/* Time Slot 4, Test Register */
-#define CS4215_DAD	(1<<0)	/* 0:Digital-Dig loop, 1:Dig-Analog-Dig loop */
-#define CS4215_ENL	(1<<1)	/* Enable Loopback Testing */
-
-/* Time Slot 5, Parallel Port Register */
-/* Read only here and the same as the in data mode */
-
-/* Time Slot 6, Reserved  */
-
-/* Time Slot 7, Version Register  */
-#define CS4215_VERSION_MASK 0xf	/* Known versions 0/C, 1/D, 2/E */
-
-/* Time Slot 8, Reserved  */
-
-
-
-/*
- * Data mode
- */
-/* Time Slot 1-2: Left Channel Data, 2-3: Right Channel Data  */
-
-/* Time Slot 5, Output Setting  */
-#define CS4215_LO(v)	v	/* Left Output Attenuation 0x3f: -94.5 dB */
-#define CS4215_LE	(1<<6)	/* Line Out Enable */
-#define CS4215_HE	(1<<7)	/* Headphone Enable */
-
-/* Time Slot 6, Output Setting  */
-#define CS4215_RO(v)	v	/* Right Output Attenuation 0x3f: -94.5 dB */
-#define CS4215_SE	(1<<6)	/* Speaker Enable */
-#define CS4215_ADI	(1<<7)	/* A/D Data Invalid: Busy in calibration */
-
-/* Time Slot 7, Input Setting */
-#define CS4215_LG(v)	v	/* Left Gain Setting 0xf: 22.5 dB */
-#define CS4215_IS	(1<<4)	/* Input Select: 1=Microphone, 0=Line */
-#define CS4215_OVR	(1<<5)	/* 1: Overrange condition occurred */
-#define CS4215_PIO0	(1<<6)	/* Parallel I/O 0 */
-#define CS4215_PIO1	(1<<7)
-
-/* Time Slot 8, Input Setting */
-#define CS4215_RG(v)	v	/* Right Gain Setting 0xf: 22.5 dB */
-#define CS4215_MA(v)	(v<<4)	/* Monitor Path Attenuation 0xf: mute */
-
-#endif /* _CS4215_H_ */
diff -Nru a/drivers/sbus/audio/cs4231.c b/drivers/sbus/audio/cs4231.c
--- a/drivers/sbus/audio/cs4231.c	Tue Oct  1 00:08:18 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,2458 +0,0 @@
-/* $Id: cs4231.c,v 1.47 2001/10/08 22:19:50 davem Exp $
- * drivers/sbus/audio/cs4231.c
- *
- * Copyright 1996, 1997, 1998, 1999 Derrick J Brashear (shadow@andrew.cmu.edu)
- * The 4231/ebus support was written by David Miller, who didn't bother
- * crediting himself here, so I will.
- *
- * Based on the AMD7930 driver:
- * Copyright 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu)
- *
- * This is the lowlevel driver for the CS4231 audio chip found on some
- * sun4m and sun4u machines.
- * 
- * This was culled from the Crystal docs on the 4231a, and the addendum they
- * faxed me on the 4231.
- * The APC DMA controller support unfortunately is not documented. Thanks, Sun.
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/soundcard.h>
-#include <linux/version.h>
-#include <linux/ioport.h>
-#include <asm/openprom.h>
-#include <asm/oplib.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/sbus.h>
-#ifdef CONFIG_PCI
-#define EB4231_SUPPORT
-#include <asm/ebus.h>
-#include <asm/pbm.h>
-#endif
-
-#include <asm/audioio.h>
-#include "cs4231.h"
-
-#undef __CS4231_DEBUG
-#undef __CS4231_TRACE
-#define __CS4231_ERROR
-#ifdef __CS4231_ERROR
-#define eprintk(x) printk x
-#else
-#define eprintk(x)
-#endif
-#ifdef __CS4231_TRACE
-#define tprintk(x) printk x
-#else
-#define tprintk(x)
-#endif
-#ifdef __CS4231_DEBUG
-#define dprintk(x) printk x
-#else
-#define dprintk(x)
-#endif
-
-#define MAX_DRIVERS 1
-static struct sparcaudio_driver drivers[MAX_DRIVERS];
-static int num_drivers;
-
-static int cs4231_record_gain(struct sparcaudio_driver *drv, int value, 
-                              unsigned char balance);
-static int cs4231_play_gain(struct sparcaudio_driver *drv, int value, 
-                            unsigned char balance);
-static void cs4231_ready(struct sparcaudio_driver *drv);
-static void cs4231_playintr(struct sparcaudio_driver *drv, int);
-static int cs4231_recintr(struct sparcaudio_driver *drv);
-static int cs4231_output_muted(struct sparcaudio_driver *drv, int value);
-static void cs4231_pollinput(struct sparcaudio_driver *drv);
-static int cs4231_length_to_samplecount(struct audio_prinfo *thisdir, 
-                                        unsigned int length);
-static void cs4231_getsamplecount(struct sparcaudio_driver *drv, 
-                                  unsigned int length, unsigned int value);
-#ifdef EB4231_SUPPORT
-static void eb4231_pollinput(struct sparcaudio_driver *drv);
-#endif
-
-/* Serveral shorthands save typing... */
-#define CHIP_READY() \
-do { udelay(100); cs4231_ready(drv); udelay(1000); } while(0)
-#define WRITE_IAR(__VAL) \
-	CS4231_WRITE8(cs4231_chip, cs4231_chip->regs + IAR, __VAL)
-#define WRITE_IDR(__VAL) \
-	CS4231_WRITE8(cs4231_chip, cs4231_chip->regs + IDR, __VAL)
-#define READ_IAR() \
-	CS4231_READ8(cs4231_chip, cs4231_chip->regs + IAR)
-#define READ_IDR() \
-	CS4231_READ8(cs4231_chip, cs4231_chip->regs + IDR)
-
-/* Enable cs4231 interrupts atomically. */
-static void cs4231_enable_interrupts(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        unsigned long flags;
-
-        tprintk(("enabling interrupts\n"));
-        save_flags(flags);
-        cli();
-        if ((cs4231_chip->status & CS_STATUS_INTS_ON) == 0) {
-                WRITE_IAR(0xa);
-                WRITE_IDR(INTR_ON);
-                cs4231_chip->status |= CS_STATUS_INTS_ON;
-        }
-        restore_flags(flags);
-}
-
-/* Disable cs4231 interrupts atomically. */
-static void cs4231_disable_interrupts(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        unsigned long flags;
-
-        tprintk(("disabling interrupts\n"));
-        save_flags(flags);
-        cli();
-        if ((cs4231_chip->status & CS_STATUS_INTS_ON) != 0) {
-                WRITE_IAR(0xa);
-                WRITE_IDR(INTR_OFF);
-                cs4231_chip->status &= ~CS_STATUS_INTS_ON;
-        }
-        restore_flags(flags);
-}
-
-static void cs4231_enable_play(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        unsigned long flags;
-
-        tprintk(("enabling play\n"));
-        save_flags(flags);
-        cli();
-        WRITE_IAR(0x9);
-        WRITE_IDR(READ_IDR() | PEN_ENABLE);
-        restore_flags(flags);
-}
-
-static void cs4231_disable_play(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        unsigned long flags;
-
-        tprintk(("disabling play\n"));
-        save_flags(flags);
-        cli();
-        WRITE_IAR(0x9);
-        WRITE_IDR(READ_IDR() & PEN_DISABLE);
-        restore_flags(flags);
-}
-
-static void cs4231_enable_rec(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        unsigned long flags;
-
-        tprintk(("enabling rec\n"));
-        save_flags(flags);
-        cli();
-        WRITE_IAR(0x9);
-        WRITE_IDR(READ_IDR() | CEN_ENABLE);
-        restore_flags(flags);
-}
-
-static void cs4231_disable_rec(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        unsigned long flags;
-
-        tprintk(("disabling rec\n"));
-        save_flags(flags);
-        cli();
-        WRITE_IAR(0x9);
-        WRITE_IDR(READ_IDR() & CEN_DISABLE);
-        restore_flags(flags);
-}
-
-static struct cs4231_rates {
-        int speed, bits;
-} cs4231_rate_table[] = {
-        { 5512, CS4231_DFR_5512 },
-        { 6615, CS4231_DFR_6615 },
-        { 8000, CS4231_DFR_8000 },
-        { 9600, CS4231_DFR_9600 },
-        { 11025, CS4231_DFR_11025 },
-        { 16000, CS4231_DFR_16000 },
-        { 18900, CS4231_DFR_18900 },
-        { 22050, CS4231_DFR_22050 },
-        { 27429, CS4231_DFR_27429 },
-        { 32000, CS4231_DFR_32000 },
-        { 33075, CS4231_DFR_33075 },
-        { 37800, CS4231_DFR_37800 },
-        { 44100, CS4231_DFR_44100 },
-        { 48000, CS4231_DFR_48000 }
-};
-
-#define NUM_RATES	(sizeof(cs4231_rate_table) / sizeof(struct cs4231_rates))
-
-static int cs4231_rate_to_bits(struct sparcaudio_driver *drv, int *value)
-{
-        struct cs4231_rates *p = &cs4231_rate_table[0];
-        int i, wanted = *value;
-
-        /* We try to be nice and approximate what the user asks for. */
-        if (wanted < 5512)
-                wanted = 5512;
-        if (wanted > 48000)
-                wanted = 48000;
-
-        for (i = 0; i < NUM_RATES; i++, p++) {
-                /* Exact match? */
-                if (wanted == p->speed)
-                        break;
-
-                /* If we're inbetween two entries, and neither is exact,
-                 * pick the closest one.
-                 */
-                if (wanted == p[1].speed)
-                        continue;
-                if (wanted > p->speed && wanted < p[1].speed) {
-                        int diff1, diff2;
-
-                        diff1 = wanted - p->speed;
-                        diff2 = p[1].speed - wanted;
-                        if (diff2 < diff1)
-                                p++;
-                        break;
-                }
-        }
-        *value = p->speed;
-        return p->bits;
-}
-
-static int cs4231_encoding_to_bits(struct sparcaudio_driver *drv, int value)
-{
-        int set_bits;
-  
-        switch (value) {
-        case AUDIO_ENCODING_ULAW:
-                set_bits = CS4231_DFR_ULAW;
-                break;
-        case AUDIO_ENCODING_ALAW:
-                set_bits = CS4231_DFR_ALAW;
-                break;
-        case AUDIO_ENCODING_DVI:
-                set_bits = CS4231_DFR_ADPCM;
-                break;
-        case AUDIO_ENCODING_LINEARLE:
-                set_bits = CS4231_DFR_LINEARLE;
-                break;
-        case AUDIO_ENCODING_LINEAR:
-                set_bits = CS4231_DFR_LINEARBE;
-                break;
-        case AUDIO_ENCODING_LINEAR8:
-                set_bits = CS4231_DFR_LINEAR8;
-                break;
-        default:
-                set_bits = -EINVAL;
-                break;
-        };
-  
-        return set_bits;
-}
-
-static int cs4231_set_output_encoding(struct sparcaudio_driver *drv, int value)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        int tmp_bits, set_bits;
-
-        tprintk(("output encoding %d\n", value));
-        if (value != 0) {
-                set_bits = cs4231_encoding_to_bits(drv, value);
-                if (set_bits >= 0) {
-                        READ_IDR();
-                        READ_IDR();
-                        WRITE_IAR(IAR_AUTOCAL_BEGIN | 0x8);
-                        tmp_bits = READ_IDR();
-                        WRITE_IDR(CHANGE_ENCODING(tmp_bits, set_bits));
-                        READ_IDR();
-                        READ_IDR();
-                        CHIP_READY();
-                        cs4231_chip->perchip_info.play.encoding = value;
-                        return 0;
-                }
-        }
-        dprintk(("output enc failed\n"));
-        return -EINVAL;
-}
-
-static int cs4231_get_output_encoding(struct sparcaudio_driver *drv)
-{
-      struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-      return cs4231_chip->perchip_info.play.encoding;
-}
-
-static int cs4231_set_input_encoding(struct sparcaudio_driver *drv, int value)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        int tmp_bits, set_bits;
-
-        tprintk(("input encoding %d\n", value));
-        if (value != 0) {
-                set_bits = cs4231_encoding_to_bits(drv, value);
-                if (set_bits >= 0) {
-                        READ_IDR();
-                        READ_IDR();
-                        WRITE_IAR(IAR_AUTOCAL_BEGIN | 0x1c);
-                        tmp_bits = READ_IDR();
-                        WRITE_IDR(CHANGE_ENCODING(tmp_bits, set_bits));
-                        READ_IDR();
-                        READ_IDR();
-                        CHIP_READY();
-
-                        cs4231_chip->perchip_info.record.encoding = value;
-                        return 0;
-                }
-        }
-        dprintk(("input enc failed\n"));
-        return -EINVAL;
-}
-
-static int cs4231_get_input_encoding(struct sparcaudio_driver *drv)
-{
-      struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-      return cs4231_chip->perchip_info.record.encoding;
-}
-
-static int cs4231_set_output_rate(struct sparcaudio_driver *drv, int value)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        int tmp_bits, set_bits;
-
-        tprintk(("output rate %d\n", value));
-        if (value != 0) {
-                set_bits = cs4231_rate_to_bits(drv, &value);
-                if (set_bits >= 0) {
-                        READ_IDR();
-                        READ_IDR();
-                        WRITE_IAR(IAR_AUTOCAL_BEGIN | 0x8);
-                        tmp_bits = READ_IDR();
-                        WRITE_IDR(CHANGE_DFR(tmp_bits, set_bits));
-                        READ_IDR();
-                        READ_IDR();
-                        CHIP_READY();
-
-                        cs4231_chip->perchip_info.play.sample_rate = value;
-                        tprintk(("tmp_bits[%02x] set_bits[%02x] CHANGE_DFR[%02x]\n",
-                                 tmp_bits, set_bits, CHANGE_DFR(tmp_bits, set_bits)));
-                        return 0;
-                }
-        }
-        dprintk(("output rate failed\n"));
-        return -EINVAL;
-}
-
-static int cs4231_get_output_rate(struct sparcaudio_driver *drv)
-{
-      struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-      return cs4231_chip->perchip_info.play.sample_rate;
-}
-
-static int cs4231_set_input_rate(struct sparcaudio_driver *drv, int value)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        int tmp_bits, set_bits;
-
-        tprintk(("input rate %d\n", value));
-        if (value != 0) {
-                set_bits = cs4231_rate_to_bits(drv, &value);
-                if (set_bits >= 0) {
-                        READ_IDR();
-                        READ_IDR();
-                        WRITE_IAR(IAR_AUTOCAL_BEGIN | 0x1c);
-                        tmp_bits = READ_IDR();
-                        WRITE_IDR(CHANGE_DFR(tmp_bits, set_bits));
-                        READ_IDR();
-                        READ_IDR();
-                        CHIP_READY();
-
-                        cs4231_chip->perchip_info.record.sample_rate = value;
-                        return 0;
-                }
-        }
-        dprintk(("input rate failed\n"));
-        return -EINVAL;
-}
-
-static int cs4231_get_input_rate(struct sparcaudio_driver *drv)
-{
-      struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-      return cs4231_chip->perchip_info.record.sample_rate;
-}
-
-/* Generically we support 4 channels. This hardware does 2 */
-static int cs4231_set_input_channels(struct sparcaudio_driver *drv, int value)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        int tmp_bits;
-
-        tprintk(("input channels %d\n", value));
-        WRITE_IAR(IAR_AUTOCAL_BEGIN | 0x1c);
-        tmp_bits = READ_IDR();
-        switch (value) {
-        case 1:
-                WRITE_IDR(CS4231_MONO_ON(tmp_bits));
-                break;
-        case 2:
-                WRITE_IDR(CS4231_STEREO_ON(tmp_bits));
-                break;
-        default:
-                dprintk(("input chan failed\n"));
-                return -EINVAL;
-        };
-        CHIP_READY();
-
-        cs4231_chip->perchip_info.record.channels = value;
-        return 0;
-}
-
-static int cs4231_get_input_channels(struct sparcaudio_driver *drv)
-{
-      struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-      return cs4231_chip->perchip_info.record.channels;
-}
-
-/* Generically we support 4 channels. This hardware does 2 */
-static int cs4231_set_output_channels(struct sparcaudio_driver *drv, int value)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        int tmp_bits;
-
-        tprintk(("output channels %d\n", value));
-        WRITE_IAR(IAR_AUTOCAL_BEGIN | 0x8);
-        tmp_bits = READ_IDR();
-        switch (value) {
-        case 1:
-                WRITE_IDR(CS4231_MONO_ON(tmp_bits));
-                break;
-        case 2:
-                WRITE_IDR(CS4231_STEREO_ON(tmp_bits));
-                break;
-        default:
-                dprintk(("output chan failed\n"));
-                return -EINVAL;
-        };
-        CHIP_READY();
-    
-	cs4231_chip->perchip_info.play.channels = value;
-        return 0;
-}
-
-static int cs4231_get_output_channels(struct sparcaudio_driver *drv)
-{
-      struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-      return cs4231_chip->perchip_info.play.channels;
-}
-
-static int cs4231_get_input_precision(struct sparcaudio_driver *drv)
-{
-      struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-      return cs4231_chip->perchip_info.record.precision;
-}
-
-static int cs4231_get_output_precision(struct sparcaudio_driver *drv)
-{
-      struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-      return cs4231_chip->perchip_info.play.precision;
-}
-
-static int cs4231_set_input_precision(struct sparcaudio_driver *drv, int val)
-{
-      struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-
-      cs4231_chip->perchip_info.record.precision = val;
-
-      return cs4231_chip->perchip_info.record.precision;
-}
-
-static int cs4231_set_output_precision(struct sparcaudio_driver *drv, int val)
-{
-      struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private; 
-
-      cs4231_chip->perchip_info.play.precision = val;
-
-      return cs4231_chip->perchip_info.play.precision;
-}
-
-/* Wait until the auto calibration process has finished */
-static void cs4231_ready(struct sparcaudio_driver *drv) 
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        unsigned int x;
-
-        WRITE_IAR(IAR_AUTOCAL_END);
-        x = 0;
-        do {
-                if (READ_IDR() != IAR_NOT_READY)
-                        break;
-                x++;
-        } while (x <= CS_TIMEOUT);
-
-        WRITE_IAR(0x0b);
-        x = 0;
-        do {
-                if (READ_IDR() != AUTOCAL_IN_PROGRESS)
-                        break;
-                x++;
-        } while (x <= CS_TIMEOUT);
-}
-
-/* Set output mute */
-static int cs4231_output_muted(struct sparcaudio_driver *drv, int value)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        tprintk(("in cs4231_output_muted: %d\n", value));
-        if (!value) {
-                WRITE_IAR(0x7);
-                WRITE_IDR(READ_IDR() & OUTCR_UNMUTE);
-                WRITE_IAR(0x6);
-                WRITE_IDR(READ_IDR() & OUTCR_UNMUTE);
-                cs4231_chip->perchip_info.output_muted = 0;
-        } else {
-                WRITE_IAR(0x7);
-                WRITE_IDR(READ_IDR() | OUTCR_MUTE);
-                WRITE_IAR(0x6);
-                WRITE_IDR(READ_IDR() | OUTCR_MUTE);
-                cs4231_chip->perchip_info.output_muted = 1;
-        }
-        return 0;
-}
-
-static int cs4231_get_output_muted(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        return cs4231_chip->perchip_info.output_muted;
-}
-
-static int cs4231_get_formats(struct sparcaudio_driver *drv)
-{
-        return (AFMT_MU_LAW | AFMT_A_LAW |
-                AFMT_U8 | AFMT_IMA_ADPCM | 
-                AFMT_S16_LE | AFMT_S16_BE);
-}
-
-static int cs4231_get_output_ports(struct sparcaudio_driver *drv)
-{
-        return (AUDIO_LINE_OUT | AUDIO_SPEAKER | AUDIO_HEADPHONE);
-}
-
-static int cs4231_get_input_ports(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-
-        /* This apparently applies only to APC ultras, not ebus ultras */
-        if (cs4231_chip->status & CS_STATUS_IS_ULTRA)
-                return (AUDIO_LINE_IN | AUDIO_MICROPHONE | AUDIO_ANALOG_LOOPBACK);
-        else
-                return (AUDIO_INTERNAL_CD_IN | AUDIO_LINE_IN |
-                        AUDIO_MICROPHONE | AUDIO_ANALOG_LOOPBACK);
-}
-
-/* Set chip "output" port */
-static int cs4231_set_output_port(struct sparcaudio_driver *drv, int value)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        int retval = 0;
-
-        tprintk(("output port: %d\n", value));
-        /* Aaaaaah! It's all coming so fast! Turn it all off, then selectively
-         * enable things.
-         */
-        WRITE_IAR(0x1a);
-        WRITE_IDR(READ_IDR() | MONO_IOCR_MUTE);
-        WRITE_IAR(0x0a);
-        WRITE_IDR(READ_IDR() | PINCR_LINE_MUTE);
-        WRITE_IDR(READ_IDR() | PINCR_HDPH_MUTE);
-
-        if (value & AUDIO_SPEAKER) {
-                WRITE_IAR(0x1a);
-                WRITE_IDR(READ_IDR() & ~MONO_IOCR_MUTE);
-                retval |= AUDIO_SPEAKER;
-        }
-
-        if (value & AUDIO_HEADPHONE) {
-                WRITE_IAR(0x0a);
-                WRITE_IDR(READ_IDR() & ~PINCR_HDPH_MUTE);
-                retval |= AUDIO_HEADPHONE;
-        }
-
-        if (value & AUDIO_LINE_OUT) {
-                WRITE_IAR(0x0a);
-                WRITE_IDR(READ_IDR() & ~PINCR_LINE_MUTE);
-                retval |= AUDIO_LINE_OUT;
-        }
-  
-        cs4231_chip->perchip_info.play.port = retval;
-
-        return (retval);
-}
-
-static int cs4231_get_output_port(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        return cs4231_chip->perchip_info.play.port;
-}
-
-/* Set chip "input" port */
-static int cs4231_set_input_port(struct sparcaudio_driver *drv, int value)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        int retval = 0;
-
-        tprintk(("input port: %d\n", value));
-
-        /* You can have one and only one. This is probably wrong, but
-         * appears to be how SunOS is doing it. Should be able to mix.
-         * More work to be done. CD input mixable, analog loopback may be.
-         */
-
-        /* Ultra systems do not support AUDIO_INTERNAL_CD_IN */
-        /* This apparently applies only to APC ultras, not ebus ultras */
-        if (!(cs4231_chip->status & CS_STATUS_IS_ULTRA)) {
-                if (value & AUDIO_INTERNAL_CD_IN) {
-                        WRITE_IAR(0x1);
-                        WRITE_IDR(CDROM_ENABLE(READ_IDR()));
-                        WRITE_IAR(0x0);
-                        WRITE_IDR(CDROM_ENABLE(READ_IDR()));
-                        retval = AUDIO_INTERNAL_CD_IN;
-                }
-        }
-        if ((value & AUDIO_LINE_IN)) {
-                WRITE_IAR(0x1);
-                WRITE_IDR(LINE_ENABLE(READ_IDR()));
-                WRITE_IAR(0x0);
-                WRITE_IDR(LINE_ENABLE(READ_IDR()));
-                retval = AUDIO_LINE_IN;
-        } else if (value & AUDIO_MICROPHONE) {
-                WRITE_IAR(0x1);
-                WRITE_IDR(MIC_ENABLE(READ_IDR()));
-                WRITE_IAR(0x0);
-                WRITE_IDR(MIC_ENABLE(READ_IDR()));
-                retval = AUDIO_MICROPHONE;
-        } else if (value & AUDIO_ANALOG_LOOPBACK) {
-                WRITE_IAR(0x1);
-                WRITE_IDR(OUTPUTLOOP_ENABLE(READ_IDR()));
-                WRITE_IAR(0x0);
-                WRITE_IDR(OUTPUTLOOP_ENABLE(READ_IDR()));
-                retval = AUDIO_ANALOG_LOOPBACK;
-        }
-
-        cs4231_chip->perchip_info.record.port = retval;
-
-        return retval;
-}
-
-static int cs4231_get_input_port(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        return cs4231_chip->perchip_info.record.port;
-}
-
-/* Set chip "monitor" gain */
-static int cs4231_set_monitor_volume(struct sparcaudio_driver *drv, int value)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        int a = 0;
-
-        tprintk(("monitor gain: %d\n", value));
-
-        /* This interpolation really sucks. The question is, be compatible 
-         * with ScumOS/Sloaris or not?
-         */
-        a = CS4231_MON_MAX_ATEN - (value * (CS4231_MON_MAX_ATEN + 1) / 
-                                   (AUDIO_MAX_GAIN + 1));
-
-        WRITE_IAR(0x0d);
-        if (a >= CS4231_MON_MAX_ATEN) 
-                WRITE_IDR(LOOPB_OFF);
-        else 
-                WRITE_IDR((a << 2) | LOOPB_ON);
-
-        if (value == AUDIO_MAX_GAIN) 
-                cs4231_chip->perchip_info.monitor_gain = AUDIO_MAX_GAIN;
-        else 
-                cs4231_chip->perchip_info.monitor_gain =
-                        ((CS4231_MAX_DEV_ATEN - a) * 
-                         (AUDIO_MAX_GAIN + 1) / 
-                         (CS4231_MAX_DEV_ATEN + 1));
-
-        return 0;
-}
-
-static int cs4231_get_monitor_volume(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-
-        return (int) cs4231_chip->perchip_info.monitor_gain;
-}
-
-static int cs4231_get_output_error(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-
-        return (int) cs4231_chip->perchip_info.play.error;
-}
-
-static int cs4231_get_input_error(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-
-        return (int) cs4231_chip->perchip_info.record.error;
-}
-
-#ifdef EB4231_SUPPORT
-static int eb4231_get_output_samples(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        u32 dbcr = readl(cs4231_chip->eb2p + EBDMA_COUNT);
-        int count =
-                cs4231_length_to_samplecount(&cs4231_chip->perchip_info.play, dbcr);
-
-        return (cs4231_chip->perchip_info.play.samples - 
-                ((count > cs4231_chip->perchip_info.play.samples) 
-                 ? 0 : count));
-}
-
-static int eb4231_get_input_samples(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        u32 dbcr = readl(cs4231_chip->eb2c + EBDMA_COUNT);
-        int count =
-                cs4231_length_to_samplecount(&cs4231_chip->perchip_info.record, dbcr);
-
-        return (cs4231_chip->perchip_info.record.samples - 
-                ((count > cs4231_chip->perchip_info.record.samples) ?
-                0 : count));
-}
-#endif
-
-static int cs4231_get_output_samples(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        u32 dmapc = sbus_readl(cs4231_chip->regs + APCPC);
-        int count = 
-          cs4231_length_to_samplecount(&cs4231_chip->perchip_info.play, dmapc);
-
-        return (cs4231_chip->perchip_info.play.samples - 
-                ((count > cs4231_chip->perchip_info.play.samples) 
-                 ? 0 : count));
-}
-
-static int cs4231_get_input_samples(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        u32 dmacc = sbus_readl(cs4231_chip->regs + APCCC);
-        int count = 
-          cs4231_length_to_samplecount(&cs4231_chip->perchip_info.record, dmacc);
-
-        return (cs4231_chip->perchip_info.record.samples - 
-                ((count > cs4231_chip->perchip_info.record.samples) ?
-                0 : count));
-}
-
-static int cs4231_get_output_pause(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-
-        return (int) cs4231_chip->perchip_info.play.pause;
-}
-
-static int cs4231_get_input_pause(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-
-        return (int) cs4231_chip->perchip_info.record.pause;
-}
-
-/* But for play/record we have these cheesy jacket routines because of 
- * how this crap gets set.
- */
-static int cs4231_set_input_volume(struct sparcaudio_driver *drv, int value)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-
-	cs4231_record_gain(drv, value, 
-                           cs4231_chip->perchip_info.record.balance);
-	
-        return 0;
-}
-
-static int cs4231_get_input_volume(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-
-        return (int) cs4231_chip->perchip_info.record.gain;
-}
-
-static int cs4231_set_output_volume(struct sparcaudio_driver *drv, int value)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-
-	cs4231_play_gain(drv, value, cs4231_chip->perchip_info.play.balance);
-	
-        return 0;
-}
-
-static int cs4231_get_output_volume(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-
-        return cs4231_chip->perchip_info.play.gain;
-}
-
-/* Likewise for balance */
-static int cs4231_set_input_balance(struct sparcaudio_driver *drv, int value)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-
-	cs4231_chip->perchip_info.record.balance = value;
-	cs4231_record_gain(drv, cs4231_chip->perchip_info.record.gain, 
-                           cs4231_chip->perchip_info.record.balance);
-	
-        return 0;
-}
-
-static int cs4231_get_input_balance(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-
-        return (int) cs4231_chip->perchip_info.record.balance;
-}
-
-static int cs4231_set_output_balance(struct sparcaudio_driver *drv, int value)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-
-	cs4231_chip->perchip_info.play.balance = value;
-	cs4231_play_gain(drv, cs4231_chip->perchip_info.play.gain, 
-                         cs4231_chip->perchip_info.play.balance);
-	
-        return 0;
-}
-
-static int cs4231_get_output_balance(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-
-        return (int) cs4231_chip->perchip_info.play.balance;
-}
-
-/* Set chip record gain */
-static int cs4231_record_gain(struct sparcaudio_driver *drv, int value,
-                              unsigned char balance)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        int tmp = 0, r, l, r_adj, l_adj;
-        unsigned char old_gain;
-
-        r = l = value;
-
-        if (balance < AUDIO_MID_BALANCE) {
-                r = (int) (value -
-                           ((AUDIO_MID_BALANCE - balance) << AUDIO_BALANCE_SHIFT));
-
-                if (r < 0)
-                        r = 0;
-        } else if (balance > AUDIO_MID_BALANCE) {
-                l = (int) (value -
-                           ((balance - AUDIO_MID_BALANCE) << AUDIO_BALANCE_SHIFT));
-
-                if (l < 0)
-                        l = 0;
-        }
-
-        l_adj = l * (CS4231_MAX_GAIN + 1) / (AUDIO_MAX_GAIN + 1);
-        r_adj = r * (CS4231_MAX_GAIN + 1) / (AUDIO_MAX_GAIN + 1);
-  
-        WRITE_IAR(0x0);
-        old_gain = READ_IDR();
-        WRITE_IDR(RECGAIN_SET(old_gain, l_adj));
-        WRITE_IAR(0x1);
-        old_gain = READ_IDR();
-        WRITE_IDR(RECGAIN_SET(old_gain, r_adj));
-  
-        if (l == value) {
-                (l == 0) ? (tmp = 0) : (tmp = ((l_adj + 1) * AUDIO_MAX_GAIN) / 
-                                        (CS4231_MAX_GAIN + 1));
-        } else if (r == value) {
-                (r == 0) ? (tmp = 0) : (tmp = ((r_adj + 1) * AUDIO_MAX_GAIN) / 
-                                        (CS4231_MAX_GAIN + 1));
-        }
-        cs4231_chip->perchip_info.record.gain = tmp;
-        return 0;
-}
-
-/* Set chip play gain */
-static int cs4231_play_gain(struct sparcaudio_driver *drv, int value,
-                            unsigned char balance)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        int tmp = 0, r, l, r_adj, l_adj;
-        unsigned char old_gain;
-
-        tprintk(("in play_gain: %d %c\n", value, balance));
-        r = l = value;
-        if (balance < AUDIO_MID_BALANCE) {
-                r = (int) (value -
-                           ((AUDIO_MID_BALANCE - balance) << AUDIO_BALANCE_SHIFT));
-
-                if (r < 0)
-                        r = 0;
-        } else if (balance > AUDIO_MID_BALANCE) {
-                l = (int) (value -
-                           ((balance - AUDIO_MID_BALANCE) << AUDIO_BALANCE_SHIFT));
-
-                if (l < 0)
-                        l = 0;
-        }
-
-        (l == 0) ? (l_adj = CS4231_MAX_DEV_ATEN) : (l_adj = CS4231_MAX_ATEN - 
-                                                    (l * (CS4231_MAX_ATEN + 1) / 
-                                                     (AUDIO_MAX_GAIN + 1)));
-        (r == 0) ? (r_adj = CS4231_MAX_DEV_ATEN) : (r_adj = CS4231_MAX_ATEN -
-                                                    (r * (CS4231_MAX_ATEN + 1) /
-                                                     (AUDIO_MAX_GAIN + 1)));
-  
-        WRITE_IAR(0x6);
-        old_gain = READ_IDR();
-        WRITE_IDR(GAIN_SET(old_gain, l_adj));
-        WRITE_IAR(0x7);
-        old_gain = READ_IDR();
-        WRITE_IDR(GAIN_SET(old_gain, r_adj));
-  
-        if ((value == 0) || (value == AUDIO_MAX_GAIN)) {
-                tmp = value;
-        } else {
-                if (value == l) {
-                        tmp = ((CS4231_MAX_ATEN - l_adj) * (AUDIO_MAX_GAIN + 1) / 
-                               (CS4231_MAX_ATEN + 1));
-                } else if (value == r) {
-                        tmp = ((CS4231_MAX_ATEN - r_adj) * (AUDIO_MAX_GAIN + 1) / 
-                               (CS4231_MAX_ATEN + 1));
-                }
-        }
-        cs4231_chip->perchip_info.play.gain = tmp;
-
-        return 0;
-}
-
-/* Reset the audio chip to a sane state. */
-static void cs4231_chip_reset(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        unsigned char vers;
-
-        tprintk(("in cs4231_chip_reset\n"));
-
-        if (cs4231_chip->status & CS_STATUS_IS_EBUS) {
-#ifdef EB4231_SUPPORT
-                writel(EBUS_DCSR_RESET, cs4231_chip->eb2p + EBDMA_CSR);
-                writel(EBUS_DCSR_RESET, cs4231_chip->eb2c + EBDMA_CSR);
-                writel(EBUS_DCSR_BURST_SZ_16, cs4231_chip->eb2p + EBDMA_CSR);
-                writel(EBUS_DCSR_BURST_SZ_16, cs4231_chip->eb2c + EBDMA_CSR);
-#endif
-        } else {
-                u32 tmp;
-
-                sbus_writel(APC_CHIP_RESET, cs4231_chip->regs + APCCSR);
-                sbus_writel(0x00, cs4231_chip->regs + APCCSR);
-                tmp = sbus_readl(cs4231_chip->regs + APCCSR);
-                tmp |= APC_CDC_RESET;
-                sbus_writel(tmp, cs4231_chip->regs + APCCSR);
-  
-                udelay(20);
-  
-                tmp = sbus_readl(cs4231_chip->regs + APCCSR);
-                tmp &= ~(APC_CDC_RESET);
-                sbus_writel(tmp, cs4231_chip->regs + APCCSR);
-        }
-
-        WRITE_IAR(READ_IAR() | IAR_AUTOCAL_BEGIN);
-        CHIP_READY();
-    
-        WRITE_IAR(IAR_AUTOCAL_BEGIN | 0x0c);
-        WRITE_IDR(MISC_IR_MODE2);
-
-        /* This is the equivalent of DEFAULT_DATA_FMAT */
-        cs4231_set_input_encoding(drv, AUDIO_ENCODING_ULAW);
-        cs4231_set_input_rate(drv, CS4231_RATE);
-        cs4231_set_input_channels(drv, CS4231_CHANNELS);
-        cs4231_set_input_precision(drv, CS4231_PRECISION);
-
-        cs4231_set_output_encoding(drv, AUDIO_ENCODING_ULAW);
-        cs4231_set_output_rate(drv, CS4231_RATE);
-        cs4231_set_output_channels(drv, CS4231_CHANNELS);
-        cs4231_set_output_precision(drv, CS4231_PRECISION);
-
-        WRITE_IAR(0x19);
-
-        /* see what we can turn on */
-        vers = READ_IDR();
-        if (vers & CS4231A) {
-                tprintk(("This is a CS4231A\n"));
-                cs4231_chip->status |= CS_STATUS_REV_A;
-        } else {
-                cs4231_chip->status &= ~CS_STATUS_REV_A;
-        }
-  
-        WRITE_IAR(IAR_AUTOCAL_BEGIN | 0x10);
-        WRITE_IDR(OLB_ENABLE);
-  
-        WRITE_IAR(IAR_AUTOCAL_BEGIN | 0x11);
-        if (cs4231_chip->status & CS_STATUS_REV_A)
-                WRITE_IDR(HPF_ON | XTALE_ON);
-        else
-                WRITE_IDR(HPF_ON);
-  
-        WRITE_IAR(IAR_AUTOCAL_BEGIN | 0x1a);
-        WRITE_IDR(0x00);
-  
-        /* Now set things up for defaults */
-        cs4231_set_input_balance(drv, AUDIO_MID_BALANCE);
-        cs4231_set_output_balance(drv, AUDIO_MID_BALANCE);
-
-        cs4231_set_input_volume(drv, CS4231_DEFAULT_RECGAIN);
-        cs4231_set_output_volume(drv, CS4231_DEFAULT_PLAYGAIN);
-
-        cs4231_set_input_port(drv, AUDIO_MICROPHONE);
-        cs4231_set_output_port(drv, AUDIO_SPEAKER);
-
-        cs4231_set_monitor_volume(drv, LOOPB_OFF);
-  
-        WRITE_IAR(IAR_AUTOCAL_END);
-  
-        cs4231_ready(drv);
-  
-        WRITE_IAR(IAR_AUTOCAL_BEGIN | 0x09);
-        WRITE_IDR(READ_IDR() & ACAL_DISABLE);
-        WRITE_IAR(IAR_AUTOCAL_END);
-  
-        cs4231_ready(drv);
-
-        cs4231_output_muted(drv, 0);
-
-        cs4231_chip->recording_count = 0;
-        cs4231_chip->input_next_dma_handle = 0;
-        cs4231_chip->input_dma_handle = 0;
-        cs4231_chip->input_next_dma_size = 0;
-        cs4231_chip->input_dma_size = 0;
-
-        cs4231_chip->playing_count = 0;
-        cs4231_chip->output_next_dma_handle = 0;
-        cs4231_chip->output_dma_handle = 0;
-        cs4231_chip->output_next_dma_size = 0;
-        cs4231_chip->output_dma_size = 0;
-}
-
-static int
-cs4231_length_to_samplecount(struct audio_prinfo *thisdir, unsigned int length)
-{
-        unsigned int count;
-
-        if (thisdir->channels == 2)
-                count = (length / 2);
-        else 
-                count = length;
-  
-        if (thisdir->encoding == AUDIO_ENCODING_LINEAR)
-                count = (count / 2);
-        else if (thisdir->encoding == AUDIO_ENCODING_DVI)
-                count = (count / 4);
-  
-        return count;
-}
-
-#ifdef EB4231_SUPPORT
-static void eb4231_getsamplecount(struct sparcaudio_driver *drv,
-                                  unsigned int length,
-                                  unsigned int direction)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        struct audio_prinfo *thisdir;
-        unsigned int count, curcount, nextcount, dbcr;
-
-        if(direction == 1) {
-                thisdir = &cs4231_chip->perchip_info.record;
-                dbcr = readl(cs4231_chip->eb2c + EBDMA_COUNT);
-                nextcount = cs4231_chip->input_next_dma_size;
-        } else {
-                thisdir = &cs4231_chip->perchip_info.play;
-                dbcr = readl(cs4231_chip->eb2p + EBDMA_COUNT);
-                nextcount = cs4231_chip->output_next_dma_size;
-        }
-        curcount = cs4231_length_to_samplecount(thisdir, dbcr);
-        count = thisdir->samples;
-        length = cs4231_length_to_samplecount(thisdir, length);
-        /* normalize for where we are. */
-        thisdir->samples = ((count - nextcount) + (length - curcount));
-}
-#endif
-
-static void cs4231_getsamplecount(struct sparcaudio_driver *drv,
-                                  unsigned int length,
-                                  unsigned int direction)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        struct audio_prinfo *thisdir;
-        unsigned int count, nextcount, curcount;
-        u32 tmp;
-
-        if (direction == 1) {
-                /* record */ 
-                thisdir = &cs4231_chip->perchip_info.record;
-                tmp = sbus_readl(cs4231_chip->regs + APCCC);
-                curcount = cs4231_length_to_samplecount(thisdir, tmp);
-                tmp = sbus_readl(cs4231_chip->regs + APCCNC);
-                nextcount = cs4231_length_to_samplecount(thisdir, tmp);
-        } else {
-                /* play */
-                thisdir = &cs4231_chip->perchip_info.play;
-                tmp = sbus_readl(cs4231_chip->regs + APCPC);
-                curcount = cs4231_length_to_samplecount(thisdir, tmp);
-                tmp = sbus_readl(cs4231_chip->regs + APCPNC);
-                nextcount = cs4231_length_to_samplecount(thisdir, tmp);
-        }
-        count = thisdir->samples;
-        length = cs4231_length_to_samplecount(thisdir, length);
-
-        /* normalize for where we are. */
-        thisdir->samples = ((count - nextcount) + (length - curcount));
-}
-
-static int cs4231_open(struct inode * inode, struct file * file, struct sparcaudio_driver *drv)
-{	
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-
-        /* Set the default audio parameters if not already in use. */
-        if (file->f_mode & FMODE_WRITE) {
-                if (!(drv->flags & SDF_OPEN_WRITE) && 
-                    (cs4231_chip->perchip_info.play.active == 0)) {
-                        cs4231_chip->perchip_info.play.open = 1;
-                        cs4231_chip->perchip_info.play.samples =
-                                cs4231_chip->perchip_info.play.error = 0;
-                }
-        }
-
-        if (file->f_mode & FMODE_READ) {
-                if (!(drv->flags & SDF_OPEN_READ) && 
-                    (cs4231_chip->perchip_info.record.active == 0)) {
-                        cs4231_chip->perchip_info.record.open = 1;
-                        cs4231_chip->perchip_info.record.samples = 
-                                cs4231_chip->perchip_info.record.error = 0;
-                }
-        }  
-
-        cs4231_ready(drv);
-        CHIP_READY();
-    
-        MOD_INC_USE_COUNT;
-  
-        return 0;
-}
-
-static void cs4231_release(struct inode * inode, struct file * file, struct sparcaudio_driver *drv)
-{
-	struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
-	void (*dma_unmap_single)(struct sbus_dev *, dma_addr_t, size_t, int) = sbus_unmap_single;
-
-#ifdef EB4231_SUPPORT
-	if (cs4231_chip->status & CS_STATUS_IS_EBUS)
-		dma_unmap_single = (void (*)(struct sbus_dev *, dma_addr_t, size_t, int)) pci_unmap_single;
-#endif
-        /* zero out any info about what data we have as well */
-        if (file->f_mode & FMODE_READ) {
-                /* stop capture here or midlevel? */
-                cs4231_chip->perchip_info.record.open = 0;
-                if (cs4231_chip->input_dma_handle) {
-			dma_unmap_single(drv->dev,
-					 cs4231_chip->input_dma_handle,
-					 cs4231_chip->input_dma_size,
-					 SBUS_DMA_FROMDEVICE);
-                        cs4231_chip->input_dma_handle = 0;
-                        cs4231_chip->input_dma_size = 0;
-                }
-                if (cs4231_chip->input_next_dma_handle) {
-			dma_unmap_single(drv->dev,
-					 cs4231_chip->input_next_dma_handle,
-					 cs4231_chip->input_next_dma_size,
-					 SBUS_DMA_FROMDEVICE);
-                        cs4231_chip->input_next_dma_handle = 0;
-                        cs4231_chip->input_next_dma_size = 0;
-                }
-        }
-
-        if (file->f_mode & FMODE_WRITE) {
-                cs4231_chip->perchip_info.play.active =
-                        cs4231_chip->perchip_info.play.open = 0;
-                if (cs4231_chip->output_dma_handle) {
-			dma_unmap_single(drv->dev,
-					 cs4231_chip->output_dma_handle,
-					 cs4231_chip->output_dma_size,
-					 SBUS_DMA_TODEVICE);
-                        cs4231_chip->output_dma_handle = 0;
-                        cs4231_chip->output_dma_size = 0;
-                }
-                if (cs4231_chip->output_next_dma_handle) {
-			dma_unmap_single(drv->dev,
-					 cs4231_chip->output_next_dma_handle,
-					 cs4231_chip->output_next_dma_size,
-					 SBUS_DMA_TODEVICE);
-                        cs4231_chip->output_next_dma_handle = 0;
-                        cs4231_chip->output_next_dma_size = 0;
-                }
-        }
-
-        if (!cs4231_chip->perchip_info.play.open && 
-            !cs4231_chip->perchip_info.record.open && 
-            (cs4231_chip->status & CS_STATUS_INIT_ON_CLOSE)) {
-                cs4231_chip_reset(drv);
-                cs4231_chip->status &= ~CS_STATUS_INIT_ON_CLOSE;
-        }
-
-        MOD_DEC_USE_COUNT;
-}
-
-static void cs4231_playintr(struct sparcaudio_driver *drv, int push)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        int status = 0;
-
-        if (!push) {
-                if (!cs4231_chip->perchip_info.play.active) {
-                        sbus_writel(cs4231_chip->output_next_dma_handle,
-                                    cs4231_chip->regs + APCPNVA);
-                        sbus_writel(cs4231_chip->output_next_dma_size,
-                                    cs4231_chip->regs + APCPNC);
-                }
-                sparcaudio_output_done(drv, 0);
-                return;
-        }
-
-        if (cs4231_chip->playlen == 0 && cs4231_chip->output_size > 0) 
-                cs4231_chip->playlen = cs4231_chip->output_size;
-
-        if (cs4231_chip->output_dma_handle) {
-                sbus_unmap_single(drv->dev,
-                                  cs4231_chip->output_dma_handle,
-                                  cs4231_chip->output_dma_size,
-                                  SBUS_DMA_TODEVICE);
-                cs4231_chip->output_dma_handle = 0;
-                cs4231_chip->output_dma_size = 0;
-                cs4231_chip->playing_count--;
-                status++;
-        }
-
-        if (cs4231_chip->output_next_dma_handle) {
-                cs4231_chip->output_dma_handle = cs4231_chip->output_next_dma_handle;
-                cs4231_chip->output_dma_size = cs4231_chip->output_next_dma_size;
-                cs4231_chip->output_next_dma_size = 0;
-                cs4231_chip->output_next_dma_handle = 0;
-        }
-
-        if ((cs4231_chip->output_ptr && cs4231_chip->output_size > 0) && 
-            !(cs4231_chip->perchip_info.play.pause)) {
-                cs4231_chip->output_next_dma_handle =
-                        sbus_map_single(drv->dev,
-                                        (char *)cs4231_chip->output_ptr,
-                                        cs4231_chip->output_size,
-                                        SBUS_DMA_TODEVICE);
-                cs4231_chip->output_next_dma_size = cs4231_chip->output_size;
-                sbus_writel(cs4231_chip->output_next_dma_handle,
-                            cs4231_chip->regs + APCPNVA);
-                sbus_writel(cs4231_chip->output_next_dma_size,
-                            cs4231_chip->regs + APCPNC);
-                cs4231_chip->output_size = 0;
-                cs4231_chip->output_ptr = NULL;
-                cs4231_chip->playing_count++;
-                status += 2;
-        } else {
-                sbus_writel(0, cs4231_chip->regs + APCPNVA);
-                sbus_writel(0, cs4231_chip->regs + APCPNC);
-        }
-
-        sparcaudio_output_done(drv, status);
-}
-
-#ifdef EB4231_SUPPORT
-static void eb4231_playintr(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        int status = 0;
-
-        if (cs4231_chip->playlen == 0 && cs4231_chip->output_size > 0) 
-                cs4231_chip->playlen = cs4231_chip->output_size;
-
-        if (cs4231_chip->output_dma_handle) {
-		pci_unmap_single((struct pci_dev *)drv->dev,
-				 cs4231_chip->output_dma_handle,
-				 cs4231_chip->output_dma_size,
-                                 PCI_DMA_TODEVICE);
-                cs4231_chip->output_dma_handle = 0;
-                cs4231_chip->output_dma_size = 0;
-                cs4231_chip->playing_count--;
-                status++;
-        }
-
-        if(cs4231_chip->output_next_dma_handle) {
-                cs4231_chip->output_dma_handle = cs4231_chip->output_next_dma_handle;
-                cs4231_chip->output_dma_size = cs4231_chip->output_next_dma_size;
-                cs4231_chip->output_next_dma_handle = 0;
-                cs4231_chip->output_next_dma_size = 0;
-        }
-
-        if ((cs4231_chip->output_ptr && cs4231_chip->output_size > 0) && 
-            !(cs4231_chip->perchip_info.play.pause)) {
-                cs4231_chip->output_next_dma_handle =
-			pci_map_single((struct pci_dev *)drv->dev,
-				       (char *)cs4231_chip->output_ptr,
-				       cs4231_chip->output_size,
-                                       PCI_DMA_TODEVICE);
-                cs4231_chip->output_next_dma_size = cs4231_chip->output_size;
-
-                writel(cs4231_chip->output_next_dma_size,
-                       cs4231_chip->eb2p + EBDMA_COUNT);
-                writel(cs4231_chip->output_next_dma_handle,
-                       cs4231_chip->eb2p + EBDMA_ADDR);
-                cs4231_chip->output_size = 0;
-                cs4231_chip->output_ptr = NULL;
-                cs4231_chip->playing_count++;
-                status += 2;
-        }
-
-        sparcaudio_output_done(drv, status);
-}
-#endif
-
-static void cs4231_recclear(int fmt, char *dmabuf, int length)
-{
-        switch (fmt) {
-        case AUDIO_ENCODING_LINEAR:
-                memset(dmabuf, 0x00, length);
-                break;
-        case AUDIO_ENCODING_ALAW:
-                memset(dmabuf, 0xd5, length);
-                break;
-        case AUDIO_ENCODING_ULAW:
-                memset(dmabuf, 0xff, length);
-                break;
-        }
-}
-
-static int cs4231_recintr(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        int status = 0;
-
-        if (cs4231_chip->perchip_info.record.active == 0) {
-                dprintk(("going inactive\n"));
-                cs4231_pollinput(drv);
-                cs4231_disable_rec(drv);    
-        } 
-
-        if (cs4231_chip->input_dma_handle) {
-                sbus_unmap_single(drv->dev,
-                                  cs4231_chip->input_dma_handle,
-                                  cs4231_chip->input_dma_size,
-                                  SBUS_DMA_FROMDEVICE);
-                cs4231_chip->input_dma_handle = 0;
-                cs4231_chip->input_dma_size = 0;
-                cs4231_chip->recording_count--;
-                status++;
-        }
-
-        if (cs4231_chip->input_next_dma_handle) {
-                cs4231_chip->input_dma_handle = cs4231_chip->input_next_dma_handle;
-                cs4231_chip->input_dma_size = cs4231_chip->input_next_dma_size;
-                cs4231_chip->input_next_dma_size = 0;
-                cs4231_chip->input_next_dma_handle = 0;
-        }
-
-        if ((cs4231_chip->input_ptr && cs4231_chip->input_size > 0) && 
-            !(cs4231_chip->perchip_info.record.pause)) {
-                cs4231_recclear(cs4231_chip->perchip_info.record.encoding, 
-                                (char *)cs4231_chip->input_ptr,
-                                cs4231_chip->input_size);
-                cs4231_chip->input_next_dma_handle =
-                        sbus_map_single(drv->dev,
-                                        (char *)cs4231_chip->input_ptr,
-                                        cs4231_chip->input_size,
-                                        SBUS_DMA_FROMDEVICE);
-                cs4231_chip->input_next_dma_size = cs4231_chip->input_size;
-                sbus_writel(cs4231_chip->input_next_dma_handle,
-                            cs4231_chip->regs + APCCNVA);
-                sbus_writel(cs4231_chip->input_next_dma_size,
-                            cs4231_chip->regs + APCCNC);
-                cs4231_chip->input_size = 0;
-                cs4231_chip->input_ptr = NULL;
-                cs4231_chip->recording_count++;
-                status += 2;
-        } else {
-                sbus_writel(0, cs4231_chip->regs + APCCNVA);
-                sbus_writel(0, cs4231_chip->regs + APCCNC);
-        }
-
-        sparcaudio_input_done(drv, status);
-        return 1;
-}
-
-#ifdef EB4231_SUPPORT
-static int eb4231_recintr(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        int status = 0;
-
-        if (cs4231_chip->perchip_info.record.active == 0) {
-                dprintk(("going inactive\n"));
-                eb4231_pollinput(drv);
-                cs4231_disable_rec(drv);    
-        } 
-
-        if (cs4231_chip->input_dma_handle) {
-		pci_unmap_single((struct pci_dev *)drv->dev,
-				 cs4231_chip->input_dma_handle,
-				 cs4231_chip->input_dma_size,
-                                 PCI_DMA_FROMDEVICE);
-                cs4231_chip->input_dma_handle = 0;
-                cs4231_chip->input_dma_size = 0;
-                cs4231_chip->recording_count--;
-                status++;
-        }
-
-        if (cs4231_chip->input_next_dma_handle) {
-                cs4231_chip->input_dma_handle = cs4231_chip->input_next_dma_handle;
-                cs4231_chip->input_dma_size = cs4231_chip->input_next_dma_size;
-                cs4231_chip->input_next_dma_size = 0;
-                cs4231_chip->input_next_dma_handle = 0;
-        }
-
-        if ((cs4231_chip->input_ptr && cs4231_chip->input_size > 0) && 
-            !(cs4231_chip->perchip_info.record.pause)) {
-                cs4231_recclear(cs4231_chip->perchip_info.record.encoding, 
-                                (char *)cs4231_chip->input_ptr,
-                                cs4231_chip->input_size);
-
-                cs4231_chip->input_next_dma_handle =
-			pci_map_single((struct pci_dev *)drv->dev,
-				       (char *)cs4231_chip->input_ptr,
-				       cs4231_chip->input_size,
-                                       PCI_DMA_FROMDEVICE);
-                cs4231_chip->input_next_dma_size = cs4231_chip->input_size;
-
-                writel(cs4231_chip->input_next_dma_size,
-                       cs4231_chip->eb2c + EBDMA_COUNT);
-                writel(cs4231_chip->input_next_dma_handle,
-                       cs4231_chip->eb2c + EBDMA_ADDR);
-
-                cs4231_chip->input_size = 0;
-                cs4231_chip->input_ptr = NULL;
-                cs4231_chip->recording_count++;
-                status += 2;
-        }
-
-        sparcaudio_input_done(drv, status);
-        return 1;
-}
-#endif
-
-#ifdef EB4231_SUPPORT
-static void eb4231_start_output(struct sparcaudio_driver *drv, __u8 * buffer,
-                                unsigned long count)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        u32 dcsr;
-
-        cs4231_chip->output_ptr = buffer;
-        cs4231_chip->output_size = count;
-
-        if (cs4231_chip->perchip_info.play.active || 
-            (cs4231_chip->perchip_info.play.pause))
-                return;
-
-        cs4231_ready(drv);
-
-        cs4231_chip->perchip_info.play.active = 1;
-        cs4231_chip->playing_count = 0;
-
-        dcsr = readl(cs4231_chip->eb2p + EBDMA_CSR);
-        if (!(dcsr & EBUS_DCSR_EN_DMA)) {
-                writel(EBUS_DCSR_RESET, cs4231_chip->eb2p + EBDMA_CSR);
-                writel(EBUS_DCSR_BURST_SZ_16, cs4231_chip->eb2p + EBDMA_CSR);
-
-                eb4231_playintr(drv);
-
-                writel(EBUS_DCSR_BURST_SZ_16 |
-                       (EBUS_DCSR_EN_DMA | EBUS_DCSR_INT_EN |
-                        EBUS_DCSR_EN_CNT | EBUS_DCSR_EN_NEXT),
-                       cs4231_chip->eb2p + EBDMA_CSR);
-
-                cs4231_enable_play(drv);
-
-                cs4231_ready(drv);
-        } else {
-                eb4231_playintr(drv);
-        }
-}
-#endif
-
-static void cs4231_start_output(struct sparcaudio_driver *drv, __u8 * buffer,
-                                unsigned long count)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        u32 csr;
-
-        tprintk(("in 4231 start output\n"));
-        cs4231_chip->output_ptr = buffer;
-        cs4231_chip->output_size = count;
-
-        if (cs4231_chip->perchip_info.play.active || 
-            (cs4231_chip->perchip_info.play.pause))
-                return;
-
-        cs4231_ready(drv);
-
-        cs4231_chip->perchip_info.play.active = 1;
-        cs4231_chip->playing_count = 0;
-
-        csr = sbus_readl(cs4231_chip->regs + APCCSR);
-        if ((csr & APC_PPAUSE) || !(csr & APC_PDMA_READY)) {
-                u32 pnva;
-
-                csr &= ~APC_XINT_PLAY;
-                sbus_writel(csr, cs4231_chip->regs + APCCSR);
-                csr &= ~APC_PPAUSE;
-                sbus_writel(csr, cs4231_chip->regs + APCCSR);
-    
-                pnva = sbus_readl(cs4231_chip->regs + APCPNVA);
-                cs4231_playintr(drv, (pnva == 0) ? 1 : 0);
-
-                csr |= APC_PLAY_SETUP;
-                sbus_writel(csr, cs4231_chip->regs + APCCSR);
-                cs4231_enable_play(drv);
-
-                cs4231_ready(drv);
-        }
-}
-
-#ifdef EB4231_SUPPORT
-static void eb4231_stop_output(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        u32 dcsr;
-
-        dprintk(("eb4231_stop_output: dcsr 0x%x dacr 0x%x dbcr %d\n",
-                 readl(cs4231_chip->eb2p + EBDMA_CSR),
-                 readl(cs4231_chip->eb2p + EBDMA_ADDR),
-                 readl(cs4231_chip->eb2p + EBDMA_COUNT)));
-
-        cs4231_chip->output_ptr = NULL;
-        cs4231_chip->output_size = 0;
-
-        if (cs4231_chip->output_dma_handle) {
-		pci_unmap_single((struct pci_dev *)drv->dev,
-				 cs4231_chip->output_dma_handle,
-				 cs4231_chip->output_dma_size,
-                                 PCI_DMA_TODEVICE);
-                cs4231_chip->output_dma_handle = 0;
-                cs4231_chip->output_dma_size = 0;
-        }
-
-        if (cs4231_chip->output_next_dma_handle) {
-		pci_unmap_single((struct pci_dev *)drv->dev,
-				 cs4231_chip->output_next_dma_handle,
-				 cs4231_chip->output_next_dma_size,
-                                 PCI_DMA_TODEVICE);
-                cs4231_chip->output_next_dma_handle = 0;
-                cs4231_chip->output_next_dma_size = 0;
-        }
-        dcsr = readl(cs4231_chip->eb2p + EBDMA_CSR);
-        if(dcsr & EBUS_DCSR_EN_DMA)
-                writel(dcsr & ~EBUS_DCSR_EN_DMA,
-                       cs4231_chip->eb2p + EBDMA_CSR);
-
-        /* Else subsequent speed setting changes are ignored by the chip. */
-        cs4231_disable_play(drv);
-}
-#endif
-
-static void cs4231_stop_output(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-
-        tprintk(("in cs4231_stop_output\n"));
-        cs4231_chip->output_ptr = NULL;
-        cs4231_chip->output_size = 0;
-
-        if (cs4231_chip->output_dma_handle) {
-                sbus_unmap_single(drv->dev,
-                                  cs4231_chip->output_dma_handle,
-                                  cs4231_chip->output_dma_size,
-                                  SBUS_DMA_TODEVICE);
-                cs4231_chip->output_dma_handle = 0;
-                cs4231_chip->output_dma_size = 0;
-        }
-
-        if (cs4231_chip->output_next_dma_handle) {
-                sbus_unmap_single(drv->dev,
-                                  cs4231_chip->output_next_dma_handle,
-                                  cs4231_chip->output_next_dma_size,
-                                  SBUS_DMA_TODEVICE);
-                cs4231_chip->output_next_dma_handle = 0;
-                cs4231_chip->output_next_dma_size = 0;
-        }
-#if 0 /* Not safe without shutting off the DMA controller as well. -DaveM */
-        /* Else subsequent speed setting changes are ignored by the chip. */
-        cs4231_disable_play(drv);
-#endif
-}
-
-#ifdef EB4231_SUPPORT
-static void eb4231_pollinput(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        int x;
-        u32 dcsr;
-
-        x = 0;
-        do {
-                dcsr = readl(cs4231_chip->eb2c + EBDMA_CSR);
-                if (dcsr & EBUS_DCSR_TC)
-                        break;
-                x++;
-        } while (x <= CS_TIMEOUT);
-
-        writel(dcsr | EBUS_DCSR_TC,
-               cs4231_chip->eb2c + EBDMA_CSR);
-}
-#endif
-
-static void cs4231_pollinput(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        int x;
-        u32 csr;
-
-        x = 0;
-        do {
-                csr = sbus_readl(cs4231_chip->regs + APCCSR);
-                if (csr & APC_XINT_COVF)
-                        break;
-                x++;
-        } while (x <= CS_TIMEOUT);
-
-        sbus_writel(csr | APC_XINT_CEMP,
-                    cs4231_chip->regs + APCCSR);
-}
-
-static void cs4231_start_input(struct sparcaudio_driver *drv, __u8 * buffer, 
-                               unsigned long count)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        u32 csr;
-
-        cs4231_chip->input_ptr = buffer;
-        cs4231_chip->input_size = count;
-
-        if (cs4231_chip->perchip_info.record.active || 
-            (cs4231_chip->perchip_info.record.pause))
-                return;
-
-        cs4231_ready(drv);
-
-        cs4231_chip->perchip_info.record.active = 1;
-        cs4231_chip->recording_count = 0;
-
-        csr = sbus_readl(cs4231_chip->regs + APCCSR);
-        if ((csr & APC_CPAUSE) || !(csr & APC_CDMA_READY)) {
-                csr &= ~APC_XINT_CAPT;
-                sbus_writel(csr, cs4231_chip->regs + APCCSR);
-                csr &= ~APC_CPAUSE;
-                sbus_writel(csr, cs4231_chip->regs + APCCSR);
-
-                cs4231_recintr(drv);
-
-                csr |= APC_CAPT_SETUP;
-                sbus_writel(csr, cs4231_chip->regs + APCCSR);
-
-                cs4231_enable_rec(drv);
-                cs4231_ready(drv);
-        } else {
-                cs4231_recintr(drv);
-        }
-}
-
-static void cs4231_stop_input(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        u32 csr;
-
-        cs4231_chip->perchip_info.record.active = 0;
-
-        csr = sbus_readl(cs4231_chip->regs + APCCSR);
-        csr |= APC_CPAUSE;
-        sbus_writel(csr, cs4231_chip->regs + APCCSR);
-
-        cs4231_chip->input_ptr = NULL;
-        cs4231_chip->input_size = 0;
-
-        if (cs4231_chip->input_dma_handle) {
-                sbus_unmap_single(drv->dev,
-                                  cs4231_chip->input_dma_handle,
-                                  cs4231_chip->input_dma_size,
-                                  SBUS_DMA_FROMDEVICE);
-                cs4231_chip->input_dma_handle = 0;
-                cs4231_chip->input_dma_size = 0;
-        }
-
-        if (cs4231_chip->input_next_dma_handle) {
-                sbus_unmap_single(drv->dev,
-                                  cs4231_chip->input_next_dma_handle,
-                                  cs4231_chip->input_next_dma_size,
-                                  SBUS_DMA_FROMDEVICE);
-                cs4231_chip->input_next_dma_handle = 0;
-                cs4231_chip->input_next_dma_size = 0;
-        }
-
-        cs4231_pollinput(drv);
-}
-
-#ifdef EB4231_SUPPORT
-static void eb4231_start_input(struct sparcaudio_driver *drv, __u8 * buffer, 
-                               unsigned long count)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        u32 dcsr;
-
-        cs4231_chip->input_ptr = buffer;
-        cs4231_chip->input_size = count;
-
-        if (cs4231_chip->perchip_info.record.active || 
-            (cs4231_chip->perchip_info.record.pause))
-                return;
-
-        cs4231_ready(drv);
-        cs4231_chip->perchip_info.record.active = 1;
-        cs4231_chip->recording_count = 0;
-
-        dcsr = readl(cs4231_chip->eb2c + EBDMA_CSR);
-        if (!(dcsr & EBUS_DCSR_EN_DMA)) {
-                writel(EBUS_DCSR_RESET, cs4231_chip->eb2c + EBDMA_CSR);
-                writel(EBUS_DCSR_BURST_SZ_16, cs4231_chip->eb2c + EBDMA_CSR);
-
-                eb4231_recintr(drv);
-
-                writel(EBUS_DCSR_BURST_SZ_16 |
-                       (EBUS_DCSR_EN_DMA | EBUS_DCSR_INT_EN |
-                        EBUS_DCSR_EN_CNT | EBUS_DCSR_EN_NEXT),
-                       cs4231_chip->eb2c + EBDMA_CSR);
-
-                cs4231_enable_rec(drv);
-                cs4231_ready(drv);
-        } else {
-                eb4231_recintr(drv);
-        }
-}
-
-static void eb4231_stop_input(struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        u32 dcsr;
-
-        cs4231_chip->perchip_info.record.active = 0;
-
-        cs4231_chip->input_ptr = NULL;
-        cs4231_chip->input_size = 0;
-
-        if (cs4231_chip->input_dma_handle) {
-		pci_unmap_single((struct pci_dev *)drv->dev,
-				 cs4231_chip->input_dma_handle,
-				 cs4231_chip->input_dma_size,
-                                 PCI_DMA_FROMDEVICE);
-                cs4231_chip->input_dma_handle = 0;
-                cs4231_chip->input_dma_size = 0;
-        }
-
-        if (cs4231_chip->input_next_dma_handle) {
-		pci_unmap_single((struct pci_dev *)drv->dev,
-				 cs4231_chip->input_next_dma_handle,
-				 cs4231_chip->input_next_dma_size,
-                                 PCI_DMA_FROMDEVICE);
-                cs4231_chip->input_next_dma_handle = 0;
-                cs4231_chip->input_next_dma_size = 0;
-        }
-
-        dcsr = readl(cs4231_chip->eb2c + EBDMA_CSR);
-        if (dcsr & EBUS_DCSR_EN_DMA)
-                writel(dcsr & ~EBUS_DCSR_EN_DMA, cs4231_chip->eb2c + EBDMA_CSR);
-
-        cs4231_disable_rec(drv);
-}
-#endif
-
-static int cs4231_set_output_pause(struct sparcaudio_driver *drv, int value)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-
-        cs4231_chip->perchip_info.play.pause = value;
-
-        if (!value)
-                sparcaudio_output_done(drv, 0);
-
-        return value;
-}
-
-static int cs4231_set_output_error(struct sparcaudio_driver *drv, int value)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        int i;
-  
-        i = cs4231_chip->perchip_info.play.error;
-        cs4231_chip->perchip_info.play.error = value;
-  
-        return i;
-}
-
-static int cs4231_set_input_error(struct sparcaudio_driver *drv, int value)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        int i;
-  
-        i = cs4231_chip->perchip_info.record.error;
-        cs4231_chip->perchip_info.record.error = value;
-  
-        return i;
-}
-
-static int cs4231_set_output_samples(struct sparcaudio_driver *drv, int value)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private;
-        int i;
-  
-        i = cs4231_chip->perchip_info.play.samples;
-        cs4231_chip->perchip_info.play.samples = value;
-  
-        return i;
-}
-
-static int cs4231_set_input_samples(struct sparcaudio_driver *drv, int value)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        int i;
-  
-        i = cs4231_chip->perchip_info.record.samples;
-        cs4231_chip->perchip_info.record.samples = value;
-
-        return i;
-}
-
-static int cs4231_set_input_pause(struct sparcaudio_driver *drv, int value)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-
-        cs4231_chip->perchip_info.record.pause = value;
-	
-        if (value)
-                cs4231_stop_input(drv);
-	
-        return value;
-}
-
-static void cs4231_audio_getdev(struct sparcaudio_driver *drv,
-                                 audio_device_t * audinfo)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-
-        strncpy(audinfo->name, "SUNW,CS4231", sizeof(audinfo->name) - 1);
-        /* versions */
-        /* a: SPARCstation 4/5          b: Ultra 1/2 (electron)       */
-        /* c: Ultra 1/2 PCI? (positron) d: ppc                        */
-        /* e: x86                       f: Ultra Enterprise? (tazmo)  */
-        /* g: Ultra 30? (quark)         h: Ultra 5/10? (darwin)       */
-        /* apparently Ultra 1, Ultra 2 don't have internal CD input */
-        if (cs4231_chip->status & CS_STATUS_IS_ULTRA)
-                strncpy(audinfo->version, "b", sizeof(audinfo->version) - 1);
-        else
-                strncpy(audinfo->version, "a", sizeof(audinfo->version) - 1);
-        strncpy(audinfo->config, "onboard1", sizeof(audinfo->config) - 1);
-}
-
-
-static int cs4231_audio_getdev_sunos(struct sparcaudio_driver *drv)
-{
-        return AUDIO_DEV_CS4231;
-}
-
-static void cs4231_loopback(struct sparcaudio_driver *drv, unsigned int value)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-
-        WRITE_IAR(0x0d);
-        WRITE_IDR(value ? LOOPB_ON : 0);
-}
-
-static int cs4231_ioctl(struct inode * inode, struct file * file,
-			unsigned int cmd, unsigned long arg, 
-			struct sparcaudio_driver *drv)
-{
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        int retval = 0;
-  
-        switch (cmd) {
-        case AUDIO_DIAG_LOOPBACK:
-                cs4231_chip->status |= CS_STATUS_INIT_ON_CLOSE;
-                cs4231_loopback(drv, (unsigned int)arg);
-                break;
-        default:
-                retval = -EINVAL;
-        };
-
-        return retval;
-}
-
-#ifdef EB4231_SUPPORT
-/* ebus audio capture interrupt handler. */
-void eb4231_cinterrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-        struct sparcaudio_driver *drv = (struct sparcaudio_driver *) dev_id;
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        u32 dummy;
-  
-        /* Clear the interrupt. */
-        dummy = readl(cs4231_chip->eb2c + EBDMA_CSR);
-        writel(dummy, cs4231_chip->eb2c + EBDMA_CSR);
-
-        if ((dummy & EBUS_DCSR_TC) != 0
-            /*&& (dummy & EBUS_DCSR_A_LOADED) != 0*/) {
-                cs4231_chip->perchip_info.record.samples += 
-                    cs4231_length_to_samplecount(&(cs4231_chip->perchip_info.record), 
-                                                 cs4231_chip->reclen);
-                eb4231_recintr(drv);
-        }
-
-        if ((dummy & EBUS_DCSR_A_LOADED) == 0) {
-                cs4231_chip->perchip_info.record.active = 0;
-                eb4231_recintr(drv);
-                eb4231_getsamplecount(drv, cs4231_chip->reclen, 1);
-        }
-}
-
-/* ebus audio play interrupt handler. */
-void eb4231_pinterrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-        struct sparcaudio_driver *drv = (struct sparcaudio_driver *) dev_id;
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        u32 dummy;
-  
-        /* Clear the interrupt.  Bleh, when not using the next-address
-         * feature, TC can only be cleared by a reset.
-         */
-        dummy = readl(cs4231_chip->eb2p + EBDMA_CSR);
-        writel(dummy, cs4231_chip->eb2p + EBDMA_CSR);
-
-        /* If we get a terminal count and address loaded condition,
-         * this means the DNAR was copied into DACR.
-         */
-        if((dummy & EBUS_DCSR_TC) != 0
-           /*&& (dummy & EBUS_DCSR_A_LOADED) != 0*/) {
-                cs4231_chip->perchip_info.play.samples += 
-                        cs4231_length_to_samplecount(&(cs4231_chip->perchip_info.play), 
-                                                     cs4231_chip->playlen); 
-                eb4231_playintr(drv);
-        }
-
-        if((dummy & EBUS_DCSR_A_LOADED) == 0) {
-                cs4231_chip->perchip_info.play.active = 0;
-                eb4231_playintr(drv);
-                eb4231_getsamplecount(drv, cs4231_chip->playlen, 0);
-        }
-}
-#endif
-
-/* Audio interrupt handler. */
-void cs4231_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-        struct sparcaudio_driver *drv = (struct sparcaudio_driver *) dev_id;
-        struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-        __u32 dummy;
-  
-        dprintk(("in cs4231_interrupt\n"));
-
-        /* Clear the interrupt. */
-        dummy = sbus_readl(cs4231_chip->regs + APCCSR);
-        sbus_writel(dummy, cs4231_chip->regs + APCCSR);
-
-        /* now go through and figure out what gets to claim the interrupt 
-         * if anything since we may be doing shared interrupts 
-         */
-        if (dummy & APC_PLAY_INT) {
-                if (dummy & APC_XINT_PNVA) {
-                        cs4231_chip->perchip_info.play.samples += 
-                         cs4231_length_to_samplecount(&(cs4231_chip->perchip_info.play), 
-                                                      cs4231_chip->playlen); 
-                        if (!(dummy & APC_XINT_EMPT))
-                                cs4231_playintr(drv, 1);
-                } 
-                /* Any other conditions we need worry about? */
-        }
-
-        if (dummy & APC_CAPT_INT) {
-                if (dummy & APC_XINT_CNVA) {
-                  cs4231_chip->perchip_info.record.samples += 
-                    cs4231_length_to_samplecount(&(cs4231_chip->perchip_info.record), 
-                                                 cs4231_chip->reclen);
-                  cs4231_recintr(drv);
-                }
-                /* Any other conditions we need worry about? */
-        }
-
-  
-        if (dummy & APC_XINT_CEMP) {
-                if (cs4231_chip->perchip_info.record.active == 0) {
-                        /* Fix me */
-                        cs4231_chip->perchip_info.record.active = 0;
-                        cs4231_chip->perchip_info.record.error = 1;
-                        cs4231_recintr(drv);
-                }
-        }
-
-        if (dummy & APC_XINT_EMPT) {
-                if (!cs4231_chip->output_next_dma_handle) {
-                        u32 csr = sbus_readl(cs4231_chip->regs + APCCSR);
-
-                        csr |= APC_PPAUSE;
-                        sbus_writel(csr, cs4231_chip->regs + APCCSR);
-                        cs4231_disable_play(drv);
-                        cs4231_chip->perchip_info.play.error = 1;
-                }
-                cs4231_chip->perchip_info.play.active = 0;
-                cs4231_playintr(drv, 0);
-
-                cs4231_getsamplecount(drv, cs4231_chip->playlen, 0);
-        }
-
-        if (dummy & APC_GENL_INT) {
-                /* If we get here we must be sharing an interrupt, but I haven't code 
-                 * to handle this right now.
-                 */
-        }
-}
-
-static struct sparcaudio_operations cs4231_ops = {
-	cs4231_open,
-	cs4231_release,
-	cs4231_ioctl,
-	cs4231_start_output,
-	cs4231_stop_output,
-	cs4231_start_input,
-        cs4231_stop_input,
-	cs4231_audio_getdev,
-        cs4231_set_output_volume,
-        cs4231_get_output_volume,
-        cs4231_set_input_volume,
-        cs4231_get_input_volume,
-        cs4231_set_monitor_volume,
-        cs4231_get_monitor_volume,
-	cs4231_set_output_balance,
-	cs4231_get_output_balance,
-        cs4231_set_input_balance,
-        cs4231_get_input_balance,
-        cs4231_set_output_channels,
-        cs4231_get_output_channels,
-        cs4231_set_input_channels,
-        cs4231_get_input_channels,
-        cs4231_set_output_precision,
-        cs4231_get_output_precision,
-        cs4231_set_input_precision,
-        cs4231_get_input_precision,
-        cs4231_set_output_port,
-        cs4231_get_output_port,
-        cs4231_set_input_port,
-        cs4231_get_input_port,
-        cs4231_set_output_encoding,
-        cs4231_get_output_encoding,
-        cs4231_set_input_encoding,
-        cs4231_get_input_encoding,
-        cs4231_set_output_rate,
-        cs4231_get_output_rate,
-        cs4231_set_input_rate,
-	cs4231_get_input_rate,
-	cs4231_audio_getdev_sunos,
-	cs4231_get_output_ports,
-	cs4231_get_input_ports,
-	cs4231_output_muted,
-	cs4231_get_output_muted,
-	cs4231_set_output_pause,
-	cs4231_get_output_pause,
-	cs4231_set_input_pause,
-	cs4231_get_input_pause,
-	cs4231_set_output_samples,
-	cs4231_get_output_samples,
-	cs4231_set_input_samples,
-	cs4231_get_input_samples,
-	cs4231_set_output_error,
-	cs4231_get_output_error,
-	cs4231_set_input_error,
-	cs4231_get_input_error,
-        cs4231_get_formats,
-};
-
-#ifdef EB4231_SUPPORT
-static struct sparcaudio_operations eb4231_ops = {
-	cs4231_open,
-	cs4231_release,
-	cs4231_ioctl,
-	eb4231_start_output,
-	eb4231_stop_output,
-	eb4231_start_input,
-        eb4231_stop_input,
-	cs4231_audio_getdev,
-        cs4231_set_output_volume,
-        cs4231_get_output_volume,
-        cs4231_set_input_volume,
-        cs4231_get_input_volume,
-        cs4231_set_monitor_volume,
-        cs4231_get_monitor_volume,
-	cs4231_set_output_balance,
-	cs4231_get_output_balance,
-        cs4231_set_input_balance,
-        cs4231_get_input_balance,
-        cs4231_set_output_channels,
-        cs4231_get_output_channels,
-        cs4231_set_input_channels,
-        cs4231_get_input_channels,
-        cs4231_set_output_precision,
-        cs4231_get_output_precision,
-        cs4231_set_input_precision,
-        cs4231_get_input_precision,
-        cs4231_set_output_port,
-        cs4231_get_output_port,
-        cs4231_set_input_port,
-        cs4231_get_input_port,
-        cs4231_set_output_encoding,
-        cs4231_get_output_encoding,
-        cs4231_set_input_encoding,
-        cs4231_get_input_encoding,
-        cs4231_set_output_rate,
-        cs4231_get_output_rate,
-        cs4231_set_input_rate,
-	cs4231_get_input_rate,
-	cs4231_audio_getdev_sunos,
-	cs4231_get_output_ports,
-	cs4231_get_input_ports,
-	cs4231_output_muted,
-	cs4231_get_output_muted,
-	cs4231_set_output_pause,
-	cs4231_get_output_pause,
-	cs4231_set_input_pause,
-	cs4231_get_input_pause,
-	cs4231_set_output_samples,
-	eb4231_get_output_samples,
-	cs4231_set_input_samples,
-	eb4231_get_input_samples,
-	cs4231_set_output_error,
-	cs4231_get_output_error,
-	cs4231_set_input_error,
-	cs4231_get_input_error,
-        cs4231_get_formats,
-};
-#endif
-
-/* Attach to an cs4231 chip given its PROM node. */
-static int cs4231_attach(struct sparcaudio_driver *drv, 
-			 struct sbus_dev *sdev)
-{
-        struct cs4231_chip *cs4231_chip;
-        int err;
-
-        /* Allocate our private information structure. */
-        drv->private = kmalloc(sizeof(struct cs4231_chip), GFP_KERNEL);
-        if (drv->private == NULL)
-                return -ENOMEM;
-
-        /* Point at the information structure and initialize it. */
-        drv->ops = &cs4231_ops;
-        cs4231_chip = (struct cs4231_chip *) drv->private;
-        cs4231_chip->input_ptr = cs4231_chip->output_ptr = NULL;
-        cs4231_chip->input_size = cs4231_chip->output_size = 0;
-        cs4231_chip->status = 0;
-
-        drv->dev = sdev;
-
-        /* Map the registers into memory. */
-        cs4231_chip->regs_size = sdev->reg_addrs[0].reg_size;
-        cs4231_chip->regs = sbus_ioremap(&sdev->resource[0], 0,
-                                         sdev->reg_addrs[0].reg_size,
-                                         "cs4231");
-
-        if (!cs4231_chip->regs) {
-                printk(KERN_ERR "cs4231: could not remap registers\n");
-                kfree(drv->private);
-                return -EIO;
-        }
-
-        /* Attach the interrupt handler to the audio interrupt. */
-        cs4231_chip->irq = sdev->irqs[0];
-        request_irq(cs4231_chip->irq, cs4231_interrupt, SA_SHIRQ, "cs4231", drv);
-
-        cs4231_chip->nirqs = 1;
-        cs4231_enable_interrupts(drv);
-
-        /* Reset the audio chip. */
-        cs4231_chip_reset(drv);
-
-        /* Register ourselves with the midlevel audio driver. */
-        err = register_sparcaudio_driver(drv, 1);
-
-        if (err < 0) {
-                printk(KERN_ERR "cs4231: unable to register\n");
-                cs4231_disable_interrupts(drv);
-                free_irq(cs4231_chip->irq, drv);
-                sbus_iounmap(cs4231_chip->regs, cs4231_chip->regs_size);
-                kfree(drv->private);
-                return -EIO;
-        }
-
-        cs4231_chip->perchip_info.play.active = 
-                cs4231_chip->perchip_info.play.pause = 0;
-
-        cs4231_chip->perchip_info.record.active = 
-                cs4231_chip->perchip_info.record.pause = 0;
-
-        cs4231_chip->perchip_info.play.avail_ports = (AUDIO_HEADPHONE |
-                                                      AUDIO_SPEAKER |
-                                                      AUDIO_LINE_OUT);
-
-        cs4231_chip->perchip_info.record.avail_ports = (AUDIO_INTERNAL_CD_IN |
-                                                        AUDIO_LINE_IN | 
-                                                        AUDIO_MICROPHONE |
-                                                        AUDIO_ANALOG_LOOPBACK);
-
-        /* Announce the hardware to the user. */
-        printk(KERN_INFO "audio%d: cs4231%c at %lx irq %s\n",
-               drv->index, (cs4231_chip->status & CS_STATUS_REV_A) ? 'a' : ' ', 
-               cs4231_chip->regs, __irq_itoa(cs4231_chip->irq));
-  
-        /* Success! */
-        return 0;
-}
-
-#ifdef EB4231_SUPPORT
-/* Attach to an cs4231 chip given its PROM node. */
-static int eb4231_attach(struct sparcaudio_driver *drv, 
-			 struct linux_ebus_device *edev)
-{
-        struct cs4231_chip *cs4231_chip;
-        int len, err, nregs;
-        struct linux_prom_registers regs[4];
-
-        /* Allocate our private information structure. */
-        drv->private = kmalloc(sizeof(struct cs4231_chip), GFP_KERNEL);
-        if (drv->private == NULL)
-                return -ENOMEM;
-
-        /* Point at the information structure and initialize it. */
-        drv->ops = &eb4231_ops;
-        cs4231_chip = (struct cs4231_chip *) drv->private;
-        cs4231_chip->input_ptr = cs4231_chip->output_ptr = NULL;
-        cs4231_chip->input_size = cs4231_chip->output_size = 0;
-        cs4231_chip->status = 0;
-
-        drv->dev = (struct sbus_dev *)edev->bus->self;
-
-        len = prom_getproperty(edev->prom_node, "reg", (void *)regs, sizeof(regs));
-        if ((len % sizeof(regs[0])) != 0) {
-                printk("eb4231: Strange reg property size %d\n", len);
-                return -ENODEV;
-        }
-
-        nregs = len / sizeof(regs[0]);
-        cs4231_chip->regs = (unsigned long)ioremap(edev->resource[0].start, 0x10);
-        cs4231_chip->eb2p = (unsigned long)ioremap(edev->resource[1].start, 0x10);
-        cs4231_chip->eb2c = (unsigned long)ioremap(edev->resource[2].start, 0x10);
-
-        cs4231_chip->status |= CS_STATUS_IS_EBUS;
-
-        /* Attach the interrupt handler to the audio interrupt. */
-        cs4231_chip->irq = edev->irqs[0];
-        cs4231_chip->irq2 = edev->irqs[1];
-
-        if(request_irq(cs4231_chip->irq, eb4231_cinterrupt, SA_SHIRQ, "cs4231", drv) ||
-           request_irq(cs4231_chip->irq2, eb4231_pinterrupt, SA_SHIRQ, "cs4231", drv))
-                goto bail;
-
-        cs4231_chip->nirqs = 2;
-        cs4231_enable_interrupts(drv);
-
-        /* Reset the audio chip. */
-        cs4231_chip_reset(drv);
-
-        /* Register ourselves with the midlevel audio driver. */
-        err = register_sparcaudio_driver(drv, 1);
-
-        if (err < 0) {
-        bail:
-                printk(KERN_ERR "cs4231: unable to register\n");
-                cs4231_disable_interrupts(drv);
-                free_irq(cs4231_chip->irq, drv);
-                free_irq(cs4231_chip->irq2, drv);
-                kfree(drv->private);
-                return -EIO;
-        }
-
-        cs4231_chip->perchip_info.play.active = 
-                cs4231_chip->perchip_info.play.pause = 0;
-
-        cs4231_chip->perchip_info.record.active = 
-                cs4231_chip->perchip_info.record.pause = 0;
-
-        cs4231_chip->perchip_info.play.avail_ports = (AUDIO_HEADPHONE |
-                                                      AUDIO_SPEAKER |
-                                                      AUDIO_LINE_OUT);
-
-        cs4231_chip->perchip_info.record.avail_ports = (AUDIO_INTERNAL_CD_IN |
-                                                        AUDIO_LINE_IN | 
-                                                        AUDIO_MICROPHONE |
-                                                        AUDIO_ANALOG_LOOPBACK);
-
-        /* Announce the hardware to the user. */
-        printk(KERN_INFO "audio%d: cs4231%c(eb2) at %lx irq %s\n",
-               drv->index, (cs4231_chip->status & CS_STATUS_REV_A) ? 'a' : ' ', 
-               cs4231_chip->regs, __irq_itoa(cs4231_chip->irq));
-  
-        /* Success! */
-        return 0;
-}
-#endif
-
-#ifdef EB4231_SUPPORT
-static int __init ebus_cs4231_p(struct linux_ebus_device *edev)
-{
-        if (!strcmp(edev->prom_name, "SUNW,CS4231"))
-                return 1;
-        if (!strcmp(edev->prom_name, "audio")) {
-                char compat[16];
-
-                prom_getstring(edev->prom_node, "compatible",
-                               compat, sizeof(compat));
-                compat[15] = '\0';
-                if (!strcmp(compat, "SUNW,CS4231"))
-                        return 1;
-        }
-
-        return 0;
-}
-#endif
-
-/* Detach from an cs4231 chip given the device structure. */
-static void __exit cs4231_detach(struct sparcaudio_driver *drv)
-{
-	struct cs4231_chip *cs4231_chip = (struct cs4231_chip *) drv->private;
-
-	cs4231_disable_interrupts(drv);
-	unregister_sparcaudio_driver(drv, 1);
-	free_irq(cs4231_chip->irq, drv);
-	if (!(cs4231_chip->status & CS_STATUS_IS_EBUS)) {
-		sbus_iounmap(cs4231_chip->regs, cs4231_chip->regs_size);
-	} else {
-#ifdef EB4231_SUPPORT
-		iounmap(cs4231_chip->regs);
-		iounmap(cs4231_chip->eb2p);
-		iounmap(cs4231_chip->eb2c);
-		free_irq(cs4231_chip->irq2, drv);
-#endif
-	}
-	kfree(drv->private);
-}
-
-
-/* Probe for the cs4231 chip and then attach the driver. */
-static int __init cs4231_init(void)
-{
-        struct sbus_bus *sbus;
-        struct sbus_dev *sdev;
-#ifdef EB4231_SUPPORT
-        struct linux_ebus *ebus;
-        struct linux_ebus_device *edev;
-#endif
-
-        num_drivers = 0;
-  
-        /* Probe each SBUS for cs4231 chips. */
-        for_all_sbusdev(sdev, sbus) {
-                if (!strcmp(sdev->prom_name, "SUNW,CS4231")) {
-                        /* Don't go over the max number of drivers. */
-                        if (num_drivers >= MAX_DRIVERS)
-                                continue;
-      
-                        if (cs4231_attach(&drivers[num_drivers], sdev) == 0)
-                                num_drivers++;
-                }
-        }
-  
-#ifdef EB4231_SUPPORT
-        for_each_ebus(ebus) {
-                for_each_ebusdev(edev, ebus) {
-                        if (ebus_cs4231_p(edev)) {
-                                /* Don't go over the max number of drivers. */
-                                if (num_drivers >= MAX_DRIVERS)
-                                        continue;
-      
-                                if (eb4231_attach(&drivers[num_drivers], edev) == 0)
-                                        num_drivers++;
-                        }
-                }
-        }
-#endif
-
-        /* Only return success if we found some cs4231 chips. */
-        return (num_drivers > 0) ? 0 : -EIO;
-}
-
-static void __exit cs4231_exit(void)
-{
-        register int i;
-
-        for (i = 0; i < num_drivers; i++) {
-                cs4231_detach(&drivers[i]);
-                num_drivers--;
-        }
-}
-
-module_init(cs4231_init);
-module_exit(cs4231_exit);
-MODULE_LICENSE("GPL");
-/*
- * 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-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
diff -Nru a/drivers/sbus/audio/cs4231.h b/drivers/sbus/audio/cs4231.h
--- a/drivers/sbus/audio/cs4231.h	Tue Oct  1 00:08:15 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,313 +0,0 @@
-/* $Id: cs4231.h,v 1.13 1999/09/21 14:37:27 davem Exp $
- * drivers/sbus/audio/cs4231.h
- *
- * Copyright (C) 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu)
- * Copyright (C) 1997 Derrick J. Brashear (shadow@dementia.org)
- * Copyright (C) 1999 David S. Miller (davem@redhat.com)
- */
-
-#ifndef _CS4231_H_
-#define _CS4231_H_
-
-#include <linux/types.h>
-
-/* According to the CS4231A data provided on CS web site and sun's includes */
-#define IAR	0x00UL	/* Index Address Register */
-#define IDR	0x04UL	/* Index Data Register */
-#define STAT	0x08UL	/* Status Register */
-#define PIOD	0x0cUL	/* PIO Data Register */
-#define APCCSR	0x10UL	/* APC DMA CSR */
-#define APCCVA	0x20UL	/* APC Capture DMA Address */
-#define APCCC	0x24UL	/* APC Capture Count */
-#define APCCNVA	0x28UL	/* APC Capture DMA Next Address */
-#define APCCNC	0x2cUL	/* APC Capture Next Count */
-#define APCPVA	0x30UL	/* APC Play DMA Address */
-#define APCPC	0x34UL	/* APC Play Count */
-#define APCPNVA	0x38UL	/* APC Play DMA Next Address */
-#define APCPNC	0x3cUL	/* APC Play Next Count */
-
-/* EBUS DMA Registers */
-#define EBDMA_CSR	0x00UL	/* Control/Status */
-#define EBDMA_ADDR	0x04UL	/* DMA Address */
-#define EBDMA_COUNT	0x08UL	/* DMA Count */
-
-/* Our structure for each chip */
-struct cs4231_chip {
-	unsigned long regs;
-	unsigned long eb2c;
-	unsigned long eb2p;
-	struct audio_info perchip_info;
-	unsigned int playlen, reclen;
-	int irq, irq2, nirqs;
-	unsigned long regs_size;
-  
-	/* Keep track of various info */
-	volatile unsigned int status;
-  
-	/* Current buffer that the driver is playing. */
-	volatile __u8 * output_ptr;
-	volatile __u32 output_size;
-	volatile __u32 output_dma_handle, output_next_dma_handle;
-	volatile __u32 output_dma_size, output_next_dma_size;
-
-	/* Current record buffer. */
-	volatile __u8 * input_ptr;
-	volatile __u32 input_size;
-	volatile __u32 input_dma_handle, input_next_dma_handle;
-	volatile __u32 input_dma_size, input_next_dma_size;
-
-	/* Number of buffers in the pipe. */
-	volatile __u32 playing_count;
-	volatile __u32 recording_count;
-};
-
-#ifdef EB4231_SUPPORT
-#define CS4231_READ32(__C, __REG)		\
-	(((__C)->status & CS_STATUS_IS_EBUS) ?	\
-	readl((__REG)) :			\
-	sbus_readl((__REG)))
-#define CS4231_READ8(__C, __REG) \
-	(((__C)->status & CS_STATUS_IS_EBUS) ?	\
-	readb((__REG)) :			\
-	sbus_readb((__REG)))
-#define CS4231_WRITE32(__C, __REG, __VAL)	\
-	(((__C)->status & CS_STATUS_IS_EBUS) ?	\
-         writel((__VAL), (__REG)) :		\
-         sbus_writel((__VAL), (__REG)))
-#define CS4231_WRITE8(__C, __REG, __VAL)	\
-	(((__C)->status & CS_STATUS_IS_EBUS) ?	\
-         writeb((__VAL), (__REG)) :		\
-         sbus_writeb((__VAL), (__REG)))
-#else
-/* We can assume all is SBUS in this case. */
-#define CS4231_READ32(__C, __REG) sbus_readl((__REG))
-#define CS4231_READ8(__C, __REG) sbus_readb((__REG))
-#define CS4231_WRITE32(__C, __REG, __VAL) sbus_writel((__VAL), (__REG))
-#define CS4231_WRITE8(__C, __REG, __VAL) sbus_writeb((__VAL), (__REG))
-#endif
-
-/* Local status bits */
-#define CS_STATUS_NEED_INIT 0x01
-#define CS_STATUS_INIT_ON_CLOSE 0x02
-#define CS_STATUS_REV_A 0x04
-#define CS_STATUS_INTS_ON 0x08
-#define CS_STATUS_IS_ULTRA 0x10
-#define CS_STATUS_IS_EBUS 0x20
-
-#define CS_TIMEOUT      9000000
-
-#define GAIN_SET(var, gain)     ((var & ~(0x3f)) | gain)
-#define RECGAIN_SET(var, gain)  ((var & ~(0x1f)) | gain)
-
-/* bits 0-3 set address of register accessed by idr register */
-/* bit 4 allows access to idr registers 16-31 in mode 2 only */
-/* bit 5 if set causes dma transfers to cease if the int bit of status set */
-#define IAR_AUTOCAL_BEGIN       0x40    /* MCE */
-#define IAR_NOT_READY           0x80    /* INIT */
-
-#define IAR_AUTOCAL_END         ~(IAR_AUTOCAL_BEGIN) /* MCD */
-
-/* Registers 1-15 modes 1 and 2. Registers 16-31 mode 2 only */
-/* Registers assumed to be same in both modes unless noted */
-
-/* 0 - Left Input Control */
-/* 1 - Right Input Control */
-#define MIC_ENABLE(var)         ((var & 0x2f) | 0x80)
-#define LINE_ENABLE(var)        (var & 0x2f)
-#define CDROM_ENABLE(var)       ((var & 0x2f) | 0x40)
-#define OUTPUTLOOP_ENABLE(var)  ((var & 0x2f) | 0xC0)
-#define INPUTCR_AUX1            0x40
-
-/* 2 - Left Aux 1 Input Control */
-/* 3 - Right Aux 1 Input Control */
-/* 4 - Left Aux 2 Input Control */
-/* 5 - Right Aux 2 Input Control */
-
-/* 6 - Left Output Control */
-/* 7 - Right Output Control */
-#define OUTCR_MUTE              0x80
-#define OUTCR_UNMUTE            ~0x80
-
-/* 8 - Playback Data Format (Mode 2) */
-#define CHANGE_DFR(var, val)            ((var & ~(0xF)) | val)
-#define CHANGE_ENCODING(var, val)       ((var & ~(0xe0)) | val)
-#define DEFAULT_DATA_FMAT               CS4231_DFR_ULAW
-#define CS4231_DFR_5512                 0x01
-#define CS4231_DFR_6615                 0x0f
-#define CS4231_DFR_8000                 0x00
-#define CS4231_DFR_9600                 0x0e
-#define CS4231_DFR_11025                0x03
-#define CS4231_DFR_16000                0x02
-#define CS4231_DFR_18900                0x05
-#define CS4231_DFR_22050                0x07
-#define CS4231_DFR_27429                0x04
-#define CS4231_DFR_32000                0x06
-#define CS4231_DFR_33075                0x0d
-#define CS4231_DFR_37800                0x09
-#define CS4231_DFR_44100                0x0b
-#define CS4231_DFR_48000                0x0c
-#define CS4231_DFR_LINEAR8              0x00
-#define CS4231_DFR_ULAW                 0x20
-#define CS4231_DFR_LINEARLE             0x40
-#define CS4231_DFR_ALAW                 0x60
-#define CS4231_DFR_ADPCM                0xa0 /* N/A in mode 1 */
-#define CS4231_DFR_LINEARBE             0xc0 /* N/A in mode 1 */
-#define CS4231_STEREO_ON(val)           (val | 0x10)
-#define CS4231_MONO_ON(val)             (val & ~0x10)
-
-/* 9 - Interface Config. Register */
-#define PEN_ENABLE              (0x01) /* Playback Enable */
-#define PEN_DISABLE             (~0x01)
-#define CEN_ENABLE              (0x02) /* Capture Enable */
-#define CEN_DISABLE             (~0x02)
-#define SDC_ENABLE              (0x04) /* Turn on single DMA Channel mode */
-#define ACAL_CONV               0x08   /* Turn on converter autocal */
-#define ACAL_DISABLE            (~0x08) 
-#define ACAL_DAC                0x10  /* Turn on DAC autocal */
-#define ACAL_FULL               (ACAL_DAC|ACAL_CONV) /* Turn on full autocal */
-#define PPIO                    0x20 /* do playback via PIO rather than DMA */
-#define CPIO                    0x40 /* do capture via PIO rather than DMA */
-#define ICR_AUTOCAL_INIT        0x01
-
-/* 10 - Pin Control Register */
-#define INTR_ON                 0x82
-#define INTR_OFF                0x80
-#define PINCR_LINE_MUTE         0x40
-#define PINCR_HDPH_MUTE         0x80
-
-/* 11 - Test/Initialization */
-#define DRQ_STAT                0x10
-#define AUTOCAL_IN_PROGRESS      0x20
-
-/* 12 - Misc Information */
-#define MISC_IR_MODE2           0x40
-
-/* 13 - Loopback Control */
-#define LOOPB_ON                0x01
-#define LOOPB_OFF               0x00
-
-/* 14 - shared play/capture upper (mode 1) */
-/* 15 - shared play/capture lower (mode 1) */
-
-/* 14 - Playback Upper (mode 2) */
-/* 15 - Playback Lower (mode 2) */
-
-/* The rest are mode 2 only */
-
-/* 16 - Alternate Feature 1 Enable */
-#define DAC_ZERO                0x01
-#define PLAY_MCE                0x10
-#define CAPTURE_MCE             0x20
-#define TIMER_ENABLE            0x40
-#define OLB_ENABLE              0x80 /* go to 2.88 vpp analog output */
-
-/* 17 - Alternate Feature 2 Enable */
-#define HPF_ON                  0x01 /* High Pass Filter */
-#define XTALE_ON                0x02 /* Enable both crystals */
-#define APAR_OFF                0x04 /* ADPCM playback accum reset */
-
-/* 18 - Left Line Input Gain */
-/* 19 - Right Line Input Gain */
-
-/* 20 - Timer High */
-/* 21 - Timer Low */
-
-/* 22 - unused */
-
-/* 23 - Alt. Fea. Ena 3 */
-#define ACF 0x01
-
-/* 24 - Alternate Feature Status */
-#define CS_PU                   0x01 /* Underrun */
-#define CS_PO                   0x02 /* Overrun */
-#define CS_CU                   0x04 /* Underrun */
-#define CS_CO                   0x08 /* Overrun */
-#define CS_PI                   0x10 
-#define CS_CI                   0x20 
-#define CS_TI                   0x40 
-
-/* 25 - Version */
-#define CS4231A         0x20
-#define CS4231CDE       0x80
-
-/* 26 - Mono I/O Control */
-#define CHANGE_MONO_GAIN(val)   ((val & ~(0xFF)) | val)
-#define MONO_IOCR_BYPASS     0x20 
-#define MONO_IOCR_MUTE       0x40
-#define MONO_IOCR_INMUTE     0x80
-
-/* 27 - Unused */
-
-/* 28 - Capture Data Format */
-/* see register 8 */
-
-/* 29 - Unused */
-
-/* 30 - Capture Upper */
-/* 31 - Capture Lower */
-
-/* Following are APC CSR register definitions for the Sparc */
-
-#define APC_INT_PENDING 0x800000 /* Interrupt Pending */
-#define APC_PLAY_INT    0x400000 /* Playback interrupt */
-#define APC_CAPT_INT    0x200000 /* Capture interrupt */
-#define APC_GENL_INT    0x100000 /* General interrupt */
-#define APC_XINT_ENA    0x80000  /* General ext int. enable */
-#define APC_XINT_PLAY   0x40000  /* Playback ext intr */
-#define APC_XINT_CAPT   0x20000  /* Capture ext intr */
-#define APC_XINT_GENL   0x10000  /* Error ext intr */
-#define APC_XINT_EMPT   0x8000   /* Pipe empty interrupt (0 write to pva) */
-#define APC_XINT_PEMP   0x4000   /* Play pipe empty (pva and pnva not set) */
-#define APC_XINT_PNVA   0x2000   /* Playback NVA dirty */
-#define APC_XINT_PENA   0x1000   /* play pipe empty Int enable */
-#define APC_XINT_COVF   0x800    /* Cap data dropped on floor */
-#define APC_XINT_CNVA   0x400    /* Capture NVA dirty */
-#define APC_XINT_CEMP   0x200    /* Capture pipe empty (cva and cnva not set) */
-#define APC_XINT_CENA   0x100    /* Cap. pipe empty int enable */
-#define APC_PPAUSE      0x80     /* Pause the play DMA */
-#define APC_CPAUSE      0x40     /* Pause the capture DMA */
-#define APC_CDC_RESET   0x20     /* CODEC RESET */
-#define APC_PDMA_READY  0x08     /* Play DMA Go */
-#define APC_CDMA_READY  0x04     /* Capture DMA Go */
-#define APC_CHIP_RESET  0x01     /* Reset the chip */
-
-#define APC_INIT_SETUP  (APC_CDMA_READY | APC_PDMA_READY | APC_XINT_ENA | \
-			 APC_XINT_PLAY | APC_XINT_GENL | APC_INT_PENDING | \
-			 APC_PLAY_INT | APC_CAPT_INT | APC_GENL_INT) 
-
-#define APC_PLAY_SETUP  (APC_GENL_INT | APC_PLAY_INT | APC_XINT_ENA | \
-			 APC_XINT_PLAY | APC_XINT_EMPT | APC_XINT_GENL | \
-			 APC_XINT_PENA | APC_PDMA_READY)
-
-#define APC_CAPT_SETUP  (APC_GENL_INT | APC_CAPT_INT | APC_XINT_ENA | \
-			 APC_XINT_CAPT | APC_XINT_CEMP | APC_XINT_GENL | \
-			 APC_CDMA_READY)
-
-/* Following are EB2 CSR register definitions for the Sparc */
-
-/* asm/ebus.h has the base settings */
-
-#define EB2_PLAY_SETUP (EBUS_DCSR_BURST_SZ_8 | EBUS_DCSR_INT_EN | EBUS_DCSR_EN_DMA | \
-			EBUS_DCSR_EN_CNT | EBUS_DCSR_TC)
-#define EB2_CAPT_SETUP (EBUS_DCSR_BURST_SZ_8 | EBUS_DCSR_INT_EN | EBUS_DCSR_EN_DMA| \
-			EBUS_DCSR_EN_CNT | EBUS_DCSR_TC | EBUS_DCSR_WRITE)
-
-#define CS4231_MIN_ATEN     (0)
-#define CS4231_MAX_ATEN     (31)
-#define CS4231_MAX_DEV_ATEN (63)
-
-#define CS4231_MON_MIN_ATEN         (0)
-#define CS4231_MON_MAX_ATEN         (63)
-
-#define CS4231_DEFAULT_PLAYGAIN     (132)
-#define CS4231_DEFAULT_RECGAIN      (126)
-
-#define CS4231_MIN_GAIN     (0)
-#define CS4231_MAX_GAIN     (15)
-
-#define CS4231_PRECISION    (8)             /* # of bits/sample */
-#define CS4231_CHANNELS     (1)             /* channels/sample */
-
-#define CS4231_RATE   (8000)                /* default sample rate */
-
-#endif /* _CS4231_H_ */
diff -Nru a/drivers/sbus/audio/dbri.c b/drivers/sbus/audio/dbri.c
--- a/drivers/sbus/audio/dbri.c	Tue Oct  1 00:08:18 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,2400 +0,0 @@
-/* $Id: dbri.c,v 1.27 2001/10/08 22:19:50 davem Exp $
- * drivers/sbus/audio/dbri.c
- *
- * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de)
- * Copyright (C) 1998, 1999 Brent Baccala (baccala@freesoft.org)
- *
- * This is the lowlevel driver for the DBRI & MMCODEC duo used for ISDN & AUDIO
- * on Sun SPARCstation 10, 20, LX and Voyager models.
- *
- * - DBRI: AT&T T5900FX Dual Basic Rates ISDN Interface. It is a 32 channel
- *   data time multiplexer with ISDN support (aka T7259)
- *   Interfaces: SBus,ISDN NT & TE, CHI, 4 bits parallel.
- *   CHI: (spelled ki) Concentration Highway Interface (AT&T or Intel bus ?).
- *   Documentation:
- *   - "STP 4000SBus Dual Basic Rate ISDN (DBRI) Tranceiver" from
- *     Sparc Technology Business (courtesy of Sun Support)
- *   - Data sheet of the T7903, a newer but very similar ISA bus equivalent
- *     available from the Lucent (formarly AT&T microelectronics) home
- *     page.
- *   - http://www.freesoft.org/Linux/DBRI/
- * - MMCODEC: Crystal Semiconductor CS4215 16 bit Multimedia Audio Codec
- *   Interfaces: CHI, Audio In & Out, 2 bits parallel
- *   Documentation: from the Crystal Semiconductor home page.
- *
- * The DBRI is a 32 pipe machine, each pipe can transfer some bits between
- * memory and a serial device (long pipes, nr 0-15) or between two serial
- * devices (short pipes, nr 16-31), or simply send a fixed data to a serial
- * device (short pipes).
- * A timeslot defines the bit-offset and nr of bits read from a serial device.
- * The timeslots are linked to 6 circular lists, one for each direction for
- * each serial device (NT,TE,CHI). A timeslot is associated to 1 or 2 pipes
- * (the second one is a monitor/tee pipe, valid only for serial input).
- *
- * The mmcodec is connected via the CHI bus and needs the data & some
- * parameters (volume, balance, output selection) timemultiplexed in 8 byte
- * chunks. It also has a control mode, which serves for audio format setting.
- *
- * Looking at the CS4215 data sheet it is easy to set up 2 or 4 codecs on
- * the same CHI bus, so I thought perhaps it is possible to use the onboard
- * & the speakerbox codec simultanously, giving 2 (not very independent :-)
- * audio devices. But the SUN HW group decided against it, at least on my
- * LX the speakerbox connector has at least 1 pin missing and 1 wrongly
- * connected.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/version.h>
-#include <linux/delay.h>
-#include <asm/openprom.h>
-#include <asm/oplib.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/sbus.h>
-#include <asm/pgtable.h>
-
-#include <asm/audioio.h>
-#include "dbri.h"
-
-#if defined(DBRI_ISDN)
-#include "../../isdn/hisax/hisax.h"
-#include "../../isdn/hisax/isdnl1.h"
-#include "../../isdn/hisax/foreign.h"
-#endif
-
-#define DBRI_DEBUG
-
-#ifdef DBRI_DEBUG
-
-#define dprintk(a, x) if(dbri_debug & a) printk x
-#define D_GEN	(1<<0)
-#define D_INT	(1<<1)
-#define D_CMD	(1<<2)
-#define D_MM	(1<<3)
-#define D_USR	(1<<4)
-#define D_DESC	(1<<5)
-
-static int dbri_debug = 0;
-MODULE_PARM(dbri_debug, "i");
-
-static int dbri_trace = 0;
-MODULE_PARM(dbri_trace, "i");
-#define tprintk(x) if(dbri_trace) printk x
-
-static char *cmds[] = { 
-  "WAIT", "PAUSE", "JUMP", "IIQ", "REX", "SDP", "CDP", "DTS",
-  "SSP", "CHI", "NT", "TE", "CDEC", "TEST", "CDM", "RESRV"
-};
-
-#define DBRI_CMD(cmd, intr, value) ((cmd << 28) | (1 << 27) | value)
-
-#else
-
-#define dprintk(a, x)
-#define DBRI_CMD(cmd, intr, value) ((cmd << 28) | (intr << 27) | value)
-
-#endif	/* DBRI_DEBUG */
-
-
-
-#define MAX_DRIVERS	2	/* Increase this if need more than 2 DBRI's */
-
-static struct sparcaudio_driver drivers[MAX_DRIVERS];
-static int num_drivers = 0;
-
-
-/*
-****************************************************************************
-************** DBRI initialization and command synchronization *************
-****************************************************************************
-
-Commands are sent to the DBRI by building a list of them in memory,
-then writing the address of the first list item to DBRI register 8.
-The list is terminated with a WAIT command, which can generate a
-CPU interrupt if required.
-
-Since the DBRI can run in parallel with the CPU, several means of
-synchronization present themselves.  The original scheme (Rudolf's)
-was to set a flag when we "cmdlock"ed the DBRI, clear the flag when
-an interrupt signaled completion, and wait on a wait_queue if a routine
-attempted to cmdlock while the flag was set.  The problems arose when
-we tried to cmdlock from inside an interrupt handler, which might
-cause scheduling in an interrupt (if we waited), etc, etc
-
-A more sophisticated scheme might involve a circular command buffer
-or an array of command buffers.  A routine could fill one with
-commands and link it onto a list.  When a interrupt signaled
-completion of the current command buffer, look on the list for
-the next one.
-
-I've decided to implement something much simpler - after each command,
-the CPU waits for the DBRI to finish the command by polling the P bit
-in DBRI register 0.  I've tried to implement this in such a way
-that might make implementing a more sophisticated scheme easier.
-
-Every time a routine wants to write commands to the DBRI, it must
-first call dbri_cmdlock() and get an initial pointer into dbri->dma->cmd
-in return.  After the commands have been writen, dbri_cmdsend() is
-called with the final pointer value.
-
-Something a little more clever is required if this code is ever run
-on an SMP machine.
-
-*/
-
-static int dbri_locked = 0;
-
-static volatile s32 *dbri_cmdlock(struct dbri *dbri)
-{
-        if (dbri_locked)
-                printk("DBRI: Command buffer locked! (bug in driver)\n");
-
-        dbri_locked++;
-        return &dbri->dma->cmd[0];
-}
-
-static void dbri_process_interrupt_buffer(struct dbri *);
-
-static void dbri_cmdsend(struct dbri *dbri, volatile s32 *cmd)
-{
-	int MAXLOOPS = 1000000;
-	int maxloops = MAXLOOPS;
-	unsigned long flags;
-	volatile s32 *ptr;
-
-	for (ptr = &dbri->dma->cmd[0]; ptr < cmd; ptr++) {
-		dprintk(D_CMD, ("DBRI cmd: %lx:%08x\n",
-				(unsigned long) ptr, *ptr));
-	}
-
-	save_and_cli(flags);
-
-        dbri_locked--;
-        if (dbri_locked != 0) {
-                printk("DBRI: Command buffer improperly locked! (bug in driver)\n");
-        } else if ((cmd - &dbri->dma->cmd[0]) >= DBRI_NO_CMDS-1) {
-                printk("DBRI: Command buffer overflow! (bug in driver)\n");
-        } else {
-                *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
-		*(cmd++) = DBRI_CMD(D_WAIT, 1, 0);
-		dbri->wait_seen = 0;
-                sbus_writel(dbri->dma_dvma, dbri->regs + REG8);
-		while ((--maxloops) > 0 &&
-                       (sbus_readl(dbri->regs + REG0) & D_P))
-                        barrier();
-		if (maxloops == 0) {
-			printk("DBRI: Chip never completed command buffer\n");
-		} else {
-			while ((--maxloops) > 0 && (! dbri->wait_seen))
-				dbri_process_interrupt_buffer(dbri);
-			if (maxloops == 0) {
-				printk("DBRI: Chip never acked WAIT\n");
-			} else {
-				dprintk(D_INT, ("DBRI: Chip completed command "
-                                                "buffer (%d)\n",
-						MAXLOOPS - maxloops));
-			}
-		}
-        }
-
-	restore_flags(flags);
-}
-
-static void dbri_reset(struct dbri *dbri)
-{
-	int i;
-
-	dprintk(D_GEN, ("DBRI: reset 0:%x 2:%x 8:%x 9:%x\n",
-                        sbus_readl(dbri->regs + REG0),
-                        sbus_readl(dbri->regs + REG2),
-                        sbus_readl(dbri->regs + REG8),
-                        sbus_readl(dbri->regs + REG9)));
-
-	sbus_writel(D_R, dbri->regs + REG0); /* Soft Reset */
-	for(i = 0; (sbus_readl(dbri->regs + REG0) & D_R) && i < 64; i++)
-		udelay(10);
-}
-
-static void dbri_detach(struct dbri *dbri)
-{
-	dbri_reset(dbri);
-        free_irq(dbri->irq, dbri);
-        sbus_iounmap(dbri->regs, dbri->regs_size);
-        sbus_free_consistent(dbri->sdev, sizeof(struct dbri_dma),
-                             (void *)dbri->dma, dbri->dma_dvma);
-        kfree(dbri);
-}
-
-static void dbri_initialize(struct dbri *dbri)
-{
-	volatile s32 *cmd;
-        u32 dma_addr, tmp;
-        int n;
-
-        dbri_reset(dbri);
-
-	dprintk(D_GEN, ("DBRI: init: cmd: %p, int: %p\n",
-			&dbri->dma->cmd[0], &dbri->dma->intr[0]));
-
-	/*
-	 * Initialize the interrupt ringbuffer.
-	 */
-	for(n = 0; n < DBRI_NO_INTS-1; n++) {
-                dma_addr = dbri->dma_dvma;
-                dma_addr += dbri_dma_off(intr, ((n+1) & DBRI_INT_BLK));
-		dbri->dma->intr[n * DBRI_INT_BLK] = dma_addr;
-        }
-        dma_addr = dbri->dma_dvma + dbri_dma_off(intr, 0);
-	dbri->dma->intr[n * DBRI_INT_BLK] = dma_addr;
-	dbri->dbri_irqp = 1;
-
-        /* We should query the openprom to see what burst sizes this
-         * SBus supports.  For now, just disable all SBus bursts */
-        tmp = sbus_readl(dbri->regs + REG0);
-        tmp &= ~(D_G | D_S | D_E);
-        sbus_writel(tmp, dbri->regs + REG0);
-
-	/*
-	 * Set up the interrupt queue
-	 */
-	cmd = dbri_cmdlock(dbri);
-        dma_addr = dbri->dma_dvma + dbri_dma_off(intr, 0);
-	*(cmd++) = DBRI_CMD(D_IIQ, 0, 0);
-	*(cmd++) = dma_addr;
-
-        dbri_cmdsend(dbri, cmd);
-}
-
-
-/*
-****************************************************************************
-*************************** DBRI interrupt handler *************************
-****************************************************************************
-
-The DBRI communicates with the CPU mainly via a circular interrupt
-buffer.  When an interrupt is signaled, the CPU walks through the
-buffer and calls dbri_process_one_interrupt() for each interrupt word.
-Complicated interrupts are handled by dedicated functions (which
-appear first in this file).  Any pending interrupts can be serviced by
-calling dbri_process_interrupt_buffer(), which works even if the CPU's
-interrupts are disabled.  This function is used by dbri_cmdsend()
-to make sure we're synced up with the chip after each command sequence,
-even if we're running cli'ed.
-
-*/
-
-
-/*
- * Short data pipes transmit LSB first. The CS4215 receives MSB first. Grrr.
- * So we have to reverse the bits. Note: not all bit lengths are supported
- */
-static __u32 reverse_bytes(__u32 b, int len)
-{
-	switch(len) {
-        case 32:
-                b = ((b & 0xffff0000) >> 16) | ((b & 0x0000ffff) << 16);
-        case 16:
-                b = ((b & 0xff00ff00) >>  8) | ((b & 0x00ff00ff) <<  8);
-        case 8:
-                b = ((b & 0xf0f0f0f0) >>  4) | ((b & 0x0f0f0f0f) <<  4);
-        case 4:
-                b = ((b & 0xcccccccc) >>  2) | ((b & 0x33333333) <<  2);
-        case 2:
-                b = ((b & 0xaaaaaaaa) >>  1) | ((b & 0x55555555) <<  1);
-        case 1:
-	case 0:
-                break;
-        default:
-                printk("DBRI reverse_bytes: unsupported length\n");
-	};
-
-	return b;
-}
-
-/* transmission_complete_intr()
- *
- * Called by main interrupt handler when DBRI signals transmission complete
- * on a pipe (interrupt triggered by the B bit in a transmit descriptor).
- *
- * Walks through the pipe's list of transmit buffer descriptors, releasing
- * each one's DMA buffer (if present), flagging the descriptor available,
- * and signaling its callback routine (if present), before proceeding
- * to the next one.  Stops when the first descriptor is found without
- * TBC (Transmit Buffer Complete) set, or we've run through them all.
- */
-
-static void transmission_complete_intr(struct dbri *dbri, int pipe)
-{
-	int td;
-        int status;
-        void *buffer;
-        void (*callback)(void *, int);
-	void *callback_arg;
-
-	td = dbri->pipes[pipe].desc;
-
-	while (td >= 0) {
-                if (td >= DBRI_NO_DESCS) {
-                        printk("DBRI: invalid td on pipe %d\n", pipe);
-                        return;
-                }
-
-		status = DBRI_TD_STATUS(dbri->dma->desc[td].word4);
-
-		if (! (status & DBRI_TD_TBC)) {
-			break;
-		}
-
-		dprintk(D_INT, ("DBRI: TD %d, status 0x%02x\n", td, status));
-
-                buffer = dbri->descs[td].buffer;
-                if (buffer)
-                        sbus_unmap_single(dbri->sdev,
-                                          dbri->descs[td].buffer_dvma,
-                                          dbri->descs[td].len,
-                                          SBUS_DMA_TODEVICE);
-
-                callback = dbri->descs[td].output_callback;
-		callback_arg = dbri->descs[td].output_callback_arg;
-
-                dbri->descs[td].inuse = 0;
-
-		td = dbri->descs[td].next;
-		dbri->pipes[pipe].desc = td;
-
-		if (callback != NULL)
-			callback(callback_arg, status & 0xe);
-        }
-}
-
-static void reception_complete_intr(struct dbri *dbri, int pipe)
-{
-        int rd = dbri->pipes[pipe].desc;
-        s32 status;
-        void *buffer;
-        void (*callback)(void *, int, unsigned int);
-
-        if (rd < 0 || rd >= DBRI_NO_DESCS) {
-                printk("DBRI: invalid rd on pipe %d\n", pipe);
-                return;
-        }
-
-        dbri->descs[rd].inuse = 0;
-	dbri->pipes[pipe].desc = dbri->descs[rd].next;
-        status = dbri->dma->desc[rd].word1;
-
-        buffer = dbri->descs[rd].buffer;
-        if (buffer)
-                sbus_unmap_single(dbri->sdev,
-                                  dbri->descs[rd].buffer_dvma,
-                                  dbri->descs[rd].len,
-                                  SBUS_DMA_FROMDEVICE);
-
-        callback = dbri->descs[rd].input_callback;
-        if (callback != NULL)
-                callback(dbri->descs[rd].input_callback_arg,
-                         DBRI_RD_STATUS(status),
-                         DBRI_RD_CNT(status)-2);
-
-	dprintk(D_INT, ("DBRI: Recv RD %d, status 0x%02x, len %d\n",
-			rd, DBRI_RD_STATUS(status), DBRI_RD_CNT(status)));
-}
-
-static void dbri_process_one_interrupt(struct dbri *dbri, int x)
-{
-	int val = D_INTR_GETVAL(x);
-	int channel = D_INTR_GETCHAN(x);
-	int command = D_INTR_GETCMD(x);
-	int code = D_INTR_GETCODE(x);
-	int rval = D_INTR_GETRVAL(x);
-
-	if (channel == D_INTR_CMD) {
-		dprintk(D_INT,("DBRI: INTR: Command: %-5s  Value:%d\n",
-			       cmds[command], val));
-	} else {
-		dprintk(D_INT,("DBRI: INTR: Chan:%d Code:%d Val:%#x\n",
-			       channel, code, rval));
-	}
-
-	if (channel == D_INTR_CMD && command == D_WAIT)
-		dbri->wait_seen++;
-
-	if (code == D_INTR_SBRI) {
-		/* SBRI - BRI status change */
-		const int liu_states[] = {1, 0, 8, 3, 4, 5, 6, 7};
-
-		dbri->liu_state = liu_states[val & 0x7];
-		if (dbri->liu_callback)
-			dbri->liu_callback(dbri->liu_callback_arg);
-	}
-
-	if (code == D_INTR_BRDY)
-		reception_complete_intr(dbri, channel);
-
-	if (code == D_INTR_XCMP)
-		transmission_complete_intr(dbri, channel);
-
-	if (code == D_INTR_UNDR) {
-		/* UNDR - Transmission underrun
-		 * resend SDP command with clear pipe bit (C) set
-		 */
-		volatile s32 *cmd;
-		int pipe = channel;
-		int td = dbri->pipes[pipe].desc;
-
-		dbri->dma->desc[td].word4 = 0;
-
-		cmd = dbri_cmdlock(dbri);
-		*(cmd++) = DBRI_CMD(D_SDP, 0,
-				    dbri->pipes[pipe].sdp
-				    | D_SDP_P | D_SDP_C | D_SDP_2SAME);
-                *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, td);
-		dbri_cmdsend(dbri, cmd);
-	}
-
-	if (code == D_INTR_FXDT) {
-		/* FXDT - Fixed data change */
-		if (dbri->pipes[channel].sdp & D_SDP_MSB)
-			val = reverse_bytes(val, dbri->pipes[channel].length);
-
-		if (dbri->pipes[channel].recv_fixed_ptr)
-			*(dbri->pipes[channel].recv_fixed_ptr) = val;
-	}
-}
-
-/* dbri_process_interrupt_buffer advances through the DBRI's interrupt
- * buffer until it finds a zero word (indicating nothing more to do
- * right now).  Non-zero words require processing and are handed off
- * to dbri_process_one_interrupt AFTER advancing the pointer.  This
- * order is important since we might recurse back into this function
- * and need to make sure the pointer has been advanced first.
- */
-static void dbri_process_interrupt_buffer(struct dbri *dbri)
-{
-	s32 x;
-
-	while ((x = dbri->dma->intr[dbri->dbri_irqp]) != 0) {
-		dbri->dma->intr[dbri->dbri_irqp] = 0;
-		dbri->dbri_irqp++;
-		if (dbri->dbri_irqp == (DBRI_NO_INTS * DBRI_INT_BLK))
-			dbri->dbri_irqp = 1;
-		else if ((dbri->dbri_irqp & (DBRI_INT_BLK-1)) == 0)
-			dbri->dbri_irqp++;
-
-		tprintk(("dbri->dbri_irqp == %d\n", dbri->dbri_irqp));
-		dbri_process_one_interrupt(dbri, x);
-	}
-}
-
-static void dbri_intr(int irq, void *opaque, struct pt_regs *regs)
-{
-	struct dbri *dbri = (struct dbri *) opaque;
-	int x;
-	
-	/*
-	 * Read it, so the interrupt goes away.
-	 */
-	x = sbus_readl(dbri->regs + REG1);
-
-	dprintk(D_INT, ("DBRI: Interrupt!  (reg1=0x%08x)\n", x));
-
-	if (x & (D_MRR|D_MLE|D_LBG|D_MBE)) {
-                u32 tmp;
-
-		if(x & D_MRR) printk("DBRI: Multiple Error Ack on SBus\n");
-		if(x & D_MLE) printk("DBRI: Multiple Late Error on SBus\n");
-		if(x & D_LBG) printk("DBRI: Lost Bus Grant on SBus\n");
-		if(x & D_MBE) printk("DBRI: Burst Error on SBus\n");
-
-		/* Some of these SBus errors cause the chip's SBus circuitry
-		 * to be disabled, so just re-enable and try to keep going.
-		 *
-		 * The only one I've seen is MRR, which will be triggered
-		 * if you let a transmit pipe underrun, then try to CDP it.
-		 *
-		 * If these things persist, we should probably reset
-		 * and re-init the chip.
-		 */
-                tmp = sbus_readl(dbri->regs + REG0);
-                tmp &= ~(D_D);
-                sbus_writel(tmp, dbri->regs + REG0);
-	}
-
-#if 0
-	if (!(x & D_IR))	/* Not for us */
-		return;
-#endif
-
-	dbri_process_interrupt_buffer(dbri);
-}
-
-
-/*
-****************************************************************************
-************************** DBRI data pipe management ***********************
-****************************************************************************
-
-While DBRI control functions use the command and interrupt buffers, the
-main data path takes the form of data pipes, which can be short (command
-and interrupt driven), or long (attached to DMA buffers).  These functions
-provide a rudimentary means of setting up and managing the DBRI's pipes,
-but the calling functions have to make sure they respect the pipes' linked
-list ordering, among other things.  The transmit and receive functions
-here interface closely with the transmit and receive interrupt code.
-
-*/
-static int pipe_active(struct dbri *dbri, int pipe)
-{
-	return (dbri->pipes[pipe].desc != -1);
-}
-
-
-/* reset_pipe(dbri, pipe)
- *
- * Called on an in-use pipe to clear anything being transmitted or received
- */
-static void reset_pipe(struct dbri *dbri, int pipe)
-{
-        int sdp;
-	int desc;
-        volatile int *cmd;
-
-        if (pipe < 0 || pipe > 31) {
-                printk("DBRI: reset_pipe called with illegal pipe number\n");
-                return;
-        }
-
-        sdp = dbri->pipes[pipe].sdp;
-        if (sdp == 0) {
-                printk("DBRI: reset_pipe called on uninitialized pipe\n");
-                return;
-        }
-
-        cmd = dbri_cmdlock(dbri);
-        *(cmd++) = DBRI_CMD(D_SDP, 0, sdp | D_SDP_C | D_SDP_P);
-        *(cmd++) = 0;
-        dbri_cmdsend(dbri, cmd);
-
-	desc = dbri->pipes[pipe].desc;
-	while (desc != -1) {
-		void *buffer = dbri->descs[desc].buffer;
-		void (*output_callback) (void *, int)
-			= dbri->descs[desc].output_callback;
-		void *output_callback_arg
-			= dbri->descs[desc].output_callback_arg;
-		void (*input_callback) (void *, int, unsigned int)
-			= dbri->descs[desc].input_callback;
-		void *input_callback_arg
-			= dbri->descs[desc].input_callback_arg;
-
-		if (buffer)
-                        sbus_unmap_single(dbri->sdev,
-                                          dbri->descs[desc].buffer_dvma,
-                                          dbri->descs[desc].len,
-                                          output_callback != NULL ? SBUS_DMA_TODEVICE
-                                          : SBUS_DMA_FROMDEVICE);
-
-		dbri->descs[desc].inuse = 0;
-		desc = dbri->descs[desc].next;
-
-		if (output_callback)
-			output_callback(output_callback_arg, -1);
-
-		if (input_callback)
-			input_callback(input_callback_arg, -1, 0);
-	}
-
-        dbri->pipes[pipe].desc = -1;
-}
-
-static void setup_pipe(struct dbri *dbri, int pipe, int sdp)
-{
-        if (pipe < 0 || pipe > 31) {
-                printk("DBRI: setup_pipe called with illegal pipe number\n");
-                return;
-        }
-
-        if ((sdp & 0xf800) != sdp) {
-                printk("DBRI: setup_pipe called with strange SDP value\n");
-                /* sdp &= 0xf800; */
-        }
-
-	/* If this is a fixed receive pipe, arrange for an interrupt
-	 * every time its data changes
-	 */
-	if (D_SDP_MODE(sdp) == D_SDP_FIXED && ! (sdp & D_SDP_TO_SER))
-		sdp |= D_SDP_CHANGE;
-
-        sdp |= D_PIPE(pipe);
-        dbri->pipes[pipe].sdp = sdp;
-	dbri->pipes[pipe].desc = -1;
-
-        reset_pipe(dbri, pipe);
-}
-
-static void link_time_slot(struct dbri *dbri, int pipe,
-			   enum in_or_out direction, int basepipe,
-			   int length, int cycle)
-{
-        volatile s32 *cmd;
-        int val;
-	int prevpipe;
-	int nextpipe;
-
-	if (pipe < 0 || pipe > 31 || basepipe < 0 || basepipe > 31) {
-		printk("DBRI: link_time_slot called with illegal pipe number\n");
-		return;
-	}
-
-	if (dbri->pipes[pipe].sdp == 0 || dbri->pipes[basepipe].sdp == 0) {
-		printk("DBRI: link_time_slot called on uninitialized pipe\n");
-		return;
-	}
-
-	/* Deal with CHI special case:
-	 * "If transmission on edges 0 or 1 is desired, then cycle n
-	 *  (where n = # of bit times per frame...) must be used."
-	 *                  - DBRI data sheet, page 11
-	 */
-	if (basepipe == 16 && direction == PIPEoutput && cycle == 0)
-		cycle = dbri->chi_bpf;
-
-	if (basepipe == pipe) {
-		prevpipe = pipe;
-		nextpipe = pipe;
-        } else {
-		/* We're not initializing a new linked list (basepipe != pipe),
-		 * so run through the linked list and find where this pipe
-		 * should be sloted in, based on its cycle.  CHI confuses
-		 * things a bit, since it has a single anchor for both its
-		 * transmit and receive lists.
-                 */
-		if (basepipe == 16) {
-			if (direction == PIPEinput) {
-				prevpipe = dbri->chi_in_pipe;
-			} else {
-				prevpipe = dbri->chi_out_pipe;
-			}
-		} else {
-			prevpipe = basepipe;
-		}
-
-		nextpipe = dbri->pipes[prevpipe].nextpipe;
-
-		while (dbri->pipes[nextpipe].cycle < cycle
-			&& dbri->pipes[nextpipe].nextpipe != basepipe) {
-			prevpipe = nextpipe;
-			nextpipe = dbri->pipes[nextpipe].nextpipe;
-                }
-	}
-
-	if (prevpipe == 16) {
-		if (direction == PIPEinput) {
-			dbri->chi_in_pipe = pipe;
-		} else {
-			dbri->chi_out_pipe = pipe;
-		}
-	} else {
-		dbri->pipes[prevpipe].nextpipe = pipe;
-        }
-
-	dbri->pipes[pipe].nextpipe = nextpipe;
-	dbri->pipes[pipe].cycle = cycle;
-	dbri->pipes[pipe].length = length;
-
-	cmd = dbri_cmdlock(dbri);
-
-	if (direction == PIPEinput) {
-		val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(prevpipe) | pipe;
-		*(cmd++) = DBRI_CMD(D_DTS, 0, val);
-		*(cmd++) = D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe);
-		*(cmd++) = 0;
-	} else {
-		val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(prevpipe) | pipe;
-		*(cmd++) = DBRI_CMD(D_DTS, 0, val);
-		*(cmd++) = 0;
-		*(cmd++) = D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe);
-	}
-
-        dbri_cmdsend(dbri, cmd);
-}
-
-/* I don't use this function, so it's basically untested. */
-static void unlink_time_slot(struct dbri *dbri, int pipe,
-			     enum in_or_out direction, int prevpipe,
-			     int nextpipe)
-{
-        volatile s32 *cmd;
-        int val;
-
-        if (pipe < 0 || pipe > 31 || prevpipe < 0 || prevpipe > 31) {
-		printk("DBRI: unlink_time_slot called with illegal pipe number\n");
-                return;
-        }
-
-        cmd = dbri_cmdlock(dbri);
-
-        if (direction == PIPEinput) {
-		val = D_DTS_VI | D_DTS_DEL | D_DTS_PRVIN(prevpipe) | pipe;
-                *(cmd++) = DBRI_CMD(D_DTS, 0, val);
-		*(cmd++) = D_TS_NEXT(nextpipe);
-                *(cmd++) = 0;
-        } else {
-		val = D_DTS_VO | D_DTS_DEL | D_DTS_PRVOUT(prevpipe) | pipe;
-                *(cmd++) = DBRI_CMD(D_DTS, 0, val);
-                *(cmd++) = 0;
-		*(cmd++) = D_TS_NEXT(nextpipe);
-        }
-
-        dbri_cmdsend(dbri, cmd);
-}
-
-/* xmit_fixed() / recv_fixed()
- *
- * Transmit/receive data on a "fixed" pipe - i.e, one whose contents are not
- * expected to change much, and which we don't need to buffer.
- * The DBRI only interrupts us when the data changes (receive pipes),
- * or only changes the data when this function is called (transmit pipes).
- * Only short pipes (numbers 16-31) can be used in fixed data mode.
- *
- * These function operate on a 32-bit field, no matter how large
- * the actual time slot is.  The interrupt handler takes care of bit
- * ordering and alignment.  An 8-bit time slot will always end up
- * in the low-order 8 bits, filled either MSB-first or LSB-first,
- * depending on the settings passed to setup_pipe()
- */
-static void xmit_fixed(struct dbri *dbri, int pipe, unsigned int data)
-{
-        volatile s32 *cmd;
-
-        if (pipe < 16 || pipe > 31) {
-		printk("DBRI: xmit_fixed: Illegal pipe number\n");
-		return;
-	}
-
-	if (D_SDP_MODE(dbri->pipes[pipe].sdp) == 0) {
-		printk("DBRI: xmit_fixed: Uninitialized pipe %d\n", pipe);
-                return;
-        }
-
-        if (D_SDP_MODE(dbri->pipes[pipe].sdp) != D_SDP_FIXED) {
-		printk("DBRI: xmit_fixed: Non-fixed pipe %d\n", pipe);
-                return;
-        }
-
-        if (! (dbri->pipes[pipe].sdp & D_SDP_TO_SER)) {
-		printk("DBRI: xmit_fixed: Called on receive pipe %d\n", pipe);
-                return;
-        }
-
-        /* DBRI short pipes always transmit LSB first */
-
-        if (dbri->pipes[pipe].sdp & D_SDP_MSB)
-                data = reverse_bytes(data, dbri->pipes[pipe].length);
-
-        cmd = dbri_cmdlock(dbri);
-
-        *(cmd++) = DBRI_CMD(D_SSP, 0, pipe);
-        *(cmd++) = data;
-
-        dbri_cmdsend(dbri, cmd);
-}
-
-static void recv_fixed(struct dbri *dbri, int pipe, volatile __u32 *ptr)
-{
-        if (pipe < 16 || pipe > 31) {
-                printk("DBRI: recv_fixed called with illegal pipe number\n");
-                return;
-        }
-
-        if (D_SDP_MODE(dbri->pipes[pipe].sdp) != D_SDP_FIXED) {
-		printk("DBRI: recv_fixed called on non-fixed pipe %d\n", pipe);
-                return;
-        }
-
-        if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) {
-		printk("DBRI: recv_fixed called on transmit pipe %d\n", pipe);
-                return;
-        }
-
-        dbri->pipes[pipe].recv_fixed_ptr = ptr;
-}
-
-
-/* xmit_on_pipe() / recv_on_pipe()
- *
- * Transmit/receive data on a "long" pipe - i.e, one associated
- * with a DMA buffer.
- *
- * Only pipe numbers 0-15 can be used in this mode.
- *
- * Both functions take pointer/len arguments pointing to a data buffer,
- * and both provide callback functions (may be NULL) to notify higher
- * level code when transmission/reception is complete.
- *
- * Both work by building chains of descriptors which identify the
- * data buffers.  Buffers too large for a single descriptor will
- * be spread across multiple descriptors.
- */
-static void xmit_on_pipe(struct dbri *dbri, int pipe,
-                         void * buffer, unsigned int len,
-                         void (*callback)(void *, int), void * callback_arg)
-{
-        volatile s32 *cmd;
-	unsigned long flags;
-        int td = 0;
-        int first_td = -1;
-	int last_td = -1;
-        __u32 dvma_buffer, dvma_buffer_base;
-
-        if (pipe < 0 || pipe > 15) {
-		printk("DBRI: xmit_on_pipe: Illegal pipe number\n");
-                return;
-        }
-
-        if (dbri->pipes[pipe].sdp == 0) {
-		printk("DBRI: xmit_on_pipe: Uninitialized pipe %d\n", pipe);
-                return;
-        }
-
-        if (! (dbri->pipes[pipe].sdp & D_SDP_TO_SER)) {
-		printk("DBRI: xmit_on_pipe: Called on receive pipe %d\n",
-		       pipe);
-                return;
-        }
-
-        dvma_buffer_base = dvma_buffer = sbus_map_single(dbri->sdev, buffer, len,
-							 SBUS_DMA_TODEVICE);
-        while (len > 0) {
-                int mylen;
-
-		for (; td < DBRI_NO_DESCS; td ++) {
-                        if (! dbri->descs[td].inuse)
-                                break;
-                }
-                if (td == DBRI_NO_DESCS) {
-			printk("DBRI: xmit_on_pipe: No descriptors\n");
-                        break;
-                }
-
-                if (len > ((1 << 13) - 1)) {
-                        mylen = (1 << 13) - 1;
-                } else {
-                        mylen = len;
-                }
-
-                dbri->descs[td].inuse = 1;
-                dbri->descs[td].next = -1;
-                dbri->descs[td].buffer = NULL;
-                dbri->descs[td].output_callback = NULL;
-                dbri->descs[td].input_callback = NULL;
-
-                dbri->dma->desc[td].word1 = DBRI_TD_CNT(mylen);
-                dbri->dma->desc[td].ba = dvma_buffer;
-                dbri->dma->desc[td].nda = 0;
-                dbri->dma->desc[td].word4 = 0;
-
-                if (first_td == -1) {
-                        first_td = td;
-                } else {
-                        dbri->descs[last_td].next = td;
-                        dbri->dma->desc[last_td].nda =
-                                dbri->dma_dvma + dbri_dma_off(desc, td);
-                }
-
-                last_td = td;
-                dvma_buffer += mylen;
-                len -= mylen;
-        }
-
-	if (first_td == -1 || last_td == -1) {
-		sbus_unmap_single(dbri->sdev, dvma_buffer_base,
-				  dvma_buffer - dvma_buffer_base + len,
-				  SBUS_DMA_TODEVICE);
-                return;
-        }
-
-        dbri->dma->desc[last_td].word1 |= DBRI_TD_I | DBRI_TD_F | DBRI_TD_B;
-
-        dbri->descs[last_td].buffer = buffer;
-        dbri->descs[last_td].buffer_dvma = dvma_buffer_base;
-        dbri->descs[last_td].len = dvma_buffer - dvma_buffer_base + len;
-        dbri->descs[last_td].output_callback = callback;
-        dbri->descs[last_td].output_callback_arg = callback_arg;
-
-	for (td=first_td; td != -1; td = dbri->descs[td].next) {
-		dprintk(D_DESC, ("DBRI TD %d: %08x %08x %08x %08x\n",
-				 td,
-				 dbri->dma->desc[td].word1,
-				 dbri->dma->desc[td].ba,
-				 dbri->dma->desc[td].nda,
-				 dbri->dma->desc[td].word4));
-	}
-
-	save_and_cli(flags);
-
-	if (pipe_active(dbri, pipe)) {
-		/* Pipe is already active - find last TD in use
-		 * and link our first TD onto its end.  Then issue
-		 * a CDP command to let the DBRI know there's more data.
-		 */
-		last_td = dbri->pipes[pipe].desc;
-		while (dbri->descs[last_td].next != -1)
-			last_td = dbri->descs[last_td].next;
-
-		dbri->descs[last_td].next = first_td;
-		dbri->dma->desc[last_td].nda =
-                        dbri->dma_dvma + dbri_dma_off(desc, first_td);
-
-		cmd = dbri_cmdlock(dbri);
-		*(cmd++) = DBRI_CMD(D_CDP, 0, pipe);
-		dbri_cmdsend(dbri,cmd);
-	} else {
-		/* Pipe isn't active - issue an SDP command to start
-		 * our chain of TDs running.
-		 */
-		dbri->pipes[pipe].desc = first_td;
-		cmd = dbri_cmdlock(dbri);
-		*(cmd++) = DBRI_CMD(D_SDP, 0,
-				    dbri->pipes[pipe].sdp
-				    | D_SDP_P | D_SDP_EVERY | D_SDP_C);
-                *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, first_td);
-		dbri_cmdsend(dbri, cmd);
-	}
-
-	restore_flags(flags);
-}
-
-static void recv_on_pipe(struct dbri *dbri, int pipe,
-                         void * buffer, unsigned int len,
-                         void (*callback)(void *, int, unsigned int),
-                         void * callback_arg)
-{
-        volatile s32 *cmd;
-	int first_rd = -1;
-	int last_rd = -1;
-        int rd;
-	__u32 bus_buffer, bus_buffer_base;
-
-        if (pipe < 0 || pipe > 15) {
-		printk("DBRI: recv_on_pipe: Illegal pipe number\n");
-                return;
-        }
-
-        if (dbri->pipes[pipe].sdp == 0) {
-		printk("DBRI: recv_on_pipe: Uninitialized pipe %d\n", pipe);
-                return;
-        }
-
-        if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) {
-		printk("DBRI: recv_on_pipe: Called on transmit pipe %d\n",
-		       pipe);
-                return;
-        }
-
-        /* XXX Fix this XXX
-	 * Should be able to queue multiple buffers to receive on a pipe
-         */
-        if (dbri->pipes[pipe].desc != -1) {
-		printk("DBRI: recv_on_pipe: Called on active pipe %d\n", pipe);
-                return;
-        }
-
-        /* Make sure buffer size is multiple of four */
-        len &= ~3;
-
-        bus_buffer_base = bus_buffer = sbus_map_single(dbri->sdev, buffer, len,
-						       SBUS_DMA_FROMDEVICE);
-
-	while (len > 0) {
-		int rd, mylen;
-
-		if (len > ((1 << 13) - 4)) {
-			mylen = (1 << 13) - 4;
-		} else {
-			mylen = len;
-		}
-
-		for (rd = 0; rd < DBRI_NO_DESCS; rd ++) {
-			if (! dbri->descs[rd].inuse)
-                                break;
-		}
-		if (rd == DBRI_NO_DESCS) {
-			printk("DBRI recv_on_pipe: No descriptors\n");
-			break;
-		}
-
-		dbri->dma->desc[rd].word1 = 0;
-		dbri->dma->desc[rd].ba = bus_buffer;
-		dbri->dma->desc[rd].nda = 0;
-		dbri->dma->desc[rd].word4 = DBRI_RD_B | DBRI_RD_BCNT(mylen);
-
-		dbri->descs[rd].buffer = NULL;
-		dbri->descs[rd].len = 0;
-		dbri->descs[rd].input_callback = NULL;
-		dbri->descs[rd].output_callback = NULL;
-		dbri->descs[rd].next = -1;
-		dbri->descs[rd].inuse = 1;
-
-		if (first_rd == -1) first_rd = rd;
-		if (last_rd != -1) {
-			dbri->dma->desc[last_rd].nda =
-                                dbri->dma_dvma + dbri_dma_off(desc, rd);
-			dbri->descs[last_rd].next = rd;
-		}
-		last_rd = rd;
-
-		bus_buffer += mylen;
-		len -= mylen;
-        }
-
-	if (last_rd == -1 || first_rd == -1) {
-		sbus_unmap_single(dbri->sdev, bus_buffer_base,
-				  bus_buffer - bus_buffer_base + len,
-				  SBUS_DMA_FROMDEVICE);
-                return;
-	}
-
-	for (rd=first_rd; rd != -1; rd = dbri->descs[rd].next) {
-		dprintk(D_DESC, ("DBRI RD %d: %08x %08x %08x %08x\n",
-				 rd,
-				 dbri->dma->desc[rd].word1,
-				 dbri->dma->desc[rd].ba,
-				 dbri->dma->desc[rd].nda,
-				 dbri->dma->desc[rd].word4));
-	}
-
-	dbri->descs[last_rd].buffer = buffer;
-        dbri->descs[last_rd].buffer_dvma = bus_buffer_base;
-	dbri->descs[last_rd].len = bus_buffer - bus_buffer_base + len;
-	dbri->descs[last_rd].input_callback = callback;
-	dbri->descs[last_rd].input_callback_arg = callback_arg;
-
-	dbri->pipes[pipe].desc = first_rd;
-
-        cmd = dbri_cmdlock(dbri);
-
-	*(cmd++) = DBRI_CMD(D_SDP, 0, dbri->pipes[pipe].sdp | D_SDP_P | D_SDP_C);
-        *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, first_rd);
-
-        dbri_cmdsend(dbri, cmd);
-}
-
-
-/*
-****************************************************************************
-************************** DBRI - CHI interface ****************************
-****************************************************************************
-
-The CHI is a four-wire (clock, frame sync, data in, data out) time-division
-multiplexed serial interface which the DBRI can operate in either master
-(give clock/frame sync) or slave (take clock/frame sync) mode.
-
-*/
-
-enum master_or_slave { CHImaster, CHIslave };
-
-static void reset_chi(struct dbri *dbri, enum master_or_slave master_or_slave,
-		      int bits_per_frame)
-{
-	volatile s32 *cmd;
-	int val;
-	static int chi_initialized = 0;
-
-	if (!chi_initialized) {
-
-		cmd = dbri_cmdlock(dbri);
-
-		/* Set CHI Anchor: Pipe 16 */
-
-		val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(16) | D_PIPE(16);
-		*(cmd++) = DBRI_CMD(D_DTS, 0, val);
-		*(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16);
-		*(cmd++) = 0;
-
-		val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(16) | D_PIPE(16);
-		*(cmd++) = DBRI_CMD(D_DTS, 0, val);
-		*(cmd++) = 0;
-		*(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16);
-
-		dbri->pipes[16].sdp = 1;
-		dbri->pipes[16].nextpipe = 16;
-		dbri->chi_in_pipe = 16;
-		dbri->chi_out_pipe = 16;
-
-#if 0
-		chi_initialized ++;
-#endif
-	} else {
-		int pipe;
-
-		for (pipe = dbri->chi_in_pipe;
-		     pipe != 16;
-		     pipe = dbri->pipes[pipe].nextpipe) {
-			unlink_time_slot(dbri, pipe, PIPEinput,
-					 16, dbri->pipes[pipe].nextpipe);
-		}
-		for (pipe = dbri->chi_out_pipe;
-		     pipe != 16;
-		     pipe = dbri->pipes[pipe].nextpipe) {
-			unlink_time_slot(dbri, pipe, PIPEoutput,
-					 16, dbri->pipes[pipe].nextpipe);
-		}
-
-		dbri->chi_in_pipe = 16;
-		dbri->chi_out_pipe = 16;
-
-		cmd = dbri_cmdlock(dbri);
-	}
-
-	if (master_or_slave == CHIslave) {
-		/* Setup DBRI for CHI Slave - receive clock, frame sync (FS)
-		 *
-		 * CHICM  = 0 (slave mode, 8 kHz frame rate)
-		 * IR     = give immediate CHI status interrupt
-		 * EN     = give CHI status interrupt upon change
-		 */
-		*(cmd++) = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(0));
-	} else {
-		/* Setup DBRI for CHI Master - generate clock, FS
-		 *
-		 * BPF				=  bits per 8 kHz frame
-		 * 12.288 MHz / CHICM_divisor	= clock rate
-		 * FD  =  1 - drive CHIFS on rising edge of CHICK
-		 */
-		int clockrate = bits_per_frame * 8;
-		int divisor   = 12288 / clockrate;
-
-		if (divisor > 255 || divisor * clockrate != 12288)
-			printk("DBRI: illegal bits_per_frame in setup_chi\n");
-
-		*(cmd++) = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(divisor) | D_CHI_FD
-				    | D_CHI_BPF(bits_per_frame));
-	}
-
-	dbri->chi_bpf = bits_per_frame;
-
-	/* CHI Data Mode
-	 *
-	 * RCE   =  0 - receive on falling edge of CHICK
-	 * XCE   =  1 - transmit on rising edge of CHICK
-	 * XEN   =  1 - enable transmitter
-	 * REN   =  1 - enable receiver
-	 */
-
-	*(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
-	*(cmd++) = DBRI_CMD(D_CDM, 0, D_CDM_XCE|D_CDM_XEN|D_CDM_REN);
-
-	dbri_cmdsend(dbri, cmd);
-}
-
-/*
-****************************************************************************
-*********************** CS4215 audio codec management **********************
-****************************************************************************
-
-In the standard SPARC audio configuration, the CS4215 codec is attached
-to the DBRI via the CHI interface and few of the DBRI's PIO pins.
-
-*/
-static void mmcodec_default(struct cs4215 *mm)
-{
-	/*
-	 * No action, memory resetting only.
-	 *
-	 * Data Time Slot 5-8
-	 * Speaker,Line and Headphone enable. Gain set to the half.
-	 * Input is mike.
-	 */
-	mm->data[0] = CS4215_LO(0x20) | CS4215_HE|CS4215_LE;
-	mm->data[1] = CS4215_RO(0x20) | CS4215_SE;
-	mm->data[2] = CS4215_LG( 0x8) | CS4215_IS | CS4215_PIO0 | CS4215_PIO1;
-	mm->data[3] = CS4215_RG( 0x8) | CS4215_MA(0xf);
-
-	/*
-	 * Control Time Slot 1-4
-	 * 0: Default I/O voltage scale
-	 * 1: 8 bit ulaw, 8kHz, mono, high pass filter disabled
-	 * 2: Serial enable, CHI master, 128 bits per frame, clock 1
-	 * 3: Tests disabled
-	 */
-	mm->ctrl[0] = CS4215_RSRVD_1 | CS4215_MLB;
-	mm->ctrl[1] = CS4215_DFR_ULAW | CS4215_FREQ[0].csval;
-	mm->ctrl[2] = CS4215_XCLK |
-			CS4215_BSEL_128 | CS4215_FREQ[0].xtal;
-	mm->ctrl[3] = 0;
-}
-
-static void mmcodec_setup_pipes(struct dbri *dbri)
-{
-	/*
-	 * Data mode:
-	 * Pipe  4: Send timeslots 1-4 (audio data)
-	 * Pipe 20: Send timeslots 5-8 (part of ctrl data)
-	 * Pipe  6: Receive timeslots 1-4 (audio data)
-	 * Pipe 21: Receive timeslots 6-7. We can only receive 20 bits via
-	 *          interrupt, and the rest of the data (slot 5 and 8) is
-	 *	    not relevant for us (only for doublechecking).
-	 *
-	 * Control mode:
-	 * Pipe 17: Send timeslots 1-4 (slots 5-8 are readonly)
-	 * Pipe 18: Receive timeslot 1 (clb).
-	 * Pipe 19: Receive timeslot 7 (version). 
-	 */
-
-	setup_pipe(dbri,  4, D_SDP_MEM   | D_SDP_TO_SER | D_SDP_MSB);
-	setup_pipe(dbri, 20, D_SDP_FIXED | D_SDP_TO_SER | D_SDP_MSB);
-	setup_pipe(dbri,  6, D_SDP_MEM   | D_SDP_FROM_SER | D_SDP_MSB);
-	setup_pipe(dbri, 21, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB);
-
-	setup_pipe(dbri, 17, D_SDP_FIXED | D_SDP_TO_SER   | D_SDP_MSB);
-	setup_pipe(dbri, 18, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB);
-	setup_pipe(dbri, 19, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB);
-
-	dbri->mm.status = 0;
-
-	recv_fixed(dbri, 18, & dbri->mm.status);
-	recv_fixed(dbri, 19, & dbri->mm.version);
-}
-
-static void mmcodec_setgain(struct dbri *dbri, int muted)
-{
-	if (muted || dbri->perchip_info.output_muted) {
-		dbri->mm.data[0] = 63;
-		dbri->mm.data[1] = 63;
-	} else {
-		int left_gain = (dbri->perchip_info.play.gain / 4) % 64;
-		int right_gain = (dbri->perchip_info.play.gain / 4) % 64;
-		int outport = dbri->perchip_info.play.port;
-
-		if (dbri->perchip_info.play.balance < AUDIO_MID_BALANCE) {
-			right_gain *= dbri->perchip_info.play.balance;
-			right_gain /= AUDIO_MID_BALANCE;
-		} else {
-			left_gain *= AUDIO_RIGHT_BALANCE
-				- dbri->perchip_info.play.balance;
-			left_gain /= AUDIO_MID_BALANCE;
-		}
-
-		dprintk(D_MM, ("DBRI: Setting codec gain left: %d right: %d\n",
-			       left_gain, right_gain));
-
-		dbri->mm.data[0] = (63 - left_gain);
-		if (outport & AUDIO_HEADPHONE) dbri->mm.data[0] |= CS4215_HE;
-		if (outport & AUDIO_LINE_OUT)  dbri->mm.data[0] |= CS4215_LE;
-		dbri->mm.data[1] = (63 - right_gain);
-		if (outport & AUDIO_SPEAKER)   dbri->mm.data[1] |= CS4215_SE;
-	}
-
-	xmit_fixed(dbri, 20, *(int *)dbri->mm.data);
-}
-
-static void mmcodec_init_data(struct dbri *dbri)
-{
-	int data_width;
-        u32 tmp;
-
-	/*
-	 * Data mode:
-	 * Pipe  4: Send timeslots 1-4 (audio data)
-	 * Pipe 20: Send timeslots 5-8 (part of ctrl data)
-	 * Pipe  6: Receive timeslots 1-4 (audio data)
-	 * Pipe 21: Receive timeslots 6-7. We can only receive 20 bits via
-	 *          interrupt, and the rest of the data (slot 5 and 8) is
-	 *	    not relevant for us (only for doublechecking).
-         *
-         * Just like in control mode, the time slots are all offset by eight
-         * bits.  The CS4215, it seems, observes TSIN (the delayed signal)
-         * even if it's the CHI master.  Don't ask me...
-	 */
-        tmp = sbus_readl(dbri->regs + REG0);
-        tmp &= ~(D_C);	/* Disable CHI */
-        sbus_writel(tmp, dbri->regs + REG0);
-
-        /* Switch CS4215 to data mode - set PIO3 to 1 */
-        sbus_writel(D_ENPIO | D_PIO1 | D_PIO3 |
-                    (dbri->mm.onboard ? D_PIO0 : D_PIO2),
-                    dbri->regs + REG2);
-
-	reset_chi(dbri, CHIslave, 128);
-
-	/* Note: this next doesn't work for 8-bit stereo, because the two
-	 * channels would be on timeslots 1 and 3, with 2 and 4 idle.
-	 * (See CS4215 datasheet Fig 15)
-	 *
-	 * DBRI non-contiguous mode would be required to make this work.
-	 */
-
-	data_width = dbri->perchip_info.play.channels
-		* dbri->perchip_info.play.precision;
-
-	link_time_slot(dbri, 20, PIPEoutput, 16,
-		       32, dbri->mm.offset + 32);
-	link_time_slot(dbri,  4, PIPEoutput, 16,
-		       data_width, dbri->mm.offset);
-	link_time_slot(dbri,  6, PIPEinput, 16,
-		       data_width, dbri->mm.offset);
-	link_time_slot(dbri, 21, PIPEinput, 16,
-		       16, dbri->mm.offset + 40);
-
-	mmcodec_setgain(dbri, 0);
-
-        tmp = sbus_readl(dbri->regs + REG0);
-	tmp |= D_C;	/* Enable CHI */
-        sbus_writel(tmp, dbri->regs + REG0);
-}
-
-/*
- * Send the control information (i.e. audio format)
- */
-static int mmcodec_setctrl(struct dbri *dbri)
-{
-	int i, val;
-        u32 tmp;
-
-	/* XXX - let the CPU do something useful during these delays */
-
-	/* Temporarily mute outputs, and wait 1/8000 sec (125 us)
-	 * to make sure this takes.  This avoids clicking noises.
-	 */
-
-	mmcodec_setgain(dbri, 1);
-	udelay(125);
-
-	/*
-	 * Enable Control mode: Set DBRI's PIO3 (4215's D/~C) to 0, then wait
-	 * 12 cycles <= 12/(5512.5*64) sec = 34.01 usec
-	 */
-	val = D_ENPIO | D_PIO1 | (dbri->mm.onboard ? D_PIO0 : D_PIO2);
-	sbus_writel(val, dbri->regs + REG2);
-	udelay(34);
-
-        /* In Control mode, the CS4215 is a slave device, so the DBRI must
-         * operate as CHI master, supplying clocking and frame synchronization.
-         *
-         * In Data mode, however, the CS4215 must be CHI master to insure
-         * that its data stream is synchronous with its codec.
-         *
-         * The upshot of all this?  We start by putting the DBRI into master
-         * mode, program the CS4215 in Control mode, then switch the CS4215
-         * into Data mode and put the DBRI into slave mode.  Various timing
-         * requirements must be observed along the way.
-         *
-         * Oh, and one more thing, on a SPARCStation 20 (and maybe
-         * others?), the addressing of the CS4215's time slots is
-         * offset by eight bits, so we add eight to all the "cycle"
-         * values in the Define Time Slot (DTS) commands.  This is
-         * done in hardware by a TI 248 that delays the DBRI->4215
-         * frame sync signal by eight clock cycles.  Anybody know why?
-         */
-        tmp = sbus_readl(dbri->regs + REG0);
-	tmp &= ~D_C;	/* Disable CHI */
-        sbus_writel(tmp, dbri->regs + REG0);
-
-        reset_chi(dbri, CHImaster, 128);
-
-	/*
-	 * Control mode:
-	 * Pipe 17: Send timeslots 1-4 (slots 5-8 are readonly)
-	 * Pipe 18: Receive timeslot 1 (clb).
-	 * Pipe 19: Receive timeslot 7 (version). 
-	 */
-
-	link_time_slot(dbri, 17, PIPEoutput, 16,
-		       32, dbri->mm.offset);
-	link_time_slot(dbri, 18, PIPEinput, 16,
-		       8, dbri->mm.offset);
-	link_time_slot(dbri, 19, PIPEinput, 16,
-		       8, dbri->mm.offset + 48);
-
-        /* Wait for the chip to echo back CLB (Control Latch Bit) as zero */
-
-	dbri->mm.ctrl[0] &= ~CS4215_CLB;
-        xmit_fixed(dbri, 17, *(int *)dbri->mm.ctrl);
-
-        tmp = sbus_readl(dbri->regs + REG0);
-        tmp |= D_C;	/* Enable CHI */
-        sbus_writel(tmp, dbri->regs + REG0);
-
-	i = 64;
-	while (((dbri->mm.status & 0xe4) != 0x20) && --i)
-                udelay(125);
-        if (i == 0) {
-		dprintk(D_MM, ("DBRI: CS4215 didn't respond to CLB (0x%02x)\n",
-			       dbri->mm.status));
-		return -1;
-        }
-
-        /* Terminate CS4215 control mode - data sheet says
-         * "Set CLB=1 and send two more frames of valid control info"
-         */
-	dbri->mm.ctrl[0] |= CS4215_CLB;
-        xmit_fixed(dbri, 17, *(int *)dbri->mm.ctrl);
-
-        /* Two frames of control info @ 8kHz frame rate = 250 us delay */
-        udelay(250);
-
-	mmcodec_setgain(dbri, 0);
-
-	return 0;
-}
-
-static int mmcodec_init(struct sparcaudio_driver *drv)
-{
-	struct dbri *dbri = (struct dbri *) drv->private;
-	u32 reg2 = sbus_readl(dbri->regs + REG2);
-
-	/* Look for the cs4215 chips */
-	if(reg2 & D_PIO2) {
-		dprintk(D_MM, ("DBRI: Onboard CS4215 detected\n"));
-		dbri->mm.onboard = 1;
-	}
-	if(reg2 & D_PIO0) {
-		dprintk(D_MM, ("DBRI: Speakerbox detected\n"));
-		dbri->mm.onboard = 0;
-	}
-	
-
-	/* Using the Speakerbox, if both are attached.  */
-	if((reg2 & D_PIO2) && (reg2 & D_PIO0)) {
-		printk("DBRI: Using speakerbox / ignoring onboard mmcodec.\n");
-		sbus_writel(D_ENPIO2, dbri->regs + REG2);
-		dbri->mm.onboard = 0;
-	}
-
-	if(!(reg2 & (D_PIO0|D_PIO2))) {
-		printk("DBRI: no mmcodec found.\n");
-		return -EIO;
-	}
-
-
-	mmcodec_setup_pipes(dbri);
-
-	mmcodec_default(&dbri->mm);
-
-	dbri->mm.version = 0xff;
-	dbri->mm.offset = dbri->mm.onboard ? 0 : 8;
-	if (mmcodec_setctrl(dbri) == -1 || dbri->mm.version == 0xff) {
-		dprintk(D_MM, ("DBRI: CS4215 failed probe at offset %d\n",
-			       dbri->mm.offset));
-		return -EIO;
-	}
-
-	dprintk(D_MM, ("DBRI: Found CS4215 at offset %d\n", dbri->mm.offset));
-
-	dbri->perchip_info.play.channels = 1;
-	dbri->perchip_info.play.precision = 8;
-	dbri->perchip_info.play.gain = (AUDIO_MAX_GAIN * 7 / 10);  /* 70% */
-	dbri->perchip_info.play.balance = AUDIO_MID_BALANCE;
-	dbri->perchip_info.play.port = dbri->perchip_info.play.avail_ports = 
-		AUDIO_SPEAKER | AUDIO_HEADPHONE | AUDIO_LINE_OUT;
-	dbri->perchip_info.record.port = AUDIO_MICROPHONE;
-	dbri->perchip_info.record.avail_ports =
-		AUDIO_MICROPHONE | AUDIO_LINE_IN;
-
-	mmcodec_init_data(dbri);
-
-	return 0;
-}
-
-
-/*
-****************************************************************************
-******************** Interface with sparcaudio midlevel ********************
-****************************************************************************
-
-The sparcaudio midlevel is contained in the file audio.c.  It interfaces
-to the user process and performs buffering, intercepts SunOS-style ioctl's,
-etc.  It interfaces to a abstract audio device via a struct sparcaudio_driver.
-This code presents such an interface for the DBRI with an attached CS4215.
-All our routines are defined, and then comes our struct sparcaudio_driver.
-
-*/
-
-/******************* sparcaudio midlevel - audio output *******************/
-static void dbri_audio_output_callback(void * callback_arg, int status)
-{
-        struct sparcaudio_driver *drv = callback_arg;
-
-	if (status != -1)
-		sparcaudio_output_done(drv, 1);
-}
-
-static void dbri_start_output(struct sparcaudio_driver *drv,
-                              __u8 * buffer, unsigned long count)
-{
-	struct dbri *dbri = (struct dbri *) drv->private;
-
-	dprintk(D_USR, ("DBRI: start audio output buf=%p/%ld\n",
-			buffer, count));
-
-        /* Pipe 4 is audio transmit */
-	xmit_on_pipe(dbri, 4, buffer, count,
-		     &dbri_audio_output_callback, drv);
-
-#if 0
-	/* Notify midlevel that we're a DMA-capable driver that
-	 * can accept another buffer immediately.  We should probably
-	 * check that we've got enough resources (i.e, descriptors)
-	 * available before doing this, but the default midlevel
-	 * settings only buffer 64KB, which we can handle with 16
-	 * of our DBRI_NO_DESCS (64) descriptors.
-	 *
-	 * This code is #ifdef'ed out because it's caused me more
-	 * problems than it solved.  It'd be nice to provide the
-	 * DBRI with a chain of buffers, but the midlevel code is
-	 * so tricky that I really don't want to deal with it.
-	 */
-
-	sparcaudio_output_done(drv, 2);
-#endif
-}
-
-static void dbri_stop_output(struct sparcaudio_driver *drv)
-{
-	struct dbri *dbri = (struct dbri *) drv->private;
-
-        reset_pipe(dbri, 4);
-}
-
-/******************* sparcaudio midlevel - audio input ********************/
-
-static void dbri_audio_input_callback(void * callback_arg, int status,
-				      unsigned int len)
-{
-	struct sparcaudio_driver * drv =
-		(struct sparcaudio_driver *) callback_arg;
-
-	if (status != -1)
-		sparcaudio_input_done(drv, 3);
-}
-
-static void dbri_start_input(struct sparcaudio_driver *drv,
-                             __u8 * buffer, unsigned long len)
-{
-	struct dbri *dbri = (struct dbri *) drv->private;
-
-	/* Pipe 6 is audio receive */
-	recv_on_pipe(dbri, 6, buffer, len,
-		     &dbri_audio_input_callback, (void *)drv);
-	dprintk(D_USR, ("DBRI: start audio input buf=%p/%ld\n",
-			buffer, len));
-}
-
-static void dbri_stop_input(struct sparcaudio_driver *drv)
-{
-	struct dbri *dbri = (struct dbri *) drv->private;
-
-	reset_pipe(dbri, 6);
-}
-
-/******************* sparcaudio midlevel - volume & balance ***************/
-
-static int dbri_set_output_volume(struct sparcaudio_driver *drv, int volume)
-{
-	struct dbri *dbri = (struct dbri *) drv->private;
-
-	dbri->perchip_info.play.gain = volume;
-	mmcodec_setgain(dbri, 0);
-
-        return 0;
-}
-
-static int dbri_get_output_volume(struct sparcaudio_driver *drv)
-{
-	struct dbri *dbri = (struct dbri *) drv->private;
-
-	return dbri->perchip_info.play.gain;
-}
-
-static int dbri_set_input_volume(struct sparcaudio_driver *drv, int volume)
-{
-        return 0;
-}
-
-static int dbri_get_input_volume(struct sparcaudio_driver *drv)
-{
-        return 0;
-}
-
-static int dbri_set_monitor_volume(struct sparcaudio_driver *drv, int volume)
-{
-        return 0;
-}
-
-static int dbri_get_monitor_volume(struct sparcaudio_driver *drv)
-{
-        return 0;
-}
-
-static int dbri_set_output_balance(struct sparcaudio_driver *drv, int balance)
-{
-	struct dbri *dbri = (struct dbri *) drv->private;
-
-	dbri->perchip_info.play.balance = balance;
-	mmcodec_setgain(dbri, 0);
-
-        return 0;
-}
-
-static int dbri_get_output_balance(struct sparcaudio_driver *drv)
-{
-	struct dbri *dbri = (struct dbri *) drv->private;
-
-	return dbri->perchip_info.play.balance;
-}
-
-static int dbri_set_input_balance(struct sparcaudio_driver *drv, int balance)
-{
-        return 0;
-}
-
-static int dbri_get_input_balance(struct sparcaudio_driver *drv)
-{
-        return 0;
-}
-
-static int dbri_set_output_muted(struct sparcaudio_driver *drv, int mute)
-{
-	struct dbri *dbri = (struct dbri *) drv->private;
-
-	dbri->perchip_info.output_muted = mute;
-
-	return 0;
-}
-
-static int dbri_get_output_muted(struct sparcaudio_driver *drv)
-{
-	struct dbri *dbri = (struct dbri *) drv->private;
-
-	return dbri->perchip_info.output_muted;
-}
-
-/******************* sparcaudio midlevel - encoding format ****************/
-
-static int dbri_set_output_channels(struct sparcaudio_driver *drv, int chan)
-{
-	struct dbri *dbri = (struct dbri *) drv->private;
-
-	switch (chan) {
-	case 0:
-		return 0;
-	case 1:
-		dbri->mm.ctrl[1] &= ~CS4215_DFR_STEREO;
-		break;
-	case 2:
-		dbri->mm.ctrl[1] |= CS4215_DFR_STEREO;
-		break;
-	default:
-		return -1;
-	}
-
-	dbri->perchip_info.play.channels = chan;
-	mmcodec_setctrl(dbri);
-	mmcodec_init_data(dbri);
-        return 0;
-}
-
-static int dbri_get_output_channels(struct sparcaudio_driver *drv)
-{
-	struct dbri *dbri = (struct dbri *) drv->private;
-
-	return dbri->perchip_info.play.channels;
-}
-
-static int dbri_set_input_channels(struct sparcaudio_driver *drv, int chan)
-{
-	return dbri_set_output_channels(drv, chan);
-}
-
-static int dbri_get_input_channels(struct sparcaudio_driver *drv)
-{
-	return dbri_get_output_channels(drv);
-}
-
-static int dbri_set_output_precision(struct sparcaudio_driver *drv, int prec)
-{
-	return 0;
-}
-
-static int dbri_get_output_precision(struct sparcaudio_driver *drv)
-{
-	struct dbri *dbri = (struct dbri *) drv->private;
-
-	return dbri->perchip_info.play.precision;
-}
-
-static int dbri_set_input_precision(struct sparcaudio_driver *drv, int prec)
-{
-	return 0;
-}
-
-static int dbri_get_input_precision(struct sparcaudio_driver *drv)
-{
-	struct dbri *dbri = (struct dbri *) drv->private;
-
-	return dbri->perchip_info.play.precision;
-}
-
-static int dbri_set_output_encoding(struct sparcaudio_driver *drv, int enc)
-{
-	struct dbri *dbri = (struct dbri *) drv->private;
-
-	/* For ULAW and ALAW, audio.c enforces precision = 8,
-	 * for LINEAR, precision must be 16
-	 */
-
-	switch (enc) {
-	case AUDIO_ENCODING_NONE:
-		return 0;
-	case AUDIO_ENCODING_ULAW:
-		dbri->mm.ctrl[1] &= ~3;
-		dbri->mm.ctrl[1] |= CS4215_DFR_ULAW;
-		dbri->perchip_info.play.encoding = enc;
-		dbri->perchip_info.play.precision = 8;
-		break;
-	case AUDIO_ENCODING_ALAW:
-		dbri->mm.ctrl[1] &= ~3;
-		dbri->mm.ctrl[1] |= CS4215_DFR_ALAW;
-		dbri->perchip_info.play.encoding = enc;
-		dbri->perchip_info.play.precision = 8;
-		break;
-	case AUDIO_ENCODING_LINEAR:
-		dbri->mm.ctrl[1] &= ~3;
-		dbri->mm.ctrl[1] |= CS4215_DFR_LINEAR16;
-		dbri->perchip_info.play.encoding = enc;
-		dbri->perchip_info.play.precision = 16;
-		break;
-	default:
-		return -1;
-	};
-
-	mmcodec_setctrl(dbri);
-	mmcodec_init_data(dbri);
-        return 0;
-}
-
-static int dbri_get_output_encoding(struct sparcaudio_driver *drv)
-{
-	struct dbri *dbri = (struct dbri *) drv->private;
-
-	return dbri->perchip_info.play.encoding;
-}
-
-static int dbri_set_input_encoding(struct sparcaudio_driver *drv, int enc)
-{
-	return dbri_set_output_encoding(drv, enc);
-}
-
-static int dbri_get_input_encoding(struct sparcaudio_driver *drv)
-{
-	return dbri_get_output_encoding(drv);
-}
-
-static int dbri_set_output_rate(struct sparcaudio_driver *drv, int rate)
-{
-	struct dbri *dbri = (struct dbri *) drv->private;
-	int i;
-
-	if (rate == 0)
-		return 0;
-
-	for (i=0; CS4215_FREQ[i].freq; i++) {
-		if (CS4215_FREQ[i].freq == rate)
-                        break;
-	}
-
-	if (CS4215_FREQ[i].freq == 0)
-		return -1;
-
-	dbri->mm.ctrl[1] &= ~ 0x38;
-	dbri->mm.ctrl[1] |= CS4215_FREQ[i].csval;
-	dbri->mm.ctrl[2] &= ~ 0x70;
-	dbri->mm.ctrl[2] |= CS4215_FREQ[i].xtal;
-
-	dbri->perchip_info.play.sample_rate = rate;
-
-	mmcodec_setctrl(dbri);
-	mmcodec_init_data(dbri);
-        return 0;
-}
-
-static int dbri_get_output_rate(struct sparcaudio_driver *drv)
-{
-	struct dbri *dbri = (struct dbri *) drv->private;
-
-	return dbri->perchip_info.play.sample_rate;
-}
-
-static int dbri_set_input_rate(struct sparcaudio_driver *drv, int rate)
-{
-	return dbri_set_output_rate(drv, rate);
-}
-
-static int dbri_get_input_rate(struct sparcaudio_driver *drv)
-{
-	return dbri_get_output_rate(drv);
-}
-
-/******************* sparcaudio midlevel - ports ***********************/
-
-static int dbri_set_output_port(struct sparcaudio_driver *drv, int port)
-{
-	struct dbri *dbri = (struct dbri *) drv->private;
-
-	port &= dbri->perchip_info.play.avail_ports;
-	dbri->perchip_info.play.port = port;
-	mmcodec_setgain(dbri, 0);
-
-	return 0;
-}
-
-static int dbri_get_output_port(struct sparcaudio_driver *drv)
-{
-	struct dbri *dbri = (struct dbri *) drv->private;
-
-	return dbri->perchip_info.play.port;
-}
-
-static int dbri_set_input_port(struct sparcaudio_driver *drv, int port)
-{
-	struct dbri *dbri = (struct dbri *) drv->private;
-
-	port &= dbri->perchip_info.record.avail_ports;
-	dbri->perchip_info.record.port = port;
-	mmcodec_setgain(dbri, 0);
-
-	return 0;
-}
-
-static int dbri_get_input_port(struct sparcaudio_driver *drv)
-{
-	struct dbri *dbri = (struct dbri *) drv->private;
-
-	return dbri->perchip_info.record.port;
-}
-
-static int dbri_get_output_ports(struct sparcaudio_driver *drv)
-{
-	struct dbri *dbri = (struct dbri *) drv->private;
-
-	return dbri->perchip_info.play.avail_ports;
-}
-
-static int dbri_get_input_ports(struct sparcaudio_driver *drv)
-{
-	struct dbri *dbri = (struct dbri *) drv->private;
-
-	return dbri->perchip_info.record.avail_ports;
-}
-
-/******************* sparcaudio midlevel - driver ID ********************/
-
-static void dbri_audio_getdev(struct sparcaudio_driver *drv,
-			      audio_device_t *audinfo)
-{
-	struct dbri *dbri = (struct dbri *) drv->private;
-
-	strncpy(audinfo->name, "SUNW,DBRI", sizeof(audinfo->name) - 1);
-
-	audinfo->version[0] = dbri->dbri_version;
-	audinfo->version[1] = '\0';
-
-	strncpy(audinfo->config, "onboard1", sizeof(audinfo->config) - 1);
-}
-
-static int dbri_sunaudio_getdev_sunos(struct sparcaudio_driver *drv)
-{
-	return AUDIO_DEV_CODEC;
-}
-
-/******************* sparcaudio midlevel - open & close ******************/
-
-static int dbri_open(struct inode * inode, struct file * file,
-		     struct sparcaudio_driver *drv)
-{
-	MOD_INC_USE_COUNT;
-
-	return 0;
-}
-
-static void dbri_release(struct inode * inode, struct file * file,
-			 struct sparcaudio_driver *drv)
-{
-	MOD_DEC_USE_COUNT;
-}
-
-static int dbri_ioctl(struct inode * inode, struct file * file,
-		      unsigned int x, unsigned long y,
-		      struct sparcaudio_driver *drv)
-{
-	return -EINVAL;
-}
-
-/*********** sparcaudio midlevel - struct sparcaudio_driver ************/
-
-static struct sparcaudio_operations dbri_ops = {
-	dbri_open,
-	dbri_release,
-	dbri_ioctl,
-	dbri_start_output,
-	dbri_stop_output,
-	dbri_start_input,
-        dbri_stop_input,
-	dbri_audio_getdev,
-	dbri_set_output_volume,
-	dbri_get_output_volume,
-	dbri_set_input_volume,
-	dbri_get_input_volume,
-	dbri_set_monitor_volume,
-	dbri_get_monitor_volume,
-	dbri_set_output_balance,
-	dbri_get_output_balance,
-	dbri_set_input_balance,
-	dbri_get_input_balance,
-	dbri_set_output_channels,
-	dbri_get_output_channels,
-	dbri_set_input_channels,
-	dbri_get_input_channels,
-	dbri_set_output_precision,
-	dbri_get_output_precision,
-	dbri_set_input_precision,
-	dbri_get_input_precision,
-	dbri_set_output_port,
-	dbri_get_output_port,
-	dbri_set_input_port,
-	dbri_get_input_port,
-	dbri_set_output_encoding,
-	dbri_get_output_encoding,
-	dbri_set_input_encoding,
-	dbri_get_input_encoding,
-	dbri_set_output_rate,
-	dbri_get_output_rate,
-	dbri_set_input_rate,
-	dbri_get_input_rate,
-	dbri_sunaudio_getdev_sunos,
-	dbri_get_output_ports,
-	dbri_get_input_ports,
-	dbri_set_output_muted,
-	dbri_get_output_muted,
-};
-
-
-/*
-****************************************************************************
-************************** ISDN (Hisax) Interface **************************
-****************************************************************************
-*/
-void dbri_isdn_init(struct dbri *dbri)
-{
-        /* Pipe  0: Receive D channel
-         * Pipe  8: Receive B1 channel
-         * Pipe  9: Receive B2 channel
-         * Pipe  1: Transmit D channel
-         * Pipe 10: Transmit B1 channel
-         * Pipe 11: Transmit B2 channel
-         */
-
-        setup_pipe(dbri, 0, D_SDP_HDLC | D_SDP_FROM_SER | D_SDP_LSB);
-        setup_pipe(dbri, 8, D_SDP_HDLC | D_SDP_FROM_SER | D_SDP_LSB);
-        setup_pipe(dbri, 9, D_SDP_HDLC | D_SDP_FROM_SER | D_SDP_LSB);
-
-        setup_pipe(dbri, 1, D_SDP_HDLC_D | D_SDP_TO_SER | D_SDP_LSB);
-        setup_pipe(dbri,10, D_SDP_HDLC | D_SDP_TO_SER | D_SDP_LSB);
-        setup_pipe(dbri,11, D_SDP_HDLC | D_SDP_TO_SER | D_SDP_LSB);
-
-        link_time_slot(dbri, 0, PIPEinput, 0, 2, 17);
-	link_time_slot(dbri, 8, PIPEinput, 0, 8, 0);
-	link_time_slot(dbri, 9, PIPEinput, 8, 8, 8);
-
-        link_time_slot(dbri,  1, PIPEoutput,  1, 2, 17);
-        link_time_slot(dbri, 10, PIPEoutput,  1, 8, 0);
-        link_time_slot(dbri, 11, PIPEoutput, 10, 8, 8);
-}
-
-int dbri_get_irqnum(int dev)
-{
-       struct dbri *dbri;
-
-       if (dev >= num_drivers)
-               return(0);
-
-       dbri = (struct dbri *) drivers[dev].private;
-
-       tprintk(("dbri_get_irqnum()\n"));
-
-        /* On the sparc, the cpu's irq number is only part of the "irq" */
-       return (dbri->irq & NR_IRQS);
-}
-
-int dbri_get_liu_state(int dev)
-{
-       struct dbri *dbri;
-
-       if (dev >= num_drivers)
-               return(0);
-
-       dbri = (struct dbri *) drivers[dev].private;
-
-       tprintk(("dbri_get_liu_state() returns %d\n", dbri->liu_state));
-
-       return dbri->liu_state;
-}
-
-void dbri_liu_activate(int dev, int priority);
-
-void dbri_liu_init(int dev, void (*callback)(void *), void *callback_arg)
-{
-       struct dbri *dbri;
-
-       if (dev >= num_drivers)
-               return;
-
-       dbri = (struct dbri *) drivers[dev].private;
-
-       tprintk(("dbri_liu_init()\n"));
-
-       /* Set callback for LIU state change */
-       dbri->liu_callback = callback;
-       dbri->liu_callback_arg = callback_arg;
-
-       dbri_isdn_init(dbri);
-       dbri_liu_activate(dev, 0);
-}
-
-void dbri_liu_activate(int dev, int priority)
-{
-       struct dbri *dbri;
-       int val;
-       volatile s32 *cmd;
-
-       if (dev >= num_drivers)
-               return;
-
-       dbri = (struct dbri *) drivers[dev].private;
-
-       tprintk(("dbri_liu_activate()\n"));
-
-       if (dbri->liu_state <= 3) {
-               u32 tmp;
-
-	       cmd = dbri_cmdlock(dbri);
-
-	       /* Turn on the ISDN TE interface and request activation */
-	       val = D_NT_IRM_IMM | D_NT_IRM_EN | D_NT_ACT;
-#ifdef LOOPBACK_D
-	       val |= D_NT_LLB(4);
-#endif
-	       *(cmd++) = DBRI_CMD(D_TE, 0, val);
-
-	       dbri_cmdsend(dbri, cmd);
-
-	       /* Activate the interface */
-               tmp = sbus_readl(dbri->regs + REG0);
-               tmp |= D_T;
-               sbus_writel(tmp, dbri->regs + REG0);
-       }
-}
-
-void dbri_liu_deactivate(int dev)
-{
-       struct dbri *dbri;
-#if 0
-       u32 tmp;
-#endif
-
-       if (dev >= num_drivers)
-               return;
-
-       dbri = (struct dbri *) drivers[dev].private;
-
-       tprintk(("dbri_liu_deactivate()\n"));
-
-#if 0
-       /* Turn off the ISDN TE interface */
-       tmp = sbus_readl(dbri->regs + REG0);
-       tmp &= ~D_T;
-       sbus_writel(tmp, dbri->regs + REG0);
-
-       dbri->liu_state = 0;
-#endif
-}
-
-void dbri_dxmit(int dev, __u8 *buffer, unsigned int count,
-                void (*callback)(void *, int), void *callback_arg)
-{
-       struct dbri *dbri;
-
-       if (dev >= num_drivers)
-               return;
-
-       dbri = (struct dbri *) drivers[dev].private;
-
-       /* Pipe 1 is D channel transmit */
-       xmit_on_pipe(dbri, 1, buffer, count, callback, callback_arg);
-}
-
-void dbri_drecv(int dev, __u8 *buffer, unsigned int size,
-                void (*callback)(void *, int, unsigned int),
-                void *callback_arg)
-{
-       struct dbri *dbri;
-
-       if (dev >= num_drivers)
-               return;
-
-       dbri = (struct dbri *) drivers[dev].private;
-
-       /* Pipe 0 is D channel receive */
-       recv_on_pipe(dbri, 0, buffer, size, callback, callback_arg);
-}
-
-int dbri_bopen(int dev, unsigned int chan,
-               int hdlcmode, u_char xmit_idle_char)
-{
-       struct dbri *dbri;
-
-       if (dev >= num_drivers || chan > 1)
-               return -1;
-
-       dbri = (struct dbri *) drivers[dev].private;
-
-       if (hdlcmode) {
-               /* return -1; */
-
-               /* Pipe 8/9: receive B1/B2 channel */
-               setup_pipe(dbri, 8+chan, D_SDP_HDLC | D_SDP_FROM_SER|D_SDP_LSB);
-
-               /* Pipe 10/11: transmit B1/B2 channel */
-               setup_pipe(dbri,10+chan, D_SDP_HDLC | D_SDP_TO_SER | D_SDP_LSB);
-       } else {        /* !hdlcmode means transparent */
-               /* Pipe 8/9: receive B1/B2 channel */
-               setup_pipe(dbri, 8+chan, D_SDP_MEM | D_SDP_FROM_SER|D_SDP_LSB);
-
-               /* Pipe 10/11: transmit B1/B2 channel */
-               setup_pipe(dbri,10+chan, D_SDP_MEM | D_SDP_TO_SER | D_SDP_LSB);
-       }
-       return 0;
-}
-
-void dbri_bclose(int dev, unsigned int chan)
-{
-       struct dbri *dbri;
-
-       if (dev >= num_drivers || chan > 1)
-               return;
-
-       dbri = (struct dbri *) drivers[dev].private;
-
-       reset_pipe(dbri, 8+chan);
-       reset_pipe(dbri, 10+chan);
-}
-
-void dbri_bxmit(int dev, unsigned int chan,
-                __u8 *buffer, unsigned long count,
-                void (*callback)(void *, int),
-                void *callback_arg)
-{
-       struct dbri *dbri;
-
-       if (dev >= num_drivers || chan > 1)
-               return;
-
-       dbri = (struct dbri *) drivers[dev].private;
-
-       /* Pipe 10/11 is B1/B2 channel transmit */
-       xmit_on_pipe(dbri, 10+chan, buffer, count, callback, callback_arg);
-}
-
-void dbri_brecv(int dev, unsigned int chan,
-                __u8 *buffer, unsigned long size,
-                void (*callback)(void *, int, unsigned int),
-                void *callback_arg)
-{
-       struct dbri *dbri;
-
-       if (dev >= num_drivers || chan > 1)
-               return;
-
-       dbri = (struct dbri *) drivers[dev].private;
-
-       /* Pipe 8/9 is B1/B2 channel receive */
-       recv_on_pipe(dbri, 8+chan, buffer, size, callback, callback_arg);
-}
-
-#if defined(DBRI_ISDN)
-struct foreign_interface dbri_foreign_interface = {
-        dbri_get_irqnum,
-        dbri_get_liu_state,
-        dbri_liu_init,
-        dbri_liu_activate,
-        dbri_liu_deactivate,
-        dbri_dxmit,
-        dbri_drecv,
-        dbri_bopen,
-        dbri_bclose,
-        dbri_bxmit,
-        dbri_brecv
-};
-EXPORT_SYMBOL(dbri_foreign_interface);
-#endif
-
-/*
-****************************************************************************
-**************************** Initialization ********************************
-****************************************************************************
-*/
-
-static int dbri_attach(struct sparcaudio_driver *drv, 
-                       struct sbus_dev *sdev)
-{
-	struct dbri *dbri;
-	struct linux_prom_irqs irq;
-	int err;
-
-	if (sdev->prom_name[9] < 'e') {
-		printk(KERN_ERR "DBRI: unsupported chip version %c found.\n",
-			sdev->prom_name[9]);
-		return -EIO;
-	}
-
-	drv->ops = &dbri_ops;
-	drv->private = kmalloc(sizeof(struct dbri), GFP_KERNEL);
-	if (drv->private == NULL)
-		return -ENOMEM;
-
-	dbri = (struct dbri *) drv->private;
-        memset(dbri, 0, sizeof(*dbri));
-
-        dbri->dma = sbus_alloc_consistent(sdev,
-                                          sizeof(struct dbri_dma),
-                                          &dbri->dma_dvma);
-
-	memset((void *) dbri->dma, 0, sizeof(struct dbri_dma));
-
-	dprintk(D_GEN, ("DBRI: DMA Cmd Block 0x%p (0x%08x)\n",
-			dbri->dma, dbri->dma_dvma));
-
-	dbri->dbri_version = sdev->prom_name[9];
-        dbri->sdev = sdev;
-
-	/* Map the registers into memory. */
-	dbri->regs_size = sdev->reg_addrs[0].reg_size;
-        dbri->regs = sbus_ioremap(&sdev->resource[0], 0,
-                                  sdev->reg_addrs[0].reg_size,
-                                  "DBRI Registers");
-	if (!dbri->regs) {
-		printk(KERN_ERR "DBRI: could not allocate registers\n");
-                sbus_free_consistent(sdev, sizeof(struct dbri_dma),
-                                     (void *)dbri->dma, dbri->dma_dvma);
-		kfree(drv->private);
-		return -EIO;
-	}
-
-	prom_getproperty(sdev->prom_node, "intr", (char *)&irq, sizeof(irq));
-	dbri->irq = irq.pri;
-
-	err = request_irq(dbri->irq, dbri_intr, SA_SHIRQ,
-                          "DBRI audio/ISDN", dbri);
-	if (err) {
-		printk(KERN_ERR "DBRI: Can't get irq %d\n", dbri->irq);
-                sbus_iounmap(dbri->regs, dbri->regs_size);
-                sbus_free_consistent(sdev, sizeof(struct dbri_dma),
-                                     (void *)dbri->dma, dbri->dma_dvma);
-		kfree(drv->private);
-		return err;
-	}
-
-	dbri_initialize(dbri);
-	err = mmcodec_init(drv);
-	if(err) {
-		dbri_detach(dbri);
-		return err;
-	}
-	  
-	/* Register ourselves with the midlevel audio driver. */
-	err = register_sparcaudio_driver(drv,1);
-	if (err) {
-		printk(KERN_ERR "DBRI: unable to register audio\n");
-                dbri_detach(dbri);
-		return err;
-	}
-
-	dbri->perchip_info.play.active   = dbri->perchip_info.play.pause = 0;
-	dbri->perchip_info.record.active = dbri->perchip_info.record.pause = 0;
-
-	printk(KERN_INFO "audio%d at 0x%lx (irq %d) is DBRI(%c)+CS4215(%d)\n",
-	       num_drivers, dbri->regs,
-	       dbri->irq, dbri->dbri_version, dbri->mm.version);
-	
-	return 0;
-}
-
-/* Probe for the dbri chip and then attach the driver. */
-static int __init dbri_init(void)
-{
-	struct sbus_bus *sbus;
-	struct sbus_dev *sdev;
-  
-	num_drivers = 0;
-  
-	/* Probe each SBUS for the DBRI chip(s). */
-	for_all_sbusdev(sdev, sbus) {
-		/*
-		 * The version is coded in the last character
-		 */
-		if (!strncmp(sdev->prom_name, "SUNW,DBRI", 9)) {
-      			dprintk(D_GEN, ("DBRI: Found %s in SBUS slot %d\n",
-				sdev->prom_name, sdev->slot));
-			if (num_drivers >= MAX_DRIVERS) {
-				printk("DBRI: Ignoring slot %d\n", sdev->slot);
-				continue;
-			}
-	      
-			if (dbri_attach(&drivers[num_drivers], sdev) == 0)
-				num_drivers++;
-		}
-	}
-  
-	return (num_drivers > 0) ? 0 : -EIO;
-}
-
-static void __exit dbri_exit(void)
-{
-        register int i;
-
-        for (i = 0; i < num_drivers; i++) {
-                dbri_detach((struct dbri *) drivers[i].private);
-                unregister_sparcaudio_driver(& drivers[i], 1);
-                num_drivers--;
-        }
-}
-
-module_init(dbri_init);
-module_exit(dbri_exit);
-MODULE_LICENSE("GPL");
-
-/*
- * 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-indent-level: 8
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
diff -Nru a/drivers/sbus/audio/dbri.h b/drivers/sbus/audio/dbri.h
--- a/drivers/sbus/audio/dbri.h	Tue Oct  1 00:08:17 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,357 +0,0 @@
-/* $Id: dbri.h,v 1.13 2000/10/13 00:34:24 uzi Exp $
- * drivers/sbus/audio/cs4231.h
- *
- * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de)
- */
-
-#ifndef _DBRI_H_
-#define _DBRI_H_
-
-#include <linux/types.h>
-
-/* DBRI main registers */
-#define REG0	0x00UL		/* Status and Control */
-#define REG1	0x04UL		/* Mode and Interrupt */
-#define REG2	0x08UL		/* Parallel IO */
-#define REG3	0x0cUL		/* Test */
-#define REG8	0x20UL		/* Command Queue Pointer */
-#define REG9	0x24UL		/* Interrupt Queue Pointer */
-
-#define DBRI_NO_CMDS	64
-#define DBRI_NO_INTS	1	/* Note: the value of this define was
-				 * originally 2.  The ringbuffer to store
-				 * interrupts in dma is currently broken.
-				 * This is a temporary fix until the ringbuffer
-				 * is fixed.
-				 */
-#define DBRI_INT_BLK	64
-#define DBRI_NO_DESCS	64
-
-#define DBRI_MM_ONB	1
-#define DBRI_MM_SB	2
-
-struct dbri_mem {
-	volatile __u32	word1;
-	volatile __u32	ba;			/* Transmit/Receive Buffer Address */
-	volatile __u32	nda;			/* Next Descriptor Address */
-	volatile __u32	word4;
-};
-
-#include "cs4215.h"
-
-/* This structure is in a DMA region where it can accessed by both
- * the CPU and the DBRI
- */
-struct dbri_dma {
-	volatile s32 cmd[DBRI_NO_CMDS];			/* Place for commands */
-	volatile s32 intr[DBRI_NO_INTS * DBRI_INT_BLK];	/* Interrupt field */
-	struct dbri_mem desc[DBRI_NO_DESCS];		/* Xmit/receive descriptors */
-};
-
-#define dbri_dma_off(member, elem)	\
-	((u32)(unsigned long)		\
-	 (&(((struct dbri_dma *)0)->member[elem])))
-
-enum in_or_out { PIPEinput, PIPEoutput };
-
-enum direction { in, out };
-
-struct dbri_pipe {
-        u32 sdp;				/* SDP command word */
-	enum direction direction;
-        int nextpipe;				/* Next pipe in linked list */
-	int prevpipe;
-        int cycle;				/* Offset of timeslot (bits) */
-        int length;				/* Length of timeslot (bits) */
-        int desc;				/* Index of active descriptor*/
-	volatile __u32 *recv_fixed_ptr;		/* Ptr to receive fixed data */
-};
-
-struct dbri_desc {
-        int inuse;				/* Boolean flag */
-        int next;				/* Index of next desc, or -1 */
-        void *buffer;				/* CPU view of buffer */
-	u32 buffer_dvma;			/* Device view */
-        unsigned int len;
-        void (*output_callback)(void *, int);
-        void *output_callback_arg;
-        void (*input_callback)(void *, int, unsigned int);
-        void *input_callback_arg;
-};
-
-/* This structure holds the information for both chips (DBRI & CS4215) */
-
-struct dbri {
-	int regs_size, irq;		/* Needed for unload */
-	struct sbus_dev *sdev;		/* SBUS device info */
-
-	volatile struct dbri_dma *dma;	/* Pointer to our DMA block */
-	u32 dma_dvma;			/* DBRI visible DMA address */
-
-	unsigned long regs;		/* dbri HW regs */
-	int dbri_version;		/* 'e' and up is OK */
-	int dbri_irqp;			/* intr queue pointer */
-	int wait_seen;
-
-	struct dbri_pipe pipes[32];	/* DBRI's 32 data pipes */
-	struct dbri_desc descs[DBRI_NO_DESCS];
-
-	int chi_in_pipe;
-	int chi_out_pipe;
-	int chi_bpf;
-
-	struct cs4215 mm;		/* mmcodec special info */
-
-#if 0
-	/* Where to sleep if busy */
-	wait_queue_head_t wait, int_wait;
-#endif
-	struct audio_info perchip_info;
-
-	/* Track ISDN LIU and notify changes */
-	int liu_state;
-	void (*liu_callback)(void *);
-	void *liu_callback_arg;
-};
-
-/* DBRI Reg0 - Status Control Register - defines. (Page 17) */
-#define D_P		(1<<15)	/* Program command & queue pointer valid */
-#define D_G		(1<<14)	/* Allow 4-Word SBus Burst */
-#define D_S		(1<<13)	/* Allow 16-Word SBus Burst */
-#define D_E		(1<<12)	/* Allow 8-Word SBus Burst */
-#define D_X		(1<<7)	/* Sanity Timer Disable */
-#define D_T		(1<<6)	/* Permit activation of the TE interface */
-#define D_N		(1<<5)	/* Permit activation of the NT interface */
-#define D_C		(1<<4)	/* Permit activation of the CHI interface */
-#define D_F		(1<<3)	/* Force Sanity Timer Time-Out */
-#define D_D		(1<<2)	/* Disable Master Mode */
-#define D_H		(1<<1)	/* Halt for Analysis */
-#define D_R		(1<<0)	/* Soft Reset */
-
-
-/* DBRI Reg1 - Mode and Interrupt Register - defines. (Page 18) */
-#define D_LITTLE_END	(1<<8)	/* Byte Order */
-#define D_BIG_END	(0<<8)	/* Byte Order */
-#define D_MRR		(1<<4)	/* Multiple Error Ack on SBus (readonly) */
-#define D_MLE		(1<<3)	/* Multiple Late Error on SBus (readonly) */
-#define D_LBG		(1<<2)	/* Lost Bus Grant on SBus (readonly) */
-#define D_MBE		(1<<1)	/* Burst Error on SBus (readonly) */
-#define D_IR		(1<<0)	/* Interrupt Indicator (readonly) */
-
-
-/* DBRI Reg2 - Parallel IO Register - defines. (Page 18) */
-#define D_ENPIO3	(1<<7)	/* Enable Pin 3 */
-#define D_ENPIO2	(1<<6)	/* Enable Pin 2 */
-#define D_ENPIO1	(1<<5)	/* Enable Pin 1 */
-#define D_ENPIO0	(1<<4)	/* Enable Pin 0 */
-#define D_ENPIO		(0xf0)	/* Enable all the pins */
-#define D_PIO3		(1<<3)	/* Pin 3: 1: Data mode, 0: Ctrl mode */
-#define D_PIO2		(1<<2)	/* Pin 2: 1: Onboard PDN */
-#define D_PIO1		(1<<1)	/* Pin 1: 0: Reset */
-#define D_PIO0		(1<<0)	/* Pin 0: 1: Speakerbox PDN */
-
-
-/* DBRI Commands (Page 20) */
-#define D_WAIT		0x0	/* Stop execution */
-#define D_PAUSE		0x1	/* Flush long pipes */
-#define D_JUMP		0x2	/* New command queue */
-#define D_IIQ		0x3	/* Initialize Interrupt Queue */
-#define D_REX		0x4	/* Report command execution via interrupt */
-#define D_SDP		0x5	/* Setup Data Pipe */
-#define D_CDP		0x6	/* Continue Data Pipe (reread NULL Pointer) */
-#define D_DTS		0x7	/* Define Time Slot */
-#define D_SSP		0x8	/* Set short Data Pipe */
-#define D_CHI		0x9	/* Set CHI Global Mode */
-#define D_NT		0xa	/* NT Command */
-#define D_TE		0xb	/* TE Command */
-#define D_CDEC		0xc	/* Codec setup */
-#define D_TEST		0xd	/* No comment */
-#define D_CDM		0xe	/* CHI Data mode command */
-
-
-
-/* Special bits for some commands */
-#define D_PIPE(v)      ((v)<<0)        /* Pipe Nr: 0-15 long, 16-21 short */
-
-/* Setup Data Pipe */
-/* IRM */
-#define D_SDP_2SAME	(1<<18) /* Report 2nd time in a row value rcvd*/
-#define D_SDP_CHANGE	(2<<18) /* Report any changes */
-#define D_SDP_EVERY	(3<<18) /* Report any changes */
-#define D_SDP_EOL	(1<<17) /* EOL interrupt enable */
-#define D_SDP_IDLE	(1<<16) /* HDLC idle interrupt enable */
-
-/* Pipe data MODE */
-#define D_SDP_MEM	(0<<13)	/* To/from memory */
-#define D_SDP_HDLC	(2<<13)
-#define D_SDP_HDLC_D	(3<<13)	/* D Channel (prio control)*/
-#define D_SDP_SER	(4<<13)	/* Serial to serial */
-#define D_SDP_FIXED	(6<<13)	/* Short only */
-#define D_SDP_MODE(v)	((v)&(7<<13))
-
-#define D_SDP_TO_SER	(1<<12)	/* Direction */
-#define D_SDP_FROM_SER	(0<<12)	/* Direction */
-#define D_SDP_MSB	(1<<11)	/* Bit order within Byte */
-#define D_SDP_LSB	(0<<11)	/* Bit order within Byte */
-#define D_SDP_P		(1<<10)	/* Pointer Valid */
-#define D_SDP_A		(1<<8)	/* Abort */
-#define D_SDP_C		(1<<7)	/* Clear */
-
-/* Define Time Slot */
-#define D_DTS_VI	(1<<17) /* Valid Input Time-Slot Descriptor */
-#define D_DTS_VO	(1<<16) /* Valid Output Time-Slot Descriptor */
-#define D_DTS_INS	(1<<15) /* Insert Time Slot */
-#define D_DTS_DEL	(0<<15) /* Delete Time Slot */
-#define D_DTS_PRVIN(v) ((v)<<10) /* Previous In Pipe */
-#define D_DTS_PRVOUT(v)        ((v)<<5)  /* Previous Out Pipe */
-
-/* Time Slot defines */
-#define D_TS_LEN(v)	((v)<<24)	/* Number of bits in this time slot */
-#define D_TS_CYCLE(v)	((v)<<14)	/* Bit Count at start of TS */
-#define D_TS_DI		(1<<13)	/* Data Invert */
-#define D_TS_1CHANNEL	(0<<10)	/* Single Channel / Normal mode */
-#define D_TS_MONITOR	(2<<10)	/* Monitor pipe */
-#define D_TS_NONCONTIG	(3<<10) /* Non contiguous mode */
-#define D_TS_ANCHOR	(7<<10) /* Starting short pipes */
-#define D_TS_MON(v)    ((v)<<5)        /* Monitor Pipe */
-#define D_TS_NEXT(v)   ((v)<<0)        /* Pipe Nr: 0-15 long, 16-21 short */
-
-/* Concentration Highway Interface Modes */
-#define D_CHI_CHICM(v)	((v)<<16)	/* Clock mode */
-#define D_CHI_IR	(1<<15) /* Immediate Interrupt Report */
-#define D_CHI_EN	(1<<14) /* CHIL Interrupt enabled */
-#define D_CHI_OD	(1<<13) /* Open Drain Enable */
-#define D_CHI_FE	(1<<12) /* Sample CHIFS on Rising Frame Edge */
-#define D_CHI_FD	(1<<11) /* Frame Drive */
-#define D_CHI_BPF(v)	((v)<<0)	/* Bits per Frame */
-
-/* NT: These are here for completeness */
-#define D_NT_FBIT	(1<<17)	/* Frame Bit */
-#define D_NT_NBF	(1<<16)	/* Number of bad frames to loose framing */
-#define D_NT_IRM_IMM	(1<<15)	/* Interrupt Report & Mask: Immediate */
-#define D_NT_IRM_EN	(1<<14)	/* Interrupt Report & Mask: Enable */
-#define D_NT_ISNT	(1<<13)	/* Configfure interface as NT */
-#define D_NT_FT		(1<<12)	/* Fixed Timing */
-#define D_NT_EZ		(1<<11)	/* Echo Channel is Zeros */
-#define D_NT_IFA	(1<<10)	/* Inhibit Final Activation */
-#define D_NT_ACT	(1<<9)	/* Activate Interface */
-#define D_NT_MFE	(1<<8)	/* Multiframe Enable */
-#define D_NT_RLB(v)	((v)<<5)	/* Remote Loopback */
-#define D_NT_LLB(v)	((v)<<2)	/* Local Loopback */
-#define D_NT_FACT	(1<<1)	/* Force Activation */
-#define D_NT_ABV	(1<<0)	/* Activate Bipolar Violation */
-
-/* Codec Setup */
-#define D_CDEC_CK(v)	((v)<<24)	/* Clock Select */
-#define D_CDEC_FED(v)	((v)<<12)	/* FSCOD Falling Edge Delay */
-#define D_CDEC_RED(v)	((v)<<0)	/* FSCOD Rising Edge Delay */
-
-/* Test */
-#define D_TEST_RAM(v)	((v)<<16)	/* RAM Pointer */
-#define D_TEST_SIZE(v)	((v)<<11)	/* */
-#define D_TEST_ROMONOFF	0x5	/* Toggle ROM opcode monitor on/off */
-#define D_TEST_PROC	0x6	/* MicroProcessor test */
-#define D_TEST_SER	0x7	/* Serial-Controller test */
-#define D_TEST_RAMREAD	0x8	/* Copy from Ram to system memory */
-#define D_TEST_RAMWRITE	0x9	/* Copy into Ram from system memory */
-#define D_TEST_RAMBIST	0xa	/* RAM Built-In Self Test */
-#define D_TEST_MCBIST	0xb	/* Microcontroller Built-In Self Test */
-#define D_TEST_DUMP	0xe	/* ROM Dump */
-
-/* CHI Data Mode */
-#define D_CDM_THI	(1<<8)	/* Transmit Data on CHIDR Pin */
-#define D_CDM_RHI	(1<<7)	/* Receive Data on CHIDX Pin */
-#define D_CDM_RCE	(1<<6)	/* Receive on Rising Edge of CHICK */
-#define D_CDM_XCE	(1<<2)	/* Transmit Data on Rising Edge of CHICK */
-#define D_CDM_XEN	(1<<1)	/* Transmit Highway Enable */
-#define D_CDM_REN	(1<<0)	/* Receive Highway Enable */
-
-/* The Interrupts */
-#define D_INTR_BRDY	1	/* Buffer Ready for processing */
-#define D_INTR_MINT	2	/* Marked Interrupt in RD/TD */
-#define D_INTR_IBEG	3	/* Flag to idle transition detected (HDLC) */
-#define D_INTR_IEND	4	/* Idle to flag transition detected (HDLC) */
-#define D_INTR_EOL	5	/* End of List */
-#define D_INTR_CMDI	6	/* Command has bean read */
-#define D_INTR_XCMP	8	/* Transmission of frame complete */
-#define D_INTR_SBRI	9	/* BRI status change info */
-#define D_INTR_FXDT	10	/* Fixed data change */
-#define D_INTR_CHIL	11	/* CHI lost frame sync (channel 36 only) */
-#define D_INTR_COLL	11	/* Unrecoverable D-Channel collision */
-#define D_INTR_DBYT	12	/* Dropped by frame slip */
-#define D_INTR_RBYT	13	/* Repeated by frame slip */
-#define D_INTR_LINT	14	/* Lost Interrupt */
-#define D_INTR_UNDR	15	/* DMA underrun */
-
-#define D_INTR_TE	32
-#define D_INTR_NT	34
-#define D_INTR_CHI	36
-#define D_INTR_CMD	38
-
-#define D_INTR_GETCHAN(v)	(((v)>>24) & 0x3f)
-#define D_INTR_GETCODE(v)	(((v)>>20) & 0xf)
-#define D_INTR_GETCMD(v)	(((v)>>16) & 0xf)
-#define D_INTR_GETVAL(v)	((v) & 0xffff)
-#define D_INTR_GETRVAL(v)	((v) & 0xfffff)
-
-#define D_P_0		0	/* TE receive anchor */
-#define D_P_1		1	/* TE transmit anchor */
-#define D_P_2		2	/* NT transmit anchor */
-#define D_P_3		3	/* NT receive anchor */
-#define D_P_4		4	/* CHI send data */
-#define D_P_5		5	/* CHI receive data */
-#define D_P_6		6	/* */
-#define D_P_7		7	/* */
-#define D_P_8		8	/* */
-#define D_P_9		9	/* */
-#define D_P_10		10	/* */
-#define D_P_11		11	/* */
-#define D_P_12		12	/* */
-#define D_P_13		13	/* */
-#define D_P_14		14	/* */
-#define D_P_15		15	/* */
-#define D_P_16		16	/* CHI anchor pipe */
-#define D_P_17		17	/* CHI send */
-#define D_P_18		18	/* CHI receive */
-#define D_P_19		19	/* CHI receive */
-#define D_P_20		20	/* CHI receive */
-#define D_P_21		21	/* */
-#define D_P_22		22	/* */
-#define D_P_23		23	/* */
-#define D_P_24		24	/* */
-#define D_P_25		25	/* */
-#define D_P_26		26	/* */
-#define D_P_27		27	/* */
-#define D_P_28		28	/* */
-#define D_P_29		29	/* */
-#define D_P_30		30	/* */
-#define D_P_31		31	/* */
-
-
-/* Transmit descriptor defines */
-#define DBRI_TD_F	(1<<31)	/* End of Frame */
-#define DBRI_TD_D	(1<<30)	/* Do not append CRC */
-#define DBRI_TD_CNT(v)	((v)<<16)	/* Number of valid bytes in the buffer */
-#define DBRI_TD_B	(1<<15)	/* Final interrupt */
-#define DBRI_TD_M	(1<<14)	/* Marker interrupt */
-#define DBRI_TD_I	(1<<13)	/* Transmit Idle Characters */
-#define DBRI_TD_FCNT(v)	(v)	/* Flag Count */
-#define DBRI_TD_UNR	(1<<3)	/* Underrun: transmitter is out of data */
-#define DBRI_TD_ABT	(1<<2)	/* Abort: frame aborted */
-#define DBRI_TD_TBC	(1<<0)	/* Transmit buffer Complete */
-#define DBRI_TD_STATUS(v)       ((v)&0xff)      /* Transmit status */
-
-/* Receive descriptor defines */
-#define DBRI_RD_F	(1<<31)	/* End of Frame */
-#define DBRI_RD_C	(1<<30)	/* Completed buffer */
-#define DBRI_RD_B	(1<<15)	/* Final interrupt */
-#define DBRI_RD_M	(1<<14)	/* Marker interrupt */
-#define DBRI_RD_BCNT(v)	(v)	/* Buffer size */
-#define DBRI_RD_CRC	(1<<7)	/* 0: CRC is correct */
-#define DBRI_RD_BBC	(1<<6)	/* 1: Bad Byte received */
-#define DBRI_RD_ABT	(1<<5)	/* Abort: frame aborted */
-#define DBRI_RD_OVRN	(1<<3)	/* Overrun: data lost */
-#define DBRI_RD_STATUS(v)      ((v)&0xff)      /* Receive status */
-#define DBRI_RD_CNT(v) (((v)>>16)&0x1fff)        /* Number of valid bytes in the buffer */
-
-#endif /* _DBRI_H_ */
diff -Nru a/drivers/sbus/audio/dmy.c b/drivers/sbus/audio/dmy.c
--- a/drivers/sbus/audio/dmy.c	Tue Oct  1 00:08:16 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,805 +0,0 @@
-/* $Id: dmy.c,v 1.10 2001/10/08 22:19:50 davem Exp $
- * drivers/sbus/audio/dummy.c
- *
- * Copyright 1998 Derrick J Brashear (shadow@andrew.cmu.edu)
- *
- * This is a dummy lowlevel driver. Consider it a distant cousin of 
- * /proc/audio; It pretends to be a piece of audio hardware, and writes
- * to a file instead. (or will shortly)
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/soundcard.h>
-#include <linux/delay.h>
-#include <asm/openprom.h>
-#include <asm/oplib.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/sbus.h>
-
-#include <asm/audioio.h>
-#include "dummy.h"
-
-#define MAX_DRIVERS 1
-static struct sparcaudio_driver drivers[MAX_DRIVERS];
-static int num_drivers;
-
-static int dummy_play_gain(struct sparcaudio_driver *drv, int value, 
-                            unsigned char balance);
-static int dummy_record_gain(struct sparcaudio_driver *drv, int value, 
-                            unsigned char balance);
-static int dummy_output_muted(struct sparcaudio_driver *drv, int value);
-static int dummy_attach(struct sparcaudio_driver *drv) __init;
-
-static int
-dummy_set_output_encoding(struct sparcaudio_driver *drv, int value)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        if (value != 0) {
-                dummy_chip->perchip_info.play.encoding = value;
-                return 0;
-        }
-        return -EINVAL;
-}
-
-static int
-dummy_set_input_encoding(struct sparcaudio_driver *drv, int value)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        if (value != 0) {
-                dummy_chip->perchip_info.record.encoding = value;
-                return 0;
-        }
-        return -EINVAL;
-}
-
-static int dummy_get_output_encoding(struct sparcaudio_driver *drv)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        return dummy_chip->perchip_info.play.encoding;
-}
-
-static int dummy_get_input_encoding(struct sparcaudio_driver *drv)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        return dummy_chip->perchip_info.record.encoding;
-}
-
-static int
-dummy_set_output_rate(struct sparcaudio_driver *drv, int value)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        if (value != 0) {
-                dummy_chip->perchip_info.play.sample_rate = value;
-                return 0;
-        }
-        return -EINVAL;
-}
-
-static int
-dummy_set_input_rate(struct sparcaudio_driver *drv, int value)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        if (value != 0) {
-                dummy_chip->perchip_info.record.sample_rate = value;
-                return 0;
-        }
-        return -EINVAL;
-}
-
-static int dummy_get_output_rate(struct sparcaudio_driver *drv)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        return dummy_chip->perchip_info.play.sample_rate;
-}
-
-static int dummy_get_input_rate(struct sparcaudio_driver *drv)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        return dummy_chip->perchip_info.record.sample_rate;
-}
-
-/* Generically we support 4 channels. This does 2 */
-static int
-dummy_set_output_channels(struct sparcaudio_driver *drv, int value)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        switch (value) {
-        case 1:
-        case 2:
-                break;
-        default:
-                return -(EINVAL);
-        };
-
-        dummy_chip->perchip_info.play.channels = value;
-        return 0;
-}
-
-/* Generically we support 4 channels. This does 2 */
-static int
-dummy_set_input_channels(struct sparcaudio_driver *drv, int value)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        switch (value) {
-        case 1:
-        case 2:
-                break;
-        default:
-                return -(EINVAL);
-        };
-
-        dummy_chip->perchip_info.record.channels = value;
-        return 0;
-}
-
-static int dummy_get_input_channels(struct sparcaudio_driver *drv)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        return dummy_chip->perchip_info.record.channels;
-}
-
-static int dummy_get_output_channels(struct sparcaudio_driver *drv)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        return dummy_chip->perchip_info.play.channels;
-}
-
-static int dummy_get_output_precision(struct sparcaudio_driver *drv)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        return dummy_chip->perchip_info.play.precision;
-}
-
-static int dummy_get_input_precision(struct sparcaudio_driver *drv)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        return dummy_chip->perchip_info.record.precision;
-}
-
-static int dummy_set_output_precision(struct sparcaudio_driver *drv, int val)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private; 
-
-        dummy_chip->perchip_info.play.precision = val;
-        return dummy_chip->perchip_info.play.precision;
-}
-
-static int dummy_set_input_precision(struct sparcaudio_driver *drv, int val)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private; 
-
-        dummy_chip->perchip_info.record.precision = val;
-        return dummy_chip->perchip_info.record.precision;
-}
-
-/* Set output mute */
-static int dummy_output_muted(struct sparcaudio_driver *drv, int value)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        if (!value) 
-                dummy_chip->perchip_info.output_muted = 0;
-        else
-                dummy_chip->perchip_info.output_muted = 1;
-
-        return 0;
-}
-
-static int dummy_get_output_muted(struct sparcaudio_driver *drv)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        return dummy_chip->perchip_info.output_muted;
-}
-
-static int dummy_get_formats(struct sparcaudio_driver *drv)
-{
-        return (AFMT_MU_LAW | AFMT_A_LAW |
-                AFMT_U8 | AFMT_IMA_ADPCM | 
-                AFMT_S16_LE | AFMT_S16_BE);
-}
-
-static int dummy_get_output_ports(struct sparcaudio_driver *drv)
-{
-        return (AUDIO_LINE_OUT | AUDIO_SPEAKER | AUDIO_HEADPHONE);
-}
-
-static int dummy_get_input_ports(struct sparcaudio_driver *drv)
-{
-        return (AUDIO_ANALOG_LOOPBACK);
-}
-
-/* Set chip "output" port */
-static int dummy_set_output_port(struct sparcaudio_driver *drv, int value)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        dummy_chip->perchip_info.play.port = value;
-        return value;
-}
-
-static int dummy_set_input_port(struct sparcaudio_driver *drv, int value)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        dummy_chip->perchip_info.record.port = value;
-        return value;
-}
-
-static int dummy_get_output_port(struct sparcaudio_driver *drv)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        return dummy_chip->perchip_info.play.port;
-}
-
-static int dummy_get_input_port(struct sparcaudio_driver *drv)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        return dummy_chip->perchip_info.record.port;
-}
-
-static int dummy_get_output_error(struct sparcaudio_driver *drv)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        return (int) dummy_chip->perchip_info.play.error;
-}
-
-static int dummy_get_input_error(struct sparcaudio_driver *drv)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        return (int) dummy_chip->perchip_info.record.error;
-}
-
-static int dummy_get_output_samples(struct sparcaudio_driver *drv)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        return dummy_chip->perchip_info.play.samples;
-}
-
-static int dummy_get_output_pause(struct sparcaudio_driver *drv)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        return (int) dummy_chip->perchip_info.play.pause;
-}
-
-static int dummy_set_output_volume(struct sparcaudio_driver *drv, int value)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        dummy_play_gain(drv, value, dummy_chip->perchip_info.play.balance);
-        return 0;
-}
-
-static int dummy_get_output_volume(struct sparcaudio_driver *drv)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        return dummy_chip->perchip_info.play.gain;
-}
-
-static int dummy_set_output_balance(struct sparcaudio_driver *drv, int value)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        dummy_chip->perchip_info.play.balance = value;
-        dummy_play_gain(drv, dummy_chip->perchip_info.play.gain, 
-                        dummy_chip->perchip_info.play.balance);
-        return 0;
-}
-
-static int dummy_get_output_balance(struct sparcaudio_driver *drv)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        return (int) dummy_chip->perchip_info.play.balance;
-}
-
-/* Set chip play gain */
-static int dummy_play_gain(struct sparcaudio_driver *drv,
-                           int value, unsigned char balance)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-        int tmp = 0, r, l, r_adj, l_adj;
-
-        r = l = value;
-        if (balance < AUDIO_MID_BALANCE) {
-                r = (int) (value -
-                           ((AUDIO_MID_BALANCE - balance) << AUDIO_BALANCE_SHIFT));
-
-                if (r < 0)
-                        r = 0;
-        } else if (balance > AUDIO_MID_BALANCE) {
-                l = (int) (value -
-                           ((balance - AUDIO_MID_BALANCE) << AUDIO_BALANCE_SHIFT));
-
-                if (l < 0)
-                        l = 0;
-        }
-        (l == 0) ? (l_adj = DUMMY_MAX_DEV_ATEN) : (l_adj = DUMMY_MAX_ATEN - 
-                                                   (l * (DUMMY_MAX_ATEN + 1) / 
-                                                    (AUDIO_MAX_GAIN + 1)));
-        (r == 0) ? (r_adj = DUMMY_MAX_DEV_ATEN) : (r_adj = DUMMY_MAX_ATEN -
-                                                   (r * (DUMMY_MAX_ATEN + 1) /
-                                                    (AUDIO_MAX_GAIN + 1)));
-        if ((value == 0) || (value == AUDIO_MAX_GAIN)) {
-                tmp = value;
-        } else {
-                if (value == l) {
-                        tmp = ((DUMMY_MAX_ATEN - l_adj) * (AUDIO_MAX_GAIN + 1) / 
-                               (DUMMY_MAX_ATEN + 1));
-                } else if (value == r) {
-                        tmp = ((DUMMY_MAX_ATEN - r_adj) * (AUDIO_MAX_GAIN + 1) / 
-                               (DUMMY_MAX_ATEN + 1));
-                }
-        }
-        dummy_chip->perchip_info.play.gain = tmp;
-        return 0;
-}
-
-static int dummy_get_input_samples(struct sparcaudio_driver *drv)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        return dummy_chip->perchip_info.record.samples;
-}
-
-static int dummy_get_input_pause(struct sparcaudio_driver *drv)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        return (int) dummy_chip->perchip_info.record.pause;
-}
-
-static int dummy_set_monitor_volume(struct sparcaudio_driver *drv, int value)
-{
-        return 0;
-}
-
-static int dummy_get_monitor_volume(struct sparcaudio_driver *drv)
-{
-        return 0;
-}
-
-static int dummy_set_input_volume(struct sparcaudio_driver *drv, int value)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        dummy_record_gain(drv, value, dummy_chip->perchip_info.record.balance);
-        return 0;
-}
-
-static int dummy_get_input_volume(struct sparcaudio_driver *drv)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        return dummy_chip->perchip_info.record.gain;
-}
-
-static int dummy_set_input_balance(struct sparcaudio_driver *drv, int value)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        dummy_chip->perchip_info.record.balance = value;
-        dummy_record_gain(drv, dummy_chip->perchip_info.record.gain, 
-                          dummy_chip->perchip_info.play.balance);
-        return 0;
-}
-
-static int dummy_get_input_balance(struct sparcaudio_driver *drv)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        return (int) dummy_chip->perchip_info.record.balance;
-}
-
-static int dummy_record_gain(struct sparcaudio_driver *drv,
-                             int value, unsigned char balance)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-        int tmp = 0, r, l, r_adj, l_adj;
-
-        r = l = value;
-        if (balance < AUDIO_MID_BALANCE) {
-                r = (int) (value -
-                           ((AUDIO_MID_BALANCE - balance) << AUDIO_BALANCE_SHIFT));
-
-                if (r < 0)
-                        r = 0;
-        } else if (balance > AUDIO_MID_BALANCE) {
-                l = (int) (value -
-                           ((balance - AUDIO_MID_BALANCE) << AUDIO_BALANCE_SHIFT));
-
-                if (l < 0)
-                        l = 0;
-        }
-        (l == 0) ? (l_adj = DUMMY_MAX_DEV_ATEN) : (l_adj = DUMMY_MAX_ATEN - 
-                                                   (l * (DUMMY_MAX_ATEN + 1) / 
-                                                    (AUDIO_MAX_GAIN + 1)));
-        (r == 0) ? (r_adj = DUMMY_MAX_DEV_ATEN) : (r_adj = DUMMY_MAX_ATEN -
-                                                   (r * (DUMMY_MAX_ATEN + 1) /
-                                                    (AUDIO_MAX_GAIN + 1)));
-        if ((value == 0) || (value == AUDIO_MAX_GAIN)) {
-                tmp = value;
-        } else {
-                if (value == l) {
-                        tmp = ((DUMMY_MAX_ATEN - l_adj) * (AUDIO_MAX_GAIN + 1) / 
-                               (DUMMY_MAX_ATEN + 1));
-                } else if (value == r) {
-                        tmp = ((DUMMY_MAX_ATEN - r_adj) * (AUDIO_MAX_GAIN + 1) / 
-                               (DUMMY_MAX_ATEN + 1));
-                }
-        }
-        dummy_chip->perchip_info.record.gain = tmp;
-        return 0;
-}
-
-/* Reset the audio chip to a sane state. */
-static void dummy_chip_reset(struct sparcaudio_driver *drv)
-{
-        dummy_set_output_encoding(drv, AUDIO_ENCODING_ULAW);
-        dummy_set_output_rate(drv, DUMMY_RATE);
-        dummy_set_output_channels(drv, DUMMY_CHANNELS);
-        dummy_set_output_precision(drv, DUMMY_PRECISION);
-        dummy_set_output_balance(drv, AUDIO_MID_BALANCE);
-        dummy_set_output_volume(drv, DUMMY_DEFAULT_PLAYGAIN);
-        dummy_set_output_port(drv, AUDIO_SPEAKER);
-        dummy_output_muted(drv, 0);
-        dummy_set_input_encoding(drv, AUDIO_ENCODING_ULAW);
-        dummy_set_input_rate(drv, DUMMY_RATE);
-        dummy_set_input_channels(drv, DUMMY_CHANNELS);
-        dummy_set_input_precision(drv, DUMMY_PRECISION);
-        dummy_set_input_balance(drv, AUDIO_MID_BALANCE);
-        dummy_set_input_volume(drv, DUMMY_DEFAULT_PLAYGAIN);
-        dummy_set_input_port(drv, AUDIO_SPEAKER);
-}
-
-static int dummy_open(struct inode * inode, struct file * file, struct sparcaudio_driver *drv)
-{	
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        /* Set the default audio parameters if not already in use. */
-        if (file->f_mode & FMODE_WRITE) {
-                if (!(drv->flags & SDF_OPEN_WRITE) && 
-                    (dummy_chip->perchip_info.play.active == 0)) {
-                        dummy_chip->perchip_info.play.open = 1;
-                        dummy_chip->perchip_info.play.samples =
-                                dummy_chip->perchip_info.play.error = 0;
-                }
-        }
-
-        if (file->f_mode & FMODE_READ) {
-                if (!(drv->flags & SDF_OPEN_READ) && 
-                    (dummy_chip->perchip_info.record.active == 0)) {
-                        dummy_chip->perchip_info.record.open = 1;
-                        dummy_chip->perchip_info.record.samples =
-                                dummy_chip->perchip_info.record.error = 0;
-                }
-        }
-
-        MOD_INC_USE_COUNT;
-
-        return 0;
-}
-
-static void dummy_release(struct inode * inode, struct file * file, struct sparcaudio_driver *drv)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        if (file->f_mode & FMODE_WRITE) {
-                dummy_chip->perchip_info.play.active =
-                        dummy_chip->perchip_info.play.open = 0;
-        }
-
-        if (file->f_mode & FMODE_READ) {
-                dummy_chip->perchip_info.record.active =
-                        dummy_chip->perchip_info.record.open = 0;
-        }
-
-        MOD_DEC_USE_COUNT;
-}
-
-static void dummy_output_done_task(void * arg)
-{
-        struct sparcaudio_driver *drv = (struct sparcaudio_driver *) arg;
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        sparcaudio_output_done(drv, 1);
-        if (dummy_chip->perchip_info.record.active)
-                sparcaudio_input_done(drv, 1);
-}
-
-static void dummy_start_output(struct sparcaudio_driver *drv, __u8 * buffer,
-                               unsigned long count)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        if (dummy_chip->perchip_info.play.pause || !count) 
-                return;
-
-        dummy_chip->perchip_info.play.active = 1;
-
-        /* fake an "interrupt" to deal with this block */
-        INIT_LIST_HEAD(&dummy_chip->tqueue.list);
-        dummy_chip->tqueue.sync = 0;
-        dummy_chip->tqueue.routine = dummy_output_done_task;
-        dummy_chip->tqueue.data = drv;
-
-        queue_task(&dummy_chip->tqueue, &tq_immediate);
-        mark_bh(IMMEDIATE_BH);
-}
-
-static void dummy_start_input(struct sparcaudio_driver *drv, __u8 * buffer,
-                              unsigned long count)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        dummy_chip->perchip_info.record.active = 1;
-}
-
-static void dummy_stop_output(struct sparcaudio_driver *drv)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        dummy_chip->perchip_info.play.active = 0;
-}
-
-static void dummy_stop_input(struct sparcaudio_driver *drv)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        dummy_chip->perchip_info.record.active = 0;
-}
-
-static int dummy_set_output_pause(struct sparcaudio_driver *drv, int value)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        dummy_chip->perchip_info.play.pause = value;
-
-        if (!value)
-                sparcaudio_output_done(drv, 0);
-
-        return value;
-}
-
-static int dummy_set_input_pause(struct sparcaudio_driver *drv, int value)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-
-        dummy_chip->perchip_info.record.pause = value;
-
-        /* This should probably cause play pause. */
-
-        return value;
-}
-
-static int dummy_set_input_error(struct sparcaudio_driver *drv, int value)
-{
-        return 0;
-}
-
-static int dummy_set_output_error(struct sparcaudio_driver *drv, int value)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-        int i;
-
-        i = dummy_chip->perchip_info.play.error;
-        dummy_chip->perchip_info.play.error = value;
-        return i;
-}
-
-static int dummy_set_output_samples(struct sparcaudio_driver *drv, int value)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-        int i;
-
-        i = dummy_chip->perchip_info.play.samples;
-        dummy_chip->perchip_info.play.samples = value;
-        return i;
-}
-
-static int dummy_set_input_samples(struct sparcaudio_driver *drv, int value)
-{
-        struct dummy_chip *dummy_chip = (struct dummy_chip *) drv->private;
-        int i;
-
-        i = dummy_chip->perchip_info.play.samples;
-        dummy_chip->perchip_info.record.samples = value;
-        return i;
-}
-
-/* In order to fake things which care out, play we're a 4231 */
-static void dummy_audio_getdev(struct sparcaudio_driver *drv,
-                               audio_device_t * audinfo)
-{
-        strncpy(audinfo->name, "SUNW,cs4231", sizeof(audinfo->name) - 1);
-        strncpy(audinfo->version, "a", sizeof(audinfo->version) - 1);
-        strncpy(audinfo->config, "onboard1", sizeof(audinfo->config) - 1);
-}
-
-
-static int dummy_audio_getdev_sunos(struct sparcaudio_driver *drv)
-{
-        return 5; 
-}
-
-static struct sparcaudio_operations dummy_ops = {
-	dummy_open,
-	dummy_release,
-	NULL,
-	dummy_start_output,
-	dummy_stop_output,
-	dummy_start_input,
-	dummy_stop_input,
-	dummy_audio_getdev,
-        dummy_set_output_volume,
-        dummy_get_output_volume,
-        dummy_set_input_volume,
-        dummy_get_input_volume,
-        dummy_set_monitor_volume,
-        dummy_get_monitor_volume,
-	dummy_set_output_balance,
-	dummy_get_output_balance,
-	dummy_set_input_balance,
-	dummy_get_input_balance,
-        dummy_set_output_channels,
-        dummy_get_output_channels,
-        dummy_set_input_channels,
-        dummy_get_input_channels,
-        dummy_set_output_precision,
-        dummy_get_output_precision,
-        dummy_set_input_precision,
-        dummy_get_input_precision,
-        dummy_set_output_port,
-        dummy_get_output_port,
-        dummy_set_input_port,
-        dummy_get_input_port,
-        dummy_set_output_encoding,
-        dummy_get_output_encoding,
-        dummy_set_input_encoding,
-        dummy_get_input_encoding,
-        dummy_set_output_rate,
-        dummy_get_output_rate,
-        dummy_set_input_rate,
-        dummy_get_input_rate,
-	dummy_audio_getdev_sunos,
-	dummy_get_output_ports,
-	dummy_get_input_ports,
-	dummy_output_muted,
-	dummy_get_output_muted,
-	dummy_set_output_pause,
-	dummy_get_output_pause,
-        dummy_set_input_pause,
-	dummy_get_input_pause,
-	dummy_set_output_samples,
-	dummy_get_output_samples,
-        dummy_set_input_samples,
-	dummy_get_input_samples,
-	dummy_set_output_error,
-	dummy_get_output_error,
-        dummy_set_input_error,
-	dummy_get_input_error,
-        dummy_get_formats,
-};
-
-/* Attach to an dummy chip given its PROM node. */
-static int __init dummy_attach(struct sparcaudio_driver *drv)
-{
-        struct dummy_chip *dummy_chip;
-        int err;
-
-        /* Allocate our private information structure. */
-        drv->private = kmalloc(sizeof(struct dummy_chip), GFP_KERNEL);
-        if (drv->private == NULL)
-                return -ENOMEM;
-
-        /* Point at the information structure and initialize it. */
-        drv->ops = &dummy_ops;
-        dummy_chip = (struct dummy_chip *) drv->private;
-
-        /* Reset parameters. */
-        dummy_chip_reset(drv);
-
-        /* Register ourselves with the midlevel audio driver. */
-        err = register_sparcaudio_driver(drv, 2);
-
-        if (err < 0) {
-                printk(KERN_ERR "dummy: unable to register\n");
-                kfree(drv->private);
-                return -EIO;
-        }
-
-        dummy_chip->perchip_info.play.active = 
-                dummy_chip->perchip_info.play.pause = 0;
-
-        dummy_chip->perchip_info.play.avail_ports = (AUDIO_HEADPHONE |
-                                                     AUDIO_SPEAKER |
-                                                     AUDIO_LINE_OUT);
-
-        /* Announce the hardware to the user. */
-        printk(KERN_INFO "audio%d: dummy at 0x0 irq 0\n", drv->index);
-  
-        /* Success! */
-        return 0;
-}
-
-/* Detach from an dummy chip given the device structure. */
-static void __exit dummy_detach(struct sparcaudio_driver *drv)
-{
-        unregister_sparcaudio_driver(drv, 2);
-        kfree(drv->private);
-}
-
-/* Probe for the dummy chip and then attach the driver. */
-static int __init dummy_init(void)
-{
-	num_drivers = 0;
-      
-	/* Add support here for specifying multiple dummies to attach at once. */
-	if (dummy_attach(&drivers[num_drivers]) == 0)
-		num_drivers++;
-  
-	/* Only return success if we found some dummy chips. */
-	return (num_drivers > 0) ? 0 : -EIO;
-}
-
-static void __exit dummy_exit(void)
-{
-        int i;
-
-        for (i = 0; i < num_drivers; i++) {
-                dummy_detach(&drivers[i]);
-                num_drivers--;
-        }
-}
-
-module_init(dummy_init);
-module_exit(dummy_exit);
-MODULE_LICENSE("GPL");
-
-/*
- * 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-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
diff -Nru a/drivers/sbus/audio/dummy.h b/drivers/sbus/audio/dummy.h
--- a/drivers/sbus/audio/dummy.h	Tue Oct  1 00:08:17 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,41 +0,0 @@
-/* $Id: dummy.h,v 1.3 1999/09/21 14:37:41 davem Exp $
- * drivers/sbus/audio/dummy.h
- *
- * Copyright (C) 1998 Derrick J. Brashear (shadow@dementia.org)
- */
-
-#ifndef _DUMMY_H_
-#define _DUMMY_H_
-
-#include <linux/types.h>
-#include <linux/tqueue.h>
-
-#define DUMMY_OUTFILE "/usr/tmp/dummy.au"
-
-/* Our structure for each chip */
-
-struct dummy_chip {
-	struct audio_info perchip_info;
-	unsigned int playlen;
-	struct tq_struct tqueue;
-};
-
-#define DUMMY_MIN_ATEN     (0)
-#define DUMMY_MAX_ATEN     (31)
-#define DUMMY_MAX_DEV_ATEN (63)
-
-#define DUMMY_MON_MIN_ATEN         (0)
-#define DUMMY_MON_MAX_ATEN         (63)
-
-#define DUMMY_DEFAULT_PLAYGAIN     (132)
-#define DUMMY_DEFAULT_RECGAIN      (126)
-
-#define DUMMY_MIN_GAIN     (0)
-#define DUMMY_MAX_GAIN     (15)
-
-#define DUMMY_PRECISION    (8)             /* # of bits/sample */
-#define DUMMY_CHANNELS     (1)             /* channels/sample */
-
-#define DUMMY_RATE   (8000)                /* default sample rate */
-
-#endif /* _DUMMY_H_ */
diff -Nru a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c
--- a/drivers/sbus/char/jsflash.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/sbus/char/jsflash.c	Tue Oct  1 00:08:17 2002
@@ -128,7 +128,6 @@
 /*
  */
 static struct gendisk jsfd_disk[JSF_MAX];
-static char names[JSF_MAX][6];
 
 /*
  * Let's pretend we may have several of these...
@@ -637,8 +636,7 @@
 
 		disk->major = JSFD_MAJOR;
 		disk->first_minor = i;
-		sprintf(names[i], "jsfd%d", i);
-		disk->major_name = names[i];
+		sprintf(disk->disk_name, "jsfd%d", i);
 		disk->fops = &jsfd_fops;
 		disk->minor_shift = 0;
 		set_capacity(disk, jdp->dsize >> 9);
diff -Nru a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
--- a/drivers/scsi/53c700.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/scsi/53c700.c	Tue Oct  1 00:08:15 2002
@@ -284,6 +284,7 @@
 	tpnt->use_clustering = DISABLE_CLUSTERING;
 	tpnt->proc_info = NCR_700_proc_directory_info;
 	tpnt->use_blk_tcq = 1;
+	tpnt->highmem_io = 1;
 	
 	if(tpnt->name == NULL)
 		tpnt->name = "53c700";
diff -Nru a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
--- a/drivers/scsi/hosts.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/scsi/hosts.c	Tue Oct  1 00:08:15 2002
@@ -259,6 +259,48 @@
     return retval;
 }
 
+void scsi_host_busy_inc(struct Scsi_Host *shost, Scsi_Device *sdev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(shost->host_lock, flags);
+	shost->host_busy++;
+	sdev->device_busy++;
+	spin_unlock_irqrestore(shost->host_lock, flags);
+}
+
+void scsi_host_busy_dec_and_test(struct Scsi_Host *shost, Scsi_Device *sdev)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(shost->host_lock, flags);
+	shost->host_busy--;
+	sdev->device_busy--;
+	if (shost->in_recovery && (shost->host_busy == shost->host_failed)) {
+		up(shost->eh_wait);
+		SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler"
+					  "thread (%d)\n",
+					  atomic_read(&shost->eh_wait->count)));
+	}
+	spin_unlock_irqrestore(shost->host_lock, flags);
+}
+
+void scsi_host_failed_inc_and_test(struct Scsi_Host *shost)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(shost->host_lock, flags);
+	shost->in_recovery = 1;
+	shost->host_failed++;
+	if (shost->host_busy == shost->host_failed) {
+		up(shost->eh_wait);
+		SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler"
+					  "thread (%d)\n",
+					  atomic_read(&shost->eh_wait->count)));
+	}
+	spin_unlock_irqrestore(shost->host_lock, flags);
+}
+
 /*
  * 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/drivers/scsi/hosts.h b/drivers/scsi/hosts.h
--- a/drivers/scsi/hosts.h	Tue Oct  1 00:08:16 2002
+++ b/drivers/scsi/hosts.h	Tue Oct  1 00:08:16 2002
@@ -543,6 +543,13 @@
 extern int scsi_register_host(Scsi_Host_Template *);
 extern int scsi_unregister_host(Scsi_Host_Template *);
 
+/*
+ * host_busy inc/dec/test functions
+ */
+extern void scsi_host_busy_inc(struct Scsi_Host *, Scsi_Device *);
+extern void scsi_host_busy_dec_and_test(struct Scsi_Host *, Scsi_Device *);
+extern void scsi_host_failed_inc_and_test(struct Scsi_Host *);
+
 
 /*
  * This is an ugly hack.  If we expect to be able to load devices at run time,
diff -Nru a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
--- a/drivers/scsi/scsi.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/scsi/scsi.c	Tue Oct  1 00:08:17 2002
@@ -566,22 +566,6 @@
 				   SCpnt->target,
 				   atomic_read(&SCpnt->host->host_active),
 				   SCpnt->host->host_failed));
-	if (SCpnt->host->host_failed != 0) {
-		SCSI_LOG_ERROR_RECOVERY(5, printk("Error handler thread %d %d\n",
-						SCpnt->host->in_recovery,
-						SCpnt->host->eh_active));
-	}
-	/*
-	 * If the host is having troubles, then look to see if this was the last
-	 * command that might have failed.  If so, wake up the error handler.
-	 */
-	if (SCpnt->host->in_recovery
-	    && !SCpnt->host->eh_active
-	    && SCpnt->host->host_busy == SCpnt->host->host_failed) {
-		SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler thread (%d)\n",
-			     atomic_read(&SCpnt->host->eh_wait->count)));
-		up(SCpnt->host->eh_wait);
-	}
 
 	spin_unlock_irqrestore(&device_request_lock, flags);
 
@@ -1217,28 +1201,11 @@
 	 * etc, etc.
 	 */
 	if (!tstatus) {
-		SCpnt->done_late = 1;
 		return;
 	}
+
 	/* Set the serial numbers back to zero */
 	SCpnt->serial_number = 0;
-
-	/*
-	 * First, see whether this command already timed out.  If so, we ignore
-	 * the response.  We treat it as if the command never finished.
-	 *
-	 * Since serial_number is now 0, the error handler cound detect this
-	 * situation and avoid to call the low level driver abort routine.
-	 * (DB)
-         *
-         * FIXME(eric) - I believe that this test is now redundant, due to
-         * the test of the return status of del_timer().
-	 */
-	if (SCpnt->state == SCSI_STATE_TIMEOUT) {
-		SCSI_LOG_MLCOMPLETE(1, printk("Ignoring completion of %p due to timeout status", SCpnt));
-		return;
-	}
-
 	SCpnt->serial_number_at_timeout = 0;
 	SCpnt->state = SCSI_STATE_BHQUEUE;
 	SCpnt->owner = SCSI_OWNER_BH_HANDLER;
@@ -1349,21 +1316,11 @@
 					SCSI_LOG_MLCOMPLETE(3, print_sense("bh", SCpnt));
 				}
 				if (SCpnt->host->eh_wait != NULL) {
-					SCpnt->host->host_failed++;
+					scsi_eh_eflags_set(SCpnt, SCSI_EH_CMD_FAILED | SCSI_EH_CMD_ERR);
 					SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
 					SCpnt->state = SCSI_STATE_FAILED;
-					SCpnt->host->in_recovery = 1;
-					/*
-					 * If the host is having troubles, then
-					 * look to see if this was the last
-					 * command that might have failed.  If
-					 * so, wake up the error handler.
-					 */
-					if (SCpnt->host->host_busy == SCpnt->host->host_failed) {
-						SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler thread (%d)\n",
-										  atomic_read(&SCpnt->host->eh_wait->count)));
-						up(SCpnt->host->eh_wait);
-					}
+
+					scsi_host_failed_inc_and_test(SCpnt->host);
 				} else {
 					/*
 					 * We only get here if the error
@@ -1418,7 +1375,6 @@
 	struct Scsi_Host *host;
 	Scsi_Device *device;
 	Scsi_Request * SRpnt;
-	unsigned long flags;
 
 	host = SCpnt->host;
 	device = SCpnt->device;
@@ -1432,10 +1388,7 @@
          * one execution context, but the device and host structures are
          * shared.
          */
-	spin_lock_irqsave(host->host_lock, flags);
-	host->host_busy--;	/* Indicate that we are free */
-	device->device_busy--;	/* Decrement device usage counter. */
-	spin_unlock_irqrestore(host->host_lock, flags);
+	scsi_host_busy_dec_and_test(host, device);
 
         /*
          * Clear the flags which say that the device/host is no longer
@@ -1450,7 +1403,7 @@
 	 * If we have valid sense information, then some kind of recovery
 	 * must have taken place.  Make a note of this.
 	 */
-	if (scsi_sense_valid(SCpnt)) {
+	if (SCSI_SENSE_VALID(SCpnt)) {
 		SCpnt->result |= (DRIVER_SENSE << 24);
 	}
 	SCSI_LOG_MLCOMPLETE(3, printk("Notifying upper driver of completion for device %d %x\n",
diff -Nru a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h
--- a/drivers/scsi/scsi.h	Tue Oct  1 00:08:16 2002
+++ b/drivers/scsi/scsi.h	Tue Oct  1 00:08:16 2002
@@ -428,7 +428,6 @@
 			   void (*complete) (Scsi_Cmnd *));
 extern int scsi_delete_timer(Scsi_Cmnd * SCset);
 extern void scsi_error_handler(void *host);
-extern int scsi_sense_valid(Scsi_Cmnd *);
 extern int scsi_decide_disposition(Scsi_Cmnd * SCpnt);
 extern int scsi_block_when_processing_errors(Scsi_Device *);
 extern void scsi_sleep(int);
@@ -701,6 +700,7 @@
 	struct scsi_cmnd *reset_chain;
 
 	int eh_state;		/* Used for state tracking in error handlr */
+	int eh_eflags;		/* Used by error handlr */
 	void (*done) (struct scsi_cmnd *);	/* Mid-level done function */
 	/*
 	   A SCSI Command is assigned a nonzero serial_number when internal_cmnd
@@ -939,5 +939,27 @@
 
         return (Scsi_Cmnd *)req->special;
 }
+
+#define scsi_eh_eflags_chk(scp, flags) (scp->eh_eflags & flags)
+
+#define scsi_eh_eflags_set(scp, flags) do { \
+	scp->eh_eflags |= flags; \
+	} while(0)
+
+#define scsi_eh_eflags_clr(scp, flags) do { \
+	scp->eh_eflags &= ~flags; \
+	} while(0)
+
+#define scsi_eh_eflags_clr_all(scp) (scp->eh_eflags = 0)
+
+/*
+ * Scsi Error Handler Flags
+ */
+#define SCSI_EH_CMD_ERR	0x0001	/* Orig cmd error'd */
+#define SCSI_EH_CMD_FAILED	0x0002	/* Orig cmd error type failed */
+#define SCSI_EH_CMD_TIMEOUT	0x0004	/* Orig cmd error type timeout */
+#define SCSI_EH_REC_TIMEOUT	0x0008	/* Recovery cmd timeout */
+
+#define SCSI_SENSE_VALID(scmd) ((scmd->sense_buffer[0] & 0x70) == 0x70)
 
 #endif
diff -Nru a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
--- a/drivers/scsi/scsi_error.c	Tue Oct  1 00:08:14 2002
+++ b/drivers/scsi/scsi_error.c	Tue Oct  1 00:08:14 2002
@@ -6,6 +6,8 @@
  *                        Leonard Zubkoff and David Miller at Linux Expo, 
  *                        ideas originating from all over the place.
  *
+ *	Restructured scsi_unjam_host and associated functions.
+ *	September 04, 2002 Mike Anderson (andmike@us.ibm.com)
  */
 
 #include <linux/module.h>
@@ -49,16 +51,10 @@
 
 #ifdef DEBUG
 #define SENSE_TIMEOUT SCSI_TIMEOUT
-#define ABORT_TIMEOUT SCSI_TIMEOUT
-#define RESET_TIMEOUT SCSI_TIMEOUT
 #else
 #define SENSE_TIMEOUT (10*HZ)
-#define RESET_TIMEOUT (2*HZ)
-#define ABORT_TIMEOUT (15*HZ)
 #endif
 
-#define STATIC
-
 /*
  * These should *probably* be handled by the host itself.
  * Since it is allowed to sleep, it probably should.
@@ -66,47 +62,21 @@
 #define BUS_RESET_SETTLE_TIME   5*HZ
 #define HOST_RESET_SETTLE_TIME  10*HZ
 
-
-static const char RCSid[] = "$Header: /mnt/ide/home/eric/CVSROOT/linux/drivers/scsi/scsi_error.c,v 1.10 1997/12/08 04:50:35 eric Exp $";
-
-STATIC int scsi_check_sense(Scsi_Cmnd * SCpnt);
-STATIC int scsi_request_sense(Scsi_Cmnd *);
-STATIC void scsi_send_eh_cmnd(Scsi_Cmnd * SCpnt, int timeout);
-STATIC int scsi_try_to_abort_command(Scsi_Cmnd *, int);
-STATIC int scsi_test_unit_ready(Scsi_Cmnd *);
-STATIC int scsi_try_bus_device_reset(Scsi_Cmnd *, int timeout);
-STATIC int scsi_try_bus_reset(Scsi_Cmnd *);
-STATIC int scsi_try_host_reset(Scsi_Cmnd *);
-STATIC int scsi_unit_is_ready(Scsi_Cmnd *);
-STATIC void scsi_eh_action_done(Scsi_Cmnd *, int);
-STATIC int scsi_eh_retry_command(Scsi_Cmnd *);
-STATIC int scsi_eh_completed_normally(Scsi_Cmnd * SCpnt);
-STATIC void scsi_restart_operations(struct Scsi_Host *);
-STATIC void scsi_eh_finish_command(Scsi_Cmnd ** SClist, Scsi_Cmnd * SCpnt);
-
-
-/*
- * Function:    scsi_add_timer()
+/**
+ * scsi_add_timer - Start timeout timer for a single scsi command.
+ * @scmd:	scsi command that is about to start running.
+ * @timeout:	amount of time to allow this command to run.
+ * @complete:	timeout function to call if timer isn't canceled.
  *
- * Purpose:     Start timeout timer for a single scsi command.
- *
- * Arguments:   SCset   - command that is about to start running.
- *              timeout - amount of time to allow this command to run.
- *              complete - timeout function to call if timer isn't
- *                      canceled.
- *
- * Returns:     Nothing
- *
- * Notes:       This should be turned into an inline function.
- *
- * More Notes:  Each scsi command has it's own timer, and as it is added to
- *              the queue, we set up the timer.  When the command completes,
- *              we cancel the timer.  Pretty simple, really, especially
- *              compared to the old way of handling this crap.
- */
-void scsi_add_timer(Scsi_Cmnd * SCset,
-		    int timeout,
-		    void (*complete) (Scsi_Cmnd *))
+ * Notes:
+ *    This should be turned into an inline function.  Each scsi command
+ *    has it's own timer, and as it is added to the queue, we set up the
+ *    timer.  When the command completes, we cancel the timer.  Pretty
+ *    simple, really, especially compared to the old way of handling this
+ *    crap.
+ **/
+void scsi_add_timer(Scsi_Cmnd *scmd, int timeout, void (*complete)
+		    (Scsi_Cmnd *))
 {
 
 	/*
@@ -114,864 +84,1203 @@
 	 * first delete the timer.  The timer handling code gets rather
 	 * confused if we don't do this.
 	 */
-	if (SCset->eh_timeout.function != NULL) {
-		del_timer(&SCset->eh_timeout);
+	if (scmd->eh_timeout.function != NULL) {
+		del_timer(&scmd->eh_timeout);
 	}
-	SCset->eh_timeout.data = (unsigned long) SCset;
-	SCset->eh_timeout.expires = jiffies + timeout;
-	SCset->eh_timeout.function = (void (*)(unsigned long)) complete;
+	scmd->eh_timeout.data = (unsigned long) scmd;
+	scmd->eh_timeout.expires = jiffies + timeout;
+	scmd->eh_timeout.function = (void (*)(unsigned long)) complete;
 
-	SCset->done_late = 0;
+	SCSI_LOG_ERROR_RECOVERY(5, printk("Adding timer for command %p at"
+					  "%d (%p)\n", scmd, timeout,
+					  complete));
 
-	SCSI_LOG_ERROR_RECOVERY(5, printk("Adding timer for command %p at %d (%p)\n", SCset, timeout, complete));
-
-	add_timer(&SCset->eh_timeout);
+	add_timer(&scmd->eh_timeout);
 
 }
 
-/*
- * Function:    scsi_delete_timer()
- *
- * Purpose:     Delete/cancel timer for a given function.
+/**
+ * scsi_delete_timer - Delete/cancel timer for a given function.
+ * @scmd:	Cmd that we are canceling timer for
  *
- * Arguments:   SCset   - command that we are canceling timer for.
- *
- * Returns:     1 if we were able to detach the timer.  0 if we
- *              blew it, and the timer function has already started
- *              to run.
+ * Notes:
+ *     This should be turned into an inline function.
  *
- * Notes:       This should be turned into an inline function.
- */
-int scsi_delete_timer(Scsi_Cmnd * SCset)
+ * Return value:
+ *     1 if we were able to detach the timer.  0 if we blew it, and the
+ *     timer function has already started to run.
+ **/
+int scsi_delete_timer(Scsi_Cmnd *scmd)
 {
 	int rtn;
 
-	rtn = del_timer(&SCset->eh_timeout);
+	rtn = del_timer(&scmd->eh_timeout);
 
-	SCSI_LOG_ERROR_RECOVERY(5, printk("Clearing timer for command %p %d\n", SCset, rtn));
+	SCSI_LOG_ERROR_RECOVERY(5, printk("Clearing timer for command %p"
+					 " %d\n", scmd, rtn));
 
-	SCset->eh_timeout.data = (unsigned long) NULL;
-	SCset->eh_timeout.function = NULL;
+	scmd->eh_timeout.data = (unsigned long) NULL;
+	scmd->eh_timeout.function = NULL;
 
 	return rtn;
 }
 
-/*
- * Function:    scsi_times_out()
- *
- * Purpose:     Timeout function for normal scsi commands..
- *
- * Arguments:   SCpnt   - command that is timing out.
+/**
+ * scsi_times_out - Timeout function for normal scsi commands.
+ * @scmd:	Cmd that is timing out.
  *
- * Returns:     Nothing.
- *
- * Notes:       We do not need to lock this.  There is the potential for
- *              a race only in that the normal completion handling might
- *              run, but if the normal completion function determines
- *              that the timer has already fired, then it mustn't do
- *              anything.
- */
-void scsi_times_out(Scsi_Cmnd * SCpnt)
+ * Notes:
+ *     We do not need to lock this.  There is the potential for a race
+ *     only in that the normal completion handling might run, but if the
+ *     normal completion function determines that the timer has already
+ *     fired, then it mustn't do anything.
+ **/
+void scsi_times_out(Scsi_Cmnd *scmd)
 {
-	/* 
-	 * Notify the low-level code that this operation failed and we are
-	 * reposessing the command.  
-	 */
-#ifdef ERIC_neverdef
-	/*
-	 * FIXME(eric)
-	 * Allow the host adapter to push a queue ordering tag
-	 * out to the bus to force the command in question to complete.
-	 * If the host wants to do this, then we just restart the timer
-	 * for the command.  Before we really do this, some real thought
-	 * as to the optimum way to handle this should be done.  We *do*
-	 * need to force ordering every so often to ensure that all requests
-	 * do eventually complete, but I am not sure if this is the best way
-	 * to actually go about it.
-	 *
-	 * Better yet, force a sync here, but don't block since we are in an
-	 * interrupt.
-	 */
-	if (SCpnt->host->hostt->eh_ordered_queue_tag) {
-		if ((*SCpnt->host->hostt->eh_ordered_queue_tag) (SCpnt)) {
-			scsi_add_timer(SCpnt, SCpnt->internal_timeout,
-				       scsi_times_out);
-			return;
-		}
-	}
-	/*
-	 * FIXME(eric) - add a second special interface to handle this
-	 * case.  Ideally that interface can also be used to request
-	 * a queu
-	 */
-	if (SCpnt->host->can_queue) {
-		SCpnt->host->hostt->queuecommand(SCpnt, NULL);
-	}
-#endif
-
 	/* Set the serial_number_at_timeout to the current serial_number */
-	SCpnt->serial_number_at_timeout = SCpnt->serial_number;
+	scmd->serial_number_at_timeout = scmd->serial_number;
 
-	SCpnt->eh_state = FAILED;
-	SCpnt->state = SCSI_STATE_TIMEOUT;
-	SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
+	scsi_eh_eflags_set(scmd, SCSI_EH_CMD_TIMEOUT | SCSI_EH_CMD_ERR);
 
-	SCpnt->host->in_recovery = 1;
-	SCpnt->host->host_failed++;
+	if( scmd->host->eh_wait == NULL ) {
+		panic("Error handler thread not present at %p %p %s %d",
+		      scmd, scmd->host, __FILE__, __LINE__);
+	}
 
-	SCSI_LOG_TIMEOUT(3, printk("Command timed out active=%d busy=%d failed=%d\n",
-				   atomic_read(&SCpnt->host->host_active),
-				   SCpnt->host->host_busy,
-				   SCpnt->host->host_failed));
+	scsi_host_failed_inc_and_test(scmd->host);
 
-	/*
-	 * If the host is having troubles, then look to see if this was the last
-	 * command that might have failed.  If so, wake up the error handler.
-	 */
-	if( SCpnt->host->eh_wait == NULL ) {
-		panic("Error handler thread not present at %p %p %s %d", 
-		      SCpnt, SCpnt->host, __FILE__, __LINE__);
-	}
-	if (SCpnt->host->host_busy == SCpnt->host->host_failed) {
-		up(SCpnt->host->eh_wait);
-	}
+	SCSI_LOG_TIMEOUT(3, printk("Command timed out active=%d busy=%d "
+				   "failed=%d\n",
+				   atomic_read(&scmd->host->host_active),
+				   scmd->host->host_busy,
+				   scmd->host->host_failed));
 }
 
-/*
- * Function     scsi_block_when_processing_errors
+/**
+ * scsi_block_when_processing_errors - Prevent cmds from being queued.
+ * @sdev:	Device on which we are performing recovery.
  *
- * Purpose:     Prevent more commands from being queued while error recovery
- *              is taking place.
+ * Description:
+ *     We block until the host is out of error recovery, and then check to
+ *     see whether the host or the device is offline.
  *
- * Arguments:   SDpnt - device on which we are performing recovery.
- *
- * Returns:     FALSE   The device was taken offline by error recovery.
- *              TRUE    OK to proceed.
- *
- * Notes:       We block until the host is out of error recovery, and then
- *              check to see whether the host or the device is offline.
- */
-int scsi_block_when_processing_errors(Scsi_Device * SDpnt)
+ * Return value:
+ *     FALSE when dev was taken offline by error recovery. TRUE OK to
+ *     proceed.
+ **/
+int scsi_block_when_processing_errors(Scsi_Device *sdev)
 {
 
-	SCSI_SLEEP(&SDpnt->host->host_wait, SDpnt->host->in_recovery);
+	SCSI_SLEEP(&sdev->host->host_wait, sdev->host->in_recovery);
 
-	SCSI_LOG_ERROR_RECOVERY(5, printk("Open returning %d\n", SDpnt->online));
+	SCSI_LOG_ERROR_RECOVERY(5, printk("Open returning %d\n",
+					  sdev->online));
 
-	return SDpnt->online;
+	return sdev->online;
 }
 
-/*
- * Function:    scsi_eh_times_out()
- *
- * Purpose:     Timeout function for error handling.
- *
- * Arguments:   SCpnt   - command that is timing out.
- *
- * Returns:     Nothing.
- *
- * Notes:       During error handling, the kernel thread will be sleeping
- *              waiting for some action to complete on the device.  Our only
- *              job is to record that it timed out, and to wake up the
- *              thread.
- */
-STATIC
-void scsi_eh_times_out(Scsi_Cmnd * SCpnt)
+#if CONFIG_SCSI_LOGGING
+/**
+ * scsi_eh_prt_fail_stats - Log info on failures.
+ * @sc_list:	List for failed cmds.
+ * @shost:	scsi host being recovered.
+ **/
+static void scsi_eh_prt_fail_stats(Scsi_Cmnd *sc_list, struct Scsi_Host *shost)
 {
-	SCpnt->eh_state = SCSI_STATE_TIMEOUT;
-	SCSI_LOG_ERROR_RECOVERY(5, printk("In scsi_eh_times_out %p\n", SCpnt));
-
-	if (SCpnt->host->eh_action != NULL)
-		up(SCpnt->host->eh_action);
-	else
-		printk("Missing scsi error handler thread\n");
-}
+	Scsi_Cmnd *scmd;
+	Scsi_Device *sdev;
+	int total_failures = 0;
+	int cmd_failed = 0;
+	int cmd_timed_out = 0;
+	int devices_failed = 0;
 
 
-/*
- * Function:    scsi_eh_done()
- *
- * Purpose:     Completion function for error handling.
- *
- * Arguments:   SCpnt   - command that is timing out.
- *
- * Returns:     Nothing.
- *
- * Notes:       During error handling, the kernel thread will be sleeping
- *              waiting for some action to complete on the device.  Our only
- *              job is to record that the action completed, and to wake up the
- *              thread.
- */
-STATIC
-void scsi_eh_done(Scsi_Cmnd * SCpnt)
-{
-	int     rtn;
+	for (sdev = shost->host_queue; sdev; sdev = sdev->next) {
+		for (scmd = sc_list; scmd; scmd = scmd->bh_next) {
+			if (scmd->device == sdev) {
+				++total_failures;
+				if (scsi_eh_eflags_chk(scmd,
+						       SCSI_EH_CMD_TIMEOUT))
+					++cmd_timed_out;
+				else
+					++cmd_failed;
+			}
+		}
 
-	/*
-	 * If the timeout handler is already running, then just set the
-	 * flag which says we finished late, and return.  We have no
-	 * way of stopping the timeout handler from running, so we must
-	 * always defer to it.
-	 */
-	rtn = del_timer(&SCpnt->eh_timeout);
-	if (!rtn) {
-		SCpnt->done_late = 1;
-		return;
+		if (cmd_timed_out || cmd_failed) {
+			SCSI_LOG_ERROR_RECOVERY(3,
+				printk("scsi_eh: %d:%d:%d:%d cmds failed: %d,"
+				       "timedout: %d\n",
+				       shost->host_no, sdev->channel,
+				       sdev->id, sdev->lun,
+				       cmd_failed, cmd_timed_out));
+			cmd_timed_out = 0;
+			cmd_failed = 0;
+			++devices_failed;
+		}
 	}
 
-	SCpnt->request->rq_status = RQ_SCSI_DONE;
+	SCSI_LOG_ERROR_RECOVERY(2, printk("Total of %d commands on %d "
+					  "devices require eh work\n",
+				  total_failures, devices_failed));
+}
+#endif
 
-	SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
-	SCpnt->eh_state = SUCCESS;
+/**
+ * scsi_eh_get_failed - Gather failed cmds.
+ * @sc_list:	A pointer to a list for failed cmds.
+ * @shost:	Scsi host being recovered.
+ *
+ * XXX Add opaque interator for device / shost. Investigate direct
+ * addition to per eh list on error allowing skipping of this step.
+ **/
+static void scsi_eh_get_failed(Scsi_Cmnd **sc_list, struct Scsi_Host *shost)
+{
+	int found;
+	Scsi_Device *sdev;
+	Scsi_Cmnd *scmd;
+
+	for (found = 0, sdev = shost->host_queue; sdev; sdev = sdev->next) {
+		for (scmd = sdev->device_queue; scmd; scmd = scmd->next) {
+			if (scsi_eh_eflags_chk(scmd, SCSI_EH_CMD_ERR)) {
+				scmd->bh_next = *sc_list;
+				*sc_list = scmd;
+				found++;
+			} else {
+				/*
+				 * FIXME Verify how this can happen and if
+				 * this is still needed??
+				 */
+			    if (scmd->state != SCSI_STATE_INITIALIZING
+			    && scmd->state != SCSI_STATE_UNUSED) {
+				/*
+				 * Rats.  Something is still floating
+				 * around out there This could be the
+				 * result of the fact that the upper level
+				 * drivers are still frobbing commands
+				 * that might have succeeded.  There are
+				 * two outcomes. One is that the command
+				 * block will eventually be freed, and the
+				 * other one is that the command will be
+				 * queued and will be finished along the
+				 * way.
+				 */
+				SCSI_LOG_ERROR_RECOVERY(1, printk("Error hdlr "
+							  "prematurely woken "
+							  "cmds still active "
+							  "(%p %x %d)\n",
+					       scmd, scmd->state,
+					       scmd->target));
+				}
+			}
+		}
+	}
 
-	SCSI_LOG_ERROR_RECOVERY(5, printk("In eh_done %p result:%x\n", SCpnt,
-					  SCpnt->result));
+	SCSI_LOG_ERROR_RECOVERY(1, scsi_eh_prt_fail_stats(*sc_list, shost));
 
-	if (SCpnt->host->eh_action != NULL)
-		up(SCpnt->host->eh_action);
+	BUG_ON(shost->host_failed != found);
 }
 
-/*
- * Function:    scsi_eh_action_done()
- *
- * Purpose:     Completion function for error handling.
- *
- * Arguments:   SCpnt   - command that is timing out.
- *              answer  - boolean that indicates whether operation succeeded.
- *
- * Returns:     Nothing.
- *
- * Notes:       This callback is only used for abort and reset operations.
- */
-STATIC
-void scsi_eh_action_done(Scsi_Cmnd * SCpnt, int answer)
+/**
+ * scsi_check_sense - Examine scsi cmd sense
+ * @scmd:	Cmd to have sense checked.
+ **/
+static int scsi_check_sense(Scsi_Cmnd *scmd)
 {
-	SCpnt->request->rq_status = RQ_SCSI_DONE;
+	if (!SCSI_SENSE_VALID(scmd)) {
+		return FAILED;
+	}
+	if (scmd->sense_buffer[2] & 0xe0)
+		return SUCCESS;
 
-	SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
-	SCpnt->eh_state = (answer ? SUCCESS : FAILED);
+	switch (scmd->sense_buffer[2] & 0xf) {
+	case NO_SENSE:
+		return SUCCESS;
+	case RECOVERED_ERROR:
+		return /* soft_error */ SUCCESS;
 
-	if (SCpnt->host->eh_action != NULL)
-		up(SCpnt->host->eh_action);
-}
+	case ABORTED_COMMAND:
+		return NEEDS_RETRY;
+	case NOT_READY:
+	case UNIT_ATTENTION:
+		/*
+		 * if we are expecting a cc/ua because of a bus reset that we
+		 * performed, treat this just as a retry.  otherwise this is
+		 * information that we should pass up to the upper-level driver
+		 * so that we can deal with it there.
+		 */
+		if (scmd->device->expecting_cc_ua) {
+			scmd->device->expecting_cc_ua = 0;
+			return NEEDS_RETRY;
+		}
+		/*
+		 * if the device is in the process of becoming ready, we 
+		 * should retry.
+		 */
+		if ((scmd->sense_buffer[12] == 0x04) &&
+			(scmd->sense_buffer[13] == 0x01)) {
+			return NEEDS_RETRY;
+		}
+		return SUCCESS;
 
-/*
- * Function:  scsi_sense_valid()
- *
- * Purpose:     Determine whether a host has automatically obtained sense
- *              information or not.  If we have it, then give a recommendation
- *              as to what we should do next.
- */
-int scsi_sense_valid(Scsi_Cmnd * SCpnt)
-{
-	if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7) {
-		return FALSE;
+		/* these three are not supported */
+	case COPY_ABORTED:
+	case VOLUME_OVERFLOW:
+	case MISCOMPARE:
+		return SUCCESS;
+
+	case MEDIUM_ERROR:
+		return NEEDS_RETRY;
+
+	case ILLEGAL_REQUEST:
+	case BLANK_CHECK:
+	case DATA_PROTECT:
+	case HARDWARE_ERROR:
+	default:
+		return SUCCESS;
 	}
-	return TRUE;
 }
 
-/*
- * Function:  scsi_eh_retry_command()
- *
- * Purpose:     Retry the original command
+/**
+ * scsi_eh_completed_normally - Disposition a eh cmd on return from LLD.
+ * @scmd:	SCSI cmd to examine.
  *
- * Returns:     SUCCESS - we were able to get the sense data.
- *              FAILED  - we were not able to get the sense data.
- * 
- * Notes:       This function will *NOT* return until the command either
- *              times out, or it completes.
- */
-STATIC int scsi_eh_retry_command(Scsi_Cmnd * SCpnt)
+ * Notes:
+ *    This is *only* called when we are examining the status of commands
+ *    queued during error recovery.  the main difference here is that we
+ *    don't allow for the possibility of retries here, and we are a lot
+ *    more restrictive about what we consider acceptable.
+ **/
+static int scsi_eh_completed_normally(Scsi_Cmnd *scmd)
 {
-	memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd,
-	       sizeof(SCpnt->data_cmnd));
-	SCpnt->request_buffer = SCpnt->buffer;
-	SCpnt->request_bufflen = SCpnt->bufflen;
-	SCpnt->use_sg = SCpnt->old_use_sg;
-	SCpnt->cmd_len = SCpnt->old_cmd_len;
-	SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
-	SCpnt->underflow = SCpnt->old_underflow;
-
-	scsi_send_eh_cmnd(SCpnt, SCpnt->timeout_per_command);
+	int rtn;
 
 	/*
-	 * Hey, we are done.  Let's look to see what happened.
+	 * first check the host byte, to see if there is anything in there
+	 * that would indicate what we need to do.
 	 */
-	return SCpnt->eh_state;
-}
-
-/*
- * Function:  scsi_request_sense()
- *
- * Purpose:     Request sense data from a particular target.
- *
- * Returns:     SUCCESS - we were able to get the sense data.
- *              FAILED  - we were not able to get the sense data.
- * 
- * Notes:       Some hosts automatically obtain this information, others
- *              require that we obtain it on our own.
- *
- *              This function will *NOT* return until the command either
- *              times out, or it completes.
- */
-STATIC int scsi_request_sense(Scsi_Cmnd * SCpnt)
-{
-	static unsigned char generic_sense[6] =
-	{REQUEST_SENSE, 0, 0, 0, 255, 0};
-	unsigned char scsi_result0[256], *scsi_result = NULL;
-	int saved_result;
-
-	memcpy((void *) SCpnt->cmnd, (void *) generic_sense,
-	       sizeof(generic_sense));
-
-	if (SCpnt->device->scsi_level <= SCSI_2)
-		SCpnt->cmnd[1] = SCpnt->lun << 5;
-
-	scsi_result = (!SCpnt->host->hostt->unchecked_isa_dma)
-	    ? &scsi_result0[0] : kmalloc(512, GFP_ATOMIC | GFP_DMA);
-
-	if (scsi_result == NULL) {
-		printk("cannot allocate scsi_result in scsi_request_sense.\n");
+	if (host_byte(scmd->result) == DID_RESET) {
+		if (scmd->flags & IS_RESETTING) {
+			/*
+			 * ok, this is normal.  we don't know whether in fact
+			 * the command in question really needs to be rerun
+			 * or not - if this was the original data command then
+			 * the answer is yes, otherwise we just flag it as
+			 * SUCCESS.
+			 */
+			scmd->flags &= ~IS_RESETTING;
+			goto maybe_retry;
+		}
+		/*
+		 * rats.  we are already in the error handler, so we now
+		 * get to try and figure out what to do next.  if the sense
+		 * is valid, we have a pretty good idea of what to do.
+		 * if not, we mark it as FAILED.
+		 */
+		rtn = scsi_check_sense(scmd);
+		if (rtn == NEEDS_RETRY)
+			goto maybe_retry;
+		return rtn;
+	}
+	if (host_byte(scmd->result) != DID_OK) {
 		return FAILED;
 	}
 	/*
-	 * Zero the sense buffer.  Some host adapters automatically always request
-	 * sense, so it is not a good idea that SCpnt->request_buffer and
-	 * SCpnt->sense_buffer point to the same address (DB).
-	 * 0 is not a valid sense code. 
+	 * next, check the message byte.
 	 */
-	memset((void *) SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
-	memset((void *) scsi_result, 0, 256);
-
-	saved_result = SCpnt->result;
-	SCpnt->request_buffer = scsi_result;
-	SCpnt->request_bufflen = 256;
-	SCpnt->use_sg = 0;
-	SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
-	SCpnt->sc_data_direction = SCSI_DATA_READ;
-	SCpnt->underflow = 0;
-
-	scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT);
-
-	/* Last chance to have valid sense data */
-	if (!scsi_sense_valid(SCpnt))
-		memcpy((void *) SCpnt->sense_buffer,
-		       SCpnt->request_buffer,
-		       sizeof(SCpnt->sense_buffer));
-
-	if (scsi_result != &scsi_result0[0] && scsi_result != NULL)
-		kfree(scsi_result);
-
+	if (msg_byte(scmd->result) != COMMAND_COMPLETE) {
+		return FAILED;
+	}
 	/*
-	 * When we eventually call scsi_finish, we really wish to complete
-	 * the original request, so let's restore the original data. (DB)
+	 * now, check the status byte to see if this indicates
+	 * anything special.
 	 */
-	memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd,
-	       sizeof(SCpnt->data_cmnd));
-	SCpnt->result = saved_result;
-	SCpnt->request_buffer = SCpnt->buffer;
-	SCpnt->request_bufflen = SCpnt->bufflen;
-	SCpnt->use_sg = SCpnt->old_use_sg;
-	SCpnt->cmd_len = SCpnt->old_cmd_len;
-	SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
-	SCpnt->underflow = SCpnt->old_underflow;
+	switch (status_byte(scmd->result)) {
+	case GOOD:
+	case COMMAND_TERMINATED:
+		return SUCCESS;
+	case CHECK_CONDITION:
+		rtn = scsi_check_sense(scmd);
+		if (rtn == NEEDS_RETRY)
+			goto maybe_retry;
+		return rtn;
+	case CONDITION_GOOD:
+	case INTERMEDIATE_GOOD:
+	case INTERMEDIATE_C_GOOD:
+		/*
+		 * who knows?  FIXME(eric)
+		 */
+		return SUCCESS;
+	case BUSY:
+	case QUEUE_FULL:
+	case RESERVATION_CONFLICT:
+	default:
+		return FAILED;
+	}
+	return FAILED;
 
-	/*
-	 * Hey, we are done.  Let's look to see what happened.
-	 */
-	return SCpnt->eh_state;
+ maybe_retry:
+	if ((++scmd->retries) < scmd->allowed) {
+		return NEEDS_RETRY;
+	} else {
+		/* no more retries - report this one back to upper level */
+		return SUCCESS;
+	}
 }
 
-/*
- * Function:  scsi_test_unit_ready()
+/**
+ * scsi_eh_times_out - timeout function for error handling.
+ * @scmd:	Cmd that is timing out.
  *
- * Purpose:     Run test unit ready command to see if the device is talking to us or not.
- *
- */
-STATIC int scsi_test_unit_ready(Scsi_Cmnd * SCpnt)
+ * Notes:
+ *    During error handling, the kernel thread will be sleeping waiting
+ *    for some action to complete on the device.  our only job is to
+ *    record that it timed out, and to wake up the thread.
+ **/
+static void scsi_eh_times_out(Scsi_Cmnd *scmd)
 {
-	static unsigned char tur_command[6] =
-	{TEST_UNIT_READY, 0, 0, 0, 0, 0};
-
-	memcpy((void *) SCpnt->cmnd, (void *) tur_command,
-	       sizeof(tur_command));
-
-	if (SCpnt->device->scsi_level <= SCSI_2)
-		SCpnt->cmnd[1] = SCpnt->lun << 5;
-
-	/*
-	 * Zero the sense buffer.  The SCSI spec mandates that any
-	 * untransferred sense data should be interpreted as being zero.
-	 */
-	memset((void *) SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
+	scsi_eh_eflags_set(scmd, SCSI_EH_REC_TIMEOUT);
+	SCSI_LOG_ERROR_RECOVERY(3, printk("in scsi_eh_times_out %p\n", scmd));
 
-	SCpnt->request_buffer = NULL;
-	SCpnt->request_bufflen = 0;
-	SCpnt->use_sg = 0;
-	SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
-	SCpnt->underflow = 0;
-	SCpnt->sc_data_direction = SCSI_DATA_NONE;
-
-	scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT);
+	if (scmd->host->eh_action != NULL)
+		up(scmd->host->eh_action);
+	else
+		printk("missing scsi error handler thread\n");
+}
 
-	/*
-	 * When we eventually call scsi_finish, we really wish to complete
-	 * the original request, so let's restore the original data. (DB)
-	 */
-	memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd,
-	       sizeof(SCpnt->data_cmnd));
-	SCpnt->request_buffer = SCpnt->buffer;
-	SCpnt->request_bufflen = SCpnt->bufflen;
-	SCpnt->use_sg = SCpnt->old_use_sg;
-	SCpnt->cmd_len = SCpnt->old_cmd_len;
-	SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
-	SCpnt->underflow = SCpnt->old_underflow;
+/**
+ * scsi_eh_done - Completion function for error handling.
+ * @scmd:	Cmd that is done.
+ **/
+static void scsi_eh_done(Scsi_Cmnd *scmd)
+{
+	int     rtn;
 
 	/*
-	 * Hey, we are done.  Let's look to see what happened.
+	 * if the timeout handler is already running, then just set the
+	 * flag which says we finished late, and return.  we have no
+	 * way of stopping the timeout handler from running, so we must
+	 * always defer to it.
 	 */
-	SCSI_LOG_ERROR_RECOVERY(3,
-		printk("scsi_test_unit_ready: SCpnt %p eh_state %x\n",
-		SCpnt, SCpnt->eh_state));
-	return SCpnt->eh_state;
-}
-
-/*
- * This would normally need to get the IO request lock,
- * but as it doesn't actually touch anything that needs
- * to be locked we can avoid the lock here..
- */
-STATIC
-void scsi_sleep_done(struct semaphore *sem)
-{
-	if (sem != NULL) {
-		up(sem);
+	rtn = del_timer(&scmd->eh_timeout);
+	if (!rtn) {
+		return;
 	}
-}
 
-void scsi_sleep(int timeout)
-{
-	DECLARE_MUTEX_LOCKED(sem);
-	struct timer_list timer;
-
-	init_timer(&timer);
-	timer.data = (unsigned long) &sem;
-	timer.expires = jiffies + timeout;
-	timer.function = (void (*)(unsigned long)) scsi_sleep_done;
+	scmd->request->rq_status = RQ_SCSI_DONE;
 
-	SCSI_LOG_ERROR_RECOVERY(5, printk("Sleeping for timer tics %d\n", timeout));
+	scmd->owner = SCSI_OWNER_ERROR_HANDLER;
 
-	add_timer(&timer);
+	SCSI_LOG_ERROR_RECOVERY(3, printk("in eh_done %p result:%x\n", scmd,
+					  scmd->result));
 
-	down(&sem);
-	del_timer(&timer);
+	if (scmd->host->eh_action != NULL)
+		up(scmd->host->eh_action);
 }
 
-/*
- * Function:  scsi_send_eh_cmnd
- *
- * Purpose:     Send a command out to a device as part of error recovery.
+/**
+ * scsi_send_eh_cmnd  - send a cmd to a device as part of error recovery.
+ * @scmd:	SCSI Cmd to send.
+ * @timeout:	Timeout for cmd.
  *
- * Notes:       The initialization of the structures is quite a bit different
- *              in this case, and furthermore, there is a different completion
- *              handler.
- */
-STATIC void scsi_send_eh_cmnd(Scsi_Cmnd * SCpnt, int timeout)
+ * Notes:
+ *    The initialization of the structures is quite a bit different in
+ *    this case, and furthermore, there is a different completion handler
+ *    vs scsi_dispatch_cmd.
+ * Return value:
+ *    SUCCESS/FAILED
+ **/
+static int scsi_send_eh_cmnd(Scsi_Cmnd *scmd, int timeout)
 {
 	unsigned long flags;
-	struct Scsi_Host *host = SCpnt->host;
+	struct Scsi_Host *host = scmd->host;
+	int rtn = SUCCESS;
 
 	ASSERT_LOCK(host->host_lock, 0);
 
 retry:
 	/*
-	 * We will use a queued command if possible, otherwise we will
+	 * we will use a queued command if possible, otherwise we will
 	 * emulate the queuing and calling of completion function ourselves.
 	 */
-	SCpnt->owner = SCSI_OWNER_LOWLEVEL;
+	scmd->owner = SCSI_OWNER_LOWLEVEL;
 
 	if (host->can_queue) {
 		DECLARE_MUTEX_LOCKED(sem);
 
-		SCpnt->eh_state = SCSI_STATE_QUEUED;
-
-		scsi_add_timer(SCpnt, timeout, scsi_eh_times_out);
+		scsi_add_timer(scmd, timeout, scsi_eh_times_out);
 
 		/*
-		 * Set up the semaphore so we wait for the command to complete.
+		 * set up the semaphore so we wait for the command to complete.
 		 */
-		SCpnt->host->eh_action = &sem;
-		SCpnt->request->rq_status = RQ_SCSI_BUSY;
+		scmd->host->eh_action = &sem;
+		scmd->request->rq_status = RQ_SCSI_BUSY;
 
-		spin_lock_irqsave(SCpnt->host->host_lock, flags);
-		host->hostt->queuecommand(SCpnt, scsi_eh_done);
-		spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
+		spin_lock_irqsave(scmd->host->host_lock, flags);
+		host->hostt->queuecommand(scmd, scsi_eh_done);
+		spin_unlock_irqrestore(scmd->host->host_lock, flags);
 
 		down(&sem);
 
-		SCpnt->host->eh_action = NULL;
+		scmd->host->eh_action = NULL;
 
 		/*
-		 * See if timeout.  If so, tell the host to forget about it.
-		 * In other words, we don't want a callback any more.
+		 * see if timeout.  if so, tell the host to forget about it.
+		 * in other words, we don't want a callback any more.
 		 */
-		if (SCpnt->eh_state == SCSI_STATE_TIMEOUT) {
-                        SCpnt->owner = SCSI_OWNER_LOWLEVEL;
+		if (scsi_eh_eflags_chk(scmd, SCSI_EH_REC_TIMEOUT)) {
+			scsi_eh_eflags_clr(scmd,  SCSI_EH_REC_TIMEOUT);
+                        scmd->owner = SCSI_OWNER_LOWLEVEL;
 
 			/*
-			 * As far as the low level driver is
+			 * as far as the low level driver is
 			 * concerned, this command is still active, so
 			 * we must give the low level driver a chance
-			 * to abort it. (DB) 
+			 * to abort it. (db) 
 			 *
 			 * FIXME(eric) - we are not tracking whether we could
-			 * abort a timed out command or not.  Not sure how
+			 * abort a timed out command or not.  not sure how
 			 * we should treat them differently anyways.
 			 */
-			spin_lock_irqsave(SCpnt->host->host_lock, flags);
-			if (SCpnt->host->hostt->eh_abort_handler)
-				SCpnt->host->hostt->eh_abort_handler(SCpnt);
-			spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
+			spin_lock_irqsave(scmd->host->host_lock, flags);
+			if (scmd->host->hostt->eh_abort_handler)
+				scmd->host->hostt->eh_abort_handler(scmd);
+			spin_unlock_irqrestore(scmd->host->host_lock, flags);
 			
-			SCpnt->request->rq_status = RQ_SCSI_DONE;
-			SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
+			scmd->request->rq_status = RQ_SCSI_DONE;
+			scmd->owner = SCSI_OWNER_ERROR_HANDLER;
 			
-			SCpnt->eh_state = FAILED;
+			rtn = FAILED;
 		}
-		SCSI_LOG_ERROR_RECOVERY(5, printk("send_eh_cmnd: %p eh_state:%x\n",
-						SCpnt, SCpnt->eh_state));
+		SCSI_LOG_ERROR_RECOVERY(3, printk("%s: %p rtn:%x\n",
+						  __FUNCTION__, scmd,
+						  rtn));
 	} else {
 		int temp;
 
 		/*
-		 * We damn well had better never use this code.  There is no
+		 * we damn well had better never use this code.  there is no
 		 * timeout protection here, since we would end up waiting in
 		 * the actual low level driver, we don't know how to wake it up.
 		 */
 		spin_lock_irqsave(host->host_lock, flags);
-		temp = host->hostt->command(SCpnt);
+		temp = host->hostt->command(scmd);
 		spin_unlock_irqrestore(host->host_lock, flags);
 
-		SCpnt->result = temp;
-		/* Fall through to code below to examine status. */
-		SCpnt->eh_state = SUCCESS;
+		scmd->result = temp;
+		/* fall through to code below to examine status. */
 	}
 
 	/*
-	 * Now examine the actual status codes to see whether the command
+	 * now examine the actual status codes to see whether the command
 	 * actually did complete normally.
 	 */
-	if (SCpnt->eh_state == SUCCESS) {
-		int ret = scsi_eh_completed_normally(SCpnt);
+	if (rtn == SUCCESS) {
+		int ret = scsi_eh_completed_normally(scmd);
 		SCSI_LOG_ERROR_RECOVERY(3,
-			printk("scsi_send_eh_cmnd: scsi_eh_completed_normally %x\n", ret));
+			printk("%s: scsi_eh_completed_normally %x\n",
+			       __FUNCTION__, ret));
 		switch (ret) {
 		case SUCCESS:
-			SCpnt->eh_state = SUCCESS;
 			break;
 		case NEEDS_RETRY:
 			goto retry;
 		case FAILED:
 		default:
-			SCpnt->eh_state = FAILED;
+			rtn = FAILED;
 			break;
 		}
-	} else {
-		SCpnt->eh_state = FAILED;
 	}
+
+	return rtn;
 }
 
-/*
- * Function:  scsi_unit_is_ready()
+/**
+ * scsi_request_sense - Request sense data from a particular target.
+ * @scmd:	SCSI cmd for request sense.
  *
- * Purpose:     Called after TEST_UNIT_READY is run, to test to see if
- *              the unit responded in a way that indicates it is ready.
- */
-STATIC int scsi_unit_is_ready(Scsi_Cmnd * SCpnt)
+ * Notes:
+ *    Some hosts automatically obtain this information, others require
+ *    that we obtain it on our own. This function will *not* return until
+ *    the command either times out, or it completes.
+ **/
+static int scsi_request_sense(Scsi_Cmnd *scmd)
 {
-	if (SCpnt->result) {
-		if (((driver_byte(SCpnt->result) & DRIVER_SENSE) ||
-		     (status_byte(SCpnt->result) & CHECK_CONDITION)) &&
-		    ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) {
-			if (((SCpnt->sense_buffer[2] & 0xf) != NOT_READY) &&
-			    ((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION) &&
-			    ((SCpnt->sense_buffer[2] & 0xf) != ILLEGAL_REQUEST)) {
-				return 0;
-			}
-		}
+	static unsigned char generic_sense[6] =
+	{REQUEST_SENSE, 0, 0, 0, 255, 0};
+	unsigned char scsi_result0[256], *scsi_result = NULL;
+	int saved_result;
+	int rtn;
+
+	memcpy((void *) scmd->cmnd, (void *) generic_sense,
+	       sizeof(generic_sense));
+
+	if (scmd->device->scsi_level <= SCSI_2)
+		scmd->cmnd[1] = scmd->lun << 5;
+
+	scsi_result = (!scmd->host->hostt->unchecked_isa_dma)
+	    ? &scsi_result0[0] : kmalloc(512, GFP_ATOMIC | GFP_DMA);
+
+	if (scsi_result == NULL) {
+		printk("cannot allocate scsi_result in scsi_request_sense.\n");
+		return FAILED;
 	}
-	return 1;
+	/*
+	 * zero the sense buffer.  some host adapters automatically always
+	 * request sense, so it is not a good idea that
+	 * scmd->request_buffer and scmd->sense_buffer point to the same
+	 * address (db).  0 is not a valid sense code. 
+	 */
+	memset((void *) scmd->sense_buffer, 0, sizeof(scmd->sense_buffer));
+	memset((void *) scsi_result, 0, 256);
+
+	saved_result = scmd->result;
+	scmd->request_buffer = scsi_result;
+	scmd->request_bufflen = 256;
+	scmd->use_sg = 0;
+	scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
+	scmd->sc_data_direction = SCSI_DATA_READ;
+	scmd->underflow = 0;
+
+	rtn = scsi_send_eh_cmnd(scmd, SENSE_TIMEOUT);
+
+	/* last chance to have valid sense data */
+	if (!SCSI_SENSE_VALID(scmd))
+		memcpy((void *) scmd->sense_buffer,
+		       scmd->request_buffer,
+		       sizeof(scmd->sense_buffer));
+
+	if (scsi_result != &scsi_result0[0] && scsi_result != NULL)
+		kfree(scsi_result);
+
+	/*
+	 * when we eventually call scsi_finish, we really wish to complete
+	 * the original request, so let's restore the original data. (db)
+	 */
+	memcpy((void *) scmd->cmnd, (void *) scmd->data_cmnd,
+	       sizeof(scmd->data_cmnd));
+	scmd->result = saved_result;
+	scmd->request_buffer = scmd->buffer;
+	scmd->request_bufflen = scmd->bufflen;
+	scmd->use_sg = scmd->old_use_sg;
+	scmd->cmd_len = scmd->old_cmd_len;
+	scmd->sc_data_direction = scmd->sc_old_data_direction;
+	scmd->underflow = scmd->old_underflow;
+
+	/*
+	 * hey, we are done.  let's look to see what happened.
+	 */
+	return rtn;
 }
 
-/*
- * Function:    scsi_eh_finish_command
- *
- * Purpose:     Handle a command that we are finished with WRT error handling.
+/**
+ * scsi_eh_retry_cmd - Retry the original command
+ * @scmd:	Original failed SCSI cmd.
  *
- * Arguments:   SClist - pointer to list into which we are putting completed commands.
- *              SCpnt  - command that is completing
+ * Notes:
+ *    This function will *not* return until the command either times out,
+ *    or it completes.
+ **/
+static int scsi_eh_retry_cmd(Scsi_Cmnd *scmd)
+{
+	memcpy((void *) scmd->cmnd, (void *) scmd->data_cmnd,
+	       sizeof(scmd->data_cmnd));
+	scmd->request_buffer = scmd->buffer;
+	scmd->request_bufflen = scmd->bufflen;
+	scmd->use_sg = scmd->old_use_sg;
+	scmd->cmd_len = scmd->old_cmd_len;
+	scmd->sc_data_direction = scmd->sc_old_data_direction;
+	scmd->underflow = scmd->old_underflow;
+
+	return scsi_send_eh_cmnd(scmd, scmd->timeout_per_command);
+}
+
+/**
+ * scsi_eh_finish_cmd - Handle a cmd that eh is finished with.
+ * @scmd:	Original SCSI cmd that eh has finished.
+ * @shost:	SCSI host that cmd originally failed on.
  *
- * Notes:       We don't want to use the normal command completion while we are
- *              are still handling errors - it may cause other commands to be queued,
- *              and that would disturb what we are doing.  Thus we really want to keep
- *              a list of pending commands for final completion, and once we
- *              are ready to leave error handling we handle completion for real.
- */
-STATIC void scsi_eh_finish_command(Scsi_Cmnd ** SClist, Scsi_Cmnd * SCpnt)
-{
-	SCpnt->state = SCSI_STATE_BHQUEUE;
-	SCpnt->bh_next = *SClist;
+ * Notes:
+ *    We don't want to use the normal command completion while we are are
+ *    still handling errors - it may cause other commands to be queued,
+ *    and that would disturb what we are doing.  thus we really want to
+ *    keep a list of pending commands for final completion, and once we
+ *    are ready to leave error handling we handle completion for real.
+ **/
+static void scsi_eh_finish_cmd(Scsi_Cmnd *scmd, struct Scsi_Host *shost)
+{
+	shost->host_failed--;
+	scmd->state = SCSI_STATE_BHQUEUE;
+	scsi_eh_eflags_clr_all(scmd);
+
 	/*
-	 * Set this back so that the upper level can correctly free up
+	 * set this back so that the upper level can correctly free up
 	 * things.
 	 */
-	SCpnt->use_sg = SCpnt->old_use_sg;
-	SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
-	SCpnt->underflow = SCpnt->old_underflow;
-	*SClist = SCpnt;
+	scmd->use_sg = scmd->old_use_sg;
+	scmd->sc_data_direction = scmd->sc_old_data_direction;
+	scmd->underflow = scmd->old_underflow;
 }
 
-/*
- * Function:  scsi_try_to_abort_command
+/**
+ * scsi_eh_get_sense - Get device sense data.
+ * @sc_todo:	list of cmds that have failed.
+ * @shost:	scsi host being recovered.
+ *
+ * Description:
+ *    See if we need to request sense information.  if so, then get it
+ *    now, so we have a better idea of what to do.  
  *
- * Purpose:     Ask host adapter to abort a running command.
  *
- * Returns:     FAILED          Operation failed or not supported.
- *              SUCCESS         Succeeded.
- *
- * Notes:       This function will not return until the user's completion
- *              function has been called.  There is no timeout on this
- *              operation.  If the author of the low-level driver wishes
- *              this operation to be timed, they can provide this facility
- *              themselves.  Helper functions in scsi_error.c can be supplied
- *              to make this easier to do.
- *
- * Notes:       It may be possible to combine this with all of the reset
- *              handling to eliminate a lot of code duplication.  I don't
- *              know what makes more sense at the moment - this is just a
- *              prototype.
- */
-STATIC int scsi_try_to_abort_command(Scsi_Cmnd * SCpnt, int timeout)
+ * Notes:
+ *    This has the unfortunate side effect that if a shost adapter does
+ *    not automatically request sense information, that we end up shutting
+ *    it down before we request it.  All shosts should be doing this
+ *    anyways, so for now all I have to say is tough noogies if you end up
+ *    in here.  On second thought, this is probably a good idea.  We
+ *    *really* want to give authors an incentive to automatically request
+ *    this.
+ *
+ *    In 2.5 this capability will be going away.
+ **/
+static int scsi_eh_get_sense(Scsi_Cmnd *sc_todo, struct Scsi_Host *shost)
 {
 	int rtn;
-	unsigned long flags;
+	Scsi_Cmnd *scmd;
 
-	SCpnt->eh_state = FAILED;	/* Until we come up with something better */
+	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: checking to see if we need"
+					  " to request sense\n",
+					  __FUNCTION__));
+
+	for (scmd = sc_todo; scmd; scmd = scmd->bh_next) {
+		if (!scsi_eh_eflags_chk(scmd, SCSI_EH_CMD_FAILED) ||
+		    SCSI_SENSE_VALID(scmd))
+			continue;
 
-	if (SCpnt->host->hostt->eh_abort_handler == NULL) {
-		return FAILED;
+		SCSI_LOG_ERROR_RECOVERY(2, printk("%s: requesting sense"
+						  "for %d\n", __FUNCTION__,
+						  scmd->target));
+		rtn = scsi_request_sense(scmd);
+		if (rtn != SUCCESS)
+			continue;
+
+		SCSI_LOG_ERROR_RECOVERY(3, printk("sense requested for %p"
+						  "- result %x\n", scmd,
+						  scmd->result));
+		SCSI_LOG_ERROR_RECOVERY(3, print_sense("bh", scmd));
+
+		rtn = scsi_decide_disposition(scmd);
+
+		/*
+		 * if the result was normal, then just pass it along to the
+		 * upper level.
+		 */
+		if (rtn == SUCCESS)
+			scsi_eh_finish_cmd(scmd, shost);
+		if (rtn != NEEDS_RETRY)
+			continue;
+
+		/*
+		 * we only come in here if we want to retry a
+		 * command.  the test to see whether the command
+		 * should be retried should be keeping track of the
+		 * number of tries, so we don't end up looping, of
+		 * course.
+		 */
+		scmd->state = NEEDS_RETRY;
+		rtn = scsi_eh_retry_cmd(scmd);
+		if (rtn != SUCCESS)
+			continue;
+
+		/*
+		 * we eventually hand this one back to the top level.
+		 */
+		scsi_eh_finish_cmd(scmd, shost);
 	}
-	/* 
+
+	return shost->host_failed;
+}
+
+/**
+ * scsi_try_to_abort_cmd - Ask host to abort a running command.
+ * @scmd:	SCSI cmd to abort from Lower Level.
+ *
+ * Notes:
+ *    This function will not return until the user's completion function
+ *    has been called.  there is no timeout on this operation.  if the
+ *    author of the low-level driver wishes this operation to be timed,
+ *    they can provide this facility themselves.  helper functions in
+ *    scsi_error.c can be supplied to make this easier to do.
+ **/
+static int scsi_try_to_abort_cmd(Scsi_Cmnd *scmd)
+{
+	int rtn = FAILED;
+	unsigned long flags;
+
+	if (scmd->host->hostt->eh_abort_handler == NULL) {
+		return rtn;
+	}
+	/*
 	 * scsi_done was called just after the command timed out and before
-	 * we had a chance to process it. (DB)
+	 * we had a chance to process it. (db)
 	 */
-	if (SCpnt->serial_number == 0)
+	if (scmd->serial_number == 0)
 		return SUCCESS;
 
-	SCpnt->owner = SCSI_OWNER_LOWLEVEL;
+	scmd->owner = SCSI_OWNER_LOWLEVEL;
 
-	spin_lock_irqsave(SCpnt->host->host_lock, flags);
-	rtn = SCpnt->host->hostt->eh_abort_handler(SCpnt);
-	spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
+	spin_lock_irqsave(scmd->host->host_lock, flags);
+	rtn = scmd->host->hostt->eh_abort_handler(scmd);
+	spin_unlock_irqrestore(scmd->host->host_lock, flags);
 	return rtn;
 }
 
-/*
- * Function:  scsi_try_bus_device_reset
- *
- * Purpose:     Ask host adapter to perform a bus device reset for a given
- *              device.
- *
- * Returns:     FAILED          Operation failed or not supported.
- *              SUCCESS         Succeeded.
- *
- * Notes:       There is no timeout for this operation.  If this operation is
- *              unreliable for a given host, then the host itself needs to put a
- *              timer on it, and set the host back to a consistent state prior
- *              to returning.
- */
-STATIC int scsi_try_bus_device_reset(Scsi_Cmnd * SCpnt, int timeout)
+/**
+ * scsi_eh_tur - Send TUR to device.
+ * @scmd:	Scsi cmd to send TUR
+ *
+ * Return value:
+ *    0 - Device is ready. 1 - Device NOT ready.
+ **/
+static int scsi_eh_tur(Scsi_Cmnd *scmd)
 {
-	unsigned long flags;
+	static unsigned char tur_command[6] =
+	{TEST_UNIT_READY, 0, 0, 0, 0, 0};
 	int rtn;
 
-	SCpnt->eh_state = FAILED;	/* Until we come up with something better */
+	memcpy((void *) scmd->cmnd, (void *) tur_command,
+	       sizeof(tur_command));
+
+	if (scmd->device->scsi_level <= SCSI_2)
+		scmd->cmnd[1] = scmd->lun << 5;
 
-	if (SCpnt->host->hostt->eh_device_reset_handler == NULL) {
-		return FAILED;
+	/*
+	 * zero the sense buffer.  the scsi spec mandates that any
+	 * untransferred sense data should be interpreted as being zero.
+	 */
+	memset((void *) scmd->sense_buffer, 0, sizeof(scmd->sense_buffer));
+
+	scmd->request_buffer = NULL;
+	scmd->request_bufflen = 0;
+	scmd->use_sg = 0;
+	scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
+	scmd->underflow = 0;
+	scmd->sc_data_direction = SCSI_DATA_NONE;
+
+	rtn = scsi_send_eh_cmnd(scmd, SENSE_TIMEOUT);
+
+	/*
+	 * when we eventually call scsi_finish, we really wish to complete
+	 * the original request, so let's restore the original data. (db)
+	 */
+	memcpy((void *) scmd->cmnd, (void *) scmd->data_cmnd,
+	       sizeof(scmd->data_cmnd));
+	scmd->request_buffer = scmd->buffer;
+	scmd->request_bufflen = scmd->bufflen;
+	scmd->use_sg = scmd->old_use_sg;
+	scmd->cmd_len = scmd->old_cmd_len;
+	scmd->sc_data_direction = scmd->sc_old_data_direction;
+	scmd->underflow = scmd->old_underflow;
+
+	/*
+	 * hey, we are done.  let's look to see what happened.
+	 */
+	SCSI_LOG_ERROR_RECOVERY(3,
+		printk("%s: scmd %p rtn %x\n",
+		__FUNCTION__, scmd, rtn));
+	if ((rtn == SUCCESS) && scmd->result) {
+		if (((driver_byte(scmd->result) & DRIVER_SENSE) ||
+		     (status_byte(scmd->result) & CHECK_CONDITION)) &&
+		    (SCSI_SENSE_VALID(scmd))) {
+			if (((scmd->sense_buffer[2] & 0xf) != NOT_READY) &&
+			    ((scmd->sense_buffer[2] & 0xf) != UNIT_ATTENTION) &&
+			    ((scmd->sense_buffer[2] & 0xf) != ILLEGAL_REQUEST)) {
+				return 0;
+			}
+		}
 	}
-	SCpnt->owner = SCSI_OWNER_LOWLEVEL;
+	return 1;
+}
+
+/**
+ * scsi_eh_abort_cmd - abort a timed-out cmd.
+ * @sc_todo:	A list of cmds that have failed.
+ * @shost:	scsi host being recovered.
+ *
+ * Decription:
+ *    Try and see whether or not it makes sense to try and abort the
+ *    running command.  this only works out to be the case if we have one
+ *    command that has timed out.  if the command simply failed, it makes
+ *    no sense to try and abort the command, since as far as the shost
+ *    adapter is concerned, it isn't running.
+ **/
+static int scsi_eh_abort_cmd(Scsi_Cmnd *sc_todo, struct Scsi_Host *shost)
+{
 
-	spin_lock_irqsave(SCpnt->host->host_lock, flags);
-	rtn = SCpnt->host->hostt->eh_device_reset_handler(SCpnt);
-	spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
+	int rtn;
+	Scsi_Cmnd *scmd;
+
+	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: checking to see if we need"
+					  " to abort cmd\n", __FUNCTION__));
 
-	if (rtn == SUCCESS)
-		SCpnt->eh_state = SUCCESS;
+	for (scmd = sc_todo; scmd; scmd = scmd->bh_next) {
+		if (!scsi_eh_eflags_chk(scmd, SCSI_EH_CMD_TIMEOUT))
+			continue;
 
-	return SCpnt->eh_state;
+		rtn = scsi_try_to_abort_cmd(scmd);
+		if (rtn == SUCCESS) {
+			if (scsi_eh_tur(scmd)) {
+				rtn = scsi_eh_retry_cmd(scmd);
+				if (rtn == SUCCESS)
+					scsi_eh_finish_cmd(scmd, shost);
+			}
+		}
+	}
+	return shost->host_failed;
 }
 
-/*
- * Function:  scsi_try_bus_reset
- *
- * Purpose:     Ask host adapter to perform a bus reset for a host.
+/**
+ * scsi_try_bus_device_reset - Ask host to perform a BDR on a dev
+ * @scmd:	SCSI cmd used to send BDR	
  *
- * Returns:     FAILED          Operation failed or not supported.
- *              SUCCESS         Succeeded.
+ * Notes:
+ *    There is no timeout for this operation.  if this operation is
+ *    unreliable for a given host, then the host itself needs to put a
+ *    timer on it, and set the host back to a consistent state prior to
+ *    returning.
+ **/
+static int scsi_try_bus_device_reset(Scsi_Cmnd *scmd)
+{
+	unsigned long flags;
+	int rtn = FAILED;
+
+	if (scmd->host->hostt->eh_device_reset_handler == NULL) {
+		return rtn;
+	}
+	scmd->owner = SCSI_OWNER_LOWLEVEL;
+
+	spin_lock_irqsave(scmd->host->host_lock, flags);
+	rtn = scmd->host->hostt->eh_device_reset_handler(scmd);
+	spin_unlock_irqrestore(scmd->host->host_lock, flags);
+
+	return rtn;
+}
+
+/**
+ * scsi_eh_bus_device_reset - send bdr is needed
+ * @sc_todo:	a list of cmds that have failed.
+ * @shost:	scsi host being recovered.
  *
- * Notes:       
- */
-STATIC int scsi_try_bus_reset(Scsi_Cmnd * SCpnt)
+ * Notes:
+ *    Try a bus device reset.  still, look to see whether we have multiple
+ *    devices that are jammed or not - if we have multiple devices, it
+ *    makes no sense to try bus_device_reset - we really would need to try
+ *    a bus_reset instead. 
+ **/
+static int scsi_eh_bus_device_reset(Scsi_Cmnd *sc_todo, struct Scsi_Host *shost)
+{
+	int rtn;
+	Scsi_Cmnd *scmd;
+	Scsi_Device *sdev;
+
+	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Trying BDR\n", __FUNCTION__));
+
+	for (sdev = shost->host_queue; sdev; sdev = sdev->next) {
+		for (scmd = sc_todo; scmd; scmd = scmd->bh_next)
+			if ((scmd->device == sdev) &&
+			    scsi_eh_eflags_chk(scmd, SCSI_EH_CMD_ERR))
+				break;
+
+		if (!scmd)
+			continue;
+
+		/*
+		 * ok, we have a device that is having problems.  try and send
+		 * a bus device reset to it.
+		 */
+		rtn = scsi_try_bus_device_reset(scmd);
+		if ((rtn == SUCCESS) && (scsi_eh_tur(scmd)))
+				for (scmd = sc_todo; scmd; scmd = scmd->bh_next)
+					if ((scmd->device == sdev) &&
+					    scsi_eh_eflags_chk(scmd, SCSI_EH_CMD_ERR)) {
+						rtn = scsi_eh_retry_cmd(scmd);
+						if (rtn == SUCCESS)
+							scsi_eh_finish_cmd(scmd, shost);
+					}
+	}
+
+	return shost->host_failed;
+}
+
+/**
+ * scsi_try_bus_reset - ask host to perform a bus reset
+ * @scmd:	SCSI cmd to send bus reset.
+ **/
+static int scsi_try_bus_reset(Scsi_Cmnd *scmd)
 {
 	unsigned long flags;
 	int rtn;
+	Scsi_Device *sdev;
 
-	SCpnt->eh_state = FAILED;	/* Until we come up with something better */
-	SCpnt->owner = SCSI_OWNER_LOWLEVEL;
-	SCpnt->serial_number_at_timeout = SCpnt->serial_number;
+	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Bus RST\n",
+					  __FUNCTION__));
+	scmd->owner = SCSI_OWNER_LOWLEVEL;
+	scmd->serial_number_at_timeout = scmd->serial_number;
 
-	if (SCpnt->host->hostt->eh_bus_reset_handler == NULL) {
+	if (scmd->host->hostt->eh_bus_reset_handler == NULL)
 		return FAILED;
-	}
 
-	spin_lock_irqsave(SCpnt->host->host_lock, flags);
-	rtn = SCpnt->host->hostt->eh_bus_reset_handler(SCpnt);
-	spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
-
-	if (rtn == SUCCESS)
-		SCpnt->eh_state = SUCCESS;
-
-	/*
-	 * If we had a successful bus reset, mark the command blocks to expect
-	 * a condition code of unit attention.
-	 */
-	scsi_sleep(BUS_RESET_SETTLE_TIME);
-	if (SCpnt->eh_state == SUCCESS) {
-		Scsi_Device *SDloop;
-		for (SDloop = SCpnt->host->host_queue; SDloop; SDloop = SDloop->next) {
-			if (SCpnt->channel == SDloop->channel) {
-				SDloop->was_reset = 1;
-				SDloop->expecting_cc_ua = 1;
+	spin_lock_irqsave(scmd->host->host_lock, flags);
+	rtn = scmd->host->hostt->eh_bus_reset_handler(scmd);
+	spin_unlock_irqrestore(scmd->host->host_lock, flags);
+
+	if (rtn == SUCCESS) {
+		scsi_sleep(BUS_RESET_SETTLE_TIME);
+		/*
+		 * Mark all affected devices to expect a unit attention.
+		 */
+		for (sdev = scmd->host->host_queue; sdev; sdev = sdev->next)
+			if (scmd->channel == sdev->channel) {
+				sdev->was_reset = 1;
+				sdev->expecting_cc_ua = 1;
 			}
-		}
 	}
-	return SCpnt->eh_state;
+	return rtn;
 }
 
-/*
- * Function:  scsi_try_host_reset
- *
- * Purpose:     Ask host adapter to reset itself, and the bus.
- *
- * Returns:     FAILED          Operation failed or not supported.
- *              SUCCESS         Succeeded.
- *
- * Notes:
- */
-STATIC int scsi_try_host_reset(Scsi_Cmnd * SCpnt)
+/**
+ * scsi_try_host_reset - ask host adapter to reset itself
+ * @scmd:	SCSI cmd to send hsot reset.
+ **/
+static int scsi_try_host_reset(Scsi_Cmnd *scmd)
 {
 	unsigned long flags;
 	int rtn;
+	 Scsi_Device *sdev;
 
-	SCpnt->eh_state = FAILED;	/* Until we come up with something better */
-	SCpnt->owner = SCSI_OWNER_LOWLEVEL;
-	SCpnt->serial_number_at_timeout = SCpnt->serial_number;
+	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Host RST\n",
+					  __FUNCTION__));
+	scmd->owner = SCSI_OWNER_LOWLEVEL;
+	scmd->serial_number_at_timeout = scmd->serial_number;
 
-	if (SCpnt->host->hostt->eh_host_reset_handler == NULL) {
+	if (scmd->host->hostt->eh_host_reset_handler == NULL)
 		return FAILED;
+
+	spin_lock_irqsave(scmd->host->host_lock, flags);
+	rtn = scmd->host->hostt->eh_host_reset_handler(scmd);
+	spin_unlock_irqrestore(scmd->host->host_lock, flags);
+
+	if (rtn == SUCCESS) {
+		scsi_sleep(HOST_RESET_SETTLE_TIME);
+		/*
+		 * Mark all affected devices to expect a unit attention.
+		 */
+		for (sdev = scmd->host->host_queue; sdev; sdev = sdev->next)
+			if (scmd->channel == sdev->channel) {
+				sdev->was_reset = 1;
+				sdev->expecting_cc_ua = 1;
+			}
 	}
-	spin_lock_irqsave(SCpnt->host->host_lock, flags);
-	rtn = SCpnt->host->hostt->eh_host_reset_handler(SCpnt);
-	spin_unlock_irqrestore(SCpnt->host->host_lock, flags);
-
-	if (rtn == SUCCESS)
-		SCpnt->eh_state = SUCCESS;
-
-	/*
-	 * If we had a successful host reset, mark the command blocks to expect
-	 * a condition code of unit attention.
-	 */
-	scsi_sleep(HOST_RESET_SETTLE_TIME);
-	if (SCpnt->eh_state == SUCCESS) {
-		Scsi_Device *SDloop;
-		for (SDloop = SCpnt->host->host_queue; SDloop; SDloop = SDloop->next) {
-			SDloop->was_reset = 1;
-			SDloop->expecting_cc_ua = 1;
+	return rtn;
+}
+
+/**
+ * scsi_eh_bus_host_reset - send a bus reset and on failure try host reset
+ * @sc_todo:	a list of cmds that have failed.
+ * @shost:	scsi host being recovered.
+ **/
+static int scsi_eh_bus_host_reset(Scsi_Cmnd *sc_todo, struct Scsi_Host *shost)
+{
+	int rtn;
+	Scsi_Cmnd *scmd;
+	Scsi_Cmnd *chan_scmd;
+	unsigned int channel;
+
+	/*
+	 * if we ended up here, we have serious problems.  the only thing left
+	 * to try is a full bus reset.  if someone has grabbed the bus and isn't
+	 * letting go, then perhaps this will help.
+	 */
+	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Try Bus/Host RST\n",
+					  __FUNCTION__));
+
+	/* 
+	 * we really want to loop over the various channels, and do this on
+	 * a channel by channel basis.  we should also check to see if any
+	 * of the failed commands are on soft_reset devices, and if so, skip
+	 * the reset.  
+	 */
+
+	for (channel = 0; channel <= shost->max_channel; channel++) {
+		for (scmd = sc_todo; scmd; scmd = scmd->bh_next) {
+			if (!scsi_eh_eflags_chk(scmd, SCSI_EH_CMD_ERR))
+				continue;
+			if (channel == scmd->channel) {
+				chan_scmd = scmd;
+				break;
+				/*
+				 * FIXME add back in some support for
+				 * soft_reset devices.
+				 */
+			}
+		}
+
+		if (!scmd)
+			continue;
+
+		/*
+		 * we now know that we are able to perform a reset for the
+		 * channel that scmd points to.
+		 */
+		rtn = scsi_try_bus_reset(scmd);
+		if (rtn != SUCCESS)
+			rtn = scsi_try_host_reset(scmd);
+
+		if (rtn == SUCCESS) {
+			for (scmd = sc_todo; scmd; scmd = scmd->bh_next) {
+				if (!scsi_eh_eflags_chk(scmd, SCSI_EH_CMD_ERR)
+				    || channel != scmd->channel)
+					continue;
+				if (scsi_eh_tur(scmd)) {
+					rtn = scsi_eh_retry_cmd(scmd);
+
+					if (rtn == SUCCESS)
+						scsi_eh_finish_cmd(scmd, shost);
+				}
+			}
 		}
+
 	}
-	return SCpnt->eh_state;
+	return shost->host_failed;
 }
 
-/*
- * Function:  scsi_decide_disposition
+/**
+ * scsi_eh_offline_sdevs - offline scsi devices that fail to recover
+ * @sc_todo:	a list of cmds that have failed.
+ * @shost:	scsi host being recovered.
+ *
+ **/
+static void scsi_eh_offline_sdevs(Scsi_Cmnd *sc_todo, struct Scsi_Host *shost)
+{
+	Scsi_Cmnd *scmd;
+
+	for (scmd = sc_todo; scmd; scmd = scmd->bh_next) {
+		if (!scsi_eh_eflags_chk(scmd, SCSI_EH_CMD_ERR))
+			continue;
+
+		printk(KERN_INFO "%s: Device set offline - not"
+				"ready or command retry failed"
+				"after error recovery: host"
+				"%d channel %d id %d lun %d\n",
+				__FUNCTION__, shost->host_no,
+				scmd->device->channel,
+				scmd->device->id,
+				scmd->device->lun);
+		scmd->device->online = FALSE;
+		scsi_eh_finish_cmd(scmd, shost);
+	}
+	return;
+}
+
+/**
+ * scsi_sleep_done - timer function for scsi_sleep
+ * @sem:	semphore to signal
  *
- * Purpose:     Examine a command block that has come back from the low-level
- *              and figure out what to do next.
+ **/
+static
+void scsi_sleep_done(struct semaphore *sem)
+{
+	if (sem != NULL) {
+		up(sem);
+	}
+}
+
+/**
+ * scsi_sleep - sleep for specified timeout
+ * @timeout:	timeout value
  *
- * Returns:     SUCCESS         - pass on to upper level.
- *              FAILED          - pass on to error handler thread.
- *              RETRY           - command should be retried.
- *              SOFTERR         - command succeeded, but we need to log
- *                                a soft error.
- *
- * Notes:       This is *ONLY* called when we are examining the status
- *              after sending out the actual data command.  Any commands
- *              that are queued for error recovery (i.e. TEST_UNIT_READY)
- *              do *NOT* come through here.
- *
- *              NOTE - When this routine returns FAILED, it means the error
- *              handler thread is woken.  In cases where the error code
- *              indicates an error that doesn't require the error handler
- *              thread (i.e. we don't need to abort/reset), then this function
- *              should return SUCCESS.
- */
-int scsi_decide_disposition(Scsi_Cmnd * SCpnt)
+ **/
+void scsi_sleep(int timeout)
+{
+	DECLARE_MUTEX_LOCKED(sem);
+	struct timer_list timer;
+
+	init_timer(&timer);
+	timer.data = (unsigned long) &sem;
+	timer.expires = jiffies + timeout;
+	timer.function = (void (*)(unsigned long)) scsi_sleep_done;
+
+	SCSI_LOG_ERROR_RECOVERY(5, printk("sleeping for timer tics %d\n",
+					  timeout));
+
+	add_timer(&timer);
+
+	down(&sem);
+	del_timer(&timer);
+}
+
+/**
+ * scsi_decide_disposition - Disposition a cmd on return from LLD.
+ * @scmd:	SCSI cmd to examine.
+ *
+ * Notes:
+ *    This is *only* called when we are examining the status after sending
+ *    out the actual data command.  any commands that are queued for error
+ *    recovery (i.e. test_unit_ready) do *not* come through here.
+ *
+ *    When this routine returns failed, it means the error handler thread
+ *    is woken.  in cases where the error code indicates an error that
+ *    doesn't require the error handler read (i.e. we don't need to
+ *    abort/reset), then this function should return SUCCESS.
+ **/
+int scsi_decide_disposition(Scsi_Cmnd *scmd)
 {
 	int rtn;
 
 	/*
-	 * If the device is offline, then we clearly just pass the result back
+	 * if the device is offline, then we clearly just pass the result back
 	 * up to the top level.
 	 */
-	if (SCpnt->device->online == FALSE) {
-		SCSI_LOG_ERROR_RECOVERY(5, printk("scsi_error.c: device offline - report as SUCCESS\n"));
+	if (scmd->device->online == FALSE) {
+		SCSI_LOG_ERROR_RECOVERY(5, printk("%s: device offline - report"
+						  "as SUCCESS\n",
+						  __FUNCTION__));
 		return SUCCESS;
 	}
 	/*
-	 * First check the host byte, to see if there is anything in there
+	 * first check the host byte, to see if there is anything in there
 	 * that would indicate what we need to do.
 	 */
 
-	switch (host_byte(SCpnt->result)) {
+	switch (host_byte(scmd->result)) {
 	case DID_PASSTHROUGH:
 		/*
-		 * No matter what, pass this through to the upper layer.
-		 * Nuke this special code so that it looks like we are saying
-		 * DID_OK.
+		 * no matter what, pass this through to the upper layer.
+		 * nuke this special code so that it looks like we are saying
+		 * did_ok.
 		 */
-		SCpnt->result &= 0xff00ffff;
+		scmd->result &= 0xff00ffff;
 		return SUCCESS;
 	case DID_OK:
 		/*
-		 * Looks good.  Drop through, and check the next byte.
+		 * looks good.  drop through, and check the next byte.
 		 */
 		break;
 	case DID_NO_CONNECT:
 	case DID_BAD_TARGET:
 	case DID_ABORT:
 		/*
-		 * Note - this means that we just report the status back to the
-		 * top level driver, not that we actually think that it indicates
-		 * success.
+		 * note - this means that we just report the status back
+		 * to the top level driver, not that we actually think
+		 * that it indicates SUCCESS.
 		 */
 		return SUCCESS;
 		/*
-		 * When the low level driver returns DID_SOFT_ERROR,
+		 * when the low level driver returns did_soft_error,
 		 * it is responsible for keeping an internal retry counter 
-		 * in order to avoid endless loops (DB)
+		 * in order to avoid endless loops (db)
 		 *
-		 * Actually this is a bug in this function here.  We should
+		 * actually this is a bug in this function here.  we should
 		 * be mindful of the maximum number of retries specified
 		 * and not get stuck in a loop.
 		 */
@@ -979,37 +1288,37 @@
 		goto maybe_retry;
 
 	case DID_ERROR:
-		if (msg_byte(SCpnt->result) == COMMAND_COMPLETE &&
-		    status_byte(SCpnt->result) == RESERVATION_CONFLICT)
+		if (msg_byte(scmd->result) == COMMAND_COMPLETE &&
+		    status_byte(scmd->result) == RESERVATION_CONFLICT)
 			/*
 			 * execute reservation conflict processing code
 			 * lower down
 			 */
 			break;
-		/* FALLTHROUGH */
+		/* fallthrough */
 
 	case DID_BUS_BUSY:
 	case DID_PARITY:
 		goto maybe_retry;
 	case DID_TIME_OUT:
 		/*
-		 * When we scan the bus, we get timeout messages for
+		 * when we scan the bus, we get timeout messages for
 		 * these commands if there is no device available.
-		 * Other hosts report DID_NO_CONNECT for the same thing.
+		 * other hosts report did_no_connect for the same thing.
 		 */
-		if ((SCpnt->cmnd[0] == TEST_UNIT_READY ||
-		     SCpnt->cmnd[0] == INQUIRY)) {
+		if ((scmd->cmnd[0] == TEST_UNIT_READY ||
+		     scmd->cmnd[0] == INQUIRY)) {
 			return SUCCESS;
 		} else {
 			return FAILED;
 		}
 	case DID_RESET:
 		/*
-		 * In the normal case where we haven't initiated a reset, this is
-		 * a failure.
+		 * in the normal case where we haven't initiated a reset,
+		 * this is a failure.
 		 */
-		if (SCpnt->flags & IS_RESETTING) {
-			SCpnt->flags &= ~IS_RESETTING;
+		if (scmd->flags & IS_RESETTING) {
+			scmd->flags &= ~IS_RESETTING;
 			goto maybe_retry;
 		}
 		return SUCCESS;
@@ -1018,26 +1327,26 @@
 	}
 
 	/*
-	 * Next, check the message byte.
+	 * next, check the message byte.
 	 */
-	if (msg_byte(SCpnt->result) != COMMAND_COMPLETE) {
+	if (msg_byte(scmd->result) != COMMAND_COMPLETE) {
 		return FAILED;
 	}
 	/*
-	 * Now, check the status byte to see if this indicates anything special.
+	 * now, check the status byte to see if this indicates anything special.
 	 */
-	switch (status_byte(SCpnt->result)) {
+	switch (status_byte(scmd->result)) {
 	case QUEUE_FULL:
 		/*
-		 * The case of trying to send too many commands to a tagged queueing
-		 * device.
+		 * the case of trying to send too many commands to a
+		 * tagged queueing device.
 		 */
 		return ADD_TO_MLQUEUE;
 	case GOOD:
 	case COMMAND_TERMINATED:
 		return SUCCESS;
 	case CHECK_CONDITION:
-		rtn = scsi_check_sense(SCpnt);
+		rtn = scsi_check_sense(scmd);
 		if (rtn == NEEDS_RETRY) {
 			goto maybe_retry;
 		}
@@ -1046,17 +1355,17 @@
 	case INTERMEDIATE_GOOD:
 	case INTERMEDIATE_C_GOOD:
 		/*
-		 * Who knows?  FIXME(eric)
+		 * who knows?  FIXME(eric)
 		 */
 		return SUCCESS;
 	case BUSY:
 		goto maybe_retry;
 
 	case RESERVATION_CONFLICT:
-		printk("scsi%d (%d,%d,%d) : RESERVATION CONFLICT\n", 
-		       SCpnt->host->host_no, SCpnt->channel,
-		       SCpnt->device->id, SCpnt->device->lun);
-		return SUCCESS; /* causes immediate I/O error */
+		printk("scsi%d (%d,%d,%d) : reservation conflict\n", 
+		       scmd->host->host_no, scmd->channel,
+		       scmd->device->id, scmd->device->lun);
+		return SUCCESS; /* causes immediate i/o error */
 	default:
 		return FAILED;
 	}
@@ -1064,811 +1373,167 @@
 
       maybe_retry:
 
-	if ((++SCpnt->retries) < SCpnt->allowed) {
-		return NEEDS_RETRY;
-	} else {
-                /*
-                 * No more retries - report this one back to upper level.
-                 */
-		return SUCCESS;
-	}
-}
-
-/*
- * Function:  scsi_eh_completed_normally
- *
- * Purpose:     Examine a command block that has come back from the low-level
- *              and figure out what to do next.
- *
- * Returns:     SUCCESS         - pass on to upper level.
- *              FAILED          - pass on to error handler thread.
- *              RETRY           - command should be retried.
- *              SOFTERR         - command succeeded, but we need to log
- *                                a soft error.
- *
- * Notes:       This is *ONLY* called when we are examining the status
- *              of commands queued during error recovery.  The main
- *              difference here is that we don't allow for the possibility
- *              of retries here, and we are a lot more restrictive about what
- *              we consider acceptable.
- */
-STATIC int scsi_eh_completed_normally(Scsi_Cmnd * SCpnt)
-{
-	int rtn;
-
-	/*
-	 * First check the host byte, to see if there is anything in there
-	 * that would indicate what we need to do.
-	 */
-	if (host_byte(SCpnt->result) == DID_RESET) {
-		if (SCpnt->flags & IS_RESETTING) {
-			/*
-			 * OK, this is normal.  We don't know whether in fact
-			 * the command in question really needs to be rerun
-			 * or not - if this was the original data command then
-			 * the answer is yes, otherwise we just flag it as
-			 * success.
-			 */
-			SCpnt->flags &= ~IS_RESETTING;
-			goto maybe_retry;
-		}
-		/*
-		 * Rats.  We are already in the error handler, so we now
-		 * get to try and figure out what to do next.  If the sense
-		 * is valid, we have a pretty good idea of what to do.
-		 * If not, we mark it as failed.
-		 */
-		rtn = scsi_check_sense(SCpnt);
-		if (rtn == NEEDS_RETRY)
-			goto maybe_retry;
-		return rtn;
-	}
-	if (host_byte(SCpnt->result) != DID_OK) {
-		return FAILED;
-	}
-	/*
-	 * Next, check the message byte.
-	 */
-	if (msg_byte(SCpnt->result) != COMMAND_COMPLETE) {
-		return FAILED;
-	}
-	/*
-	 * Now, check the status byte to see if this indicates
-	 * anything special.
-	 */
-	switch (status_byte(SCpnt->result)) {
-	case GOOD:
-	case COMMAND_TERMINATED:
-		return SUCCESS;
-	case CHECK_CONDITION:
-		rtn = scsi_check_sense(SCpnt);
-		if (rtn == NEEDS_RETRY)
-			goto maybe_retry;
-		return rtn;
-	case CONDITION_GOOD:
-	case INTERMEDIATE_GOOD:
-	case INTERMEDIATE_C_GOOD:
-		/*
-		 * Who knows?  FIXME(eric)
-		 */
-		return SUCCESS;
-	case BUSY:
-	case QUEUE_FULL:
-	case RESERVATION_CONFLICT:
-	default:
-		return FAILED;
-	}
-	return FAILED;
-
- maybe_retry:
-	if ((++SCpnt->retries) < SCpnt->allowed) {
+	if ((++scmd->retries) < scmd->allowed) {
 		return NEEDS_RETRY;
 	} else {
-		/* No more retries - report this one back to upper level */
-		return SUCCESS;
-	}
-}
-
-/*
- * Function:  scsi_check_sense
- *
- * Purpose:     Examine sense information - give suggestion as to what
- *              we should do with it.
- */
-STATIC int scsi_check_sense(Scsi_Cmnd * SCpnt)
-{
-	if (!scsi_sense_valid(SCpnt)) {
-		return FAILED;
-	}
-	if (SCpnt->sense_buffer[2] & 0xe0)
-		return SUCCESS;
-
-	switch (SCpnt->sense_buffer[2] & 0xf) {
-	case NO_SENSE:
-		return SUCCESS;
-	case RECOVERED_ERROR:
-		return /* SOFT_ERROR */ SUCCESS;
-
-	case ABORTED_COMMAND:
-		return NEEDS_RETRY;
-	case NOT_READY:
-	case UNIT_ATTENTION:
-		/*
-		 * If we are expecting a CC/UA because of a bus reset that we
-		 * performed, treat this just as a retry.  Otherwise this is
-		 * information that we should pass up to the upper-level driver
-		 * so that we can deal with it there.
-		 */
-		if (SCpnt->device->expecting_cc_ua) {
-			SCpnt->device->expecting_cc_ua = 0;
-			return NEEDS_RETRY;
-		}
 		/*
-		 * If the device is in the process of becoming ready, we 
-		 * should retry.
+		 * no more retries - report this one back to upper level.
 		 */
-		if ((SCpnt->sense_buffer[12] == 0x04) &&
-			(SCpnt->sense_buffer[13] == 0x01)) {
-			return NEEDS_RETRY;
-		}
-		return SUCCESS;
-
-		/* these three are not supported */
-	case COPY_ABORTED:
-	case VOLUME_OVERFLOW:
-	case MISCOMPARE:
-		return SUCCESS;
-
-	case MEDIUM_ERROR:
-		return NEEDS_RETRY;
-
-	case ILLEGAL_REQUEST:
-	case BLANK_CHECK:
-	case DATA_PROTECT:
-	case HARDWARE_ERROR:
-	default:
 		return SUCCESS;
 	}
 }
 
-
-/*
- * Function:  scsi_restart_operations
- *
- * Purpose:     Restart IO operations to the specified host.
- *
- * Arguments:   host  - host that we are restarting
+/**
+ * scsi_restart_operations - restart io operations to the specified host.
+ * @shost:	Host we are restarting.
  *
- * Lock status: Assumed that locks are not held upon entry.
- *
- * Returns:     Nothing
- *
- * Notes:       When we entered the error handler, we blocked all further
- *              I/O to this device.  We need to 'reverse' this process.
- */
-STATIC void scsi_restart_operations(struct Scsi_Host *host)
+ * Notes:
+ *    When we entered the error handler, we blocked all further i/o to
+ *    this device.  we need to 'reverse' this process.
+ **/
+static void scsi_restart_operations(struct Scsi_Host *shost)
 {
-	Scsi_Device *SDpnt;
+	Scsi_Device *sdev;
 	unsigned long flags;
 
-	ASSERT_LOCK(host->host_lock, 0);
+	ASSERT_LOCK(shost->host_lock, 0);
 
 	/*
-	 * Next free up anything directly waiting upon the host.  This will be
-	 * requests for character device operations, and also for ioctls to queued
-	 * block devices.
+	 * next free up anything directly waiting upon the host.  this
+	 * will be requests for character device operations, and also for
+	 * ioctls to queued block devices.
 	 */
-	SCSI_LOG_ERROR_RECOVERY(5, printk("scsi_error.c: Waking up host to restart\n"));
+	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: waking up host to restart\n",
+					  __FUNCTION__));
 
-	wake_up(&host->host_wait);
+	wake_up(&shost->host_wait);
 
 	/*
-	 * Finally we need to re-initiate requests that may be pending.  We will
+	 * finally we need to re-initiate requests that may be pending.  we will
 	 * have had everything blocked while error handling is taking place, and
 	 * now that error recovery is done, we will need to ensure that these
 	 * requests are started.
 	 */
-	spin_lock_irqsave(host->host_lock, flags);
-	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
-		request_queue_t *q = &SDpnt->request_queue;
-
-		if ((host->can_queue > 0 && (host->host_busy >= host->can_queue))
-		    || (host->host_blocked)
-		    || (host->host_self_blocked)
-		    || (SDpnt->device_blocked)) {
+	spin_lock_irqsave(shost->host_lock, flags);
+	for (sdev = shost->host_queue; sdev; sdev = sdev->next) {
+		request_queue_t *q = &sdev->request_queue;
+
+		if ((shost->can_queue > 0 &&
+		     (shost->host_busy >= shost->can_queue))
+		    || (shost->host_blocked)
+		    || (shost->host_self_blocked)
+		    || (sdev->device_blocked)) {
 			break;
 		}
 
 		q->request_fn(q);
 	}
-	spin_unlock_irqrestore(host->host_lock, flags);
+	spin_unlock_irqrestore(shost->host_lock, flags);
 }
 
-/*
- * Function:  scsi_unjam_host
+/**
+ * scsi_unjam_host - Attempt to fix a host which has a cmd that failed.
+ * @shost:	Host to unjam.
  *
- * Purpose:     Attempt to fix a host which has a command that failed for
- *              some reason.
+ * Notes:
+ *    When we come in here, we *know* that all commands on the bus have
+ *    either completed, failed or timed out.  we also know that no further
+ *    commands are being sent to the host, so things are relatively quiet
+ *    and we have freedom to fiddle with things as we wish.
  *
- * Arguments:   host    - host that needs unjamming.
- * 
- * Returns:     Nothing
- *
- * Notes:       When we come in here, we *know* that all commands on the
- *              bus have either completed, failed or timed out.  We also
- *              know that no further commands are being sent to the host,
- *              so things are relatively quiet and we have freedom to
- *              fiddle with things as we wish.
- *
- * Additional note:  This is only the *default* implementation.  It is possible
- *              for individual drivers to supply their own version of this
- *              function, and if the maintainer wishes to do this, it is
- *              strongly suggested that this function be taken as a template
- *              and modified.  This function was designed to correctly handle
- *              problems for about 95% of the different cases out there, and
- *              it should always provide at least a reasonable amount of error
- *              recovery.
- *
- * Note3:       Any command marked 'FAILED' or 'TIMEOUT' must eventually
- *              have scsi_finish_command() called for it.  We do all of
- *              the retry stuff here, so when we restart the host after we
- *              return it should have an empty queue.
- */
-STATIC int scsi_unjam_host(struct Scsi_Host *host)
-{
-	int devices_failed;
-	int numfailed;
-	int ourrtn;
-	int rtn = FALSE;
-	int result;
-	Scsi_Cmnd *SCloop;
-	Scsi_Cmnd *SCpnt;
-	Scsi_Device *SDpnt;
-	Scsi_Device *SDloop;
-	Scsi_Cmnd *SCdone;
-	int timed_out;
-
-	ASSERT_LOCK(host->host_lock, 0);
-
-	SCdone = NULL;
-
-	/*
-	 * First, protect against any sort of race condition.  If any of the outstanding
-	 * commands are in states that indicate that we are not yet blocked (i.e. we are
-	 * not in a quiet state) then we got woken up in error.  If we ever end up here,
-	 * we need to re-examine some of the assumptions.
-	 */
-	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
-		for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
-			if (SCpnt->state == SCSI_STATE_FAILED
-			    || SCpnt->state == SCSI_STATE_TIMEOUT
-			    || SCpnt->state == SCSI_STATE_INITIALIZING
-			    || SCpnt->state == SCSI_STATE_UNUSED) {
-				continue;
-			}
-			/*
-			 * Rats.  Something is still floating around out there.  This could
-			 * be the result of the fact that the upper level drivers are still frobbing
-			 * commands that might have succeeded.  There are two outcomes.  One is that
-			 * the command block will eventually be freed, and the other one is that
-			 * the command will be queued and will be finished along the way.
-			 */
-			SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler prematurely woken - commands still active (%p %x %d)\n", SCpnt, SCpnt->state, SCpnt->target));
-
-/*
- *        panic("SCSI Error handler woken too early\n");
+ *    This is only the *default* implementation.  it is possible for
+ *    individual drivers to supply their own version of this function, and
+ *    if the maintainer wishes to do this, it is strongly suggested that
+ *    this function be taken as a template and modified.  this function
+ *    was designed to correctly handle problems for about 95% of the
+ *    different cases out there, and it should always provide at least a
+ *    reasonable amount of error recovery.
  *
- * This is no longer a problem, since now the code cares only about
- * SCSI_STATE_TIMEOUT and SCSI_STATE_FAILED.
- * Other states are useful only to release active commands when devices are
- * set offline. If (host->host_active == host->host_busy) we can safely assume
- * that there are no commands in state other then TIMEOUT od FAILED. (DB)
- *
- * FIXME:
- * It is not easy to release correctly commands according to their state when 
- * devices are set offline, when the state is neither TIMEOUT nor FAILED.
- * When a device is set offline, we can have some command with
- * rq_status=RQ_SCSY_BUSY, owner=SCSI_STATE_HIGHLEVEL, 
- * state=SCSI_STATE_INITIALIZING and the driver module cannot be released.
- * (DB, 17 May 1998)
- */
-		}
-	}
-
-	/*
-	 * Next, see if we need to request sense information.  if so,
-	 * then get it now, so we have a better idea of what to do.
-	 * FIXME(eric) this has the unfortunate side effect that if a host
-	 * adapter does not automatically request sense information, that we end
-	 * up shutting it down before we request it.  All hosts should be doing this
-	 * anyways, so for now all I have to say is tough noogies if you end up in here.
-	 * On second thought, this is probably a good idea.  We *really* want to give
-	 * authors an incentive to automatically request this.
-	 */
-	SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Checking to see if we need to request sense\n"));
-
-	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
-		for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
-			if (SCpnt->state != SCSI_STATE_FAILED || scsi_sense_valid(SCpnt)) {
-				continue;
-			}
-			SCSI_LOG_ERROR_RECOVERY(2, printk("scsi_unjam_host: Requesting sense for %d\n",
-							  SCpnt->target));
-			rtn = scsi_request_sense(SCpnt);
-			if (rtn != SUCCESS) {
-				continue;
-			}
-			SCSI_LOG_ERROR_RECOVERY(3, printk("Sense requested for %p - result %x\n",
-						  SCpnt, SCpnt->result));
-			SCSI_LOG_ERROR_RECOVERY(3, print_sense("bh", SCpnt));
-
-			result = scsi_decide_disposition(SCpnt);
-
-			/*
-			 * If the result was normal, then just pass it along to the
-			 * upper level.
-			 */
-			if (result == SUCCESS) {
-				SCpnt->host->host_failed--;
-				scsi_eh_finish_command(&SCdone, SCpnt);
-			}
-			if (result != NEEDS_RETRY) {
-				continue;
-			}
-			/* 
-			 * We only come in here if we want to retry a
-			 * command.  The test to see whether the command
-			 * should be retried should be keeping track of the
-			 * number of tries, so we don't end up looping, of
-			 * course.  
-			 */
-			SCpnt->state = NEEDS_RETRY;
-			rtn = scsi_eh_retry_command(SCpnt);
-			if (rtn != SUCCESS) {
-				continue;
-			}
-			/*
-			 * We eventually hand this one back to the top level.
-			 */
-			SCpnt->host->host_failed--;
-			scsi_eh_finish_command(&SCdone, SCpnt);
-		}
-	}
-
-	/*
-	 * Go through the list of commands and figure out where we stand and how bad things
-	 * really are.
-	 */
-	numfailed = 0;
-	timed_out = 0;
-	devices_failed = 0;
-	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
-		unsigned int device_error = 0;
-
-		for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
-			if (SCpnt->state == SCSI_STATE_FAILED) {
-				SCSI_LOG_ERROR_RECOVERY(5, printk("Command to ID %d failed\n",
-							 SCpnt->target));
-				numfailed++;
-				device_error++;
-			}
-			if (SCpnt->state == SCSI_STATE_TIMEOUT) {
-				SCSI_LOG_ERROR_RECOVERY(5, printk("Command to ID %d timedout\n",
-							 SCpnt->target));
-				timed_out++;
-				device_error++;
-			}
-		}
-		if (device_error > 0) {
-			devices_failed++;
-		}
-	}
-
-	SCSI_LOG_ERROR_RECOVERY(2, printk("Total of %d+%d commands on %d devices require eh work\n",
-				  numfailed, timed_out, devices_failed));
-
-	if (host->host_failed == 0) {
-		ourrtn = TRUE;
-		goto leave;
-	}
-	/*
-	 * Next, try and see whether or not it makes sense to try and abort
-	 * the running command.  This only works out to be the case if we have
-	 * one command that has timed out.  If the command simply failed, it
-	 * makes no sense to try and abort the command, since as far as the
-	 * host adapter is concerned, it isn't running.
-	 */
-
-	SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Checking to see if we want to try abort\n"));
-
-	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
-		for (SCloop = SDpnt->device_queue; SCloop; SCloop = SCloop->next) {
-			if (SCloop->state != SCSI_STATE_TIMEOUT) {
-				continue;
-			}
-			rtn = scsi_try_to_abort_command(SCloop, ABORT_TIMEOUT);
-			if (rtn == SUCCESS) {
-				rtn = scsi_test_unit_ready(SCloop);
-
-				if (rtn == SUCCESS && scsi_unit_is_ready(SCloop)) {
-					rtn = scsi_eh_retry_command(SCloop);
-
-					if (rtn == SUCCESS) {
-						SCloop->host->host_failed--;
-						scsi_eh_finish_command(&SCdone, SCloop);
-					}
-				}
-			}
-		}
-	}
-
-	/*
-	 * If we have corrected all of the problems, then we are done.
-	 */
-	if (host->host_failed == 0) {
-		ourrtn = TRUE;
-		goto leave;
-	}
-	/*
-	 * Either the abort wasn't appropriate, or it didn't succeed.
-	 * Now try a bus device reset.  Still, look to see whether we have
-	 * multiple devices that are jammed or not - if we have multiple devices,
-	 * it makes no sense to try BUS_DEVICE_RESET - we really would need
-	 * to try a BUS_RESET instead.
-	 *
-	 * Does this make sense - should we try BDR on each device individually?
-	 * Yes, definitely.
-	 */
-	SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Checking to see if we want to try BDR\n"));
-
-	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
-		for (SCloop = SDpnt->device_queue; SCloop; SCloop = SCloop->next) {
-			if (SCloop->state == SCSI_STATE_FAILED
-			    || SCloop->state == SCSI_STATE_TIMEOUT) {
-				break;
-			}
-		}
-
-		if (SCloop == NULL) {
-			continue;
-		}
-		/*
-		 * OK, we have a device that is having problems.  Try and send
-		 * a bus device reset to it.
-		 *
-		 * FIXME(eric) - make sure we handle the case where multiple
-		 * commands to the same device have failed. They all must
-		 * get properly restarted.
-		 */
-		rtn = scsi_try_bus_device_reset(SCloop, RESET_TIMEOUT);
-
-		if (rtn == SUCCESS) {
-			rtn = scsi_test_unit_ready(SCloop);
-
-			if (rtn == SUCCESS && scsi_unit_is_ready(SCloop)) {
-				rtn = scsi_eh_retry_command(SCloop);
-
-				if (rtn == SUCCESS) {
-					SCloop->host->host_failed--;
-					scsi_eh_finish_command(&SCdone, SCloop);
-				}
-			}
-		}
-	}
-
-	if (host->host_failed == 0) {
-		ourrtn = TRUE;
-		goto leave;
-	}
-	/*
-	 * If we ended up here, we have serious problems.  The only thing left
-	 * to try is a full bus reset.  If someone has grabbed the bus and isn't
-	 * letting go, then perhaps this will help.
-	 */
-	SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Try hard bus reset\n"));
-
-	/* 
-	 * We really want to loop over the various channels, and do this on
-	 * a channel by channel basis.  We should also check to see if any
-	 * of the failed commands are on soft_reset devices, and if so, skip
-	 * the reset.  
-	 */
-	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
-	      next_device:
-		for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
-			if (SCpnt->state != SCSI_STATE_FAILED
-			    && SCpnt->state != SCSI_STATE_TIMEOUT) {
-				continue;
-			}
-			/*
-			 * We have a failed command.  Make sure there are no other failed
-			 * commands on the same channel that are timed out and implement a
-			 * soft reset.
-			 */
-			for (SDloop = host->host_queue; SDloop; SDloop = SDloop->next) {
-				for (SCloop = SDloop->device_queue; SCloop; SCloop = SCloop->next) {
-					if (SCloop->channel != SCpnt->channel) {
-						continue;
-					}
-					if (SCloop->state != SCSI_STATE_FAILED
-					    && SCloop->state != SCSI_STATE_TIMEOUT) {
-						continue;
-					}
-					if (SDloop->soft_reset && SCloop->state == SCSI_STATE_TIMEOUT) {
-						/* 
-						 * If this device uses the soft reset option, and this
-						 * is one of the devices acting up, then our only
-						 * option is to wait a bit, since the command is
-						 * supposedly still running.  
-						 *
-						 * FIXME(eric) - right now we will just end up falling
-						 * through to the 'take device offline' case.
-						 *
-						 * FIXME(eric) - It is possible that the command completed
-						 * *after* the error recovery procedure started, and if this
-						 * is the case, we are worrying about nothing here.
-						 */
-
-						scsi_sleep(1 * HZ);
-						goto next_device;
-					}
-				}
-			}
-
-			/*
-			 * We now know that we are able to perform a reset for the
-			 * bus that SCpnt points to.  There are no soft-reset devices
-			 * with outstanding timed out commands.
-			 */
-			rtn = scsi_try_bus_reset(SCpnt);
-			if (rtn == SUCCESS) {
-				for (SDloop = host->host_queue; SDloop; SDloop = SDloop->next) {
-					for (SCloop = SDloop->device_queue; SCloop; SCloop = SCloop->next) {
-						if (SCloop->channel != SCpnt->channel) {
-							continue;
-						}
-						if (SCloop->state != SCSI_STATE_FAILED
-						    && SCloop->state != SCSI_STATE_TIMEOUT) {
-							continue;
-						}
-						rtn = scsi_test_unit_ready(SCloop);
-
-						if (rtn == SUCCESS && scsi_unit_is_ready(SCloop)) {
-							rtn = scsi_eh_retry_command(SCloop);
-
-							if (rtn == SUCCESS) {
-								SCpnt->host->host_failed--;
-								scsi_eh_finish_command(&SCdone, SCloop);
-							}
-						}
-						/*
-						 * If the bus reset worked, but we are still unable to
-						 * talk to the device, take it offline.
-						 * FIXME(eric) - is this really the correct thing to do?
-						 */
-						if (rtn != SUCCESS) {
-							printk(KERN_INFO "scsi: device set offline - not ready or command retry failed after bus reset: host %d channel %d id %d lun %d\n", SDloop->host->host_no, SDloop->channel, SDloop->id, SDloop->lun);
-
-							SDloop->online = FALSE;
-							SDloop->host->host_failed--;
-							scsi_eh_finish_command(&SCdone, SCloop);
-						}
-					}
-				}
-			}
-		}
-	}
-
-	if (host->host_failed == 0) {
-		ourrtn = TRUE;
-		goto leave;
-	}
-	/*
-	 * If we ended up here, we have serious problems.  The only thing left
-	 * to try is a full host reset - perhaps the firmware on the device
-	 * crashed, or something like that.
-	 *
-	 * It is assumed that a succesful host reset will cause *all* information
-	 * about the command to be flushed from both the host adapter *and* the
-	 * device.
-	 *
-	 * FIXME(eric) - it isn't clear that devices that implement the soft reset
-	 * option can ever be cleared except via cycling the power.  The problem is
-	 * that sending the host reset command will cause the host to forget
-	 * about the pending command, but the device won't forget.  For now, we
-	 * skip the host reset option if any of the failed devices are configured
-	 * to use the soft reset option.
-	 */
-	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
-	      next_device2:
-		for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
-			if (SCpnt->state != SCSI_STATE_FAILED
-			    && SCpnt->state != SCSI_STATE_TIMEOUT) {
-				continue;
-			}
-			if (SDpnt->soft_reset && SCpnt->state == SCSI_STATE_TIMEOUT) {
-				/* 
-				 * If this device uses the soft reset option, and this
-				 * is one of the devices acting up, then our only
-				 * option is to wait a bit, since the command is
-				 * supposedly still running.  
-				 *
-				 * FIXME(eric) - right now we will just end up falling
-				 * through to the 'take device offline' case.
-				 */
-				SCSI_LOG_ERROR_RECOVERY(3,
-							printk("scsi_unjam_host: Unable to try hard host reset\n"));
-
-				/*
-				 * Due to the spinlock, we will never get out of this
-				 * loop without a proper wait. (DB)
-				 */
-				scsi_sleep(1 * HZ);
-
-				goto next_device2;
-			}
-			SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Try hard host reset\n"));
-
-			/*
-			 * FIXME(eric) - we need to obtain a valid SCpnt to perform this call.
-			 */
-			rtn = scsi_try_host_reset(SCpnt);
-			if (rtn == SUCCESS) {
-				/*
-				 * FIXME(eric) we assume that all commands are flushed from the
-				 * controller.  We should get a DID_RESET for all of the commands
-				 * that were pending.  We should ignore these so that we can
-				 * guarantee that we are in a consistent state.
-				 *
-				 * I believe this to be the case right now, but this needs to be
-				 * tested.
-				 */
-				for (SDloop = host->host_queue; SDloop; SDloop = SDloop->next) {
-					for (SCloop = SDloop->device_queue; SCloop; SCloop = SCloop->next) {
-						if (SCloop->state != SCSI_STATE_FAILED
-						    && SCloop->state != SCSI_STATE_TIMEOUT) {
-							continue;
-						}
-						rtn = scsi_test_unit_ready(SCloop);
-
-						if (rtn == SUCCESS && scsi_unit_is_ready(SCloop)) {
-							rtn = scsi_eh_retry_command(SCloop);
-
-							if (rtn == SUCCESS) {
-								SCpnt->host->host_failed--;
-								scsi_eh_finish_command(&SCdone, SCloop);
-							}
-						}
-						if (rtn != SUCCESS) {
-							printk(KERN_INFO "scsi: device set offline - not ready or command retry failed after host reset: host %d channel %d id %d lun %d\n", SDloop->host->host_no, SDloop->channel, SDloop->id, SDloop->lun);
-							SDloop->online = FALSE;
-							SDloop->host->host_failed--;
-							scsi_eh_finish_command(&SCdone, SCloop);
-						}
-					}
-				}
-			}
-		}
-	}
+ *    Any command marked 'failed' or 'timeout' must eventually have
+ *    scsi_finish_cmd() called for it.  we do all of the retry stuff
+ *    here, so when we restart the host after we return it should have an
+ *    empty queue.
+ **/
+static void scsi_unjam_host(struct Scsi_Host *shost)
+{
+	Scsi_Cmnd *sc_todo = NULL;
+	Scsi_Cmnd *scmd;
 
 	/*
-	 * If we solved all of the problems, then let's rev up the engines again.
+	 * Is this assert really ok anymore (andmike). Should we at least
+	 * be using spin_lock_unlocked.
 	 */
-	if (host->host_failed == 0) {
-		ourrtn = TRUE;
-		goto leave;
-	}
-	/*
-	 * If the HOST RESET failed, then for now we assume that the entire host
-	 * adapter is too hosed to be of any use.  For our purposes, however, it is
-	 * easier to simply take the devices offline that correspond to commands
-	 * that failed.
-	 */
-	SCSI_LOG_ERROR_RECOVERY(1, printk("scsi_unjam_host: Take device offline\n"));
-
-	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
-		for (SCloop = SDpnt->device_queue; SCloop; SCloop = SCloop->next) {
-			if (SCloop->state == SCSI_STATE_FAILED || SCloop->state == SCSI_STATE_TIMEOUT) {
-				SDloop = SCloop->device;
-				if (SDloop->online == TRUE) {
-					printk(KERN_INFO "scsi: device set offline - command error recover failed: host %d channel %d id %d lun %d\n", SDloop->host->host_no, SDloop->channel, SDloop->id, SDloop->lun);
-					SDloop->online = FALSE;
-				}
-
-				/*
-				 * This should pass the failure up to the top level driver, and
-				 * it will have to try and do something intelligent with it.
-				 */
-				SCloop->host->host_failed--;
+	ASSERT_LOCK(shost->host_lock, 0);
 
-				if (SCloop->state == SCSI_STATE_TIMEOUT) {
-					SCloop->result |= (DRIVER_TIMEOUT << 24);
-				}
-				SCSI_LOG_ERROR_RECOVERY(3, printk("Finishing command for device %d %x\n",
-				    SDloop->id, SCloop->result));
-
-				scsi_eh_finish_command(&SCdone, SCloop);
-			}
-		}
-	}
+	scsi_eh_get_failed(&sc_todo, shost);
 
-	if (host->host_failed != 0) {
-		panic("scsi_unjam_host: Miscount of number of failed commands.\n");
-	}
-	SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Returning\n"));
+	if (scsi_eh_get_sense(sc_todo, shost))
+		if (scsi_eh_abort_cmd(sc_todo, shost))
+			if (scsi_eh_bus_device_reset(sc_todo, shost))
+				if(scsi_eh_bus_host_reset(sc_todo, shost))
+					scsi_eh_offline_sdevs(sc_todo, shost);
 
-	ourrtn = FALSE;
+	BUG_ON(shost->host_failed);
 
-      leave:
 
 	/*
-	 * We should have a list of commands that we 'finished' during the course of
-	 * error recovery.  This should be the same as the list of commands that timed out
-	 * or failed.  We are currently holding these things in a linked list - we didn't
-	 * put them in the bottom half queue because we wanted to keep things quiet while
-	 * we were working on recovery, and passing them up to the top level could easily
-	 * cause the top level to try and queue something else again.
+	 * We are currently holding these things in a linked list - we
+	 * didn't put them in the bottom half queue because we wanted to
+	 * keep things quiet while we were working on recovery, and
+	 * passing them up to the top level could easily cause the top
+	 * level to try and queue something else again.
 	 *
-	 * Start by marking that the host is no longer in error recovery.
+	 * start by marking that the host is no longer in error recovery.
 	 */
-	host->in_recovery = 0;
+	shost->in_recovery = 0;
 
 	/*
-	 * Take the list of commands, and stick them in the bottom half queue.
-	 * The current implementation of scsi_done will do this for us - if need
+	 * take the list of commands, and stick them in the bottom half queue.
+	 * the current implementation of scsi_done will do this for us - if need
 	 * be we can create a special version of this function to do the
 	 * same job for us.
 	 */
-	for (SCpnt = SCdone; SCpnt != NULL; SCpnt = SCdone) {
-		SCdone = SCpnt->bh_next;
-		SCpnt->bh_next = NULL;
-                /*
-                 * Oh, this is a vile hack.  scsi_done() expects a timer
-                 * to be running on the command.  If there isn't, it assumes
-                 * that the command has actually timed out, and a timer
-                 * handler is running.  That may well be how we got into
-                 * this fix, but right now things are stable.  We add
-                 * a timer back again so that we can report completion.
-                 * scsi_done() will immediately remove said timer from
-                 * the command, and then process it.
-                 */
-		scsi_add_timer(SCpnt, 100, scsi_eh_times_out);
-		scsi_done(SCpnt);
+	for (scmd = sc_todo; scmd; scmd = sc_todo) {
+		sc_todo = scmd->bh_next;
+		scmd->bh_next = NULL;
+		/*
+		 * Oh, this is a vile hack.  scsi_done() expects a timer
+		 * to be running on the command.  If there isn't, it assumes
+		 * that the command has actually timed out, and a timer
+		 * handler is running.  That may well be how we got into
+		 * this fix, but right now things are stable.  We add
+		 * a timer back again so that we can report completion.
+		 * scsi_done() will immediately remove said timer from
+		 * the command, and then process it.
+		 */
+		scsi_add_timer(scmd, 100, scsi_eh_times_out);
+		scsi_done(scmd);
 	}
 
-	return (ourrtn);
 }
 
-
-/*
- * Function:  scsi_error_handler
- *
- * Purpose:     Handle errors/timeouts of scsi commands, try and clean up
- *              and unjam the bus, and restart things.
- *
- * Arguments:   host    - host for which we are running.
+/**
+ * scsi_error_handler - Handle errors/timeouts of SCSI cmds.
+ * @data:	Host for which we are running.
  *
- * Returns:     Never returns.
- *
- * Notes:       This is always run in the context of a kernel thread.  The
- *              idea is that we start this thing up when the kernel starts
- *              up (one per host that we detect), and it immediately goes to
- *              sleep and waits for some event (i.e. failure).  When this
- *              takes place, we have the job of trying to unjam the bus
- *              and restarting things.
- *
- */
+ * Notes:
+ *    This is always run in the context of a kernel thread.  The idea is
+ *    that we start this thing up when the kernel starts up (one per host
+ *    that we detect), and it immediately goes to sleep and waits for some
+ *    event (i.e. failure).  When this takes place, we have the job of
+ *    trying to unjam the bus and restarting things.
+ **/
 void scsi_error_handler(void *data)
 {
-	struct Scsi_Host *host = (struct Scsi_Host *) data;
+	struct Scsi_Host *shost = (struct Scsi_Host *) data;
 	int rtn;
 	DECLARE_MUTEX_LOCKED(sem);
 
-        /*
-         * We only listen to signals if the HA was loaded as a module.
-         * If the HA was compiled into the kernel, then we don't listen
-         * to any signals.
-         */
+	/*
+	 * We only listen to signals if the HA was loaded as a module.
+	 * If the HA was compiled into the kernel, then we don't listen
+	 * to any signals.
+	 */
 	siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
 
 	lock_kernel();
@@ -1883,19 +1548,20 @@
 	 * Set the name of this process.
 	 */
 
-	sprintf(current->comm, "scsi_eh_%d", host->host_no);
+	sprintf(current->comm, "scsi_eh_%d", shost->host_no);
 
-	host->eh_wait = &sem;
-	host->ehandler = current;
+	shost->eh_wait = &sem;
+	shost->ehandler = current;
 
 	unlock_kernel();
 
 	/*
 	 * Wake up the thread that created us.
 	 */
-	SCSI_LOG_ERROR_RECOVERY(3, printk("Wake up parent %d\n", host->eh_notify->count.counter));
+	SCSI_LOG_ERROR_RECOVERY(3, printk("Wake up parent %d\n",
+					  shost->eh_notify->count.counter));
 
-	up(host->eh_notify);
+	up(shost->eh_notify);
 
 	while (1) {
 		/*
@@ -1920,20 +1586,20 @@
 
 		SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler waking up\n"));
 
-		host->eh_active = 1;
+		shost->eh_active = 1;
 
 		/*
 		 * We have a host that is failing for some reason.  Figure out
 		 * what we need to do to get it up and online again (if we can).
 		 * If we fail, we end up taking the thing offline.
 		 */
-		if (host->hostt->eh_strategy_handler != NULL) {
-			rtn = host->hostt->eh_strategy_handler(host);
+		if (shost->hostt->eh_strategy_handler != NULL) {
+			rtn = shost->hostt->eh_strategy_handler(shost);
 		} else {
-			rtn = scsi_unjam_host(host);
+			scsi_unjam_host(shost);
 		}
 
-		host->eh_active = 0;
+		shost->eh_active = 0;
 
 		/*
 		 * Note - if the above fails completely, the action is to take
@@ -1942,7 +1608,7 @@
 		 * restart, we restart any I/O to any other devices on the bus
 		 * which are still online.
 		 */
-		scsi_restart_operations(host);
+		scsi_restart_operations(shost);
 
 	}
 
@@ -1951,7 +1617,7 @@
 	/*
 	 * Make sure that nobody tries to wake us up again.
 	 */
-	host->eh_wait = NULL;
+	shost->eh_wait = NULL;
 
 	/*
 	 * Knock this down too.  From this point on, the host is flying
@@ -1959,9 +1625,9 @@
 	 * that's fine.  If the user sent a signal to this thing, we are
 	 * potentially in real danger.
 	 */
-	host->in_recovery = 0;
-	host->eh_active = 0;
-	host->ehandler = NULL;
+	shost->in_recovery = 0;
+	shost->eh_active = 0;
+	shost->ehandler = NULL;
 
 	/*
 	 * If anyone is waiting for us to exit (i.e. someone trying to unload
@@ -1971,41 +1637,39 @@
 	 * the error handling thread wakes up that it would just exit without
 	 * needing to touch any memory associated with the driver itself.
 	 */
-	if (host->eh_notify != NULL)
-		up(host->eh_notify);
+	if (shost->eh_notify != NULL)
+		up(shost->eh_notify);
 }
 
-/*
- * Function:	scsi_new_reset
- *
- * Purpose:	Send requested reset to a bus or device at any phase.
- *
- * Arguments:	SCpnt	- command ptr to send reset with (usually a dummy)
- *		flag - reset type (see scsi.h)
- *
- * Returns:	SUCCESS/FAILURE.
- *
- * Notes:	This is used by the SCSI Generic driver to provide
- *		Bus/Device reset capability.
- */
-int
-scsi_new_reset(Scsi_Cmnd *SCpnt, int flag)
+/**
+ * scsi_new_reset - Send reset to a bus or device at any phase.
+ * @scmd:	Cmd to send reset with (usually a dummy)
+ * @flag:	Reset type.
+ *
+ * Description:
+ *    This is used by the SCSI Generic driver to provide Bus/Device reset
+ *    capability.
+ *
+ * Return value:
+ *    SUCCESS/FAILED.
+ **/
+int scsi_new_reset(Scsi_Cmnd *scmd, int flag)
 {
 	int rtn;
 
 	switch(flag) {
 	case SCSI_TRY_RESET_DEVICE:
-		rtn = scsi_try_bus_device_reset(SCpnt, 0);
+		rtn = scsi_try_bus_device_reset(scmd);
 		if (rtn == SUCCESS)
 			break;
 		/* FALLTHROUGH */
 	case SCSI_TRY_RESET_BUS:
-		rtn = scsi_try_bus_reset(SCpnt);
+		rtn = scsi_try_bus_reset(scmd);
 		if (rtn == SUCCESS)
 			break;
 		/* FALLTHROUGH */
 	case SCSI_TRY_RESET_HOST:
-		rtn = scsi_try_host_reset(SCpnt);
+		rtn = scsi_try_host_reset(scmd);
 		break;
 	default:
 		rtn = FAILED;
diff -Nru a/drivers/scsi/scsi_merge.c b/drivers/scsi/scsi_merge.c
--- a/drivers/scsi/scsi_merge.c	Tue Oct  1 00:08:20 2002
+++ b/drivers/scsi/scsi_merge.c	Tue Oct  1 00:08:20 2002
@@ -140,7 +140,7 @@
 	 * Enable highmem I/O, if appropriate.
 	 */
 	bounce_limit = BLK_BOUNCE_HIGH;
-	if (SHpnt->highmem_io && (SDpnt->type == TYPE_DISK)) {
+	if (SHpnt->highmem_io) {
 		if (!PCI_DMA_BUS_IS_PHYS)
 			/* Platforms with virtual-DMA translation
  			 * hardware have no practical limit.
diff -Nru a/drivers/scsi/sd.c b/drivers/scsi/sd.c
--- a/drivers/scsi/sd.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/scsi/sd.c	Tue Oct  1 00:08:15 2002
@@ -1297,30 +1297,23 @@
 {
 	Scsi_Disk *sdkp;
 	int dsk_nr;
-	char diskname[6];
 	unsigned long iflags;
-	struct {
-		struct gendisk disk;
-		char name[5];
-	} *p;
 	struct gendisk *gd;
 
 	if ((NULL == sdp) ||
 	    ((sdp->type != TYPE_DISK) && (sdp->type != TYPE_MOD)))
 		return 0;
 
-	p = kmalloc(sizeof(*p), GFP_KERNEL);
-	if (!p)
+	gd = alloc_disk();
+	if (!gd)
 		return 1;
-	memset(p, 0, sizeof(*p));
-	gd = &p->disk;
 
 	SCSI_LOG_HLQUEUE(3, printk("sd_attach: scsi device: <%d,%d,%d,%d>\n", 
 			 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun));
 	if (sd_template.nr_dev >= sd_template.dev_max) {
 		sdp->attached--;
 		printk(KERN_ERR "sd_init: no more room for device\n");
-		kfree(p);
+		put_disk(gd);
 		return 1;
 	}
 
@@ -1340,7 +1333,7 @@
 	if (dsk_nr >= sd_template.dev_max) {
 		/* panic("scsi_devices corrupt (sd)");  overkill */
 		printk(KERN_ERR "sd_init: sd_dsk_arr corrupted\n");
-		kfree(p);
+		put_disk(gd);
 		return 1;
 	}
 
@@ -1351,18 +1344,16 @@
 	gd->minor_shift = 4;
 	gd->fops = &sd_fops;
 	if (dsk_nr > 26)
-		sprintf(p->name, "sd%c%c", 'a'+dsk_nr/26-1, 'a'+dsk_nr%26);
+		sprintf(gd->disk_name, "sd%c%c",'a'+dsk_nr/26-1,'a'+dsk_nr%26);
 	else
-		sprintf(p->name, "sd%c", 'a'+dsk_nr%26);
-	gd->major_name = p->name;
+		sprintf(gd->disk_name, "sd%c",'a'+dsk_nr%26);
         gd->flags = sdp->removable ? GENHD_FL_REMOVABLE : 0;
         gd->driverfs_dev = &sdp->sdev_driverfs_dev;
         gd->flags |= GENHD_FL_DRIVERFS | GENHD_FL_DEVFS;
 	sd_disks[dsk_nr] = gd;
-	sd_dskname(dsk_nr, diskname);
 	printk(KERN_NOTICE "Attached scsi %sdisk %s at scsi%d, channel %d, "
 	       "id %d, lun %d\n", sdp->removable ? "removable " : "",
-	       diskname, sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
+	       gd->disk_name, sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
 	return 0;
 }
 
@@ -1422,7 +1413,7 @@
 	sdp->attached--;
 	sd_template.dev_noticed--;
 	sd_template.nr_dev--;
-	kfree(sd_disks[dsk_nr]);
+	put_disk(sd_disks[dsk_nr]);
 	sd_disks[dsk_nr] = NULL;
 }
 
diff -Nru a/drivers/scsi/sg.c b/drivers/scsi/sg.c
--- a/drivers/scsi/sg.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/scsi/sg.c	Tue Oct  1 00:08:17 2002
@@ -82,6 +82,19 @@
 
 #define SG_MAX_DEVS_MASK ((1U << KDEV_MINOR_BITS) - 1)
 
+/*
+ * Suppose you want to calculate the formula muldiv(x,m,d)=int(x * m / d)
+ * Then when using 32 bit integers x * m may overflow during the calculation.
+ * Replacing muldiv(x) by muldiv(x)=((x % d) * m) / d + int(x / d) * m
+ * calculates the same, but prevents the overflow when both m and d
+ * are "small" numbers (like HZ and USER_HZ).
+ * Of course an overflow is inavoidable if the result of muldiv doesn't fit
+ * in 32 bits.
+ */
+#define MULDIV(X,MUL,DIV) ((((X % DIV) * MUL) / DIV) + ((X / DIV) * MUL))
+
+#define SG_DEFAULT_TIMEOUT MULDIV(SG_DEFAULT_TIMEOUT_USER, HZ, USER_HZ)
+
 int sg_big_buff = SG_DEF_RESERVED_SIZE;
 /* N.B. This variable is readable and writeable via
    /proc/scsi/sg/def_reserved_size . Each time sg_open() is called a buffer
@@ -150,7 +163,8 @@
 	struct sg_device *parentdp;	/* owning device */
 	wait_queue_head_t read_wait;	/* queue read until command done */
 	rwlock_t rq_list_lock;	/* protect access to list in req_arr */
-	int timeout;		/* defaults to SG_DEFAULT_TIMEOUT */
+	int timeout;		/* defaults to SG_DEFAULT_TIMEOUT      */
+	int timeout_user;	/* defaults to SG_DEFAULT_TIMEOUT_USER */
 	Sg_scatter_hold reserve;	/* buffer held for this file descriptor */
 	unsigned save_scat_len;	/* original length of trunc. scat. element */
 	Sg_request *headrp;	/* head of request slist, NULL->empty */
@@ -790,10 +804,15 @@
 			return result;
 		if (val < 0)
 			return -EIO;
-		sfp->timeout = val;
+		if (val >= MULDIV (INT_MAX, USER_HZ, HZ))
+		    val = MULDIV (INT_MAX, USER_HZ, HZ);
+		sfp->timeout_user = val;
+		sfp->timeout = MULDIV (val, HZ, USER_HZ);
+
 		return 0;
 	case SG_GET_TIMEOUT:	/* N.B. User receives timeout as return value */
-		return sfp->timeout;	/* strange ..., for backward compatibility */
+				/* strange ..., for backward compatibility */
+		return sfp->timeout_user;
 	case SG_SET_FORCE_LOW_DMA:
 		result = get_user(val, (int *) arg);
 		if (result)
@@ -2432,6 +2451,7 @@
 	sfp->rq_list_lock = RW_LOCK_UNLOCKED;
 
 	sfp->timeout = SG_DEFAULT_TIMEOUT;
+	sfp->timeout_user = SG_DEFAULT_TIMEOUT_USER;
 	sfp->force_packid = SG_DEF_FORCE_PACK_ID;
 	sfp->low_dma = (SG_DEF_FORCE_LOW_DMA == 0) ?
 	    sdp->device->host->unchecked_isa_dma : 1;
diff -Nru a/drivers/scsi/sr.c b/drivers/scsi/sr.c
--- a/drivers/scsi/sr.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/scsi/sr.c	Tue Oct  1 00:08:16 2002
@@ -749,18 +749,17 @@
 		 * with loadable modules. */
 		if (cd->disk)
 			continue;
-		disk = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
+		disk = alloc_disk();
 		if (!disk)
 			continue;
 		if (cd->disk) {
-			kfree(disk);
+			put_disk(disk);
 			continue;
 		}
-		memset(disk, 0, sizeof(struct gendisk));
 		disk->major = MAJOR_NR;
 		disk->first_minor = i;
 		disk->minor_shift = 0;
-		disk->major_name = cd->cdi.name;
+		strcpy(disk->disk_name, cd->cdi.name);
 		disk->fops = &sr_bdops;
 		disk->flags = GENHD_FL_CD;
 		cd->disk = disk;
@@ -826,7 +825,7 @@
 			 * We should be kind to our buffer cache, however.
 			 */
 			del_gendisk(cpnt->disk);
-			kfree(cpnt->disk);
+			put_disk(cpnt->disk);
 			cpnt->disk = NULL;
 
 			/*
diff -Nru a/drivers/scsi/st.c b/drivers/scsi/st.c
--- a/drivers/scsi/st.c	Tue Oct  1 00:08:18 2002
+++ b/drivers/scsi/st.c	Tue Oct  1 00:08:18 2002
@@ -12,13 +12,13 @@
    Copyright 1992 - 2002 Kai Makisara
    email Kai.Makisara@metla.fi
 
-   Last modified: Thu Aug 22 21:57:07 2002 by makisara
+   Last modified: Sun Sep 29 22:29:16 2002 by makisara
    Some small formal changes - aeb, 950809
 
    Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
  */
 
-static char *verstr = "20020822";
+static char *verstr = "20020929";
 
 #include <linux/module.h>
 
@@ -3738,51 +3738,6 @@
 	scsi_tapes[i] = tpnt;
 	dev_num = i;
 
-	for (mode = 0; mode < ST_NBR_MODES; ++mode) {
-	    char name[8];
-	    static char *formats[ST_NBR_MODES] ={"", "l", "m", "a"};
-
-	    /*  Rewind entry  */
-	    sprintf (name, "mt%s", formats[mode]);
-	    sprintf(tpnt->driverfs_dev_r[mode].bus_id, "%s:%s", 
-		    SDp->sdev_driverfs_dev.bus_id, name);
-	    sprintf(tpnt->driverfs_dev_r[mode].name, "%s%s", 
-		    SDp->sdev_driverfs_dev.name, name);
-	    tpnt->driverfs_dev_r[mode].parent = &SDp->sdev_driverfs_dev;
-	    tpnt->driverfs_dev_r[mode].bus = &scsi_driverfs_bus_type;
-	    tpnt->driverfs_dev_r[mode].driver_data =
-			(void *)(long)__mkdev(MAJOR_NR, i + (mode << 5));
-	    device_register(&tpnt->driverfs_dev_r[mode]);
-	    device_create_file(&tpnt->driverfs_dev_r[mode], 
-			       &dev_attr_type);
-	    device_create_file(&tpnt->driverfs_dev_r[mode], &dev_attr_kdev);
-	    tpnt->de_r[mode] =
-		devfs_register (SDp->de, name, DEVFS_FL_DEFAULT,
-				MAJOR_NR, i + (mode << 5),
-				S_IFCHR | S_IRUGO | S_IWUGO,
-				&st_fops, NULL);
-	    /*  No-rewind entry  */
-	    sprintf (name, "mt%sn", formats[mode]);
-	    sprintf(tpnt->driverfs_dev_n[mode].bus_id, "%s:%s", 
-		    SDp->sdev_driverfs_dev.bus_id, name);
-	    sprintf(tpnt->driverfs_dev_n[mode].name, "%s%s", 
-		    SDp->sdev_driverfs_dev.name, name);
-	    tpnt->driverfs_dev_n[mode].parent= &SDp->sdev_driverfs_dev;
-	    tpnt->driverfs_dev_n[mode].bus = &scsi_driverfs_bus_type;
-	    tpnt->driverfs_dev_n[mode].driver_data =
-			(void *)(long)__mkdev(MAJOR_NR, i + (mode << 5) + 128);
-	    device_register(&tpnt->driverfs_dev_n[mode]);
-	    device_create_file(&tpnt->driverfs_dev_n[mode], 
-			       &dev_attr_type);
-	    device_create_file(&tpnt->driverfs_dev_n[mode], 
-			       &dev_attr_kdev);
-	    tpnt->de_n[mode] =
-		devfs_register (SDp->de, name, DEVFS_FL_DEFAULT,
-				MAJOR_NR, i + (mode << 5) + 128,
-				S_IFCHR | S_IRUGO | S_IWUGO,
-				&st_fops, NULL);
-	}
-	devfs_register_tape (tpnt->de_r[0]);
 	tpnt->device = SDp;
 	if (SDp->scsi_level <= 2)
 		tpnt->tape_type = MT_ISSCSI1;
@@ -3863,6 +3818,53 @@
 
 	st_template.nr_dev++;
 	write_unlock(&st_dev_arr_lock);
+
+	for (mode = 0; mode < ST_NBR_MODES; ++mode) {
+	    char name[8];
+	    static char *formats[ST_NBR_MODES] ={"", "l", "m", "a"};
+
+	    /*  Rewind entry  */
+	    sprintf (name, "mt%s", formats[mode]);
+	    sprintf(tpnt->driverfs_dev_r[mode].bus_id, "%s:%s", 
+		    SDp->sdev_driverfs_dev.bus_id, name);
+	    sprintf(tpnt->driverfs_dev_r[mode].name, "%s%s", 
+		    SDp->sdev_driverfs_dev.name, name);
+	    tpnt->driverfs_dev_r[mode].parent = &SDp->sdev_driverfs_dev;
+	    tpnt->driverfs_dev_r[mode].bus = &scsi_driverfs_bus_type;
+	    tpnt->driverfs_dev_r[mode].driver_data =
+			(void *)(long)__mkdev(MAJOR_NR, i + (mode << 5));
+	    device_register(&tpnt->driverfs_dev_r[mode]);
+	    device_create_file(&tpnt->driverfs_dev_r[mode], 
+			       &dev_attr_type);
+	    device_create_file(&tpnt->driverfs_dev_r[mode], &dev_attr_kdev);
+	    tpnt->de_r[mode] =
+		devfs_register (SDp->de, name, DEVFS_FL_DEFAULT,
+				MAJOR_NR, i + (mode << 5),
+				S_IFCHR | S_IRUGO | S_IWUGO,
+				&st_fops, NULL);
+	    /*  No-rewind entry  */
+	    sprintf (name, "mt%sn", formats[mode]);
+	    sprintf(tpnt->driverfs_dev_n[mode].bus_id, "%s:%s", 
+		    SDp->sdev_driverfs_dev.bus_id, name);
+	    sprintf(tpnt->driverfs_dev_n[mode].name, "%s%s", 
+		    SDp->sdev_driverfs_dev.name, name);
+	    tpnt->driverfs_dev_n[mode].parent= &SDp->sdev_driverfs_dev;
+	    tpnt->driverfs_dev_n[mode].bus = &scsi_driverfs_bus_type;
+	    tpnt->driverfs_dev_n[mode].driver_data =
+			(void *)(long)__mkdev(MAJOR_NR, i + (mode << 5) + 128);
+	    device_register(&tpnt->driverfs_dev_n[mode]);
+	    device_create_file(&tpnt->driverfs_dev_n[mode], 
+			       &dev_attr_type);
+	    device_create_file(&tpnt->driverfs_dev_n[mode], 
+			       &dev_attr_kdev);
+	    tpnt->de_n[mode] =
+		devfs_register (SDp->de, name, DEVFS_FL_DEFAULT,
+				MAJOR_NR, i + (mode << 5) + 128,
+				S_IFCHR | S_IRUGO | S_IWUGO,
+				&st_fops, NULL);
+	}
+	devfs_register_tape (tpnt->de_r[0]);
+
 	printk(KERN_WARNING
 	"Attached scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n",
 	       dev_num, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
@@ -3893,13 +3895,21 @@
 			for (mode = 0; mode < ST_NBR_MODES; ++mode) {
 				devfs_unregister (tpnt->de_r[mode]);
 				tpnt->de_r[mode] = NULL;
+				devfs_unregister (tpnt->de_n[mode]);
+				tpnt->de_n[mode] = NULL;
+			}
+			scsi_tapes[i] = 0;
+			SDp->attached--;
+			st_template.nr_dev--;
+			st_template.dev_noticed--;
+			write_unlock(&st_dev_arr_lock);
+
+			for (mode = 0; mode < ST_NBR_MODES; ++mode) {
 				device_remove_file(&tpnt->driverfs_dev_r[mode],
 						   &dev_attr_type);
 				device_remove_file(&tpnt->driverfs_dev_r[mode],
 						   &dev_attr_kdev);
 				put_device(&tpnt->driverfs_dev_r[mode]);
-				devfs_unregister (tpnt->de_n[mode]);
-				tpnt->de_n[mode] = NULL;
 				device_remove_file(&tpnt->driverfs_dev_n[mode],
 						   &dev_attr_type);
 				device_remove_file(&tpnt->driverfs_dev_n[mode],
@@ -3912,11 +3922,6 @@
 				kfree(tpnt->buffer);
 			}
 			kfree(tpnt);
-			scsi_tapes[i] = 0;
-			SDp->attached--;
-			st_template.nr_dev--;
-			st_template.dev_noticed--;
-			write_unlock(&st_dev_arr_lock);
 			return;
 		}
 	}
@@ -4020,7 +4025,7 @@
 	if (count == 0)
 		return 0;
 
-	if ((pages = kmalloc(max_pages * sizeof(*pages), GFP_ATOMIC)) == NULL)
+	if ((pages = kmalloc(max_pages * sizeof(*pages), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
 
         /* Try to fault in all of the necessary pages */
diff -Nru a/drivers/scsi/sym53c8xx_2/Makefile b/drivers/scsi/sym53c8xx_2/Makefile
--- a/drivers/scsi/sym53c8xx_2/Makefile	Tue Oct  1 00:08:19 2002
+++ b/drivers/scsi/sym53c8xx_2/Makefile	Tue Oct  1 00:08:19 2002
@@ -7,5 +7,3 @@
 
 include $(TOPDIR)/Rules.make
 
-clean:
-	rm -f *.o
diff -Nru a/drivers/tc/lk201-map.map b/drivers/tc/lk201-map.map
--- a/drivers/tc/lk201-map.map	Tue Oct  1 00:08:17 2002
+++ b/drivers/tc/lk201-map.map	Tue Oct  1 00:08:17 2002
@@ -3,8 +3,8 @@
 # Change the above line into
 #	keymaps 0-2,4-6,8,12
 # in case you want the entries
-#	altgr   control keycode  83 = Boot            
-#	altgr   control keycode 111 = Boot            
+#	altgr   control keycode  83 = Boot
+#	altgr   control keycode 111 = Boot
 # below.
 #
 # In fact AltGr is used very little, and one more keymap can
diff -Nru a/drivers/tc/lk201-remap.c b/drivers/tc/lk201-remap.c
--- a/drivers/tc/lk201-remap.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/tc/lk201-remap.c	Tue Oct  1 00:08:15 2002
@@ -1,17 +1,17 @@
 /*
  * Keyboard mappings for DEC LK201/401/501 keyboards
- * 
+ *
  * 17.05.99 Michael Engel (engel@unix-ag.org)
  *
  * DEC US keyboards generate keycodes in the range 0x55 - 0xfb
  *
- * This conflicts with Linux scancode conventions which define 
+ * This conflicts with Linux scancode conventions which define
  * 0x00-0x7f as "normal" and 0x80-0xff as "shifted" scancodes, so we
  * have to remap the keycodes to 0x00-0x7f with the scancodeRemap
  * array. The generated scancode is simply the number of the key counted
  * from the left upper to the right lower corner of the keyboard ...
  *
- * These scancodes are then being remapped (I hope ;-)) with the 
+ * These scancodes are then being remapped (I hope ;-)) with the
  * lk501*map[] arrays which define scancode -> Linux code mapping
  *
  * Oh man is this horrible ;-)
@@ -91,7 +91,7 @@
 /* ----- 								*/
 /* 60 */ 0,		0,		0,		0,
 /* ----- F6		F7		F8		F9		*/
-/* 64 */ 0x06,		0x07,		0x08,		0x09, 
+/* 64 */ 0x06,		0x07,		0x08,		0x09,
 /* ----- F10								*/
 /* 68 */ 0x0a,		0,		0,		0,
 /* ----- 								*/
diff -Nru a/drivers/tc/zs.h b/drivers/tc/zs.h
--- a/drivers/tc/zs.h	Tue Oct  1 00:08:16 2002
+++ b/drivers/tc/zs.h	Tue Oct  1 00:08:16 2002
@@ -38,7 +38,7 @@
 /*
  * Definitions for ZILOG_struct (and serial_struct) flags field
  */
-#define ZILOG_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes 
+#define ZILOG_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes
 				   on the callout port */
 #define ZILOG_FOURPORT  0x0002	/* Set OU1, OUT2 per AST Fourport settings */
 #define ZILOG_SAK	0x0004	/* Secure Attention Key (Orange book) */
@@ -74,7 +74,7 @@
 #ifdef __KERNEL__
 /*
  * This is our internal structure for each serial port's state.
- * 
+ *
  * Many fields are paralleled by the structure used by the serial_struct
  * structure.
  *
diff -Nru a/drivers/usb/class/bluetty.c b/drivers/usb/class/bluetty.c
--- a/drivers/usb/class/bluetty.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/usb/class/bluetty.c	Tue Oct  1 00:08:15 2002
@@ -1006,9 +1006,7 @@
 	}
 
 	/* wake up our little function to let the tty layer know that something happened */
-	queue_task(&bluetooth->tqueue, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
-	return;
+	schedule_task(&bluetooth->tqueue);
 }
 
 
diff -Nru a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
--- a/drivers/usb/class/cdc-acm.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/usb/class/cdc-acm.c	Tue Oct  1 00:08:15 2002
@@ -272,8 +272,7 @@
 	if (urb->status)
 		dbg("nonzero write bulk status received: %d", urb->status);
 
-	queue_task(&acm->tqueue, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
+	schedule_task(&acm->tqueue);
 }
 
 static void acm_softint(void *private)
diff -Nru a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile
--- a/drivers/usb/core/Makefile	Tue Oct  1 00:08:21 2002
+++ b/drivers/usb/core/Makefile	Tue Oct  1 00:08:21 2002
@@ -5,7 +5,7 @@
 export-objs	:= usb.o hcd.o hcd-pci.o urb.o message.o file.o buffer.o
 
 usbcore-objs	:= usb.o usb-debug.o hub.o hcd.o urb.o message.o \
-			config.o file.o buffer.o
+			config.o file.o buffer.o driverfs.o
 
 ifeq ($(CONFIG_PCI),y)
 	usbcore-objs	+= hcd-pci.o
diff -Nru a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
--- a/drivers/usb/core/devio.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/usb/core/devio.c	Tue Oct  1 00:08:17 2002
@@ -1067,6 +1067,10 @@
        /* disconnect kernel driver from interface, leaving it unbound.  */
        case USBDEVFS_DISCONNECT:
 		/* this function is voodoo. */
+		/* which function ... usb_device_remove()?
+		 * FIXME either the module lock (BKL) should be involved
+		 * here too, or the 'default' case below is broken
+		 */
 		driver = ifp->driver;
 		if (driver) {
 			dbg ("disconnect '%s' from dev %d interface %d",
@@ -1081,26 +1085,28 @@
 		retval = usb_device_probe (&ifp->dev);
 		break;
 
-       /* talk directly to the interface's driver */
-       default:
-		lock_kernel(); /* against module unload */
-               driver = ifp->driver;
-               if (driver == 0 || driver->ioctl == 0) {
+	/* talk directly to the interface's driver */
+	default:
+		/* BKL used here to protect against changing the binding
+		 * of this driver to this device, as well as unloading its
+		 * driver module.
+		 */
+		lock_kernel ();
+		driver = ifp->driver;
+		if (driver == 0 || driver->ioctl == 0) {
 			unlock_kernel();
 			retval = -ENOSYS;
 		} else {
-			if (ifp->driver->owner) {
-				__MOD_INC_USE_COUNT(ifp->driver->owner);
-				unlock_kernel();
-			}
-			/* ifno might usefully be passed ... */
-                       retval = driver->ioctl (ps->dev, ctrl.ioctl_code, buf);
-			/* size = min_t(int, size, retval)? */
-			if (ifp->driver->owner) {
-				__MOD_DEC_USE_COUNT(ifp->driver->owner);
-			} else {
+			if (driver->owner
+					&& !try_inc_mod_count (driver->owner)) {
 				unlock_kernel();
+				retval = -ENOSYS;
+				break;
 			}
+			unlock_kernel ();
+			retval = driver->ioctl (ifp, ctrl.ioctl_code, buf);
+			if (driver->owner)
+				__MOD_DEC_USE_COUNT (driver->owner);
 		}
 		
 		if (retval == -ENOIOCTLCMD)
diff -Nru a/drivers/usb/core/driverfs.c b/drivers/usb/core/driverfs.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/core/driverfs.c	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,177 @@
+/*
+ * drivers/usb/core/driverfs.c
+ *
+ * (C) Copyright 2002 David Brownell
+ * (C) Copyright 2002 Greg Kroah-Hartman
+ * (C) Copyright 2002 IBM Corp.
+ *
+ * All of the driverfs file attributes for usb devices and interfaces.
+ *
+ */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+
+#ifdef CONFIG_USB_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+#include <linux/usb.h>
+
+#include "usb.h"
+
+/* Active configuration fields */
+#define usb_actconfig_attr(field, format_string)			\
+static ssize_t								\
+show_##field (struct device *dev, char *buf, size_t count, loff_t off)	\
+{									\
+	struct usb_device *udev;					\
+									\
+	if (off)							\
+		return 0;						\
+									\
+	udev = to_usb_device (dev);					\
+	return sprintf (buf, format_string, udev->actconfig->field);	\
+}									\
+static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
+
+usb_actconfig_attr (bNumInterfaces, "%2d\n")
+usb_actconfig_attr (bConfigurationValue, "%2d\n")
+usb_actconfig_attr (bmAttributes, "%2x\n")
+usb_actconfig_attr (MaxPower, "%3dmA\n")
+
+/* String fields */
+static ssize_t show_product (struct device *dev, char *buf, size_t count, loff_t off)
+{
+	struct usb_device *udev;
+	int len;
+
+	if (off)
+		return 0;
+	udev = to_usb_device (dev);
+
+	len = usb_string(udev, udev->descriptor.iProduct, buf, PAGE_SIZE);
+	if (len < 0)
+		return 0;
+	buf[len] = '\n';
+	buf[len+1] = 0;
+	return len+1;
+}
+static DEVICE_ATTR(product,S_IRUGO,show_product,NULL);
+
+static ssize_t
+show_manufacturer (struct device *dev, char *buf, size_t count, loff_t off)
+{
+	struct usb_device *udev;
+	int len;
+
+	if (off)
+		return 0;
+	udev = to_usb_device (dev);
+
+	len = usb_string(udev, udev->descriptor.iManufacturer, buf, PAGE_SIZE);
+	if (len < 0)
+		return 0;
+	buf[len] = '\n';
+	buf[len+1] = 0;
+	return len+1;
+}
+static DEVICE_ATTR(manufacturer,S_IRUGO,show_manufacturer,NULL);
+
+static ssize_t
+show_serial (struct device *dev, char *buf, size_t count, loff_t off)
+{
+	struct usb_device *udev;
+	int len;
+
+	if (off)
+		return 0;
+	udev = to_usb_device (dev);
+
+	len = usb_string(udev, udev->descriptor.iSerialNumber, buf, PAGE_SIZE);
+	if (len < 0)
+		return 0;
+	buf[len] = '\n';
+	buf[len+1] = 0;
+	return len+1;
+}
+static DEVICE_ATTR(serial,S_IRUGO,show_serial,NULL);
+
+/* Descriptor fields */
+#define usb_descriptor_attr(field, format_string)			\
+static ssize_t								\
+show_##field (struct device *dev, char *buf, size_t count, loff_t off)	\
+{									\
+	struct usb_device *udev;					\
+									\
+	if (off)							\
+		return 0;						\
+									\
+	udev = to_usb_device (dev);					\
+	return sprintf (buf, format_string, udev->descriptor.field);	\
+}									\
+static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
+
+usb_descriptor_attr (idVendor, "%04x\n")
+usb_descriptor_attr (idProduct, "%04x\n")
+usb_descriptor_attr (bcdDevice, "%04x\n")
+usb_descriptor_attr (bDeviceClass, "%02x\n")
+usb_descriptor_attr (bDeviceSubClass, "%02x\n")
+usb_descriptor_attr (bDeviceProtocol, "%02x\n")
+
+
+void usb_create_driverfs_dev_files (struct usb_device *udev)
+{
+	struct device *dev = &udev->dev;
+
+	device_create_file (dev, &dev_attr_bNumInterfaces);
+	device_create_file (dev, &dev_attr_bConfigurationValue);
+	device_create_file (dev, &dev_attr_bmAttributes);
+	device_create_file (dev, &dev_attr_MaxPower);
+	device_create_file (dev, &dev_attr_idVendor);
+	device_create_file (dev, &dev_attr_idProduct);
+	device_create_file (dev, &dev_attr_bcdDevice);
+	device_create_file (dev, &dev_attr_bDeviceClass);
+	device_create_file (dev, &dev_attr_bDeviceSubClass);
+	device_create_file (dev, &dev_attr_bDeviceProtocol);
+
+	if (udev->descriptor.iManufacturer)
+		device_create_file (dev, &dev_attr_manufacturer);
+	if (udev->descriptor.iProduct)
+		device_create_file (dev, &dev_attr_product);
+	if (udev->descriptor.iSerialNumber)
+		device_create_file (dev, &dev_attr_serial);
+}
+
+/* Interface fields */
+#define usb_intf_attr(field, format_string)				\
+static ssize_t								\
+show_##field (struct device *dev, char *buf, size_t count, loff_t off)	\
+{									\
+	struct usb_interface *intf;					\
+	int alt;							\
+									\
+	if (off)							\
+		return 0;						\
+									\
+	intf = to_usb_interface (dev);					\
+	alt = intf->act_altsetting;					\
+									\
+	return sprintf (buf, format_string, intf->altsetting[alt].field);	\
+}									\
+static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
+
+usb_intf_attr (bAlternateSetting, "%2d\n")
+usb_intf_attr (bInterfaceClass, "%02x\n")
+usb_intf_attr (bInterfaceSubClass, "%02x\n")
+usb_intf_attr (bInterfaceProtocol, "%02x\n")
+
+void usb_create_driverfs_intf_files (struct usb_interface *intf)
+{
+	device_create_file (&intf->dev, &dev_attr_bAlternateSetting);
+	device_create_file (&intf->dev, &dev_attr_bInterfaceClass);
+	device_create_file (&intf->dev, &dev_attr_bInterfaceSubClass);
+	device_create_file (&intf->dev, &dev_attr_bInterfaceProtocol);
+}
diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
--- a/drivers/usb/core/hcd.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/usb/core/hcd.c	Tue Oct  1 00:08:17 2002
@@ -1024,6 +1024,11 @@
 	 */
 	urb = usb_get_urb (urb);
 	if (urb->dev == hcd->self.root_hub) {
+		/* NOTE:  requirement on hub callers (usbfs and the hub
+		 * driver, for now) that URBs' urb->transfer_buffer be
+		 * valid and usb_buffer_{sync,unmap}() not be needed, since
+		 * they could clobber root hub response data.
+		 */
 		urb->transfer_flags |= URB_NO_DMA_MAP;
 		return rh_urb_enqueue (hcd, urb);
 	}
@@ -1132,11 +1137,11 @@
 		goto done;
 	}
 
-	/* For non-periodic transfers, any status except -EINPROGRESS means
-	 * the HCD has already started to unlink this URB from the hardware.
-	 * In that case, there's no more work to do.
+	/* Except for interrupt transfers, any status except -EINPROGRESS
+	 * means the HCD already started to unlink this URB from the hardware.
+	 * So there's no more work to do.
 	 *
-	 * For periodic transfers, this is the only way to trigger unlinking
+	 * For interrupt transfers, this is the only way to trigger unlinking
 	 * from the hardware.  Since we (currently) overload urb->status to
 	 * tell the driver to unlink, error status might get clobbered ...
 	 * unless that transfer hasn't yet restarted.  One such case is when
@@ -1144,13 +1149,10 @@
 	 *
 	 * FIXME use an URB_UNLINKED flag to match URB_TIMEOUT_KILLED
 	 */
-	switch (usb_pipetype (urb->pipe)) {
-	case PIPE_CONTROL:
-	case PIPE_BULK:
-		if (urb->status != -EINPROGRESS) {
-			retval = -EINVAL;
-			goto done;
-		}
+	if (urb->status != -EINPROGRESS
+			&& usb_pipetype (urb->pipe) != PIPE_INTERRUPT) {
+		retval = -EINVAL;
+		goto done;
 	}
 
 	/* maybe set up to block on completion notification */
diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
--- a/drivers/usb/core/hub.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/usb/core/hub.c	Tue Oct  1 00:08:17 2002
@@ -537,7 +537,7 @@
 	dev_set_drvdata (&intf->dev, hub);
 
 	if (usb_hub_configure(hub, endpoint) >= 0) {
-		strcpy (intf->dev.name, "Hub/Port Status Changes");
+		strcpy (intf->dev.name, "Hub");
 		return 0;
 	}
 
@@ -547,8 +547,11 @@
 	return -ENODEV;
 }
 
-static int hub_ioctl(struct usb_device *hub, unsigned int code, void *user_data)
+static int
+hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
 {
+	struct usb_device *hub = interface_to_usbdev (intf);
+
 	/* assert ifno == 0 (part of hub spec) */
 	switch (code) {
 	case USBDEVFS_HUB_PORTINFO: {
diff -Nru a/drivers/usb/core/message.c b/drivers/usb/core/message.c
--- a/drivers/usb/core/message.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/usb/core/message.c	Tue Oct  1 00:08:16 2002
@@ -2,6 +2,7 @@
  * message.c - synchronous message handling
  */
 
+#include <linux/pci.h>	/* for scatterlist macros */
 #include <linux/usb.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -123,6 +124,9 @@
  *	Don't use this function from within an interrupt context, like a
  *	bottom half handler.  If you need an asynchronous message, or need to send
  *	a message from within interrupt context, use usb_submit_urb()
+ *      If a thread in your driver uses this call, make sure your disconnect()
+ *      method can wait for it to complete.  Since you don't have a handle on
+ *      the URB used, you can't cancel the request.
  */
 int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,
 			 __u16 value, __u16 index, void *data, __u16 size, int timeout)
@@ -170,6 +174,9 @@
  *	Don't use this function from within an interrupt context, like a
  *	bottom half handler.  If you need an asynchronous message, or need to
  *	send a message from within interrupt context, use usb_submit_urb()
+ *      If a thread in your driver uses this call, make sure your disconnect()
+ *      method can wait for it to complete.  Since you don't have a handle on
+ *      the URB used, you can't cancel the request.
  */
 int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, 
 			void *data, int len, int *actual_length, int timeout)
@@ -189,6 +196,321 @@
 	return usb_start_wait_urb(urb,timeout,actual_length);
 }
 
+/*-------------------------------------------------------------------*/
+
+static void sg_clean (struct usb_sg_request *io)
+{
+	if (io->urbs) {
+		while (io->entries--)
+			usb_free_urb (io->urbs [io->entries]);
+		kfree (io->urbs);
+		io->urbs = 0;
+	}
+	usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents);
+	io->dev = 0;
+}
+
+static void sg_complete (struct urb *urb)
+{
+	struct usb_sg_request	*io = (struct usb_sg_request *) urb->context;
+	unsigned long		flags;
+
+	spin_lock_irqsave (&io->lock, flags);
+
+	/* In 2.5 we require hcds' endpoint queues not to progress after fault
+	 * reports, until the competion callback (this!) returns.  That lets
+	 * device driver code (like this routine) unlink queued urbs first,
+	 * if it needs to, since the HC won't work on them at all.  So it's
+	 * not possible for page N+1 to overwrite page N, and so on.
+	 */
+	if (io->status && urb->actual_length) {
+		err ("driver for bus %s dev %s ep %d-%s corrupted data!",
+			io->dev->bus->bus_name, io->dev->devpath,
+			usb_pipeendpoint (urb->pipe),
+			usb_pipein (urb->pipe) ? "in" : "out");
+		// BUG ();
+	}
+
+	if (urb->status && urb->status != -ECONNRESET) {
+		int		i, found, status;
+
+		io->status = urb->status;
+
+		/* the previous urbs, and this one, completed already.
+		 * unlink the later ones so they won't rx/tx bad data,
+		 *
+		 * FIXME don't bother unlinking urbs that haven't yet been
+		 * submitted; those non-error cases shouldn't be syslogged
+		 */
+		for (i = 0, found = 0; i < io->entries; i++) {
+			if (found) {
+				status = usb_unlink_urb (io->urbs [i]);
+				if (status && status != -EINPROGRESS)
+					err ("sg_complete, unlink --> %d",
+							status);
+			} else if (urb == io->urbs [i])
+				found = 1;
+		}
+	}
+
+	/* on the last completion, signal usb_sg_wait() */
+	io->bytes += urb->actual_length;
+	io->count--;
+	if (!io->count)
+		complete (&io->complete);
+
+	spin_unlock_irqrestore (&io->lock, flags);
+}
+
+
+/**
+ * usb_sg_init - initializes scatterlist-based bulk/interrupt I/O request
+ * @io: request block being initialized.  until usb_sg_wait() returns,
+ *	treat this as a pointer to an opaque block of memory,
+ * @dev: the usb device that will send or receive the data
+ * @pipe: endpoint "pipe" used to transfer the data
+ * @period: polling rate for interrupt endpoints, in frames or
+ * 	(for high speed endpoints) microframes; ignored for bulk
+ * @sg: scatterlist entries
+ * @nents: how many entries in the scatterlist
+ * @length: how many bytes to send from the scatterlist, or zero to
+ * 	send every byte identified in the list.
+ * @mem_flags: SLAB_* flags affecting memory allocations in this call
+ *
+ * Returns zero for success, else a negative errno value.  This initializes a
+ * scatter/gather request, allocating resources such as I/O mappings and urb
+ * memory (except maybe memory used by USB controller drivers).
+ *
+ * The request must be issued using usb_sg_wait(), which waits for the I/O to
+ * complete (or to be canceled) and then cleans up all resources allocated by
+ * usb_sg_init().
+ *
+ * The request may be canceled with usb_sg_cancel(), either before or after
+ * usb_sg_wait() is called.
+ *
+ * NOTE:
+ *
+ * At this writing, don't use the interrupt transfer mode, since the old old
+ * "automagic resubmit" mode hasn't yet been removed.  It should be removed
+ * by the time 2.5 finalizes.
+ */
+int usb_sg_init (
+	struct usb_sg_request	*io,
+	struct usb_device	*dev,
+	unsigned		pipe, 
+	unsigned		period,
+	struct scatterlist	*sg,
+	int			nents,
+	size_t			length,
+	int			mem_flags
+)
+{
+	int			i;
+	int			urb_flags;
+
+	if (!io || !dev || !sg
+			|| usb_pipecontrol (pipe)
+			|| usb_pipeisoc (pipe)
+			|| nents <= 0)
+		return -EINVAL;
+
+	spin_lock_init (&io->lock);
+	io->dev = dev;
+	io->pipe = pipe;
+	io->sg = sg;
+	io->nents = nents;
+
+	/* initialize all the urbs we'll use */
+	io->entries = usb_buffer_map_sg (dev, pipe, sg, nents);
+	if (io->entries <= 0)
+		return io->entries;
+
+	io->count = 0;
+	io->urbs = kmalloc (io->entries * sizeof *io->urbs, mem_flags);
+	if (!io->urbs)
+		goto nomem;
+
+	urb_flags = USB_ASYNC_UNLINK | URB_NO_DMA_MAP | URB_NO_INTERRUPT;
+	if (usb_pipein (pipe))
+		urb_flags |= URB_SHORT_NOT_OK;
+
+	for (i = 0; i < io->entries; i++, io->count = i) {
+		unsigned		len;
+
+		io->urbs [i] = usb_alloc_urb (0, mem_flags);
+		if (!io->urbs [i]) {
+			io->entries = i;
+			goto nomem;
+		}
+
+		io->urbs [i]->dev = dev;
+		io->urbs [i]->pipe = pipe;
+		io->urbs [i]->interval = period;
+		io->urbs [i]->transfer_flags = urb_flags;
+
+		io->urbs [i]->complete = sg_complete;
+		io->urbs [i]->context = io;
+		io->urbs [i]->status = -EINPROGRESS;
+		io->urbs [i]->actual_length = 0;
+
+		io->urbs [i]->transfer_dma = sg_dma_address (sg + i);
+		len = sg_dma_len (sg + i);
+		if (length) {
+			len = min_t (unsigned, len, length);
+			length -= len;
+			if (length == 0)
+				io->entries = i + 1;
+		}
+		io->urbs [i]->transfer_buffer_length = len;
+	}
+	io->urbs [--i]->transfer_flags &= ~URB_NO_INTERRUPT;
+
+	/* transaction state */
+	io->status = 0;
+	io->bytes = 0;
+	init_completion (&io->complete);
+	return 0;
+
+nomem:
+	sg_clean (io);
+	return -ENOMEM;
+}
+
+
+/**
+ * usb_sg_wait - synchronously execute scatter/gather request
+ * @io: request block handle, as initialized with usb_sg_init().
+ * 	some fields become accessible when this call returns.
+ * Context: !in_interrupt ()
+ *
+ * This function blocks until the specified I/O operation completes.  It
+ * leverages the grouping of the related I/O requests to get good transfer
+ * rates, by queueing the requests.  At higher speeds, such queuing can
+ * significantly improve USB throughput.
+ *
+ * There are three kinds of completion for this function.
+ * (1) success, where io->status is zero.  The number of io->bytes
+ *     transferred is as requested.
+ * (2) error, where io->status is a negative errno value.  The number
+ *     of io->bytes transferred before the error is usually less
+ *     than requested, and can be nonzero.
+ * (3) cancelation, a type of error with status -ECONNRESET that
+ *     is initiated by usb_sg_cancel().
+ *
+ * When this function returns, all memory allocated through usb_sg_init() or
+ * this call will have been freed.  The request block parameter may still be
+ * passed to usb_sg_cancel(), or it may be freed.  It could also be
+ * reinitialized and then reused.
+ *
+ * Data Transfer Rates:
+ *
+ * Bulk transfers are valid for full or high speed endpoints.
+ * The best full speed data rate is 19 packets of 64 bytes each
+ * per frame, or 1216 bytes per millisecond.
+ * The best high speed data rate is 13 packets of 512 bytes each
+ * per microframe, or 52 KBytes per millisecond.
+ *
+ * The reason to use interrupt transfers through this API would most likely
+ * be to reserve high speed bandwidth, where up to 24 KBytes per millisecond
+ * could be transferred.  That capability is less useful for low or full
+ * speed interrupt endpoints, which allow at most one packet per millisecond,
+ * of at most 8 or 64 bytes (respectively).
+ */
+void usb_sg_wait (struct usb_sg_request *io)
+{
+	int		i;
+	unsigned long	flags;
+
+	/* queue the urbs.  */
+	spin_lock_irqsave (&io->lock, flags);
+	for (i = 0; i < io->entries && !io->status; i++) {
+		int	retval;
+
+		retval = usb_submit_urb (io->urbs [i], SLAB_ATOMIC);
+
+		/* after we submit, let completions or cancelations fire;
+		 * we handshake using io->status.
+		 */
+		spin_unlock_irqrestore (&io->lock, flags);
+		switch (retval) {
+			/* maybe we retrying will recover */
+		case -ENXIO:	// hc didn't queue this one
+		case -EAGAIN:
+		case -ENOMEM:
+			retval = 0;
+			i--;
+			// FIXME:  should it usb_sg_cancel() on INTERRUPT?
+			// how about imposing a backoff?
+			set_current_state (TASK_UNINTERRUPTIBLE);
+			schedule ();
+			break;
+
+			/* no error? continue immediately.
+			 *
+			 * NOTE: to work better with UHCI (4K I/O buffer may
+			 * need 3K of TDs) it may be good to limit how many
+			 * URBs are queued at once; N milliseconds?
+			 */
+		case 0:
+			cpu_relax ();
+			break;
+
+			/* fail any uncompleted urbs */
+		default:
+			io->urbs [i]->status = retval;
+			dbg ("usb_sg_msg, submit --> %d", retval);
+			usb_sg_cancel (io);
+		}
+		spin_lock_irqsave (&io->lock, flags);
+		if (retval && io->status == -ECONNRESET)
+			io->status = retval;
+	}
+	spin_unlock_irqrestore (&io->lock, flags);
+
+	/* OK, yes, this could be packaged as non-blocking.
+	 * So could the submit loop above ... but it's easier to
+	 * solve neither problem than to solve both!
+	 */
+	wait_for_completion (&io->complete);
+
+	sg_clean (io);
+}
+
+/**
+ * usb_sg_cancel - stop scatter/gather i/o issued by usb_sg_wait()
+ * @io: request block, initialized with usb_sg_init()
+ *
+ * This stops a request after it has been started by usb_sg_wait().
+ * It can also prevents one initialized by usb_sg_init() from starting,
+ * so that call just frees resources allocated to the request.
+ */
+void usb_sg_cancel (struct usb_sg_request *io)
+{
+	unsigned long	flags;
+
+	spin_lock_irqsave (&io->lock, flags);
+
+	/* shut everything down, if it didn't already */
+	if (!io->status) {
+		int	i;
+
+		io->status = -ECONNRESET;
+		for (i = 0; i < io->entries; i++) {
+			int	retval;
+
+			if (!io->urbs [i]->dev)
+				continue;
+			retval = usb_unlink_urb (io->urbs [i]);
+			if (retval && retval != -EINPROGRESS)
+				warn ("usb_sg_cancel, unlink --> %d", retval);
+			// FIXME don't warn on "not yet submitted" error
+		}
+	}
+	spin_unlock_irqrestore (&io->lock, flags);
+}
+
+/*-------------------------------------------------------------------*/
+
 /**
  * usb_get_descriptor - issues a generic GET_DESCRIPTOR request
  * @dev: the device whose descriptor is being retrieved
@@ -659,6 +981,11 @@
 // synchronous request completion model
 EXPORT_SYMBOL(usb_control_msg);
 EXPORT_SYMBOL(usb_bulk_msg);
+
+EXPORT_SYMBOL(usb_sg_init);
+EXPORT_SYMBOL(usb_sg_cancel);
+EXPORT_SYMBOL(usb_sg_wait);
+
 // synchronous control message convenience routines
 EXPORT_SYMBOL(usb_get_descriptor);
 EXPORT_SYMBOL(usb_get_device_descriptor);
diff -Nru a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
--- a/drivers/usb/core/urb.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/usb/core/urb.c	Tue Oct  1 00:08:17 2002
@@ -232,22 +232,19 @@
 		return -EMSGSIZE;
 	}
 
-	/* "high bandwidth" mode, 1-3 packets/uframe? */
-	if (dev->speed == USB_SPEED_HIGH) {
-		int	mult;
-		switch (temp) {
-		case PIPE_ISOCHRONOUS:
-		case PIPE_INTERRUPT:
-			mult = 1 + ((max >> 11) & 0x03);
+	/* periodic transfers limit size per frame/uframe,
+	 * but drivers only control those sizes for ISO.
+	 * while we're checking, initialize return status.
+	 */
+	if (temp == PIPE_ISOCHRONOUS) {
+		int	n, len;
+
+		/* "high bandwidth" mode, 1-3 packets/uframe? */
+		if (dev->speed == USB_SPEED_HIGH) {
+			int	mult = 1 + ((max >> 11) & 0x03);
 			max &= 0x03ff;
 			max *= mult;
 		}
-	}
-
-	/* periodic transfers limit size per frame/uframe */
-	switch (temp) {
-	case PIPE_ISOCHRONOUS: {
-		int	n, len;
 
 		if (urb->number_of_packets <= 0)		    
 			return -EINVAL;
@@ -255,13 +252,9 @@
 			len = urb->iso_frame_desc [n].length;
 			if (len < 0 || len > max) 
 				return -EMSGSIZE;
+			urb->iso_frame_desc [n].status = -EXDEV;
+			urb->iso_frame_desc [n].actual_length = 0;
 		}
-
-		}
-		break;
-	case PIPE_INTERRUPT:
-		if (urb->transfer_buffer_length > max)
-			return -EMSGSIZE;
 	}
 
 	/* the I/O buffer must be mapped/unmapped, except when length=0 */
diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
--- a/drivers/usb/core/usb.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/usb/core/usb.c	Tue Oct  1 00:08:17 2002
@@ -42,6 +42,7 @@
 #include <linux/usb.h>
 
 #include "hcd.h"
+#include "usb.h"
 
 extern int  usb_hub_init(void);
 extern void usb_hub_cleanup(void);
@@ -123,6 +124,8 @@
 	if (driver->owner) {
 		m = try_inc_mod_count(driver->owner);
 		if (m == 0) {
+			// FIXME this happens even when we just rmmod
+			// drivers that aren't in active use... 
 			err("Dieing driver still bound to device.\n");
 			return -EIO;
 		}
@@ -524,9 +527,8 @@
 	if (!dev)
 		return -ENODEV;
 
-	/* check for generic driver, we do not call do hotplug calls for it */
 	if (dev->driver == &usb_generic_driver)
-		return -ENODEV;
+		return 0;
 
 	intf = to_usb_interface(dev);
 	if (!intf)
@@ -629,98 +631,6 @@
 
 #endif	/* CONFIG_HOTPLUG */
 
-/* driverfs files */
-
-/* devices have one current configuration, with one
- * or more interfaces that are used concurrently 
- */
-static ssize_t
-show_config (struct device *dev, char *buf, size_t count, loff_t off)
-{
-	struct usb_device	*udev;
-
-	if (off)
-		return 0;
-	udev = to_usb_device (dev);
-	return sprintf (buf, "%u\n", udev->actconfig->bConfigurationValue);
-}
-
-static DEVICE_ATTR(configuration,S_IRUGO,show_config,NULL);
-
-/* interfaces have one current setting; alternates
- * can have different endpoints and class info.
- */
-static ssize_t
-show_altsetting (struct device *dev, char *buf, size_t count, loff_t off)
-{
-	struct usb_interface	*interface;
-
-	if (off)
-		return 0;
-	interface = to_usb_interface (dev);
-	return sprintf (buf, "%u\n", interface->altsetting->bAlternateSetting);
-}
-static DEVICE_ATTR(altsetting,S_IRUGO,show_altsetting,NULL);
-
-/* product driverfs file */
-static ssize_t show_product (struct device *dev, char *buf, size_t count, loff_t off)
-{
-	struct usb_device *udev;
-	int len;
-
-	if (off)
-		return 0;
-	udev = to_usb_device (dev);
-
-	len = usb_string(udev, udev->descriptor.iProduct, buf, PAGE_SIZE);
-	if (len < 0)
-		return 0;
-	buf[len] = '\n';
-	buf[len+1] = 0;
-	return len+1;
-}
-static DEVICE_ATTR(product,S_IRUGO,show_product,NULL);
-
-/* manufacturer driverfs file */
-static ssize_t
-show_manufacturer (struct device *dev, char *buf, size_t count, loff_t off)
-{
-	struct usb_device *udev;
-	int len;
-
-	if (off)
-		return 0;
-	udev = to_usb_device (dev);
-
-	len = usb_string(udev, udev->descriptor.iManufacturer, buf, PAGE_SIZE);
-	if (len < 0)
-		return 0;
-	buf[len] = '\n';
-	buf[len+1] = 0;
-	return len+1;
-}
-static DEVICE_ATTR(manufacturer,S_IRUGO,show_manufacturer,NULL);
-
-/* serial number driverfs file */
-static ssize_t
-show_serial (struct device *dev, char *buf, size_t count, loff_t off)
-{
-	struct usb_device *udev;
-	int len;
-
-	if (off)
-		return 0;
-	udev = to_usb_device (dev);
-
-	len = usb_string(udev, udev->descriptor.iSerialNumber, buf, PAGE_SIZE);
-	if (len < 0)
-		return 0;
-	buf[len] = '\n';
-	buf[len+1] = 0;
-	return len+1;
-}
-static DEVICE_ATTR(serial,S_IRUGO,show_serial,NULL);
-
 /**
  * usb_alloc_dev - allocate a usb device structure (usbcore-internal)
  * @parent: hub to which device is connected
@@ -1133,13 +1043,7 @@
 		return err;
 
 	/* add the USB device specific driverfs files */
-	device_create_file (&dev->dev, &dev_attr_configuration);
-	if (dev->descriptor.iManufacturer)
-		device_create_file (&dev->dev, &dev_attr_manufacturer);
-	if (dev->descriptor.iProduct)
-		device_create_file (&dev->dev, &dev_attr_product);
-	if (dev->descriptor.iSerialNumber)
-		device_create_file (&dev->dev, &dev_attr_serial);
+	usb_create_driverfs_dev_files (dev);
 
 	/* Register all of the interfaces for this device with the driver core.
 	 * Remember, interfaces get bound to drivers, not devices. */
@@ -1169,7 +1073,7 @@
 		}
 		dbg ("%s - registering %s", __FUNCTION__, interface->dev.bus_id);
 		device_register (&interface->dev);
-		device_create_file (&interface->dev, &dev_attr_altsetting);
+		usb_create_driverfs_intf_files (interface);
 	}
 
 	/* add a /proc/bus/usb entry */
@@ -1194,6 +1098,8 @@
  * avoid behaviors like using "DMA bounce buffers", or tying down I/O mapping
  * hardware for long idle periods.  The implementation varies between
  * platforms, depending on details of how DMA will work to this device.
+ * Using these buffers also helps prevent cacheline sharing problems on
+ * architectures where CPU caches are not DMA-coherent.
  *
  * When the buffer is no longer used, free it with usb_buffer_free().
  */
diff -Nru a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/core/usb.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,5 @@
+/* Functions local to drivers/usb/core/ */
+
+extern void usb_create_driverfs_dev_files (struct usb_device *dev);
+extern void usb_create_driverfs_intf_files (struct usb_interface *intf);
+
diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
--- a/drivers/usb/host/ehci-hcd.c	Tue Oct  1 00:08:18 2002
+++ b/drivers/usb/host/ehci-hcd.c	Tue Oct  1 00:08:18 2002
@@ -749,7 +749,7 @@
 	default:
 		spin_lock_irqsave (&ehci->lock, flags);
 		if (ehci->reclaim) {
-			dbg ("dq %p: reclaim = %p, %s",
+			vdbg ("dq %p: reclaim = %p, %s",
 				qh, ehci->reclaim, RUN_CONTEXT);
 			if (qh == ehci->reclaim) {
 				/* unlinking qh for another queued urb? */
diff -Nru a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
--- a/drivers/usb/host/ehci-q.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/usb/host/ehci-q.c	Tue Oct  1 00:08:16 2002
@@ -255,23 +255,23 @@
 		struct urb	*urb = qtd->urb;
 		u32		token = 0;
 
+		/* hc's on-chip qh overlay cache can overwrite our idea of
+		 * next qtd ptrs, if we appended a qtd while the queue was
+		 * advancing.  (because we don't use dummy qtds.)
+		 */
+		if (cpu_to_le32 (qtd->qtd_dma) == qh->hw_current
+				&& qtd->hw_next != qh->hw_qtd_next) {
+			qh->hw_alt_next = qtd->hw_alt_next;
+			qh->hw_qtd_next = qtd->hw_next;
+			COUNT (ehci->stats.qpatch);
+		}
+
 		/* clean up any state from previous QTD ...*/
 		if (last) {
 			if (likely (last->urb != urb)) {
 				ehci_urb_done (ehci, last->urb);
 				count++;
 			}
-
-			/* qh overlays can have HC's old cached copies of
-			 * next qtd ptrs, if an URB was queued afterwards.
-			 */
-			if (cpu_to_le32 (last->qtd_dma) == qh->hw_current
-					&& last->hw_next != qh->hw_qtd_next) {
-				qh->hw_alt_next = last->hw_alt_next;
-				qh->hw_qtd_next = last->hw_next;
-				COUNT (ehci->stats.qpatch);
-			}
-
 			ehci_qtd_free (ehci, last);
 			last = 0;
 		}
@@ -529,7 +529,8 @@
 	}
 
 	/* by default, enable interrupt on urb completion */
-	if (likely (!(urb->transfer_flags & URB_NO_INTERRUPT)))
+// ... do it always, unless we switch over to dummy qtds
+//	if (likely (!(urb->transfer_flags & URB_NO_INTERRUPT)))
 		qtd->hw_token |= __constant_cpu_to_le32 (QTD_IOC);
 	return head;
 
@@ -785,7 +786,6 @@
 		/* append to tds already queued to this qh? */
 		if (unlikely (!list_empty (&qh->qtd_list) && qtd)) {
 			struct ehci_qtd		*last_qtd;
-			int			short_rx = 0;
 			u32			hw_next;
 
 			/* update the last qtd's "next" pointer */
@@ -800,23 +800,16 @@
 					&& (epnum & 0x10)) {
 				// only the last QTD for now
 				last_qtd->hw_alt_next = hw_next;
-				short_rx = 1;
 			}
 
-			/* Adjust any old copies in qh overlay too.
-			 * Interrupt code must cope with case of HC having it
-			 * cached, and clobbering these updates.
-			 * ... complicates getting rid of extra interrupts!
-			 * (Or:  use dummy td, so cache always stays valid.)
+			/* qh_completions() may need to patch the qh overlay if
+			 * the hc was advancing this queue while we appended.
+			 * we know it can: last_qtd->hw_token has IOC set.
+			 *
+			 * or:  use a dummy td (so the overlay gets the next td
+			 * only when we set its active bit); fewer irqs.
 			 */
-			if (qh->hw_current == cpu_to_le32 (last_qtd->qtd_dma)) {
-				wmb ();
-				qh->hw_qtd_next = hw_next;
-				if (short_rx)
-					qh->hw_alt_next = hw_next
-				    		| (qh->hw_alt_next & 0x1e);
-				vdbg ("queue to qh %p, patch", qh);
-			}
+			wmb ();
 
 		/* no URB queued */
 		} else {
diff -Nru a/drivers/usb/host/hc_sl811.c b/drivers/usb/host/hc_sl811.c
--- a/drivers/usb/host/hc_sl811.c	Tue Oct  1 00:08:18 2002
+++ b/drivers/usb/host/hc_sl811.c	Tue Oct  1 00:08:18 2002
@@ -28,7 +28,7 @@
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/smp_lock.h>
@@ -1158,6 +1158,7 @@
 	bus = usb_alloc_bus (&hci_device_operations);
 	if (!bus) {
 		kfree (hci);
+		kfree (ps);
 		return NULL;
 	}
 
diff -Nru a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
--- a/drivers/usb/host/ohci-hcd.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/usb/host/ohci-hcd.c	Tue Oct  1 00:08:15 2002
@@ -193,12 +193,6 @@
 			break;
 		case PIPE_ISOCHRONOUS: /* number of packets from URB */
 			size = urb->number_of_packets;
-			if (size <= 0)
-				return -EINVAL;
-			for (i = 0; i < urb->number_of_packets; i++) {
-  				urb->iso_frame_desc [i].actual_length = 0;
-  				urb->iso_frame_desc [i].status = -EXDEV;
-  			}
 			break;
 	}
 
diff -Nru a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c
--- a/drivers/usb/host/ohci-mem.c	Tue Oct  1 00:08:18 2002
+++ b/drivers/usb/host/ohci-mem.c	Tue Oct  1 00:08:18 2002
@@ -48,10 +48,10 @@
 	struct hash_t * scan = entry->head;
 	while (scan && scan->dma != dma)
 		scan = scan->next;
-	return scan->virt;
+	return scan ? scan->virt : 0;
 }
 
-static struct td *
+static inline struct td *
 dma_to_td (struct ohci_hcd *hc, dma_addr_t td_dma)
 {
 	td_dma &= TD_MASK;
@@ -62,7 +62,7 @@
 // FIXME:  when updating the hashtables this way, mem_flags is unusable...
 
 /* Add a hash entry for a TD/ED; return true on success */
-static int
+static inline int
 hash_add_ed_td (
 	struct hash_list_t *entry,
 	void *virt,
@@ -97,7 +97,7 @@
 }
 
 
-static void
+static inline void
 hash_free_ed_td (struct hash_list_t *entry, void *virt)
 {
 	struct hash_t *scan, *prev;
diff -Nru a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
--- a/drivers/usb/host/ohci-q.c	Tue Oct  1 00:08:20 2002
+++ b/drivers/usb/host/ohci-q.c	Tue Oct  1 00:08:20 2002
@@ -854,6 +854,11 @@
 	    	int		cc;
 
 		td = dma_to_td (ohci, td_dma);
+		if (!td) {
+			err ("%s bad entry %8x",
+				ohci->hcd.self.bus_name, td_dma);
+			break;
+		}
 
 		td->hwINFO |= cpu_to_le32 (TD_DONE);
 		cc = TD_CC_GET (le32_to_cpup (&td->hwINFO));
diff -Nru a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
--- a/drivers/usb/host/ohci-sa1111.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/usb/host/ohci-sa1111.c	Tue Oct  1 00:08:17 2002
@@ -25,7 +25,7 @@
 
 /*-------------------------------------------------------------------------*/
 
-static void sa1111_start_hc(void)
+static void sa1111_start_hc(struct sa1111_dev *dev)
 {
 	unsigned int usb_rst = 0;
 
@@ -48,31 +48,35 @@
 	 * Configure the power sense and control lines.  Place the USB
 	 * host controller in reset.
 	 */
-	USB_RESET = usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET;
+	sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
+		      dev->mapbase + SA1111_USB_RESET);
 
 	/*
 	 * Now, carefully enable the USB clock, and take
 	 * the USB host controller out of reset.
 	 */
-	SKPCR |= SKPCR_UCLKEN;
+	sa1111_enable_device(dev);
 	udelay(11);
-	USB_RESET = usb_rst;
+	sa1111_writel(usb_rst, dev->mapbase + SA1111_USB_RESET);
 }
 
-static void sa1111_stop_hc(void)
+static void sa1111_stop_hc(struct sa1111_dev *dev)
 {
+	unsigned int usb_rst;
 	printk(KERN_DEBUG __FILE__ 
 	       ": stopping SA-1111 OHCI USB Controller\n");
 
 	/*
 	 * Put the USB host controller into reset.
 	 */
-	USB_RESET |= USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET;
+	usb_rst = sa1111_readl(dev->mapbase + SA1111_USB_RESET);
+	sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
+		      dev->mapbase + SA1111_USB_RESET);
 
 	/*
 	 * Stop the USB clock.
 	 */
-	SKPCR &= ~SKPCR_UCLKEN;
+	sa1111_disable_device(dev);
 
 #ifdef CONFIG_SA1100_BADGE4
 	if (machine_is_badge4()) {
@@ -86,9 +90,9 @@
 /*-------------------------------------------------------------------------*/
 
 #if 0
-static void dump_hci_status(const char *label)
+static void dump_hci_status(struct usb_hcd *hcd, const char *label)
 {
-	unsigned long status = USB_STATUS; 
+	unsigned long status = sa1111_readl(hcd->regs + SA1111_USB_STATUS);
 
 	dbg ("%s USB_STATUS = { %s%s%s%s%s}", label,
 	     ((status & USB_STATUS_IRQHCIRMTWKUP) ? "IRQHCIRMTWKUP " : ""),
@@ -101,11 +105,14 @@
 
 static void usb_hcd_sa1111_hcim_irq (int irq, void *__hcd, struct pt_regs * r)
 {
-	//dump_hci_status("irq");
+	struct usb_hcd *hcd = __hcd;
+//	unsigned long status = sa1111_readl(hcd->regs + SA1111_USB_STATUS);
+
+	//dump_hci_status(hcd, "irq");
 
 #if 0
 	/* may work better this way -- need to investigate further */
-	if (USB_STATUS & USB_STATUS_NIRQHCIM) {
+	if (status & USB_STATUS_NIRQHCIM) {
 		//dbg ("not normal HC interrupt; ignoring");
 		return;
 	}
@@ -116,7 +123,7 @@
 
 /*-------------------------------------------------------------------------*/
 
-void usb_hcd_sa1111_remove (struct usb_hcd *);
+void usb_hcd_sa1111_remove (struct usb_hcd *, struct sa1111_dev *);
 
 /* configure so an HC device and id are always provided */
 /* always called with process context; sleeping is OK */
@@ -132,21 +139,20 @@
  *
  * Store this function in the HCD's struct pci_driver as probe().
  */
-int usb_hcd_sa1111_probe (const struct hc_driver *driver, struct usb_hcd **hcd_out)
+int usb_hcd_sa1111_probe (const struct hc_driver *driver,
+			  struct usb_hcd **hcd_out,
+			  struct sa1111_dev *dev)
 {
 	int retval;
 	struct usb_hcd *hcd = 0;
 
-	if (!sa1111)
-		return -ENODEV;
-
-	if (!request_mem_region(_USB_OHCI_OP_BASE, 
-				_USB_EXTENT, hcd_name)) {
+	if (!request_mem_region(dev->res.start, 
+				dev->res.end - dev->res.start + 1, hcd_name)) {
 		dbg("request_mem_region failed");
 		return -EBUSY;
 	}
 
-	sa1111_start_hc();
+	sa1111_start_hc(dev);
 
 	hcd = driver->hcd_alloc ();
 	if (hcd == NULL){
@@ -157,9 +163,10 @@
 
 	hcd->driver = (struct hc_driver *) driver;
 	hcd->description = driver->description;
-	hcd->irq = NIRQHCIM;
-	hcd->regs = (void *) &USB_OHCI_OP_BASE;
+	hcd->irq = dev->irq[1];
+	hcd->regs = dev->mapbase;
 	hcd->pdev = SA1111_FAKE_PCIDEV;
+	hcd->parent = &dev->dev;
 
 	retval = hcd_buffer_create (hcd);
 	if (retval != 0) {
@@ -167,8 +174,8 @@
 		goto err1;
 	}
 
-	set_irq_type(NIRQHCIM, IRQT_RISING);
-	retval = request_irq (NIRQHCIM, usb_hcd_sa1111_hcim_irq, SA_INTERRUPT,
+	set_irq_type(hcd->irq, IRQT_RISING);
+	retval = request_irq (hcd->irq, usb_hcd_sa1111_hcim_irq, SA_INTERRUPT,
 			      hcd->description, hcd);
 	if (retval != 0) {
 		dbg("request_irq failed");
@@ -191,7 +198,7 @@
 
 	if ((retval = driver->start (hcd)) < 0) 
 	{
-		usb_hcd_sa1111_remove(hcd);
+		usb_hcd_sa1111_remove(hcd, dev);
 		return retval;
 	}
 
@@ -202,8 +209,8 @@
 	hcd_buffer_destroy (hcd);
 	if (hcd) driver->hcd_free(hcd);
  err1:
-	sa1111_stop_hc();
-	release_mem_region(_USB_OHCI_OP_BASE, _USB_EXTENT);
+	sa1111_stop_hc(dev);
+	release_mem_region(dev->res.start, dev->res.end - dev->res.start + 1);
 	return retval;
 }
 
@@ -221,7 +228,7 @@
  * context, normally "rmmod", "apmd", or something similar.
  *
  */
-void usb_hcd_sa1111_remove (struct usb_hcd *hcd)
+void usb_hcd_sa1111_remove (struct usb_hcd *hcd, struct sa1111_dev *dev)
 {
 	struct usb_device	*hub;
 	void *base;
@@ -244,13 +251,13 @@
 
 	usb_deregister_bus (&hcd->self);
 	if (atomic_read (&hcd->self.refcnt) != 1)
-		err (__FUNCTION__ ": %s, count != 1", hcd->self.bus_name);
+		err ("%s: %s, count != 1", __FUNCTION__, hcd->self.bus_name);
 
 	base = hcd->regs;
 	hcd->driver->hcd_free (hcd);
 
-	sa1111_stop_hc();
-	release_mem_region(_USB_OHCI_OP_BASE, _USB_EXTENT);
+	sa1111_stop_hc(dev);
+	release_mem_region(dev->res.start, dev->res.end - dev->res.start + 1);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -275,7 +282,7 @@
 	}
 	ohci->regs = hcd->regs;
 
-	ohci->parent_dev = &sa1111->dev;
+	ohci->parent_dev = hcd->parent;
 
 	if (hc_reset (ohci) < 0) {
 		ohci_stop (hcd);
@@ -342,26 +349,67 @@
 
 /*-------------------------------------------------------------------------*/
 
-/* Only one SA-1111 ever exists. */
-static struct usb_hcd *the_sa1111_hcd;
+static int ohci_hcd_sa1111_drv_probe(struct device *_dev)
+{
+	struct sa1111_dev *dev = SA1111_DEV(_dev);
+	struct usb_hcd *hcd = NULL;
+	int ret;
+
+	ret = usb_hcd_sa1111_probe(&ohci_sa1111_hc_driver, &hcd, dev);
+
+	if (ret == 0)
+		dev->dev.driver_data = hcd;
+
+	return ret;
+}
+
+static int ohci_hcd_sa1111_drv_remove(struct device *_dev)
+{
+	struct sa1111_dev *dev = SA1111_DEV(_dev);
+	struct usb_hcd *hcd = dev->dev.driver_data;
+
+	usb_hcd_sa1111_remove(hcd, dev);
+
+	dev->dev.driver_data = NULL;
 
-static int __init ohci_hcd_sa1111_init (void) 
+	return 0;
+}
+
+static int ohci_hcd_sa1111_drv_suspend(struct device *dev, u32 state, u32 level)
+{
+	return 0;
+}
+
+static int ohci_hcd_sa1111_drv_resume(struct device *dev, u32 level)
+{
+	return 0;
+}
+
+static struct sa1111_driver ohci_hcd_sa1111_driver = {
+	.drv = {
+		.name		= "SA1111 OHCI",
+		.bus		= &sa1111_bus_type,
+		.probe		= ohci_hcd_sa1111_drv_probe,
+		.remove		= ohci_hcd_sa1111_drv_remove,
+		.suspend	= ohci_hcd_sa1111_drv_suspend,
+		.resume		= ohci_hcd_sa1111_drv_resume,
+	},
+	.devid			= SA1111_DEVID_USB,
+};
+
+static int __init ohci_hcd_sa1111_init (void)
 {
 	dbg (DRIVER_INFO " (SA-1111)");
 	dbg ("block sizes: ed %d td %d",
 		sizeof (struct ed), sizeof (struct td));
 
-	the_sa1111_hcd = 0;
-	return usb_hcd_sa1111_probe(&ohci_sa1111_hc_driver, &the_sa1111_hcd);
+	return driver_register(&ohci_hcd_sa1111_driver.drv);
 }
-module_init (ohci_hcd_sa1111_init);
 
-
-static void __exit ohci_hcd_sa1111_cleanup (void) 
-{	
-	if (the_sa1111_hcd) {
-		usb_hcd_sa1111_remove(the_sa1111_hcd);
-		the_sa1111_hcd = 0;
-	}
+static void __exit ohci_hcd_sa1111_cleanup (void)
+{
+	remove_driver(&ohci_hcd_sa1111_driver.drv);
 }
+
+module_init (ohci_hcd_sa1111_init);
 module_exit (ohci_hcd_sa1111_cleanup);
diff -Nru a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
--- a/drivers/usb/serial/cyberjack.c	Tue Oct  1 00:08:20 2002
+++ b/drivers/usb/serial/cyberjack.c	Tue Oct  1 00:08:20 2002
@@ -437,9 +437,7 @@
 			/* Throw away data. No better idea what to do with it. */
 			priv->wrfilled=0;
 			priv->wrsent=0;
-			queue_task(&port->tqueue, &tq_immediate);
-			mark_bh(IMMEDIATE_BH);
-			return;
+			goto exit;
 		}
 
 		dbg("%s - priv->wrsent=%d", __FUNCTION__,priv->wrsent);
@@ -453,16 +451,10 @@
 			priv->wrfilled=0;
 			priv->wrsent=0;
 		}
-
-		queue_task(&port->tqueue, &tq_immediate);
-		mark_bh(IMMEDIATE_BH);
-		return;
 	}
 
-	queue_task(&port->tqueue, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
-	
-	return;
+exit:
+	schedule_task(&port->tqueue);
 }
 
 static int __init cyberjack_init (void)
diff -Nru a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
--- a/drivers/usb/serial/empeg.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/usb/serial/empeg.c	Tue Oct  1 00:08:17 2002
@@ -362,11 +362,7 @@
 		return;
 	}
 
-	queue_task(&port->tqueue, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
-
-	return;
-
+	schedule_task(&port->tqueue);
 }
 
 
diff -Nru a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
--- a/drivers/usb/serial/ftdi_sio.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/usb/serial/ftdi_sio.c	Tue Oct  1 00:08:16 2002
@@ -484,10 +484,8 @@
 		dbg("nonzero write bulk status received: %d", urb->status);
 		return;
 	}
-	queue_task(&port->tqueue, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
 
-	return;
+	schedule_task(&port->tqueue);
 } /* ftdi_sio_write_bulk_callback */
 
 
diff -Nru a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
--- a/drivers/usb/serial/ipaq.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/usb/serial/ipaq.c	Tue Oct  1 00:08:16 2002
@@ -465,10 +465,8 @@
 		priv->active = 0;
 		spin_unlock_irqrestore(&write_list_lock, flags);
 	}
-	queue_task(&port->tqueue, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
-	
-	return;
+
+	schedule_task(&port->tqueue);
 }
 
 static int ipaq_write_room(struct usb_serial_port *port)
diff -Nru a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
--- a/drivers/usb/serial/ir-usb.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/usb/serial/ir-usb.c	Tue Oct  1 00:08:17 2002
@@ -426,10 +426,7 @@
 		urb->actual_length,
 		urb->transfer_buffer);
 
-	queue_task(&port->tqueue, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
-	
-	return;
+	schedule_task(&port->tqueue);
 }
 
 static void ir_read_bulk_callback (struct urb *urb)
diff -Nru a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
--- a/drivers/usb/serial/keyspan.c	Tue Oct  1 00:08:15 2002
+++ b/drivers/usb/serial/keyspan.c	Tue Oct  1 00:08:15 2002
@@ -447,10 +447,8 @@
 	p_priv = (struct keyspan_port_private *)(port->private);
 	dbg ("%s - urb %d", __FUNCTION__, urb == p_priv->out_urbs[1]); 
 
-	if (port->open_count) {
-		queue_task(&port->tqueue, &tq_immediate);
-		mark_bh(IMMEDIATE_BH);
-	}
+	if (port->open_count)
+		schedule_task(&port->tqueue);
 }
 
 static void	usa26_inack_callback(struct urb *urb)
diff -Nru a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
--- a/drivers/usb/serial/kl5kusb105.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/usb/serial/kl5kusb105.c	Tue Oct  1 00:08:17 2002
@@ -577,10 +577,7 @@
 	}
 
 	/* from generic_write_bulk_callback */
-	queue_task(&port->tqueue, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
-
-	return;
+	schedule_task(&port->tqueue);
 } /* klsi_105_write_bulk_completion_callback */
 
 
diff -Nru a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
--- a/drivers/usb/serial/mct_u232.c	Tue Oct  1 00:08:18 2002
+++ b/drivers/usb/serial/mct_u232.c	Tue Oct  1 00:08:18 2002
@@ -507,8 +507,7 @@
 		
 	} else {
 		/* from generic_write_bulk_callback */
-		queue_task(&port->tqueue, &tq_immediate);
-		mark_bh(IMMEDIATE_BH);
+		schedule_task(&port->tqueue);
 	}
 
 	return;
diff -Nru a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
--- a/drivers/usb/serial/omninet.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/usb/serial/omninet.c	Tue Oct  1 00:08:16 2002
@@ -359,12 +359,9 @@
 		return;
 	}
 
-	queue_task(&port->tqueue, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
+	schedule_task(&port->tqueue);
 
 //	dbg("omninet_write_bulk_callback, tty %0x\n", tty);
-
-	return;
 }
 
 
diff -Nru a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
--- a/drivers/usb/serial/pl2303.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/usb/serial/pl2303.c	Tue Oct  1 00:08:17 2002
@@ -705,10 +705,7 @@
 		return;
 	}
 
-	queue_task(&port->tqueue, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
-
-	return;
+	schedule_task(&port->tqueue);
 }
 
 
diff -Nru a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c
--- a/drivers/usb/serial/usbserial.c	Tue Oct  1 00:08:17 2002
+++ b/drivers/usb/serial/usbserial.c	Tue Oct  1 00:08:17 2002
@@ -1092,10 +1092,7 @@
 
 	usb_serial_port_softint((void *)port);
 
-	queue_task(&port->tqueue, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
-
-	return;
+	schedule_task(&port->tqueue);
 }
 
 static void generic_shutdown (struct usb_serial *serial)
diff -Nru a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
--- a/drivers/usb/serial/visor.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/usb/serial/visor.c	Tue Oct  1 00:08:16 2002
@@ -182,9 +182,10 @@
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_I705_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID) },
-	{ USB_DEVICE(PALM_VENDOR_ID, PALM_I705_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) },
 	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID) },
@@ -202,9 +203,10 @@
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_I705_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID) },
-	{ USB_DEVICE(PALM_VENDOR_ID, PALM_I705_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID) },
@@ -458,10 +460,7 @@
 	/* free up the transfer buffer, as usb_free_urb() does not do this */
 	kfree (urb->transfer_buffer);
 
-	queue_task(&port->tqueue, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
-
-	return;
+	schedule_task(&port->tqueue);
 }
 
 
diff -Nru a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h
--- a/drivers/usb/serial/visor.h	Tue Oct  1 00:08:16 2002
+++ b/drivers/usb/serial/visor.h	Tue Oct  1 00:08:16 2002
@@ -27,6 +27,7 @@
 #define PALM_I705_ID			0x0020
 #define PALM_M125_ID			0x0040
 #define PALM_M130_ID			0x0050
+#define PALM_ZIRE_ID			0x0070
 
 #define SONY_VENDOR_ID			0x054C
 #define SONY_CLIE_3_5_ID		0x0038
diff -Nru a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
--- a/drivers/usb/serial/whiteheat.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/usb/serial/whiteheat.c	Tue Oct  1 00:08:16 2002
@@ -918,10 +918,7 @@
 
 	usb_serial_port_softint((void *)port);
 
-	queue_task(&port->tqueue, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
-
-	return;
+	schedule_task(&port->tqueue);
 }
 
 
diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
--- a/drivers/usb/storage/transport.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/usb/storage/transport.c	Tue Oct  1 00:08:16 2002
@@ -530,6 +530,8 @@
 	if (result < 0)
 		return result;
 
+	printk(KERN_ERR "usb_stor_clear_halt() WORKED!\n");
+
 	/* reset the toggles and endpoint flags */
 	usb_endpoint_running(us->pusb_dev, usb_pipeendpoint(pipe),
 		usb_pipeout(pipe));
diff -Nru a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
--- a/drivers/usb/storage/usb.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/usb/storage/usb.c	Tue Oct  1 00:08:16 2002
@@ -311,12 +311,12 @@
 	daemonize();
 
 	/* avoid getting signals */
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	flush_signals(current);
 	current->flags |= PF_IOTHREAD;
 	sigfillset(&current->blocked);
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	/* set our name for identification purposes */
 	sprintf(current->comm, "usb-storage-%d", us->host_number);
diff -Nru a/drivers/video/matrox/Makefile b/drivers/video/matrox/Makefile
--- a/drivers/video/matrox/Makefile	Tue Oct  1 00:08:16 2002
+++ b/drivers/video/matrox/Makefile	Tue Oct  1 00:08:16 2002
@@ -18,5 +18,3 @@
 
 include $(TOPDIR)/Rules.make
 
-clean:
-	rm -f core *.o *.a *.s
diff -Nru a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
--- a/drivers/video/sa1100fb.c	Tue Oct  1 00:08:16 2002
+++ b/drivers/video/sa1100fb.c	Tue Oct  1 00:08:16 2002
@@ -209,17 +209,17 @@
  * IMHO this looks wrong.  In 8BPP, length should be 8.
  */
 static struct sa1100fb_rgb rgb_8 = {
-	red:	{ offset: 0,  length: 4, },
-	green:	{ offset: 0,  length: 4, },
-	blue:	{ offset: 0,  length: 4, },
-	transp:	{ offset: 0,  length: 0, },
+	.red	= { .offset = 0,  .length = 4, },
+	.green	= { .offset = 0,  .length = 4, },
+	.blue	= { .offset = 0,  .length = 4, },
+	.transp	= { .offset = 0,  .length = 0, },
 };
 
 static struct sa1100fb_rgb def_rgb_16 = {
-	red:	{ offset: 11, length: 5, },
-	green:	{ offset: 5,  length: 6, },
-	blue:	{ offset: 0,  length: 5, },
-	transp:	{ offset: 0,  length: 0, },
+	.red	= { .offset = 11, .length = 5, },
+	.green	= { .offset = 5,  .length = 6, },
+	.blue	= { .offset = 0,  .length = 5, },
+	.transp	= { .offset = 0,  .length = 0, },
 };
 
 #ifdef CONFIG_SA1100_ASSABET
@@ -230,155 +230,151 @@
  * instead (def_rgb_16).
  */
 static struct sa1100fb_mach_info lq039q2ds54_info __initdata = {
-	pixclock:	171521,		bpp:		16,
-	xres:		320,		yres:		240,
+	.pixclock	= 171521,	.bpp		= 16,
+	.xres		= 320,		.yres		= 240,
 
-	hsync_len:	5,		vsync_len:	1,
-	left_margin:	61,		upper_margin:	3,
-	right_margin:	9,		lower_margin:	0,
+	.hsync_len	= 5,		.vsync_len	= 1,
+	.left_margin	= 61,		.upper_margin	= 3,
+	.right_margin	= 9,		.lower_margin	= 0,
 
-	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 
-	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
+	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
 };
 #else
 static struct sa1100fb_mach_info pal_info __initdata = {
-	pixclock:	67797,		bpp:		16,
-	xres:		640,		yres:		512,
+	.pixclock	= 67797,	.bpp		= 16,
+	.xres		= 640,		.yres		= 512,
 
-	hsync_len:	64,		vsync_len:	6,
-	left_margin:	125,		upper_margin:	70,
-	right_margin:	115,		lower_margin:	36,
+	.hsync_len	= 64,		.vsync_len	= 6,
+	.left_margin	= 125,		.upper_margin	= 70,
+	.right_margin	= 115,		.lower_margin	= 36,
 
-	sync:		0,
-
-	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg |	LCCR3_ACBsDiv(512),
+	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
 };
 #endif
 #endif
 
 #ifdef CONFIG_SA1100_H3800
 static struct sa1100fb_mach_info h3800_info __initdata = {
-	pixclock:	174757, 	bpp:		16,
-	xres:		320,		yres:		240,
+	.pixclock	= 174757, 	.bpp		= 16,
+	.xres		= 320,		.yres		= 240,
+
+	.hsync_len	= 3,		.vsync_len	= 3,
+	.left_margin	= 12,		.upper_margin	= 10,
+	.right_margin	= 17,		.lower_margin	= 1,
 
-	hsync_len:	3,		vsync_len:	3,
-	left_margin:	12,		upper_margin:	10,
-	right_margin:	17,		lower_margin:	1,
-
-	sync:		0,		cmap_static:	1,
-
-	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-	lccr3:		LCCR3_ACBsDiv(2) | LCCR3_PixRsEdg | LCCR3_OutEnH |
-			LCCR3_ACBsCntOff,
+	.cmap_static	= 1,
+
+	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
 };
 #endif
 
 #ifdef CONFIG_SA1100_H3600
 static struct sa1100fb_mach_info h3600_info __initdata = {
-	pixclock:	174757, 	bpp:		16,
-	xres:		320,		yres:		240,
+	.pixclock	= 174757, 	.bpp		= 16,
+	.xres		= 320,		.yres		= 240,
+
+	.hsync_len	= 3,		.vsync_len	= 3,
+	.left_margin	= 12,		.upper_margin	= 10,
+	.right_margin	= 17,		.lower_margin	= 1,
 
-	hsync_len:	3,		vsync_len:	3,
-	left_margin:	12,		upper_margin:	10,
-	right_margin:	17,		lower_margin:	1,
-
-	sync:		0,		cmap_static:	1,
-
-	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-	lccr3:		LCCR3_ACBsDiv(2) | LCCR3_PixRsEdg | LCCR3_OutEnH |
-			LCCR3_ACBsCntOff,
+	.cmap_static	= 1,
+
+	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
 };
 
 static struct sa1100fb_rgb h3600_rgb_16 = {
-	red:	{ offset: 12, length: 4, },
-	green:	{ offset: 7,  length: 4, },
-	blue:	{ offset: 1,  length: 4, },
-	transp: { offset: 0,  length: 0, },
+	.red	= { .offset = 12, .length = 4, },
+	.green	= { .offset = 7,  .length = 4, },
+	.blue	= { .offset = 1,  .length = 4, },
+	.transp	= { .offset = 0,  .length = 0, },
 };
 #endif
 
 #ifdef CONFIG_SA1100_H3100
 static struct sa1100fb_mach_info h3100_info __initdata = {
-	pixclock:	406977, 	bpp:		4,
-	xres:		320,		yres:		240,
+	.pixclock	= 406977, 	.bpp		= 4,
+	.xres		= 320,		.yres		= 240,
 
-	hsync_len:	26,		vsync_len:	41,
-	left_margin:	4,		upper_margin:	0,
-	right_margin:	4,		lower_margin:	0,
-
-	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-	cmap_greyscale: 1,
-	cmap_inverse:	1,
+	.hsync_len	= 26,		.vsync_len	= 41,
+	.left_margin	= 4,		.upper_margin	= 0,
+	.right_margin	= 4,		.lower_margin	= 0,
+
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	.cmap_greyscale	= 1,
+	.cmap_inverse	= 1,
 
-	lccr0:		LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas,
-	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
+	.lccr0		= LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
 };
 #endif
 
 #ifdef CONFIG_SA1100_BRUTUS
 static struct sa1100fb_mach_info brutus_info __initdata = {
-	pixclock:	0,		bpp:		8,
-	xres:		320,		yres:		240,
+	.pixclock	= 0,		.bpp		= 8,
+	.xres		= 320,		.yres		= 240,
 
-	hsync_len:	3,		vsync_len:	1,
-	left_margin:	41,		upper_margin:	0,
-	right_margin:	101,		lower_margin:	0,
-
-	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-
-	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Pas,
-	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) |
-			LCCR3_PixClkDiv(44),
+	.hsync_len	= 3,		.vsync_len	= 1,
+	.left_margin	= 41,		.upper_margin	= 0,
+	.right_margin	= 101,		.lower_margin	= 0,
+
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Pas,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) |
+			  LCCR3_PixClkDiv(44),
 };
 #endif
 
 #ifdef CONFIG_SA1100_CERF
 static struct sa1100fb_mach_info cerf_info __initdata = {
 #if defined(CONFIG_CERF_LCD_72_A)
-	pixclock:       171521,         bpp:            8,
-	xres:		640,		yres:		480,
-	lccr0:		LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
-	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) |
-			LCCR3_PixClkDiv(38),
+	.pixclock	= 171521, 	.bpp		= 8,
+	.xres		= 640,		.yres		= 480,
+	.lccr0		= LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) |
+			  LCCR3_PixClkDiv(38),
 #elif defined(CONFIG_CERF_LCD_57_A)
-	pixclock:       171521,         bpp:            8,
-	xres:		320,		yres:		240,
-	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Pas,
-	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) |
-			LCCR3_PixClkDiv(38),
+	.pixclock	= 171521, 	.bpp		= 8,
+	.xres		= 320,		.yres		= 240,
+	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Pas,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) |
+			  LCCR3_PixClkDiv(38),
 #elif defined(CONFIG_CERF_LCD_38_A)
-	pixclock:       171521,         bpp:            8,
-	xres:		240,		yres:		320,
-	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Pas,
-	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(56) |
-			LCCR3_PixClkDiv(38),
+	.pixclock	= 171521, 	.bpp		= 8,
+	.xres		= 240,		.yres		= 320,
+	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Pas,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(56) |
+			  LCCR3_PixClkDiv(38),
 #elif defined(CONFIG_CERF_LCD_38_B)
-	pixclock:	171521, 	bpp:		4,
-	xres:		320,		yres:		240,
-	lccr0:		LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas,
-	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(56) |
-			LCCR3_PixClkDiv(38),
+	.pixclock	= 171521,	.bpp		= 4,
+	.xres		= 320,		.yres		= 240,
+	.lccr0		= LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(56) |
+			  LCCR3_PixClkDiv(38),
 #else
 #error "Must have a CerfBoard LCD form factor selected"
 #endif
 
-	hsync_len:	5,		vsync_len:	1,
-	left_margin:	61,		upper_margin:	3,
-	right_margin:	9,		lower_margin:	0,
+	.hsync_len	= 5,		.vsync_len	= 1,
+	.left_margin	= 61,		.upper_margin	= 3,
+	.right_margin	= 9,		.lower_margin	= 0,
 
-	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 
 };
 
 #if 0
 static struct sa1100fb_rgb cerf_rgb_16 = {
-	red:	{ offset: 8,	length: 4, },
-	green:	{ offset: 4,	length: 4, },
-	blue:	{ offset: 0,	length: 4, },
-	transp:	{ offset: 0,	length: 0, },
+	.red	= { .offset = 8,	.length = 4, },
+	.green	= { .offset = 4,	.length = 4, },
+	.blue	= { .offset = 0,	.length = 4, },
+	.transp	= { .offset = 0,	.length = 0, },
 };
 #endif
 #endif
@@ -386,56 +382,54 @@
 #ifdef CONFIG_SA1100_FREEBIRD
 #warning Please check this carefully
 static struct sa1100fb_mach_info freebird_info __initdata = {
-	pixclock:	171521,		bpp:		16,
-	xres:		240,		yres:		320,
+	.pixclock	= 171521,	.bpp		= 16,
+	.xres		= 240,		.yres		= 320,
 
-	hsync_len:	3,		vsync_len:	2,
-	left_margin:	2,		upper_margin:	0,
-	right_margin:	2,		lower_margin:	0,
+	.hsync_len	= 3,		.vsync_len	= 2,
+	.left_margin	= 2,		.upper_margin	= 0,
+	.right_margin	= 2,		.lower_margin	= 0,
 
-	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 
-	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Pas,
-	lccr3:		LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsDiv(2),
+	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Pas,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsDiv(2),
 };
 
 static struct sa1100fb_rgb freebird_rgb_16 = {
-	red:	{ offset: 8,  length: 4, },
-	green:	{ offset: 4,  length: 4, },
-	blue:	{ offset: 0,  length: 4, },
-	transp:	{ offset: 12, length: 4, },
+	.red	= { .offset = 8,  .length = 4, },
+	.green	= { .offset = 4,  .length = 4, },
+	.blue	= { .offset = 0,  .length = 4, },
+	.transp	= { .offset = 12, .length = 4, },
 };
 #endif
 
 #ifdef CONFIG_SA1100_GRAPHICSCLIENT
 static struct sa1100fb_mach_info graphicsclient_info __initdata = {
-	pixclock:	53500,		bpp:		8,
-	xres:		640,		yres:		480,
-
-	hsync_len:	9,		vsync_len:	9,
-	left_margin:	54,		upper_margin:	24,
-	right_margin:	54,		lower_margin:	32,
+	.pixclock	= 53500,	.bpp		= 8,
+	.xres		= 640,		.yres		= 480,
 
-	sync:		0,
+	.hsync_len	= 9,		.vsync_len	= 9,
+	.left_margin	= 54,		.upper_margin	= 24,
+	.right_margin	= 54,		.lower_margin	= 32,
 
-	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
+	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
 };
 #endif
 
 #ifdef CONFIG_SA1100_HUW_WEBPANEL
 static struct sa1100fb_mach_info huw_webpanel_info __initdata = {
-	pixclock:	0,		bpp:		8,
-	xres:		640,		yres:		480,
+	.pixclock	= 0,		.bpp		= 8,
+	.xres		= 640,		.yres		= 480,
 
-	hsync_len:	3,		vsync_len:	1,
-	left_margin:	41,		upper_margin:	0,
-	right_margin:	101,		lower_margin:	0,
+	.hsync_len	= 3,		.vsync_len	= 1,
+	.left_margin	= 41,		.upper_margin	= 0,
+	.right_margin	= 101,		.lower_margin	= 0,
 
-	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 
-	lccr0:		LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
-	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) | 8,
+	.lccr0		= LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) | 8,
 #error FIXME
 	/*
 	 * FIXME: please get rid of the '| 8' in preference to an
@@ -446,99 +440,94 @@
 
 #ifdef LART_GREY_LCD
 static struct sa1100fb_mach_info lart_grey_info __initdata = {
-	pixclock:	150000,		bpp:		4,
-	xres:		320,		yres:		240,
+	.pixclock	= 150000,	.bpp		= 4,
+	.xres		= 320,		.yres		= 240,
 
-	hsync_len:	1,		vsync_len:	1,
-	left_margin:	4,		upper_margin:	0,
-	right_margin:	2,		lower_margin:	0,
+	.hsync_len	= 1,		.vsync_len	= 1,
+	.left_margin	= 4,		.upper_margin	= 0,
+	.right_margin	= 2,		.lower_margin	= 0,
 
-	cmap_greyscale:	1,
-	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	.cmap_greyscale	= 1,
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 
-	lccr0:		LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_4PixMono,
-	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
+	.lccr0		= LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_4PixMono,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
 };
 #endif
 #ifdef LART_COLOR_LCD
 static struct sa1100fb_mach_info lart_color_info __initdata = {
-	pixclock:	150000,		bpp:		16,
-	xres:		320,		yres:		240,
+	.pixclock	= 150000,	.bpp		= 16,
+	.xres		= 320,		.yres		= 240,
 
-	hsync_len:	2,		vsync_len:	3,
-	left_margin:	69,		upper_margin:	14,
-	right_margin:	8,		lower_margin:	4,
+	.hsync_len	= 2,		.vsync_len	= 3,
+	.left_margin	= 69,		.upper_margin	= 14,
+	.right_margin	= 8,		.lower_margin	= 4,
 
-	sync:		0,
-
-	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-	lccr3:		LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
+	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
 };
 #endif
 #ifdef LART_VIDEO_OUT
 static struct sa1100fb_mach_info lart_video_info __initdata = {
-	pixclock:	39721,		bpp:		16,
-	xres:		640,		yres:		480,
+	.pixclock	= 39721,	.bpp		= 16,
+	.xres		= 640,		.yres		= 480,
 
-	hsync_len:	95,		vsync_len:	2,
-	left_margin:	40,		upper_margin:	32,
-	right_margin:	24,		lower_margin:	11,
+	.hsync_len	= 95,		.vsync_len	= 2,
+	.left_margin	= 40,		.upper_margin	= 32,
+	.right_margin	= 24,		.lower_margin	= 11,
 
-	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 
-	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-	lccr3:		LCCR3_OutEnL | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
+	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	.lccr3		= LCCR3_OutEnL | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
 };
 #endif
 
 #ifdef LART_KIT01_LCD
-static struct sa1100fb_mach_info lart_kit01_info __initdata =
-{
-	pixclock:	63291,		bpp:		16,
-	xres:		640,		yres:		480,
+static struct sa1100fb_mach_info lart_kit01_info __initdata = {
+	.pixclock	= 63291,	.bpp		= 16,
+	.xres		= 640,		.yres		= 480,
+
+	.hsync_len	= 64,		.vsync_len	= 3,
+	.left_margin	= 122,		.upper_margin	= 45,
+	.right_margin	= 10,		.lower_margin	= 10,
 
-	hsync_len:	64,		vsync_len:	3,
-	left_margin:	122,		upper_margin:	45,
-	right_margin:	10,		lower_margin:	10,
-
-	sync:		0,
-
-	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-	lccr3:		LCCR3_OutEnH | LCCR3_PixFlEdg
+	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixFlEdg
 };
 #endif
 
 #ifdef CONFIG_SA1100_SHANNON
 static struct sa1100fb_mach_info shannon_info __initdata = {
-	pixclock:	152500,		bpp:		8,
-	xres:		640,		yres:		480,
+	.pixclock	= 152500,	.bpp		= 8,
+	.xres		= 640,		.yres		= 480,
 
-	hsync_len:	4,		vsync_len:	3,
-	left_margin:	2,		upper_margin:	0,
-	right_margin:	1,		lower_margin:	0,
+	.hsync_len	= 4,		.vsync_len	= 3,
+	.left_margin	= 2,		.upper_margin	= 0,
+	.right_margin	= 1,		.lower_margin	= 0,
 
-	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 
 
-	lccr0:		LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
-	lccr3:		LCCR3_ACBsDiv(512),
+	.lccr0		= LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
+	.lccr3		= LCCR3_ACBsDiv(512),
 };
 #endif
 
 #ifdef CONFIG_SA1100_OMNIMETER
 static struct sa1100fb_mach_info omnimeter_info __initdata = {
-	pixclock:	0,		bpp:		4,
-	xres:		480,		yres:		320,
+	.pixclock	= 0,		.bpp		= 4,
+	.xres		= 480,		.yres		= 320,
 
-	hsync_len:	1,		vsync_len:	1,
-	left_margin:	10,		upper_margin:	0,
-	right_margin:	10,		lower_margin:	0,
-
-	cmap_greyscale:	1,
-	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-
-	lccr0:		LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_8PixMono,
-	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(255) |
-			LCCR3_PixClkDiv(44),
+	.hsync_len	= 1,		.vsync_len	= 1,
+	.left_margin	= 10,		.upper_margin	= 0,
+	.right_margin	= 10,		.lower_margin	= 0,
+
+	.cmap_greyscale	= 1,
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+	.lccr0		= LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_8PixMono,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(255) |
+			  LCCR3_PixClkDiv(44),
 #error FIXME: fix pixclock, ACBsDiv
 	/*
 	 * FIXME: I think ACBsDiv is wrong above - should it be 512 (disabled)?
@@ -549,17 +538,17 @@
 
 #ifdef CONFIG_SA1100_PANGOLIN
 static struct sa1100fb_mach_info pangolin_info __initdata = {
-	pixclock:	341521,		bpp:		16,
-	xres:		800,		yres:		600,
+	.pixclock	= 341521,	.bpp		= 16,
+	.xres		= 800,		.yres		= 600,
 
-	hsync_len:	64,		vsync_len:	7,
-	left_margin:	160,		upper_margin:	7,
-	right_margin:	24,		lower_margin:	1,
+	.hsync_len	= 64,		.vsync_len	= 7,
+	.left_margin	= 160,		.upper_margin	= 7,
+	.right_margin	= 24,		.lower_margin	= 1,
 
-	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 
-	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-	lccr3:		LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsCntOff,
+	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsCntOff,
 };
 #endif
 
@@ -571,49 +560,47 @@
  * NB likely to be increased to ease bus timings wrt pcmcia interface
  */
 static struct sa1100fb_mach_info stork_tft_info __initdata = {
-	pixclock:	28935,		bpp:		16,
-	xres:		640,		yres:		480,
+	.pixclock	= 28935,	.bpp		= 16,
+	.xres		= 640,		.yres		= 480,
 
-	hsync_len:	64,		vsync_len:	2,
-	left_margin:	48,		upper_margin:	12,
-	right_margin:	48,		lower_margin:	31,
+	.hsync_len	= 64,		.vsync_len	= 2,
+	.left_margin	= 48,		.upper_margin	= 12,
+	.right_margin	= 48,		.lower_margin	= 31,
 
-	sync:		0,
-
-	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg,
+	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsCntOff,
 };
 
 static struct sa1100fb_rgb stork_tft_rgb_16 = {
-	red:	{ offset: 11, length: 5, },
-	green:	{ offset: 5,  length: 6, },
-	blue:	{ offset: 0,  length: 5, },
-	transp:	{ offset: 0,  length: 0, },
+	.red	= { .offset = 11, .length = 5, },
+	.green	= { .offset = 5,  .length = 6, },
+	.blue	= { .offset = 0,  .length = 5, },
+	.transp	= { .offset = 0,  .length = 0, },
 };
 
 #else	/* Kyocera DSTN */
 
 static struct sa1100fb_mach_info stork_dstn_info __initdata = {
-	pixclock:	0,		bpp:		16,
-	xres:		640,		yres:		480,
+	.pixclock	= 0,		.bpp		= 16,
+	.xres		= 640,		.yres		= 480,
 
-	hsync_len:	2,		vsync_len:	2,
-	left_margin:	2,		upper_margin:	0,
-	right_margin:	2,		lower_margin:	0,
+	.hsync_len	= 2,		.vsync_len	= 2,
+	.left_margin	= 2,		.upper_margin	= 0,
+	.right_margin	= 2,		.lower_margin	= 0,
 
-	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT ,
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT ,
 
-	lccr0:		LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
+	.lccr0		= LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
 #error Fixme
-	lccr3:		0xff00 |
+	.lccr3		= 0xff00 |
 			0x18		/* ought to be 0x14 but DMA isn't up to that as yet */
 };
 
 static struct sa1100fb_rgb stork_dstn_rgb_16 = {
-	red:	{ offset: 8,  length: 4, },
-	green:	{ offset: 4,  length: 4, },
-	blue:	{ offset: 0,  length: 4, },
-	transp:	{ offset: 0,  length: 0, },
+	.red	= { .offset = 8,  .length = 4, },
+	.green	= { .offset = 4,  .length = 4, },
+	.blue	= { .offset = 0,  .length = 4, },
+	.transp	= { .offset = 0,  .length = 0, },
 };
 #endif
 #endif
@@ -630,34 +617,31 @@
  *	=>4.32Mhz => 231481E-12s
  */
 static struct sa1100fb_mach_info system3_info __initdata = {
-	pixclock:	231481,		bpp:		8,
-	xres:		640,		yres:		480,
+	.pixclock	= 231481,	.bpp		= 8,
+	.xres		= 640,		.yres		= 480,
+
+	.hsync_len	= 2,		.vsync_len	= 2,
+	.left_margin	= 2,		.upper_margin	= 0,
+	.right_margin	= 2,		.lower_margin	= 0,
 
-	hsync_len:	2,		vsync_len:	2,
-	left_margin:	2,		upper_margin:	0,
-	right_margin:	2,		lower_margin:	0,
-
-	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-
-	lccr0:		LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
-	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg |	LCCR3_ACBsDiv(512) |
-			LCCR3_ACBsCntOff,
+	.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+	.lccr0		= LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
 };
 #endif
 
 #ifdef CONFIG_SA1100_XP860
 static struct sa1100fb_mach_info xp860_info __initdata = {
-	pixclock:	0,		bpp:		8,
-	xres:		1024,		yres:		768,
-
-	hsync_len:	3,		vsync_len:	3,
-	left_margin:	3,		upper_margin:	2,
-	right_margin:	2,		lower_margin:	1,
+	.pixclock	= 0,		.bpp		= 8,
+	.xres		= 1024,		.yres		= 768,
 
-	sync:		0,
+	.hsync_len	= 3,		.vsync_len	= 3,
+	.left_margin	= 3,		.upper_margin	= 2,
+	.right_margin	= 2,		.lower_margin	= 1,
 
-	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
-	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_PixClkDiv(6),
+	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_PixClkDiv(6),
 };
 #endif
 
@@ -808,33 +792,7 @@
 	local_irq_restore(flags);
 }
 
-/*
- * Get the VAR structure pointer for the specified console
- */
-static inline struct fb_var_screeninfo *get_con_var(struct fb_info *info, int con)
-{
-	return (con == info->currcon || con == -1) ? &info->var : &fb_display[con].var;
-}
-
-/*
- * Get the DISPLAY structure pointer for the specified console
- */
-static inline struct display *get_con_display(struct fb_info *info, int con)
-{
-	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
-	return (con < 0) ? fbi->fb.disp : &fb_display[con];
-}
-
-/*
- * Get the CMAP pointer for the specified console
- */
-static inline struct fb_cmap *get_con_cmap(struct fb_info *info, int con)
-{
-	return (con == info->currcon || con == -1) ? &info->cmap : &fb_display[con].cmap;
-}
-
-static inline u_int
-chan_to_field(u_int chan, struct fb_bitfield *bf)
+static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
 {
 	chan &= 0xffff;
 	chan >>= 16 - bf->length;
@@ -844,8 +802,7 @@
 /*
  * Convert bits-per-pixel to a hardware palette PBS value.
  */
-static inline u_int
-palette_pbs(struct fb_var_screeninfo *var)
+static inline u_int palette_pbs(struct fb_var_screeninfo *var)
 {
 	int ret = 0;
 	switch (var->bits_per_pixel) {
@@ -888,8 +845,7 @@
 		   u_int trans, struct fb_info *info)
 {
 	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
-	struct display *disp = get_con_display(info, info->currcon);
-	u_int val;
+	unsigned int val;
 	int ret = 1;
 
 	/*
@@ -898,7 +854,7 @@
 	 * is what you poke into the framebuffer to produce the
 	 * colour you requested.
 	 */
-	if (disp->inverse) {
+	if (fbi->cmap_inverse) {
 		red   = 0xffff - red;
 		green = 0xffff - green;
 		blue  = 0xffff - blue;
@@ -912,7 +868,7 @@
 		red = green = blue = (19595 * red + 38470 * green +
 					7471 * blue) >> 16;
 
-	switch (fbi->fb.disp->visual) {
+	switch (fbi->fb.fix.visual) {
 	case FB_VISUAL_TRUECOLOR:
 		/*
 		 * 12 or 16-bit True Colour.  We encode the RGB value
@@ -942,38 +898,29 @@
 /*
  *  sa1100fb_display_dma_period()
  *    Calculate the minimum period (in picoseconds) between two DMA
- *    requests for the LCD controller.
+ *    requests for the LCD controller.  If we hit this, it means we're
+ *    doing nothing but LCD DMA.
  */
-static unsigned int
-sa1100fb_display_dma_period(struct fb_var_screeninfo *var)
+static unsigned int sa1100fb_display_dma_period(struct fb_var_screeninfo *var)
 {
-	unsigned int mem_bits_per_pixel;
-
-	mem_bits_per_pixel = var->bits_per_pixel;
-	if (mem_bits_per_pixel == 12)
-		mem_bits_per_pixel = 16;
-
 	/*
 	 * Period = pixclock * bits_per_byte * bytes_per_transfer
 	 *		/ memory_bits_per_pixel;
 	 */
-	return var->pixclock * 8 * 16 / mem_bits_per_pixel;
+	return var->pixclock * 8 * 16 / var->bits_per_pixel;
 }
 
 /*
- *  sa1100fb_decode_var():
- *    Get the video params out of 'var'. If a value doesn't fit, round it up,
- *    if it's too big, return -EINVAL.
- *
- *    Suggestion: Round up in the following order: bits_per_pixel, xres,
+ *  sa1100fb_check_var():
+ *    Round up in the following order: bits_per_pixel, xres,
  *    yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
  *    bitfields, horizontal timing, vertical timing.
  */
 static int
-sa1100fb_validate_var(struct fb_var_screeninfo *var,
-		      struct sa1100fb_info *fbi)
+sa1100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
-	int ret = -EINVAL;
+	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
+	int rgbidx;
 
 	if (var->xres < MIN_XRES)
 		var->xres = MIN_XRES;
@@ -983,42 +930,60 @@
 		var->xres = fbi->max_xres;
 	if (var->yres > fbi->max_yres)
 		var->yres = fbi->max_yres;
-	var->xres_virtual =
-	    var->xres_virtual < var->xres ? var->xres : var->xres_virtual;
-	var->yres_virtual =
-	    var->yres_virtual < var->yres ? var->yres : var->yres_virtual;
+	var->xres_virtual = max(var->xres_virtual, var->xres);
+	var->yres_virtual = max(var->yres_virtual, var->yres);
 
 	DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel);
 	switch (var->bits_per_pixel) {
 #ifdef FBCON_HAS_CFB4
-	case 4:		ret = 0; break;
+	case 4:
+		rgbidx = RGB_8;
+		break;
 #endif
 #ifdef FBCON_HAS_CFB8
-	case 8:		ret = 0; break;
+	case 8:
+		rgbidx = RGB_8;
+		break;
 #endif
 #ifdef FBCON_HAS_CFB16
-	case 16:	ret = 0; break;
+	case 16:
+		rgbidx = RGB_16;
+		break;
 #endif
 	default:
-		break;
+		return -EINVAL;
 	}
 
+	/*
+	 * Copy the RGB parameters for this display
+	 * from the machine specific parameters.
+	 */
+	var->red    = fbi->rgb[rgbidx]->red;
+	var->green  = fbi->rgb[rgbidx]->green;
+	var->blue   = fbi->rgb[rgbidx]->blue;
+	var->transp = fbi->rgb[rgbidx]->transp;
+
+	DPRINTK("RGBT length = %d:%d:%d:%d\n",
+		var->red.length, var->green.length, var->blue.length,
+		var->transp.length);
+
+	DPRINTK("RGBT offset = %d:%d:%d:%d\n",
+		var->red.offset, var->green.offset, var->blue.offset,
+		var->transp.offset);
+
 #ifdef CONFIG_CPU_FREQ
 	printk(KERN_DEBUG "dma period = %d ps, clock = %d kHz\n",
 		sa1100fb_display_dma_period(var),
 		cpufreq_get(smp_processor_id()));
 #endif
 
-	return ret;
+	return 0;
 }
 
 static inline void sa1100fb_set_truecolor(u_int is_true_color)
 {
-	DPRINTK("true_color = %d\n", is_true_color);
-
 	if (machine_is_assabet()) {
-#if 1
-		// phase 4 or newer Assabet's
+#if 1		// phase 4 or newer Assabet's
 		if (is_true_color)
 			ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB);
 		else
@@ -1033,10 +998,30 @@
 	}
 }
 
-static void
-sa1100fb_hw_set_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi)
+/*
+ * sa1100fb_set_par():
+ *	Set the user defined part of the display for the specified console
+ */
+static int sa1100fb_set_par(struct fb_info *info)
 {
-	u_long palette_mem_size;
+	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
+	struct fb_var_screeninfo *var = &info->var;
+	unsigned long palette_mem_size;
+
+	DPRINTK("set_par\n");
+
+	if (var->bits_per_pixel == 16)
+		fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR;
+	else if (!fbi->cmap_static)
+		fbi->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
+	else {
+		/*
+		 * Some people have weird ideas about wanting static
+		 * pseudocolor maps.  I suspect their user space
+		 * applications are broken.
+		 */
+		fbi->fb.fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
+	}
 
 	fbi->palette_size = var->bits_per_pixel == 8 ? 256 : 16;
 
@@ -1047,10 +1032,10 @@
 	fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
 	fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
 
-	fb_set_cmap(&fbi->fb.cmap, 1, &fbi->fb);
-
-	/* Set board control register to handle new color depth */
-	sa1100fb_set_truecolor(var->bits_per_pixel >= 16);
+	/*
+	 * Set (any) board control register to handle new color depth
+	 */
+	sa1100fb_set_truecolor(fbi->fb.fix.visual == FB_VISUAL_TRUECOLOR);
 
 #ifdef CONFIG_SA1100_OMNIMETER
 #error Do we have to do this here?   We already do it at init time.
@@ -1060,9 +1045,7 @@
 
 	sa1100fb_activate_var(var, fbi);
 
-	fbi->palette_cpu[0] = (fbi->palette_cpu[0] &
-					 0xcfff) | palette_pbs(var);
-
+	return 0;
 }
 
 /*
@@ -1072,197 +1055,38 @@
 static int
 sa1100fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
 {
-	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
-	struct fb_var_screeninfo *dvar = get_con_var(&fbi->fb, con);
-	struct display *display = get_con_display(&fbi->fb, con);
-	int err, chgvar = 0, rgbidx;
-
-	DPRINTK("set_var\n");
-
-	/*
-	 * Decode var contents into a par structure, adjusting any
-	 * out of range values.
-	 */
-	err = sa1100fb_validate_var(var, fbi);
-	if (err)
-		return err;
+	int ret, act;
 
-	if (var->activate & FB_ACTIVATE_TEST)
-		return 0;
+	act = var->activate & FB_ACTIVATE_MASK;
 
-	if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
-		return -EINVAL;
+	ret = gen_set_var(var, con, info);
 
-	if (dvar->xres != var->xres)
-		chgvar = 1;
-	if (dvar->yres != var->yres)
-		chgvar = 1;
-	if (dvar->xres_virtual != var->xres_virtual)
-		chgvar = 1;
-	if (dvar->yres_virtual != var->yres_virtual)
-		chgvar = 1;
-	if (dvar->bits_per_pixel != var->bits_per_pixel)
-		chgvar = 1;
-	if (con < 0)
-		chgvar = 0;
+	if (ret == 0 && act & FB_ACTIVATE_NOW) {
+		struct display *display = (con < 0) ? info->disp : fb_display + con;
 
-	switch (var->bits_per_pixel) {
-#ifdef FBCON_HAS_CFB4
-	case 4:
-		if (fbi->cmap_static)
-			display->visual	= FB_VISUAL_STATIC_PSEUDOCOLOR;
-		else
-			display->visual	= FB_VISUAL_PSEUDOCOLOR;
-		display->line_length	= var->xres / 2;
-		display->dispsw		= &fbcon_cfb4;
-		rgbidx			= RGB_8;
-		break;
-#endif
-#ifdef FBCON_HAS_CFB8
-	case 8:
-		if (fbi->cmap_static)
-			display->visual	= FB_VISUAL_STATIC_PSEUDOCOLOR;
-		else
-			display->visual	= FB_VISUAL_PSEUDOCOLOR;
-		display->line_length	= var->xres;
-		display->dispsw		= &fbcon_cfb8;
-		rgbidx			= RGB_8;
-		break;
-#endif
-#ifdef FBCON_HAS_CFB16
-	case 16:
-		display->visual		= FB_VISUAL_TRUECOLOR;
-		display->line_length	= var->xres * 2;
-		display->dispsw		= &fbcon_cfb16;
-		display->dispsw_data	= fbi->fb.pseudo_palette;
-		rgbidx			= RGB_16;
-		break;
-#endif
-	default:
-		rgbidx = 0;
-		display->dispsw = &fbcon_dummy;
-		break;
+		/*
+		 * fbcon assumes too much.
+		 */
+		display->can_soft_blank = 1;
 	}
 
-	display->next_line	= display->line_length;
-	display->type		= fbi->fb.fix.type;
-	display->type_aux	= fbi->fb.fix.type_aux;
-	display->ypanstep	= fbi->fb.fix.ypanstep;
-	display->ywrapstep	= fbi->fb.fix.ywrapstep;
-	display->can_soft_blank	= 1;
-	display->inverse	= fbi->cmap_inverse;
-
-	*dvar			= *var;
-	dvar->activate		&= ~FB_ACTIVATE_ALL;
-
-	/*
-	 * Copy the RGB parameters for this display
-	 * from the machine specific parameters.
-	 */
-	dvar->red		= fbi->rgb[rgbidx]->red;
-	dvar->green		= fbi->rgb[rgbidx]->green;
-	dvar->blue		= fbi->rgb[rgbidx]->blue;
-	dvar->transp		= fbi->rgb[rgbidx]->transp;
-
-	DPRINTK("RGBT length = %d:%d:%d:%d\n",
-		dvar->red.length, dvar->green.length, dvar->blue.length,
-		dvar->transp.length);
-
-	DPRINTK("RGBT offset = %d:%d:%d:%d\n",
-		dvar->red.offset, dvar->green.offset, dvar->blue.offset,
-		dvar->transp.offset);
-
-	/*
-	 * Update the old var.  The fbcon drivers still use this.
-	 * Once they are using fbi->fb.var, this can be dropped.
-	 */
-	display->var = *dvar;
-
-	/*
-	 * If we are setting all the virtual consoles, also set the
-	 * defaults used to create new consoles.
-	 */
-	if (var->activate & FB_ACTIVATE_ALL)
-		fbi->fb.disp->var = *dvar;
-
-	/*
-	 * If the console has changed and the console has defined
-	 * a changevar function, call that function.
-	 */
-	if (chgvar && info && fbi->fb.changevar)
-		fbi->fb.changevar(con);
-
-	/* If the current console is selected, activate the new var. */
-	if (con != fbi->fb.currcon)
-		return 0;
-
-	sa1100fb_hw_set_var(dvar, fbi);
-
-	return 0;
-}
-
-static int
-__do_set_cmap(struct fb_cmap *cmap, int kspc, int con,
-	      struct fb_info *info)
-{
-	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
-	struct fb_cmap *dcmap = get_con_cmap(info, con);
-	int err = 0;
-
-	if (con == -1)
-		con = info->currcon;
-
-	/* no colormap allocated? (we always have "this" colour map allocated) */
-	if (con >= 0)
-		err = fb_alloc_cmap(&fb_display[con].cmap, fbi->palette_size, 0);
-
-	if (!err && con == info->currcon)
-		err = fb_set_cmap(cmap, kspc, info);
-
-	if (!err)
-		fb_copy_cmap(cmap, dcmap, kspc ? 0 : 1);
-
-	return err;
+	return ret;
 }
 
 static int
 sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
 		  struct fb_info *info)
 {
-	struct display *disp = get_con_display(info, con);
+	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
+	struct display *disp = (con < 0) ? info->disp : (fb_display + con);
 
-	if (disp->visual == FB_VISUAL_TRUECOLOR ||
-	    disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
+	/*
+	 * Make sure the user isn't doing something stupid.
+	 */
+	if (!kspc && (disp->var.bits_per_pixel == 16 || fbi->cmap_static))
 		return -EINVAL;
 
-	return __do_set_cmap(cmap, kspc, con, info);
-}
-
-static int
-sa1100fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
-{
-	struct display *display = get_con_display(info, con);
-
-	*fix = info->fix;
-
-	fix->line_length = display->line_length;
-	fix->visual	 = display->visual;
-	return 0;
-}
-
-static int
-sa1100fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
-{
-	*var = *get_con_var(info, con);
-	return 0;
-}
-
-static int
-sa1100fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
-{
-	struct fb_cmap *dcmap = get_con_cmap(info, con);
-	fb_copy_cmap(dcmap, cmap, kspc ? 0 : 2);
-	return 0;
+	return gen_set_cmap(cmap, kspc, con, info);
 }
 
 /*
@@ -1312,16 +1136,16 @@
 	case VESA_POWERDOWN:
 	case VESA_VSYNC_SUSPEND:
 	case VESA_HSYNC_SUSPEND:
-		if (fbi->fb.disp->visual == FB_VISUAL_PSEUDOCOLOR ||
-		    fbi->fb.disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
+		if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
+		    fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
 			for (i = 0; i < fbi->palette_size; i++)
 				sa1100fb_setpalettereg(i, 0, 0, 0, 0, info);
 		sa1100fb_schedule_task(fbi, C_DISABLE);
 		break;
 
 	case VESA_NO_BLANKING:
-		if (fbi->fb.disp->visual == FB_VISUAL_PSEUDOCOLOR ||
-		    fbi->fb.disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
+		if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
+		    fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
 			fb_set_cmap(&fbi->fb.cmap, 1, info);
 		sa1100fb_schedule_task(fbi, C_ENABLE);
 	}
@@ -1329,71 +1153,19 @@
 }
 
 static struct fb_ops sa1100fb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	sa1100fb_get_fix,
-	fb_get_var:	sa1100fb_get_var,
-	fb_set_var:	sa1100fb_set_var,
-	fb_get_cmap:	sa1100fb_get_cmap,
-	fb_set_cmap:	sa1100fb_set_cmap,
-	fb_setcolreg:	sa1100fb_setcolreg,
-	fb_blank:	sa1100fb_blank,
+	.owner		= THIS_MODULE,
+	.fb_check_var	= sa1100fb_check_var,
+	.fb_set_par	= sa1100fb_set_par,
+	.fb_set_var	= sa1100fb_set_var,
+	.fb_get_cmap	= gen_get_cmap,
+	.fb_set_cmap	= sa1100fb_set_cmap,
+	.fb_setcolreg	= sa1100fb_setcolreg,
+	.fb_blank	= sa1100fb_blank,
 };
 
-/*
- *  sa1100fb_switch():       
- *	Change to the specified console.  Palette and video mode
- *      are changed to the console's stored parameters.
- *
- *	Uh oh, this can be called from a tasklet (IRQ)
- */
-static int sa1100fb_switch(int con, struct fb_info *info)
-{
-	struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
-	struct display *disp;
-	struct fb_cmap *cmap;
-
-	DPRINTK("con=%d info->modename=%s\n", con, fbi->fb.modename);
-
-	if (con == info->currcon)
-		return 0;
-
-	if (info->currcon >= 0) {
-		disp = fb_display + info->currcon;
-
-		/*
-		 * Save the old colormap and video mode.
-		 */
-		disp->var = fbi->fb.var;
-
-		if (disp->cmap.len)
-			fb_copy_cmap(&fbi->fb.cmap, &disp->cmap, 0);
-	}
-
-	info->currcon = con;
-	disp = fb_display + con;
-
-	/*
-	 * Make sure that our colourmap contains 256 entries.
-	 */
-	fb_alloc_cmap(&fbi->fb.cmap, 256, 0);
-
-	if (disp->cmap.len)
-		cmap = &disp->cmap;
-	else
-		cmap = fb_default_cmap(1 << disp->var.bits_per_pixel);
-
-	fb_copy_cmap(cmap, &fbi->fb.cmap, 0);
-
-	fbi->fb.var = disp->var;
-	fbi->fb.var.activate = FB_ACTIVATE_NOW;
-
-	sa1100fb_set_var(&fbi->fb.var, con, info);
-	return 0;
-}
-
 static int sa1100fb_updatevar(int con, struct fb_info *info)
 {
-	DPRINTK("entered\n");
+	/* we don't support panning nor scrolling */
 	return 0;
 }
 
@@ -1401,34 +1173,14 @@
  * Calculate the PCD value from the clock rate (in picoseconds).
  * We take account of the PPCR clock setting.
  */
-static inline int get_pcd(unsigned int pixclock)
+static inline unsigned int get_pcd(unsigned int pixclock, unsigned int cpuclock)
 {
-	unsigned int pcd;
+	unsigned int pcd = cpuclock / 100;
 
-	if (pixclock) {
-		pcd = cpufreq_get(0) / 100;
-		pcd *= pixclock;
-		pcd /= 10000000;
-		pcd += 1;	/* make up for integer math truncations */
-	} else {
-		/*
-		 * People seem to be missing this message.  Make it big.
-		 * Make it stand out.  Make sure people see it.
-		 */
-		printk(KERN_WARNING "******************************************************\n");
-		printk(KERN_WARNING "**            ZERO PIXEL CLOCK DETECTED             **\n");
-		printk(KERN_WARNING "** You are using a zero pixclock.  This means that  **\n");
-		printk(KERN_WARNING "** clock scaling will not be able to adjust your    **\n");
-		printk(KERN_WARNING "** your timing parameters appropriately, and the    **\n");
-		printk(KERN_WARNING "** bandwidth calculations will fail to work.  This  **\n");
-		printk(KERN_WARNING "** will shortly become an error condition, which    **\n");
-		printk(KERN_WARNING "** will prevent your LCD display working.  Please   **\n");
-		printk(KERN_WARNING "** send your patches in as soon as possible to shut **\n");
-		printk(KERN_WARNING "** this message up.                                 **\n");
-		printk(KERN_WARNING "******************************************************\n");
-		pcd = 0;
-	}
-	return pcd;
+	pcd *= pixclock;
+	pcd /= 10000000;
+
+	return pcd + 1;	/* make up for integer math truncations */
 }
 
 /*
@@ -1439,7 +1191,7 @@
 static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi)
 {
 	struct sa1100fb_lcd_reg new_regs;
-	u_int half_screen_size, yres, pcd = get_pcd(var->pixclock);
+	u_int half_screen_size, yres, pcd;
 	u_long flags;
 
 	DPRINTK("Configuring SA1100 LCD\n");
@@ -1502,13 +1254,10 @@
 		LCCR2_BegFrmDel(var->upper_margin) +
 		LCCR2_EndFrmDel(var->lower_margin);
 
-	new_regs.lccr3 = fbi->lccr3 |
+	pcd = get_pcd(var->pixclock, cpufreq_get(0));
+	new_regs.lccr3 = LCCR3_PixClkDiv(pcd) | fbi->lccr3 |
 		(var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
-		(var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL) |
-		LCCR3_ACBsCntOff;
-
-	if (pcd)
-		new_regs.lccr3 |= LCCR3_PixClkDiv(pcd);
+		(var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);
 
 	DPRINTK("nlccr0 = 0x%08x\n", new_regs.lccr0);
 	DPRINTK("nlccr1 = 0x%08x\n", new_regs.lccr1);
@@ -1547,61 +1296,20 @@
  * to ensure that things happen in the right way 100% of time time.
  *	-- rmk
  */
-
-/*
- * FIXME: move LCD power stuff into sa1100fb_power_up_lcd()
- * Also, I'm expecting that the backlight stuff should
- * be handled differently.
- */
-static inline void sa1100fb_backlight_on(struct sa1100fb_info *fbi)
-{
-	DPRINTK("backlight on\n");
-
-	if (sa1100fb_backlight_power)
-		sa1100fb_backlight_power(1);
-}
-
-/*
- * FIXME: move LCD power stuf into sa1100fb_power_down_lcd()
- * Also, I'm expecting that the backlight stuff should
- * be handled differently.
- */
-static inline void sa1100fb_backlight_off(struct sa1100fb_info *fbi)
+static inline void __sa1100fb_backlight_power(struct sa1100fb_info *fbi, int on)
 {
-	DPRINTK("backlight off\n");
+	DPRINTK("backlight o%s\n", on ? "n" : "ff");
 
 	if (sa1100fb_backlight_power)
-		sa1100fb_backlight_power(0);
-}
-
-static inline void sa1100fb_power_up_lcd(struct sa1100fb_info *fbi)
-{
-	DPRINTK("LCD power on\n");
-
-	if (sa1100fb_lcd_power)
-		sa1100fb_lcd_power(1);
-
-#ifdef CONFIG_SA1100_STORK
-	if (machine_is_stork()) {
-		storkSetLCDCPLD(0, 1);
-		storkSetLatchA(STORK_LCD_BACKLIGHT_INVERTER_ON);
- 	}
-#endif
+		sa1100fb_backlight_power(on);
 }
 
-static inline void sa1100fb_power_down_lcd(struct sa1100fb_info *fbi)
+static inline void __sa1100fb_lcd_power(struct sa1100fb_info *fbi, int on)
 {
-	DPRINTK("LCD power off\n");
+	DPRINTK("LCD power o%s\n", on ? "n" : "ff");
 
 	if (sa1100fb_lcd_power)
-		sa1100fb_lcd_power(0);
-
-#ifdef CONFIG_SA1100_STORK
-	if (machine_is_stork()) {
-		storkSetLCDCPLD(0, 0);
-		storkClearLatchA(STORK_LCD_BACKLIGHT_INVERTER_ON);
-	}
-#endif
+		sa1100fb_lcd_power(on);
 }
 
 static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi)
@@ -1630,38 +1338,9 @@
 
 	}
 
-	if (machine_is_cerf()) {
-		/* GPIO15 is used as a bypass for 3.8" displays */
+	/* GPIO15 is used as a bypass for 3.8" displays */
+	if (machine_is_cerf())
 		mask |= GPIO_GPIO15;
-#ifdef CONFIG_SA1100_CERF
-#warning Read Me Now!
-#endif
-#if 0 /* if this causes you problems, mail <rmk@arm.linux.org.uk> please. */
-      /*
-       * This was enabled for the 72_A version only, which is a _color_
-       * _dual_ LCD.  Now look at the generic test above, and calculate
-       * the mask value for a colour dual display...
-       *
-       * I therefore conclude that the code below is redundant, and will
-       * be killed at the start of November 2001.
-       */
-		/* FIXME: why is this? The Cerf's display doesn't seem
-		 * to be dual scan or active. I just leave it here,
-		 * but in my opinion this is definitively wrong.
-		 *  -- Erik <J.A.K.Mouw@its.tudelft.nl>
-		 */
-
-		/* REPLY: Umm.. Well to be honest, the 5.7" LCD which
-		 * this was used for does not use these pins, but
-		 * apparently all hell breaks loose if they are not
-		 * set on the Cerf, so we decided to leave them in ;)
-		 *  -- Daniel Chemko <dchemko@intrinsyc.com>
-		 */
-		/* color {dual/single} passive */
-		mask |= GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 |
-			GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9  | GPIO_LDD8;
-#endif
-	}
 
 	if (mask) {
 		GPDR |= mask;
@@ -1733,7 +1412,7 @@
 	}
 #endif
 #ifdef CONFIG_SA1100_HUW_WEBPANEL
-#error Move me into sa1100fb_power_up_lcd and/or sa1100fb_backlight_on
+#error Move me into __sa1100fb_lcd_power and/or __sa1100fb_backlight_power
 	if (machine_is_huw_webpanel()) {
 		// dont forget to set the control lines to zero (?)
 		DPRINTK("ShutDown HuW LCD controller\n");
@@ -1806,10 +1485,10 @@
 		if (old_state != C_DISABLE) {
 			fbi->state = state;
 
-			sa1100fb_backlight_off(fbi);
+			__sa1100fb_backlight_power(fbi, 0);
 			if (old_state != C_DISABLE_CLKCHANGE)
 				sa1100fb_disable_controller(fbi);
-			sa1100fb_power_down_lcd(fbi);
+			__sa1100fb_lcd_power(fbi, 0);
 		}
 		break;
 
@@ -1855,9 +1534,9 @@
 		if (old_state != C_ENABLE) {
 			fbi->state = C_ENABLE;
 			sa1100fb_setup_gpio(fbi);
-			sa1100fb_power_up_lcd(fbi);
+			__sa1100fb_lcd_power(fbi, 1);
 			sa1100fb_enable_controller(fbi);
-			sa1100fb_backlight_on(fbi);
+			__sa1100fb_backlight_power(fbi, 1);
 		}
 		break;
 	}
@@ -1888,18 +1567,19 @@
 	int i;
 
 	for (i = 0; i < MAX_NR_CONSOLES; i++) {
+		struct display *disp = &fb_display[i];
 		unsigned int period;
 
 		/*
 		 * Do we own this display?
 		 */
-		if (fb_display[i].fb_info != &fbi->fb)
+		if (disp->fb_info != &fbi->fb)
 			continue;
 
 		/*
 		 * Ok, calculate its DMA period
 		 */
-		period = sa1100fb_display_dma_period(get_con_var(&fbi->fb, i));
+		period = sa1100fb_display_dma_period(&disp->var);
 		if (period < min_period)
 			min_period = period;
 	}
@@ -1913,33 +1593,42 @@
  * subsystem.
  */
 static int
-sa1100fb_clkchg_notifier(struct notifier_block *nb, unsigned long val,
+sa1100fb_freq_transition(struct notifier_block *nb, unsigned long val,
 			 void *data)
 {
-	struct sa1100fb_info *fbi = TO_INF(nb, clockchg);
-	struct cpufreq_minmax *mm = data;
+	struct sa1100fb_info *fbi = TO_INF(nb, freq_transition);
+	struct cpufreq_freqs *f = data;
 	u_int pcd;
 
 	switch (val) {
-	case CPUFREQ_MINMAX:
-		printk(KERN_DEBUG "min dma period: %d ps, old clock %d kHz, "
-			"new clock %d kHz\n", sa1100fb_min_dma_period(fbi),
-			mm->cur_freq, mm->new_freq);
-		/* todo: fill in min/max values */
-		break;
-
 	case CPUFREQ_PRECHANGE:
 		set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);
 		break;
 
 	case CPUFREQ_POSTCHANGE:
-		pcd = get_pcd(fbi->fb.var.pixclock);
+		pcd = get_pcd(fbi->fb.var.pixclock, f->new);
 		fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
 		set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
 		break;
 	}
 	return 0;
 }
+
+static int
+sa1100fb_freq_policy(struct notifier_block *nb, unsigned long val,
+		     void *data)
+{
+	struct sa1100fb_info *fbi = TO_INF(nb, freq_policy);
+	struct cpufreq_policy *policy = data;
+
+	if (val == CPUFREQ_INCOMPATIBLE) {
+		printk(KERN_DEBUG "min dma period: %d ps, "
+			"new clock %d kHz\n", sa1100fb_min_dma_period(fbi),
+			policy->max);
+		/* todo: fill in min/max values */
+	}
+	return 0;
+}
 #endif
 
 #ifdef CONFIG_PM
@@ -2015,8 +1704,6 @@
 
 	memset(fbi, 0, sizeof(struct sa1100fb_info) + sizeof(struct display));
 
-	fbi->fb.currcon		= -1;
-
 	strcpy(fbi->fb.fix.id, SA1100_NAME);
 
 	fbi->fb.fix.type	= FB_TYPE_PACKED_PIXELS;
@@ -2024,6 +1711,7 @@
 	fbi->fb.fix.xpanstep	= 0;
 	fbi->fb.fix.ypanstep	= 0;
 	fbi->fb.fix.ywrapstep	= 0;
+	fbi->fb.fix.line_length	= 0;
 	fbi->fb.fix.accel	= FB_ACCEL_NONE;
 
 	fbi->fb.var.nonstd	= 0;
@@ -2038,7 +1726,7 @@
 
 	fbi->fb.fbops		= &sa1100fb_ops;
 	fbi->fb.changevar	= NULL;
-	fbi->fb.switch_con	= sa1100fb_switch;
+	fbi->fb.switch_con	= gen_switch;
 	fbi->fb.updatevar	= sa1100fb_updatevar;
 	fbi->fb.flags		= FBINFO_FLAG_DEFAULT;
 	fbi->fb.node		= NODEV;
@@ -2052,6 +1740,16 @@
 
 	inf = sa1100fb_get_machine_info(fbi);
 
+	/*
+	 * People just don't seem to get this.  We don't support
+	 * anything but correct entries now, so panic if someone
+	 * does something stupid.
+	 */
+	if (inf->lccr3 & (LCCR3_VrtSnchL|LCCR3_HorSnchL|0xff) ||
+	    inf->pixclock == 0)
+		panic("sa1100fb error: invalid LCCR3 fields set or zero "
+			"pixclock.");
+
 	fbi->max_xres			= inf->xres;
 	fbi->fb.var.xres		= inf->xres;
 	fbi->fb.var.xres_virtual	= inf->xres;
@@ -2077,6 +1775,7 @@
 	fbi->task_state			= (u_char)-1;
 	fbi->fb.fix.smem_len		= fbi->max_xres * fbi->max_yres *
 					  fbi->max_bpp / 8;
+	fbi->fb.disp->inverse		= inf->cmap_inverse;
 
 	init_waitqueue_head(&fbi->ctrlr_wait);
 	INIT_TQUEUE(&fbi->task, sa1100fb_task, fbi);
@@ -2116,7 +1815,7 @@
 #endif
 
 #ifdef CONFIG_SA1100_FREEBIRD
-#error Please move this into sa1100fb_power_up_lcd
+#error Please move this into __sa1100fb_lcd_power
 	if (machine_is_freebird()) {
 		BCR_set(BCR_FREEBIRD_LCD_DISP);
 		mdelay(20);
@@ -2141,8 +1840,10 @@
 		fbi->pm->data = fbi;
 #endif
 #ifdef CONFIG_CPU_FREQ
-	fbi->clockchg.notifier_call = sa1100fb_clkchg_notifier;
-	cpufreq_register_notifier(&fbi->clockchg);
+	fbi->freq_transition.notifier_call = sa1100fb_freq_transition;
+	fbi->freq_policy.notifier_call = sa1100fb_freq_policy;
+	cpufreq_register_notifier(&fbi->freq_transition, CPUFREQ_TRANSITION_NOTIFIER);
+	cpufreq_register_notifier(&fbi->freq_policy, CPUFREQ_POLICY_NOTIFIER);
 #endif
 
 	/*
diff -Nru a/drivers/video/sa1100fb.h b/drivers/video/sa1100fb.h
--- a/drivers/video/sa1100fb.h	Tue Oct  1 00:08:15 2002
+++ b/drivers/video/sa1100fb.h	Tue Oct  1 00:08:15 2002
@@ -107,7 +107,8 @@
 	struct pm_dev		*pm;
 #endif
 #ifdef CONFIG_CPU_FREQ
-	struct notifier_block	clockchg;
+	struct notifier_block	freq_transition;
+	struct notifier_block	freq_policy;
 #endif
 };
 
diff -Nru a/fs/autofs/waitq.c b/fs/autofs/waitq.c
--- a/fs/autofs/waitq.c	Tue Oct  1 00:08:15 2002
+++ b/fs/autofs/waitq.c	Tue Oct  1 00:08:15 2002
@@ -70,10 +70,10 @@
 	/* Keep the currently executing process from receiving a
 	   SIGPIPE unless it was already supposed to get one */
 	if (wr == -EPIPE && !sigpipe) {
-		spin_lock_irqsave(&current->sigmask_lock, flags);
+		spin_lock_irqsave(&current->sig->siglock, flags);
 		sigdelset(&current->pending.signal, SIGPIPE);
 		recalc_sigpending();
-		spin_unlock_irqrestore(&current->sigmask_lock, flags);
+		spin_unlock_irqrestore(&current->sig->siglock, flags);
 	}
 
 	return (bytes > 0);
@@ -161,18 +161,18 @@
 		sigset_t oldset;
 		unsigned long irqflags;
 
-		spin_lock_irqsave(&current->sigmask_lock, irqflags);
+		spin_lock_irqsave(&current->sig->siglock, irqflags);
 		oldset = current->blocked;
 		siginitsetinv(&current->blocked, SHUTDOWN_SIGS & ~oldset.sig[0]);
 		recalc_sigpending();
-		spin_unlock_irqrestore(&current->sigmask_lock, irqflags);
+		spin_unlock_irqrestore(&current->sig->siglock, irqflags);
 
 		interruptible_sleep_on(&wq->queue);
 
-		spin_lock_irqsave(&current->sigmask_lock, irqflags);
+		spin_lock_irqsave(&current->sig->siglock, irqflags);
 		current->blocked = oldset;
 		recalc_sigpending();
-		spin_unlock_irqrestore(&current->sigmask_lock, irqflags);
+		spin_unlock_irqrestore(&current->sig->siglock, irqflags);
 	} else {
 		DPRINTK(("autofs_wait: skipped sleeping\n"));
 	}
diff -Nru a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
--- a/fs/autofs4/waitq.c	Tue Oct  1 00:08:20 2002
+++ b/fs/autofs4/waitq.c	Tue Oct  1 00:08:20 2002
@@ -74,10 +74,10 @@
 	/* Keep the currently executing process from receiving a
 	   SIGPIPE unless it was already supposed to get one */
 	if (wr == -EPIPE && !sigpipe) {
-		spin_lock_irqsave(&current->sigmask_lock, flags);
+		spin_lock_irqsave(&current->sig->siglock, flags);
 		sigdelset(&current->pending.signal, SIGPIPE);
 		recalc_sigpending();
-		spin_unlock_irqrestore(&current->sigmask_lock, flags);
+		spin_unlock_irqrestore(&current->sig->siglock, flags);
 	}
 
 	return (bytes > 0);
@@ -198,18 +198,18 @@
 		sigset_t oldset;
 		unsigned long irqflags;
 
-		spin_lock_irqsave(&current->sigmask_lock, irqflags);
+		spin_lock_irqsave(&current->sig->siglock, irqflags);
 		oldset = current->blocked;
 		siginitsetinv(&current->blocked, SHUTDOWN_SIGS & ~oldset.sig[0]);
 		recalc_sigpending();
-		spin_unlock_irqrestore(&current->sigmask_lock, irqflags);
+		spin_unlock_irqrestore(&current->sig->siglock, irqflags);
 
 		interruptible_sleep_on(&wq->queue);
 
-		spin_lock_irqsave(&current->sigmask_lock, irqflags);
+		spin_lock_irqsave(&current->sig->siglock, irqflags);
 		current->blocked = oldset;
 		recalc_sigpending();
-		spin_unlock_irqrestore(&current->sigmask_lock, irqflags);
+		spin_unlock_irqrestore(&current->sig->siglock, irqflags);
 	} else {
 		DPRINTK(("autofs_wait: skipped sleeping\n"));
 	}
diff -Nru a/fs/bfs/dir.c b/fs/bfs/dir.c
--- a/fs/bfs/dir.c	Tue Oct  1 00:08:19 2002
+++ b/fs/bfs/dir.c	Tue Oct  1 00:08:19 2002
@@ -71,9 +71,9 @@
 }
 
 struct file_operations bfs_dir_operations = {
-	read:		generic_read_dir,
-	readdir:	bfs_readdir,
-	fsync:		file_fsync,
+	.read		= generic_read_dir,
+	.readdir	= bfs_readdir,
+	.fsync		= file_fsync,
 };
 
 extern void dump_imap(const char *, struct super_block *);
@@ -263,11 +263,11 @@
 }
 
 struct inode_operations bfs_dir_inops = {
-	create:			bfs_create,
-	lookup:			bfs_lookup,
-	link:			bfs_link,
-	unlink:			bfs_unlink,
-	rename:			bfs_rename,
+	.create			= bfs_create,
+	.lookup			= bfs_lookup,
+	.link			= bfs_link,
+	.unlink			= bfs_unlink,
+	.rename			= bfs_rename,
 };
 
 static int bfs_add_entry(struct inode * dir, const char * name, int namelen, int ino)
diff -Nru a/fs/bfs/file.c b/fs/bfs/file.c
--- a/fs/bfs/file.c	Tue Oct  1 00:08:15 2002
+++ b/fs/bfs/file.c	Tue Oct  1 00:08:15 2002
@@ -18,11 +18,11 @@
 #endif
 
 struct file_operations bfs_file_operations = {
-	llseek: 	generic_file_llseek,
-	read:		generic_file_read,
-	write:		generic_file_write,
-	mmap:		generic_file_mmap,
-	sendfile:	generic_file_sendfile,
+	.llseek 	= generic_file_llseek,
+	.read		= generic_file_read,
+	.write		= generic_file_write,
+	.mmap		= generic_file_mmap,
+	.sendfile	= generic_file_sendfile,
 };
 
 static int bfs_move_block(unsigned long from, unsigned long to, struct super_block *sb)
@@ -151,12 +151,12 @@
 }
 
 struct address_space_operations bfs_aops = {
-	readpage:	bfs_readpage,
-	writepage:	bfs_writepage,
-	sync_page:	block_sync_page,
-	prepare_write:	bfs_prepare_write,
-	commit_write:	generic_commit_write,
-	bmap:		bfs_bmap,
+	.readpage	= bfs_readpage,
+	.writepage	= bfs_writepage,
+	.sync_page	= block_sync_page,
+	.prepare_write	= bfs_prepare_write,
+	.commit_write	= generic_commit_write,
+	.bmap		= bfs_bmap,
 };
 
 struct inode_operations bfs_file_inops;
diff -Nru a/fs/bfs/inode.c b/fs/bfs/inode.c
--- a/fs/bfs/inode.c	Tue Oct  1 00:08:17 2002
+++ b/fs/bfs/inode.c	Tue Oct  1 00:08:17 2002
@@ -253,14 +253,14 @@
 }
 
 static struct super_operations bfs_sops = {
-	alloc_inode:	bfs_alloc_inode,
-	destroy_inode:	bfs_destroy_inode,
-	read_inode:	bfs_read_inode,
-	write_inode:	bfs_write_inode,
-	delete_inode:	bfs_delete_inode,
-	put_super:	bfs_put_super,
-	write_super:	bfs_write_super,
-	statfs:		bfs_statfs,
+	.alloc_inode	= bfs_alloc_inode,
+	.destroy_inode	= bfs_destroy_inode,
+	.read_inode	= bfs_read_inode,
+	.write_inode	= bfs_write_inode,
+	.delete_inode	= bfs_delete_inode,
+	.put_super	= bfs_put_super,
+	.write_super	= bfs_write_super,
+	.statfs		= bfs_statfs,
 };
 
 void dump_imap(const char *prefix, struct super_block * s)
@@ -381,11 +381,11 @@
 }
 
 static struct file_system_type bfs_fs_type = {
-	owner:		THIS_MODULE,
-	name:		"bfs",
-	get_sb:		bfs_get_sb,
-	kill_sb:	kill_block_super,
-	fs_flags:	FS_REQUIRES_DEV,
+	.owner		= THIS_MODULE,
+	.name		= "bfs",
+	.get_sb		= bfs_get_sb,
+	.kill_sb	= kill_block_super,
+	.fs_flags	= FS_REQUIRES_DEV,
 };
 
 static int __init init_bfs_fs(void)
diff -Nru a/fs/block_dev.c b/fs/block_dev.c
--- a/fs/block_dev.c	Tue Oct  1 00:08:21 2002
+++ b/fs/block_dev.c	Tue Oct  1 00:08:21 2002
@@ -526,6 +526,7 @@
 	struct block_device_operations * bdops = bdev->bd_op;
 	kdev_t dev = to_kdev_t(bdev->bd_dev);
 	struct gendisk *disk;
+	int part;
 
 	if (bdops->check_media_change == NULL)
 		return 0;
@@ -535,7 +536,7 @@
 	if (invalidate_device(dev, 0))
 		printk("VFS: busy inodes on changed media.\n");
 
-	disk = get_gendisk(dev);
+	disk = get_gendisk(bdev->bd_dev, &part);
 	if (bdops->revalidate)
 		bdops->revalidate(dev);
 	if (disk && disk->minor_shift)
@@ -546,11 +547,12 @@
 int full_check_disk_change(struct block_device *bdev)
 {
 	int res = 0;
+	int n;
 	if (bdev->bd_contains != bdev)
 		BUG();
 	down(&bdev->bd_sem);
 	if (check_disk_change(bdev)) {
-		rescan_partitions(get_gendisk(to_kdev_t(bdev->bd_dev)), bdev);
+		rescan_partitions(get_gendisk(bdev->bd_dev, &n), bdev);
 		res = 1;
 	}
 	up(&bdev->bd_sem);
@@ -612,26 +614,24 @@
 			__MOD_DEC_USE_COUNT(owner);
 	}
 	if (!bdev->bd_contains) {
-		unsigned minor = minor(dev);
-		struct gendisk *g = get_gendisk(dev);
+		int part;
+		struct gendisk *g = get_gendisk(bdev->bd_dev, &part);
 		bdev->bd_contains = bdev;
-		if (g) {
-			unsigned minor0 = g->first_minor;
-			if (minor != minor0) {
-				struct block_device *disk;
-				disk = bdget(MKDEV(major(dev), minor0));
-				ret = -ENOMEM;
-				if (!disk)
-					goto out1;
-				ret = blkdev_get(disk, file->f_mode, file->f_flags, BDEV_RAW);
-				if (ret)
-					goto out1;
-				bdev->bd_contains = disk;
-			}
+		if (g && part) {
+			struct block_device *disk;
+			disk = bdget(MKDEV(g->major, g->first_minor));
+			ret = -ENOMEM;
+			if (!disk)
+				goto out1;
+			ret = blkdev_get(disk, file->f_mode, file->f_flags, BDEV_RAW);
+			if (ret)
+				goto out1;
+			bdev->bd_contains = disk;
 		}
 	}
 	if (bdev->bd_contains == bdev) {
-		struct gendisk *g = get_gendisk(dev);
+		int part;
+		struct gendisk *g = get_gendisk(bdev->bd_dev, &part);
 
 		if (!bdev->bd_queue) {
 			struct blk_dev_struct *p = blk_dev + major(dev);
@@ -665,9 +665,10 @@
 		down(&bdev->bd_contains->bd_sem);
 		bdev->bd_contains->bd_part_count++;
 		if (!bdev->bd_openers) {
-			struct gendisk *g = get_gendisk(dev);
+			int part;
+			struct gendisk *g = get_gendisk(bdev->bd_dev, &part);
 			struct hd_struct *p;
-			p = g->part + minor(dev) - g->first_minor - 1;
+			p = g->part + part - 1;
 			inode->i_data.backing_dev_info =
 			   bdev->bd_inode->i_data.backing_dev_info =
 			   bdev->bd_contains->bd_inode->i_data.backing_dev_info;
@@ -793,12 +794,14 @@
 
 static int blkdev_reread_part(struct block_device *bdev)
 {
-	kdev_t dev = to_kdev_t(bdev->bd_dev);
-	struct gendisk *disk = get_gendisk(dev);
+	int part;
+	struct gendisk *disk = get_gendisk(bdev->bd_dev, &part);
 	int res = 0;
 
 	if (!disk || !disk->minor_shift || bdev != bdev->bd_contains)
 		return -EINVAL;
+	if (part)
+		BUG();
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
 	if (down_trylock(&bdev->bd_sem))
diff -Nru a/fs/cramfs/inode.c b/fs/cramfs/inode.c
--- a/fs/cramfs/inode.c	Tue Oct  1 00:08:15 2002
+++ b/fs/cramfs/inode.c	Tue Oct  1 00:08:15 2002
@@ -435,7 +435,7 @@
 }
 
 static struct address_space_operations cramfs_aops = {
-	readpage: cramfs_readpage
+	.readpage = cramfs_readpage
 };
 
 /*
@@ -446,17 +446,17 @@
  * A directory can only readdir
  */
 static struct file_operations cramfs_directory_operations = {
-	read:		generic_read_dir,
-	readdir:	cramfs_readdir,
+	.read		= generic_read_dir,
+	.readdir	= cramfs_readdir,
 };
 
 static struct inode_operations cramfs_dir_inode_operations = {
-	lookup:		cramfs_lookup,
+	.lookup		= cramfs_lookup,
 };
 
 static struct super_operations cramfs_ops = {
-	put_super:	cramfs_put_super,
-	statfs:		cramfs_statfs,
+	.put_super	= cramfs_put_super,
+	.statfs		= cramfs_statfs,
 };
 
 static struct super_block *cramfs_get_sb(struct file_system_type *fs_type,
@@ -466,11 +466,11 @@
 }
 
 static struct file_system_type cramfs_fs_type = {
-	owner:		THIS_MODULE,
-	name:		"cramfs",
-	get_sb:		cramfs_get_sb,
-	kill_sb:	kill_block_super,
-	fs_flags:	FS_REQUIRES_DEV,
+	.owner		= THIS_MODULE,
+	.name		= "cramfs",
+	.get_sb		= cramfs_get_sb,
+	.kill_sb	= kill_block_super,
+	.fs_flags	= FS_REQUIRES_DEV,
 };
 
 static int __init init_cramfs_fs(void)
diff -Nru a/fs/devfs/base.c b/fs/devfs/base.c
--- a/fs/devfs/base.c	Tue Oct  1 00:08:15 2002
+++ b/fs/devfs/base.c	Tue Oct  1 00:08:15 2002
@@ -2396,7 +2396,6 @@
     warn_no_part = 0;
     retval = full_check_disk_change (bdev);
     warn_no_part = tmp;
-out:
     devfs_put_ops (de);
     return retval;
 }   /*  End Function check_disc_changed  */
diff -Nru a/fs/devpts/inode.c b/fs/devpts/inode.c
--- a/fs/devpts/inode.c	Tue Oct  1 00:08:16 2002
+++ b/fs/devpts/inode.c	Tue Oct  1 00:08:16 2002
@@ -27,7 +27,7 @@
 	uid_t   uid;
 	gid_t   gid;
 	umode_t mode;
-} config = {mode: 0600};
+} config = {.mode = 0600};
 
 static int devpts_remount(struct super_block *sb, int *flags, char *data)
 {
@@ -67,8 +67,8 @@
 }
 
 static struct super_operations devpts_sops = {
-	statfs:		simple_statfs,
-	remount_fs:	devpts_remount,
+	.statfs		= simple_statfs,
+	.remount_fs	= devpts_remount,
 };
 
 static int devpts_fill_super(struct super_block *s, void *data, int silent)
@@ -110,10 +110,10 @@
 }
 
 static struct file_system_type devpts_fs_type = {
-	owner:		THIS_MODULE,
-	name:		"devpts",
-	get_sb:		devpts_get_sb,
-	kill_sb:	kill_anon_super,
+	.owner		= THIS_MODULE,
+	.name		= "devpts",
+	.get_sb		= devpts_get_sb,
+	.kill_sb	= kill_anon_super,
 };
 
 /*
diff -Nru a/fs/driverfs/inode.c b/fs/driverfs/inode.c
--- a/fs/driverfs/inode.c	Tue Oct  1 00:08:15 2002
+++ b/fs/driverfs/inode.c	Tue Oct  1 00:08:15 2002
@@ -703,3 +703,4 @@
 EXPORT_SYMBOL(driverfs_create_dir);
 EXPORT_SYMBOL(driverfs_remove_file);
 EXPORT_SYMBOL(driverfs_remove_dir);
+MODULE_LICENSE("GPL");
diff -Nru a/fs/efs/dir.c b/fs/efs/dir.c
--- a/fs/efs/dir.c	Tue Oct  1 00:08:18 2002
+++ b/fs/efs/dir.c	Tue Oct  1 00:08:18 2002
@@ -11,12 +11,12 @@
 static int efs_readdir(struct file *, void *, filldir_t);
 
 struct file_operations efs_dir_operations = {
-	read:		generic_read_dir,
-	readdir:	efs_readdir,
+	.read		= generic_read_dir,
+	.readdir	= efs_readdir,
 };
 
 struct inode_operations efs_dir_inode_operations = {
-	lookup:		efs_lookup,
+	.lookup		= efs_lookup,
 };
 
 static int efs_readdir(struct file *filp, void *dirent, filldir_t filldir) {
diff -Nru a/fs/efs/inode.c b/fs/efs/inode.c
--- a/fs/efs/inode.c	Tue Oct  1 00:08:17 2002
+++ b/fs/efs/inode.c	Tue Oct  1 00:08:17 2002
@@ -24,9 +24,9 @@
 	return generic_block_bmap(mapping,block,efs_get_block);
 }
 struct address_space_operations efs_aops = {
-	readpage: efs_readpage,
-	sync_page: block_sync_page,
-	bmap: _efs_bmap
+	.readpage = efs_readpage,
+	.sync_page = block_sync_page,
+	.bmap = _efs_bmap
 };
 
 static inline void extent_copy(efs_extent *src, efs_extent *dst) {
diff -Nru a/fs/efs/super.c b/fs/efs/super.c
--- a/fs/efs/super.c	Tue Oct  1 00:08:16 2002
+++ b/fs/efs/super.c	Tue Oct  1 00:08:16 2002
@@ -21,11 +21,11 @@
 }
 
 static struct file_system_type efs_fs_type = {
-	owner:		THIS_MODULE,
-	name:		"efs",
-	get_sb:		efs_get_sb,
-	kill_sb:	kill_block_super,
-	fs_flags:	FS_REQUIRES_DEV,
+	.owner		= THIS_MODULE,
+	.name		= "efs",
+	.get_sb		= efs_get_sb,
+	.kill_sb	= kill_block_super,
+	.fs_flags	= FS_REQUIRES_DEV,
 };
 
 static kmem_cache_t * efs_inode_cachep;
@@ -77,11 +77,11 @@
 }
 
 static struct super_operations efs_superblock_operations = {
-	alloc_inode:	efs_alloc_inode,
-	destroy_inode:	efs_destroy_inode,
-	read_inode:	efs_read_inode,
-	put_super:	efs_put_super,
-	statfs:		efs_statfs,
+	.alloc_inode	= efs_alloc_inode,
+	.destroy_inode	= efs_destroy_inode,
+	.read_inode	= efs_read_inode,
+	.put_super	= efs_put_super,
+	.statfs		= efs_statfs,
 };
 
 static int __init init_efs_fs(void) {
diff -Nru a/fs/efs/symlink.c b/fs/efs/symlink.c
--- a/fs/efs/symlink.c	Tue Oct  1 00:08:17 2002
+++ b/fs/efs/symlink.c	Tue Oct  1 00:08:17 2002
@@ -54,5 +54,5 @@
 }
 
 struct address_space_operations efs_symlink_aops = {
-	readpage:	efs_symlink_readpage
+	.readpage	= efs_symlink_readpage
 };
diff -Nru a/fs/exec.c b/fs/exec.c
--- a/fs/exec.c	Tue Oct  1 00:08:16 2002
+++ b/fs/exec.c	Tue Oct  1 00:08:16 2002
@@ -400,6 +400,7 @@
 		mpnt->vm_ops = NULL;
 		mpnt->vm_pgoff = 0;
 		mpnt->vm_file = NULL;
+		INIT_LIST_HEAD(&mpnt->shared);
 		mpnt->vm_private_data = (void *) 0;
 		insert_vm_struct(mm, mpnt);
 		mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
@@ -649,12 +650,19 @@
 	memcpy(newsig->action, current->sig->action, sizeof(newsig->action));
 	init_sigpending(&newsig->shared_pending);
 
-	remove_thread_group(current, current->sig);
-	spin_lock_irq(&current->sigmask_lock);
+	write_lock_irq(&tasklist_lock);
+	spin_lock(&oldsig->siglock);
+	spin_lock(&newsig->siglock);
+
+	if (current == oldsig->curr_target)
+		oldsig->curr_target = next_thread(current);
 	current->sig = newsig;
 	init_sigpending(&current->pending);
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+
+	spin_unlock(&newsig->siglock);
+	spin_unlock(&oldsig->siglock);
+	write_unlock_irq(&tasklist_lock);
 
 	if (atomic_dec_and_test(&oldsig->count))
 		kmem_cache_free(sigact_cachep, oldsig);
@@ -753,12 +761,12 @@
 
 mmap_failed:
 flush_failed:
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	if (current->sig != oldsig) {
 		kmem_cache_free(sigact_cachep, current->sig);
 		current->sig = oldsig;
 	}
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 	return retval;
 }
 
diff -Nru a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
--- a/fs/exportfs/expfs.c	Tue Oct  1 00:08:16 2002
+++ b/fs/exportfs/expfs.c	Tue Oct  1 00:08:16 2002
@@ -514,12 +514,12 @@
 }
 
 struct export_operations export_op_default = {
-	decode_fh:	export_decode_fh,
-	encode_fh:	export_encode_fh,
+	.decode_fh	= export_decode_fh,
+	.encode_fh	= export_encode_fh,
 
-	get_name:	get_name,
-	get_parent:	get_parent,
-	get_dentry:	get_object,
+	.get_name	= get_name,
+	.get_parent	= get_parent,
+	.get_dentry	= get_object,
 };
 
 EXPORT_SYMBOL(export_op_default);
diff -Nru a/fs/file_table.c b/fs/file_table.c
--- a/fs/file_table.c	Tue Oct  1 00:08:15 2002
+++ b/fs/file_table.c	Tue Oct  1 00:08:15 2002
@@ -25,6 +25,9 @@
 /* public *and* exported. Not pretty! */
 spinlock_t files_lock = SPIN_LOCK_UNLOCKED;
 
+/* file version */
+unsigned long event;
+
 /* Find an unused file structure and return a pointer to it.
  * Returns NULL, if there are no more free file structures or
  * we run out of memory.
diff -Nru a/fs/isofs/compress.c b/fs/isofs/compress.c
--- a/fs/isofs/compress.c	Tue Oct  1 00:08:15 2002
+++ b/fs/isofs/compress.c	Tue Oct  1 00:08:15 2002
@@ -325,7 +325,7 @@
 }
 
 struct address_space_operations zisofs_aops = {
-	readpage: zisofs_readpage,
+	.readpage = zisofs_readpage,
 	/* No sync_page operation supported? */
 	/* No bmap operation supported */
 };
diff -Nru a/fs/isofs/dir.c b/fs/isofs/dir.c
--- a/fs/isofs/dir.c	Tue Oct  1 00:08:16 2002
+++ b/fs/isofs/dir.c	Tue Oct  1 00:08:16 2002
@@ -29,8 +29,8 @@
 
 struct file_operations isofs_dir_operations =
 {
-	read:		generic_read_dir,
-	readdir:	isofs_readdir,
+	.read		= generic_read_dir,
+	.readdir	= isofs_readdir,
 };
 
 /*
@@ -38,7 +38,7 @@
  */
 struct inode_operations isofs_dir_inode_operations =
 {
-	lookup:		isofs_lookup,
+	.lookup		= isofs_lookup,
 };
 
 int isofs_name_translate(struct iso_directory_record *de, char *new, struct inode *inode)
diff -Nru a/fs/isofs/inode.c b/fs/isofs/inode.c
--- a/fs/isofs/inode.c	Tue Oct  1 00:08:20 2002
+++ b/fs/isofs/inode.c	Tue Oct  1 00:08:20 2002
@@ -124,11 +124,11 @@
 }
 
 static struct super_operations isofs_sops = {
-	alloc_inode:	isofs_alloc_inode,
-	destroy_inode:	isofs_destroy_inode,
-	read_inode:	isofs_read_inode,
-	put_super:	isofs_put_super,
-	statfs:		isofs_statfs,
+	.alloc_inode	= isofs_alloc_inode,
+	.destroy_inode	= isofs_destroy_inode,
+	.read_inode	= isofs_read_inode,
+	.put_super	= isofs_put_super,
+	.statfs		= isofs_statfs,
 };
 
 /* the export_operations structure for describing
@@ -148,21 +148,21 @@
 
 static struct dentry_operations isofs_dentry_ops[] = {
 	{
-		d_hash:		isofs_hash,
-		d_compare:	isofs_dentry_cmp,
+		.d_hash		= isofs_hash,
+		.d_compare	= isofs_dentry_cmp,
 	},
 	{
-		d_hash:		isofs_hashi,
-		d_compare:	isofs_dentry_cmpi,
+		.d_hash		= isofs_hashi,
+		.d_compare	= isofs_dentry_cmpi,
 	},
 #ifdef CONFIG_JOLIET
 	{
-		d_hash:		isofs_hash_ms,
-		d_compare:	isofs_dentry_cmp_ms,
+		.d_hash		= isofs_hash_ms,
+		.d_compare	= isofs_dentry_cmp_ms,
 	},
 	{
-		d_hash:		isofs_hashi_ms,
-		d_compare:	isofs_dentry_cmpi_ms,
+		.d_hash		= isofs_hashi_ms,
+		.d_compare	= isofs_dentry_cmpi_ms,
 	}
 #endif
 };
@@ -1063,9 +1063,9 @@
 }
 
 static struct address_space_operations isofs_aops = {
-	readpage: isofs_readpage,
-	sync_page: block_sync_page,
-	bmap: _isofs_bmap
+	.readpage = isofs_readpage,
+	.sync_page = block_sync_page,
+	.bmap = _isofs_bmap
 };
 
 static inline void test_and_set_uid(uid_t *p, uid_t value)
@@ -1430,11 +1430,11 @@
 }
 
 static struct file_system_type iso9660_fs_type = {
-	owner:		THIS_MODULE,
-	name:		"iso9660",
-	get_sb:		isofs_get_sb,
-	kill_sb:	kill_block_super,
-	fs_flags:	FS_REQUIRES_DEV,
+	.owner		= THIS_MODULE,
+	.name		= "iso9660",
+	.get_sb		= isofs_get_sb,
+	.kill_sb	= kill_block_super,
+	.fs_flags	= FS_REQUIRES_DEV,
 };
 
 static int __init init_iso9660_fs(void)
diff -Nru a/fs/isofs/rock.c b/fs/isofs/rock.c
--- a/fs/isofs/rock.c	Tue Oct  1 00:08:17 2002
+++ b/fs/isofs/rock.c	Tue Oct  1 00:08:17 2002
@@ -590,5 +590,5 @@
 }
 
 struct address_space_operations isofs_symlink_aops = {
-	readpage:	rock_ridge_symlink_readpage
+	.readpage	= rock_ridge_symlink_readpage
 };
diff -Nru a/fs/jbd/journal.c b/fs/jbd/journal.c
--- a/fs/jbd/journal.c	Tue Oct  1 00:08:15 2002
+++ b/fs/jbd/journal.c	Tue Oct  1 00:08:15 2002
@@ -205,10 +205,10 @@
 
 	lock_kernel();
 	daemonize();
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	sigfillset(&current->blocked);
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	sprintf(current->comm, "kjournald");
 
diff -Nru a/fs/jffs/intrep.c b/fs/jffs/intrep.c
--- a/fs/jffs/intrep.c	Tue Oct  1 00:08:17 2002
+++ b/fs/jffs/intrep.c	Tue Oct  1 00:08:17 2002
@@ -3347,10 +3347,10 @@
 	current->session = 1;
 	current->pgrp = 1;
 	init_completion(&c->gc_thread_comp); /* barrier */ 
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	siginitsetinv (&current->blocked, sigmask(SIGHUP) | sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT));
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 	strcpy(current->comm, "jffs_gcd");
 
 	D1(printk (KERN_NOTICE "jffs_garbage_collect_thread(): Starting infinite loop.\n"));
@@ -3378,9 +3378,9 @@
 			siginfo_t info;
 			unsigned long signr;
 
-			spin_lock_irq(&current->sigmask_lock);
+			spin_lock_irq(&current->sig->siglock);
 			signr = dequeue_signal(&current->blocked, &info);
-			spin_unlock_irq(&current->sigmask_lock);
+			spin_unlock_irq(&current->sig->siglock);
 
 			switch(signr) {
 			case SIGSTOP:
diff -Nru a/fs/jffs2/background.c b/fs/jffs2/background.c
--- a/fs/jffs2/background.c	Tue Oct  1 00:08:14 2002
+++ b/fs/jffs2/background.c	Tue Oct  1 00:08:14 2002
@@ -91,10 +91,10 @@
 	set_user_nice(current, 10);
 
 	for (;;) {
-		spin_lock_irq(&current->sigmask_lock);
+		spin_lock_irq(&current->sig->siglock);
 		siginitsetinv (&current->blocked, sigmask(SIGHUP) | sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT));
 		recalc_sigpending();
-		spin_unlock_irq(&current->sigmask_lock);
+		spin_unlock_irq(&current->sig->siglock);
 
 		if (!thread_should_wake(c)) {
                         set_current_state (TASK_INTERRUPTIBLE);
@@ -114,9 +114,9 @@
                         siginfo_t info;
                         unsigned long signr;
 
-                        spin_lock_irq(&current->sigmask_lock);
+                        spin_lock_irq(&current->sig->siglock);
                         signr = dequeue_signal(&current->blocked, &info);
-                        spin_unlock_irq(&current->sigmask_lock);
+                        spin_unlock_irq(&current->sig->siglock);
 
                         switch(signr) {
                         case SIGSTOP:
@@ -141,10 +141,10 @@
                         }
                 }
 		/* We don't want SIGHUP to interrupt us. STOP and KILL are OK though. */
-		spin_lock_irq(&current->sigmask_lock);
+		spin_lock_irq(&current->sig->siglock);
 		siginitsetinv (&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT));
 		recalc_sigpending();
-		spin_unlock_irq(&current->sigmask_lock);
+		spin_unlock_irq(&current->sig->siglock);
 
 		D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): pass\n"));
 		jffs2_garbage_collect_pass(c);
diff -Nru a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
--- a/fs/jfs/jfs_logmgr.c	Tue Oct  1 00:08:17 2002
+++ b/fs/jfs/jfs_logmgr.c	Tue Oct  1 00:08:17 2002
@@ -1202,8 +1202,6 @@
 	/*
 	 * validate log superblock
 	 */
-
-
 	if (!test_bit(log_INLINELOG, &log->flag))
 		log->l2bsize = 12;	/* XXX kludge alert XXX */
 	if ((rc = lbmRead(log, 1, &bpsuper)))
@@ -2134,10 +2132,10 @@
 
 	unlock_kernel();
 
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	sigfillset(&current->blocked);
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	complete(&jfsIOwait);
 
diff -Nru a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
--- a/fs/jfs/jfs_txnmgr.c	Tue Oct  1 00:08:17 2002
+++ b/fs/jfs/jfs_txnmgr.c	Tue Oct  1 00:08:17 2002
@@ -2779,10 +2779,10 @@
 
 	jfsCommitTask = current;
 
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	sigfillset(&current->blocked);
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	LAZY_LOCK_INIT();
 	TxAnchor.unlock_queue = TxAnchor.unlock_tail = 0;
@@ -2979,10 +2979,10 @@
 
 	unlock_kernel();
 
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	sigfillset(&current->blocked);
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	complete(&jfsIOwait);
 
diff -Nru a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
--- a/fs/lockd/clntproc.c	Tue Oct  1 00:08:15 2002
+++ b/fs/lockd/clntproc.c	Tue Oct  1 00:08:15 2002
@@ -139,7 +139,7 @@
 	}
 
 	/* Keep the old signal mask */
-	spin_lock_irqsave(&current->sigmask_lock, flags);
+	spin_lock_irqsave(&current->sig->siglock, flags);
 	oldset = current->blocked;
 
 	/* If we're cleaning up locks because the process is exiting,
@@ -149,7 +149,7 @@
 	    && (current->flags & PF_EXITING)) {
 		sigfillset(&current->blocked);	/* Mask all signals */
 		recalc_sigpending();
-		spin_unlock_irqrestore(&current->sigmask_lock, flags);
+		spin_unlock_irqrestore(&current->sig->siglock, flags);
 
 		call = nlmclnt_alloc_call();
 		if (!call) {
@@ -158,7 +158,7 @@
 		}
 		call->a_flags = RPC_TASK_ASYNC;
 	} else {
-		spin_unlock_irqrestore(&current->sigmask_lock, flags);
+		spin_unlock_irqrestore(&current->sig->siglock, flags);
 		memset(call, 0, sizeof(*call));
 		locks_init_lock(&call->a_args.lock.fl);
 		locks_init_lock(&call->a_res.lock.fl);
@@ -183,10 +183,10 @@
 		kfree(call);
 
  out_restore:
-	spin_lock_irqsave(&current->sigmask_lock, flags);
+	spin_lock_irqsave(&current->sig->siglock, flags);
 	current->blocked = oldset;
 	recalc_sigpending();
-	spin_unlock_irqrestore(&current->sigmask_lock, flags);
+	spin_unlock_irqrestore(&current->sig->siglock, flags);
 
 done:
 	dprintk("lockd: clnt proc returns %d\n", status);
@@ -592,11 +592,11 @@
 	int		status;
 
 	/* Block all signals while setting up call */
-	spin_lock_irqsave(&current->sigmask_lock, flags);
+	spin_lock_irqsave(&current->sig->siglock, flags);
 	oldset = current->blocked;
 	sigfillset(&current->blocked);
 	recalc_sigpending();
-	spin_unlock_irqrestore(&current->sigmask_lock, flags);
+	spin_unlock_irqrestore(&current->sig->siglock, flags);
 
 	req = nlmclnt_alloc_call();
 	if (!req)
@@ -611,10 +611,10 @@
 	if (status < 0)
 		kfree(req);
 
-	spin_lock_irqsave(&current->sigmask_lock, flags);
+	spin_lock_irqsave(&current->sig->siglock, flags);
 	current->blocked = oldset;
 	recalc_sigpending();
-	spin_unlock_irqrestore(&current->sigmask_lock, flags);
+	spin_unlock_irqrestore(&current->sig->siglock, flags);
 
 	return status;
 }
diff -Nru a/fs/lockd/svc.c b/fs/lockd/svc.c
--- a/fs/lockd/svc.c	Tue Oct  1 00:08:18 2002
+++ b/fs/lockd/svc.c	Tue Oct  1 00:08:18 2002
@@ -101,10 +101,10 @@
 	sprintf(current->comm, "lockd");
 
 	/* Process request with signals blocked.  */
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	siginitsetinv(&current->blocked, sigmask(SIGKILL));
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	/* kick rpciod */
 	rpciod_up();
@@ -126,9 +126,9 @@
 	{
 		long timeout = MAX_SCHEDULE_TIMEOUT;
 		if (signalled()) {
-			spin_lock_irq(&current->sigmask_lock);
+			spin_lock_irq(&current->sig->siglock);
 			flush_signals(current);
-			spin_unlock_irq(&current->sigmask_lock);
+			spin_unlock_irq(&current->sig->siglock);
 			if (nlmsvc_ops) {
 				nlmsvc_invalidate_all();
 				grace_period_expire = set_grace_period();
@@ -297,9 +297,9 @@
 			"lockd_down: lockd failed to exit, clearing pid\n");
 		nlmsvc_pid = 0;
 	}
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 out:
 	up(&nlmsvc_sema);
 }
diff -Nru a/fs/minix/dir.c b/fs/minix/dir.c
--- a/fs/minix/dir.c	Tue Oct  1 00:08:15 2002
+++ b/fs/minix/dir.c	Tue Oct  1 00:08:16 2002
@@ -15,9 +15,9 @@
 static int minix_readdir(struct file *, void *, filldir_t);
 
 struct file_operations minix_dir_operations = {
-	read:		generic_read_dir,
-	readdir:	minix_readdir,
-	fsync:		minix_sync_file,
+	.read		= generic_read_dir,
+	.readdir	= minix_readdir,
+	.fsync		= minix_sync_file,
 };
 
 static inline void dir_put_page(struct page *page)
diff -Nru a/fs/minix/file.c b/fs/minix/file.c
--- a/fs/minix/file.c	Tue Oct  1 00:08:16 2002
+++ b/fs/minix/file.c	Tue Oct  1 00:08:16 2002
@@ -16,17 +16,17 @@
 int minix_sync_file(struct file *, struct dentry *, int);
 
 struct file_operations minix_file_operations = {
-	llseek:		generic_file_llseek,
-	read:		generic_file_read,
-	write:		generic_file_write,
-	mmap:		generic_file_mmap,
-	fsync:		minix_sync_file,
-	sendfile:	generic_file_sendfile,
+	.llseek		= generic_file_llseek,
+	.read		= generic_file_read,
+	.write		= generic_file_write,
+	.mmap		= generic_file_mmap,
+	.fsync		= minix_sync_file,
+	.sendfile	= generic_file_sendfile,
 };
 
 struct inode_operations minix_file_inode_operations = {
-	truncate:	minix_truncate,
-	getattr:	minix_getattr,
+	.truncate	= minix_truncate,
+	.getattr	= minix_getattr,
 };
 
 int minix_sync_file(struct file * file, struct dentry *dentry, int datasync)
diff -Nru a/fs/minix/inode.c b/fs/minix/inode.c
--- a/fs/minix/inode.c	Tue Oct  1 00:08:17 2002
+++ b/fs/minix/inode.c	Tue Oct  1 00:08:17 2002
@@ -92,14 +92,14 @@
 }
 
 static struct super_operations minix_sops = {
-	alloc_inode:	minix_alloc_inode,
-	destroy_inode:	minix_destroy_inode,
-	read_inode:	minix_read_inode,
-	write_inode:	minix_write_inode,
-	delete_inode:	minix_delete_inode,
-	put_super:	minix_put_super,
-	statfs:		minix_statfs,
-	remount_fs:	minix_remount,
+	.alloc_inode	= minix_alloc_inode,
+	.destroy_inode	= minix_destroy_inode,
+	.read_inode	= minix_read_inode,
+	.write_inode	= minix_write_inode,
+	.delete_inode	= minix_delete_inode,
+	.put_super	= minix_put_super,
+	.statfs		= minix_statfs,
+	.remount_fs	= minix_remount,
 };
 
 static int minix_remount (struct super_block * sb, int * flags, char * data)
@@ -333,18 +333,18 @@
 	return generic_block_bmap(mapping,block,minix_get_block);
 }
 static struct address_space_operations minix_aops = {
-	readpage: minix_readpage,
-	writepage: minix_writepage,
-	sync_page: block_sync_page,
-	prepare_write: minix_prepare_write,
-	commit_write: generic_commit_write,
-	bmap: minix_bmap
+	.readpage = minix_readpage,
+	.writepage = minix_writepage,
+	.sync_page = block_sync_page,
+	.prepare_write = minix_prepare_write,
+	.commit_write = generic_commit_write,
+	.bmap = minix_bmap
 };
 
 static struct inode_operations minix_symlink_inode_operations = {
-	readlink:	page_readlink,
-	follow_link:	page_follow_link,
-	getattr:	minix_getattr,
+	.readlink	= page_readlink,
+	.follow_link	= page_follow_link,
+	.getattr	= minix_getattr,
 };
 
 void minix_set_inode(struct inode *inode, dev_t rdev)
@@ -554,11 +554,11 @@
 }
 
 static struct file_system_type minix_fs_type = {
-	owner:		THIS_MODULE,
-	name:		"minix",
-	get_sb:		minix_get_sb,
-	kill_sb:	kill_block_super,
-	fs_flags:	FS_REQUIRES_DEV,
+	.owner		= THIS_MODULE,
+	.name		= "minix",
+	.get_sb		= minix_get_sb,
+	.kill_sb	= kill_block_super,
+	.fs_flags	= FS_REQUIRES_DEV,
 };
 
 static int __init init_minix_fs(void)
diff -Nru a/fs/minix/namei.c b/fs/minix/namei.c
--- a/fs/minix/namei.c	Tue Oct  1 00:08:16 2002
+++ b/fs/minix/namei.c	Tue Oct  1 00:08:16 2002
@@ -51,7 +51,7 @@
 }
 
 struct dentry_operations minix_dentry_operations = {
-	d_hash:		minix_hash,
+	.d_hash		= minix_hash,
 };
 
 static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry)
@@ -298,14 +298,14 @@
  * directories can handle most operations...
  */
 struct inode_operations minix_dir_inode_operations = {
-	create:		minix_create,
-	lookup:		minix_lookup,
-	link:		minix_link,
-	unlink:		minix_unlink,
-	symlink:	minix_symlink,
-	mkdir:		minix_mkdir,
-	rmdir:		minix_rmdir,
-	mknod:		minix_mknod,
-	rename:		minix_rename,
-	getattr:	minix_getattr,
+	.create		= minix_create,
+	.lookup		= minix_lookup,
+	.link		= minix_link,
+	.unlink		= minix_unlink,
+	.symlink	= minix_symlink,
+	.mkdir		= minix_mkdir,
+	.rmdir		= minix_rmdir,
+	.mknod		= minix_mknod,
+	.rename		= minix_rename,
+	.getattr	= minix_getattr,
 };
diff -Nru a/fs/ncpfs/sock.c b/fs/ncpfs/sock.c
--- a/fs/ncpfs/sock.c	Tue Oct  1 00:08:16 2002
+++ b/fs/ncpfs/sock.c	Tue Oct  1 00:08:16 2002
@@ -743,7 +743,7 @@
 		sigset_t old_set;
 		unsigned long mask, flags;
 
-		spin_lock_irqsave(&current->sigmask_lock, flags);
+		spin_lock_irqsave(&current->sig->siglock, flags);
 		old_set = current->blocked;
 		if (current->flags & PF_EXITING)
 			mask = 0;
@@ -762,7 +762,7 @@
 		}
 		siginitsetinv(&current->blocked, mask);
 		recalc_sigpending();
-		spin_unlock_irqrestore(&current->sigmask_lock, flags);
+		spin_unlock_irqrestore(&current->sig->siglock, flags);
 		
 		fs = get_fs();
 		set_fs(get_ds());
@@ -771,10 +771,10 @@
 
 		set_fs(fs);
 
-		spin_lock_irqsave(&current->sigmask_lock, flags);
+		spin_lock_irqsave(&current->sig->siglock, flags);
 		current->blocked = old_set;
 		recalc_sigpending();
-		spin_unlock_irqrestore(&current->sigmask_lock, flags);
+		spin_unlock_irqrestore(&current->sig->siglock, flags);
 	}
 
 	DDPRINTK("do_ncp_rpc_call returned %d\n", result);
diff -Nru a/fs/ncpfs/symlink.c b/fs/ncpfs/symlink.c
--- a/fs/ncpfs/symlink.c	Tue Oct  1 00:08:20 2002
+++ b/fs/ncpfs/symlink.c	Tue Oct  1 00:08:20 2002
@@ -49,7 +49,7 @@
 	char *buf = kmap(page);
 
 	error = -ENOMEM;
-	rawlink=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_NFS);
+	rawlink=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_KERNEL);
 	if (!rawlink)
 		goto fail;
 
@@ -126,7 +126,7 @@
 	/* EPERM is returned by VFS if symlink procedure does not exist */
 		return -EPERM;
   
-	rawlink=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_NFS);
+	rawlink=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_KERNEL);
 	if (!rawlink)
 		return -ENOMEM;
 
diff -Nru a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
--- a/fs/nfsd/nfssvc.c	Tue Oct  1 00:08:14 2002
+++ b/fs/nfsd/nfssvc.c	Tue Oct  1 00:08:14 2002
@@ -186,10 +186,10 @@
 	 */
 	for (;;) {
 		/* Block all but the shutdown signals */
-		spin_lock_irq(&current->sigmask_lock);
+		spin_lock_irq(&current->sig->siglock);
 		siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
 		recalc_sigpending();
-		spin_unlock_irq(&current->sigmask_lock);
+		spin_unlock_irq(&current->sig->siglock);
 
 		/*
 		 * Find a socket with data available and call its
@@ -211,10 +211,10 @@
 		 */
 		rqstp->rq_client = exp_getclient(&rqstp->rq_addr);
 		/* Process request with signals blocked.  */
-		spin_lock_irq(&current->sigmask_lock);
+		spin_lock_irq(&current->sig->siglock);
 		siginitsetinv(&current->blocked, ALLOWED_SIGS);
 		recalc_sigpending();
-		spin_unlock_irq(&current->sigmask_lock);
+		spin_unlock_irq(&current->sig->siglock);
 
 		svc_process(serv, rqstp);
 
diff -Nru a/fs/nls/nls_cp1250.c b/fs/nls/nls_cp1250.c
--- a/fs/nls/nls_cp1250.c	Tue Oct  1 00:08:17 2002
+++ b/fs/nls/nls_cp1250.c	Tue Oct  1 00:08:17 2002
@@ -344,7 +344,7 @@
 module_init(init_nls_cp1250)
 module_exit(exit_nls_cp1250)
 
-MODULE_LICENSE("BSD without advertising clause");
+MODULE_LICENSE("Dual BSD/GPL");
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -Nru a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c
--- a/fs/openpromfs/inode.c	Tue Oct  1 00:08:17 2002
+++ b/fs/openpromfs/inode.c	Tue Oct  1 00:08:17 2002
@@ -582,28 +582,28 @@
 }
 
 static struct file_operations openpromfs_prop_ops = {
-	read:		property_read,
-	write:		property_write,
-	release:	property_release,
+	.read		= property_read,
+	.write		= property_write,
+	.release	= property_release,
 };
 
 static struct file_operations openpromfs_nodenum_ops = {
-	read:		nodenum_read,
+	.read		= nodenum_read,
 };
 
 static struct file_operations openprom_operations = {
-	read:		generic_read_dir,
-	readdir:	openpromfs_readdir,
+	.read		= generic_read_dir,
+	.readdir	= openpromfs_readdir,
 };
 
 static struct inode_operations openprom_alias_inode_operations = {
-	create:		openpromfs_create,
-	lookup:		openpromfs_lookup,
-	unlink:		openpromfs_unlink,
+	.create		= openpromfs_create,
+	.lookup		= openpromfs_lookup,
+	.unlink		= openpromfs_unlink,
 };
 
 static struct inode_operations openprom_inode_operations = {
-	lookup:		openpromfs_lookup,
+	.lookup		= openpromfs_lookup,
 };
 
 static int lookup_children(u16 n, const char * name, int len)
@@ -1026,8 +1026,8 @@
 }
 
 static struct super_operations openprom_sops = { 
-	read_inode:	openprom_read_inode,
-	statfs:		simple_statfs,
+	.read_inode	= openprom_read_inode,
+	.statfs		= simple_statfs,
 };
 
 static int openprom_fill_super(struct super_block *s, void *data, int silent)
@@ -1059,10 +1059,10 @@
 }
 
 static struct file_system_type openprom_fs_type = {
-	owner:		THIS_MODULE,
-	name:		"openpromfs",
-	get_sb:		openprom_get_sb,
-	kill_sb:	kill_anon_super,
+	.owner		= THIS_MODULE,
+	.name		= "openpromfs",
+	.get_sb		= openprom_get_sb,
+	.kill_sb	= kill_anon_super,
 };
 
 static int __init init_openprom_fs(void)
diff -Nru a/fs/partitions/check.c b/fs/partitions/check.c
--- a/fs/partitions/check.c	Tue Oct  1 00:08:16 2002
+++ b/fs/partitions/check.c	Tue Oct  1 00:08:16 2002
@@ -96,17 +96,17 @@
 			if (pos >= 0)
 				return buf + pos;
 		}
-		sprintf(buf, "%s", hd->major_name);
+		sprintf(buf, "%s", hd->disk_name);
 	} else {
 		if (hd->part[part-1].de) {
 			pos = devfs_generate_path(hd->part[part-1].de, buf, 64);
 			if (pos >= 0)
 				return buf + pos;
 		}
-		if (isdigit(hd->major_name[strlen(hd->major_name)-1]))
-			sprintf(buf, "%sp%d", hd->major_name, part);
+		if (isdigit(hd->disk_name[strlen(hd->disk_name)-1]))
+			sprintf(buf, "%sp%d", hd->disk_name, part);
 		else
-			sprintf(buf, "%s%d", hd->major_name, part);
+			sprintf(buf, "%s%d", hd->disk_name, part);
 	}
 	return buf;
 }
@@ -313,7 +313,7 @@
 		strncpy(dirname + pos, "../", 3);
 	} else {
 		/*  Unaware driver: construct "real" directory  */
-		sprintf(dirname, "../%s/disc%d", dev->major_name,
+		sprintf(dirname, "../%s/disc%d", dev->disk_name,
 			dev->first_minor >> dev->minor_shift);
 		dir = devfs_mk_dir(NULL, dirname + 3, NULL);
 	}
@@ -393,26 +393,10 @@
 #endif
 }
 
-/*
- * This function will re-read the partition tables for a given device,
- * and set things back up again.  There are some important caveats,
- * however.  You must ensure that no one is using the device, and no one
- * can start using the device while this function is being executed.
- *
- * Much of the cleanup from the old partition tables should have already been
- * done
- */
-
-void register_disk(struct gendisk *disk, kdev_t dev, unsigned minors,
-	struct block_device_operations *ops, long size)
+/* Not exported, helper to add_disk(). */
+void register_disk(struct gendisk *disk)
 {
 	struct block_device *bdev;
-
-	if (!disk)
-		return;
-
-	set_capacity(disk, size);
-
 	if (disk->flags & GENHD_FL_CD)
 		devfs_create_cdrom(disk);
 
@@ -421,10 +405,10 @@
 		return;
 
 	/* No such device (e.g., media were just removed) */
-	if (!size)
+	if (!get_capacity(disk))
 		return;
 
-	bdev = bdget(kdev_t_to_nr(dev));
+	bdev = bdget(MKDEV(disk->major, disk->first_minor));
 	if (blkdev_get(bdev, FMODE_READ, 0, BDEV_RAW) < 0)
 		return;
 	check_partition(disk, bdev);
@@ -569,6 +553,7 @@
 	static char nomem [] = "<nomem>";
 	struct dev_name *dname;
 	struct list_head *tmp;
+	int part;
 
 	list_for_each(tmp, &device_names) {
 		dname = list_entry(tmp, struct dev_name, list);
@@ -583,10 +568,10 @@
 	/*
 	 * ok, add this new device name to the list
 	 */
-	hd = get_gendisk(to_kdev_t(dev));
+	hd = get_gendisk(dev, &part);
 	dname->name = NULL;
 	if (hd)
-		dname->name = disk_name(hd, MINOR(dev)-hd->first_minor, dname->namebuf);
+		dname->name = disk_name(hd, part, dname->namebuf);
 	if (!dname->name) {
 		sprintf(dname->namebuf, "[dev %s]", kdevname(to_kdev_t(dev)));
 		dname->name = dname->namebuf;
diff -Nru a/fs/partitions/sun.c b/fs/partitions/sun.c
--- a/fs/partitions/sun.c	Tue Oct  1 00:08:20 2002
+++ b/fs/partitions/sun.c	Tue Oct  1 00:08:20 2002
@@ -18,7 +18,14 @@
 	Sector sect;
 	struct sun_disklabel {
 		unsigned char info[128];   /* Informative text string */
-		unsigned char spare[292];  /* Boot information etc. */
+		unsigned char spare0[14];
+		struct sun_info {
+			unsigned char spare1;
+			unsigned char id;
+			unsigned char spare2;
+			unsigned char flags;
+		} infos[8];
+		unsigned char spare[246];  /* Boot information etc. */
 		unsigned short rspeed;     /* Disk rotational speed */
 		unsigned short pcylcount;  /* Physical cylinder count */
 		unsigned short sparecyl;   /* extra sects per cylinder */
@@ -54,22 +61,27 @@
 	ush = ((unsigned short *) (label+1)) - 1;
 	for (csum = 0; ush >= ((unsigned short *) label);)
 		csum ^= *ush--;
-	if(csum) {
+	if (csum) {
 		printk("Dev %s Sun disklabel: Csum bad, label corrupted\n",
 		       bdevname(bdev));
 		put_dev_sector(sect);
 		return 0;
 	}
+
 	/* All Sun disks have 8 partition entries */
 	spc = be16_to_cpu(label->ntrks) * be16_to_cpu(label->nsect);
-	for(i=0; i < 8; i++, p++) {
+	for (i = 0; i < 8; i++, p++) {
 		unsigned long st_sector;
 		int num_sectors;
 
 		st_sector = be32_to_cpu(p->start_cylinder) * spc;
 		num_sectors = be32_to_cpu(p->num_sectors);
-		if (num_sectors)
-			put_partition(state, slot++, st_sector, num_sectors);
+		if (num_sectors) {
+			put_partition(state, slot, st_sector, num_sectors);
+			if (label->infos[i].id == LINUX_RAID_PARTITION)
+				state->parts[slot].flags = 1;
+			slot++;
+		}
 	}
 	printk("\n");
 	put_dev_sector(sect);
diff -Nru a/fs/proc/array.c b/fs/proc/array.c
--- a/fs/proc/array.c	Tue Oct  1 00:08:17 2002
+++ b/fs/proc/array.c	Tue Oct  1 00:08:17 2002
@@ -228,8 +228,9 @@
 	sigemptyset(ign);
 	sigemptyset(catch);
 
-	spin_lock_irq(&p->sigmask_lock);
+	read_lock(&tasklist_lock);
 	if (p->sig) {
+		spin_lock_irq(&p->sig->siglock);
 		k = p->sig->action;
 		for (i = 1; i <= _NSIG; ++i, ++k) {
 			if (k->sa.sa_handler == SIG_IGN)
@@ -237,8 +238,9 @@
 			else if (k->sa.sa_handler != SIG_DFL)
 				sigaddset(catch, i);
 		}
+		spin_unlock_irq(&p->sig->siglock);
 	}
-	spin_unlock_irq(&p->sigmask_lock);
+	read_unlock(&tasklist_lock);
 }
 
 static inline char * task_sig(struct task_struct *p, char *buffer)
diff -Nru a/fs/proc/base.c b/fs/proc/base.c
--- a/fs/proc/base.c	Tue Oct  1 00:08:15 2002
+++ b/fs/proc/base.c	Tue Oct  1 00:08:15 2002
@@ -310,7 +310,7 @@
 }
 
 static struct file_operations proc_maps_operations = {
-	read:		pid_maps_read,
+	.read		= pid_maps_read,
 };
 
 extern struct seq_operations mounts_op;
@@ -347,10 +347,10 @@
 }
 
 static struct file_operations proc_mounts_operations = {
-	open:		mounts_open,
-	read:		seq_read,
-	llseek:		seq_lseek,
-	release:	mounts_release,
+	.open		= mounts_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= mounts_release,
 };
 
 #define PROC_BLOCK_SIZE	(3*1024)		/* 4K page size but our output routines use some slack for overruns */
@@ -390,7 +390,7 @@
 }
 
 static struct file_operations proc_info_file_operations = {
-	read:		proc_info_read,
+	.read		= proc_info_read,
 };
 
 #define MAY_PTRACE(p) \
@@ -509,13 +509,13 @@
 #endif
 
 static struct file_operations proc_mem_operations = {
-	read:		mem_read,
-	write:		mem_write,
-	open:		mem_open,
+	.read		= mem_read,
+	.write		= mem_write,
+	.open		= mem_open,
 };
 
 static struct inode_operations proc_mem_inode_operations = {
-	permission:	proc_permission,
+	.permission	= proc_permission,
 };
 
 static int proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
@@ -587,8 +587,8 @@
 }
 
 static struct inode_operations proc_pid_link_inode_operations = {
-	readlink:	proc_pid_readlink,
-	follow_link:	proc_pid_follow_link
+	.readlink	= proc_pid_readlink,
+	.follow_link	= proc_pid_follow_link
 };
 
 #define NUMBUF 10
@@ -823,21 +823,21 @@
 
 static struct dentry_operations pid_fd_dentry_operations =
 {
-	d_revalidate:	pid_fd_revalidate,
-	d_delete:	pid_delete_dentry,
+	.d_revalidate	= pid_fd_revalidate,
+	.d_delete	= pid_delete_dentry,
 };
 
 static struct dentry_operations pid_dentry_operations =
 {
-	d_revalidate:	pid_revalidate,
-	d_delete:	pid_delete_dentry,
+	.d_revalidate	= pid_revalidate,
+	.d_delete	= pid_delete_dentry,
 };
 
 static struct dentry_operations pid_base_dentry_operations =
 {
-	d_revalidate:	pid_revalidate,
-	d_iput:		pid_base_iput,
-	d_delete:	pid_delete_dentry,
+	.d_revalidate	= pid_revalidate,
+	.d_iput		= pid_base_iput,
+	.d_delete	= pid_delete_dentry,
 };
 
 /* Lookups */
@@ -918,16 +918,16 @@
 }
 
 static struct file_operations proc_fd_operations = {
-	read:		generic_read_dir,
-	readdir:	proc_readfd,
+	.read		= generic_read_dir,
+	.readdir	= proc_readfd,
 };
 
 /*
  * proc directories can do almost nothing..
  */
 static struct inode_operations proc_fd_inode_operations = {
-	lookup:		proc_lookupfd,
-	permission:	proc_permission,
+	.lookup		= proc_lookupfd,
+	.permission	= proc_permission,
 };
 
 /* SMP-safe */
@@ -1032,12 +1032,12 @@
 }
 
 static struct file_operations proc_base_operations = {
-	read:		generic_read_dir,
-	readdir:	proc_base_readdir,
+	.read		= generic_read_dir,
+	.readdir	= proc_base_readdir,
 };
 
 static struct inode_operations proc_base_inode_operations = {
-	lookup:		proc_base_lookup,
+	.lookup		= proc_base_lookup,
 };
 
 /*
@@ -1058,8 +1058,8 @@
 }	
 
 static struct inode_operations proc_self_inode_operations = {
-	readlink:	proc_self_readlink,
-	follow_link:	proc_self_follow_link,
+	.readlink	= proc_self_readlink,
+	.follow_link	= proc_self_follow_link,
 };
 
 /* SMP-safe */
diff -Nru a/fs/proc/generic.c b/fs/proc/generic.c
--- a/fs/proc/generic.c	Tue Oct  1 00:08:21 2002
+++ b/fs/proc/generic.c	Tue Oct  1 00:08:21 2002
@@ -33,9 +33,9 @@
 }
 
 static struct file_operations proc_file_operations = {
-	llseek:		proc_file_lseek,
-	read:		proc_file_read,
-	write:		proc_file_write,
+	.llseek		= proc_file_lseek,
+	.read		= proc_file_read,
+	.write		= proc_file_write,
 };
 
 #ifndef MIN
@@ -230,8 +230,8 @@
 }
 
 static struct inode_operations proc_link_inode_operations = {
-	readlink:	proc_readlink,
-	follow_link:	proc_follow_link,
+	.readlink	= proc_readlink,
+	.follow_link	= proc_follow_link,
 };
 
 /*
@@ -247,7 +247,7 @@
 
 static struct dentry_operations proc_dentry_operations =
 {
-	d_delete:	proc_delete_dentry,
+	.d_delete	= proc_delete_dentry,
 };
 
 /*
@@ -359,15 +359,15 @@
  * the /proc directory.
  */
 static struct file_operations proc_dir_operations = {
-	read:			generic_read_dir,
-	readdir:		proc_readdir,
+	.read			= generic_read_dir,
+	.readdir		= proc_readdir,
 };
 
 /*
  * proc directories can do almost nothing..
  */
 static struct inode_operations proc_dir_inode_operations = {
-	lookup:		proc_lookup,
+	.lookup		= proc_lookup,
 };
 
 static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
diff -Nru a/fs/proc/inode.c b/fs/proc/inode.c
--- a/fs/proc/inode.c	Tue Oct  1 00:08:19 2002
+++ b/fs/proc/inode.c	Tue Oct  1 00:08:19 2002
@@ -130,12 +130,12 @@
 }
 
 static struct super_operations proc_sops = { 
-	alloc_inode:	proc_alloc_inode,
-	destroy_inode:	proc_destroy_inode,
-	read_inode:	proc_read_inode,
-	drop_inode:	generic_delete_inode,
-	delete_inode:	proc_delete_inode,
-	statfs:		simple_statfs,
+	.alloc_inode	= proc_alloc_inode,
+	.destroy_inode	= proc_destroy_inode,
+	.read_inode	= proc_read_inode,
+	.drop_inode	= generic_delete_inode,
+	.delete_inode	= proc_delete_inode,
+	.statfs		= simple_statfs,
 };
 
 static int parse_options(char *options,uid_t *uid,gid_t *gid)
diff -Nru a/fs/proc/kcore.c b/fs/proc/kcore.c
--- a/fs/proc/kcore.c	Tue Oct  1 00:08:14 2002
+++ b/fs/proc/kcore.c	Tue Oct  1 00:08:14 2002
@@ -30,8 +30,8 @@
 static ssize_t read_kcore(struct file *, char *, size_t, loff_t *);
 
 struct file_operations proc_kcore_operations = {
-	read:		read_kcore,
-	open:		open_kcore,
+	.read		= read_kcore,
+	.open		= open_kcore,
 };
 
 #ifdef CONFIG_KCORE_AOUT
diff -Nru a/fs/proc/kmsg.c b/fs/proc/kmsg.c
--- a/fs/proc/kmsg.c	Tue Oct  1 00:08:17 2002
+++ b/fs/proc/kmsg.c	Tue Oct  1 00:08:17 2002
@@ -46,8 +46,8 @@
 
 
 struct file_operations proc_kmsg_operations = {
-	read:		kmsg_read,
-	poll:		kmsg_poll,
-	open:		kmsg_open,
-	release:	kmsg_release,
+	.read		= kmsg_read,
+	.poll		= kmsg_poll,
+	.open		= kmsg_open,
+	.release	= kmsg_release,
 };
diff -Nru a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
--- a/fs/proc/proc_misc.c	Tue Oct  1 00:08:15 2002
+++ b/fs/proc/proc_misc.c	Tue Oct  1 00:08:15 2002
@@ -215,6 +215,20 @@
 #undef K
 }
 
+extern struct seq_operations fragmentation_op;
+static int fragmentation_open(struct inode *inode, struct file *file)
+{
+	(void)inode;
+	return seq_open(file, &fragmentation_op);
+}
+
+static struct file_operations fragmentation_file_operations = {
+	open:		fragmentation_open,
+	read:		seq_read,
+	llseek:		seq_lseek,
+	release:	seq_release,
+};
+
 static int version_read_proc(char *page, char **start, off_t off,
 				 int count, int *eof, void *data)
 {
@@ -232,10 +246,10 @@
 	return seq_open(file, &cpuinfo_op);
 }
 static struct file_operations proc_cpuinfo_operations = {
-	open:		cpuinfo_open,
-	read:		seq_read,
-	llseek:		seq_lseek,
-	release:	seq_release,
+	.open		= cpuinfo_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
 };
 
 #ifdef CONFIG_PROC_HARDWARE
@@ -262,10 +276,10 @@
 	return seq_open(file, &partitions_op);
 }
 static struct file_operations proc_partitions_operations = {
-	open:		partitions_open,
-	read:		seq_read,
-	llseek:		seq_lseek,
-	release:	seq_release,
+	.open		= partitions_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
 };
 
 #ifdef CONFIG_MODULES
@@ -275,10 +289,10 @@
 	return seq_open(file, &modules_op);
 }
 static struct file_operations proc_modules_operations = {
-	open:		modules_open,
-	read:		seq_read,
-	llseek:		seq_lseek,
-	release:	seq_release,
+	.open		= modules_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
 };
 extern struct seq_operations ksyms_op;
 static int ksyms_open(struct inode *inode, struct file *file)
@@ -286,10 +300,10 @@
 	return seq_open(file, &ksyms_op);
 }
 static struct file_operations proc_ksyms_operations = {
-	open:		ksyms_open,
-	read:		seq_read,
-	llseek:		seq_lseek,
-	release:	seq_release,
+	.open		= ksyms_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
 };
 #endif
 
@@ -300,11 +314,11 @@
 	return seq_open(file, &slabinfo_op);
 }
 static struct file_operations proc_slabinfo_operations = {
-	open:		slabinfo_open,
-	read:		seq_read,
-	write:		slabinfo_write,
-	llseek:		seq_lseek,
-	release:	seq_release,
+	.open		= slabinfo_open,
+	.read		= seq_read,
+	.write		= slabinfo_write,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
 };
 
 static int kstat_read_proc(char *page, char **start, off_t off,
@@ -442,10 +456,10 @@
 	return res;
 }
 static struct file_operations proc_interrupts_operations = {
-	open:		interrupts_open,
-	read:		seq_read,
-	llseek:		seq_lseek,
-	release:	single_release,
+	.open		= interrupts_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
 };
 
 static int filesystems_read_proc(char *page, char **start, off_t off,
@@ -573,8 +587,8 @@
 }
 
 static struct file_operations proc_profile_operations = {
-	read:		read_profile,
-	write:		write_profile,
+	.read		= read_profile,
+	.write		= write_profile,
 };
 
 struct proc_dir_entry *proc_root_kcore;
@@ -631,6 +645,7 @@
 	create_seq_entry("partitions", 0, &proc_partitions_operations);
 	create_seq_entry("interrupts", 0, &proc_interrupts_operations);
 	create_seq_entry("slabinfo",S_IWUSR|S_IRUGO,&proc_slabinfo_operations);
+	create_seq_entry("buddyinfo",S_IRUGO, &fragmentation_file_operations);
 #ifdef CONFIG_MODULES
 	create_seq_entry("modules", 0, &proc_modules_operations);
 	create_seq_entry("ksyms", 0, &proc_ksyms_operations);
diff -Nru a/fs/proc/root.c b/fs/proc/root.c
--- a/fs/proc/root.c	Tue Oct  1 00:08:19 2002
+++ b/fs/proc/root.c	Tue Oct  1 00:08:19 2002
@@ -31,9 +31,9 @@
 }
 
 static struct file_system_type proc_fs_type = {
-	name:		"proc",
-	get_sb:		proc_get_sb,
-	kill_sb:	kill_anon_super,
+	.name		= "proc",
+	.get_sb		= proc_get_sb,
+	.kill_sb	= kill_anon_super,
 };
 
 extern int __init proc_init_inodecache(void);
@@ -122,29 +122,29 @@
  * directory handling functions for that..
  */
 static struct file_operations proc_root_operations = {
-	read:		 generic_read_dir,
-	readdir:	 proc_root_readdir,
+	.read		 = generic_read_dir,
+	.readdir	 = proc_root_readdir,
 };
 
 /*
  * proc root can do almost nothing..
  */
 static struct inode_operations proc_root_inode_operations = {
-	lookup:		proc_root_lookup,
+	.lookup		= proc_root_lookup,
 };
 
 /*
  * This is the root "inode" in the /proc tree..
  */
 struct proc_dir_entry proc_root = {
-	low_ino:	PROC_ROOT_INO, 
-	namelen:	5, 
-	name:		"/proc",
-	mode:		S_IFDIR | S_IRUGO | S_IXUGO, 
-	nlink:		2, 
-	proc_iops:	&proc_root_inode_operations, 
-	proc_fops:	&proc_root_operations,
-	parent:		&proc_root,
+	.low_ino	= PROC_ROOT_INO, 
+	.namelen	= 5, 
+	.name		= "/proc",
+	.mode		= S_IFDIR | S_IRUGO | S_IXUGO, 
+	.nlink		= 2, 
+	.proc_iops	= &proc_root_inode_operations, 
+	.proc_fops	= &proc_root_operations,
+	.parent		= &proc_root,
 };
 
 #ifdef CONFIG_SYSCTL
diff -Nru a/fs/ramfs/inode.c b/fs/ramfs/inode.c
--- a/fs/ramfs/inode.c	Tue Oct  1 00:08:16 2002
+++ b/fs/ramfs/inode.c	Tue Oct  1 00:08:16 2002
@@ -276,35 +276,35 @@
 }
 
 static struct address_space_operations ramfs_aops = {
-	readpage:	ramfs_readpage,
-	writepage:	fail_writepage,
-	prepare_write:	ramfs_prepare_write,
-	commit_write:	ramfs_commit_write
+	.readpage	= ramfs_readpage,
+	.writepage	= fail_writepage,
+	.prepare_write	= ramfs_prepare_write,
+	.commit_write	= ramfs_commit_write
 };
 
 static struct file_operations ramfs_file_operations = {
-	read:		generic_file_read,
-	write:		generic_file_write,
-	mmap:		generic_file_mmap,
-	fsync:		ramfs_sync_file,
-	sendfile:	generic_file_sendfile,
+	.read		= generic_file_read,
+	.write		= generic_file_write,
+	.mmap		= generic_file_mmap,
+	.fsync		= ramfs_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,
-	symlink:	ramfs_symlink,
-	mkdir:		ramfs_mkdir,
-	rmdir:		ramfs_rmdir,
-	mknod:		ramfs_mknod,
-	rename:		ramfs_rename,
+	.create		= ramfs_create,
+	.lookup		= simple_lookup,
+	.link		= ramfs_link,
+	.unlink		= ramfs_unlink,
+	.symlink	= ramfs_symlink,
+	.mkdir		= ramfs_mkdir,
+	.rmdir		= ramfs_rmdir,
+	.mknod		= ramfs_mknod,
+	.rename		= ramfs_rename,
 };
 
 static struct super_operations ramfs_ops = {
-	statfs:		simple_statfs,
-	drop_inode:	generic_delete_inode,
+	.statfs		= simple_statfs,
+	.drop_inode	= generic_delete_inode,
 };
 
 static int ramfs_fill_super(struct super_block * sb, void * data, int silent)
@@ -342,14 +342,14 @@
 }
 
 static struct file_system_type ramfs_fs_type = {
-	name:		"ramfs",
-	get_sb:		ramfs_get_sb,
-	kill_sb:	kill_litter_super,
+	.name		= "ramfs",
+	.get_sb		= ramfs_get_sb,
+	.kill_sb	= kill_litter_super,
 };
 static struct file_system_type rootfs_fs_type = {
-	name:		"rootfs",
-	get_sb:		rootfs_get_sb,
-	kill_sb:	kill_litter_super,
+	.name		= "rootfs",
+	.get_sb		= rootfs_get_sb,
+	.kill_sb	= kill_litter_super,
 };
 
 static int __init init_ramfs_fs(void)
diff -Nru a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
--- a/fs/reiserfs/journal.c	Tue Oct  1 00:08:17 2002
+++ b/fs/reiserfs/journal.c	Tue Oct  1 00:08:17 2002
@@ -65,13 +65,6 @@
 */
 static int reiserfs_mounted_fs_count = 0 ;
 
-/* wake this up when you add something to the commit thread task queue */
-DECLARE_WAIT_QUEUE_HEAD(reiserfs_commit_thread_wait) ;
-
-/* wait on this if you need to be sure you task queue entries have been run */
-static DECLARE_WAIT_QUEUE_HEAD(reiserfs_commit_thread_done) ;
-DECLARE_TASK_QUEUE(reiserfs_commit_thread_tq) ;
-
 #define JOURNAL_TRANS_HALF 1018   /* must be correct to keep the desc and commit
 				     structs at 4k */
 #define BUFNR 64 /*read ahead */
@@ -1339,12 +1332,9 @@
     do_journal_end(&myth, p_s_sb,1, FLUSH_ALL) ;
   }
 
-  /* we decrement before we wake up, because the commit thread dies off
-  ** when it has been woken up and the count is <= 0
-  */
   reiserfs_mounted_fs_count-- ;
-  wake_up(&reiserfs_commit_thread_wait) ;
-  sleep_on(&reiserfs_commit_thread_done) ;
+  /* wait for all commits to finish */
+  flush_scheduled_tasks();
 
   release_journal_dev( p_s_sb, SB_JOURNAL( p_s_sb ) );
   free_journal_ram(p_s_sb) ;
@@ -1815,6 +1805,10 @@
 static void reiserfs_journal_commit_task_func(struct reiserfs_journal_commit_task *ct) {
 
   struct reiserfs_journal_list *jl ;
+
+  /* FIXMEL: is this needed? */
+  lock_kernel();
+
   jl = SB_JOURNAL_LIST(ct->p_s_sb) + ct->jindex ;
 
   flush_commit_list(ct->p_s_sb, SB_JOURNAL_LIST(ct->p_s_sb) + ct->jindex, 1) ; 
@@ -1824,6 +1818,7 @@
     kupdate_one_transaction(ct->p_s_sb, jl) ;
   }
   reiserfs_kfree(ct->self, sizeof(struct reiserfs_journal_commit_task), ct->p_s_sb) ;
+  unlock_kernel();
 }
 
 static void setup_commit_task_arg(struct reiserfs_journal_commit_task *ct,
@@ -1850,8 +1845,7 @@
   ct = reiserfs_kmalloc(sizeof(struct reiserfs_journal_commit_task), GFP_NOFS, p_s_sb) ;
   if (ct) {
     setup_commit_task_arg(ct, p_s_sb, jindex) ;
-    queue_task(&(ct->task), &reiserfs_commit_thread_tq);
-    wake_up(&reiserfs_commit_thread_wait) ;
+    schedule_task(&ct->task) ;
   } else {
 #ifdef CONFIG_REISERFS_CHECK
     reiserfs_warning("journal-1540: kmalloc failed, doing sync commit\n") ;
@@ -1860,49 +1854,6 @@
   }
 }
 
-/*
-** this is the commit thread.  It is started with kernel_thread on
-** FS mount, and journal_release() waits for it to exit.
-**
-** It could do a periodic commit, but there is a lot code for that
-** elsewhere right now, and I only wanted to implement this little
-** piece for starters.
-**
-** All we do here is sleep on the j_commit_thread_wait wait queue, and
-** then run the per filesystem commit task queue when we wakeup.
-*/
-static int reiserfs_journal_commit_thread(void *nullp) {
-
-  daemonize() ;
-
-  spin_lock_irq(&current->sigmask_lock);
-  sigfillset(&current->blocked);
-  recalc_sigpending();
-  spin_unlock_irq(&current->sigmask_lock);
-
-  sprintf(current->comm, "kreiserfsd") ;
-  lock_kernel() ;
-  while(1) {
-
-    while(TQ_ACTIVE(reiserfs_commit_thread_tq)) {
-      run_task_queue(&reiserfs_commit_thread_tq) ;
-    }
-
-    /* if there aren't any more filesystems left, break */
-    if (reiserfs_mounted_fs_count <= 0) {
-      run_task_queue(&reiserfs_commit_thread_tq) ;
-      break ;
-    }
-    wake_up(&reiserfs_commit_thread_done) ;
-    if (current->flags & PF_FREEZE)
-      refrigerator(PF_IOTHREAD);
-    interruptible_sleep_on_timeout(&reiserfs_commit_thread_wait, 5 * HZ) ;
-  }
-  unlock_kernel() ;
-  wake_up(&reiserfs_commit_thread_done) ;
-  return 0 ;
-}
-
 static void journal_list_init(struct super_block *p_s_sb) {
   int i ;
   for (i = 0 ; i < JOURNAL_LIST_COUNT ; i++) {
@@ -2175,10 +2126,6 @@
     return 0;
 
   reiserfs_mounted_fs_count++ ;
-  if (reiserfs_mounted_fs_count <= 1) {
-    kernel_thread((void *)(void *)reiserfs_journal_commit_thread, NULL,
-                  CLONE_FS | CLONE_FILES | CLONE_VM) ;
-  }
   return 0 ;
 
 }
diff -Nru a/fs/romfs/inode.c b/fs/romfs/inode.c
--- a/fs/romfs/inode.c	Tue Oct  1 00:08:18 2002
+++ b/fs/romfs/inode.c	Tue Oct  1 00:08:18 2002
@@ -456,16 +456,16 @@
 /* Mapping from our types to the kernel */
 
 static struct address_space_operations romfs_aops = {
-	readpage: romfs_readpage
+	.readpage = romfs_readpage
 };
 
 static struct file_operations romfs_dir_operations = {
-	read:		generic_read_dir,
-	readdir:	romfs_readdir,
+	.read		= generic_read_dir,
+	.readdir	= romfs_readdir,
 };
 
 static struct inode_operations romfs_dir_inode_operations = {
-	lookup:		romfs_lookup,
+	.lookup		= romfs_lookup,
 };
 
 static mode_t romfs_modemap[] =
@@ -590,10 +590,10 @@
 }
 
 static struct super_operations romfs_ops = {
-	alloc_inode:	romfs_alloc_inode,
-	destroy_inode:	romfs_destroy_inode,
-	read_inode:	romfs_read_inode,
-	statfs:		romfs_statfs,
+	.alloc_inode	= romfs_alloc_inode,
+	.destroy_inode	= romfs_destroy_inode,
+	.read_inode	= romfs_read_inode,
+	.statfs		= romfs_statfs,
 };
 
 static struct super_block *romfs_get_sb(struct file_system_type *fs_type,
@@ -603,11 +603,11 @@
 }
 
 static struct file_system_type romfs_fs_type = {
-	owner:		THIS_MODULE,
-	name:		"romfs",
-	get_sb:		romfs_get_sb,
-	kill_sb:	kill_block_super,
-	fs_flags:	FS_REQUIRES_DEV,
+	.owner		= THIS_MODULE,
+	.name		= "romfs",
+	.get_sb		= romfs_get_sb,
+	.kill_sb	= kill_block_super,
+	.fs_flags	= FS_REQUIRES_DEV,
 };
 
 static int __init init_romfs_fs(void)
diff -Nru a/fs/smbfs/ChangeLog b/fs/smbfs/ChangeLog
--- a/fs/smbfs/ChangeLog	Tue Oct  1 00:08:19 2002
+++ b/fs/smbfs/ChangeLog	Tue Oct  1 00:08:19 2002
@@ -1,5 +1,10 @@
 ChangeLog for smbfs.
 
+2002-04-19 John Newbigin <jn@it.swin.edu.au>
+
+	* Implementation of CIFS Extensions for UNIX systems, including soft
+	  and hard links.
+
 2001-08-03 Urban Widmark <urban@teststation.com>
 
 	* *.c: Unicode support
diff -Nru a/fs/smbfs/Makefile b/fs/smbfs/Makefile
--- a/fs/smbfs/Makefile	Tue Oct  1 00:08:16 2002
+++ b/fs/smbfs/Makefile	Tue Oct  1 00:08:16 2002
@@ -5,7 +5,7 @@
 obj-$(CONFIG_SMB_FS) += smbfs.o
 
 smbfs-objs := proc.o dir.o cache.o sock.o inode.o file.o ioctl.o getopt.o \
-		smbiod.o request.o
+		symlink.o smbiod.o request.o
 
 # If you want debugging output, you may add these flags to the EXTRA_CFLAGS
 # SMBFS_PARANOIA should normally be enabled.
@@ -24,7 +24,8 @@
 #
 
 # getopt.c not included. It is intentionally separate
-SRC = proc.c dir.c cache.c sock.c inode.c file.c ioctl.c smbiod.c request.c
+SRC = proc.c dir.c cache.c sock.c inode.c file.c ioctl.c smbiod.c request.c \
+	symlink.c
 
 proto:
 	-rm -f proto.h
diff -Nru a/fs/smbfs/dir.c b/fs/smbfs/dir.c
--- a/fs/smbfs/dir.c	Tue Oct  1 00:08:17 2002
+++ b/fs/smbfs/dir.c	Tue Oct  1 00:08:17 2002
@@ -30,6 +30,8 @@
 static int smb_unlink(struct inode *, struct dentry *);
 static int smb_rename(struct inode *, struct dentry *,
 		      struct inode *, struct dentry *);
+static int smb_make_node(struct inode *,struct dentry *,int,int);
+static int smb_link(struct dentry *, struct inode *, struct dentry *);
 
 struct file_operations smb_dir_operations =
 {
@@ -51,6 +53,21 @@
 	.setattr	= smb_notify_change,
 };
 
+struct inode_operations smb_dir_inode_operations_unix =
+{
+	.create		= smb_create,
+	.lookup		= smb_lookup,
+	.unlink		= smb_unlink,
+	.mkdir		= smb_mkdir,
+	.rmdir		= smb_rmdir,
+	.rename		= smb_rename,
+	.getattr	= smb_getattr,
+	.setattr	= smb_notify_change,
+	.symlink	= smb_symlink,
+	.mknod		= smb_make_node,
+	.link		= smb_link,
+};
+
 /*
  * Read a directory, using filldir to fill the dirent memory.
  * smb_proc_readdir does the actual reading from the smb server.
@@ -485,8 +502,10 @@
 static int
 smb_create(struct inode *dir, struct dentry *dentry, int mode)
 {
+	struct smb_sb_info *server = server_from_dentry(dentry);
 	__u16 fileid;
 	int error;
+	struct iattr attr;
 
 	VERBOSE("creating %s/%s, mode=%d\n", DENTRY_PATH(dentry), mode);
 
@@ -494,6 +513,12 @@
 	smb_invalid_dir_cache(dir);
 	error = smb_proc_create(dentry, 0, CURRENT_TIME, &fileid);
 	if (!error) {
+		if (server->opt.capabilities & SMB_CAP_UNIX) {
+			/* Set attributes for new file */
+			attr.ia_valid = ATTR_MODE;
+			attr.ia_mode = mode;
+			error = smb_proc_setattr_unix(dentry, &attr, 0, 0);
+		}
 		error = smb_instantiate(dentry, fileid, 1);
 	} else {
 		PARANOIA("%s/%s failed, error=%d\n",
@@ -507,12 +532,20 @@
 static int
 smb_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
+	struct smb_sb_info *server = server_from_dentry(dentry);
 	int error;
+	struct iattr attr;
 
 	lock_kernel();
 	smb_invalid_dir_cache(dir);
 	error = smb_proc_mkdir(dentry);
 	if (!error) {
+		if (server->opt.capabilities & SMB_CAP_UNIX) {
+			/* Set attributes for new directory */
+			attr.ia_valid = ATTR_MODE;
+			attr.ia_mode = mode;
+			error = smb_proc_setattr_unix(dentry, &attr, 0, 0);
+		}
 		error = smb_instantiate(dentry, 0, 0);
 	}
 	unlock_kernel();
@@ -599,5 +632,48 @@
 	}
 out:
 	unlock_kernel();
+	return error;
+}
+
+/*
+ * FIXME: samba servers won't let you create device nodes unless uid/gid
+ * matches the connection credentials (and we don't know which those are ...)
+ */
+static int
+smb_make_node(struct inode *dir, struct dentry *dentry, int mode, int dev)
+{
+	int error;
+	struct iattr attr;
+
+	attr.ia_valid = ATTR_MODE | ATTR_UID | ATTR_GID;
+	attr.ia_mode = mode;
+	attr.ia_uid = current->euid;
+	attr.ia_gid = current->egid;
+
+	smb_invalid_dir_cache(dir);
+	error = smb_proc_setattr_unix(dentry, &attr, MAJOR(dev), MINOR(dev));
+	if (!error) {
+		error = smb_instantiate(dentry, 0, 0);
+	}
+	return error;
+}
+
+/*
+ * dentry = existing file
+ * new_dentry = new file
+ */
+static int
+smb_link(struct dentry *dentry, struct inode *dir, struct dentry *new_dentry)
+{
+	int error;
+
+	DEBUG1("smb_link old=%s/%s new=%s/%s\n",
+	       DENTRY_PATH(dentry), DENTRY_PATH(new_dentry));
+	smb_invalid_dir_cache(dir);
+	error = smb_proc_link(server_from_dentry(dentry), dentry, new_dentry);
+	if (!error) {
+		smb_renew_times(dentry);
+		error = smb_instantiate(new_dentry, 0, 0);
+	}
 	return error;
 }
diff -Nru a/fs/smbfs/inode.c b/fs/smbfs/inode.c
--- a/fs/smbfs/inode.c	Tue Oct  1 00:08:15 2002
+++ b/fs/smbfs/inode.c	Tue Oct  1 00:08:15 2002
@@ -106,6 +106,7 @@
 struct inode *
 smb_iget(struct super_block *sb, struct smb_fattr *fattr)
 {
+	struct smb_sb_info *server = SMB_SB(sb);
 	struct inode *result;
 
 	DEBUG1("smb_iget: %p\n", fattr);
@@ -126,8 +127,15 @@
 		result->i_fop = &smb_file_operations;
 		result->i_data.a_ops = &smb_file_aops;
 	} else if (S_ISDIR(result->i_mode)) {
-		result->i_op = &smb_dir_inode_operations;
+		if (server->opt.capabilities & SMB_CAP_UNIX)
+			result->i_op = &smb_dir_inode_operations_unix;
+		else
+			result->i_op = &smb_dir_inode_operations;
 		result->i_fop = &smb_dir_operations;
+	} else if (S_ISLNK(result->i_mode)) {
+		result->i_op = &smb_link_inode_operations;
+	} else {
+		init_special_inode(result, result->i_mode, fattr->f_rdev);
 	}
 	insert_inode_hash(result);
 	return result;
@@ -235,7 +243,14 @@
 		/*
 		 * Check whether the type part of the mode changed,
 		 * and don't update the attributes if it did.
+		 *
+		 * And don't dick with the root inode
 		 */
+		if (inode->i_ino == 2)
+			return error;
+		if (S_ISLNK(inode->i_mode))
+			return error;	/* VFS will deal with it */
+
 		if ((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT)) {
 			smb_set_inode_attr(inode, &fattr);
 		} else {
@@ -434,10 +449,9 @@
 {
 	struct smb_sb_info *server = SMB_SB(sb);
 
-	smbiod_unregister_server(server);
-
 	smb_lock_server(server);
 	server->state = CONN_INVALID;
+	smbiod_unregister_server(server);
 
 	smb_close_socket(server);
 
@@ -663,6 +677,17 @@
 		if (error)
 			goto out;
 		refresh = 1;
+	}
+
+	if (server->opt.capabilities & SMB_CAP_UNIX) {
+		/* For now we don't want to set the size with setattr_unix */
+		attr->ia_valid &= ~ATTR_SIZE;
+		/* FIXME: only call if we actually want to set something? */
+		error = smb_proc_setattr_unix(dentry, attr, 0, 0);
+		if (!error)
+			refresh = 1;
+
+		goto out;
 	}
 
 	/*
diff -Nru a/fs/smbfs/proc.c b/fs/smbfs/proc.c
--- a/fs/smbfs/proc.c	Tue Oct  1 00:08:15 2002
+++ b/fs/smbfs/proc.c	Tue Oct  1 00:08:15 2002
@@ -54,6 +54,7 @@
 static struct smb_ops smb_ops_os2;
 static struct smb_ops smb_ops_win95;
 static struct smb_ops smb_ops_winNT;
+static struct smb_ops smb_ops_unix;
 
 static void
 smb_init_dirent(struct smb_sb_info *server, struct smb_fattr *fattr);
@@ -71,6 +72,8 @@
 static int
 smb_proc_setattr_ext(struct smb_sb_info *server,
 		     struct inode *inode, struct smb_fattr *fattr);
+int
+smb_proc_query_cifsunix(struct smb_sb_info *server);
 static void
 install_ops(struct smb_ops *dst, struct smb_ops *src);
 
@@ -521,15 +524,47 @@
 	return (time_t)t;
 }
 
-#if 0
 /* Convert the Unix UTC into NT time */
 static u64
-smb_unixutc2ntutc(struct smb_sb_info *server, time_t t)
+smb_unixutc2ntutc(time_t t)
 {
 	/* Note: timezone conversion is probably wrong. */
-	return ((u64)utc2local(server, t)) * 10000000 + NTFS_TIME_OFFSET;
+	/* return ((u64)utc2local(server, t)) * 10000000 + NTFS_TIME_OFFSET; */
+	return ((u64)t) * 10000000 + NTFS_TIME_OFFSET;
+}
+
+#define MAX_FILE_MODE	6
+static mode_t file_mode[] = {
+	S_IFREG, S_IFDIR, S_IFLNK, S_IFCHR, S_IFBLK, S_IFIFO, S_IFSOCK
+};
+
+static int smb_filetype_to_mode(u32 filetype)
+{
+	if (filetype > MAX_FILE_MODE) {
+		PARANOIA("Filetype out of range: %d\n", filetype);
+		return S_IFREG;
+	}
+	return file_mode[filetype];
+}
+
+static u32 smb_filetype_from_mode(int mode)
+{
+	if (mode & S_IFREG)
+		return UNIX_TYPE_FILE;
+	if (mode & S_IFDIR)
+		return UNIX_TYPE_DIR;
+	if (mode & S_IFLNK)
+		return UNIX_TYPE_SYMLINK;
+	if (mode & S_IFCHR)
+		return UNIX_TYPE_CHARDEV;
+	if (mode & S_IFBLK)
+		return UNIX_TYPE_BLKDEV;
+	if (mode & S_IFIFO)
+		return UNIX_TYPE_FIFO;
+	if (mode & S_IFSOCK)
+		return UNIX_TYPE_SOCKET;
+	return UNIX_TYPE_UNKNOWN;
 }
-#endif
 
 
 /*****************************************************************************/
@@ -913,6 +948,14 @@
 		VERBOSE("Large writes enabled\n");
 	}
 #endif
+	if (server->opt.capabilities & SMB_CAP_UNIX) {
+		struct inode *inode;
+		VERBOSE("Using UNIX CIFS extensions\n");
+		install_ops(server->ops, &smb_ops_unix);
+		inode = SB_of(server)->s_root->d_inode;
+		if (inode)
+			inode->i_op = &smb_dir_inode_operations_unix;
+	}
 
 	VERBOSE("protocol=%d, max_xmit=%d, pid=%d capabilities=0x%x\n",
 		server->opt.protocol, server->opt.max_xmit, server->conn_pid,
@@ -923,6 +966,12 @@
 		server->opt.max_xmit = SMB_MAX_PACKET_SIZE;
 	}
 
+	smb_unlock_server(server);
+	smbiod_wake_up();
+	if (server->opt.capabilities & SMB_CAP_UNIX)
+		smb_proc_query_cifsunix(server);
+	return error;
+
 out:
 	smb_unlock_server(server);
 	smbiod_wake_up();
@@ -1078,6 +1127,7 @@
 			VERBOSE("%s/%s R/W failed, error=%d, retrying R/O\n",
 				DENTRY_PATH(dentry), res);
 			mode = read_only;
+			req->rq_flags = 0;
 			goto retry;
 		}
 		goto out_free;
@@ -1197,7 +1247,8 @@
 		 * If the file is open with write permissions,
 		 * update the time stamps to sync mtime and atime.
 		 */
-		if ((server->opt.protocol >= SMB_PROTOCOL_LANMAN2) &&
+		if ((server->opt.capabilities & SMB_CAP_UNIX) == 0 &&
+		    (server->opt.protocol >= SMB_PROTOCOL_LANMAN2) &&
 		    !(ei->access == SMB_O_RDONLY))
 		{
 			struct smb_fattr fattr;
@@ -1593,6 +1644,8 @@
 	int result;
 	struct smb_fattr fattr;
 
+	/* FIXME: cifsUE should allow removing a readonly file. */
+
 	/* first get current attribute */
 	smb_init_dirent(server, &fattr);
 	result = server->ops->getattr(server, dentry, &fattr);
@@ -1649,6 +1702,7 @@
 			result = smb_set_rw(dentry,server);
 			if (result == 0) {
 				flag = 1;
+				req->rq_flags = 0;
 				goto retry;
 			}
 		}
@@ -1762,14 +1816,17 @@
 	fattr->f_uid = server->mnt->uid;
 	fattr->f_gid = server->mnt->gid;
 	fattr->f_blksize = SMB_ST_BLKSIZE;
+	fattr->f_unix = 0;
 }
 
 static void
 smb_finish_dirent(struct smb_sb_info *server, struct smb_fattr *fattr)
 {
+	if (fattr->f_unix)
+		return;
+
 	fattr->f_mode = server->mnt->file_mode;
-	if (fattr->attr & aDIR)
-	{
+	if (fattr->attr & aDIR) {
 		fattr->f_mode = server->mnt->dir_mode;
 		fattr->f_size = SMB_ST_BLKSIZE;
 	}
@@ -2006,6 +2063,43 @@
 	return result;
 }
 
+void smb_decode_unix_basic(struct smb_fattr *fattr, char *p)
+{
+	/* FIXME: verify nls support. all is sent as utf8? */
+	__u64 devmajor, devminor;
+
+	fattr->f_unix = 1;
+	fattr->f_mode = 0;
+
+	/* FIXME: use the uniqueID from the remote instead? */
+	/* 0 L file size in bytes */
+	/* 8 L file size on disk in bytes (block count) */
+	/* 40 L uid */
+	/* 48 L gid */
+	/* 56 W file type */
+	/* 60 L devmajor */
+	/* 68 L devminor */
+	/* 76 L unique ID (inode) */
+	/* 84 L permissions */
+	/* 92 L link count */
+
+	fattr->f_size = LVAL(p, 0);
+	fattr->f_blocks = LVAL(p, 8);
+	fattr->f_ctime = smb_ntutc2unixutc(LVAL(p, 16));
+	fattr->f_atime = smb_ntutc2unixutc(LVAL(p, 24));
+	fattr->f_mtime = smb_ntutc2unixutc(LVAL(p, 32));
+	fattr->f_uid = LVAL(p, 40); 
+	fattr->f_gid = LVAL(p, 48); 
+	fattr->f_mode |= smb_filetype_to_mode(WVAL(p, 56));
+
+	if (S_ISBLK(fattr->f_mode) || S_ISCHR(fattr->f_mode)) {
+		devmajor = LVAL(p, 60);
+		devminor = LVAL(p, 68);
+		fattr->f_rdev = ((devmajor & 0xFF) << 8) | (devminor & 0xFF);
+	}
+	fattr->f_mode |= LVAL(p, 84);
+}
+
 /*
  * Interpret a long filename structure using the specified info level:
  *   level 1 for anything below NT1 protocol
@@ -2078,6 +2172,18 @@
 		VERBOSE("info 260 at %p, len=%d, name=%.*s\n",
 			p, len, len, qname->name);
 		break;
+	case SMB_FIND_FILE_UNIX:
+		result = p + WVAL(p, 0);
+		qname->name = p + 108;
+
+		len = strlen(qname->name);
+		/* FIXME: should we check the length?? */
+
+		p += 8;
+		smb_decode_unix_basic(fattr, p);
+		VERBOSE("info SMB_FIND_FILE_UNIX at %p, len=%d, name=%.*s\n",
+			p, len, len, qname->name);
+		break;
 	default:
 		PARANOIA("Unknown info level %d\n", level);
 		result = p + WVAL(p, 0);
@@ -2166,9 +2272,12 @@
 	lock_kernel();
 
 	/*
-	 * use info level 1 for older servers that don't do 260
+	 * We always prefer unix style. Use info level 1 for older
+	 * servers that don't do 260.
 	 */
-	if (server->opt.protocol < SMB_PROTOCOL_NT1)
+	if (server->opt.capabilities & SMB_CAP_UNIX)
+		info_level = SMB_FIND_FILE_UNIX;
+	else if (server->opt.protocol < SMB_PROTOCOL_NT1)
 		info_level = 1;
 
 	result = -ENOMEM;
@@ -2309,13 +2418,18 @@
 		 * here that those who do not point to a filename do not need
 		 * this info to continue the listing.
 		 *
-		 * OS/2 needs this and talks infolevel 1
-		 * NetApps want lastname with infolevel 260
+		 * OS/2 needs this and talks infolevel 1.
+		 * NetApps want lastname with infolevel 260.
+		 * win2k want lastname with infolevel 260, and points to
+		 *       the record not to the name.
+		 * Samba+CifsUnixExt doesn't need lastname.
 		 *
 		 * Both are happy if we return the data they point to. So we do.
+		 * (FIXME: above is not true with win2k)
 		 */
 		mask_len = 0;
-		if (ff_lastname > 0 && ff_lastname < req->rq_ldata) {
+		if (info_level != SMB_FIND_FILE_UNIX &&
+		    ff_lastname > 0 && ff_lastname < req->rq_ldata) {
 			lastname = req->rq_data + ff_lastname;
 
 			switch (info_level) {
@@ -2607,6 +2721,30 @@
 }
 
 static int
+smb_proc_getattr_unix(struct smb_sb_info *server, struct dentry *dir,
+		      struct smb_fattr *attr)
+{
+	struct smb_request *req;
+	int result;
+
+	result = -ENOMEM;
+	if (! (req = smb_alloc_request(server, PAGE_SIZE)))
+		goto out;
+
+	result = smb_proc_getattr_trans2(server, dir, req,
+					 SMB_QUERY_FILE_UNIX_BASIC);
+	if (result < 0)
+		goto out_free;
+
+	smb_decode_unix_basic(attr, req->rq_data);
+
+out_free:
+	smb_rput(req);
+out:
+	return result;
+}
+
+static int
 smb_proc_getattr_95(struct smb_sb_info *server, struct dentry *dir,
 		    struct smb_fattr *attr)
 {
@@ -2825,6 +2963,120 @@
 }
 
 /*
+ * ATTR_MODE      0x001
+ * ATTR_UID       0x002
+ * ATTR_GID       0x004
+ * ATTR_SIZE      0x008
+ * ATTR_ATIME     0x010
+ * ATTR_MTIME     0x020
+ * ATTR_CTIME     0x040
+ * ATTR_ATIME_SET 0x080
+ * ATTR_MTIME_SET 0x100
+ * ATTR_FORCE     0x200	
+ * ATTR_ATTR_FLAG 0x400
+ *
+ * major/minor should only be set by mknod.
+ */
+int
+smb_proc_setattr_unix(struct dentry *d, struct iattr *attr,
+		      int major, int minor)
+{
+	struct smb_sb_info *server = server_from_dentry(d);
+	u64 nttime;
+	char *p, *param;
+	int result;
+	char data[100];
+	struct smb_request *req;
+
+	result = -ENOMEM;
+	if (! (req = smb_alloc_request(server, PAGE_SIZE)))
+		goto out;
+	param = req->rq_buffer;
+
+	DEBUG1("valid flags = 0x%04x\n", attr->ia_valid);
+
+	WSET(param, 0, SMB_SET_FILE_UNIX_BASIC);
+	DSET(param, 2, 0);
+	result = smb_encode_path(server, param+6, SMB_MAXPATHLEN+1, d, NULL);
+	if (result < 0)
+		goto out_free;
+	p = param + 6 + result;
+
+	/* 0 L file size in bytes */
+	/* 8 L file size on disk in bytes (block count) */
+	/* 40 L uid */
+	/* 48 L gid */
+	/* 56 W file type enum */
+	/* 60 L devmajor */
+	/* 68 L devminor */
+	/* 76 L unique ID (inode) */
+	/* 84 L permissions */
+	/* 92 L link count */
+	LSET(data, 0, SMB_SIZE_NO_CHANGE);
+	LSET(data, 8, SMB_SIZE_NO_CHANGE);
+	LSET(data, 16, SMB_TIME_NO_CHANGE);
+	LSET(data, 24, SMB_TIME_NO_CHANGE);
+	LSET(data, 32, SMB_TIME_NO_CHANGE);
+	LSET(data, 40, SMB_UID_NO_CHANGE);
+	LSET(data, 48, SMB_GID_NO_CHANGE);
+	LSET(data, 56, smb_filetype_from_mode(attr->ia_mode));
+	LSET(data, 60, major);
+	LSET(data, 68, minor);
+	LSET(data, 76, 0);
+	LSET(data, 84, SMB_MODE_NO_CHANGE);
+	LSET(data, 92, 0);
+
+	if (attr->ia_valid & ATTR_SIZE) {
+		LSET(data, 0, attr->ia_size);
+		LSET(data, 8, 0); /* can't set anyway */
+	}
+
+	/*
+	 * FIXME: check the conversion function it the correct one
+	 *
+	 * we can't set ctime but we might as well pass this to the server
+	 * and let it ignore it.
+	 */
+	if (attr->ia_valid & ATTR_CTIME) {
+		nttime = smb_unixutc2ntutc(attr->ia_ctime);
+		LSET(data, 16, nttime);
+	}
+	if (attr->ia_valid & ATTR_ATIME) {
+		nttime = smb_unixutc2ntutc(attr->ia_atime);
+		LSET(data, 24, nttime);
+	}
+	if (attr->ia_valid & ATTR_MTIME) {
+		nttime = smb_unixutc2ntutc(attr->ia_mtime);
+		LSET(data, 32, nttime);
+	}
+	
+	if (attr->ia_valid & ATTR_UID) {
+		LSET(data, 40, attr->ia_uid);
+	}
+	if (attr->ia_valid & ATTR_GID) {
+		LSET(data, 48, attr->ia_gid); 
+	}
+	
+	if (attr->ia_valid & ATTR_MODE) {
+		LSET(data, 84, attr->ia_mode);
+	}
+
+	req->rq_trans2_command = TRANSACT2_SETPATHINFO;
+	req->rq_ldata = 100;
+	req->rq_data  = data;
+	req->rq_lparm = p - param;
+	req->rq_parm  = param;
+	req->rq_flags = 0;
+	result = smb_add_request(req);
+
+out_free:
+	smb_rput(req);
+out:
+	return result;
+}
+
+
+/*
  * Set the modify and access timestamps for a file.
  *
  * Incredibly enough, in all of SMB there is no message to allow
@@ -2907,6 +3159,189 @@
 	return result;
 }
 
+int
+smb_proc_read_link(struct smb_sb_info *server, struct dentry *d,
+		   char *buffer, int len)
+{
+	char *p, *param;
+	int result;
+	struct smb_request *req;
+
+	DEBUG1("readlink of %s/%s\n", DENTRY_PATH(d));
+
+	result = -ENOMEM;
+	if (! (req = smb_alloc_request(server, PAGE_SIZE)))
+		goto out;
+	param = req->rq_buffer;
+
+	WSET(param, 0, SMB_QUERY_FILE_UNIX_LINK);
+	DSET(param, 2, 0);
+	result = smb_encode_path(server, param+6, SMB_MAXPATHLEN+1, d, NULL);
+	if (result < 0)
+		goto out_free;
+	p = param + 6 + result;
+
+	req->rq_trans2_command = TRANSACT2_QPATHINFO;
+	req->rq_ldata = 0;
+	req->rq_data  = NULL;
+	req->rq_lparm = p - param;
+	req->rq_parm  = param;
+	req->rq_flags = 0;
+	result = smb_add_request(req);
+	if (result < 0)
+		goto out_free;
+	DEBUG1("for %s: result=%d, rcls=%d, err=%d\n",
+		&param[6], result, server->rcls, server->err);
+
+	/* copy data up to the \0 or buffer length */
+	result = len;
+	if (req->rq_ldata < len)
+		result = req->rq_ldata;
+	strncpy(buffer, req->rq_data, result);
+
+out_free:
+	smb_rput(req);
+out:
+	return result;
+}
+
+
+/*
+ * Create a symlink object called dentry which points to oldpath.
+ * Samba does not permit dangling links but returns a suitable error message.
+ */
+int
+smb_proc_symlink(struct smb_sb_info *server, struct dentry *d,
+		 const char *oldpath)
+{
+	char *p, *param;
+	int result;
+	struct smb_request *req;
+
+	result = -ENOMEM;
+	if (! (req = smb_alloc_request(server, PAGE_SIZE)))
+		goto out;
+	param = req->rq_buffer;
+
+	WSET(param, 0, SMB_SET_FILE_UNIX_LINK);
+	DSET(param, 2, 0);
+	result = smb_encode_path(server, param + 6, SMB_MAXPATHLEN+1, d, NULL);
+	if (result < 0)
+		goto out_free;
+	p = param + 6 + result;
+
+	req->rq_trans2_command = TRANSACT2_SETPATHINFO;
+	req->rq_ldata = strlen(oldpath) + 1;
+	req->rq_data  = (char *) oldpath;
+	req->rq_lparm = p - param;
+	req->rq_parm  = param;
+	req->rq_flags = 0;
+	result = smb_add_request(req);
+	if (result < 0)
+		goto out_free;
+
+	DEBUG1("for %s: result=%d, rcls=%d, err=%d\n",
+		&param[6], result, server->rcls, server->err);
+	result = 0;
+
+out_free:
+	smb_rput(req);
+out:
+	return result;
+}
+
+/*
+ * Create a hard link object called new_dentry which points to dentry.
+ */
+int
+smb_proc_link(struct smb_sb_info *server, struct dentry *dentry,
+	      struct dentry *new_dentry)
+{
+	char *p, *param;
+	int result;
+	struct smb_request *req;
+
+	result = -ENOMEM;
+	if (! (req = smb_alloc_request(server, PAGE_SIZE)))
+		goto out;
+	param = req->rq_buffer;
+
+	WSET(param, 0, SMB_SET_FILE_UNIX_HLINK);
+	DSET(param, 2, 0);
+	result = smb_encode_path(server, param + 6, SMB_MAXPATHLEN+1,
+				 new_dentry, NULL);
+	if (result < 0)
+		goto out_free;
+	p = param + 6 + result;
+
+	/* Grr, pointless separation of parameters and data ... */
+	req->rq_data = p;
+	req->rq_ldata = smb_encode_path(server, p, SMB_MAXPATHLEN+1,
+					dentry, NULL);
+
+	req->rq_trans2_command = TRANSACT2_SETPATHINFO;
+	req->rq_lparm = p - param;
+	req->rq_parm  = param;
+	req->rq_flags = 0;
+	result = smb_add_request(req);
+	if (result < 0)
+		goto out_free;
+
+	DEBUG1("for %s: result=%d, rcls=%d, err=%d\n",
+	       &param[6], result, server->rcls, server->err);
+	result = 0;
+
+out_free:
+	smb_rput(req);
+out:
+	return result;
+}
+
+int
+smb_proc_query_cifsunix(struct smb_sb_info *server)
+{
+	int result;
+	int major, minor;
+	u64 caps;
+	char param[2];
+	struct smb_request *req;
+
+	result = -ENOMEM;
+	if (! (req = smb_alloc_request(server, 100)))
+		goto out;
+
+	WSET(param, 0, SMB_QUERY_CIFS_UNIX_INFO);
+
+	req->rq_trans2_command = TRANSACT2_QFSINFO;
+	req->rq_ldata = 0;
+	req->rq_data  = NULL;
+	req->rq_lparm = 2;
+	req->rq_parm  = param;
+	req->rq_flags = 0;
+	result = smb_add_request(req);
+	if (result < 0)
+		goto out_free;
+
+	if (req->rq_ldata < 12) {
+		PARANOIA("Not enough data\n");
+		goto out_free;
+	}
+	major = WVAL(req->rq_data, 0);
+	minor = WVAL(req->rq_data, 2);
+
+	DEBUG1("Server implements CIFS Extensions for UNIX systems v%d.%d\n",
+	       major, minor);
+	/* FIXME: verify that we are ok with this major/minor? */
+
+	caps = LVAL(req->rq_data, 4);
+	DEBUG1("Server capabilities 0x%016llx\n", caps);
+
+out_free:
+	smb_rput(req);
+out:
+	return result;
+}
+
 
 static void
 install_ops(struct smb_ops *dst, struct smb_ops *src)
@@ -2951,5 +3386,17 @@
 	.write		= smb_proc_writeX,
 	.readdir	= smb_proc_readdir_long,
 	.getattr	= smb_proc_getattr_trans2_all,
+	.truncate	= smb_proc_trunc64,
+};
+
+/* Samba w/ unix extensions. Others? */
+static struct smb_ops smb_ops_unix =
+{
+	.read		= smb_proc_readX,
+	.write		= smb_proc_writeX,
+	.readdir	= smb_proc_readdir_long,
+	.getattr	= smb_proc_getattr_unix,
+	/* FIXME: core/ext/time setattr needs to be cleaned up! */
+	/* .setattr	= smb_proc_setattr_unix, */
 	.truncate	= smb_proc_trunc64,
 };
diff -Nru a/fs/smbfs/proto.h b/fs/smbfs/proto.h
--- a/fs/smbfs/proto.h	Tue Oct  1 00:08:17 2002
+++ b/fs/smbfs/proto.h	Tue Oct  1 00:08:17 2002
@@ -1,5 +1,5 @@
 /*
- *  Autogenerated with cproto on:  Fri Jul 12 22:15:26 CEST 2002
+ *  Autogenerated with cproto on:  Sun Sep 29 21:48:59 CEST 2002
  */
 
 struct smb_request;
@@ -22,13 +22,20 @@
 extern int smb_proc_unlink(struct dentry *dentry);
 extern int smb_proc_flush(struct smb_sb_info *server, __u16 fileid);
 extern void smb_init_root_dirent(struct smb_sb_info *server, struct smb_fattr *fattr);
+extern void smb_decode_unix_basic(struct smb_fattr *fattr, char *p);
 extern int smb_proc_getattr(struct dentry *dir, struct smb_fattr *fattr);
 extern int smb_proc_setattr(struct dentry *dir, struct smb_fattr *fattr);
+extern int smb_proc_setattr_unix(struct dentry *d, struct iattr *attr, int major, int minor);
 extern int smb_proc_settime(struct dentry *dentry, struct smb_fattr *fattr);
 extern int smb_proc_dskattr(struct super_block *sb, struct statfs *attr);
+extern int smb_proc_read_link(struct smb_sb_info *server, struct dentry *d, char *buffer, int len);
+extern int smb_proc_symlink(struct smb_sb_info *server, struct dentry *d, const char *oldpath);
+extern int smb_proc_link(struct smb_sb_info *server, struct dentry *dentry, struct dentry *new_dentry);
+extern int smb_proc_query_cifsunix(struct smb_sb_info *server);
 /* dir.c */
 extern struct file_operations smb_dir_operations;
 extern struct inode_operations smb_dir_inode_operations;
+extern struct inode_operations smb_dir_inode_operations_unix;
 extern void smb_new_dentry(struct dentry *dentry);
 extern void smb_renew_times(struct dentry *dentry);
 /* cache.c */
@@ -76,3 +83,8 @@
 extern int smb_request_send_req(struct smb_request *req);
 extern int smb_request_send_server(struct smb_sb_info *server);
 extern int smb_request_recv(struct smb_sb_info *server);
+/* symlink.c */
+extern int smb_read_link(struct dentry *dentry, char *buffer, int len);
+extern int smb_symlink(struct inode *inode, struct dentry *dentry, const char *oldname);
+extern int smb_follow_link(struct dentry *dentry, struct nameidata *nd);
+extern struct inode_operations smb_link_inode_operations;
diff -Nru a/fs/smbfs/request.c b/fs/smbfs/request.c
--- a/fs/smbfs/request.c	Tue Oct  1 00:08:21 2002
+++ b/fs/smbfs/request.c	Tue Oct  1 00:08:21 2002
@@ -332,8 +332,8 @@
 
 	smbiod_wake_up();
 
-	/* FIXME: replace with a timeout-able wake_event_interruptible */
-	timeleft = interruptible_sleep_on_timeout(&req->rq_wait, 30*HZ);
+	timeleft = wait_event_interruptible_timeout(req->rq_wait,
+				    req->rq_flags & SMB_REQ_RECEIVED, 30*HZ);
 	if (!timeleft || signal_pending(current)) {
 		/*
 		 * On timeout or on interrupt we want to try and remove the
@@ -346,7 +346,7 @@
 		}
 		smb_unlock_server(server);
 	}
-		
+
 	if (!timeleft) {
 		PARANOIA("request [%p, mid=%d] timed out!\n",
 			 req, req->rq_mid);
@@ -777,7 +777,7 @@
 
 	/*
 	 * Response completely read. Drop any extra bytes sent by the server.
-	 * (Yes, servers sometimes add extra bytes to requests)
+	 * (Yes, servers sometimes add extra bytes to responses)
 	 */
 	VERBOSE("smb_len: %d   smb_read: %d\n",
 		server->smb_len, server->smb_read);
diff -Nru a/fs/smbfs/smbiod.c b/fs/smbfs/smbiod.c
--- a/fs/smbfs/smbiod.c	Tue Oct  1 00:08:18 2002
+++ b/fs/smbfs/smbiod.c	Tue Oct  1 00:08:18 2002
@@ -18,6 +18,7 @@
 #include <linux/file.h>
 #include <linux/dcache.h>
 #include <linux/smp_lock.h>
+#include <linux/module.h>
 #include <net/ip.h>
 
 #include <linux/smb_fs.h>
@@ -31,7 +32,14 @@
 #include "request.h"
 #include "proto.h"
 
-static int smbiod_pid = -1;
+enum smbiod_state {
+	SMBIOD_DEAD,
+	SMBIOD_STARTING,
+	SMBIOD_RUNNING,
+};
+
+static enum smbiod_state smbiod_state = SMBIOD_DEAD;
+static pid_t smbiod_pid;
 static DECLARE_WAIT_QUEUE_HEAD(smbiod_wait);
 static LIST_HEAD(smb_servers);
 static spinlock_t servers_lock = SPIN_LOCK_UNLOCKED;
@@ -41,14 +49,13 @@
 
 static int smbiod(void *);
 static void smbiod_start(void);
-static void smbiod_stop(void);
 
 /*
  * called when there's work for us to do
  */
 void smbiod_wake_up()
 {
-	if (smbiod_pid == -1)
+	if (smbiod_state == SMBIOD_DEAD)
 		return;
 	set_bit(SMBIOD_DATA_READY, &smbiod_flags);
 	wake_up_interruptible(&smbiod_wait);
@@ -59,18 +66,16 @@
  */
 static void smbiod_start()
 {
-	if (smbiod_pid != -1)
+	pid_t pid;
+	if (smbiod_state != SMBIOD_DEAD)
 		return;
-	smbiod_pid = kernel_thread(smbiod, NULL, 0);
-}
+	smbiod_state = SMBIOD_STARTING;
+	spin_unlock(&servers_lock);
+	pid = kernel_thread(smbiod, NULL, 0);
 
-/*
- * stop smbiod if there are no open connections
- */
-static void smbiod_stop()
-{
-	if (smbiod_pid != -1 && list_empty(&smb_servers))
-		kill_proc(smbiod_pid, SIGKILL, 1);
+	spin_lock(&servers_lock);
+	smbiod_state = SMBIOD_RUNNING;
+	smbiod_pid = pid;
 }
 
 /*
@@ -86,19 +91,18 @@
 }
 
 /*
- * unregister a server & stop smbiod if necessary
+ * Unregister a server
+ * Must be called with the server lock held.
  */
 void smbiod_unregister_server(struct smb_sb_info *server)
 {
 	spin_lock(&servers_lock);
 	list_del_init(&server->entry);
 	VERBOSE("%p\n", server);
-	smbiod_stop();
 	spin_unlock(&servers_lock);
 
-	smb_lock_server(server);
+	smbiod_wake_up();
 	smbiod_flush(server);
-	smb_unlock_server(server);
 }
 
 void smbiod_flush(struct smb_sb_info *server)
@@ -277,12 +281,13 @@
  */
 static int smbiod(void *unused)
 {
+	MOD_INC_USE_COUNT;
 	daemonize();
 
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	siginitsetinv(&current->blocked, sigmask(SIGKILL));
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	strcpy(current->comm, "smbiod");
 
@@ -295,32 +300,40 @@
 		/* FIXME: Use poll? */
 		wait_event_interruptible(smbiod_wait,
 			 test_bit(SMBIOD_DATA_READY, &smbiod_flags));
-		if (signal_pending(current))
+		if (signal_pending(current)) {
+			spin_lock(&servers_lock);
+			smbiod_state = SMBIOD_DEAD;
+			spin_unlock(&servers_lock);
 			break;
+		}
 
 		clear_bit(SMBIOD_DATA_READY, &smbiod_flags);
 
-		/*
-		 * We must hold the servers_lock while looking for servers
-		 * to check or else we have a race with put_super.
-		 */
 		spin_lock(&servers_lock);
+		if (list_empty(&smb_servers)) {
+			smbiod_state = SMBIOD_DEAD;
+			spin_unlock(&servers_lock);
+			break;
+		}
+
 		list_for_each_safe(pos, n, &smb_servers) {
 			server = list_entry(pos, struct smb_sb_info, entry);
 			VERBOSE("checking server %p\n", server);
-			smb_lock_server(server);
-			spin_unlock(&servers_lock);
 
-			smbiod_doio(server);
+			if (server->state == CONN_VALID) {
+				spin_unlock(&servers_lock);
 
-			smb_unlock_server(server);
-			spin_lock(&servers_lock);
+				smb_lock_server(server);
+				smbiod_doio(server);
+				smb_unlock_server(server);
+
+				spin_lock(&servers_lock);
+			}
 		}
 		spin_unlock(&servers_lock);
 	}
 
 	VERBOSE("SMB Kernel thread exiting (%d) ...\n", current->pid);
-	smbiod_pid = -1;
-
+	MOD_DEC_USE_COUNT;
 	return 0;
 }
diff -Nru a/fs/smbfs/symlink.c b/fs/smbfs/symlink.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/smbfs/symlink.c	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,68 @@
+/*
+ *  symlink.c
+ *
+ *  Copyright (C) 2002 by John Newbigin
+ *
+ *  Please add a note about your changes to smbfs in the ChangeLog file.
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/fcntl.h>
+#include <linux/stat.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#include <linux/smp_lock.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#include <linux/smbno.h>
+#include <linux/smb_fs.h>
+
+#include "smb_debug.h"
+#include "proto.h"
+
+int smb_read_link(struct dentry *dentry, char *buffer, int len)
+{
+	char link[256];		/* FIXME: pain ... */
+	int r;
+	DEBUG1("read link buffer len = %d\n", len);
+
+	r = smb_proc_read_link(server_from_dentry(dentry), dentry, link,
+			       sizeof(link) - 1);
+	if (r < 0)
+		return -ENOENT;
+	return vfs_readlink(dentry, buffer, len, link);
+}
+
+int smb_symlink(struct inode *inode, struct dentry *dentry, const char *oldname)
+{
+	DEBUG1("create symlink %s -> %s/%s\n", oldname, DENTRY_PATH(dentry));
+
+	return smb_proc_symlink(server_from_dentry(dentry), dentry, oldname);
+}
+
+int smb_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+	char link[256];		/* FIXME: pain ... */
+	int len;
+	DEBUG1("followlink of %s/%s\n", DENTRY_PATH(dentry));
+
+	len = smb_proc_read_link(server_from_dentry(dentry), dentry, link,
+				 sizeof(link) - 1);
+	if(len < 0)
+		return -ENOENT;
+
+	link[len] = 0;
+	return vfs_follow_link(nd, link);
+}
+
+
+struct inode_operations smb_link_inode_operations =
+{
+	.readlink	smb_read_link,
+	.follow_link	smb_follow_link,
+};
diff -Nru a/fs/ufs/dir.c b/fs/ufs/dir.c
--- a/fs/ufs/dir.c	Tue Oct  1 00:08:16 2002
+++ b/fs/ufs/dir.c	Tue Oct  1 00:08:16 2002
@@ -623,7 +623,7 @@
 }
 
 struct file_operations ufs_dir_operations = {
-	read:		generic_read_dir,
-	readdir:	ufs_readdir,
-	fsync:		file_fsync,
+	.read		= generic_read_dir,
+	.readdir	= ufs_readdir,
+	.fsync		= file_fsync,
 };
diff -Nru a/fs/ufs/file.c b/fs/ufs/file.c
--- a/fs/ufs/file.c	Tue Oct  1 00:08:16 2002
+++ b/fs/ufs/file.c	Tue Oct  1 00:08:16 2002
@@ -42,14 +42,14 @@
  */
  
 struct file_operations ufs_file_operations = {
-	llseek:		generic_file_llseek,
-	read:		generic_file_read,
-	write:		generic_file_write,
-	mmap:		generic_file_mmap,
-	open:           generic_file_open,
-	sendfile:	generic_file_sendfile,
+	.llseek		= generic_file_llseek,
+	.read		= generic_file_read,
+	.write		= generic_file_write,
+	.mmap		= generic_file_mmap,
+	.open           = generic_file_open,
+	.sendfile	= generic_file_sendfile,
 };
 
 struct inode_operations ufs_file_inode_operations = {
-	truncate:	ufs_truncate,
+	.truncate	= ufs_truncate,
 };
diff -Nru a/fs/ufs/inode.c b/fs/ufs/inode.c
--- a/fs/ufs/inode.c	Tue Oct  1 00:08:15 2002
+++ b/fs/ufs/inode.c	Tue Oct  1 00:08:15 2002
@@ -462,12 +462,12 @@
 	return generic_block_bmap(mapping,block,ufs_getfrag_block);
 }
 struct address_space_operations ufs_aops = {
-	readpage: ufs_readpage,
-	writepage: ufs_writepage,
-	sync_page: block_sync_page,
-	prepare_write: ufs_prepare_write,
-	commit_write: generic_commit_write,
-	bmap: ufs_bmap
+	.readpage = ufs_readpage,
+	.writepage = ufs_writepage,
+	.sync_page = block_sync_page,
+	.prepare_write = ufs_prepare_write,
+	.commit_write = generic_commit_write,
+	.bmap = ufs_bmap
 };
 
 void ufs_read_inode (struct inode * inode)
diff -Nru a/fs/ufs/namei.c b/fs/ufs/namei.c
--- a/fs/ufs/namei.c	Tue Oct  1 00:08:21 2002
+++ b/fs/ufs/namei.c	Tue Oct  1 00:08:21 2002
@@ -350,13 +350,13 @@
 }
 
 struct inode_operations ufs_dir_inode_operations = {
-	create:		ufs_create,
-	lookup:		ufs_lookup,
-	link:		ufs_link,
-	unlink:		ufs_unlink,
-	symlink:	ufs_symlink,
-	mkdir:		ufs_mkdir,
-	rmdir:		ufs_rmdir,
-	mknod:		ufs_mknod,
-	rename:		ufs_rename,
+	.create		= ufs_create,
+	.lookup		= ufs_lookup,
+	.link		= ufs_link,
+	.unlink		= ufs_unlink,
+	.symlink	= ufs_symlink,
+	.mkdir		= ufs_mkdir,
+	.rmdir		= ufs_rmdir,
+	.mknod		= ufs_mknod,
+	.rename		= ufs_rename,
 };
diff -Nru a/fs/ufs/super.c b/fs/ufs/super.c
--- a/fs/ufs/super.c	Tue Oct  1 00:08:13 2002
+++ b/fs/ufs/super.c	Tue Oct  1 00:08:13 2002
@@ -1041,15 +1041,15 @@
 }
 
 static struct super_operations ufs_super_ops = {
-	alloc_inode:	ufs_alloc_inode,
-	destroy_inode:	ufs_destroy_inode,
-	read_inode:	ufs_read_inode,
-	write_inode:	ufs_write_inode,
-	delete_inode:	ufs_delete_inode,
-	put_super:	ufs_put_super,
-	write_super:	ufs_write_super,
-	statfs:		ufs_statfs,
-	remount_fs:	ufs_remount,
+	.alloc_inode	= ufs_alloc_inode,
+	.destroy_inode	= ufs_destroy_inode,
+	.read_inode	= ufs_read_inode,
+	.write_inode	= ufs_write_inode,
+	.delete_inode	= ufs_delete_inode,
+	.put_super	= ufs_put_super,
+	.write_super	= ufs_write_super,
+	.statfs		= ufs_statfs,
+	.remount_fs	= ufs_remount,
 };
 
 static struct super_block *ufs_get_sb(struct file_system_type *fs_type,
@@ -1059,11 +1059,11 @@
 }
 
 static struct file_system_type ufs_fs_type = {
-	owner:		THIS_MODULE,
-	name:		"ufs",
-	get_sb:		ufs_get_sb,
-	kill_sb:	kill_block_super,
-	fs_flags:	FS_REQUIRES_DEV,
+	.owner		= THIS_MODULE,
+	.name		= "ufs",
+	.get_sb		= ufs_get_sb,
+	.kill_sb	= kill_block_super,
+	.fs_flags	= FS_REQUIRES_DEV,
 };
 
 static int __init init_ufs_fs(void)
diff -Nru a/fs/ufs/symlink.c b/fs/ufs/symlink.c
--- a/fs/ufs/symlink.c	Tue Oct  1 00:08:16 2002
+++ b/fs/ufs/symlink.c	Tue Oct  1 00:08:16 2002
@@ -41,6 +41,6 @@
 }
 
 struct inode_operations ufs_fast_symlink_inode_operations = {
-	readlink:	ufs_readlink,
-	follow_link:	ufs_follow_link,
+	.readlink	= ufs_readlink,
+	.follow_link	= ufs_follow_link,
 };
diff -Nru a/fs/umsdos/Makefile b/fs/umsdos/Makefile
--- a/fs/umsdos/Makefile	Tue Oct  1 00:08:16 2002
+++ b/fs/umsdos/Makefile	Tue Oct  1 00:08:16 2002
@@ -8,9 +8,6 @@
 
 include $(TOPDIR)/Rules.make
 
-clean:
-	rm -f core *.o *.a *.s
-
 p:
 	proto *.c >/usr/include/linux/umsdos_fs.p
 
diff -Nru a/fs/vfat/namei.c b/fs/vfat/namei.c
--- a/fs/vfat/namei.c	Tue Oct  1 00:08:18 2002
+++ b/fs/vfat/namei.c	Tue Oct  1 00:08:18 2002
@@ -890,7 +890,6 @@
 	struct msdos_dir_entry *dummy_de;
 	struct buffer_head *dummy_bh;
 	int dummy_ino;
-	loff_t dummy;
 
 	dir_slots = (struct msdos_dir_slot *)
 	       kmalloc(sizeof(struct msdos_dir_slot) * MSDOS_SLOTS, GFP_KERNEL);
@@ -900,15 +899,6 @@
 	len = qname->len;
 	while (len && qname->name[len-1] == '.')
 		len--;
-	res = fat_search_long(dir, qname->name, len,
-			      (MSDOS_SB(sb)->options.name_check != 's')
-			      || !MSDOS_SB(sb)->options.posixfs,
-			      &dummy, &dummy);
-	if (res > 0) /* found */
-		res = -EEXIST;
-	if (res)
-		goto cleanup;
-
 	res = vfat_build_slots(dir, qname->name, len,
 			       dir_slots, &slots, is_dir);
 	if (res < 0)
diff -Nru a/fs/xfs/pagebuf/page_buf.c b/fs/xfs/pagebuf/page_buf.c
--- a/fs/xfs/pagebuf/page_buf.c	Tue Oct  1 00:08:15 2002
+++ b/fs/xfs/pagebuf/page_buf.c	Tue Oct  1 00:08:15 2002
@@ -1684,10 +1684,10 @@
 	daemonize();
 
 	/* Avoid signals */
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	sigfillset(&current->blocked);
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	/* Migrate to the right CPU */
 	set_cpus_allowed(current, 1UL << cpu);
@@ -1752,10 +1752,10 @@
 	daemonize();
 
 	/* Avoid signals */
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	sigfillset(&current->blocked);
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	strcpy(current->comm, "pagebufd");
 	current->flags |= PF_MEMALLOC;
diff -Nru a/include/asm-alpha/mmzone.h b/include/asm-alpha/mmzone.h
--- a/include/asm-alpha/mmzone.h	Tue Oct  1 00:08:20 2002
+++ b/include/asm-alpha/mmzone.h	Tue Oct  1 00:08:20 2002
@@ -107,15 +107,6 @@
 #ifdef CONFIG_NUMA_SCHED
 #define NODE_SCHEDULE_DATA(nid)	(&((PLAT_NODE_DATA(nid))->schedule_data))
 #endif
-
-#ifdef CONFIG_ALPHA_WILDFIRE
-/* With wildfire assume 4 CPUs per node */
-#define cputonode(cpu)	((cpu) >> 2)
-#else
-#define cputonode(cpu)	0
-#endif /* CONFIG_ALPHA_WILDFIRE */
-
-#define numa_node_id()	cputonode(smp_processor_id())
 #endif /* CONFIG_NUMA */
 
 #endif /* CONFIG_DISCONTIGMEM */
diff -Nru a/include/asm-alpha/topology.h b/include/asm-alpha/topology.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-alpha/topology.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,20 @@
+#ifndef _ASM_ALPHA_TOPOLOGY_H
+#define _ASM_ALPHA_TOPOLOGY_H
+
+#ifdef CONFIG_NUMA
+#ifdef CONFIG_ALPHA_WILDFIRE
+/* With wildfire assume 4 CPUs per node */
+#define __cpu_to_node(cpu)		((cpu) >> 2)
+#endif /* CONFIG_ALPHA_WILDFIRE */
+#endif /* CONFIG_NUMA */
+
+#if !defined(CONFIG_NUMA) || !defined(CONFIG_ALPHA_WILDFIRE)
+#define __cpu_to_node(cpu)		(0)
+#define __memblk_to_node(memblk)	(0)
+#define __parent_node(nid)		(0)
+#define __node_to_first_cpu(node)	(0)
+#define __node_to_cpu_mask(node)	(cpu_online_map)
+#define __node_to_memblk(node)		(0)
+#endif /* !CONFIG_NUMA || !CONFIG_ALPHA_WILDFIRE */
+
+#endif /* _ASM_ALPHA_TOPOLOGY_H */
diff -Nru a/include/asm-arm/arch-adifcc/memory.h b/include/asm-arm/arch-adifcc/memory.h
--- a/include/asm-arm/arch-adifcc/memory.h	Tue Oct  1 00:08:15 2002
+++ b/include/asm-arm/arch-adifcc/memory.h	Tue Oct  1 00:08:15 2002
@@ -52,6 +52,4 @@
 #define __virt_to_bus(x)	 __virt_to_phys(x)
 #define __bus_to_virt(x)	 __phys_to_virt(x)
 
-#define	PHYS_TO_NID(x)		0
-
 #endif
diff -Nru a/include/asm-arm/arch-anakin/keyboard.h b/include/asm-arm/arch-anakin/keyboard.h
--- a/include/asm-arm/arch-anakin/keyboard.h	Tue Oct  1 00:08:20 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,15 +0,0 @@
-/*
- *  linux/include/asm-arm/arch-anakin/keyboard.h
- *
- *  Copyright (C) 2001 Aleph One Ltd. for Acunia N.V.
- *
- * 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.
- *
- *  Changelog:
- *   11-Apr-2001 TTC	Created
- */
-#define kbd_init_hw()		do { } while (0)
-#define kbd_enable_irq()	do { } while (0)
-#define kbd_disable_irq()	do { } while (0)
diff -Nru a/include/asm-arm/arch-anakin/memory.h b/include/asm-arm/arch-anakin/memory.h
--- a/include/asm-arm/arch-anakin/memory.h	Tue Oct  1 00:08:20 2002
+++ b/include/asm-arm/arch-anakin/memory.h	Tue Oct  1 00:08:20 2002
@@ -31,6 +31,4 @@
 #define __virt_to_bus__is_a_macro
 #define __bus_to_virt__is_a_macro
 
-#define PHYS_TO_NID(addr)	(0)
-
 #endif
diff -Nru a/include/asm-arm/arch-arc/memory.h b/include/asm-arm/arch-arc/memory.h
--- a/include/asm-arm/arch-arc/memory.h	Tue Oct  1 00:08:18 2002
+++ b/include/asm-arm/arch-arc/memory.h	Tue Oct  1 00:08:18 2002
@@ -50,6 +50,4 @@
 #define __bus_to_virt__is_a_macro
 #define __bus_to_virt(x)	(x)
 
-#define PHYS_TO_NID(addr)	(0)
-
 #endif
diff -Nru a/include/asm-arm/arch-cl7500/memory.h b/include/asm-arm/arch-cl7500/memory.h
--- a/include/asm-arm/arch-cl7500/memory.h	Tue Oct  1 00:08:17 2002
+++ b/include/asm-arm/arch-cl7500/memory.h	Tue Oct  1 00:08:17 2002
@@ -46,6 +46,4 @@
 #define __bus_to_virt__is_a_macro
 #define __bus_to_virt(x) __phys_to_virt(x)
 
-#define PHYS_TO_NID(addr)	(0)
-
 #endif
diff -Nru a/include/asm-arm/arch-clps711x/hardware.h b/include/asm-arm/arch-clps711x/hardware.h
--- a/include/asm-arm/arch-clps711x/hardware.h	Tue Oct  1 00:08:17 2002
+++ b/include/asm-arm/arch-clps711x/hardware.h	Tue Oct  1 00:08:17 2002
@@ -65,7 +65,6 @@
 #define EP7212_BASE		CLPS7111_VIRT_BASE
 #include <asm/hardware/ep7212.h>
 
-
 #endif
 
 #define SYSPLD_VIRT_BASE	0xfe000000
@@ -175,5 +174,65 @@
 #define EDB_PD3_LCDBL		(1<<3)
 
 
-#endif
+#if defined (CONFIG_ARCH_CEIVA)
+
+#define  CEIVA_VIRT_BASE	CLPS7111_VIRT_BASE
+#define  CEIVA_BASE		CLPS7111_VIRT_BASE
+
+#include <asm/hardware/clps7111.h>
+#include <asm/hardware/ep7212.h>
+
+
+/*
+ * The two flash banks are wired to chip selects 0 and 1. This is the mapping
+ * for them.
+ *
+ * nCS0 and nCS1 are at 0x70000000 and 0x60000000, respectively, when running
+ * in jumpered boot mode.
+ */
+#define CEIVA_PHYS_FLASH1	CS0_PHYS_BASE	/* physical */
+#define CEIVA_PHYS_FLASH2	CS1_PHYS_BASE	/* physical */
+
+#define CEIVA_VIRT_FLASH1	(0xfa000000)	/* virtual */
+#define CEIVA_VIRT_FLASH2	(0xfb000000)	/* virtual */
+
+#define CEIVA_FLASH_SIZE        0x100000
+#define CEIVA_FLASH_WIDTH       2
+
+#define SRAM_START       0x60000000
+#define SRAM_SIZE        0xc000
+#define SRAM_WIDTH       4
+
+#define BOOTROM_START    0x70000000
+#define BOOTROM_SIZE     0x80
+#define BOOTROM_WIDTH    4
 
+/*
+ * SED1355 LCD controller
+ */
+#define CEIVA_PHYS_SED1355	CS2_PHYS_BASE
+#define CEIVA_VIRT_SED1355	(0xfc000000)
+
+/*
+ * Relevant bits in port D, which controls power to the various parts of
+ * the LCD on the Ceiva Photo Max, and reset to the LCD controller.
+ */
+
+// Reset line to SED1355 (must be high to operate)
+#define CEIVA_PD1_LCDRST	(1<<1)
+// LCD panel enable (set to one, to enable LCD)
+#define CEIVA_PD4_LCDEN		(1<<4)
+// Backlight (set to one, to turn on backlight
+#define CEIVA_PD5_LCDBL		(1<<5)
+
+/*
+ * Relevant bits in port B, which report the status of the buttons.
+ */
+
+// White button
+#define CEIVA_PB4_WHT_BTN	(1<<4)
+// Black button
+#define CEIVA_PB0_BLK_BTN	(1<<0)
+#endif // #if defined (CONFIG_ARCH_CEIVA)
+
+#endif
diff -Nru a/include/asm-arm/arch-clps711x/memory.h b/include/asm-arm/arch-clps711x/memory.h
--- a/include/asm-arm/arch-clps711x/memory.h	Tue Oct  1 00:08:15 2002
+++ b/include/asm-arm/arch-clps711x/memory.h	Tue Oct  1 00:08:15 2002
@@ -90,8 +90,6 @@
  * memory bank.  For those systems, simply undefine CONFIG_DISCONTIGMEM.
  */
 
-#ifdef CONFIG_ARCH_EDB7211
-
 #ifdef CONFIG_DISCONTIGMEM
 /*
  * Because of the wide memory address space between physical RAM banks on the 
@@ -154,12 +152,6 @@
 #define NODE_MAX_MEM_SIZE	(1<<NODE_MAX_MEM_SHIFT)
 
 #endif /* CONFIG_DISCONTIGMEM */
-
-#endif	/* CONFIG_ARCH_EDB7211 */
-
-#ifndef PFN_TO_NID
-#define PFN_TO_NID(pfn)		(0)
-#endif
 
 #endif
 
diff -Nru a/include/asm-arm/arch-ebsa110/memory.h b/include/asm-arm/arch-ebsa110/memory.h
--- a/include/asm-arm/arch-ebsa110/memory.h	Tue Oct  1 00:08:16 2002
+++ b/include/asm-arm/arch-ebsa110/memory.h	Tue Oct  1 00:08:16 2002
@@ -48,6 +48,4 @@
 #define __bus_to_virt__is_a_macro
 #define __bus_to_virt(x)	(x)
 
-#define PHYS_TO_NID(addr)	(0)
-
 #endif
diff -Nru a/include/asm-arm/arch-ebsa285/keyboard.h b/include/asm-arm/arch-ebsa285/keyboard.h
--- a/include/asm-arm/arch-ebsa285/keyboard.h	Tue Oct  1 00:08:16 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,9 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa285/keyboard.h
- *
- * Keyboard driver definitions for EBSA285 architecture
- *
- * Copyright (C) 1998-2001 Russell King
- * (C) 1998 Phil Blundell
- */
-#define kbd_init_hw()		do { } while (0)
diff -Nru a/include/asm-arm/arch-ebsa285/memory.h b/include/asm-arm/arch-ebsa285/memory.h
--- a/include/asm-arm/arch-ebsa285/memory.h	Tue Oct  1 00:08:18 2002
+++ b/include/asm-arm/arch-ebsa285/memory.h	Tue Oct  1 00:08:18 2002
@@ -80,6 +80,4 @@
 #define __phys_to_virt__is_a_macro
 #define __phys_to_virt(ppage) ((unsigned long)(ppage) + PAGE_OFFSET)
 
-#define PHYS_TO_NID(addr)	(0)
-
 #endif
diff -Nru a/include/asm-arm/arch-epxa10db/memory.h b/include/asm-arm/arch-epxa10db/memory.h
--- a/include/asm-arm/arch-epxa10db/memory.h	Tue Oct  1 00:08:18 2002
+++ b/include/asm-arm/arch-epxa10db/memory.h	Tue Oct  1 00:08:18 2002
@@ -38,8 +38,6 @@
 #define PAGE_OFFSET	(0xc0000000UL)
 #define PHYS_OFFSET	(0x00000000UL)
 
-#define PHYS_TO_NID(addr)    (0)
-
 /*
  * On epxa10, the dram is contiguous
  */
diff -Nru a/include/asm-arm/arch-integrator/keyboard.h b/include/asm-arm/arch-integrator/keyboard.h
--- a/include/asm-arm/arch-integrator/keyboard.h	Tue Oct  1 00:08:16 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,22 +0,0 @@
-/*
- *  linux/include/asm-arm/arch-integrator/keyboard.h
- *
- *  Copyright (C) 2000-2001 Deep Blue Solutions Ltd.
- *
- * 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
- *
- *  Keyboard driver definitions for the Integrator architecture
- *  Now using the input subsystem...
- */
-#define kbd_init_hw()		do { } while (0)
diff -Nru a/include/asm-arm/arch-integrator/memory.h b/include/asm-arm/arch-integrator/memory.h
--- a/include/asm-arm/arch-integrator/memory.h	Tue Oct  1 00:08:16 2002
+++ b/include/asm-arm/arch-integrator/memory.h	Tue Oct  1 00:08:16 2002
@@ -58,6 +58,4 @@
 #define __bus_to_virt__is_a_macro
 #define __bus_to_virt(x)	(x - INTEGRATOR_HDR0_SDRAM_BASE + PAGE_OFFSET)
 
-#define PHYS_TO_NID(addr)	(0)
-
 #endif
diff -Nru a/include/asm-arm/arch-iop310/memory.h b/include/asm-arm/arch-iop310/memory.h
--- a/include/asm-arm/arch-iop310/memory.h	Tue Oct  1 00:08:19 2002
+++ b/include/asm-arm/arch-iop310/memory.h	Tue Oct  1 00:08:19 2002
@@ -49,8 +49,6 @@
 #define __virt_to_bus(x)	(((__virt_to_phys(x)) & ~(*IOP310_SIATVR)) | ((*IOP310_SIABAR) & 0xfffffff0))
 #define __bus_to_virt(x)    (__phys_to_virt(((x) & ~(*IOP310_SIALR)) | ( *IOP310_SIATVR)))
 
-#define PHYS_TO_NID(x)		0
-
 /* boot mem allocate global pointer for MU circular queues QBAR */
 #ifdef CONFIG_IOP310_MU
 extern void *mu_mem;
diff -Nru a/include/asm-arm/arch-l7200/memory.h b/include/asm-arm/arch-l7200/memory.h
--- a/include/asm-arm/arch-l7200/memory.h	Tue Oct  1 00:08:16 2002
+++ b/include/asm-arm/arch-l7200/memory.h	Tue Oct  1 00:08:16 2002
@@ -47,6 +47,4 @@
 #define __bus_to_virt__is_a_macro
 #define __bus_to_virt(x) __phys_to_virt(x)
 
-#define PHYS_TO_NID(addr)	(0)
-
 #endif
diff -Nru a/include/asm-arm/arch-nexuspci/keyboard.h b/include/asm-arm/arch-nexuspci/keyboard.h
--- a/include/asm-arm/arch-nexuspci/keyboard.h	Tue Oct  1 00:08:17 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,14 +0,0 @@
-/*
- * linux/include/asm-arm/arch-nexuspci/keyboard.h
- *
- * Driver definitions for PCI card dummy keyboard.
- *
- * Copyright (C) 1998-2001 Russell King
- * Copyright (C) 1998 Philip Blundell
- */
-
-#define NR_SCANCODES 128
-
-#define kbd_init_hw()		do { } while (0)
-#define kbd_disable_irq()	do { } while (0)
-#define kbd_enable_irq()	do { } while (0)
diff -Nru a/include/asm-arm/arch-nexuspci/memory.h b/include/asm-arm/arch-nexuspci/memory.h
--- a/include/asm-arm/arch-nexuspci/memory.h	Tue Oct  1 00:08:21 2002
+++ b/include/asm-arm/arch-nexuspci/memory.h	Tue Oct  1 00:08:21 2002
@@ -43,6 +43,4 @@
 #define __bus_to_virt__is_a_macro
 #define __bus_to_virt(x) ((unsigned long)(x) + PAGE_OFFSET - BUS_OFFSET)
 
-#define PHYS_TO_NID(addr)	(0)
-
 #endif
diff -Nru a/include/asm-arm/arch-pxa/idp.h b/include/asm-arm/arch-pxa/idp.h
--- a/include/asm-arm/arch-pxa/idp.h	Tue Oct  1 00:08:13 2002
+++ b/include/asm-arm/arch-pxa/idp.h	Tue Oct  1 00:08:13 2002
@@ -19,9 +19,10 @@
 
 /* comment out following if you have a rev01 board */
 #define PXA_IDP_REV02	1
-//#undef PXA_IDP_REV02
 
 #ifdef PXA_IDP_REV02
+//Use this as well for 0017-x004 and greater pcb's:
+#define PXA_IDP_REV04 1
 
 #define IDP_FLASH_PHYS		(PXA_CS0_PHYS)
 #define IDP_ALT_FLASH_PHYS	(PXA_CS1_PHYS)
@@ -38,6 +39,7 @@
 
 #define IDP_IDE_BASE		(0xf0000000)
 #define IDP_IDE_SIZE		(1*1024*1024)
+#define IDE_REG_STRIDE		4
 
 #define IDP_ETH_BASE		(IDP_IDE_BASE + IDP_IDE_SIZE)
 #define IDP_ETH_SIZE		(1*1024*1024)
@@ -111,6 +113,33 @@
  * Bit masks for various registers
  */
 
+// IDP_CPLD_PCCARD_PWR
+#define PCC0_PWR0	(1 << 0)
+#define PCC0_PWR1	(1 << 1)
+#define PCC0_PWR2	(1 << 2)
+#define PCC0_PWR3	(1 << 3)
+#define PCC1_PWR0	(1 << 4)
+#define PCC1_PWR1	(1 << 5)
+#define PCC1_PWR2	(1 << 6)
+#define PCC1_PWR3	(1 << 7)
+
+// IDP_CPLD_PCCARD_EN
+#define PCC0_RESET	(1 << 6)
+#define PCC1_RESET	(1 << 7)
+#define PCC0_ENABLE	(1 << 0)
+#define PCC1_ENABLE	(1 << 1)
+
+// IDP_CPLD_PCCARDx_STATUS
+#define _PCC_WRPROT	(1 << 7) // 7-4 read as low true
+#define _PCC_RESET	(1 << 6)
+#define _PCC_IRQ	(1 << 5)
+#define _PCC_INPACK	(1 << 4)
+#define PCC_BVD2	(1 << 3)
+#define PCC_BVD1	(1 << 2)
+#define PCC_VS2		(1 << 1)
+#define PCC_VS1		(1 << 0)
+
+#define PCC_DETECT(x)	(GPLR(7 + (x)) & GPIO_bit(7 + (x)))
 
 /*
  * Macros for LCD Driver
@@ -129,6 +158,32 @@
 
 #endif
 
+/* A listing of interrupts used by external hardware devices */
+
+#ifdef PXA_IDP_REV04
+#define TOUCH_PANEL_IRQ			IRQ_GPIO(5)
+#define IDE_IRQ				IRQ_GPIO(21)
+#else
+#define TOUCH_PANEL_IRQ			IRQ_GPIO(21)
+#define IDE_IRQ				IRQ_GPIO(5)
+#endif
+
+#define TOUCH_PANEL_IRQ_EDGE		IRQT_FALLING
+
+#define ETHERNET_IRQ			IRQ_GPIO(4)
+#define ETHERNET_IRQ_EDGE		IRQT_RISING
+
+#define IDE_IRQ_EDGE			IRQT_RISING
+
+#define PCMCIA_S0_CD_VALID		IRQ_GPIO(7)
+#define PCMCIA_S0_CD_VALID_EDGE		IRQT_BOTHEDGE
+
+#define PCMCIA_S1_CD_VALID		IRQ_GPIO(8)
+#define PCMCIA_S1_CD_VALID_EDGE		IRQT_BOTHEDGE
+
+#define PCMCIA_S0_RDYINT		IRQ_GPIO(19)
+#define PCMCIA_S1_RDYINT		IRQ_GPIO(22)
+
 
 /*
  * Macros for LED Driver
@@ -173,14 +228,6 @@
 	inputs = (IDP_CPLD_KB_ROW & 0x7f);\
 }
 
-/* A listing of interrupts used by external hardware devices */
-
-#define TOUCH_PANEL_IRQ			IRQ_GPIO(21)
-#define TOUCH_PANEL_IRQ_EGDE		GPIO_FALLING_EDGE
-
-#define ETHERNET_IRQ			IRQ_GPIO(4)
-#define ETHERNET_IRQ_EDGE		GPIO_RISING_EDGE
-
 #else
 
 /*
@@ -286,7 +333,7 @@
 
 #define WRITE_IDP_CPLD_LED_CONTROL(value, mask) \
 {\
-	idp_cpld_led_control_shadow = ((value & mask) | (idp_cpld_led_control_shadow & ~mask));\
+	idp_cpld_led_control_shadow = (((value & mask) | (idp_cpld_led_control_shadow & ~mask)));\
 	IDP_CPLD_LED_CONTROL = idp_cpld_led_control_shadow;\
 }
 #define WRITE_IDP_CPLD_PERIPH_PWR(value, mask) \
@@ -346,10 +393,10 @@
 /* A listing of interrupts used by external hardware devices */
 
 #define TOUCH_PANEL_IRQ			IRQ_GPIO(21)
-#define TOUCH_PANEL_IRQ_EGDE		GPIO_FALLING_EDGE
+#define TOUCH_PANEL_IRQ_EGDE		IRQT_FALLING
 
 #define ETHERNET_IRQ			IRQ_GPIO(4)
-#define ETHERNET_IRQ_EDGE		GPIO_RISING_EDGE
+#define ETHERNET_IRQ_EDGE		IRQT_RISING
 
 /*
  * Bit masks for various registers
diff -Nru a/include/asm-arm/arch-pxa/memory.h b/include/asm-arm/arch-pxa/memory.h
--- a/include/asm-arm/arch-pxa/memory.h	Tue Oct  1 00:08:17 2002
+++ b/include/asm-arm/arch-pxa/memory.h	Tue Oct  1 00:08:17 2002
@@ -34,7 +34,6 @@
  * Physical DRAM offset.
  */
 #define PHYS_OFFSET	(0xa0000000UL)
-#define PHYS_TO_NID(addr)	(0)
 
 /*
  * physical vs virtual ram conversion
diff -Nru a/include/asm-arm/arch-rpc/keyboard.h b/include/asm-arm/arch-rpc/keyboard.h
--- a/include/asm-arm/arch-rpc/keyboard.h	Tue Oct  1 00:08:16 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,13 +0,0 @@
-/*
- *  linux/include/asm-arm/arch-rpc/keyboard.h
- *
- *  Copyright (C) 1998-2001 Russell King
- *
- * 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.
- *
- *  Keyboard driver definitions for RiscPC architecture
- *  Now using the input subsystem...
- */
-#define kbd_init_hw()		do { } while (0)
diff -Nru a/include/asm-arm/arch-rpc/memory.h b/include/asm-arm/arch-rpc/memory.h
--- a/include/asm-arm/arch-rpc/memory.h	Tue Oct  1 00:08:18 2002
+++ b/include/asm-arm/arch-rpc/memory.h	Tue Oct  1 00:08:18 2002
@@ -50,6 +50,4 @@
 #define __bus_to_virt__is_a_macro
 #define __bus_to_virt(x) __phys_to_virt(x)
 
-#define PHYS_TO_NID(addr)	(0)
-
 #endif
diff -Nru a/include/asm-arm/arch-sa1100/h3600.h b/include/asm-arm/arch-sa1100/h3600.h
--- a/include/asm-arm/arch-sa1100/h3600.h	Tue Oct  1 00:08:18 2002
+++ b/include/asm-arm/arch-sa1100/h3600.h	Tue Oct  1 00:08:18 2002
@@ -16,7 +16,7 @@
  *
  * History:
  *
- * 2001-10-??   Andrew Christian   Added support for iPAQ H3800
+ * 2001-10-??	Andrew Christian   Added support for iPAQ H3800
  *
  */
 
@@ -26,6 +26,11 @@
 /* generalized support for H3xxx series Compaq Pocket PC's */
 #define machine_is_h3xxx() (machine_is_h3100() || machine_is_h3600() || machine_is_h3800())
 
+/* Physical memory regions corresponding to chip selects */
+#define H3600_EGPIO_PHYS     (SA1100_CS5_PHYS + 0x01000000)
+#define H3600_BANK_2_PHYS    SA1100_CS2_PHYS
+#define H3600_BANK_4_PHYS    SA1100_CS4_PHYS
+
 /* Virtual memory regions corresponding to chip selects 2 & 4 (used on sleeves) */
 #define H3600_EGPIO_VIRT     0xf0000000
 #define H3600_BANK_2_VIRT    0xf1000000
@@ -36,8 +41,7 @@
    --- these are common across all current iPAQ platforms
 */
 
-#define GPIO_H3600_NPOWER_BUTTON	GPIO_GPIO (0)   /* Also known as the "off button"  */
-#define GPIO_H3600_MICROCONTROLLER	GPIO_GPIO (1)   /* From ASIC2 on H3800 */
+#define GPIO_H3600_NPOWER_BUTTON	GPIO_GPIO (0)	/* Also known as the "off button"  */
 
 #define GPIO_H3600_PCMCIA_CD1		GPIO_GPIO (10)
 #define GPIO_H3600_PCMCIA_IRQ1		GPIO_GPIO (11)
@@ -56,80 +60,102 @@
 #define GPIO_H3600_COM_CTS		GPIO_GPIO (25)
 #define GPIO_H3600_COM_RTS		GPIO_GPIO (26)
 
-#define IRQ_GPIO_H3600_NPOWER_BUTTON    IRQ_GPIO0
-#define IRQ_GPIO_H3600_MICROCONTROLLER  IRQ_GPIO1
+#define IRQ_GPIO_H3600_NPOWER_BUTTON	IRQ_GPIO0
 #define IRQ_GPIO_H3600_PCMCIA_CD1	IRQ_GPIO10
 #define IRQ_GPIO_H3600_PCMCIA_IRQ1	IRQ_GPIO11
 #define IRQ_GPIO_H3600_PCMCIA_CD0	IRQ_GPIO17
 #define IRQ_GPIO_H3600_PCMCIA_IRQ0	IRQ_GPIO21
-#define IRQ_GPIO_H3600_COM_DCD          IRQ_GPIO23
+#define IRQ_GPIO_H3600_COM_DCD		IRQ_GPIO23
 #define IRQ_GPIO_H3600_OPT_IRQ		IRQ_GPIO24
-#define IRQ_GPIO_H3600_COM_CTS          IRQ_GPIO25
+#define IRQ_GPIO_H3600_COM_CTS		IRQ_GPIO25
 
 
 #ifndef __ASSEMBLY__
-enum ipaq_model {
-	IPAQ_H3100,
-	IPAQ_H3600,
-	IPAQ_H3800
-};
 
 enum ipaq_egpio_type {
-	IPAQ_EGPIO_LCD_ON,        /* Power to the LCD panel */
+	IPAQ_EGPIO_LCD_POWER,	  /* Power to the LCD panel */
 	IPAQ_EGPIO_CODEC_NRESET,  /* Clear to reset the audio codec (remember to return high) */
-	IPAQ_EGPIO_AUDIO_ON,      /* Audio power */
-	IPAQ_EGPIO_QMUTE,         /* Audio muting */
+	IPAQ_EGPIO_AUDIO_ON,	  /* Audio power */
+	IPAQ_EGPIO_QMUTE,	  /* Audio muting */
 	IPAQ_EGPIO_OPT_NVRAM_ON,  /* Non-volatile RAM on extension sleeves (SPI interface) */
-	IPAQ_EGPIO_OPT_ON,        /* Power to extension sleeves */
-	IPAQ_EGPIO_CARD_RESET,    /* Reset PCMCIA cards on extension sleeve (???) */
-	IPAQ_EGPIO_OPT_RESET,     /* Reset option pack (???) */
-	IPAQ_EGPIO_IR_ON,         /* IR sensor/emitter power */
-	IPAQ_EGPIO_IR_FSEL,       /* IR speed selection 1->fast, 0->slow */
-	IPAQ_EGPIO_RS232_ON,      /* Maxim RS232 chip power */
-	IPAQ_EGPIO_VPP_ON,        /* Turn on power to flash programming */
+	IPAQ_EGPIO_OPT_ON,	  /* Power to extension sleeves */
+	IPAQ_EGPIO_CARD_RESET,	  /* Reset PCMCIA cards on extension sleeve (???) */
+	IPAQ_EGPIO_OPT_RESET,	  /* Reset option pack (???) */
+	IPAQ_EGPIO_IR_ON,	  /* IR sensor/emitter power */
+	IPAQ_EGPIO_IR_FSEL,	  /* IR speed selection 1->fast, 0->slow */
+	IPAQ_EGPIO_RS232_ON,	  /* Maxim RS232 chip power */
+	IPAQ_EGPIO_VPP_ON,	  /* Turn on power to flash programming */
+	IPAQ_EGPIO_LCD_ENABLE,	  /* Enable/disable LCD controller */
 };
 
 struct ipaq_model_ops {
-	enum ipaq_model model;
 	const char     *generic_name;
-	void          (*initialize)(void);
-	void          (*control)(enum ipaq_egpio_type, int);
+	void	      (*control)(enum ipaq_egpio_type, int);
 	unsigned long (*read)(void);
+	void	      (*blank_callback)(int blank);
+	int	      (*pm_callback)(int req);	    /* Primary model callback */
+	int	      (*pm_callback_aux)(int req);  /* Secondary callback (used by HAL modules) */
 };
 
 extern struct ipaq_model_ops ipaq_model_ops;
 
-static __inline__ enum ipaq_model h3600_model( void ) {
-	return ipaq_model_ops.model;
-}
-
-static __inline__ const char * h3600_generic_name( void ) {
+static __inline__ const char * h3600_generic_name(void)
+{
 	return ipaq_model_ops.generic_name;
 }
 
-static __inline__ void init_h3600_egpio( void ) {
-	if (ipaq_model_ops.initialize)
-		ipaq_model_ops.initialize();
-}
-
-static __inline__ void assign_h3600_egpio( enum ipaq_egpio_type x, int level ) {
+static __inline__ void assign_h3600_egpio(enum ipaq_egpio_type x, int level)
+{
 	if (ipaq_model_ops.control)
 		ipaq_model_ops.control(x,level);
 }
 
-static __inline__ void clr_h3600_egpio( enum ipaq_egpio_type x ) {
+static __inline__ void clr_h3600_egpio(enum ipaq_egpio_type x)
+{
 	if (ipaq_model_ops.control)
 		ipaq_model_ops.control(x,0);
 }
 
-static __inline__ void set_h3600_egpio( enum ipaq_egpio_type x ) {
+static __inline__ void set_h3600_egpio(enum ipaq_egpio_type x)
+{
 	if (ipaq_model_ops.control)
 		ipaq_model_ops.control(x,1);
 }
 
-static __inline__ unsigned long read_h3600_egpio( void ) {
+static __inline__ unsigned long read_h3600_egpio(void)
+{
 	if (ipaq_model_ops.read)
 		return ipaq_model_ops.read();
+	return 0;
+}
+
+static __inline__ int  h3600_register_blank_callback(void (*f)(int))
+{
+	ipaq_model_ops.blank_callback = f;
+	return 0;
+}
+
+static __inline__ void h3600_unregister_blank_callback(void (*f)(int))
+{
+	ipaq_model_ops.blank_callback = NULL;
+}
+
+
+static __inline__ int  h3600_register_pm_callback(int (*f)(int))
+{
+	ipaq_model_ops.pm_callback_aux = f;
+	return 0;
+}
+
+static __inline__ void h3600_unregister_pm_callback(int (*f)(int))
+{
+	ipaq_model_ops.pm_callback_aux = NULL;
+}
+
+static __inline__ int h3600_power_management(int req)
+{
+	if (ipaq_model_ops.pm_callback)
+		return ipaq_model_ops.pm_callback(req);
 	return 0;
 }
 
diff -Nru a/include/asm-arm/arch-sa1100/irqs.h b/include/asm-arm/arch-sa1100/irqs.h
--- a/include/asm-arm/arch-sa1100/irqs.h	Tue Oct  1 00:08:13 2002
+++ b/include/asm-arm/arch-sa1100/irqs.h	Tue Oct  1 00:08:13 2002
@@ -108,18 +108,18 @@
 #define AUDDTS			(IRQ_BOARD_END + 40)
 #define AUDRDD			(IRQ_BOARD_END + 41)
 #define AUDSTO			(IRQ_BOARD_END + 42)
-#define USBPWR			(IRQ_BOARD_END + 43)
-#define NIRQHCIM		(IRQ_BOARD_END + 44)
-#define IRQHCIBUFFACC		(IRQ_BOARD_END + 45)
-#define IRQHCIRMTWKP		(IRQ_BOARD_END + 46)
-#define NHCIMFCIR		(IRQ_BOARD_END + 47)
-#define USB_PORT_RESUME		(IRQ_BOARD_END + 48)
-#define S0_READY_NINT		(IRQ_BOARD_END + 49)
-#define S1_READY_NINT		(IRQ_BOARD_END + 50)
-#define S0_CD_VALID		(IRQ_BOARD_END + 51)
-#define S1_CD_VALID		(IRQ_BOARD_END + 52)
-#define S0_BVD1_STSCHG		(IRQ_BOARD_END + 53)
-#define S1_BVD1_STSCHG		(IRQ_BOARD_END + 54)
+#define IRQ_USBPWR		(IRQ_BOARD_END + 43)
+#define IRQ_NHCIM		(IRQ_BOARD_END + 44)
+#define IRQ_HCIBUFFACC		(IRQ_BOARD_END + 45)
+#define IRQ_HCIRMTWKP		(IRQ_BOARD_END + 46)
+#define IRQ_NHCIMFCIR		(IRQ_BOARD_END + 47)
+#define IRQ_USB_PORT_RESUME	(IRQ_BOARD_END + 48)
+#define IRQ_S0_READY_NINT	(IRQ_BOARD_END + 49)
+#define IRQ_S1_READY_NINT	(IRQ_BOARD_END + 50)
+#define IRQ_S0_CD_VALID		(IRQ_BOARD_END + 51)
+#define IRQ_S1_CD_VALID		(IRQ_BOARD_END + 52)
+#define IRQ_S0_BVD1_STSCHG	(IRQ_BOARD_END + 53)
+#define IRQ_S1_BVD1_STSCHG	(IRQ_BOARD_END + 54)
 
 /*
  * Figure out the MAX IRQ number.
@@ -129,7 +129,7 @@
  * Otherwise, we have the standard IRQs only.
  */
 #ifdef CONFIG_SA1111
-#define NR_IRQS			(S1_BVD1_STSCHG + 1)
+#define NR_IRQS			(IRQ_S1_BVD1_STSCHG + 1)
 #elif defined(CONFIG_SA1100_GRAPHICSCLIENT) || \
       defined(CONFIG_SA1100_GRAPHICSMASTER) || \
       defined(CONFIG_SA1100_H3800)
diff -Nru a/include/asm-arm/arch-shark/memory.h b/include/asm-arm/arch-shark/memory.h
--- a/include/asm-arm/arch-shark/memory.h	Tue Oct  1 00:08:21 2002
+++ b/include/asm-arm/arch-shark/memory.h	Tue Oct  1 00:08:21 2002
@@ -40,6 +40,4 @@
 
 #define isa_virt_to_bus		virt_to_bus
 
-#define PHYS_TO_NID(addr)	(0)
-
 #endif
diff -Nru a/include/asm-arm/arch-tbox/keyboard.h b/include/asm-arm/arch-tbox/keyboard.h
--- a/include/asm-arm/arch-tbox/keyboard.h	Tue Oct  1 00:08:22 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,14 +0,0 @@
-/*
- * linux/include/asm-arm/arch-tbox/keyboard.h
- *
- * Driver definitions for Tbox dummy keyboard.
- *
- * Copyright (C) 1998-2001 Russell King
- * Copyright (C) 1998 Philip Blundell
- */
-
-#define NR_SCANCODES 128
-
-#define kbd_init_hw()		do { } while (0)
-#define kbd_disable_irq()	do { } while (0)
-#define kbd_enable_irq()	do { } while (0)
diff -Nru a/include/asm-arm/arch-tbox/memory.h b/include/asm-arm/arch-tbox/memory.h
--- a/include/asm-arm/arch-tbox/memory.h	Tue Oct  1 00:08:15 2002
+++ b/include/asm-arm/arch-tbox/memory.h	Tue Oct  1 00:08:15 2002
@@ -41,6 +41,4 @@
 #define __bus_to_virt__is_a_macro
 #define __bus_to_virt(x)	__phys_to_virt(x)
 
-#define PHYS_TO_NID(addr)	(0)
-
 #endif
diff -Nru a/include/asm-arm/elf.h b/include/asm-arm/elf.h
--- a/include/asm-arm/elf.h	Tue Oct  1 00:08:20 2002
+++ b/include/asm-arm/elf.h	Tue Oct  1 00:08:20 2002
@@ -53,7 +53,6 @@
 /* This yields a mask that user programs can use to figure out what
    instruction set this cpu supports. */
 
-extern unsigned int elf_hwcap;
 #define ELF_HWCAP	(elf_hwcap)
 
 /* This yields a string that ld.so will use to load implementation
diff -Nru a/include/asm-arm/hardware/sa1111.h b/include/asm-arm/hardware/sa1111.h
--- a/include/asm-arm/hardware/sa1111.h	Tue Oct  1 00:08:17 2002
+++ b/include/asm-arm/hardware/sa1111.h	Tue Oct  1 00:08:17 2002
@@ -64,18 +64,10 @@
 #define SA1111_SMCR	0x0004
 #define SA1111_SKID	0x0008
 
-#define _SBI_SKCR	_SA1111(SA1111_SKCR)
-#define _SBI_SMCR	_SA1111(SA1111_SMCR)
-#define _SBI_SKID	_SA1111(SA1111_SKID)
-
-#if LANGUAGE == C
-
 #define SBI_SKCR	__CCREG(SA1111_SKCR)
 #define SBI_SMCR	__CCREG(SA1111_SMCR)
 #define SBI_SKID	__CCREG(SA1111_SKID)
 
-#endif  /* LANGUAGE == C */
-
 #define SKCR_PLL_BYPASS	(1<<0)
 #define SKCR_RCLKEN	(1<<1)
 #define SKCR_SLEEP	(1<<2)
@@ -135,22 +127,10 @@
 #define SA1111_SKPMC	0x020c
 #define SA1111_SKPTC	0x0210
 #define SA1111_SKPEN0	0x0214
-#define SA1111_SKPWN0	0x0218
+#define SA1111_SKPWM0	0x0218
 #define SA1111_SKPEN1	0x021c
 #define SA1111_SKPWM1	0x0220
 
-#define _SKPCR		_SA1111(SA1111_SKPCR)
-#define _SKCDR		_SA1111(SA1111_SKCDR)
-#define _SKAUD		_SA1111(SA1111_SKAUD)
-#define _SKPMC		_SA1111(SA1111_SKPMC)
-#define _SKPTC		_SA1111(SA1111_SKPTC)
-#define _SKPEN0		_SA1111(SA1111_SKPEN0)
-#define _SKPWM0		_SA1111(SA1111_SKPWM0)
-#define _SKPEN1		_SA1111(SA1111_SKPEN1)
-#define _SKPWM1		_SA1111(SA1111_SKPWM1)
-
-#if LANGUAGE == C
-
 #define SKPCR		__CCREG(SA1111_SKPCR)
 #define SKCDR		__CCREG(SA1111_SKCDR)
 #define SKAUD		__CCREG(SA1111_SKAUD)
@@ -161,8 +141,6 @@
 #define SKPEN1		__CCREG(SA1111_SKPEN1)
 #define SKPWM1		__CCREG(SA1111_SKPWM1)
 
-#endif  /* LANGUAGE == C */
-
 #define SKPCR_UCLKEN	(1<<0)
 #define SKPCR_ACCLKEN	(1<<1)
 #define SKPCR_I2SCLKEN	(1<<2)
@@ -176,21 +154,14 @@
 /*
  * USB Host controller
  */
-#define _USB_OHCI_OP_BASE	_SA1111( 0x400 )
-#define _USB_STATUS		_SA1111( 0x518 )
-#define _USB_RESET		_SA1111( 0x51c )
-#define _USB_INTERRUPTEST	_SA1111( 0x520 )
-
-#define _USB_EXTENT		(_USB_INTERRUPTEST - _USB_OHCI_OP_BASE + 4)
-
-#if LANGUAGE == C
-
-#define USB_OHCI_OP_BASE	__CCREG(0x0400)
-#define USB_STATUS		__CCREG(0x0518)
-#define USB_RESET		__CCREG(0x051c)
-#define USB_INTERRUPTEST	__CCReG(0x0520)
+#define SA1111_USB		0x0400
 
-#endif  /* LANGUAGE == C */
+/*
+ * Offsets from SA1111_USB_BASE
+ */
+#define SA1111_USB_STATUS	0x0118
+#define SA1111_USB_RESET	0x011c
+#define SA1111_USB_IRQTEST	0x0120
 
 #define USB_RESET_FORCEIFRESET	(1 << 0)
 #define USB_RESET_FORCEHCRESET	(1 << 1)
@@ -451,82 +422,56 @@
  *    WAKE_POL0		Wake-up polarity selection 0
  *    WAKE_POL1		Wake-up polarity selection 1
  */
+#define SA1111_INTC		0x1600
 
-#define SA1111_INTTEST0		0x1600
-#define SA1111_INTTEST1		0x1604
-#define SA1111_INTEN0		0x1608
-#define SA1111_INTEN1		0x160c
-#define SA1111_INTPOL0		0x1610
-#define SA1111_INTPOL1		0x1614
-#define SA1111_INTTSTSEL	0x1618
-#define SA1111_INTSTATCLR0	0x161c
-#define SA1111_INTSTATCLR1	0x1620
-#define SA1111_INTSET0		0x1624
-#define SA1111_INTSET1		0x1628
-#define SA1111_WAKE_EN0		0x162c
-#define SA1111_WAKE_EN1		0x1630
-#define SA1111_WAKE_POL0	0x1634
-#define SA1111_WAKE_POL1	0x1638
-
-#define _INTTEST0	_SA1111(SA1111_INTTEST0)
-#define _INTTEST1	_SA1111(SA1111_INTTEST1)
-#define _INTEN0		_SA1111(SA1111_INTEN0)
-#define _INTEN1		_SA1111(SA1111_INTEN1)
-#define _INTPOL0	_SA1111(SA1111_INTPOL0)
-#define _INTPOL1	_SA1111(SA1111_INTPOL1)
-#define _INTTSTSEL	_SA1111(SA1111_INTTSTSEL)
-#define _INTSTATCLR0	_SA1111(SA1111_INTSTATCLR0)
-#define _INTSTATCLR1	_SA1111(SA1111_INTSTATCLR1)
-#define _INTSET0	_SA1111(SA1111_INTSET0)
-#define _INTSET1	_SA1111(SA1111_INTSET1)
-#define _WAKE_EN0	_SA1111(SA1111_WAKE_EN0)
-#define _WAKE_EN1	_SA1111(SA1111_WAKE_EN1)
-#define _WAKE_POL0	_SA1111(SA1111_WAKE_POL0)
-#define _WAKE_POL1	_SA1111(SA1111_WAKE_POL1)
-
-#if LANGUAGE == C
-
-#define INTTEST0	__CCREG(SA1111_INTTEST0)
-#define INTTEST1	__CCREG(SA1111_INTTEST1)
-#define INTEN0		__CCREG(SA1111_INTEN0)
-#define INTEN1		__CCREG(SA1111_INTEN1)
-#define INTPOL0		__CCREG(SA1111_INTPOL0)
-#define INTPOL1		__CCREG(SA1111_INTPOL1)
-#define INTTSTSEL	__CCREG(SA1111_INTTSTSEL)
-#define INTSTATCLR0	__CCREG(SA1111_INTSTATCLR0)
-#define INTSTATCLR1	__CCREG(SA1111_INTSTATCLR1)
-#define INTSET0		__CCREG(SA1111_INTSET0)
-#define INTSET1		__CCREG(SA1111_INTSET1)
-#define WAKE_EN0	__CCREG(SA1111_WAKE_EN0)
-#define WAKE_EN1	__CCREG(SA1111_WAKE_EN1)
-#define WAKE_POL0	__CCREG(SA1111_WAKE_POL0)
-#define WAKE_POL1	__CCREG(SA1111_WAKE_POL1)
-
-#endif  /* LANGUAGE == C */
+/*
+ * These are offsets from the above base.
+ */
+#define SA1111_INTTEST0		0x0000
+#define SA1111_INTTEST1		0x0004
+#define SA1111_INTEN0		0x0008
+#define SA1111_INTEN1		0x000c
+#define SA1111_INTPOL0		0x0010
+#define SA1111_INTPOL1		0x0014
+#define SA1111_INTTSTSEL	0x0018
+#define SA1111_INTSTATCLR0	0x001c
+#define SA1111_INTSTATCLR1	0x0020
+#define SA1111_INTSET0		0x0024
+#define SA1111_INTSET1		0x0028
+#define SA1111_WAKEEN0		0x002c
+#define SA1111_WAKEEN1		0x0030
+#define SA1111_WAKEPOL0		0x0034
+#define SA1111_WAKEPOL1		0x0038
+
+#define INTTEST0	__CCREG(SA1111_INTC + SA1111_INTTEST0)
+#define INTTEST1	__CCREG(SA1111_INTC + SA1111_INTTEST1)
+#define INTEN0		__CCREG(SA1111_INTC + SA1111_INTEN0)
+#define INTEN1		__CCREG(SA1111_INTC + SA1111_INTEN1)
+#define INTPOL0		__CCREG(SA1111_INTC + SA1111_INTPOL0)
+#define INTPOL1		__CCREG(SA1111_INTC + SA1111_INTPOL1)
+#define INTTSTSEL	__CCREG(SA1111_INTC + SA1111_INTTSTSEL)
+#define INTSTATCLR0	__CCREG(SA1111_INTC + SA1111_INTSTATCLR0)
+#define INTSTATCLR1	__CCREG(SA1111_INTC + SA1111_INTSTATCLR1)
+#define INTSET0		__CCREG(SA1111_INTC + SA1111_INTSET0)
+#define INTSET1		__CCREG(SA1111_INTC + SA1111_INTSET1)
+#define WAKE_EN0	__CCREG(SA1111_INTC + SA1111_WAKEEN0)
+#define WAKE_EN1	__CCREG(SA1111_INTC + SA1111_WAKEEN1)
+#define WAKE_POL0	__CCREG(SA1111_INTC + SA1111_WAKEPOL0)
+#define WAKE_POL1	__CCREG(SA1111_INTC + SA1111_WAKEPOL1)
 
 /*
  * PS/2 Trackpad and Mouse Interfaces
  *
- * Registers   (prefix kbd applies to trackpad interface, mse to mouse)
- *    KBDCR     Control Register
- *    KBDSTAT       Status Register
- *    KBDDATA       Transmit/Receive Data register
- *    KBDCLKDIV     Clock Division Register
- *    KBDPRECNT     Clock Precount Register
- *    KBDTEST1      Test register 1
- *    KBDTEST2      Test register 2
- *    KBDTEST3      Test register 3
- *    KBDTEST4      Test register 4
- *    MSECR
- *    MSESTAT
- *    MSEDATA
- *    MSECLKDIV
- *    MSEPRECNT
- *    MSETEST1
- *    MSETEST2
- *    MSETEST3
- *    MSETEST4
- *
+ * Registers
+ *    PS2CR		Control Register
+ *    PS2STAT		Status Register
+ *    PS2DATA		Transmit/Receive Data register
+ *    PS2CLKDIV		Clock Division Register
+ *    PS2PRECNT		Clock Precount Register
+ *    PS2TEST1		Test register 1
+ *    PS2TEST2		Test register 2
+ *    PS2TEST3		Test register 3
+ *    PS2TEST4		Test register 4
  */
 
 #define SA1111_KBD		0x0a00
@@ -564,17 +509,14 @@
  *    PCSSR	Sleep State Register
  */
 
-#define _PCCR		_SA1111( 0x1800 )
-#define _PCSSR		_SA1111( 0x1804 )
-#define _PCSR		_SA1111( 0x1808 )
-
-#if LANGUAGE == C
-
-#define PCCR		__CCREG(0x1800)
-#define PCSSR		__CCREG(0x1804)
-#define PCSR		__CCREG(0x1808)
+#define SA1111_PCMCIA	0x1600
 
-#endif  /* LANGUAGE == C */
+/*
+ * These are offsets from the above base.
+ */
+#define SA1111_PCCR	0x0000
+#define SA1111_PCSSR	0x0004
+#define SA1111_PCSR	0x0008
 
 #define PCSR_S0_READY	(1<<0)
 #define PCSR_S1_READY	(1<<1)
@@ -603,18 +545,61 @@
 #define PCSSR_S0_SLEEP	(1<<0)
 #define PCSSR_S1_SLEEP	(1<<1)
 
-struct sa1111_device {
+
+
+
+extern struct bus_type sa1111_bus_type;
+
+#define SA1111_DEVID_SBI	0
+#define SA1111_DEVID_SK		1
+#define SA1111_DEVID_USB	2
+#define SA1111_DEVID_SAC	3
+#define SA1111_DEVID_SSP	4
+#define SA1111_DEVID_PS2	5
+#define SA1111_DEVID_GPIO	6
+#define SA1111_DEVID_INT	7
+#define SA1111_DEVID_PCMCIA	8
+
+struct sa1111_dev {
 	struct device	dev;
-	struct resource	resource;
-	void		*base;
+	unsigned int	devid;
+	struct resource	res;
+	void		*mapbase;
+	unsigned int	skpcr_mask;
+	unsigned int	irq[6];
+};
+
+#define SA1111_DEV(_d)	container_of((_d), struct sa1111_dev, dev)
+
+struct sa1111_driver {
+	struct device_driver	drv;
+	unsigned int		devid;
 };
 
-extern struct sa1111_device *sa1111;
+#define SA1111_DRV(_d)	container_of((_d), struct sa1111_driver, drv)
+
+#define SA1111_DRIVER_NAME(_sadev) ((_sadev)->dev.driver->name)
+
+/*
+ * Probe for a SA1111 chip.
+ */
+extern int sa1111_init(unsigned long phys, unsigned int irq);
 
 /*
  * These frob the SKPCR register.
  */
-void sa1111_enable_device(unsigned int mask);
-void sa1111_disable_device(unsigned int mask);
+void sa1111_enable_device(struct sa1111_dev *);
+void sa1111_disable_device(struct sa1111_dev *);
+
+unsigned int sa1111_pll_clock(struct sa1111_dev *);
+
+#define SA1111_AUDIO_ACLINK	0
+#define SA1111_AUDIO_I2S	1
+
+void sa1111_select_audio_mode(struct sa1111_dev *sadev, int mode);
+int sa1111_set_audio_rate(struct sa1111_dev *sadev, int rate);
+int sa1111_get_audio_rate(struct sa1111_dev *sadev);
+
+int sa1111_check_dma_bug(dma_addr_t addr);
 
 #endif  /* _ASM_ARCH_SA1111 */
diff -Nru a/include/asm-arm/ide.h b/include/asm-arm/ide.h
--- a/include/asm-arm/ide.h	Tue Oct  1 00:08:17 2002
+++ b/include/asm-arm/ide.h	Tue Oct  1 00:08:17 2002
@@ -26,6 +26,20 @@
 #define ide_default_io_base(i)		((ide_ioreg_t)0)
 #define ide_default_irq(b)		(0)
 
+#define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
+#define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
+#define ide_check_region(from,extent)		check_region((from), (extent))
+#define ide_request_region(from,extent,name)	request_region((from), (extent), (name))
+#define ide_release_region(from,extent)		release_region((from), (extent))
+
+/*
+ * The following are not needed for the non-m68k ports
+ */
+#define ide_ack_intr(hwif)		(1)
+#define ide_fix_driveid(id)		do {} while (0)
+#define ide_release_lock(lock)		do {} while (0)
+#define ide_get_lock(lock, hdlr, data)	do {} while (0)
+
 #endif /* __KERNEL__ */
 
 #endif /* __ASMARM_IDE_H */
diff -Nru a/include/asm-arm/kmap_types.h b/include/asm-arm/kmap_types.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-arm/kmap_types.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,12 @@
+#ifndef __ARM_KMAP_TYPES_H
+#define __ARM_KMAP_TYPES_H
+
+/*
+ * This is the "bare minimum".  AIO seems to require this.
+ */
+enum km_type {
+	KM_IRQ0,
+	KM_USER1
+};
+
+#endif
diff -Nru a/include/asm-arm/mach/amba_kmi.h b/include/asm-arm/mach/amba_kmi.h
--- a/include/asm-arm/mach/amba_kmi.h	Tue Oct  1 00:08:17 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,40 +0,0 @@
-/*
- *  linux/include/asm-arm/mach/amba_kmi.h
- *
- *  Copyright (C) 2000 Deep Blue Solutions Ltd.
- *
- * 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
- */
-struct kmi_info {
-	u_int			base;
-	u_int			irq;
-	u_char			divisor;
-	u_char			type;
-	u_char			state;
-	u_char			prev_rx;
-	u_char			last_tx;
-	u_char			resend_count;
-	u_short			res;
-	u_char			present;
-	wait_queue_head_t	wait_q;
-	void			(*rx)(struct kmi_info *, u_int val,
-				      struct pt_regs *regs);
-	char			name[8];
-};
-
-#define KMI_KEYBOARD		0
-#define KMI_MOUSE		1
-
-int register_kmi(struct kmi_info *kmi);
diff -Nru a/include/asm-arm/memory.h b/include/asm-arm/memory.h
--- a/include/asm-arm/memory.h	Tue Oct  1 00:08:20 2002
+++ b/include/asm-arm/memory.h	Tue Oct  1 00:08:20 2002
@@ -74,6 +74,8 @@
 #define virt_to_page(kaddr)	(pfn_to_page(__pa(kaddr) >> PAGE_SHIFT))
 #define virt_addr_valid(kaddr)	((kaddr) >= PAGE_OFFSET && (kaddr) < (unsigned long)high_memory)
 
+#define PHYS_TO_NID(addr)	(0)
+
 #else
 /*
  * This is more complex.  We have a set of mem_map arrays spread
diff -Nru a/include/asm-arm/mmu_context.h b/include/asm-arm/mmu_context.h
--- a/include/asm-arm/mmu_context.h	Tue Oct  1 00:08:17 2002
+++ b/include/asm-arm/mmu_context.h	Tue Oct  1 00:08:17 2002
@@ -34,13 +34,17 @@
 
 /*
  * This is the actual mm switch as far as the scheduler
- * is concerned.  No registers are touched.
+ * is concerned.  No registers are touched.  We avoid
+ * calling the CPU specific function when the mm hasn't
+ * actually changed.
  */
 static inline void
 switch_mm(struct mm_struct *prev, struct mm_struct *next,
 	  struct task_struct *tsk, unsigned int cpu)
 {
-	cpu_switch_mm(next->pgd, next);
+	if (prev != next) {
+		cpu_switch_mm(next->pgd, next);
+	}
 }
 
 static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next)
diff -Nru a/include/asm-arm/pci.h b/include/asm-arm/pci.h
--- a/include/asm-arm/pci.h	Tue Oct  1 00:08:16 2002
+++ b/include/asm-arm/pci.h	Tue Oct  1 00:08:16 2002
@@ -12,6 +12,30 @@
 
 struct pci_dev;
 
+/*
+ * For SA-1111 these functions are "magic" and utilize bounce
+ * buffers as need to workaround SA-1111 DMA bugs.  They are called in
+ * place of their pci_* counterparts when dev_is_sa1111() returns true.
+ */
+dma_addr_t sa1111_map_single(struct pci_dev *, void *, size_t, int);
+void sa1111_unmap_single(struct pci_dev *, dma_addr_t, size_t, int);
+int sa1111_map_sg(struct pci_dev *, struct scatterlist *, int, int);
+void sa1111_unmap_sg(struct pci_dev *, struct scatterlist *, int, int);
+void sa1111_dma_sync_single(struct pci_dev *, dma_addr_t, size_t, int);
+void sa1111_dma_sync_sg(struct pci_dev *, struct scatterlist *, int, int);
+
+#ifdef CONFIG_SA1111
+
+#define SA1111_FAKE_PCIDEV ((struct pci_dev *) 1111)
+#define dev_is_sa1111(dev) (dev == SA1111_FAKE_PCIDEV)
+
+#else
+
+#define dev_is_sa1111(dev) (0)
+
+#endif
+
+
 static inline void pcibios_set_master(struct pci_dev *dev)
 {
 	/* No special bus mastering setup handling */
@@ -61,17 +85,9 @@
 static inline dma_addr_t
 pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction)
 {
-#ifdef CONFIG_SA1111
-	extern dma_addr_t sa1111_map_single(struct pci_dev *, void *, size_t, int);
-
-	/*
-	 * for SA1111 these functions are "magic" and relocate buffers.  We
-	 * only need to do these if hwdev is non-null; otherwise we expect
-	 * the buffer to already be suitable for DMA.
-	 */
-	if (hwdev != NULL)
+	if (dev_is_sa1111(hwdev))
 		return sa1111_map_single(hwdev, ptr, size, direction);
-#endif
+
 	consistent_sync(ptr, size, direction);
 	return virt_to_bus(ptr);
 }
@@ -86,12 +102,9 @@
 static inline void
 pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction)
 {
-#ifdef CONFIG_SA1111
-	extern void sa1111_unmap_single(struct pci_dev *, dma_addr_t, size_t, int);
-
-	if (hwdev != NULL)
+	if (dev_is_sa1111(hwdev))
 		sa1111_unmap_single(hwdev, dma_addr, size, direction);
-#endif
+
 	/* nothing to do */
 }
 
@@ -99,7 +112,7 @@
  * Whether pci_unmap_{single,page} is a nop depends upon the
  * configuration.
  */
-#ifdef CONFIG_PCI
+#if defined(CONFIG_PCI) || defined(CONFIG_SA1111)
 #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)	dma_addr_t ADDR_NAME;
 #define DECLARE_PCI_UNMAP_LEN(LEN_NAME)		__u32 LEN_NAME;
 #define pci_unmap_addr(PTR, ADDR_NAME)		((PTR)->ADDR_NAME)
@@ -135,6 +148,9 @@
 {
 	int i;
 
+	if (dev_is_sa1111(hwdev))
+		return sa1111_map_sg(hwdev, sg, nents, direction);
+
 	for (i = 0; i < nents; i++, sg++) {
 		char *virt;
 
@@ -153,6 +169,11 @@
 static inline void
 pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction)
 {
+	if (dev_is_sa1111(hwdev)) {
+		sa1111_unmap_sg(hwdev, sg, nents, direction);
+		return;
+	}
+
 	/* nothing to do */
 }
 
@@ -168,6 +189,11 @@
 static inline void
 pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction)
 {
+	if (dev_is_sa1111(hwdev)) {
+	  	sa1111_dma_sync_single(hwdev, dma_handle, size, direction);
+		return;
+	}
+
 	consistent_sync(bus_to_virt(dma_handle), size, direction);
 }
 
@@ -182,6 +208,11 @@
 {
 	int i;
 
+	if (dev_is_sa1111(hwdev)) {
+	  	sa1111_dma_sync_sg(hwdev, sg, nelems, direction);
+		return;
+	}
+
 	for (i = 0; i < nelems; i++, sg++) {
 		char *virt = page_address(sg->page) + sg->offset;
 		consistent_sync(virt, sg->length, direction);
@@ -203,6 +234,19 @@
 
 /* Return the index of the PCI controller for device PDEV. */
 #define pci_controller_num(PDEV)	(0)
+
+
+#if defined(CONFIG_SA1111) && !defined(CONFIG_PCI)
+/* SA-1111 needs these prototypes even when !defined(CONFIG_PCI) */
+
+/* kmem_cache style wrapper around pci_alloc_consistent() */
+struct pci_pool *pci_pool_create (const char *name, struct pci_dev *dev,
+		size_t size, size_t align, size_t allocation, int flags);
+void pci_pool_destroy (struct pci_pool *pool);
+
+void *pci_pool_alloc (struct pci_pool *pool, int flags, dma_addr_t *handle);
+void pci_pool_free (struct pci_pool *pool, void *vaddr, dma_addr_t addr);
+#endif
 
 #endif /* __KERNEL__ */
  
diff -Nru a/include/asm-arm/percpu.h b/include/asm-arm/percpu.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-arm/percpu.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,6 @@
+#ifndef __ARM_PERCPU
+#define __ARM_PERCPU
+
+#include <asm-generic/percpu.h>
+
+#endif
diff -Nru a/include/asm-arm/proc-armv/elf.h b/include/asm-arm/proc-armv/elf.h
--- a/include/asm-arm/proc-armv/elf.h	Tue Oct  1 00:08:18 2002
+++ b/include/asm-arm/proc-armv/elf.h	Tue Oct  1 00:08:18 2002
@@ -6,10 +6,14 @@
 
 #ifdef __KERNEL__
 
-/* 32-bit code is always OK.  Some cpus can do 26-bit, some can't.  */
-#define ELF_PROC_OK(x)				\
-	((! ((x)->e_flags & EF_ARM_APCS26))	\
-	|| (elf_hwcap & HWCAP_26BIT))
+/*
+ * 32-bit code is always OK.  Some cpus can do 26-bit, some can't.
+ */
+#define ELF_PROC_OK(x)							 \
+	(( (elf_hwcap & HWCAP_THUMB) && ((x)->e_entry & 1) == 1)      || \
+	 (!(elf_hwcap & HWCAP_THUMB) && ((x)->e_entry & 3) == 0)      || \
+	 ( (elf_hwcap & HWCAP_26BIT) && (x)->e_flags & EF_ARM_APCS26) || \
+	 ((x)->e_flags & EF_ARM_APCS26) == 0)
 
 /* Old NetWinder binaries were compiled in such a way that the iBCS
    heuristic always trips on them.  Until these binaries become uncommon
diff -Nru a/include/asm-arm/proc-armv/processor.h b/include/asm-arm/proc-armv/processor.h
--- a/include/asm-arm/proc-armv/processor.h	Tue Oct  1 00:08:20 2002
+++ b/include/asm-arm/proc-armv/processor.h	Tue Oct  1 00:08:20 2002
@@ -36,7 +36,9 @@
 		regs->ARM_cpsr = USR_MODE;				\
 	else								\
 		regs->ARM_cpsr = USR26_MODE;				\
-	regs->ARM_pc = pc;		/* pc */			\
+	if (elf_hwcap & HWCAP_THUMB && pc & 1)				\
+		regs->ARM_cpsr |= PSR_T_BIT;				\
+	regs->ARM_pc = pc & ~1;		/* pc */			\
 	regs->ARM_sp = sp;		/* sp */			\
 	regs->ARM_r2 = stack[2];	/* r2 (envp) */			\
 	regs->ARM_r1 = stack[1];	/* r1 (argv) */			\
diff -Nru a/include/asm-arm/processor.h b/include/asm-arm/processor.h
--- a/include/asm-arm/processor.h	Tue Oct  1 00:08:17 2002
+++ b/include/asm-arm/processor.h	Tue Oct  1 00:08:17 2002
@@ -25,6 +25,7 @@
 
 #include <asm/atomic.h>
 #include <asm/ptrace.h>
+#include <asm/procinfo.h>
 #include <asm/arch/memory.h>
 #include <asm/proc/processor.h>
 
diff -Nru a/include/asm-arm/procinfo.h b/include/asm-arm/procinfo.h
--- a/include/asm-arm/procinfo.h	Tue Oct  1 00:08:15 2002
+++ b/include/asm-arm/procinfo.h	Tue Oct  1 00:08:15 2002
@@ -46,6 +46,8 @@
 	struct cpu_user_fns	*user;
 };
 
+extern unsigned int elf_hwcap;
+
 #endif	/* __ASSEMBLY__ */
 
 #define PROC_INFO_SZ	44
diff -Nru a/include/asm-arm/setup.h b/include/asm-arm/setup.h
--- a/include/asm-arm/setup.h	Tue Oct  1 00:08:17 2002
+++ b/include/asm-arm/setup.h	Tue Oct  1 00:08:17 2002
@@ -65,14 +65,14 @@
 	u32 start;	/* starting block of floppy-based RAM disk image */
 };
 
-/* describes where the compressed ramdisk image lives */
+/* describes where the compressed ramdisk image lives (virtual address) */
 /*
  * this one accidentally used virtual addresses - as such,
  * its depreciated.
  */
 #define ATAG_INITRD	0x54410005
 
-/* describes where the compressed ramdisk image lives */
+/* describes where the compressed ramdisk image lives (physical address) */
 #define ATAG_INITRD2	0x54420005
 
 struct tag_initrd {
diff -Nru a/include/asm-arm/stat.h b/include/asm-arm/stat.h
--- a/include/asm-arm/stat.h	Tue Oct  1 00:08:15 2002
+++ b/include/asm-arm/stat.h	Tue Oct  1 00:08:15 2002
@@ -40,6 +40,8 @@
 
 /* This matches struct stat64 in glibc2.1, hence the absolutely
  * insane amounts of padding around dev_t's.
+ * Note: The kernel zero's the padded region because glibc might read them
+ * in the hope that the kernel has stretched to using larger sizes.
  */
 struct stat64 {
 #if defined(__ARMEB__)
diff -Nru a/include/asm-arm/system.h b/include/asm-arm/system.h
--- a/include/asm-arm/system.h	Tue Oct  1 00:08:15 2002
+++ b/include/asm-arm/system.h	Tue Oct  1 00:08:15 2002
@@ -86,6 +86,13 @@
 #define clf()			__clf()
 #define stf()			__stf()
 
+#define irqs_disabled()			\
+({					\
+	unsigned long flags;		\
+	local_save_flags(flags);	\
+	flags & PSR_I_BIT;		\
+})
+
 #endif /* CONFIG_SMP */
 
 #endif /* __KERNEL__ */
diff -Nru a/include/asm-arm/topology.h b/include/asm-arm/topology.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-arm/topology.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,6 @@
+#ifndef _ASM_ARM_TOPOLOGY_H
+#define _ASM_ARM_TOPOLOGY_H
+
+#include <asm-generic/topology.h>
+
+#endif /* _ASM_ARM_TOPOLOGY_H */
diff -Nru a/include/asm-arm/unistd.h b/include/asm-arm/unistd.h
--- a/include/asm-arm/unistd.h	Tue Oct  1 00:08:20 2002
+++ b/include/asm-arm/unistd.h	Tue Oct  1 00:08:20 2002
@@ -15,7 +15,11 @@
 
 #include <linux/linkage.h>
 
+#if defined(__thumb__)
+#define __NR_SYSCALL_BASE	0
+#else
 #define __NR_SYSCALL_BASE	0x900000
+#endif
 
 /*
  * This file contains the system call numbers.
@@ -273,8 +277,16 @@
 #define __sys1(x) __sys2(x)
 
 #ifndef __syscall
+#if defined(__thumb__)
+#define __syscall(name)					\
+	"push	{r7}\n\t"				\
+	"mov	r7, #" __sys1(__NR_##name) "\n\t"	\
+	"swi	0\n\t"					\
+	"pop	{r7}"
+#else
 #define __syscall(name) "swi\t" __sys1(__NR_##name) "\n\t"
 #endif
+#endif
 
 #define __syscall_return(type, res)					\
 do {									\
@@ -287,91 +299,103 @@
 
 #define _syscall0(type,name)						\
 type name(void) {							\
-  long __res;								\
+  register long __res __asm__("r0");					\
   __asm__ __volatile__ (						\
   __syscall(name)							\
-  "mov %0,r0"								\
-  :"=r" (__res) : : "r0","lr");						\
+	:"=r" (__res)							\
+	:								\
+	: "lr");							\
   __syscall_return(type,__res);						\
 }
 
-#define _syscall1(type,name,type1,arg1)					\
-type name(type1 arg1) {							\
-  long __res;								\
+#define _syscall1(type,name,type1,arg1) 				\
+type name(type1 arg1) { 						\
+  register long __r0 __asm__("r0") = (long)arg1;			\
+  register long __res __asm__("r0");					\
   __asm__ __volatile__ (						\
-  "mov\tr0,%1\n\t"							\
   __syscall(name)							\
-  "mov %0,r0"								\
-        : "=r" (__res)							\
-        : "r" ((long)(arg1))						\
-	: "r0","lr");							\
+	: "=r" (__res)							\
+	: "r" (__r0)							\
+	: "lr");							\
   __syscall_return(type,__res);						\
 }
 
 #define _syscall2(type,name,type1,arg1,type2,arg2)			\
 type name(type1 arg1,type2 arg2) {					\
-  long __res;								\
+  register long __r0 __asm__("r0") = (long)arg1;			\
+  register long __r1 __asm__("r1") = (long)arg2;			\
+  register long __res __asm__("r0");					\
   __asm__ __volatile__ (						\
-  "mov\tr0,%1\n\t"							\
-  "mov\tr1,%2\n\t"							\
   __syscall(name)							\
-  "mov\t%0,r0"								\
-        : "=r" (__res)							\
-        : "r" ((long)(arg1)),"r" ((long)(arg2))				\
-	: "r0","r1","lr");						\
+	: "=r" (__res)							\
+	: "r" (__r0),"r" (__r1) 					\
+	: "lr");							\
   __syscall_return(type,__res);						\
 }
 
 
 #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)		\
 type name(type1 arg1,type2 arg2,type3 arg3) {				\
-  long __res;								\
+  register long __r0 __asm__("r0") = (long)arg1;			\
+  register long __r1 __asm__("r1") = (long)arg2;			\
+  register long __r2 __asm__("r2") = (long)arg3;			\
+  register long __res __asm__("r0");					\
   __asm__ __volatile__ (						\
-  "mov\tr0,%1\n\t"							\
-  "mov\tr1,%2\n\t"							\
-  "mov\tr2,%3\n\t"							\
   __syscall(name)							\
-  "mov\t%0,r0"								\
-        : "=r" (__res)							\
-        : "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3))	\
-        : "r0","r1","r2","lr");						\
+	: "=r" (__res)							\
+	: "r" (__r0),"r" (__r1),"r" (__r2)				\
+	: "lr");							\
   __syscall_return(type,__res);						\
 }
 
 
-#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4)		\
-type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) {				\
-  long __res;										\
-  __asm__ __volatile__ (								\
-  "mov\tr0,%1\n\t"									\
-  "mov\tr1,%2\n\t"									\
-  "mov\tr2,%3\n\t"									\
-  "mov\tr3,%4\n\t"									\
-  __syscall(name)									\
-  "mov\t%0,r0"										\
-  	: "=r" (__res)									\
-  	: "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3)),"r" ((long)(arg4))	\
-  	: "r0","r1","r2","r3","lr");							\
-  __syscall_return(type,__res);								\
+#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4)\
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) {		\
+  register long __r0 __asm__("r0") = (long)arg1;			\
+  register long __r1 __asm__("r1") = (long)arg2;			\
+  register long __r2 __asm__("r2") = (long)arg3;			\
+  register long __r3 __asm__("r3") = (long)arg4;			\
+  register long __res __asm__("r0");					\
+  __asm__ __volatile__ (						\
+  __syscall(name)							\
+	: "=r" (__res)							\
+	: "r" (__r0),"r" (__r1),"r" (__r2),"r" (__r3)			\
+	: "lr");							\
+  __syscall_return(type,__res);						\
 }
   
 
 #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5)	\
-type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) {			\
-  long __res;										\
-  __asm__ __volatile__ (								\
-  "mov\tr0,%1\n\t"									\
-  "mov\tr1,%2\n\t"									\
-  "mov\tr2,%3\n\t"									\
-  "mov\tr3,%4\n\t"									\
-  "mov\tr4,%5\n\t"									\
-  __syscall(name)									\
-  "mov\t%0,r0"										\
-  	: "=r" (__res)									\
-  	: "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3)),"r" ((long)(arg4)),	\
-	  "r" ((long)(arg5))								\
-	: "r0","r1","r2","r3","r4","lr");						\
-  __syscall_return(type,__res);								\
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) {	\
+  register long __r0 __asm__("r0") = (long)arg1;			\
+  register long __r1 __asm__("r1") = (long)arg2;			\
+  register long __r2 __asm__("r2") = (long)arg3;			\
+  register long __r3 __asm__("r3") = (long)arg4;			\
+  register long __r4 __asm__("r4") = (long)arg5;			\
+  register long __res __asm__("r0");					\
+  __asm__ __volatile__ (						\
+  __syscall(name)							\
+	: "=r" (__res)							\
+	: "r" (__r0),"r" (__r1),"r" (__r2),"r" (__r3),"r" (__r4)	\
+	: "lr");							\
+  __syscall_return(type,__res);						\
+}
+
+#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5,type6,arg6)	\
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6) {	\
+  register long __r0 __asm__("r0") = (long)arg1;			\
+  register long __r1 __asm__("r1") = (long)arg2;			\
+  register long __r2 __asm__("r2") = (long)arg3;			\
+  register long __r3 __asm__("r3") = (long)arg4;			\
+  register long __r4 __asm__("r4") = (long)arg5;			\
+  register long __r5 __asm__("r5") = (long)arg6;			\
+  register long __res __asm__("r0");					\
+  __asm__ __volatile__ (						\
+  __syscall(name)							\
+	: "=r" (__res)							\
+	: "r" (__r0),"r" (__r1),"r" (__r2),"r" (__r3), "r" (__r4),"r" (__r5)		\
+	: "lr");							\
+  __syscall_return(type,__res);						\
 }
 
 #ifdef __KERNEL_SYSCALLS__
diff -Nru a/include/asm-cris/topology.h b/include/asm-cris/topology.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-cris/topology.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,6 @@
+#ifndef _ASM_CRIS_TOPOLOGY_H
+#define _ASM_CRIS_TOPOLOGY_H
+
+#include <asm-generic/topology.h>
+
+#endif /* _ASM_CRIS_TOPOLOGY_H */
diff -Nru a/include/asm-generic/topology.h b/include/asm-generic/topology.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-generic/topology.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,51 @@
+/*
+ * linux/include/asm-generic/topology.h
+ *
+ * Written by: Matthew Dobson, IBM Corporation
+ *
+ * Copyright (C) 2002, IBM Corp.
+ *
+ * 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.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  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.
+ *
+ * Send feedback to <colpatch@us.ibm.com>
+ */
+#ifndef _ASM_GENERIC_TOPOLOGY_H
+#define _ASM_GENERIC_TOPOLOGY_H
+
+/* Other architectures wishing to use this simple topology API should fill
+   in the below functions as appropriate in their own <asm/topology.h> file. */
+#ifndef __cpu_to_node
+#define __cpu_to_node(cpu)		(0)
+#endif
+#ifndef __memblk_to_node
+#define __memblk_to_node(memblk)	(0)
+#endif
+#ifndef __parent_node
+#define __parent_node(node)		(0)
+#endif
+#ifndef __node_to_first_cpu
+#define __node_to_first_cpu(node)	(0)
+#endif
+#ifndef __node_to_cpu_mask
+#define __node_to_cpu_mask(node)	(cpu_online_map)
+#endif
+#ifndef __node_to_memblk
+#define __node_to_memblk(node)		(0)
+#endif
+
+#endif /* _ASM_GENERIC_TOPOLOGY_H */
diff -Nru a/include/asm-i386/mmzone.h b/include/asm-i386/mmzone.h
--- a/include/asm-i386/mmzone.h	Tue Oct  1 00:08:17 2002
+++ b/include/asm-i386/mmzone.h	Tue Oct  1 00:08:17 2002
@@ -14,14 +14,7 @@
 #include <asm/numaq.h>
 #else
 #define pfn_to_nid(pfn)		(0)
-#ifdef CONFIG_NUMA
-#define _cpu_to_node(cpu) 0
-#endif /* CONFIG_NUMA */
 #endif /* CONFIG_X86_NUMAQ */
-
-#ifdef CONFIG_NUMA
-#define numa_node_id() _cpu_to_node(smp_processor_id())
-#endif /* CONFIG_NUMA */
 
 extern struct pglist_data *node_data[];
 
diff -Nru a/include/asm-i386/msr.h b/include/asm-i386/msr.h
--- a/include/asm-i386/msr.h	Tue Oct  1 00:08:14 2002
+++ b/include/asm-i386/msr.h	Tue Oct  1 00:08:14 2002
@@ -125,4 +125,10 @@
 #define MSR_VIA_LONGHAUL		0x110a
 #define MSR_VIA_BCR2			0x1147
 
+/* Transmeta defined MSRs */
+#define MSR_TMTA_LONGRUN_CTRL		0x80868010
+#define MSR_TMTA_LONGRUN_FLAGS		0x80868011
+#define MSR_TMTA_LRTI_READOUT		0x80868018
+#define MSR_TMTA_LRTI_VOLT_MHZ		0x8086801a
+
 #endif /* __ASM_MSR_H */
diff -Nru a/include/asm-i386/numaq.h b/include/asm-i386/numaq.h
--- a/include/asm-i386/numaq.h	Tue Oct  1 00:08:17 2002
+++ b/include/asm-i386/numaq.h	Tue Oct  1 00:08:17 2002
@@ -41,9 +41,6 @@
 #define pfn_to_pgdat(pfn) NODE_DATA(pfn_to_nid(pfn))
 #define PHYSADDR_TO_NID(pa) pfn_to_nid(pa >> PAGE_SHIFT)
 #define MAX_NUMNODES		8
-#ifdef CONFIG_NUMA
-#define _cpu_to_node(cpu) (cpu_to_logical_apicid(cpu) >> 4)
-#endif /* CONFIG_NUMA */
 extern int pfn_to_nid(unsigned long);
 extern void get_memcfg_numaq(void);
 #define get_memcfg_numa() get_memcfg_numaq()
diff -Nru a/include/asm-i386/topology.h b/include/asm-i386/topology.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-i386/topology.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,96 @@
+/*
+ * linux/include/asm-i386/topology.h
+ *
+ * Written by: Matthew Dobson, IBM Corporation
+ *
+ * Copyright (C) 2002, IBM Corp.
+ *
+ * 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.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  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.
+ *
+ * Send feedback to <colpatch@us.ibm.com>
+ */
+#ifndef _ASM_I386_TOPOLOGY_H
+#define _ASM_I386_TOPOLOGY_H
+
+#ifdef CONFIG_X86_NUMAQ
+
+#include <asm/smpboot.h>
+
+/* Returns the number of the node containing CPU 'cpu' */
+#define __cpu_to_node(cpu) (cpu_to_logical_apicid(cpu) >> 4)
+
+/* Returns the number of the node containing MemBlk 'memblk' */
+#define __memblk_to_node(memblk) (memblk)
+
+/* Returns the number of the node containing Node 'node'.  This architecture is flat, 
+   so it is a pretty simple function! */
+#define __parent_node(node) (node)
+
+/* Returns the number of the first CPU on Node 'node'.
+ * This should be changed to a set of cached values
+ * but this will do for now.
+ */
+static inline int __node_to_first_cpu(int node)
+{
+	int i, cpu, logical_apicid = node << 4;
+
+	for(i = 1; i < 16; i <<= 1)
+		/* check to see if the cpu is in the system */
+		if ((cpu = logical_apicid_to_cpu(logical_apicid | i)) >= 0)
+			/* if yes, return it to caller */
+			return cpu;
+
+	BUG(); /* couldn't find a cpu on given node */
+	return -1;
+}
+
+/* Returns a bitmask of CPUs on Node 'node'.
+ * This should be changed to a set of cached bitmasks
+ * but this will do for now.
+ */
+static inline unsigned long __node_to_cpu_mask(int node)
+{
+	int i, cpu, logical_apicid = node << 4;
+	unsigned long mask = 0UL;
+
+	if (sizeof(unsigned long) * 8 < NR_CPUS)
+		BUG();
+
+	for(i = 1; i < 16; i <<= 1)
+		/* check to see if the cpu is in the system */
+		if ((cpu = logical_apicid_to_cpu(logical_apicid | i)) >= 0)
+			/* if yes, add to bitmask */
+			mask |= 1 << cpu;
+
+	return mask;
+}
+
+/* Returns the number of the first MemBlk on Node 'node' */
+#define __node_to_memblk(node) (node)
+
+#else /* !CONFIG_X86_NUMAQ */
+/*
+ * Other i386 platforms should define their own version of the 
+ * above macros here.
+ */
+
+#include <asm-generic/topology.h>
+
+#endif /* CONFIG_X86_NUMAQ */
+
+#endif /* _ASM_I386_TOPOLOGY_H */
diff -Nru a/include/asm-ia64/topology.h b/include/asm-ia64/topology.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ia64/topology.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,6 @@
+#ifndef _ASM_IA64_TOPOLOGY_H
+#define _ASM_IA64_TOPOLOGY_H
+
+#include <asm-generic/topology.h>
+
+#endif /* _ASM_IA64_TOPOLOGY_H */
diff -Nru a/include/asm-m68k/topology.h b/include/asm-m68k/topology.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-m68k/topology.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,6 @@
+#ifndef _ASM_M68K_TOPOLOGY_H
+#define _ASM_M68K_TOPOLOGY_H
+
+#include <asm-generic/topology.h>
+
+#endif /* _ASM_M68K_TOPOLOGY_H */
diff -Nru a/include/asm-mips/topology.h b/include/asm-mips/topology.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-mips/topology.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,6 @@
+#ifndef _ASM_MIPS_TOPOLOGY_H
+#define _ASM_MIPS_TOPOLOGY_H
+
+#include <asm-generic/topology.h>
+
+#endif /* _ASM_MIPS_TOPOLOGY_H */
diff -Nru a/include/asm-mips64/mmzone.h b/include/asm-mips64/mmzone.h
--- a/include/asm-mips64/mmzone.h	Tue Oct  1 00:08:15 2002
+++ b/include/asm-mips64/mmzone.h	Tue Oct  1 00:08:15 2002
@@ -28,8 +28,6 @@
 #define PLAT_NODE_DATA_LOCALNR(p, n) \
 		(((p) >> PAGE_SHIFT) - PLAT_NODE_DATA(n)->gendata.node_start_pfn)
 
-#define numa_node_id()	cputocnode(current->processor)
-
 #ifdef CONFIG_DISCONTIGMEM
 
 /*
diff -Nru a/include/asm-mips64/topology.h b/include/asm-mips64/topology.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-mips64/topology.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,8 @@
+#ifndef _ASM_MIPS64_TOPOLOGY_H
+#define _ASM_MIPS64_TOPOLOGY_H
+
+#include <asm/mmzone.h>
+
+#define __cpu_to_node(cpu)		(cputocnode(cpu))
+
+#endif /* _ASM_MIPS64_TOPOLOGY_H */
diff -Nru a/include/asm-parisc/topology.h b/include/asm-parisc/topology.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-parisc/topology.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,6 @@
+#ifndef _ASM_PARISC_TOPOLOGY_H
+#define _ASM_PARISC_TOPOLOGY_H
+
+#include <asm-generic/topology.h>
+
+#endif /* _ASM_PARISC_TOPOLOGY_H */
diff -Nru a/include/asm-ppc/topology.h b/include/asm-ppc/topology.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ppc/topology.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,6 @@
+#ifndef _ASM_PPC_TOPOLOGY_H
+#define _ASM_PPC_TOPOLOGY_H
+
+#include <asm-generic/topology.h>
+
+#endif /* _ASM_PPC_TOPOLOGY_H */
diff -Nru a/include/asm-ppc64/mmzone.h b/include/asm-ppc64/mmzone.h
--- a/include/asm-ppc64/mmzone.h	Tue Oct  1 00:08:20 2002
+++ b/include/asm-ppc64/mmzone.h	Tue Oct  1 00:08:20 2002
@@ -56,25 +56,6 @@
 #define node_size(nid)		(NODE_DATA(nid)->node_size)
 #define node_localnr(pfn, nid)	((pfn) - NODE_DATA(nid)->node_start_pfn)
 
-#ifdef CONFIG_NUMA
-
-static inline int __cpu_to_node(int cpu)
-{
-	int node;
-
-	node = numa_cpu_lookup_table[cpu];
-
-#ifdef DEBUG_NUMA
-	if (node == -1)
-		BUG();
-#endif
-
-	return node;
-}
-
-#define numa_node_id()	__cpu_to_node(smp_processor_id())
-#endif /* CONFIG_NUMA */
-
 /*
  * Following are macros that each numa implmentation must define.
  */
diff -Nru a/include/asm-ppc64/topology.h b/include/asm-ppc64/topology.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ppc64/topology.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,60 @@
+#ifndef _ASM_PPC64_TOPOLOGY_H
+#define _ASM_PPC64_TOPOLOGY_H
+
+#include <asm/mmzone.h>
+
+#ifdef CONFIG_NUMA
+
+static inline int __cpu_to_node(int cpu)
+{
+	int node;
+
+	node = numa_cpu_lookup_table[cpu];
+
+#ifdef DEBUG_NUMA
+	if (node == -1)
+		BUG();
+#endif
+
+	return node;
+}
+
+static inline int __node_to_first_cpu(int node)
+{
+	int cpu;
+
+	for(cpu = 0; cpu < NR_CPUS; cpu++)
+		if (numa_cpu_lookup_table[cpu] == node)
+			return cpu;
+
+	BUG(); /* couldn't find a cpu on given node */
+	return -1;
+}
+
+static inline unsigned long __node_to_cpu_mask(int node)
+{
+	int cpu;
+	unsigned long mask = 0UL;
+
+	if (sizeof(unsigned long) * 8 < NR_CPUS)
+		BUG();
+
+	for(cpu = 0; cpu < NR_CPUS; cpu++)
+		if (numa_cpu_lookup_table[cpu] == node)
+			mask |= 1 << cpu;
+
+	return mask;
+}
+
+#else /* !CONFIG_NUMA */
+
+#define __cpu_to_node(cpu)		(0)
+#define __memblk_to_node(memblk)	(0)
+#define __parent_node(nid)		(0)
+#define __node_to_first_cpu(node)	(0)
+#define __node_to_cpu_mask(node)	(cpu_online_map)
+#define __node_to_memblk(node)		(0)
+
+#endif /* CONFIG_NUMA */
+
+#endif /* _ASM_PPC64_TOPOLOGY_H */
diff -Nru a/include/asm-s390/qdio.h b/include/asm-s390/qdio.h
--- a/include/asm-s390/qdio.h	Tue Oct  1 00:08:15 2002
+++ b/include/asm-s390/qdio.h	Tue Oct  1 00:08:15 2002
@@ -82,8 +82,6 @@
 #define QDIO_CLEANUP_CLEAR_TIMEOUT 20000
 #define QDIO_CLEANUP_HALT_TIMEOUT 10000
 
-#define QDIO_BH AURORA_BH
-
 #define QDIO_IRQ_BUCKETS 256 /* heavy..., but does only use a few bytes, but
 			      be rather faster in cases of collisions
 			      (if there really is a collision, it is
diff -Nru a/include/asm-s390/topology.h b/include/asm-s390/topology.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-s390/topology.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,6 @@
+#ifndef _ASM_S390_TOPOLOGY_H
+#define _ASM_S390_TOPOLOGY_H
+
+#include <asm-generic/topology.h>
+
+#endif /* _ASM_S390_TOPOLOGY_H */
diff -Nru a/include/asm-s390x/qdio.h b/include/asm-s390x/qdio.h
--- a/include/asm-s390x/qdio.h	Tue Oct  1 00:08:17 2002
+++ b/include/asm-s390x/qdio.h	Tue Oct  1 00:08:17 2002
@@ -83,8 +83,6 @@
 #define QDIO_CLEANUP_CLEAR_TIMEOUT 20000
 #define QDIO_CLEANUP_HALT_TIMEOUT 10000
 
-#define QDIO_BH AURORA_BH
-
 #define QDIO_IRQ_BUCKETS 256 /* heavy..., but does only use a few bytes, but
 			      be rather faster in cases of collisions
 			      (if there really is a collision, it is
diff -Nru a/include/asm-s390x/topology.h b/include/asm-s390x/topology.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-s390x/topology.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,6 @@
+#ifndef _ASM_S390X_TOPOLOGY_H
+#define _ASM_S390X_TOPOLOGY_H
+
+#include <asm-generic/topology.h>
+
+#endif /* _ASM_S390X_TOPOLOGY_H */
diff -Nru a/include/asm-sh/topology.h b/include/asm-sh/topology.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-sh/topology.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,6 @@
+#ifndef _ASM_SH_TOPOLOGY_H
+#define _ASM_SH_TOPOLOGY_H
+
+#include <asm-generic/topology.h>
+
+#endif /* _ASM_SH_TOPOLOGY_H */
diff -Nru a/include/asm-sparc/audioio.h b/include/asm-sparc/audioio.h
--- a/include/asm-sparc/audioio.h	Tue Oct  1 00:08:17 2002
+++ b/include/asm-sparc/audioio.h	Tue Oct  1 00:08:17 2002
@@ -231,414 +231,4 @@
  */
 #define	AUDIO_DIAG_LOOPBACK	_IOW('A', 101, int)
 
-/*
- *	Linux kernel internal implementation.
- */
-
-#ifdef __KERNEL__
-
-#include <linux/fs.h>
-#include <linux/tqueue.h>
-#include <linux/wait.h>
-
-#define	SDF_OPEN_WRITE	0x00000001
-#define	SDF_OPEN_READ	0x00000002
-
-struct sparcaudio_ringbuffer
-{
-  __u8 *rb_start, *rb_end;		/* start, end of this memory buffer */
-  __u8 *rb_in, *rb_out;			/* input, output pointers */
-
-  int rb_fragsize;			/* size of an audio frag */
-  int rb_numfrags;			/* number of frags */
-
-  int rb_count, rb_hiwat, rb_lowat;	/* bytes in use, hi/lo wat points */
-
-  int rb_bufsize;			/* total size of buffer */
-};
-
-struct sparcaudio_driver
-{
-	const char * name;
-	struct sparcaudio_operations *ops;
-	void *private;
-	unsigned long flags;
-        struct strevent *sd_siglist;
-        /* duplex: 0=simplex, 1=duplex, 2=loop */
-        int sd_sigflags, duplex;
-
-        /* Which audio device are we? */
-        int index; 
-
-        /* This device */
-        struct sbus_dev *dev;
-
-	/* Processes blocked on open() sit here. */
-	wait_queue_head_t open_wait;
-
-	/* Task queue for this driver's bottom half. */
-	struct tq_struct tqueue;
-
-        /* Start of ring buffer support */
-        __u8 *input_buffer, *output_buffer;
-
-	/* Support for a circular queue of output buffers. */
-	__u8 **output_buffers;
-	size_t *output_sizes, output_size, output_buffer_size;
-	int num_output_buffers, output_front, output_rear, output_offset;
-	int output_count, output_active, playing_count, output_eof;
-	wait_queue_head_t output_write_wait, output_drain_wait;
-        char *output_notify;
-
-        /* Support for a circular queue of input buffers. */
-        __u8 **input_buffers;
-	size_t *input_sizes, input_size, input_buffer_size;
-        int num_input_buffers, input_front, input_rear, input_offset;
-        int input_count, input_active, recording_count;
-        wait_queue_head_t input_read_wait;
-
-        /* Hack to make it look like we support variable size buffers. */
-        int buffer_size;
-
-        int mixer_modify_counter;
-};
-
-struct sparcaudio_operations
-{
-	int (*open)(struct inode *, struct file *, struct sparcaudio_driver *);
-	void (*release)(struct inode *, struct file *, struct sparcaudio_driver *);
-	int (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long,
-		     struct sparcaudio_driver *);
-
-	/* Ask driver to begin playing a buffer. */
-	void (*start_output)(struct sparcaudio_driver *, __u8 *, unsigned long);
-
-	/* Ask driver to stop playing a buffer. */
-	void (*stop_output)(struct sparcaudio_driver *);
-
-	/* Ask driver to begin recording into a buffer. */
-	void (*start_input)(struct sparcaudio_driver *, __u8 *, unsigned long);
-
-	/* Ask driver to stop recording. */
-	void (*stop_input)(struct sparcaudio_driver *);
-
-	/* Return driver name/version to caller. (/dev/audio specific) */
-	void (*sunaudio_getdev)(struct sparcaudio_driver *, audio_device_t *);
-
-        /* Get and set the output volume. (0-255) */
-        int (*set_output_volume)(struct sparcaudio_driver *, int);
-        int (*get_output_volume)(struct sparcaudio_driver *);
-
-        /* Get and set the input volume. (0-255) */
-        int (*set_input_volume)(struct sparcaudio_driver *, int);
-        int (*get_input_volume)(struct sparcaudio_driver *);
-
-        /* Get and set the monitor volume. (0-255) */
-        int (*set_monitor_volume)(struct sparcaudio_driver *, int);
-        int (*get_monitor_volume)(struct sparcaudio_driver *);
-
-        /* Get and set the output balance. (0-64) */
-        int (*set_output_balance)(struct sparcaudio_driver *, int);
-        int (*get_output_balance)(struct sparcaudio_driver *);
-
-        /* Get and set the input balance. (0-64) */
-        int (*set_input_balance)(struct sparcaudio_driver *, int);
-        int (*get_input_balance)(struct sparcaudio_driver *);
-
-        /* Get and set the output channels. (1-4) */
-        int (*set_output_channels)(struct sparcaudio_driver *, int);
-        int (*get_output_channels)(struct sparcaudio_driver *);
-
-        /* Get and set the input channels. (1-4) */
-        int (*set_input_channels)(struct sparcaudio_driver *, int);
-        int (*get_input_channels)(struct sparcaudio_driver *);
-
-        /* Get and set the output precision. (8-32) */
-        int (*set_output_precision)(struct sparcaudio_driver *, int);
-        int (*get_output_precision)(struct sparcaudio_driver *);
-
-        /* Get and set the input precision. (8-32) */
-        int (*set_input_precision)(struct sparcaudio_driver *, int);
-        int (*get_input_precision)(struct sparcaudio_driver *);
-
-        /* Get and set the output port. () */
-        int (*set_output_port)(struct sparcaudio_driver *, int);
-        int (*get_output_port)(struct sparcaudio_driver *);
-
-        /* Get and set the input port. () */
-        int (*set_input_port)(struct sparcaudio_driver *, int);
-        int (*get_input_port)(struct sparcaudio_driver *);
-
-        /* Get and set the output encoding. () */
-        int (*set_output_encoding)(struct sparcaudio_driver *, int);
-        int (*get_output_encoding)(struct sparcaudio_driver *);
-
-        /* Get and set the input encoding. () */
-        int (*set_input_encoding)(struct sparcaudio_driver *, int);
-        int (*get_input_encoding)(struct sparcaudio_driver *);
-
-        /* Get and set the output rate. () */
-        int (*set_output_rate)(struct sparcaudio_driver *, int);
-        int (*get_output_rate)(struct sparcaudio_driver *);
-
-        /* Get and set the input rate. () */
-        int (*set_input_rate)(struct sparcaudio_driver *, int);
-        int (*get_input_rate)(struct sparcaudio_driver *);
-
-	/* Return driver number to caller. (SunOS /dev/audio specific) */
-	int (*sunaudio_getdev_sunos)(struct sparcaudio_driver *);
-
-        /* Get available ports */
-        int (*get_output_ports)(struct sparcaudio_driver *);
-        int (*get_input_ports)(struct sparcaudio_driver *);
-
-        /* Get and set output mute */
-        int (*set_output_muted)(struct sparcaudio_driver *, int);
-        int (*get_output_muted)(struct sparcaudio_driver *);
-
-        /* Get and set output pause */
-        int (*set_output_pause)(struct sparcaudio_driver *, int);
-        int (*get_output_pause)(struct sparcaudio_driver *);
-
-        /* Get and set input pause */
-        int (*set_input_pause)(struct sparcaudio_driver *, int);
-        int (*get_input_pause)(struct sparcaudio_driver *);
-
-        /* Get and set output samples */
-        int (*set_output_samples)(struct sparcaudio_driver *, int);
-        int (*get_output_samples)(struct sparcaudio_driver *);
-
-        /* Get and set input samples */
-        int (*set_input_samples)(struct sparcaudio_driver *, int);
-        int (*get_input_samples)(struct sparcaudio_driver *);
-
-        /* Get and set output error */
-        int (*set_output_error)(struct sparcaudio_driver *, int);
-        int (*get_output_error)(struct sparcaudio_driver *);
-
-        /* Get and set input error */
-        int (*set_input_error)(struct sparcaudio_driver *, int);
-        int (*get_input_error)(struct sparcaudio_driver *);
-
-        /* Get supported encodings */
-        int (*get_formats)(struct sparcaudio_driver *);
-};
-
-extern int register_sparcaudio_driver(struct sparcaudio_driver *, int);
-extern int unregister_sparcaudio_driver(struct sparcaudio_driver *, int);
-extern void sparcaudio_output_done(struct sparcaudio_driver *, int);
-extern void sparcaudio_input_done(struct sparcaudio_driver *, int);
-
-#endif
-
-/* Device minor numbers */
-
-#define SPARCAUDIO_MIXER_MINOR 0
-/* No sequencer (1) */
-/* No midi (2) */
-#define SPARCAUDIO_DSP_MINOR   3
-#define SPARCAUDIO_AUDIO_MINOR 4
-#define SPARCAUDIO_DSP16_MINOR 5
-#define SPARCAUDIO_STATUS_MINOR 6
-#define SPARCAUDIO_AUDIOCTL_MINOR 7
-/* No sequencer l2 (8) */
-/* No sound processor (9) */
-
-/* allocate 2^SPARCAUDIO_DEVICE_SHIFT minors per audio device */
-#define SPARCAUDIO_DEVICE_SHIFT 4
-
-/* With the coming of dummy devices this should perhaps be as high as 5? */
-#define SPARCAUDIO_MAX_DEVICES 3
-
-/* Streams crap for realaudio */
-
-typedef
-struct strevent {
-    struct strevent *se_next;   /* next event for this stream or NULL*/
-    struct strevent *se_prev;   /* previous event for this stream or last
-                                 * event if this is the first one*/
-    pid_t se_pid;               /* process to be signaled */
-    short se_evs;               /* events wanted */
-} strevent_t;
-
-typedef
-struct stdata
-{
-        struct stdata    *sd_next ;     /* all stdatas are linked together */
-        struct stdata    *sd_prev ;
-        struct strevent   *sd_siglist;  /* processes to be sent SIGPOLL */
-        int  sd_sigflags;               /* logical OR of all siglist events */
-} stdata_t;
-
-#define I_NREAD _IOR('S',01, int)
-#define I_NREAD_SOLARIS (('S'<<8)|1)
-
-#define I_FLUSH _IO('S',05)
-#define I_FLUSH_SOLARIS (('S'<<8)|5)
-#define FLUSHR  1                       /* flush read queue */
-#define FLUSHW  2                       /* flush write queue */
-#define FLUSHRW 3                       /* flush both queues */
-
-#define I_SETSIG _IO('S',011)
-#define I_SETSIG_SOLARIS (('S'<<8)|11)
-#define S_INPUT         0x01
-#define S_HIPRI         0x02           
-#define S_OUTPUT        0x04           
-#define S_MSG           0x08           
-#define S_ERROR         0x0010         
-#define S_HANGUP        0x0020         
-#define S_RDNORM        0x0040         
-#define S_WRNORM        S_OUTPUT
-#define S_RDBAND        0x0080         
-#define S_WRBAND        0x0100         
-#define S_BANDURG       0x0200         
-#define S_ALL           0x03FF
-
-#define I_GETSIG _IOR('S',012,int)
-#define I_GETSIG_SOLARIS (('S'<<8)|12)
-
-/* Conversion between Sun and OSS volume settings */
-static __inline__ 
-int OSS_LEFT(int value)
-{
-  return ((value & 0xff) % 101);
-}
-
-static __inline__ 
-int OSS_RIGHT(int value)
-{
-  return  (((value >> 8) & 0xff) % 101);
-}
-
-static __inline__ 
-int O_TO_S(int value)
-{
-  return value * 255 / 100;
-}
-
-static __inline__ 
-int S_TO_O(int value)
-{
-  return value * 100 / 255;
-}
-
-static __inline__ 
-int OSS_TO_GAIN(int value)
-{
-  int l = O_TO_S(OSS_LEFT(value));
-  int r = O_TO_S(OSS_RIGHT(value));
-  return ((l > r) ? l : r);
-}
-
-static __inline__ 
-int OSS_TO_LGAIN(int value)
-{
-  int l = O_TO_S(OSS_LEFT(value));
-  int r = O_TO_S(OSS_RIGHT(value));
-  return ((l < r) ? l : r);
-}
-
-static __inline__ 
-int OSS_TO_BAL(int value) 
-{
-  if (!OSS_TO_GAIN(value))
-    return AUDIO_MID_BALANCE;
-  if (!OSS_TO_LGAIN(value)) {
-    if (OSS_TO_GAIN(value) == OSS_TO_GAIN(OSS_RIGHT(value)))
-      return AUDIO_RIGHT_BALANCE;
-    else
-      return AUDIO_LEFT_BALANCE;
-  }
-  if (OSS_TO_GAIN(value) == OSS_TO_GAIN(OSS_RIGHT(value)))
-    return ((OSS_TO_GAIN(value) - OSS_TO_LGAIN(value)) >> AUDIO_BALANCE_SHIFT)
-      + AUDIO_MID_BALANCE;
-  else
-    return AUDIO_MID_BALANCE - ((OSS_TO_GAIN(value) - OSS_TO_LGAIN(value)) 
-				>> AUDIO_BALANCE_SHIFT);
-}
-
-static __inline__ 
-int BAL_TO_OSS(int value, unsigned char balance)
-{
-  int l, r, adj;
-  if (balance > 63) balance = 63;
-  if (balance < AUDIO_MID_BALANCE) {
-    l = (int)value * 100 / 255 + ((value * 100 % 255) > 0);
-    adj = ((AUDIO_MID_BALANCE - balance) << AUDIO_BALANCE_SHIFT);
-    if (adj < value)
-      r = (int)(value - adj)
-	* 100 / 255;
-    else r = 0;
-  } else if (balance > AUDIO_MID_BALANCE) {
-    r = (int)value * 100 / 255 + ((value * 100 % 255) > 0);
-    adj = ((balance - AUDIO_MID_BALANCE) << AUDIO_BALANCE_SHIFT);
-    if (adj < value)
-      l = (int)(value - adj)
-	* 100 / 255;
-    else l = 0;
-  } else {
-    l = r = (int)value * 100 / 255 + ((value * 100 % 255) > 0);
-  }
-
-  return ((r << 8) + l);
-}
-
-#ifdef __KERNEL__
-/* OSS mixer ioctl port handling */
-static __inline__
-int OSS_PORT_AUDIO(struct sparcaudio_driver *drv, unsigned int set) 
-{
-  int p;
-  if (drv->ops->get_output_port) {
-    p = drv->ops->get_output_port(drv);
-    if (p & set)
-      return 0x6464;
-  }  
-  return 0;
-}
-
-static __inline__
-int OSS_IPORT_AUDIO(struct sparcaudio_driver *drv, unsigned int set) 
-{
-  int p;
-  if (drv->ops->get_input_port) {
-    p = drv->ops->get_input_port(drv);
-    if (p & set)
-      return 0x6464;
-  }  
-  return 0;
-}
-
-static __inline__ 
-void OSS_TWIDDLE_PORT(struct sparcaudio_driver *drv, unsigned int ioctl, 
-		      unsigned int port, unsigned int set, unsigned int value) 
-{
-  if (ioctl == port) {
-    int p;
-    if (drv->ops->get_output_port && drv->ops->set_output_port) {
-      p = drv->ops->get_output_port(drv);
-      if ((value == 0) || ((p & set) && (OSS_LEFT(value) < 100)))
-	drv->ops->set_output_port(drv, p & ~(set));
-      else
-	drv->ops->set_output_port(drv, p | set);
-    }
-  }
-}
-
-static __inline__ 
-void OSS_TWIDDLE_IPORT(struct sparcaudio_driver *drv, unsigned int ioctl, 
-		      unsigned int port, unsigned int set, unsigned int value) 
-{
-  if (ioctl == port) {
-    int p;
-    if (drv->ops->get_input_port && drv->ops->set_input_port) {
-      p = drv->ops->get_input_port(drv);
-      if ((value == 0) || ((p & set) && (OSS_LEFT(value) < 100)))
-	drv->ops->set_input_port(drv, p & ~(set));
-      else
-	drv->ops->set_input_port(drv, p | set);
-    }
-  }
-}
-#endif /* __KERNEL__ */
 #endif /* _AUDIOIO_H_ */
diff -Nru a/include/asm-sparc/bitops.h b/include/asm-sparc/bitops.h
--- a/include/asm-sparc/bitops.h	Tue Oct  1 00:08:19 2002
+++ b/include/asm-sparc/bitops.h	Tue Oct  1 00:08:19 2002
@@ -267,7 +267,7 @@
 {
 	if (!x)
 		return 0;
-	return __ffs((unsigned long)x);
+	return __ffs((unsigned long)x) + 1;
 }
 
 /*
diff -Nru a/include/asm-sparc/irq.h b/include/asm-sparc/irq.h
--- a/include/asm-sparc/irq.h	Tue Oct  1 00:08:14 2002
+++ b/include/asm-sparc/irq.h	Tue Oct  1 00:08:14 2002
@@ -47,7 +47,7 @@
 #define clear_profile_irq(cpu) BTFIXUP_CALL(clear_profile_irq)(cpu)
 #define load_profile_irq(cpu,limit) BTFIXUP_CALL(load_profile_irq)(cpu,limit)
 
-extern void (*init_timers)(void (*lvl10_irq)(int, void *, struct pt_regs *));
+extern void (*sparc_init_timers)(void (*lvl10_irq)(int, void *, struct pt_regs *));
 extern void claim_ticker14(void (*irq_handler)(int, void *, struct pt_regs *),
 			   int irq,
 			   unsigned int timeout);
diff -Nru a/include/asm-sparc/topology.h b/include/asm-sparc/topology.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-sparc/topology.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,6 @@
+#ifndef _ASM_SPARC_TOPOLOGY_H
+#define _ASM_SPARC_TOPOLOGY_H
+
+#include <asm-generic/topology.h>
+
+#endif /* _ASM_SPARC_TOPOLOGY_H */
diff -Nru a/include/asm-sparc64/audioio.h b/include/asm-sparc64/audioio.h
--- a/include/asm-sparc64/audioio.h	Tue Oct  1 00:08:15 2002
+++ b/include/asm-sparc64/audioio.h	Tue Oct  1 00:08:15 2002
@@ -231,414 +231,4 @@
  */
 #define	AUDIO_DIAG_LOOPBACK	_IOW('A', 101, int)
 
-/*
- *	Linux kernel internal implementation.
- */
-
-#ifdef __KERNEL__
-
-#include <linux/fs.h>
-#include <linux/tqueue.h>
-#include <linux/wait.h>
-
-#define	SDF_OPEN_WRITE	0x00000001
-#define	SDF_OPEN_READ	0x00000002
-
-struct sparcaudio_ringbuffer
-{
-  __u8 *rb_start, *rb_end;		/* start, end of this memory buffer */
-  __u8 *rb_in, *rb_out;			/* input, output pointers */
-
-  int rb_fragsize;			/* size of an audio frag */
-  int rb_numfrags;			/* number of frags */
-
-  int rb_count, rb_hiwat, rb_lowat;	/* bytes in use, hi/lo wat points */
-
-  int rb_bufsize;			/* total size of buffer */
-};
-
-struct sparcaudio_driver
-{
-	const char * name;
-	struct sparcaudio_operations *ops;
-	void *private;
-	unsigned long flags;
-        struct strevent *sd_siglist;
-        /* duplex: 0=simplex, 1=duplex, 2=loop */
-        int sd_sigflags, duplex;
-
-        /* Which audio device are we? */
-        int index; 
-
-        /* This device */
-        struct sbus_dev *dev;
-
-	/* Processes blocked on open() sit here. */
-	wait_queue_head_t open_wait;
-
-	/* Task queue for this driver's bottom half. */
-	struct tq_struct tqueue;
-
-        /* Start of ring buffer support */
-        __u8 *input_buffer, *output_buffer;
-
-	/* Support for a circular queue of output buffers. */
-	__u8 **output_buffers;
-	size_t *output_sizes, output_size, output_buffer_size;
-	int num_output_buffers, output_front, output_rear, output_offset;
-	int output_count, output_active, playing_count, output_eof;
-	wait_queue_head_t output_write_wait, output_drain_wait;
-        char *output_notify;
-
-        /* Support for a circular queue of input buffers. */
-        __u8 **input_buffers;
-	size_t *input_sizes, input_size, input_buffer_size;
-        int num_input_buffers, input_front, input_rear, input_offset;
-        int input_count, input_active, recording_count;
-        wait_queue_head_t input_read_wait;
-
-        /* Hack to make it look like we support variable size buffers. */
-        int buffer_size;
-
-        int mixer_modify_counter;
-};
-
-struct sparcaudio_operations
-{
-	int (*open)(struct inode *, struct file *, struct sparcaudio_driver *);
-	void (*release)(struct inode *, struct file *, struct sparcaudio_driver *);
-	int (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long,
-		     struct sparcaudio_driver *);
-
-	/* Ask driver to begin playing a buffer. */
-	void (*start_output)(struct sparcaudio_driver *, __u8 *, unsigned long);
-
-	/* Ask driver to stop playing a buffer. */
-	void (*stop_output)(struct sparcaudio_driver *);
-
-	/* Ask driver to begin recording into a buffer. */
-	void (*start_input)(struct sparcaudio_driver *, __u8 *, unsigned long);
-
-	/* Ask driver to stop recording. */
-	void (*stop_input)(struct sparcaudio_driver *);
-
-	/* Return driver name/version to caller. (/dev/audio specific) */
-	void (*sunaudio_getdev)(struct sparcaudio_driver *, audio_device_t *);
-
-        /* Get and set the output volume. (0-255) */
-        int (*set_output_volume)(struct sparcaudio_driver *, int);
-        int (*get_output_volume)(struct sparcaudio_driver *);
-
-        /* Get and set the input volume. (0-255) */
-        int (*set_input_volume)(struct sparcaudio_driver *, int);
-        int (*get_input_volume)(struct sparcaudio_driver *);
-
-        /* Get and set the monitor volume. (0-255) */
-        int (*set_monitor_volume)(struct sparcaudio_driver *, int);
-        int (*get_monitor_volume)(struct sparcaudio_driver *);
-
-        /* Get and set the output balance. (0-64) */
-        int (*set_output_balance)(struct sparcaudio_driver *, int);
-        int (*get_output_balance)(struct sparcaudio_driver *);
-
-        /* Get and set the input balance. (0-64) */
-        int (*set_input_balance)(struct sparcaudio_driver *, int);
-        int (*get_input_balance)(struct sparcaudio_driver *);
-
-        /* Get and set the output channels. (1-4) */
-        int (*set_output_channels)(struct sparcaudio_driver *, int);
-        int (*get_output_channels)(struct sparcaudio_driver *);
-
-        /* Get and set the input channels. (1-4) */
-        int (*set_input_channels)(struct sparcaudio_driver *, int);
-        int (*get_input_channels)(struct sparcaudio_driver *);
-
-        /* Get and set the output precision. (8-32) */
-        int (*set_output_precision)(struct sparcaudio_driver *, int);
-        int (*get_output_precision)(struct sparcaudio_driver *);
-
-        /* Get and set the input precision. (8-32) */
-        int (*set_input_precision)(struct sparcaudio_driver *, int);
-        int (*get_input_precision)(struct sparcaudio_driver *);
-
-        /* Get and set the output port. () */
-        int (*set_output_port)(struct sparcaudio_driver *, int);
-        int (*get_output_port)(struct sparcaudio_driver *);
-
-        /* Get and set the input port. () */
-        int (*set_input_port)(struct sparcaudio_driver *, int);
-        int (*get_input_port)(struct sparcaudio_driver *);
-
-        /* Get and set the output encoding. () */
-        int (*set_output_encoding)(struct sparcaudio_driver *, int);
-        int (*get_output_encoding)(struct sparcaudio_driver *);
-
-        /* Get and set the input encoding. () */
-        int (*set_input_encoding)(struct sparcaudio_driver *, int);
-        int (*get_input_encoding)(struct sparcaudio_driver *);
-
-        /* Get and set the output rate. () */
-        int (*set_output_rate)(struct sparcaudio_driver *, int);
-        int (*get_output_rate)(struct sparcaudio_driver *);
-
-        /* Get and set the input rate. () */
-        int (*set_input_rate)(struct sparcaudio_driver *, int);
-        int (*get_input_rate)(struct sparcaudio_driver *);
-
-	/* Return driver number to caller. (SunOS /dev/audio specific) */
-	int (*sunaudio_getdev_sunos)(struct sparcaudio_driver *);
-
-        /* Get available ports */
-        int (*get_output_ports)(struct sparcaudio_driver *);
-        int (*get_input_ports)(struct sparcaudio_driver *);
-
-        /* Get and set output mute */
-        int (*set_output_muted)(struct sparcaudio_driver *, int);
-        int (*get_output_muted)(struct sparcaudio_driver *);
-
-        /* Get and set output pause */
-        int (*set_output_pause)(struct sparcaudio_driver *, int);
-        int (*get_output_pause)(struct sparcaudio_driver *);
-
-        /* Get and set input pause */
-        int (*set_input_pause)(struct sparcaudio_driver *, int);
-        int (*get_input_pause)(struct sparcaudio_driver *);
-
-        /* Get and set output samples */
-        int (*set_output_samples)(struct sparcaudio_driver *, int);
-        int (*get_output_samples)(struct sparcaudio_driver *);
-
-        /* Get and set input samples */
-        int (*set_input_samples)(struct sparcaudio_driver *, int);
-        int (*get_input_samples)(struct sparcaudio_driver *);
-
-        /* Get and set output error */
-        int (*set_output_error)(struct sparcaudio_driver *, int);
-        int (*get_output_error)(struct sparcaudio_driver *);
-
-        /* Get and set input error */
-        int (*set_input_error)(struct sparcaudio_driver *, int);
-        int (*get_input_error)(struct sparcaudio_driver *);
-
-        /* Get supported encodings */
-        int (*get_formats)(struct sparcaudio_driver *);
-};
-
-extern int register_sparcaudio_driver(struct sparcaudio_driver *, int);
-extern int unregister_sparcaudio_driver(struct sparcaudio_driver *, int);
-extern void sparcaudio_output_done(struct sparcaudio_driver *, int);
-extern void sparcaudio_input_done(struct sparcaudio_driver *, int);
-
-#endif
-
-/* Device minor numbers */
-
-#define SPARCAUDIO_MIXER_MINOR 0
-/* No sequencer (1) */
-/* No midi (2) */
-#define SPARCAUDIO_DSP_MINOR   3
-#define SPARCAUDIO_AUDIO_MINOR 4
-#define SPARCAUDIO_DSP16_MINOR 5
-#define SPARCAUDIO_STATUS_MINOR 6
-#define SPARCAUDIO_AUDIOCTL_MINOR 7
-/* No sequencer l2 (8) */
-/* No sound processor (9) */
-
-/* allocate 2^SPARCAUDIO_DEVICE_SHIFT minors per audio device */
-#define SPARCAUDIO_DEVICE_SHIFT 4
-
-/* With the coming of dummy devices this should perhaps be as high as 5? */
-#define SPARCAUDIO_MAX_DEVICES 3
-
-/* Streams crap for realaudio */
-
-typedef
-struct strevent {
-    struct strevent *se_next;   /* next event for this stream or NULL*/
-    struct strevent *se_prev;   /* previous event for this stream or last
-                                 * event if this is the first one*/
-    pid_t se_pid;               /* process to be signaled */
-    short se_evs;               /* events wanted */
-} strevent_t;
-
-typedef
-struct stdata
-{
-        struct stdata    *sd_next ;     /* all stdatas are linked together */
-        struct stdata    *sd_prev ;
-        struct strevent   *sd_siglist;  /* processes to be sent SIGPOLL */
-        int  sd_sigflags;               /* logical OR of all siglist events */
-} stdata_t;
-
-#define I_NREAD _IOR('S',01, int)
-#define I_NREAD_SOLARIS (('S'<<8)|1)
-
-#define I_FLUSH _IO('S',05)
-#define I_FLUSH_SOLARIS (('S'<<8)|5)
-#define FLUSHR  1                       /* flush read queue */
-#define FLUSHW  2                       /* flush write queue */
-#define FLUSHRW 3                       /* flush both queues */
-
-#define I_SETSIG _IO('S',011)
-#define I_SETSIG_SOLARIS (('S'<<8)|11)
-#define S_INPUT         0x01
-#define S_HIPRI         0x02           
-#define S_OUTPUT        0x04           
-#define S_MSG           0x08           
-#define S_ERROR         0x0010         
-#define S_HANGUP        0x0020         
-#define S_RDNORM        0x0040         
-#define S_WRNORM        S_OUTPUT
-#define S_RDBAND        0x0080         
-#define S_WRBAND        0x0100         
-#define S_BANDURG       0x0200         
-#define S_ALL           0x03FF
-
-#define I_GETSIG _IOR('S',012,int)
-#define I_GETSIG_SOLARIS (('S'<<8)|12)
-
-/* Conversion between Sun and OSS volume settings */
-static __inline__ 
-int OSS_LEFT(int value)
-{
-  return ((value & 0xff) % 101);
-}
-
-static __inline__ 
-int OSS_RIGHT(int value)
-{
-  return  (((value >> 8) & 0xff) % 101);
-}
-
-static __inline__ 
-int O_TO_S(int value)
-{
-  return value * 255 / 100;
-}
-
-static __inline__ 
-int S_TO_O(int value)
-{
-  return value * 100 / 255;
-}
-
-static __inline__ 
-int OSS_TO_GAIN(int value)
-{
-  int l = O_TO_S(OSS_LEFT(value));
-  int r = O_TO_S(OSS_RIGHT(value));
-  return ((l > r) ? l : r);
-}
-
-static __inline__ 
-int OSS_TO_LGAIN(int value)
-{
-  int l = O_TO_S(OSS_LEFT(value));
-  int r = O_TO_S(OSS_RIGHT(value));
-  return ((l < r) ? l : r);
-}
-
-static __inline__ 
-int OSS_TO_BAL(int value) 
-{
-  if (!OSS_TO_GAIN(value))
-    return AUDIO_MID_BALANCE;
-  if (!OSS_TO_LGAIN(value)) {
-    if (OSS_TO_GAIN(value) == OSS_TO_GAIN(OSS_RIGHT(value)))
-      return AUDIO_RIGHT_BALANCE;
-    else
-      return AUDIO_LEFT_BALANCE;
-  }
-  if (OSS_TO_GAIN(value) == OSS_TO_GAIN(OSS_RIGHT(value)))
-    return ((OSS_TO_GAIN(value) - OSS_TO_LGAIN(value)) >> AUDIO_BALANCE_SHIFT)
-      + AUDIO_MID_BALANCE;
-  else
-    return AUDIO_MID_BALANCE - ((OSS_TO_GAIN(value) - OSS_TO_LGAIN(value)) 
-				>> AUDIO_BALANCE_SHIFT);
-}
-
-static __inline__ 
-int BAL_TO_OSS(int value, unsigned char balance)
-{
-  int l, r, adj;
-  if (balance > 63) balance = 63;
-  if (balance < AUDIO_MID_BALANCE) {
-    l = (int)value * 100 / 255 + ((value * 100 % 255) > 0);
-    adj = ((AUDIO_MID_BALANCE - balance) << AUDIO_BALANCE_SHIFT);
-    if (adj < value)
-      r = (int)(value - adj)
-	* 100 / 255;
-    else r = 0;
-  } else if (balance > AUDIO_MID_BALANCE) {
-    r = (int)value * 100 / 255 + ((value * 100 % 255) > 0);
-    adj = ((balance - AUDIO_MID_BALANCE) << AUDIO_BALANCE_SHIFT);
-    if (adj < value)
-      l = (int)(value - adj)
-	* 100 / 255;
-    else l = 0;
-  } else {
-    l = r = (int)value * 100 / 255 + ((value * 100 % 255) > 0);
-  }
-
-  return ((r << 8) + l);
-}
-
-#ifdef __KERNEL__
-/* OSS mixer ioctl port handling */
-static __inline__
-int OSS_PORT_AUDIO(struct sparcaudio_driver *drv, unsigned int set) 
-{
-  int p;
-  if (drv->ops->get_output_port) {
-    p = drv->ops->get_output_port(drv);
-    if (p & set)
-      return 0x6464;
-  }  
-  return 0;
-}
-
-static __inline__
-int OSS_IPORT_AUDIO(struct sparcaudio_driver *drv, unsigned int set) 
-{
-  int p;
-  if (drv->ops->get_input_port) {
-    p = drv->ops->get_input_port(drv);
-    if (p & set)
-      return 0x6464;
-  }  
-  return 0;
-}
-
-static __inline__ 
-void OSS_TWIDDLE_PORT(struct sparcaudio_driver *drv, unsigned int ioctl, 
-		      unsigned int port, unsigned int set, unsigned int value) 
-{
-  if (ioctl == port) {
-    int p;
-    if (drv->ops->get_output_port && drv->ops->set_output_port) {
-      p = drv->ops->get_output_port(drv);
-      if ((value == 0) || ((p & set) && (OSS_LEFT(value) < 100)))
-	drv->ops->set_output_port(drv, p & ~(set));
-      else
-	drv->ops->set_output_port(drv, p | set);
-    }
-  }
-}
-
-static __inline__ 
-void OSS_TWIDDLE_IPORT(struct sparcaudio_driver *drv, unsigned int ioctl, 
-		      unsigned int port, unsigned int set, unsigned int value) 
-{
-  if (ioctl == port) {
-    int p;
-    if (drv->ops->get_input_port && drv->ops->set_input_port) {
-      p = drv->ops->get_input_port(drv);
-      if ((value == 0) || ((p & set) && (OSS_LEFT(value) < 100)))
-	drv->ops->set_input_port(drv, p & ~(set));
-      else
-	drv->ops->set_input_port(drv, p | set);
-    }
-  }
-}
-#endif /* __KERNEL__ */
 #endif /* _AUDIOIO_H_ */
diff -Nru a/include/asm-sparc64/bitops.h b/include/asm-sparc64/bitops.h
--- a/include/asm-sparc64/bitops.h	Tue Oct  1 00:08:15 2002
+++ b/include/asm-sparc64/bitops.h	Tue Oct  1 00:08:15 2002
@@ -146,7 +146,7 @@
 {
 	if (!x)
 		return 0;
-	return __ffs((unsigned long)x);
+	return __ffs((unsigned long)x) + 1;
 }
 
 /*
diff -Nru a/include/asm-sparc64/ebus.h b/include/asm-sparc64/ebus.h
--- a/include/asm-sparc64/ebus.h	Tue Oct  1 00:08:18 2002
+++ b/include/asm-sparc64/ebus.h	Tue Oct  1 00:08:18 2002
@@ -51,38 +51,34 @@
 	struct linux_prom_ebus_intmask	 ebus_intmask;
 };
 
-struct linux_ebus_dma {
-	unsigned int dcsr;
-	unsigned int dacr;
-	unsigned int dbcr;
+struct ebus_dma_info {
+	spinlock_t	lock;
+	unsigned long	regs;
+
+	unsigned int	flags;
+#define EBUS_DMA_FLAG_USE_EBDMA_HANDLER		0x00000001
+
+	/* These are only valid is EBUS_DMA_FLAG_USE_EBDMA_HANDLER is
+	 * set.
+	 */
+	void (*callback)(struct ebus_dma_info *p, int event, void *cookie);
+	void *client_cookie;
+	unsigned int	irq;
+#define EBUS_DMA_EVENT_ERROR	1
+#define EBUS_DMA_EVENT_DMA	2
+#define EBUS_DMA_EVENT_DEVICE	4
+
+	unsigned char	name[64];
 };
 
-#define EBUS_DCSR_INT_PEND	0x00000001
-#define EBUS_DCSR_ERR_PEND	0x00000002
-#define EBUS_DCSR_DRAIN		0x00000004
-#define EBUS_DCSR_INT_EN	0x00000010
-#define EBUS_DCSR_RESET		0x00000080
-#define EBUS_DCSR_WRITE		0x00000100
-#define EBUS_DCSR_EN_DMA	0x00000200
-#define EBUS_DCSR_CYC_PEND	0x00000400
-#define EBUS_DCSR_DIAG_RD_DONE	0x00000800
-#define EBUS_DCSR_DIAG_WR_DONE	0x00001000
-#define EBUS_DCSR_EN_CNT	0x00002000
-#define EBUS_DCSR_TC		0x00004000
-#define EBUS_DCSR_DIS_CSR_DRN	0x00010000
-#define EBUS_DCSR_BURST_SZ_MASK	0x000c0000
-#define EBUS_DCSR_BURST_SZ_1	0x00080000
-#define EBUS_DCSR_BURST_SZ_4	0x00000000
-#define EBUS_DCSR_BURST_SZ_8	0x00040000
-#define EBUS_DCSR_BURST_SZ_16	0x000c0000
-#define EBUS_DCSR_DIAG_EN	0x00100000
-#define EBUS_DCSR_DIS_ERR_PEND	0x00400000
-#define EBUS_DCSR_TCI_DIS	0x00800000
-#define EBUS_DCSR_EN_NEXT	0x01000000
-#define EBUS_DCSR_DMA_ON	0x02000000
-#define EBUS_DCSR_A_LOADED	0x04000000
-#define EBUS_DCSR_NA_LOADED	0x08000000
-#define EBUS_DCSR_DEV_ID_MASK	0xf0000000
+extern int ebus_dma_register(struct ebus_dma_info *p);
+extern int ebus_dma_irq_enable(struct ebus_dma_info *p, int on);
+extern void ebus_dma_unregister(struct ebus_dma_info *p);
+extern int ebus_dma_request(struct ebus_dma_info *p, dma_addr_t bus_addr,
+			    size_t len);
+extern void ebus_dma_prepare(struct ebus_dma_info *p, int write);
+extern unsigned int ebus_dma_residue(struct ebus_dma_info *p);
+extern void ebus_dma_enable(struct ebus_dma_info *p, int on);
 
 extern struct linux_ebus		*ebus_chain;
 
diff -Nru a/include/asm-sparc64/floppy.h b/include/asm-sparc64/floppy.h
--- a/include/asm-sparc64/floppy.h	Tue Oct  1 00:08:21 2002
+++ b/include/asm-sparc64/floppy.h	Tue Oct  1 00:08:21 2002
@@ -264,7 +264,7 @@
 #include <asm/isa.h>
 #include <asm/ns87303.h>
 
-static struct linux_ebus_dma *sun_pci_fd_ebus_dma;
+static struct ebus_dma_info sun_pci_fd_ebus_dma;
 static struct pci_dev *sun_pci_ebus_dev;
 static int sun_pci_broken_drive = -1;
 
@@ -330,26 +330,12 @@
 }
 #endif /* PCI_FDC_SWAP_DRIVES */
 
-static void sun_pci_fd_reset_dma(void)
-{
-	unsigned int dcsr;
-
-	writel(EBUS_DCSR_RESET, &sun_pci_fd_ebus_dma->dcsr);
-	udelay(1);
-	dcsr = EBUS_DCSR_BURST_SZ_16 | EBUS_DCSR_TCI_DIS |
-	       EBUS_DCSR_EN_CNT;
-	writel(dcsr, (unsigned long)&sun_pci_fd_ebus_dma->dcsr);
-}
-
 static void sun_pci_fd_enable_dma(void)
 {
-	unsigned int dcsr;
-
-	if((NULL == sun_pci_dma_pending.buf) 	||
-	   (0	== sun_pci_dma_pending.len) 	||
-	   (0	== sun_pci_dma_pending.direction)) {
-		goto enable; /* TODO: BUG() */
-	}
+	if ((NULL == sun_pci_dma_pending.buf) 	||
+	    (0	  == sun_pci_dma_pending.len) 	||
+	    (0	  == sun_pci_dma_pending.direction))
+		BUG();
 
 	sun_pci_dma_current.buf = sun_pci_dma_pending.buf;
 	sun_pci_dma_current.len = sun_pci_dma_pending.len;
@@ -361,36 +347,22 @@
 	sun_pci_dma_pending.addr = -1U;
 
 	sun_pci_dma_current.addr = 
-		pci_map_single(	sun_pci_ebus_dev,
-				sun_pci_dma_current.buf,
-				sun_pci_dma_current.len,
-				sun_pci_dma_current.direction);
-	writel(sun_pci_dma_current.addr, &sun_pci_fd_ebus_dma->dacr);
-
-enable:
-	dcsr = readl(&sun_pci_fd_ebus_dma->dcsr);
-	dcsr |= EBUS_DCSR_EN_DMA;
-	writel(dcsr, &sun_pci_fd_ebus_dma->dcsr);
+		pci_map_single(sun_pci_ebus_dev,
+			       sun_pci_dma_current.buf,
+			       sun_pci_dma_current.len,
+			       sun_pci_dma_current.direction);
+
+	if (ebus_dma_request(&sun_pci_fd_ebus_dma,
+			     sun_pci_dma_current.addr,
+			     sun_pci_dma_current.len))
+		BUG();
+
+	ebus_dma_enable(&sun_pci_fd_ebus_dma, 1);
 }
 
 static void sun_pci_fd_disable_dma(void)
 {
-	unsigned int dcsr;
-
-	dcsr = readl(&sun_pci_fd_ebus_dma->dcsr);
-	if (dcsr & EBUS_DCSR_EN_DMA) {
-		while (dcsr & EBUS_DCSR_DRAIN) {
-			udelay(1);
-			dcsr = readl(&sun_pci_fd_ebus_dma->dcsr);
-		}
-		dcsr &= ~(EBUS_DCSR_EN_DMA);
-		writel(dcsr, &sun_pci_fd_ebus_dma->dcsr);
-		if (dcsr & EBUS_DCSR_ERR_PEND) {
-			sun_pci_fd_reset_dma();
-			dcsr &= ~(EBUS_DCSR_ERR_PEND);
-			writel(dcsr, &sun_pci_fd_ebus_dma->dcsr);
-		}
-	}
+	ebus_dma_enable(&sun_pci_fd_ebus_dma, 0);
 	if (sun_pci_dma_current.addr != -1U)
 		pci_unmap_single(sun_pci_ebus_dev,
 				 sun_pci_dma_current.addr,
@@ -401,33 +373,12 @@
 
 static void sun_pci_fd_set_dma_mode(int mode)
 {
-	unsigned int dcsr;
-
-	dcsr = readl(&sun_pci_fd_ebus_dma->dcsr);
-	if (readl(&sun_pci_fd_ebus_dma->dbcr)) {
-		sun_pci_fd_reset_dma();
-		writel(dcsr, &sun_pci_fd_ebus_dma->dcsr);
-	}
-
-	dcsr |= EBUS_DCSR_EN_CNT | EBUS_DCSR_TC;
-	/*
-	 * For EBus WRITE means to system memory, which is
-	 * READ for us.
-	 */
-	if (mode == DMA_MODE_WRITE) {
-		dcsr &= ~(EBUS_DCSR_WRITE);
-		sun_pci_dma_pending.direction = PCI_DMA_TODEVICE;
-	} else {
-		dcsr |= EBUS_DCSR_WRITE;
-		sun_pci_dma_pending.direction = PCI_DMA_FROMDEVICE;
-	}
-	writel(dcsr, &sun_pci_fd_ebus_dma->dcsr);
+	ebus_dma_prepare(&sun_pci_fd_ebus_dma, mode != DMA_MODE_WRITE);
 }
 
 static void sun_pci_fd_set_dma_count(int length)
 {
 	sun_pci_dma_pending.len = length;
-	writel(length, &sun_pci_fd_ebus_dma->dbcr);
 }
 
 static void sun_pci_fd_set_dma_addr(char *buffer)
@@ -437,51 +388,28 @@
 
 static unsigned int sun_pci_get_dma_residue(void)
 {
-	unsigned int dcsr, res;
-
-	res = readl(&sun_pci_fd_ebus_dma->dbcr);
-	if (res != 0) {
-		dcsr = readl(&sun_pci_fd_ebus_dma->dcsr);
-		sun_pci_fd_reset_dma();
-		writel(dcsr, &sun_pci_fd_ebus_dma->dcsr);
-	}
-	return res;
+	return ebus_dma_residue(&sun_pci_fd_ebus_dma);
 }
 
 static void sun_pci_fd_enable_irq(void)
 {
-	unsigned int dcsr;
-
-	dcsr = readl(&sun_pci_fd_ebus_dma->dcsr);
-	dcsr |= EBUS_DCSR_INT_EN;
-	writel(dcsr, &sun_pci_fd_ebus_dma->dcsr);
+	ebus_dma_irq_enable(&sun_pci_fd_ebus_dma, 1);
 }
 
 static void sun_pci_fd_disable_irq(void)
 {
-	unsigned int dcsr;
-
-	dcsr = readl(&sun_pci_fd_ebus_dma->dcsr);
-	dcsr &= ~(EBUS_DCSR_INT_EN);
-	writel(dcsr, &sun_pci_fd_ebus_dma->dcsr);
+	ebus_dma_irq_enable(&sun_pci_fd_ebus_dma, 0);
 }
 
 static int sun_pci_fd_request_irq(void)
 {
-	int err;
-
-	err = request_irq(FLOPPY_IRQ, floppy_interrupt, SA_SHIRQ,
-			  "floppy", sun_fdc);
-	if (err)
-		return -1;
-	sun_pci_fd_enable_irq();
+	/* Done by enable/disable irq */
 	return 0;
 }
 
 static void sun_pci_fd_free_irq(void)
 {
-	sun_pci_fd_disable_irq();
-	free_irq(FLOPPY_IRQ, sun_fdc);
+	/* Done by enable/disable irq */
 }
 
 static int sun_pci_fd_eject(int drive)
@@ -489,6 +417,10 @@
 	return -EINVAL;
 }
 
+void sun_pci_fd_dma_callback(struct ebus_dma_info *p, int event, void *cookie)
+{
+	floppy_interrupt(0, NULL, NULL);
+}
 
 /*
  * Floppy probing, we'd like to use /dev/fd0 for a single Floppy on PCI,
@@ -724,6 +656,7 @@
 		if(!strncmp(state, "disabled", 8))
 			return 0;
 			
+		/* XXX ioremap */
 		sun_fdc = (struct sun_flpy_controller *)edev->resource[0].start;
 		FLOPPY_IRQ = edev->irqs[0];
 
@@ -735,9 +668,18 @@
 
 		sun_pci_ebus_dev = ebus->self;
 
-		sun_pci_fd_ebus_dma = (struct linux_ebus_dma *)
-			edev->resource[1].start;
-		sun_pci_fd_reset_dma();
+		spin_lock_init(&sun_pci_fd_ebus_dma.lock);
+		/* XXX ioremap */
+		sun_pci_fd_ebus_dma.regs = edev->resource[1].start;
+		if (!sun_pci_fd_ebus_dma.regs)
+			return 0;
+		sun_pci_fd_ebus_dma.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER;
+		sun_pci_fd_ebus_dma.callback = sun_pci_fd_dma_callback;
+		sun_pci_fd_ebus_dma.client_cookie = NULL;
+		sun_pci_fd_ebus_dma.irq = FLOPPY_IRQ;
+		strcpy(sun_pci_fd_ebus_dma.name, "floppy");
+		if (ebus_dma_register(&sun_pci_fd_ebus_dma))
+			return 0;
 
 		sun_fdops.fd_inb = sun_pci_fd_inb;
 		sun_fdops.fd_outb = sun_pci_fd_outb;
diff -Nru a/include/asm-sparc64/irq.h b/include/asm-sparc64/irq.h
--- a/include/asm-sparc64/irq.h	Tue Oct  1 00:08:17 2002
+++ b/include/asm-sparc64/irq.h	Tue Oct  1 00:08:17 2002
@@ -116,8 +116,8 @@
 extern void disable_irq(unsigned int);
 #define disable_irq_nosync disable_irq
 extern void enable_irq(unsigned int);
-extern void init_timers(void (*lvl10_irq)(int, void *, struct pt_regs *),
-			unsigned long *);
+extern void sparc64_init_timers(void (*lvl10_irq)(int, void *, struct pt_regs *),
+				unsigned long *);
 extern unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long imap);
 extern unsigned int sbus_build_irq(void *sbus, unsigned int ino);
 extern unsigned int psycho_build_irq(void *psycho, int imap_off, int ino, int need_dma_sync);
diff -Nru a/include/asm-sparc64/parport.h b/include/asm-sparc64/parport.h
--- a/include/asm-sparc64/parport.h	Tue Oct  1 00:08:13 2002
+++ b/include/asm-sparc64/parport.h	Tue Oct  1 00:08:13 2002
@@ -13,91 +13,50 @@
 
 #define PARPORT_PC_MAX_PORTS	PARPORT_MAX
 
-static struct linux_ebus_dma *sparc_ebus_dmas[PARPORT_PC_MAX_PORTS];
+static struct sparc_ebus_info {
+	struct ebus_dma_info info;
+	unsigned int addr;
+	unsigned int count;
+} sparc_ebus_dmas[PARPORT_PC_MAX_PORTS];
 
-static __inline__ void
-reset_dma(unsigned int dmanr)
+static __inline__ void enable_dma(unsigned int dmanr)
 {
-	unsigned int dcsr;
+	if (ebus_dma_request(&sparc_ebus_dmas[dmanr].info,
+			     sparc_ebus_dmas[dmanr].addr,
+			     sparc_ebus_dmas[dmanr].count))
+		BUG();
 
-	writel(EBUS_DCSR_RESET, &sparc_ebus_dmas[dmanr]->dcsr);
-	udelay(1);
-	dcsr = EBUS_DCSR_BURST_SZ_16 | EBUS_DCSR_TCI_DIS |
-	       EBUS_DCSR_EN_CNT | EBUS_DCSR_INT_EN;
-	writel(dcsr, &sparc_ebus_dmas[dmanr]->dcsr);
+	ebus_dma_enable(&sparc_ebus_dmas[dmanr].info, 1);
 }
 
-static __inline__ void
-enable_dma(unsigned int dmanr)
+static __inline__ void disable_dma(unsigned int dmanr)
 {
-	unsigned int dcsr;
-
-	dcsr = readl(&sparc_ebus_dmas[dmanr]->dcsr);
-	dcsr |= EBUS_DCSR_EN_DMA;
-	writel(dcsr, &sparc_ebus_dmas[dmanr]->dcsr);
-}
-
-static __inline__ void
-disable_dma(unsigned int dmanr)
-{
-	unsigned int dcsr;
-
-	dcsr = readl(&sparc_ebus_dmas[dmanr]->dcsr);
-	if (dcsr & EBUS_DCSR_EN_DMA) {
-		while (dcsr & EBUS_DCSR_DRAIN) {
-			udelay(1);
-			dcsr = readl(&sparc_ebus_dmas[dmanr]->dcsr);
-		}
-		dcsr &= ~(EBUS_DCSR_EN_DMA);
-		writel(dcsr, &sparc_ebus_dmas[dmanr]->dcsr);
-
-		dcsr = readl(&sparc_ebus_dmas[dmanr]->dcsr);
-		if (dcsr & EBUS_DCSR_ERR_PEND)
-			reset_dma(dmanr);
-	}
+	ebus_dma_enable(&sparc_ebus_dmas[dmanr].info, 0);
 }
 
-static __inline__ void
-clear_dma_ff(unsigned int dmanr)
+static __inline__ void clear_dma_ff(unsigned int dmanr)
 {
 	/* nothing */
 }
 
-static __inline__ void
-set_dma_mode(unsigned int dmanr, char mode)
+static __inline__ void set_dma_mode(unsigned int dmanr, char mode)
 {
-	unsigned int dcsr;
-
-	dcsr = readl(&sparc_ebus_dmas[dmanr]->dcsr);
-	dcsr |= EBUS_DCSR_EN_CNT | EBUS_DCSR_TC;
-	if (mode == DMA_MODE_WRITE)
-		dcsr &= ~(EBUS_DCSR_WRITE);
-	else
-		dcsr |= EBUS_DCSR_WRITE;
-	writel(dcsr, &sparc_ebus_dmas[dmanr]->dcsr);
+	ebus_dma_prepare(&sparc_ebus_dmas[dmanr].info, (mode != DMA_MODE_WRITE));
 }
 
-static __inline__ void
-set_dma_addr(unsigned int dmanr, unsigned int addr)
+static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int addr)
 {
-	writel(addr, &sparc_ebus_dmas[dmanr]->dacr);
+	sparc_ebus_dmas[dmanr].addr = addr;
 }
 
-static __inline__ void
-set_dma_count(unsigned int dmanr, unsigned int count)
+static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
 {
-	writel(count, &sparc_ebus_dmas[dmanr]->dbcr);
+	sparc_ebus_dmas[dmanr].count = count;
 }
 
-static __inline__ int
-get_dma_residue(unsigned int dmanr)
+static __inline__ unsigned int get_dma_residue(unsigned int dmanr)
 {
-	int res;
-
-	res = readl(&sparc_ebus_dmas[dmanr]->dbcr);
-	if (res != 0)
-		reset_dma(dmanr);
-	return res;
+	return ebus_dma_residue(&sparc_ebus_dmas[dmanr].info);
 }
 
 static int ebus_ecpp_p(struct linux_ebus_device *edev)
@@ -171,10 +130,19 @@
 				unsigned long base = edev->resource[0].start;
 				unsigned long config = edev->resource[1].start;
 
-				sparc_ebus_dmas[count] =
-						(struct linux_ebus_dma *)
-							edev->resource[2].start;
-				reset_dma(count);
+				spin_lock_init(&sparc_ebus_dmas[count].info);
+				sparc_ebus_dmas[count].info.regs =
+					edev->resource[2].start;
+				if (!sparc_ebus_dmas[count].info.regs)
+					continue;
+				sparc_ebus_dmas[count].info.flags = 0;
+				sparc_ebus_dmas[count].info.callback = NULL;
+				sparc_ebus_dmas[count].info.client_cookie = NULL;
+				sparc_ebus_dmas[count].info.irq = 0xdeadbeef;
+				strcpy(sparc_ebus_dmas[count].info.name, "parport");
+				if (ebus_dma_register(&sparc_ebus_dmas[count].info))
+					continue;
+				ebus_dma_irq_enable(&sparc_ebus_dmas[count].info, 1);
 
 				/* Configure IRQ to Push Pull, Level Low */
 				/* Enable ECP, set bit 2 of the CTR first */
diff -Nru a/include/asm-sparc64/topology.h b/include/asm-sparc64/topology.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-sparc64/topology.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,6 @@
+#ifndef _ASM_SPARC64_TOPOLOGY_H
+#define _ASM_SPARC64_TOPOLOGY_H
+
+#include <asm-generic/topology.h>
+
+#endif /* _ASM_SPARC64_TOPOLOGY_H */
diff -Nru a/include/asm-um/fixmap.h b/include/asm-um/fixmap.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-um/fixmap.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,96 @@
+#ifndef __UM_FIXMAP_H
+#define __UM_FIXMAP_H
+
+#include <linux/config.h>
+#include <asm/kmap_types.h>
+
+/*
+ * Here we define all the compile-time 'special' virtual
+ * addresses. The point is to have a constant address at
+ * compile time, but to set the physical address only
+ * in the boot process. We allocate these special  addresses
+ * from the end of virtual memory (0xfffff000) backwards.
+ * Also this lets us do fail-safe vmalloc(), we
+ * can guarantee that these special addresses and
+ * vmalloc()-ed addresses never overlap.
+ *
+ * these 'compile-time allocated' memory buffers are
+ * fixed-size 4k pages. (or larger if used with an increment
+ * highger than 1) use fixmap_set(idx,phys) to associate
+ * physical memory with fixmap indices.
+ *
+ * TLB entries of such buffers will not be flushed across
+ * task switches.
+ */
+
+/*
+ * on UP currently we will have no trace of the fixmap mechanizm,
+ * no page table allocations, etc. This might change in the
+ * future, say framebuffers for the console driver(s) could be
+ * fix-mapped?
+ */
+enum fixed_addresses {
+#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,
+#endif
+	__end_of_fixed_addresses
+};
+
+extern void __set_fixmap (enum fixed_addresses idx,
+			  unsigned long phys, pgprot_t flags);
+
+#define set_fixmap(idx, phys) \
+		__set_fixmap(idx, phys, PAGE_KERNEL)
+/*
+ * Some hardware wants to get fixmapped without caching.
+ */
+#define set_fixmap_nocache(idx, phys) \
+		__set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE)
+/*
+ * used by vmalloc.c.
+ *
+ * Leave one empty page between vmalloc'ed areas and
+ * the start of the fixmap, and leave one page empty
+ * at the top of mem..
+ */
+extern unsigned long get_kmem_end(void);
+
+#define FIXADDR_TOP	(get_kmem_end() - 0x2000)
+#define FIXADDR_SIZE	(__end_of_fixed_addresses << PAGE_SHIFT)
+#define FIXADDR_START	(FIXADDR_TOP - FIXADDR_SIZE)
+
+#define __fix_to_virt(x)	(FIXADDR_TOP - ((x) << PAGE_SHIFT))
+#define __virt_to_fix(x)      ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT)
+
+extern void __this_fixmap_does_not_exist(void);
+
+/*
+ * 'index to address' translation. If anyone tries to use the idx
+ * directly without tranlation, we catch the bug with a NULL-deference
+ * kernel oops. Illegal ranges of incoming indices are caught too.
+ */
+static inline unsigned long fix_to_virt(const unsigned int idx)
+{
+	/*
+	 * this branch gets completely eliminated after inlining,
+	 * except when someone tries to use fixaddr indices in an
+	 * illegal way. (such as mixing up address types or using
+	 * out-of-range indices).
+	 *
+	 * If it doesn't get removed, the linker will complain
+	 * loudly with a reasonably clear error message..
+	 */
+	if (idx >= __end_of_fixed_addresses)
+		__this_fixmap_does_not_exist();
+
+        return __fix_to_virt(idx);
+}
+
+static inline unsigned long virt_to_fix(const unsigned long vaddr)
+{
+      BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START);
+      return __virt_to_fix(vaddr);
+}
+
+#endif
diff -Nru a/include/asm-um/highmem.h b/include/asm-um/highmem.h
--- a/include/asm-um/highmem.h	Tue Oct  1 00:08:16 2002
+++ b/include/asm-um/highmem.h	Tue Oct  1 00:08:16 2002
@@ -1,6 +1,12 @@
 #ifndef __UM_HIGHMEM_H
 #define __UM_HIGHMEM_H
 
+#include "asm/page.h"
+#include "asm/fixmap.h"
 #include "asm/arch/highmem.h"
+
+#undef PKMAP_BASE
+
+#define PKMAP_BASE ((FIXADDR_START - LAST_PKMAP * PAGE_SIZE) & PMD_MASK)
 
 #endif
diff -Nru a/include/asm-um/irq.h b/include/asm-um/irq.h
--- a/include/asm-um/irq.h	Tue Oct  1 00:08:21 2002
+++ b/include/asm-um/irq.h	Tue Oct  1 00:08:21 2002
@@ -6,7 +6,6 @@
  */
 struct task_struct;
 
-#include "asm/arch/irq.h"
 #include "asm/ptrace.h"
 
 #undef NR_IRQS
diff -Nru a/include/asm-um/page.h b/include/asm-um/page.h
--- a/include/asm-um/page.h	Tue Oct  1 00:08:17 2002
+++ b/include/asm-um/page.h	Tue Oct  1 00:08:17 2002
@@ -43,10 +43,11 @@
 #define __pa(virt) region_pa((void *) (virt))
 #define __va(phys) region_va((unsigned long) (phys))
 
+extern unsigned long page_to_pfn(struct page *page);
+extern struct page *pfn_to_page(unsigned long pfn);
+
 extern struct page *phys_to_page(unsigned long phys);
 
-#define pfn_to_page(pfn) (phys_to_page(pfn << PAGE_SHIFT))
-#define page_to_pfn(page) (page_to_phys(page) >> PAGE_SHIFT)
 #define virt_to_page(v) (phys_to_page(__pa(v)))
 
 extern struct page *page_mem_map(struct page *page);
diff -Nru a/include/asm-um/percpu.h b/include/asm-um/percpu.h
--- a/include/asm-um/percpu.h	Tue Oct  1 00:08:17 2002
+++ b/include/asm-um/percpu.h	Tue Oct  1 00:08:17 2002
@@ -1,5 +1,5 @@
-#ifndef __UM_CACHEFLUSH_H
-#define __UM_CACHEFLUSH_H
+#ifndef __UM_PERCPU_H
+#define __UM_PERCPU_H
 
 #include "asm/arch/percpu.h"
 
diff -Nru a/include/asm-um/pgalloc.h b/include/asm-um/pgalloc.h
--- a/include/asm-um/pgalloc.h	Tue Oct  1 00:08:19 2002
+++ b/include/asm-um/pgalloc.h	Tue Oct  1 00:08:19 2002
@@ -8,6 +8,7 @@
 #define __UM_PGALLOC_H
 
 #include "linux/mm.h"
+#include "asm/fixmap.h"
 
 #define pmd_populate_kernel(mm, pmd, pte) \
 		set_pmd(pmd, __pmd(_PAGE_TABLE + (unsigned long) __pa(pte)))
@@ -15,7 +16,7 @@
 static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, 
 				struct page *pte)
 {
-	set_pmd(pmd, __pmd(_PAGE_TABLE + phys_addr(page_to_phys(pte))));
+	set_pmd(pmd, __pmd(_PAGE_TABLE + page_to_phys(pte)));
 }
 
 extern pgd_t *pgd_alloc(struct mm_struct *);
diff -Nru a/include/asm-um/pgtable.h b/include/asm-um/pgtable.h
--- a/include/asm-um/pgtable.h	Tue Oct  1 00:08:22 2002
+++ b/include/asm-um/pgtable.h	Tue Oct  1 00:08:22 2002
@@ -10,6 +10,7 @@
 #include "linux/sched.h"
 #include "asm/processor.h"
 #include "asm/page.h"
+#include "asm/fixmap.h"
 
 extern pgd_t swapper_pg_dir[1024];
 
@@ -62,12 +63,16 @@
  */
 
 extern unsigned long high_physmem;
-extern unsigned long end_vm;
 
 #define VMALLOC_OFFSET	(__va_space)
 #define VMALLOC_START	(((unsigned long) high_physmem + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
-#define VMALLOC_END	(end_vm)
+
+#if CONFIG_HIGHMEM
+# define VMALLOC_END	(PKMAP_BASE-2*PAGE_SIZE)
+#else
+# define VMALLOC_END	(FIXADDR_START-2*PAGE_SIZE)
+#endif
 
 #define _PAGE_PRESENT	0x001
 #define _PAGE_NEWPAGE	0x002
@@ -183,15 +188,17 @@
 
 extern struct page *pte_mem_map(pte_t pte);
 extern struct page *phys_mem_map(unsigned long phys);
+extern unsigned long phys_to_pfn(unsigned long p);
+extern unsigned long pfn_to_phys(unsigned long pfn);
 
 #define pte_page(x) pfn_to_page(pte_pfn(x))
 #define pte_address(x) (__va(pte_val(x) & PAGE_MASK))
 #define mk_phys(a, r) ((a) + (r << REGION_SHIFT))
 #define phys_addr(p) ((p) & ~REGION_MASK)
 #define phys_page(p) (phys_mem_map(p) + ((phys_addr(p)) >> PAGE_SHIFT))
-#define pte_pfn(x) ((unsigned long)(((x).pte_low >> PAGE_SHIFT)))
-#define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
-#define pfn_pmd(pfn, prot)	__pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
+#define pte_pfn(x) phys_to_pfn(pte_val(x))
+#define pfn_pte(pfn, prot) __pte(pfn_to_phys(pfn) | pgprot_val(prot))
+#define pfn_pmd(pfn, prot) __pmd(pfn_to_phys(pfn) | pgprot_val(prot))
 
 static inline pte_t pte_mknewprot(pte_t pte)
 {
@@ -333,6 +340,7 @@
 
 /* to find an entry in a page-table-directory. */
 #define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
+#define __pgd_offset(address) pgd_index(address)
 
 /* to find an entry in a page-table-directory */
 #define pgd_offset(mm, address) \
@@ -341,6 +349,9 @@
 /* to find an entry in a kernel page-table-directory */
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
+#define __pmd_offset(address) \
+		(((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
+
 /* Find an entry in the second-level page table.. */
 static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
 {
@@ -357,6 +368,18 @@
 	((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)
+
+#if defined(CONFIG_HIGHPTE) && defined(CONFIG_HIGHMEM4G)
+typedef u32 pte_addr_t;
+#endif
+
+#if defined(CONFIG_HIGHPTE) && defined(CONFIG_HIGHMEM64G)
+typedef u64 pte_addr_t;
+#endif
+
+#if !defined(CONFIG_HIGHPTE)
+typedef pte_t *pte_addr_t;
+#endif
 
 #define update_mmu_cache(vma,address,pte) do ; while (0)
 
diff -Nru a/include/asm-um/system-i386.h b/include/asm-um/system-i386.h
--- a/include/asm-um/system-i386.h	Tue Oct  1 00:08:16 2002
+++ b/include/asm-um/system-i386.h	Tue Oct  1 00:08:16 2002
@@ -3,4 +3,35 @@
 
 #include "asm/system-generic.h"
 
+static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
+				      unsigned long new, int size)
+{
+	unsigned long prev;
+	switch (size) {
+	case 1:
+		__asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
+				     : "=a"(prev)
+				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
+				     : "memory");
+		return prev;
+	case 2:
+		__asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
+				     : "=a"(prev)
+				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
+				     : "memory");
+		return prev;
+	case 4:
+		__asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
+				     : "=a"(prev)
+				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
+				     : "memory");
+		return prev;
+	}
+	return old;
+}
+
+#define cmpxchg(ptr,o,n)\
+	((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
+					(unsigned long)(n),sizeof(*(ptr))))
+    
 #endif
diff -Nru a/include/asm-um/timex.h b/include/asm-um/timex.h
--- a/include/asm-um/timex.h	Tue Oct  1 00:08:18 2002
+++ b/include/asm-um/timex.h	Tue Oct  1 00:08:18 2002
@@ -12,4 +12,6 @@
 	return 0;
 }
 
+#define CLOCK_TICK_RATE (HZ)
+
 #endif
diff -Nru a/include/asm-um/tlbflush.h b/include/asm-um/tlbflush.h
--- a/include/asm-um/tlbflush.h	Tue Oct  1 00:08:13 2002
+++ b/include/asm-um/tlbflush.h	Tue Oct  1 00:08:13 2002
@@ -27,6 +27,7 @@
 extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
 extern void flush_tlb_kernel_vm(void);
 extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
+extern void __flush_tlb_one(unsigned long addr);
 
 static inline void flush_tlb_pgtables(struct mm_struct *mm,
 				      unsigned long start, unsigned long end)
diff -Nru a/include/asm-x86_64/topology.h b/include/asm-x86_64/topology.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-x86_64/topology.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,6 @@
+#ifndef _ASM_X86_64_TOPOLOGY_H
+#define _ASM_X86_64_TOPOLOGY_H
+
+#include <asm-generic/topology.h>
+
+#endif /* _ASM_X86_64_TOPOLOGY_H */
diff -Nru a/include/linux/auto_fs.h b/include/linux/auto_fs.h
--- a/include/linux/auto_fs.h	Tue Oct  1 00:08:13 2002
+++ b/include/linux/auto_fs.h	Tue Oct  1 00:08:13 2002
@@ -45,7 +45,7 @@
  * If so, 32-bit user-space code should be backwards compatible.
  */
 
-#if defined(__sparc__) || defined(__mips__) || defined(__x86_64) \
+#if defined(__sparc__) || defined(__mips__) || defined(__x86_64__) \
  || defined(__powerpc__) || defined(__s390__)
 typedef unsigned int autofs_wqt_t;
 #else
diff -Nru a/include/linux/blkdev.h b/include/linux/blkdev.h
--- a/include/linux/blkdev.h	Tue Oct  1 00:08:16 2002
+++ b/include/linux/blkdev.h	Tue Oct  1 00:08:16 2002
@@ -286,7 +286,7 @@
 
 extern struct sec_size * blk_sec[MAX_BLKDEV];
 extern struct blk_dev_struct blk_dev[MAX_BLKDEV];
-extern void register_disk(struct gendisk *dev, kdev_t first, unsigned minors, struct block_device_operations *ops, long size);
+extern void register_disk(struct gendisk *dev);
 extern void generic_make_request(struct bio *bio);
 extern inline request_queue_t *bdev_get_queue(struct block_device *bdev);
 extern void blk_put_request(struct request *);
@@ -326,6 +326,7 @@
 extern void blk_queue_segment_boundary(request_queue_t *, unsigned long);
 extern void blk_queue_assign_lock(request_queue_t *, spinlock_t *);
 extern void blk_queue_prep_rq(request_queue_t *, prep_rq_fn *pfn);
+extern void blk_queue_merge_bvec(request_queue_t *, merge_bvec_fn *);
 extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev);
 
 extern int blk_rq_map_sg(request_queue_t *, struct request *, struct scatterlist *);
diff -Nru a/include/linux/cpufreq.h b/include/linux/cpufreq.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/cpufreq.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,252 @@
+/*
+ *  linux/include/linux/cpufreq.h
+ *
+ *  Copyright (C) 2001 Russell King
+ *            (C) 2002 Dominik Brodowski <linux@brodo.de>
+ *            
+ *
+ * $Id: cpufreq.h,v 1.26 2002/09/21 09:05:29 db Exp $
+ *
+ * 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.
+ */
+#ifndef _LINUX_CPUFREQ_H
+#define _LINUX_CPUFREQ_H
+
+#include <linux/config.h>
+#include <linux/notifier.h>
+#include <linux/threads.h>
+
+
+/*********************************************************************
+ *                     CPUFREQ NOTIFIER INTERFACE                    *
+ *********************************************************************/
+
+int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list);
+int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list);
+
+#define CPUFREQ_TRANSITION_NOTIFIER     (0)
+#define CPUFREQ_POLICY_NOTIFIER         (1)
+
+#define CPUFREQ_ALL_CPUS        ((NR_CPUS))
+
+
+/********************** cpufreq policy notifiers *********************/
+
+#define CPUFREQ_POLICY_POWERSAVE        (1)
+#define CPUFREQ_POLICY_PERFORMANCE      (2)
+
+/* values here are CPU kHz so that hardware which doesn't run with some
+ * frequencies can complain without having to guess what per cent / per
+ * mille means. */
+struct cpufreq_policy {
+	unsigned int            cpu;    /* cpu nr or CPUFREQ_ALL_CPUS */
+	unsigned int            min;    /* in kHz */
+	unsigned int            max;    /* in kHz */
+        unsigned int            policy; /* see above */
+	unsigned int            max_cpu_freq; /* for information */
+};
+
+#define CPUFREQ_ADJUST          (0)
+#define CPUFREQ_INCOMPATIBLE    (1)
+#define CPUFREQ_NOTIFY          (2)
+
+
+/******************** cpufreq transition notifiers *******************/
+
+#define CPUFREQ_PRECHANGE	(0)
+#define CPUFREQ_POSTCHANGE	(1)
+
+struct cpufreq_freqs {
+	unsigned int cpu;      /* cpu nr or CPUFREQ_ALL_CPUS */
+	unsigned int old;
+	unsigned int new;
+};
+
+
+/**
+ * cpufreq_scale - "old * mult / div" calculation for large values (32-bit-arch safe)
+ * @old:   old value
+ * @div:   divisor
+ * @mult:  multiplier
+ *
+ * Needed for loops_per_jiffy and similar calculations.  We do it 
+ * this way to avoid math overflow on 32-bit machines.  This will
+ * become architecture dependent once high-resolution-timer is
+ * merged (or any other thing that introduces sc_math.h).
+ *
+ *    new = old * mult / div
+ */
+static inline unsigned long cpufreq_scale(unsigned long old, u_int div, u_int mult)
+{
+	unsigned long val, carry;
+
+	mult /= 100;
+	div  /= 100;
+        val   = (old / div) * mult;
+        carry = old % div;
+	carry = carry * mult / div;
+
+	return carry + val;
+};
+
+
+/*********************************************************************
+ *                      DYNAMIC CPUFREQ INTERFACE                    *
+ *********************************************************************/
+#ifdef CONFIG_CPU_FREQ_DYNAMIC
+/* TBD */
+#endif /* CONFIG_CPU_FREQ_DYNAMIC */
+
+
+/*********************************************************************
+ *                      CPUFREQ DRIVER INTERFACE                     *
+ *********************************************************************/
+
+typedef void (*cpufreq_policy_t)          (struct cpufreq_policy *policy);
+
+struct cpufreq_driver {
+	/* needed by all drivers */
+	cpufreq_policy_t        verify;
+	cpufreq_policy_t        setpolicy;
+	struct cpufreq_policy   *policy;
+#ifdef CONFIG_CPU_FREQ_DYNAMIC
+	/* TBD */
+#endif
+	/* 2.4. compatible API */
+#ifdef CONFIG_CPU_FREQ_24_API
+	unsigned int            cpu_min_freq;
+	unsigned int            cpu_cur_freq[NR_CPUS];
+#endif
+};
+
+int cpufreq_register(struct cpufreq_driver *driver_data);
+int cpufreq_unregister(void);
+
+void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state);
+
+
+static inline void cpufreq_verify_within_limits(struct cpufreq_policy *policy, unsigned int min, unsigned int max) 
+{
+	if (policy->min < min)
+		policy->min = min;
+	if (policy->max < min)
+		policy->max = min;
+	if (policy->min > max)
+		policy->min = max;
+	if (policy->max > max)
+		policy->max = max;
+	if (policy->min > policy->max)
+		policy->min = policy->max;
+	return;
+}
+
+/*********************************************************************
+ *                        CPUFREQ 2.6. INTERFACE                     *
+ *********************************************************************/
+int cpufreq_set_policy(struct cpufreq_policy *policy);
+int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu);
+
+#ifdef CONFIG_CPU_FREQ_26_API
+#ifdef CONFIG_PM
+int cpufreq_restore(void);
+#endif
+#endif
+
+
+#ifdef CONFIG_CPU_FREQ_24_API
+/*********************************************************************
+ *                        CPUFREQ 2.4. INTERFACE                     *
+ *********************************************************************/
+int cpufreq_setmax(unsigned int cpu);
+#ifdef CONFIG_PM
+int cpufreq_restore(void);
+#endif
+int cpufreq_set(unsigned int kHz, unsigned int cpu);
+unsigned int cpufreq_get(unsigned int cpu);
+
+/* /proc/sys/cpu */
+enum {
+	CPU_NR   = 1,           /* compatibilty reasons */
+	CPU_NR_0 = 1,
+	CPU_NR_1 = 2,
+	CPU_NR_2 = 3,
+	CPU_NR_3 = 4,
+	CPU_NR_4 = 5,
+	CPU_NR_5 = 6,
+	CPU_NR_6 = 7,
+	CPU_NR_7 = 8,
+	CPU_NR_8 = 9,
+	CPU_NR_9 = 10,
+	CPU_NR_10 = 11,
+	CPU_NR_11 = 12,
+	CPU_NR_12 = 13,
+	CPU_NR_13 = 14,
+	CPU_NR_14 = 15,
+	CPU_NR_15 = 16,
+	CPU_NR_16 = 17,
+	CPU_NR_17 = 18,
+	CPU_NR_18 = 19,
+	CPU_NR_19 = 20,
+	CPU_NR_20 = 21,
+	CPU_NR_21 = 22,
+	CPU_NR_22 = 23,
+	CPU_NR_23 = 24,
+	CPU_NR_24 = 25,
+	CPU_NR_25 = 26,
+	CPU_NR_26 = 27,
+	CPU_NR_27 = 28,
+	CPU_NR_28 = 29,
+	CPU_NR_29 = 30,
+	CPU_NR_30 = 31,
+	CPU_NR_31 = 32,
+};
+
+/* /proc/sys/cpu/{0,1,...,(NR_CPUS-1)} */
+enum {
+	CPU_NR_FREQ_MAX = 1,
+	CPU_NR_FREQ_MIN = 2,
+	CPU_NR_FREQ = 3,
+};
+
+#define CTL_CPU_VARS_SPEED_MAX { \
+                ctl_name: CPU_NR_FREQ_MAX, \
+                data: &cpu_max_freq, \
+                procname: "speed-max", \
+                maxlen:	sizeof(cpu_max_freq),\
+                mode: 0444, \
+                proc_handler: proc_dointvec, }
+
+#define CTL_CPU_VARS_SPEED_MIN { \
+                ctl_name: CPU_NR_FREQ_MIN, \
+                data: &cpu_min_freq, \
+                procname: "speed-min", \
+                maxlen:	sizeof(cpu_min_freq),\
+                mode: 0444, \
+                proc_handler: proc_dointvec, }
+
+#define CTL_CPU_VARS_SPEED(cpunr) { \
+                ctl_name: CPU_NR_FREQ, \
+                procname: "speed", \
+                mode: 0644, \
+                proc_handler: cpufreq_procctl, \
+                strategy: cpufreq_sysctl, \
+                extra1: (void*) (cpunr), }
+
+#define CTL_TABLE_CPU_VARS(cpunr) static ctl_table ctl_cpu_vars_##cpunr[] = {\
+                CTL_CPU_VARS_SPEED_MAX, \
+                CTL_CPU_VARS_SPEED_MIN, \
+                CTL_CPU_VARS_SPEED(cpunr),  \
+                { ctl_name: 0, }, }
+
+/* the ctl_table entry for each CPU */
+#define CPU_ENUM(s) { \
+                ctl_name: (CPU_NR + s), \
+                procname: #s, \
+                mode: 0555, \
+                child: ctl_cpu_vars_##s }
+
+#endif /* CONFIG_CPU_FREQ_24_API */
+
+#endif /* _LINUX_CPUFREQ_H */
diff -Nru a/include/linux/genhd.h b/include/linux/genhd.h
--- a/include/linux/genhd.h	Tue Oct  1 00:08:15 2002
+++ b/include/linux/genhd.h	Tue Oct  1 00:08:15 2002
@@ -73,15 +73,14 @@
 struct gendisk {
 	int major;			/* major number of driver */
 	int first_minor;
-	const char *major_name;		/* name of major driver */
 	int minor_shift;		/* number of times minor is shifted to
 					   get real minor */
-
+	char disk_name[16];		/* name of major driver */
 	struct hd_struct *part;		/* [indexed by minor] */
-	struct gendisk *next;
 	struct block_device_operations *fops;
 	sector_t capacity;
 	struct list_head list;
+	struct list_head full_list;
 
 	int flags;
 	int number;			/* devfs crap */
@@ -95,7 +94,7 @@
 extern void add_disk(struct gendisk *disk);
 extern void del_gendisk(struct gendisk *gp);
 extern void unlink_gendisk(struct gendisk *gp);
-extern struct gendisk *get_gendisk(kdev_t dev);
+extern struct gendisk *get_gendisk(dev_t dev, int *part);
 static inline unsigned long get_start_sect(struct block_device *bdev)
 {
 	return bdev->bd_offset;
@@ -263,12 +262,16 @@
 extern int rescan_partitions(struct gendisk *disk, struct block_device *bdev);
 extern void update_partition(struct gendisk *disk, int part);
 
+extern struct gendisk *alloc_disk(void);
+extern void put_disk(struct gendisk *disk);
+
 /* will go away */
 extern void blk_set_probe(int major, struct gendisk *(p)(int));
 
 static inline unsigned int disk_index (kdev_t dev)
 {
-	struct gendisk *g = get_gendisk(dev);
+	int part;
+	struct gendisk *g = get_gendisk(kdev_t_to_nr(dev), &part);
 	return g ? (minor(dev) >> g->minor_shift) : 0;
 }
 
diff -Nru a/include/linux/gfp.h b/include/linux/gfp.h
--- a/include/linux/gfp.h	Tue Oct  1 00:08:16 2002
+++ b/include/linux/gfp.h	Tue Oct  1 00:08:16 2002
@@ -25,7 +25,6 @@
 #define GFP_USER	(             __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
 #define GFP_HIGHUSER	(             __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS | __GFP_HIGHMEM)
 #define GFP_KERNEL	(             __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
-#define GFP_NFS		(             __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
 #define GFP_KSWAPD	(             __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
 
 /* Flag - indicates that the buffer will be suitable for DMA.  Ignored on some
diff -Nru a/include/linux/init_task.h b/include/linux/init_task.h
--- a/include/linux/init_task.h	Tue Oct  1 00:08:15 2002
+++ b/include/linux/init_task.h	Tue Oct  1 00:08:15 2002
@@ -90,7 +90,6 @@
 	.thread		= INIT_THREAD,					\
 	.fs		= &init_fs,					\
 	.files		= &init_files,					\
-	.sigmask_lock	= SPIN_LOCK_UNLOCKED,				\
 	.sig		= &init_signals,				\
 	.pending	= { NULL, &tsk.pending.head, {{0}}},		\
 	.blocked	= {{0}},					\
diff -Nru a/include/linux/interrupt.h b/include/linux/interrupt.h
--- a/include/linux/interrupt.h	Tue Oct  1 00:08:17 2002
+++ b/include/linux/interrupt.h	Tue Oct  1 00:08:17 2002
@@ -22,25 +22,6 @@
 	struct irqaction *next;
 };
 
-
-/* Who gets which entry in bh_base.  Things which will occur most often
-   should come first */
-   
-enum {
-	TIMER_BH = 0,
-	TQUEUE_BH = 1,
-	DIGI_BH = 2,
-	SERIAL_BH = 3,
-	RISCOM8_BH = 4,
-	SPECIALIX_BH = 5,
-	AURORA_BH = 6,
-	ESP_BH = 7,
-	IMMEDIATE_BH = 9,
-	CYCLADES_BH = 10,
-	MACSERIAL_BH = 13,
-	ISICOM_BH = 14
-};
-
 #include <asm/hardirq.h>
 #include <asm/softirq.h>
 
@@ -217,23 +198,6 @@
 #define SMP_TIMER_DEFINE(name, task)
 
 #endif /* CONFIG_SMP */
-
-
-/* Old BH definitions */
-
-extern struct tasklet_struct bh_task_vec[];
-
-/* It is exported _ONLY_ for wait_on_irq(). */
-extern spinlock_t global_bh_lock;
-
-static inline void mark_bh(int nr)
-{
-	tasklet_hi_schedule(bh_task_vec+nr);
-}
-
-extern void init_bh(int nr, void (*routine)(void));
-extern void remove_bh(int nr);
-
 
 /*
  * Autoprobing for irqs:
diff -Nru a/include/linux/isdn.h b/include/linux/isdn.h
--- a/include/linux/isdn.h	Tue Oct  1 00:08:21 2002
+++ b/include/linux/isdn.h	Tue Oct  1 00:08:21 2002
@@ -75,7 +75,7 @@
 #define ISDN_NET_ENCAP_UIHDLC     5
 #define ISDN_NET_ENCAP_CISCOHDLCK 6 /* With SLARP and keepalive    */
 #define ISDN_NET_ENCAP_X25IFACE   7 /* Documentation/networking/x25-iface.txt*/
-#define ISDN_NET_ENCAP_MAX_ENCAP  ISDN_NET_ENCAP_X25IFACE
+#define ISDN_NET_ENCAP_NR         8
 
 /* Facility which currently uses an ISDN-channel */
 #define ISDN_USAGE_NONE       0
@@ -256,7 +256,6 @@
 /*=================== Start of ip-over-ISDN stuff =========================*/
 
 /* Feature- and status-flags for a net-interface */
-#define ISDN_NET_CONNECTED  0x01       /* Bound to ISDN-Channel             */
 #define ISDN_NET_SECURE     0x02       /* Accept calls from phonelist only  */
 #define ISDN_NET_CALLBACK   0x04       /* activate callback                 */
 #define ISDN_NET_CBHUP      0x08       /* hangup before callback            */
@@ -279,58 +278,57 @@
      which holds the linux device structure (here: isdn_net_device)
 */
 
+struct isdn_net_dev_s;
+struct isdn_net_local_s;
+
+struct isdn_netif_ops {
+	int			(*hard_header) (struct sk_buff *skb,
+						struct net_device *dev,
+						unsigned short type,
+						void *daddr,
+						void *saddr,
+						unsigned len);
+	int			(*do_ioctl)(struct net_device *dev,
+					    struct ifreq *ifr, int cmd);
+
+	unsigned short		flags;	/* interface flags (a la BSD)	*/
+	unsigned short		type;	/* interface hardware type	*/
+	unsigned char		addr_len;/* hardware address length	*/
+	void                    (*receive)(struct isdn_net_dev_s *p,
+					   struct isdn_net_local_s *olp,
+					   struct sk_buff *skb);
+	void                    (*connected)(struct isdn_net_local_s *lp);
+	void                    (*disconnected)(struct isdn_net_local_s *lp);
+	int                     (*bind)(struct isdn_net_local_s *lp);
+	void                    (*unbind)(struct isdn_net_local_s *lp);
+	int                     (*init)(struct isdn_net_local_s *lp);
+	void                    (*cleanup)(struct isdn_net_local_s *lp);
+	int                     (*open)(struct isdn_net_local_s *lp);
+	void                    (*close)(struct isdn_net_local_s *lp);
+};
+
 /* Local interface-data */
 typedef struct isdn_net_local_s {
-  spinlock_t             lock;
   ulong                  magic;
-  char                   name[10];     /* Name of device                   */
-  struct timer_list      dial_timer;   /* dial events timer                */
-  int                    dial_event;   /* event in case of timer expiry    */
+  spinlock_t             lock;
   struct net_device_stats stats;       /* Ethernet Statistics              */
-  struct timer_list      hup_timer;    /* auto hangup timer                */
-  int                    isdn_slot;    /* Index to isdn device/channel     */
-  int			 ppp_slot;     /* PPPD device slot number          */
-  int                    pre_device;   /* Preselected isdn-device          */
-  int                    pre_channel;  /* Preselected isdn-channel         */
-  int                    exclusive;    /* If non-zero idx to reserved chan.*/
   int                    flags;        /* Connection-flags                 */
   int                    dialretry;    /* Counter for Dialout-retries      */
   int                    dialmax;      /* Max. Number of Dial-retries      */
+  int	        	 dialtimeout;  /* How long shall we try on dialing */
+  int			 dialwait;     /* wait after failed attempt        */
+
   int                    cbdelay;      /* Delay before Callback starts     */
   char                   msn[ISDN_MSNLEN]; /* MSNs/EAZs for this interface */
+
   u_char                 cbhup;        /* Flag: Reject Call before Callback*/
-  u_char                 dialstate;    /* State for dialing                */
+  int                    hupflags;     /* Flags for charge-unit-hangup:    */
+  int                    onhtime;      /* Time to keep link up             */
+
   u_char                 p_encap;      /* Packet encapsulation             */
-                                       /*   0 = Ethernet over ISDN         */
-				       /*   1 = RAW-IP                     */
-                                       /*   2 = IP with type field         */
   u_char                 l2_proto;     /* Layer-2-protocol                 */
-				       /* See ISDN_PROTO_L2..-constants in */
-                                       /* isdnif.h                         */
-                                       /*   0 = X75/LAPB with I-Frames     */
-				       /*   1 = X75/LAPB with UI-Frames    */
-				       /*   2 = X75/LAPB with BUI-Frames   */
-				       /*   3 = HDLC                       */
   u_char                 l3_proto;     /* Layer-3-protocol                 */
-				       /* See ISDN_PROTO_L3..-constants in */
-                                       /* isdnif.h                         */
-                                       /*   0 = Transparent                */
-  int                    huptimer;     /* Timeout-counter for auto-hangup  */
-  int                    charge;       /* Counter for charging units       */
-  int                    charge_state; /* ChargeInfo state machine         */
-  ulong                  chargetime;   /* Timer for Charging info          */
-  int                    hupflags;     /* Flags for charge-unit-hangup:    */
-				       /* bit0: chargeint is invalid       */
-				       /* bit1: Getting charge-interval    */
-                                       /* bit2: Do charge-unit-hangup      */
-                                       /* bit3: Do hangup even on incoming */
-  int                    outgoing;     /* Flag: outgoing call              */
-  int                    onhtime;      /* Time to keep link up             */
-  int                    chargeint;    /* Interval between charge-infos    */
-  int                    onum;         /* Flag: at least 1 outgoing number */
-  int                    cps;          /* current speed of this interface  */
-  int                    transcount;   /* byte-counter for cps-calculation */
-  int                    last_jiffies; /* when transcount was reset        */
+
   int                    sqfull;       /* Flag: netdev-queue overloaded    */
   ulong                  sqfull_stamp; /* Start-Time of overload           */
   ulong                  slavedelay;   /* Dynamic bundling delaytime       */
@@ -338,7 +336,6 @@
   struct list_head       phone[2];     /* List of remote-phonenumbers      */
 				       /* phone[0] = Incoming Numbers      */
 				       /* phone[1] = Outgoing Numbers      */
-  int                    dial;         /* # of phone number just dialed    */
   struct net_device      *master;      /* Ptr to Master device for slaves  */
   struct net_device      *slave;       /* Ptr to Slave device for masters  */
   struct isdn_net_local_s *next;       /* Ptr to next link in bundle       */
@@ -353,19 +350,6 @@
                                        /* a particular channel (including  */
                                        /* the frame_cnt                    */
 
-  int                    (*org_hhc)(
-				    struct neighbour *neigh,
-				    struct hh_cache *hh);
-                                       /* Ptr to orig. header_cache_update */
-  void                   (*org_hcu)(struct hh_cache *,
-				    struct net_device *,
-                                    unsigned char *);
-  int  pppbind;                        /* ippp device for bindings         */
-  int					dialtimeout;	/* How long shall we try on dialing? (jiffies) */
-  int					dialwait;		/* How long shall we wait after failed attempt? (jiffies) */
-  ulong					dialstarted;	/* jiffies of first dialing-attempt */
-  ulong					dialwait_timer;	/* jiffies of earliest next dialing-attempt */
-  int					huptimeout;		/* How long will the connection be up? (seconds) */
 #ifdef CONFIG_ISDN_X25
   struct concap_device_ops *dops;      /* callbacks used by encapsulator   */
 #endif
@@ -379,15 +363,45 @@
   char cisco_debserint;			/* debugging flag of cisco hdlc with slarp */
   struct timer_list cisco_timer;
   struct tq_struct tqueue;
+  struct isdn_netif_ops   *ops;
 } isdn_net_local;
 
 /* the interface itself */
 typedef struct isdn_net_dev_s {
-  isdn_net_local local;
-  isdn_net_local *queue;               /* circular list of all bundled
+  isdn_net_local         local;
+
+  int                    isdn_slot;    /* Index to isdn device/channel     */
+  int                    pre_device;   /* Preselected isdn-device          */
+  int                    pre_channel;  /* Preselected isdn-channel         */
+  int                    exclusive;    /* -1 if non excl./idx to excl chan */
+
+  struct timer_list      dial_timer;   /* dial events timer                */
+  int                    dial_event;   /* event in case of timer expiry    */
+  int                    dialstate;    /* State for dialing                */
+  int                    dial;         /* # of phone number just dialed    */
+  int                    outgoing;     /* Flag: outgoing call              */
+  unsigned long		 dialstarted;	/* first dialing-attempt           */
+  unsigned long		 dialwait_timer;/* earliest next dialing-attempt   */
+
+  int                    cps;          /* current speed of this interface  */
+  int                    transcount;   /* byte-counter for cps-calculation */
+  int                    last_jiffies; /* when transcount was reset        */
+
+  struct timer_list      hup_timer;    /* auto hangup timer                */
+  int                    huptimer;     /* Timeout-counter for auto-hangup  */
+  int                    charge;       /* Counter for charging units       */
+  int                    charge_state; /* ChargeInfo state machine         */
+  unsigned long          chargetime;   /* Timer for Charging info          */
+  int                    chargeint;    /* Interval between charge-infos    */
+
+  int                    pppbind;      /* ippp device for bindings         */
+  int			 ppp_slot;     /* PPPD device slot number          */
+
+  isdn_net_local         *queue;       /* circular list of all bundled
 					  channels, which are currently
 					  online                           */
   spinlock_t queue_lock;               /* lock to protect queue            */
+  char                   name[10];     /* Name of device                   */
   struct list_head global_list;        /* global list of all isdn_net_devs */
   struct net_device dev;               /* interface to upper levels        */
 #ifdef CONFIG_ISDN_PPP
diff -Nru a/include/linux/isdn_ppp.h b/include/linux/isdn_ppp.h
--- a/include/linux/isdn_ppp.h	Tue Oct  1 00:08:16 2002
+++ b/include/linux/isdn_ppp.h	Tue Oct  1 00:08:16 2002
@@ -138,8 +138,6 @@
 
 extern int isdn_ppp_register_compressor(struct isdn_ppp_compressor *);
 extern int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *);
-extern int isdn_ppp_dial_slave(char *);
-extern int isdn_ppp_hangup_slave(char *);
 
 typedef struct {
   unsigned long seqerrs;
@@ -214,7 +212,7 @@
   unsigned int mpmru;
   unsigned int mpmtu;
   unsigned int maxcid;
-  struct isdn_net_local_s *lp;
+  struct isdn_net_dev_s *idev;
   int unit;
   int minor;
   unsigned int last_link_seqno;
diff -Nru a/include/linux/loop.h b/include/linux/loop.h
--- a/include/linux/loop.h	Tue Oct  1 00:08:21 2002
+++ b/include/linux/loop.h	Tue Oct  1 00:08:21 2002
@@ -56,6 +56,8 @@
 	struct semaphore	lo_ctl_mutex;
 	struct semaphore	lo_bh_mutex;
 	atomic_t		lo_pending;
+
+	request_queue_t		lo_queue;
 };
 
 typedef	int (* transfer_proc_t)(struct loop_device *, int cmd,
diff -Nru a/include/linux/mii.h b/include/linux/mii.h
--- a/include/linux/mii.h	Tue Oct  1 00:08:14 2002
+++ b/include/linux/mii.h	Tue Oct  1 00:08:14 2002
@@ -107,9 +107,11 @@
 struct mii_if_info {
 	int phy_id;
 	int advertising;
+	int phy_id_mask;
+	int reg_num_mask;
 
-	unsigned int full_duplex : 1;
-	unsigned int duplex_lock : 1;
+	unsigned int full_duplex : 1;	/* is full duplex? */
+	unsigned int force_media : 1;	/* is autoneg. disabled? */
 
 	struct net_device *dev;
 	int (*mdio_read) (struct net_device *dev, int phy_id, int location);
@@ -117,13 +119,20 @@
 };
 
 struct ethtool_cmd;
+struct mii_ioctl_data;
 
 extern int mii_link_ok (struct mii_if_info *mii);
 extern int mii_nway_restart (struct mii_if_info *mii);
 extern int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd);
 extern int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd);
 extern void mii_check_link (struct mii_if_info *mii);
-extern unsigned int mii_check_media (struct mii_if_info *mii, unsigned int ok_to_print);
+extern unsigned int mii_check_media (struct mii_if_info *mii,
+				     unsigned int ok_to_print,
+				     unsigned int init_media);
+extern int generic_mii_ioctl(struct mii_if_info *mii_if,
+                      	     struct mii_ioctl_data *mii_data, int cmd,
+			     unsigned int *duplex_changed);
+
 
 
 /* This structure is used in all SIOCxMIIxxx ioctl calls */
diff -Nru a/include/linux/mmzone.h b/include/linux/mmzone.h
--- a/include/linux/mmzone.h	Tue Oct  1 00:08:14 2002
+++ b/include/linux/mmzone.h	Tue Oct  1 00:08:14 2002
@@ -24,10 +24,10 @@
 #define MAX_ORDER CONFIG_FORCE_MAX_ZONEORDER
 #endif
 
-typedef struct free_area_struct {
+struct free_area {
 	struct list_head	free_list;
 	unsigned long		*map;
-} free_area_t;
+};
 
 struct pglist_data;
 
@@ -78,7 +78,7 @@
 	/*
 	 * free areas of different sizes
 	 */
-	free_area_t		free_area[MAX_ORDER];
+	struct free_area	free_area[MAX_ORDER];
 
 	/*
 	 * wait_table		-- the array holding the hash table
@@ -168,6 +168,7 @@
 	unsigned long node_size;
 	int node_id;
 	struct pglist_data *pgdat_next;
+	wait_queue_head_t       kswapd_wait;
 } pg_data_t;
 
 extern int numnodes;
@@ -248,13 +249,23 @@
 #define for_each_zone(zone) \
 	for (zone = pgdat_list->node_zones; zone; zone = next_zone(zone))
 
+#ifdef CONFIG_NUMA
+#define MAX_NR_MEMBLKS	BITS_PER_LONG /* Max number of Memory Blocks */
+#else /* !CONFIG_NUMA */
+#define MAX_NR_MEMBLKS	1
+#endif /* CONFIG_NUMA */
+
+#include <asm/topology.h>
+/* Returns the number of the current Node. */
+#define numa_node_id()		(__cpu_to_node(smp_processor_id()))
+
 #ifndef CONFIG_DISCONTIGMEM
 
 #define NODE_DATA(nid)		(&contig_page_data)
 #define NODE_MEM_MAP(nid)	mem_map
 #define MAX_NR_NODES		1
 
-#else /* !CONFIG_DISCONTIGMEM */
+#else /* CONFIG_DISCONTIGMEM */
 
 #include <asm/mmzone.h>
 
diff -Nru a/include/linux/module.h b/include/linux/module.h
--- a/include/linux/module.h	Tue Oct  1 00:08:19 2002
+++ b/include/linux/module.h	Tue Oct  1 00:08:19 2002
@@ -253,6 +253,7 @@
  * software modules
  *
  *	"GPL"				[GNU Public License v2 or later]
+ *	"GPL v2"			[GNU Public License v2]
  *	"GPL and additional rights"	[GNU Public License v2 rights and more]
  *	"Dual BSD/GPL"			[GNU Public License v2 or BSD license choice]
  *	"Dual MPL/GPL"			[GNU Public License v2 or Mozilla license choice]
diff -Nru a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h
--- a/include/linux/msdos_fs.h	Tue Oct  1 00:08:19 2002
+++ b/include/linux/msdos_fs.h	Tue Oct  1 00:08:19 2002
@@ -68,9 +68,9 @@
 	MSDOS_SB(s)->fat_bits == 16 ? BAD_FAT16 : BAD_FAT12)
 
 /* standard EOF */
-#define EOF_FAT12 0xFF8
-#define EOF_FAT16 0xFFF8
-#define EOF_FAT32 0xFFFFFF8
+#define EOF_FAT12 0xFFF
+#define EOF_FAT16 0xFFFF
+#define EOF_FAT32 0xFFFFFFF
 #define EOF_FAT(s) (MSDOS_SB(s)->fat_bits == 32 ? EOF_FAT32 : \
 	MSDOS_SB(s)->fat_bits == 16 ? EOF_FAT16 : EOF_FAT12)
 
diff -Nru a/include/linux/page-flags.h b/include/linux/page-flags.h
--- a/include/linux/page-flags.h	Tue Oct  1 00:08:18 2002
+++ b/include/linux/page-flags.h	Tue Oct  1 00:08:18 2002
@@ -211,6 +211,8 @@
 extern struct address_space swapper_space;
 #define PageSwapCache(page) ((page)->mapping == &swapper_space)
 
+struct page;	/* forward declaration */
+
 int test_clear_page_dirty(struct page *page);
 
 static inline void clear_page_dirty(struct page *page)
diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h
--- a/include/linux/pci_ids.h	Tue Oct  1 00:08:17 2002
+++ b/include/linux/pci_ids.h	Tue Oct  1 00:08:17 2002
@@ -1713,8 +1713,13 @@
 #define PCI_DEVICE_ID_INTEL_82801BA_9	0x244b
 #define PCI_DEVICE_ID_INTEL_82801BA_10	0x244c
 #define PCI_DEVICE_ID_INTEL_82801BA_11	0x244e
+#define PCI_DEVICE_ID_INTEL_82801E_0	0x2450
+#define PCI_DEVICE_ID_INTEL_82801E_2	0x2452
+#define PCI_DEVICE_ID_INTEL_82801E_3	0x2453
 #define PCI_DEVICE_ID_INTEL_82801E_9	0x245b
 #define PCI_DEVICE_ID_INTEL_82801E_11	PCI_DEVICE_ID_INTEL_82801E_9
+#define PCI_DEVICE_ID_INTEL_82801E_13	0x245d
+#define PCI_DEVICE_ID_INTEL_82801E_14	0x245e
 #define PCI_DEVICE_ID_INTEL_82801CA_0	0x2480
 #define PCI_DEVICE_ID_INTEL_82801CA_2	0x2482
 #define PCI_DEVICE_ID_INTEL_82801CA_3	0x2483
@@ -1725,8 +1730,16 @@
 #define PCI_DEVICE_ID_INTEL_82801CA_10	0x248a
 #define PCI_DEVICE_ID_INTEL_82801CA_11	0x248b
 #define PCI_DEVICE_ID_INTEL_82801CA_12	0x248c
+#define PCI_DEVICE_ID_INTEL_82801DB_0	0x24c0
+#define PCI_DEVICE_ID_INTEL_82801DB_2	0x24c2
+#define PCI_DEVICE_ID_INTEL_82801DB_3	0x24c3
+#define PCI_DEVICE_ID_INTEL_82801DB_4	0x24c4
+#define PCI_DEVICE_ID_INTEL_82801DB_5	0x24c5
+#define PCI_DEVICE_ID_INTEL_82801DB_6	0x24c6
+#define PCI_DEVICE_ID_INTEL_82801DB_7	0x24c7
 #define PCI_DEVICE_ID_INTEL_82801DB_9	0x24cb
 #define PCI_DEVICE_ID_INTEL_82801DB_11	PCI_DEVICE_ID_INTEL_82801DB_9
+#define PCI_DEVICE_ID_INTEL_82801DB_13	0x24cd
 #define PCI_DEVICE_ID_INTEL_82820_HB	0x2500
 #define PCI_DEVICE_ID_INTEL_82820_UP_HB	0x2501
 #define PCI_DEVICE_ID_INTEL_82850_HB	0x2530
diff -Nru a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
--- a/include/linux/reiserfs_fs.h	Tue Oct  1 00:08:19 2002
+++ b/include/linux/reiserfs_fs.h	Tue Oct  1 00:08:19 2002
@@ -1632,9 +1632,6 @@
   /* 12 */ struct journal_params jh_journal;
 } ;
 
-extern task_queue reiserfs_commit_thread_tq ;
-extern wait_queue_head_t reiserfs_commit_thread_wait ;
-
 /* biggest tunable defines are right here */
 #define JOURNAL_BLOCK_COUNT 8192 /* number of blocks in the journal */
 #define JOURNAL_TRANS_MAX_DEFAULT 1024   /* biggest possible single transaction, don't change for now (8/3/99) */
diff -Nru a/include/linux/sched.h b/include/linux/sched.h
--- a/include/linux/sched.h	Tue Oct  1 00:08:15 2002
+++ b/include/linux/sched.h	Tue Oct  1 00:08:15 2002
@@ -172,7 +172,6 @@
 extern signed long FASTCALL(schedule_timeout(signed long timeout));
 asmlinkage void schedule(void);
 
-extern void flush_scheduled_tasks(void);
 extern int start_context_thread(void);
 extern int current_is_keventd(void);
 
@@ -226,15 +225,15 @@
 	struct k_sigaction	action[_NSIG];
 	spinlock_t		siglock;
 
-        /* current thread group signal load-balancing target: */
-        task_t                  *curr_target;
+	/* current thread group signal load-balancing target: */
+	task_t			*curr_target;
 
+	/* shared signal handling: */
 	struct sigpending	shared_pending;
 
 	/* thread group exit support */
 	int			group_exit;
 	int			group_exit_code;
-
 	struct task_struct	*group_exit_task;
 };
 
@@ -380,7 +379,6 @@
 /* namespace */
 	struct namespace *namespace;
 /* signal handlers */
-	spinlock_t sigmask_lock;	/* Protects signal and blocked */
 	struct signal_struct *sig;
 
 	sigset_t blocked, real_blocked, shared_unblocked;
@@ -657,7 +655,6 @@
 extern void exit_files(struct task_struct *);
 extern void exit_sighand(struct task_struct *);
 extern void __exit_sighand(struct task_struct *);
-extern void remove_thread_group(struct task_struct *tsk, struct signal_struct *sig);
 
 extern void reparent_to_init(void);
 extern void daemonize(void);
@@ -720,6 +717,45 @@
 	current->state = TASK_RUNNING;					\
 	remove_wait_queue(&wq, &__wait);				\
 } while (0)
+
+#define wait_event_interruptible(wq, condition)				\
+({									\
+	int __ret = 0;							\
+	if (!(condition))						\
+		__wait_event_interruptible(wq, condition, __ret);	\
+	__ret;								\
+})
+
+#define __wait_event_interruptible_timeout(wq, condition, ret)		\
+do {									\
+	wait_queue_t __wait;						\
+	init_waitqueue_entry(&__wait, current);				\
+									\
+	add_wait_queue(&wq, &__wait);					\
+	for (;;) {							\
+		set_current_state(TASK_INTERRUPTIBLE);			\
+		if (condition)						\
+			break;						\
+		if (!signal_pending(current)) {				\
+			ret = schedule_timeout(ret);			\
+			if (!ret)					\
+				break;					\
+			continue;					\
+		}							\
+		ret = -ERESTARTSYS;					\
+		break;							\
+	}								\
+	current->state = TASK_RUNNING;					\
+	remove_wait_queue(&wq, &__wait);				\
+} while (0)
+
+#define wait_event_interruptible_timeout(wq, condition, timeout)	\
+({									\
+	long __ret = timeout;						\
+	if (!(condition))						\
+		__wait_event_interruptible_timeout(wq, condition, __ret); \
+	__ret;								\
+})
 	
 /*
  * Must be called with the spinlock in the wait_queue_head_t held.
@@ -740,14 +776,6 @@
 	__remove_wait_queue(q,  wait);
 }
 
-#define wait_event_interruptible(wq, condition)				\
-({									\
-	int __ret = 0;							\
-	if (!(condition))						\
-		__wait_event_interruptible(wq, condition, __ret);	\
-	__ret;								\
-})
-
 #define remove_parent(p)	list_del_init(&(p)->sibling)
 #define add_parent(p, parent)	list_add_tail(&(p)->sibling,&(parent)->children)
 
@@ -955,7 +983,7 @@
 
 /* Reevaluate whether the task has signals pending delivery.
    This is required every time the blocked sigset_t changes.
-   Athread cathreaders should have t->sigmask_lock.  */
+   callers must hold sig->siglock.  */
 
 extern FASTCALL(void recalc_sigpending_tsk(struct task_struct *t));
 extern void recalc_sigpending(void);
diff -Nru a/include/linux/slab.h b/include/linux/slab.h
--- a/include/linux/slab.h	Tue Oct  1 00:08:17 2002
+++ b/include/linux/slab.h	Tue Oct  1 00:08:17 2002
@@ -21,7 +21,6 @@
 #define	SLAB_ATOMIC		GFP_ATOMIC
 #define	SLAB_USER		GFP_USER
 #define	SLAB_KERNEL		GFP_KERNEL
-#define	SLAB_NFS		GFP_NFS
 #define	SLAB_DMA		GFP_DMA
 
 #define SLAB_LEVEL_MASK		(__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_HIGHIO|__GFP_FS)
diff -Nru a/include/linux/smb.h b/include/linux/smb.h
--- a/include/linux/smb.h	Tue Oct  1 00:08:17 2002
+++ b/include/linux/smb.h	Tue Oct  1 00:08:17 2002
@@ -76,7 +76,6 @@
  * Contains all relevant data on a SMB networked file.
  */
 struct smb_fattr {
-
 	__u16 attr;
 
 	unsigned long	f_ino;
@@ -84,12 +83,14 @@
 	nlink_t		f_nlink;
 	uid_t		f_uid;
 	gid_t		f_gid;
+	dev_t		f_rdev;
 	loff_t		f_size;
 	time_t		f_atime;
 	time_t		f_mtime;
 	time_t		f_ctime;
 	unsigned long	f_blksize;
 	unsigned long	f_blocks;
+	int		f_unix;
 };
 
 enum smb_conn_state {
diff -Nru a/include/linux/smb_fs.h b/include/linux/smb_fs.h
--- a/include/linux/smb_fs.h	Tue Oct  1 00:08:18 2002
+++ b/include/linux/smb_fs.h	Tue Oct  1 00:08:18 2002
@@ -112,19 +112,20 @@
 
 
 /* NT1 protocol capability bits */
-#define SMB_CAP_RAW_MODE         0x0001
-#define SMB_CAP_MPX_MODE         0x0002
-#define SMB_CAP_UNICODE          0x0004
-#define SMB_CAP_LARGE_FILES      0x0008
-#define SMB_CAP_NT_SMBS          0x0010
-#define SMB_CAP_RPC_REMOTE_APIS  0x0020
-#define SMB_CAP_STATUS32         0x0040
-#define SMB_CAP_LEVEL_II_OPLOCKS 0x0080
-#define SMB_CAP_LOCK_AND_READ    0x0100
-#define SMB_CAP_NT_FIND          0x0200
-#define SMB_CAP_DFS              0x1000
-#define SMB_CAP_LARGE_READX      0x4000
-#define SMB_CAP_LARGE_WRITEX     0x8000
+#define SMB_CAP_RAW_MODE         0x00000001
+#define SMB_CAP_MPX_MODE         0x00000002
+#define SMB_CAP_UNICODE          0x00000004
+#define SMB_CAP_LARGE_FILES      0x00000008
+#define SMB_CAP_NT_SMBS          0x00000010
+#define SMB_CAP_RPC_REMOTE_APIS  0x00000020
+#define SMB_CAP_STATUS32         0x00000040
+#define SMB_CAP_LEVEL_II_OPLOCKS 0x00000080
+#define SMB_CAP_LOCK_AND_READ    0x00000100
+#define SMB_CAP_NT_FIND          0x00000200
+#define SMB_CAP_DFS              0x00001000
+#define SMB_CAP_LARGE_READX      0x00004000
+#define SMB_CAP_LARGE_WRITEX     0x00008000
+#define SMB_CAP_UNIX             0x00800000	/* unofficial ... */
 
 
 /*
diff -Nru a/include/linux/smbno.h b/include/linux/smbno.h
--- a/include/linux/smbno.h	Tue Oct  1 00:08:17 2002
+++ b/include/linux/smbno.h	Tue Oct  1 00:08:17 2002
@@ -328,4 +328,36 @@
 #define SMB_FLAGS2_32_BIT_ERROR_CODES		0x4000 
 #define SMB_FLAGS2_UNICODE_STRINGS		0x8000
 
+
+/*
+ * UNIX stuff  (from samba trans2.h)
+ */
+#define MIN_UNIX_INFO_LEVEL		0x200
+#define MAX_UNIX_INFO_LEVEL		0x2FF
+#define SMB_FIND_FILE_UNIX		0x202
+#define SMB_QUERY_FILE_UNIX_BASIC	0x200
+#define SMB_QUERY_FILE_UNIX_LINK	0x201
+#define SMB_QUERY_FILE_UNIX_HLINK	0x202
+#define SMB_SET_FILE_UNIX_BASIC		0x200
+#define SMB_SET_FILE_UNIX_LINK		0x201
+#define SMB_SET_FILE_UNIX_HLINK		0x203
+#define SMB_QUERY_CIFS_UNIX_INFO	0x200
+
+/* values which means "don't change it" */
+#define SMB_MODE_NO_CHANGE		0xFFFFFFFF
+#define SMB_UID_NO_CHANGE		0xFFFFFFFF
+#define SMB_GID_NO_CHANGE		0xFFFFFFFF
+#define SMB_TIME_NO_CHANGE		0xFFFFFFFFFFFFFFFF
+#define SMB_SIZE_NO_CHANGE		0xFFFFFFFFFFFFFFFF
+
+/* UNIX filetype mappings. */
+#define UNIX_TYPE_FILE		0
+#define UNIX_TYPE_DIR		1
+#define UNIX_TYPE_SYMLINK	2
+#define UNIX_TYPE_CHARDEV	3
+#define UNIX_TYPE_BLKDEV	4
+#define UNIX_TYPE_FIFO		5
+#define UNIX_TYPE_SOCKET	6
+#define UNIX_TYPE_UNKNOWN	0xFFFFFFFF
+
 #endif /* _SMBNO_H_ */
diff -Nru a/include/linux/swap.h b/include/linux/swap.h
--- a/include/linux/swap.h	Tue Oct  1 00:08:15 2002
+++ b/include/linux/swap.h	Tue Oct  1 00:08:15 2002
@@ -162,7 +162,6 @@
 extern void swap_setup(void);
 
 /* linux/mm/vmscan.c */
-extern wait_queue_head_t kswapd_wait;
 extern int try_to_free_pages(struct zone *, unsigned int, unsigned int);
 
 /* linux/mm/page_io.c */
diff -Nru a/include/linux/timer.h b/include/linux/timer.h
--- a/include/linux/timer.h	Tue Oct  1 00:08:15 2002
+++ b/include/linux/timer.h	Tue Oct  1 00:08:15 2002
@@ -2,11 +2,15 @@
 #define _LINUX_TIMER_H
 
 #include <linux/config.h>
+#include <linux/smp.h>
 #include <linux/stddef.h>
 #include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/cache.h>
+
+struct tvec_t_base_s;
 
 /*
- * In Linux 2.4, static timers have been removed from the kernel.
  * Timers may be dynamically created and destroyed, and should be initialized
  * by a call to init_timer() upon creation.
  *
@@ -14,22 +18,31 @@
  * timeouts. You can use this field to distinguish between the different
  * invocations.
  */
-struct timer_list {
+typedef struct timer_list {
 	struct list_head list;
 	unsigned long expires;
 	unsigned long data;
 	void (*function)(unsigned long);
-};
-
-extern void add_timer(struct timer_list * timer);
-extern int del_timer(struct timer_list * timer);
+	struct tvec_t_base_s *base;
+} timer_t;
 
+extern void add_timer(timer_t * timer);
+extern int del_timer(timer_t * timer);
+  
 #ifdef CONFIG_SMP
-extern int del_timer_sync(struct timer_list * timer);
+extern int del_timer_sync(timer_t * timer);
+extern void sync_timers(void);
+#define timer_enter(base, t) do { base->running_timer = t; mb(); } while (0)
+#define timer_exit(base) do { base->running_timer = NULL; } while (0)
+#define timer_is_running(base,t) (base->running_timer == t)
+#define timer_synchronize(base,t) while (timer_is_running(base,t)) barrier()
 #else
 #define del_timer_sync(t)	del_timer(t)
+#define sync_timers()		do { } while (0)
+#define timer_enter(base,t)          do { } while (0)
+#define timer_exit(base)            do { } while (0)
 #endif
-
+  
 /*
  * mod_timer is a more efficient way to update the expire field of an
  * active timer (if the timer is inactive it will be activated)
@@ -37,16 +50,20 @@
  * If the timer is known to be not pending (ie, in the handler), mod_timer
  * is less efficient than a->expires = b; add_timer(a).
  */
-int mod_timer(struct timer_list *timer, unsigned long expires);
+int mod_timer(timer_t *timer, unsigned long expires);
 
 extern void it_real_fn(unsigned long);
 
-static inline void init_timer(struct timer_list * timer)
+extern void init_timers(void);
+extern void run_local_timers(void);
+
+static inline void init_timer(timer_t * timer)
 {
 	timer->list.next = timer->list.prev = NULL;
+	timer->base = NULL;
 }
 
-static inline int timer_pending (const struct timer_list * timer)
+static inline int timer_pending(const timer_t * timer)
 {
 	return timer->list.next != NULL;
 }
diff -Nru a/include/linux/tqueue.h b/include/linux/tqueue.h
--- a/include/linux/tqueue.h	Tue Oct  1 00:08:15 2002
+++ b/include/linux/tqueue.h	Tue Oct  1 00:08:15 2002
@@ -1,13 +1,12 @@
 /*
  * tqueue.h --- task queue handling for Linux.
  *
- * Mostly based on a proposed bottom-half replacement code written by
- * Kai Petzke, wpp@marie.physik.tu-berlin.de.
+ * Modified version of previous incarnations of task-queues,
+ * written by:
  *
+ * (C) 1994 Kai Petzke, wpp@marie.physik.tu-berlin.de
  * Modified for use in the Linux kernel by Theodore Ts'o,
- * tytso@mit.edu.  Any bugs are my fault, not Kai's.
- *
- * The original comment follows below.
+ * tytso@mit.edu.
  */
 
 #ifndef _LINUX_TQUEUE_H
@@ -18,25 +17,8 @@
 #include <linux/bitops.h>
 #include <asm/system.h>
 
-/*
- * New proposed "bottom half" handlers:
- * (C) 1994 Kai Petzke, wpp@marie.physik.tu-berlin.de
- *
- * Advantages:
- * - Bottom halfs are implemented as a linked list.  You can have as many
- *   of them, as you want.
- * - No more scanning of a bit field is required upon call of a bottom half.
- * - Support for chained bottom half lists.  The run_task_queue() function can be
- *   used as a bottom half handler.  This is for example useful for bottom
- *   halfs, which want to be delayed until the next clock tick.
- *
- * Notes:
- * - Bottom halfs are called in the reverse order that they were linked into
- *   the list.
- */
-
 struct tq_struct {
-	struct list_head list;		/* linked list of active bh's */
+	struct list_head list;		/* linked list of active tq's */
 	unsigned long sync;		/* must be initialized to zero */
 	void (*routine)(void *);	/* function to call */
 	void *data;			/* argument to function */
@@ -61,68 +43,13 @@
 		PREPARE_TQUEUE((_tq), (_routine), (_data));	\
 	} while (0)
 
-typedef struct list_head task_queue;
-
 #define DECLARE_TASK_QUEUE(q)	LIST_HEAD(q)
-#define TQ_ACTIVE(q)		(!list_empty(&q))
-
-extern task_queue tq_timer, tq_immediate;
-
-/*
- * To implement your own list of active bottom halfs, use the following
- * two definitions:
- *
- * DECLARE_TASK_QUEUE(my_tqueue);
- * struct tq_struct my_task = {
- * 	routine: (void (*)(void *)) my_routine,
- *	data: &my_data
- * };
- *
- * To activate a bottom half on a list, use:
- *
- *	queue_task(&my_task, &my_tqueue);
- *
- * To later run the queued tasks use
- *
- *	run_task_queue(&my_tqueue);
- *
- * This allows you to do deferred processing.  For example, you could
- * have a task queue called tq_timer, which is executed within the timer
- * interrupt.
- */
-
-extern spinlock_t tqueue_lock;
-
-/*
- * Queue a task on a tq.  Return non-zero if it was successfully
- * added.
- */
-static inline int queue_task(struct tq_struct *bh_pointer, task_queue *bh_list)
-{
-	int ret = 0;
-	if (!test_and_set_bit(0,&bh_pointer->sync)) {
-		unsigned long flags;
-		spin_lock_irqsave(&tqueue_lock, flags);
-		list_add_tail(&bh_pointer->list, bh_list);
-		spin_unlock_irqrestore(&tqueue_lock, flags);
-		ret = 1;
-	}
-	return ret;
-}
 
 /* Schedule a tq to run in process context */
 extern int schedule_task(struct tq_struct *task);
 
-/*
- * Call all "bottom halfs" on a given list.
- */
-
-extern void __run_task_queue(task_queue *list);
+/* finish all currently pending tasks - do not call from irq context */
+extern void flush_scheduled_tasks(void);
 
-static inline void run_task_queue(task_queue *list)
-{
-	if (TQ_ACTIVE(*list))
-		__run_task_queue(list);
-}
+#endif
 
-#endif /* _LINUX_TQUEUE_H */
diff -Nru a/include/linux/tty_flip.h b/include/linux/tty_flip.h
--- a/include/linux/tty_flip.h	Tue Oct  1 00:08:17 2002
+++ b/include/linux/tty_flip.h	Tue Oct  1 00:08:17 2002
@@ -19,7 +19,7 @@
 
 _INLINE_ void tty_schedule_flip(struct tty_struct *tty)
 {
-	queue_task(&tty->flip.tqueue, &tq_timer);
+	schedule_task(&tty->flip.tqueue);
 }
 
 #undef _INLINE_
diff -Nru a/include/linux/usb.h b/include/linux/usb.h
--- a/include/linux/usb.h	Tue Oct  1 00:08:17 2002
+++ b/include/linux/usb.h	Tue Oct  1 00:08:17 2002
@@ -84,6 +84,7 @@
 #include <linux/list.h>		/* for struct list_head */
 #include <linux/device.h>	/* for struct device */
 #include <linux/fs.h>		/* for struct file_operations */
+#include <linux/completion.h>	/* for struct completion */
 
 
 static __inline__ void wait_ms(unsigned int ms)
@@ -452,9 +453,9 @@
  * User mode code can read these tables to choose which modules to load.
  * Declare the table as a MODULE_DEVICE_TABLE.
  *
- * The third probe() parameter will point to a matching entry from this
- * table.  (Null value reserved.)  Use the driver_data field for each
- * match to hold information tied to that match:  device quirks, etc.
+ * A probe() parameter will point to a matching entry from this table.
+ * Use the driver_info field for each match to hold information tied
+ * to that match:  device quirks, etc.
  *
  * Terminate the driver's table with an all-zeroes entry.
  * Use the flag values to control which fields are compared.
@@ -604,17 +605,14 @@
  * @name: The driver name should be unique among USB drivers,
  *	and should normally be the same as the module name.
  * @probe: Called to see if the driver is willing to manage a particular
- *	interface on a device.  The probe routine returns a handle that 
- *	will later be provided to disconnect(), or a null pointer to
- *	indicate that the driver will not handle the interface.
- *	The handle is normally a pointer to driver-specific data.
- *	If the probe() routine needs to access the interface
- *	structure itself, use usb_ifnum_to_if() to make sure it's using
- *	the right one.
+ *	interface on a device.  If it is, probe returns zero and uses
+ *	dev_set_drvdata() to associate driver-specific data with the
+ *	interface.  It may also use usb_set_interface() to specify the
+ *	appropriate altsetting.  If unwilling to manage the interface,
+ *	return a negative errno value.
  * @disconnect: Called when the interface is no longer accessible, usually
- *	because its device has been (or is being) disconnected.  The
- *	handle passed is what was returned by probe(), or was provided
- *	to usb_driver_claim_interface().
+ *	because its device has been (or is being) disconnected or the
+ *	driver module is being unloaded.
  * @ioctl: Used for drivers that want to talk to userspace through
  *	the "usbfs" filesystem.  This lets devices provide ways to
  *	expose information to user space regardless of where they
@@ -648,7 +646,7 @@
 
 	void (*disconnect) (struct usb_interface *intf);
 
-	int (*ioctl) (struct usb_device *dev, unsigned int code, void *buf);
+	int (*ioctl) (struct usb_interface *intf, unsigned int code, void *buf);
 
 	const struct usb_device_id *id_table;
 
@@ -1073,6 +1071,57 @@
 #endif
 
 #define USB_CTRL_SET_TIMEOUT	3
+
+
+/**
+ * struct usb_sg_request - support for scatter/gather I/O
+ * @status: zero indicates success, else negative errno
+ * @bytes: counts bytes transferred.
+ *
+ * These requests are initialized using usb_sg_init(), and then are used
+ * as request handles passed to usb_sg_wait() or usb_sg_cancel().  Most
+ * members of the request object aren't for driver access.
+ *
+ * The status and bytecount values are valid only after usb_sg_wait()
+ * returns.  If the status is zero, then the bytecount matches the total
+ * from the request.
+ *
+ * After an error completion, drivers may need to clear a halt condition
+ * on the endpoint.
+ */
+struct usb_sg_request {
+	int			status;
+	size_t			bytes;
+
+	// members not documented above are private to usbcore,
+	// and are not provided for driver access!
+	spinlock_t		lock;
+
+	struct usb_device	*dev;
+	int			pipe;
+	struct scatterlist	*sg;
+	int			nents;
+
+	int			entries;
+	struct urb		**urbs;
+
+	int			count;
+	struct completion	complete;
+};
+
+int usb_sg_init (
+	struct usb_sg_request	*io,
+	struct usb_device	*dev,
+	unsigned		pipe, 
+	unsigned		period,
+	struct scatterlist	*sg,
+	int			nents,
+	size_t			length,
+	int			mem_flags
+);
+void usb_sg_cancel (struct usb_sg_request *io);
+void usb_sg_wait (struct usb_sg_request *io);
+
 
 /* -------------------------------------------------------------------------- */
 
diff -Nru a/include/linux/usbdevice_fs.h b/include/linux/usbdevice_fs.h
--- a/include/linux/usbdevice_fs.h	Tue Oct  1 00:08:16 2002
+++ b/include/linux/usbdevice_fs.h	Tue Oct  1 00:08:16 2002
@@ -108,7 +108,7 @@
 	struct usbdevfs_iso_packet_desc iso_frame_desc[0];
 };
 
-/* ioctls for talking to drivers in the usbcore module: */
+/* ioctls for talking directly to drivers */
 struct usbdevfs_ioctl {
 	int	ifno;		/* interface 0..N ; negative numbers reserved */
 	int	ioctl_code;	/* MUST encode size + direction of data so the
diff -Nru a/include/net/lapb.h b/include/net/lapb.h
--- a/include/net/lapb.h	Tue Oct  1 00:08:20 2002
+++ b/include/net/lapb.h	Tue Oct  1 00:08:20 2002
@@ -78,8 +78,8 @@
 /*
  *	The per LAPB connection control structure.
  */
-typedef struct lapb_cb {
-	struct lapb_cb		*next;
+struct lapb_cb {
+	struct list_head	node;
 	void			*token;
 
 	/* Link status fields */
@@ -100,43 +100,45 @@
 	/* FRMR control information */
 	struct lapb_frame	frmr_data;
 	unsigned char		frmr_type;
-} lapb_cb;
+
+	atomic_t		refcnt;
+};
 
 /* lapb_iface.c */
-extern void lapb_connect_confirmation(lapb_cb *, int);
-extern void lapb_connect_indication(lapb_cb *, int);
-extern void lapb_disconnect_confirmation(lapb_cb *, int);
-extern void lapb_disconnect_indication(lapb_cb *, int);
-extern int  lapb_data_indication(lapb_cb *, struct sk_buff *);
-extern int  lapb_data_transmit(lapb_cb *, struct sk_buff *);
+extern void lapb_connect_confirmation(struct lapb_cb *lapb, int);
+extern void lapb_connect_indication(struct lapb_cb *lapb, int);
+extern void lapb_disconnect_confirmation(struct lapb_cb *lapb, int);
+extern void lapb_disconnect_indication(struct lapb_cb *lapb, int);
+extern int  lapb_data_indication(struct lapb_cb *lapb, struct sk_buff *);
+extern int  lapb_data_transmit(struct lapb_cb *lapb, struct sk_buff *);
 
 /* lapb_in.c */
-extern void lapb_data_input(lapb_cb *, struct sk_buff *);
+extern void lapb_data_input(struct lapb_cb *lapb, struct sk_buff *);
 
 /* lapb_out.c */
-extern void lapb_kick(lapb_cb *);
-extern void lapb_transmit_buffer(lapb_cb *, struct sk_buff *, int);
-extern void lapb_establish_data_link(lapb_cb *);
-extern void lapb_enquiry_response(lapb_cb *);
-extern void lapb_timeout_response(lapb_cb *);
-extern void lapb_check_iframes_acked(lapb_cb *, unsigned short);
-extern void lapb_check_need_response(lapb_cb *, int, int);
+extern void lapb_kick(struct lapb_cb *lapb);
+extern void lapb_transmit_buffer(struct lapb_cb *lapb, struct sk_buff *, int);
+extern void lapb_establish_data_link(struct lapb_cb *lapb);
+extern void lapb_enquiry_response(struct lapb_cb *lapb);
+extern void lapb_timeout_response(struct lapb_cb *lapb);
+extern void lapb_check_iframes_acked(struct lapb_cb *lapb, unsigned short);
+extern void lapb_check_need_response(struct lapb_cb *lapb, int, int);
 
 /* lapb_subr.c */
-extern void lapb_clear_queues(lapb_cb *);
-extern void lapb_frames_acked(lapb_cb *, unsigned short);
-extern void lapb_requeue_frames(lapb_cb *);
-extern int  lapb_validate_nr(lapb_cb *, unsigned short);
-extern void lapb_decode(lapb_cb *, struct sk_buff *, struct lapb_frame *);
-extern void lapb_send_control(lapb_cb *, int, int, int);
-extern void lapb_transmit_frmr(lapb_cb *);
+extern void lapb_clear_queues(struct lapb_cb *lapb);
+extern void lapb_frames_acked(struct lapb_cb *lapb, unsigned short);
+extern void lapb_requeue_frames(struct lapb_cb *lapb);
+extern int  lapb_validate_nr(struct lapb_cb *lapb, unsigned short);
+extern void lapb_decode(struct lapb_cb *lapb, struct sk_buff *, struct lapb_frame *);
+extern void lapb_send_control(struct lapb_cb *lapb, int, int, int);
+extern void lapb_transmit_frmr(struct lapb_cb *lapb);
 
 /* lapb_timer.c */
-extern void lapb_start_t1timer(lapb_cb *);
-extern void lapb_start_t2timer(lapb_cb *);
-extern void lapb_stop_t1timer(lapb_cb *);
-extern void lapb_stop_t2timer(lapb_cb *);
-extern int  lapb_t1timer_running(lapb_cb *);
+extern void lapb_start_t1timer(struct lapb_cb *lapb);
+extern void lapb_start_t2timer(struct lapb_cb *lapb);
+extern void lapb_stop_t1timer(struct lapb_cb *lapb);
+extern void lapb_stop_t2timer(struct lapb_cb *lapb);
+extern int  lapb_t1timer_running(struct lapb_cb *lapb);
 
 /*
  * Debug levels.
diff -Nru a/include/net/llc_conn.h b/include/net/llc_conn.h
--- a/include/net/llc_conn.h	Tue Oct  1 00:08:19 2002
+++ b/include/net/llc_conn.h	Tue Oct  1 00:08:19 2002
@@ -21,7 +21,6 @@
 };
 
 struct llc_opt {
-	struct list_head    node;		/* entry in sap->sk_list.list */
 	struct sock	    *sk;		/* sock that has this llc_opt */
 	struct sockaddr_llc addr;		/* address sock is bound to */
 	u8		    state;		/* state of connection */
diff -Nru a/include/net/llc_mac.h b/include/net/llc_mac.h
--- a/include/net/llc_mac.h	Tue Oct  1 00:08:19 2002
+++ b/include/net/llc_mac.h	Tue Oct  1 00:08:19 2002
@@ -11,8 +11,6 @@
  *
  * See the GNU General Public License for more details.
  */
-/* Defines MAC-layer interface to LLC layer */
-extern int mac_send_pdu(struct sk_buff *skb);
 extern int llc_rcv(struct sk_buff *skb, struct net_device *dev,
 		   struct packet_type *pt);
 extern struct net_device *mac_dev_peer(struct net_device *current_dev,
diff -Nru a/include/net/llc_sap.h b/include/net/llc_sap.h
--- a/include/net/llc_sap.h	Tue Oct  1 00:08:14 2002
+++ b/include/net/llc_sap.h	Tue Oct  1 00:08:14 2002
@@ -44,5 +44,4 @@
 extern void llc_sap_unassign_sock(struct llc_sap *sap, struct sock *sk);
 extern void llc_sap_state_process(struct llc_sap *sap, struct sk_buff *skb);
 extern void llc_sap_rtn_pdu(struct llc_sap *sap, struct sk_buff *skb);
-extern void llc_sap_send_pdu(struct llc_sap *sap, struct sk_buff *skb);
 #endif /* LLC_SAP_H */
diff -Nru a/include/net/sock.h b/include/net/sock.h
--- a/include/net/sock.h	Tue Oct  1 00:08:18 2002
+++ b/include/net/sock.h	Tue Oct  1 00:08:18 2002
@@ -309,7 +309,8 @@
 extern void __lock_sock(struct sock *sk);
 extern void __release_sock(struct sock *sk);
 #define lock_sock(__sk) \
-do {	spin_lock_bh(&((__sk)->lock.slock)); \
+do {	might_sleep(); \
+	spin_lock_bh(&((__sk)->lock.slock)); \
 	if ((__sk)->lock.users != 0) \
 		__lock_sock(__sk); \
 	(__sk)->lock.users = 1; \
diff -Nru a/include/net/x25.h b/include/net/x25.h
--- a/include/net/x25.h	Tue Oct  1 00:08:18 2002
+++ b/include/net/x25.h	Tue Oct  1 00:08:18 2002
@@ -101,25 +101,35 @@
 #define	X25_MAX_FAC_LEN		20		/* Plenty to spare */
 #define	X25_MAX_CUD_LEN		128
 
+/**
+ *	struct x25_route - x25 routing entry
+ *	@node - entry in x25_list_lock
+ *	@address - Start of address range
+ *	@sigdigits - Number of sig digits
+ *	@dev - More than one for MLP
+ *	@refcnt - reference counter
+ */
 struct x25_route {
-	struct x25_route	*next;
-	struct x25_address	address;	/* Start of address range */
-	unsigned int		sigdigits;	/* Number of sig digits */
-	struct net_device	*dev;		/* More than one for MLP */
+	struct list_head	node;		
+	struct x25_address	address;
+	unsigned int		sigdigits;
+	struct net_device	*dev;
+	atomic_t		refcnt;
 };
 
 struct x25_neigh {
-	struct x25_neigh	*next;
-	struct net_device		*dev;
+	struct list_head	node;
+	struct net_device	*dev;
 	unsigned int		state;
 	unsigned int		extended;
 	struct sk_buff_head	queue;
 	unsigned long		t20;
 	struct timer_list	t20timer;
 	unsigned long		global_facil_mask;
+	atomic_t		refcnt;
 };
 
-typedef struct {
+struct x25_opt {
 	struct x25_address	source_addr, dest_addr;
 	struct x25_neigh	*neighbour;
 	unsigned int		lci;
@@ -137,9 +147,9 @@
 	struct x25_facilities	facilities;
 	struct x25_calluserdata	calluserdata;
 	unsigned long 		vc_facil_mask;	/* inc_call facilities mask */
-} x25_cb;
+};
 
-#define x25_sk(__sk) ((x25_cb *)(__sk)->protinfo)
+#define x25_sk(__sk) ((struct x25_opt *)(__sk)->protinfo)
 
 /* af_x25.c */
 extern int  sysctl_x25_restart_request_timeout;
@@ -190,18 +200,41 @@
 extern struct x25_neigh *x25_get_neigh(struct net_device *);
 extern void x25_link_free(void);
 
+/* x25_neigh.c */
+static __inline__ void x25_neigh_hold(struct x25_neigh *nb)
+{
+	atomic_inc(&nb->refcnt);
+}
+
+static __inline__ void x25_neigh_put(struct x25_neigh *nb)
+{
+	if (atomic_dec_and_test(&nb->refcnt))
+		kfree(nb);
+}
+
 /* x25_out.c */
 extern  int x25_output(struct sock *, struct sk_buff *);
 extern void x25_kick(struct sock *);
 extern void x25_enquiry_response(struct sock *);
 
 /* x25_route.c */
-extern struct net_device *x25_get_route(struct x25_address *);
+extern struct x25_route *x25_get_route(struct x25_address *addr);
 extern struct net_device *x25_dev_get(char *);
 extern void x25_route_device_down(struct net_device *);
 extern int  x25_route_ioctl(unsigned int, void *);
 extern int  x25_routes_get_info(char *, char **, off_t, int);
 extern void x25_route_free(void);
+
+static __inline__ void x25_route_hold(struct x25_route *rt)
+{
+	atomic_inc(&rt->refcnt);
+}
+
+static __inline__ void x25_route_put(struct x25_route *rt)
+{
+	if (atomic_dec_and_test(&rt->refcnt))
+		kfree(rt);
+}
 
 /* x25_subr.c */
 extern void x25_clear_queues(struct sock *);
diff -Nru a/include/scsi/sg.h b/include/scsi/sg.h
--- a/include/scsi/sg.h	Tue Oct  1 00:08:17 2002
+++ b/include/scsi/sg.h	Tue Oct  1 00:08:17 2002
@@ -304,7 +304,12 @@
 
 
 /* Defaults, commented if they differ from original sg driver */
-#define SG_DEFAULT_TIMEOUT (60*HZ) /* HZ == 'jiffies in 1 second' */
+#ifdef __KERNEL__
+#define SG_DEFAULT_TIMEOUT_USER	(60*USER_HZ) /* HZ == 'jiffies in 1 second' */
+#else
+#define SG_DEFAULT_TIMEOUT	(60*HZ)	     /* HZ == 'jiffies in 1 second' */
+#endif
+
 #define SG_DEF_COMMAND_Q 0     /* command queuing is always on when
 				  the new interface is used */
 #define SG_DEF_UNDERRUN_FLAG 0
diff -Nru a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h
--- a/include/sound/ac97_codec.h	Tue Oct  1 00:08:17 2002
+++ b/include/sound/ac97_codec.h	Tue Oct  1 00:08:17 2002
@@ -127,6 +127,14 @@
 #define AC97_CSR_SPECF_DATA	0x6e	/* Special Feature Data */
 #define AC97_CSR_BDI_STATUS	0x7a	/* BDI Status */
 
+/* specific - Conexant */
+#define AC97_CXR_AUDIO_MISC	0x5c
+#define AC97_CXR_SPDIFEN	(1<<3)
+#define AC97_CXR_COPYRGT	(1<<2)
+#define AC97_CXR_SPDIF_MASK	(3<<0)
+#define AC97_CXR_SPDIF_PCM	0x0
+#define AC97_CXR_SPDIF_AC3	0x2
+
 /* ac97->scaps */
 #define AC97_SCAP_SURROUND_DAC	(1<<0)	/* surround L&R DACs are present */
 #define AC97_SCAP_CENTER_LFE_DAC (1<<1)	/* center and LFE DACs are present */
@@ -135,6 +143,7 @@
 #define AC97_HAS_PC_BEEP	(1<<0)	/* force PC Speaker usage */
 #define AC97_AD_MULTI		(1<<1)	/* Analog Devices - multi codecs */
 #define AC97_CS_SPDIF		(1<<2)	/* Cirrus Logic uses funky SPDIF */
+#define AC97_CX_SPDIF		(1<<3)	/* Conexant's spdif interface */
 
 /*
 
@@ -143,6 +152,7 @@
 typedef struct _snd_ac97 ac97_t;
 
 struct _snd_ac97 {
+	void (*reset) (ac97_t *ac97);
 	void (*write) (ac97_t *ac97, unsigned short reg, unsigned short val);
 	unsigned short (*read) (ac97_t *ac97, unsigned short reg);
 	void (*wait) (ac97_t *ac97);
@@ -169,6 +179,7 @@
 	unsigned int rates_mic_adc;
 	unsigned int spdif_status;
 	unsigned short regs[0x80]; /* register cache */
+	unsigned int limited_regs; /* allow limited registers only */
 	bitmap_member(reg_accessed,0x80); /* bit flags */
 	union {			/* vendor specific code */
 		struct {
diff -Nru a/include/sound/asequencer.h b/include/sound/asequencer.h
--- a/include/sound/asequencer.h	Tue Oct  1 00:08:17 2002
+++ b/include/sound/asequencer.h	Tue Oct  1 00:08:17 2002
@@ -257,7 +257,7 @@
 struct sndrv_seq_ev_ext {
 	unsigned int len;	/* length of data */
 	void *ptr;		/* pointer to data (note: maybe 64-bit) */
-};
+} __attribute__((packed));
 
 /* Instrument cluster type */
 typedef unsigned int sndrv_seq_instr_cluster_t;
@@ -373,7 +373,7 @@
 	struct sndrv_seq_addr origin;		/* original sender */
 	unsigned short value;		/* optional data */
 	struct sndrv_seq_event *event;		/* quoted event */
-};
+} __attribute__((packed));
 
 
 	/* sequencer event */
@@ -486,6 +486,16 @@
 };
 
 
+	/* system running information */
+struct sndrv_seq_running_info {
+	unsigned char client;		/* client id */
+	unsigned char big_endian;	/* 1 = big-endian */
+	unsigned char cpu_mode;		/* 4 = 32bit, 8 = 64bit */
+	unsigned char pad;		/* reserved */
+	unsigned char reserved[12];
+};
+
+
 	/* known client numbers */
 #define SNDRV_SEQ_CLIENT_SYSTEM		0
 #define SNDRV_SEQ_CLIENT_DUMMY		62	/* dummy ports */
@@ -609,7 +619,6 @@
 	int write_use;			/* R/O: subscribers for input (to this port) */
 
 	void *kernel;			/* reserved for kernel use (must be NULL) */
-
 	unsigned int flags;		/* misc. conditioning */
 	char reserved[60];		/* for future use */
 };
@@ -853,6 +862,7 @@
 #define SNDRV_SEQ_IOCTL_PVERSION	_IOR ('S', 0x00, int)
 #define SNDRV_SEQ_IOCTL_CLIENT_ID	_IOR ('S', 0x01, int)
 #define SNDRV_SEQ_IOCTL_SYSTEM_INFO	_IOWR('S', 0x02, struct sndrv_seq_system_info)
+#define SNDRV_SEQ_IOCTL_RUNNING_MODE	_IOWR('S', 0x03, struct sndrv_seq_running_info)
 
 #define SNDRV_SEQ_IOCTL_GET_CLIENT_INFO	_IOWR('S', 0x10, struct sndrv_seq_client_info)
 #define SNDRV_SEQ_IOCTL_SET_CLIENT_INFO	_IOW ('S', 0x11, struct sndrv_seq_client_info)
diff -Nru a/include/sound/asound.h b/include/sound/asound.h
--- a/include/sound/asound.h	Tue Oct  1 00:08:18 2002
+++ b/include/sound/asound.h	Tue Oct  1 00:08:18 2002
@@ -128,7 +128,7 @@
  *                                                                           *
  *****************************************************************************/
 
-#define SNDRV_PCM_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 1)
+#define SNDRV_PCM_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 2)
 
 typedef unsigned long sndrv_pcm_uframes_t;
 typedef long sndrv_pcm_sframes_t;
@@ -191,7 +191,19 @@
 	SNDRV_PCM_FORMAT_MPEG,
 	SNDRV_PCM_FORMAT_GSM,
 	SNDRV_PCM_FORMAT_SPECIAL = 31,
-	SNDRV_PCM_FORMAT_LAST = 31,
+	SNDRV_PCM_FORMAT_S24_3LE = 32,	/* in three bytes */
+	SNDRV_PCM_FORMAT_S24_3BE,	/* in three bytes */
+	SNDRV_PCM_FORMAT_U24_3LE,	/* in three bytes */
+	SNDRV_PCM_FORMAT_U24_3BE,	/* in three bytes */
+	SNDRV_PCM_FORMAT_S20_3LE,	/* in three bytes */
+	SNDRV_PCM_FORMAT_S20_3BE,	/* in three bytes */
+	SNDRV_PCM_FORMAT_U20_3LE,	/* in three bytes */
+	SNDRV_PCM_FORMAT_U20_3BE,	/* in three bytes */
+	SNDRV_PCM_FORMAT_S18_3LE,	/* in three bytes */
+	SNDRV_PCM_FORMAT_S18_3BE,	/* in three bytes */
+	SNDRV_PCM_FORMAT_U18_3LE,	/* in three bytes */
+	SNDRV_PCM_FORMAT_U18_3BE,	/* in three bytes */
+	SNDRV_PCM_FORMAT_LAST = SNDRV_PCM_FORMAT_U18_3BE,
 
 #ifdef SNDRV_LITTLE_ENDIAN
 	SNDRV_PCM_FORMAT_S16 = SNDRV_PCM_FORMAT_S16_LE,
@@ -284,7 +296,7 @@
 	SNDRV_PCM_HW_PARAM_SUBFORMAT,	/* Subformat */
 	SNDRV_PCM_HW_PARAM_LAST_MASK = SNDRV_PCM_HW_PARAM_SUBFORMAT,
 
-	SNDRV_PCM_HW_PARAM_SAMPLE_BITS, /* Bits per sample */
+	SNDRV_PCM_HW_PARAM_SAMPLE_BITS = 8, /* Bits per sample */
 	SNDRV_PCM_HW_PARAM_FIRST_INTERVAL = SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
 	SNDRV_PCM_HW_PARAM_FRAME_BITS,	/* Bits per frame */
 	SNDRV_PCM_HW_PARAM_CHANNELS,	/* Channels */
@@ -298,8 +310,7 @@
 	SNDRV_PCM_HW_PARAM_BUFFER_SIZE,	/* Size of buffer in frames */
 	SNDRV_PCM_HW_PARAM_BUFFER_BYTES, /* Size of buffer in bytes */
 	SNDRV_PCM_HW_PARAM_TICK_TIME,	/* Approx tick duration in us */
-	SNDRV_PCM_HW_PARAM_LAST_INTERVAL = SNDRV_PCM_HW_PARAM_TICK_TIME,
-	SNDRV_PCM_HW_PARAM_LAST = SNDRV_PCM_HW_PARAM_LAST_INTERVAL,
+	SNDRV_PCM_HW_PARAM_LAST_INTERVAL = SNDRV_PCM_HW_PARAM_TICK_TIME
 };
 
 #define SNDRV_PCM_HW_PARAMS_RUNTIME		(1<<0)
@@ -312,20 +323,28 @@
 		     empty:1;
 };
 
+#define SNDRV_MASK_MAX	256
+
+struct sndrv_mask {
+	u_int32_t bits[(SNDRV_MASK_MAX+31)/32];
+};
+
 struct sndrv_pcm_hw_params {
 	unsigned int flags;
-	unsigned int masks[SNDRV_PCM_HW_PARAM_LAST_MASK - 
-			   SNDRV_PCM_HW_PARAM_FIRST_MASK + 1];
+	struct sndrv_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK - 
+			       SNDRV_PCM_HW_PARAM_FIRST_MASK + 1];
+	struct sndrv_mask mres[5];	/* reserved masks */
 	struct sndrv_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL -
 				        SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1];
-	unsigned int rmask;
-	unsigned int cmask;
+	struct sndrv_interval ires[9];	/* reserved intervals */
+	unsigned int rmask;		/* W: requested masks */
+	unsigned int cmask;		/* R: changed masks */
 	unsigned int info;		/* R: Info flags for returned setup */
 	unsigned int msbits;		/* R: used most significant bits */
 	unsigned int rate_num;		/* R: rate numerator */
 	unsigned int rate_den;		/* R: rate denominator */
 	sndrv_pcm_uframes_t fifo_size;	/* R: chip FIFO size in frames */
-	unsigned char reserved[64];
+	unsigned char reserved[64];	/* reserved for future */
 };
 
 enum sndrv_pcm_tstamp {
@@ -345,7 +364,7 @@
 	sndrv_pcm_uframes_t silence_threshold;	/* min distance from noise for silence filling */
 	sndrv_pcm_uframes_t silence_size;	/* silence block size */
 	sndrv_pcm_uframes_t boundary;		/* pointers wrap point */
-	unsigned char reserved[64];
+	unsigned char reserved[64];		/* reserved for future */
 };
 
 struct sndrv_pcm_channel_info {
diff -Nru a/include/sound/core.h b/include/sound/core.h
--- a/include/sound/core.h	Tue Oct  1 00:08:21 2002
+++ b/include/sound/core.h	Tue Oct  1 00:08:21 2002
@@ -22,9 +22,8 @@
  *
  */
 
-#ifdef CONFIG_PM
-#include <linux/sched.h>		/* wake_up() and struct semaphore */
-#endif
+#include <linux/sched.h>		/* wake_up() */
+#include <asm/semaphore.h>		/* struct semaphore */
 
 /* Typedef's */
 typedef struct timeval snd_timestamp_t;
@@ -38,6 +37,9 @@
 #ifdef CONFIG_PCI
 struct pci_dev;
 #endif
+#ifdef CONFIG_SBUS
+struct sbus_dev;
+#endif
 
 /* device allocation stuff */
 
@@ -243,8 +245,10 @@
 #define kfree_nocheck(obj) snd_wrapper_kfree(obj)
 #define vmalloc(size) snd_hidden_vmalloc(size)
 #define vfree(obj) snd_hidden_vfree(obj)
+#define vfree_nocheck(obj) snd_wrapper_vfree(obj)
 #else
 #define kfree_nocheck(obj) kfree(obj)
+#define vfree_nocheck(obj) vfree(obj)
 #endif
 void *snd_kcalloc(size_t size, int flags);
 char *snd_kmalloc_strdup(const char *string, int flags);
@@ -255,6 +259,11 @@
 void *snd_malloc_pci_pages(struct pci_dev *pci, unsigned long size, dma_addr_t *dma_addr);
 void *snd_malloc_pci_pages_fallback(struct pci_dev *pci, unsigned long size, dma_addr_t *dma_addr, unsigned long *res_size);
 void snd_free_pci_pages(struct pci_dev *pci, unsigned long size, void *ptr, dma_addr_t dma_addr);
+#endif
+#ifdef CONFIG_SBUS
+void *snd_malloc_sbus_pages(struct sbus_dev *sdev, unsigned long size, dma_addr_t *dma_addr);
+void *snd_malloc_sbus_pages_fallback(struct sbus_dev *sdev, unsigned long size, dma_addr_t *dma_addr, unsigned long *res_size);
+void snd_free_sbus_pages(struct sbus_dev *sdev, unsigned long size, void *ptr, dma_addr_t dma_addr);
 #endif
 #ifdef CONFIG_ISA
 #ifdef CONFIG_PCI
diff -Nru a/include/sound/cs46xx.h b/include/sound/cs46xx.h
--- a/include/sound/cs46xx.h	Tue Oct  1 00:08:16 2002
+++ b/include/sound/cs46xx.h	Tue Oct  1 00:08:16 2002
@@ -26,6 +26,7 @@
 #include "pcm.h"
 #include "rawmidi.h"
 #include "ac97_codec.h"
+#include "cs46xx_dsp_spos.h"
 
 #ifndef PCI_VENDOR_ID_CIRRUS
 #define PCI_VENDOR_ID_CIRRUS            0x1013
@@ -194,6 +195,81 @@
 #define BA1_FRSC                                0x00030038
 #define BA1_OMNI_MEM                            0x000E0000
 
+
+
+
+/*
+ * The following define the offsets of the AC97 shadow registers, which appear
+ * as a virtual extension to the base address register zero memory range.
+ */
+#define AC97_REG_OFFSET_MASK                    0x0000007EL
+#define AC97_CODEC_NUMBER_MASK                  0x00003000L
+
+#define BA0_AC97_RESET                          0x00001000L
+#define BA0_AC97_MASTER_VOLUME                  0x00001002L
+#define BA0_AC97_HEADPHONE_VOLUME               0x00001004L
+#define BA0_AC97_MASTER_VOLUME_MONO             0x00001006L
+#define BA0_AC97_MASTER_TONE                    0x00001008L
+#define BA0_AC97_PC_BEEP_VOLUME                 0x0000100AL
+#define BA0_AC97_PHONE_VOLUME                   0x0000100CL
+#define BA0_AC97_MIC_VOLUME                     0x0000100EL
+#define BA0_AC97_LINE_IN_VOLUME                 0x00001010L
+#define BA0_AC97_CD_VOLUME                      0x00001012L
+#define BA0_AC97_VIDEO_VOLUME                   0x00001014L
+#define BA0_AC97_AUX_VOLUME                     0x00001016L
+#define BA0_AC97_PCM_OUT_VOLUME                 0x00001018L
+#define BA0_AC97_RECORD_SELECT                  0x0000101AL
+#define BA0_AC97_RECORD_GAIN                    0x0000101CL
+#define BA0_AC97_RECORD_GAIN_MIC                0x0000101EL
+#define BA0_AC97_GENERAL_PURPOSE                0x00001020L
+#define BA0_AC97_3D_CONTROL                     0x00001022L
+#define BA0_AC97_MODEM_RATE                     0x00001024L
+#define BA0_AC97_POWERDOWN                      0x00001026L
+#define BA0_AC97_EXT_AUDIO_ID                   0x00001028L
+#define BA0_AC97_EXT_AUDIO_POWER                0x0000102AL
+#define BA0_AC97_PCM_FRONT_DAC_RATE             0x0000102CL
+#define BA0_AC97_PCM_SURR_DAC_RATE              0x0000102EL
+#define BA0_AC97_PCM_LFE_DAC_RATE               0x00001030L
+#define BA0_AC97_PCM_LR_ADC_RATE                0x00001032L
+#define BA0_AC97_MIC_ADC_RATE                   0x00001034L
+#define BA0_AC97_6CH_VOL_C_LFE                  0x00001036L
+#define BA0_AC97_6CH_VOL_SURROUND               0x00001038L
+#define BA0_AC97_RESERVED_3A                    0x0000103AL
+#define BA0_AC97_EXT_MODEM_ID                   0x0000103CL
+#define BA0_AC97_EXT_MODEM_POWER                0x0000103EL
+#define BA0_AC97_LINE1_CODEC_RATE               0x00001040L
+#define BA0_AC97_LINE2_CODEC_RATE               0x00001042L
+#define BA0_AC97_HANDSET_CODEC_RATE             0x00001044L
+#define BA0_AC97_LINE1_CODEC_LEVEL              0x00001046L
+#define BA0_AC97_LINE2_CODEC_LEVEL              0x00001048L
+#define BA0_AC97_HANDSET_CODEC_LEVEL            0x0000104AL
+#define BA0_AC97_GPIO_PIN_CONFIG                0x0000104CL
+#define BA0_AC97_GPIO_PIN_TYPE                  0x0000104EL
+#define BA0_AC97_GPIO_PIN_STICKY                0x00001050L
+#define BA0_AC97_GPIO_PIN_WAKEUP                0x00001052L
+#define BA0_AC97_GPIO_PIN_STATUS                0x00001054L
+#define BA0_AC97_MISC_MODEM_AFE_STAT            0x00001056L
+#define BA0_AC97_RESERVED_58                    0x00001058L
+#define BA0_AC97_CRYSTAL_REV_N_FAB_ID           0x0000105AL
+#define BA0_AC97_TEST_AND_MISC_CTRL             0x0000105CL
+#define BA0_AC97_AC_MODE                        0x0000105EL
+#define BA0_AC97_MISC_CRYSTAL_CONTROL           0x00001060L
+#define BA0_AC97_LINE1_HYPRID_CTRL              0x00001062L
+#define BA0_AC97_VENDOR_RESERVED_64             0x00001064L
+#define BA0_AC97_VENDOR_RESERVED_66             0x00001066L
+#define BA0_AC97_SPDIF_CONTROL                  0x00001068L
+#define BA0_AC97_VENDOR_RESERVED_6A             0x0000106AL
+#define BA0_AC97_VENDOR_RESERVED_6C             0x0000106CL
+#define BA0_AC97_VENDOR_RESERVED_6E             0x0000106EL
+#define BA0_AC97_VENDOR_RESERVED_70             0x00001070L
+#define BA0_AC97_VENDOR_RESERVED_72             0x00001072L
+#define BA0_AC97_VENDOR_RESERVED_74             0x00001074L
+#define BA0_AC97_CAL_ADDRESS                    0x00001076L
+#define BA0_AC97_CAL_DATA                       0x00001078L
+#define BA0_AC97_VENDOR_RESERVED_7A             0x0000107AL
+#define BA0_AC97_VENDOR_ID1                     0x0000107CL
+#define BA0_AC97_VENDOR_ID2                     0x0000107EL
+
 /*
  *  The following defines are for the flags in the host interrupt status
  *  register.
@@ -936,9 +1012,10 @@
 #define SERACC_CHIP_TYPE_MASK                  0x00000001
 #define SERACC_CHIP_TYPE_1_03                  0x00000000
 #define SERACC_CHIP_TYPE_2_0                   0x00000001
-#define SERACC_TWO_CODECS                       0x00000002
-#define SERACC_MDM                              0x00000004
-#define SERACC_HSP                              0x00000008
+#define SERACC_TWO_CODECS                      0x00000002
+#define SERACC_MDM                             0x00000004
+#define SERACC_HSP                             0x00000008
+#define SERACC_ODT                             0x00000010 /* only CS4630 */
 #endif
 
 /*
@@ -1626,12 +1703,39 @@
 #define SAVE_REG_MAX             0x10
 #define POWER_DOWN_ALL         0x7f0f
 
+/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */
+#define MAX_NR_AC97				            4
+#define CS46XX_PRIMARY_CODEC_INDEX          0
+#define CS46XX_SECONDARY_CODEC_INDEX		1
+#define CS46XX_SECONDARY_CODEC_OFFSET		0x80
+#define CS46XX_DSP_CAPTURE_CHANNEL          1
+
 /*
  *
  */
 
 typedef struct _snd_cs46xx cs46xx_t;
 
+typedef struct _snd_cs46xx_pcm_t {
+	unsigned char *hw_area;
+	dma_addr_t hw_addr;	/* PCI bus address, not accessible */
+	unsigned long hw_size;
+  
+	unsigned int ctl;
+	unsigned int shift;	/* Shift count to trasform frames in bytes */
+	unsigned int sw_bufsize;
+	unsigned int sw_data;	/* Offset to next dst (or src) in sw ring buffer */
+	unsigned int sw_io;
+	int sw_ready;		/* Bytes ready to be transferred to/from hw */
+	unsigned int hw_data;	/* Offset to next dst (or src) in hw ring buffer */
+	unsigned int hw_io;	/* Ring buffer hw pointer */
+	int hw_ready;		/* Bytes ready for play (or captured) in hw ring buffer */
+	size_t appl_ptr;	/* Last seen appl_ptr */
+	snd_pcm_substream_t *substream;
+
+	pcm_channel_descriptor_t * pcm_channel;
+} cs46xx_pcm_t;
+
 typedef struct {
 	char name[24];
 	unsigned long base;
@@ -1674,10 +1778,11 @@
 		int hw_ready;		/* Bytes ready for play (or captured) in hw ring buffer */
 		size_t appl_ptr;	/* Last seen appl_ptr */
 		snd_pcm_substream_t *substream;
-	} play, capt;
+	} capt;
 
 
-	ac97_t *ac97;
+	int nr_ac97_codecs;
+	ac97_t *ac97[MAX_NR_AC97];
 
 	struct pci_dev *pci;
 	snd_card_t *card;
@@ -1703,6 +1808,13 @@
 
 #ifdef CONFIG_PM
 	struct pm_dev *pm_dev;
+#endif
+
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	dsp_spos_instance_t * dsp_spos_instance;
+#else /* for compatibility */
+	cs46xx_pcm_t *playback_pcm;
+	unsigned int play_ctl;
 #endif
 };
 
diff -Nru a/include/sound/cs46xx_dsp_scb_types.h b/include/sound/cs46xx_dsp_scb_types.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/sound/cs46xx_dsp_scb_types.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,936 @@
+/*
+ *  The driver for the Cirrus Logic's Sound Fusion CS46XX based soundcards
+ *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *
+ *
+ *   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
+ *
+ *
+ * NOTE: comments are copy/paste from cwcemb80.lst 
+ * provided by Tom Woller at Cirrus (my only
+ * documentation about the SP OS running inside
+ * the DSP) 
+ */
+
+#ifndef __CS46XX_DSP_SCB_TYPES_H__
+#define __CS46XX_DSP_SCB_TYPES_H__
+
+/* This structs are used internally by the SP */
+
+typedef struct _basic_dma_req_t {
+	/* DMA Requestor Word 0 (DCW)  fields:
+
+	   31 [30-28]27  [26:24] 23 22 21 20 [19:18] [17:16] 15 14 13  12  11 10 9 8 7 6  [5:0]
+	   _______________________________________________________________________________________	
+	   |S| SBT  |D|  DBT    |wb|wb|  |  |  LS  |  SS   |Opt|Do|SSG|DSG|  |  | | | | | Dword   |
+	   |H|_____ |H|_________|S_|D |__|__|______|_______|___|ne|__ |__ |__|__|_|_|_|_|_Count -1|
+	*/
+	u32 dcw;                 /* DMA Control Word */
+	u32 dmw;                 /* DMA Mode Word */
+	u32 saw;                 /* Source Address Word */
+	u32 daw;                 /* Destination Address Word  */
+} basic_dma_req_t;
+
+typedef struct _scatter_gather_ext_t {
+	u32 npaw;                /* Next-Page Address Word */
+
+	/* DMA Requestor Word 5 (NPCW)  fields:
+     
+	   31-30 29 28          [27:16]              [15:12]             [11:3]                [2:0] 				
+	   _________________________________________________________________________________________	
+	   |SV  |LE|SE|   Sample-end byte offset   |         | Page-map entry offset for next  |    | 
+	   |page|__|__| ___________________________|_________|__page, if !sample-end___________|____|
+	*/
+	u32 npcw;                /* Next-Page Control Word */
+	u32 lbaw;                /* Loop-Begin Address Word */
+	u32 nplbaw;              /* Next-Page after Loop-Begin Address Word */
+	u32 sgaw;                /* Scatter/Gather Address Word */
+} scatter_gather_ext_t;
+
+typedef struct _volume_control_t {
+	u16 rightTarg;     /* Target volume for left & right channels */
+	u16 leftTarg;
+
+	u16 rightVol;       /* Current left & right channel volumes */
+	u16 leftVol;
+} volume_control_t;
+
+/* Generic stream control block (SCB) structure definition */
+typedef struct _generic_scb_t {
+	/* For streaming I/O, the DSP should never alter any words in the DMA
+	   requestor or the scatter/gather extension.  Only ad hoc DMA request
+	   streams are free to alter the requestor (currently only occur in the
+	   DOS-based MIDI controller and in debugger-inserted code).
+    
+	   If an SCB does not have any associated DMA requestor, these 9 ints
+	   may be freed for use by other tasks, but the pointer to the SCB must
+	   still be such that the insOrd:nextSCB appear at offset 9 from the
+	   SCB pointer.
+     
+	   Basic (non scatter/gather) DMA requestor (4 ints)
+	*/
+  
+	/* Initialized by the host, only modified by DMA 
+	   R/O for the DSP task */
+	basic_dma_req_t  basic_req;  /* Optional */
+
+	/* Scatter/gather DMA requestor extension   (5 ints) 
+	   Initialized by the host, only modified by DMA
+	   DSP task never needs to even read these.
+	*/
+	scatter_gather_ext_t sg_ext;  /* Optional */
+
+	/* Sublist pointer & next stream control block (SCB) link.
+	   Initialized & modified by the host R/O for the DSP task
+	*/
+	u16 next_scb;     /* REQUIRED */
+	u16 sub_list_ptr; /* REQUIRED */
+
+  
+	/* Pointer to this tasks parameter block & stream function pointer 
+	   Initialized by the host  R/O for the DSP task */
+	u16 entry_point;  /* REQUIRED */
+	u16 this_spb;     /* REQUIRED */
+
+
+	/* rsConfig register for stream buffer (rsDMA reg. 
+	   is loaded from basicReq.daw for incoming streams, or 
+	   basicReq.saw, for outgoing streams) 
+
+	   31 30 29  [28:24]     [23:16] 15 14 13 12 11 10 9 8 7 6  5      4      [3:0]
+	   ______________________________________________________________________________
+	   |DMA  |D|maxDMAsize| streamNum|dir|p|  |  |  |  | | |ds |shr 1|rev Cy | mod   |
+	   |prio |_|__________|__________|___|_|__|__|__|__|_|_|___|_____|_______|_______|
+	   31 30 29  [28:24]     [23:16] 15 14 13 12 11 10 9 8 7 6  5      4      [3:0]
+
+
+	   Initialized by the host R/O for the DSP task
+	*/
+	u32  strm_rs_config; /* REQUIRED */
+               // 
+	/* On mixer input streams: indicates mixer input stream configuration
+	   On Tees, this is copied from the stream being snooped
+
+	   Stream sample pointer & MAC-unit mode for this stream 
+     
+	   Initialized by the host Updated by the DSP task
+	*/
+	u32  strm_buf_ptr; /* REQUIRED  */
+
+	/* On mixer input streams: points to next mixer input and is updated by the
+                                   mixer subroutine in the "parent" DSP task
+				   (least-significant 16 bits are preserved, unused)
+    
+           On Tees, the pointer is copied from the stream being snooped on
+	   initialization, and, subsequently, it is copied into the
+	   stream being snooped.
+
+	   On wavetable/3D voices: the strmBufPtr will use all 32 bits to allow for
+                                   fractional phase accumulation
+
+	   Fractional increment per output sample in the input sample buffer
+
+	   (Not used on mixer input streams & redefined on Tees)
+	   On wavetable/3D voices: this 32-bit word specifies the integer.fractional 
+	   increment per output sample.
+	*/
+	u32  strmPhiIncr;
+
+
+	/* Standard stereo volume control
+	   Initialized by the host (host updates target volumes) 
+
+	   Current volumes update by the DSP task
+	   On mixer input streams: required & updated by the mixer subroutine in the
+                                   "parent" DSP task
+
+	   On Tees, both current & target volumes are copied up on initialization,
+	   and, subsequently, the target volume is copied up while the current
+	   volume is copied down.
+     
+	   These two 32-bit words are redefined for wavetable & 3-D voices.    
+	*/
+	volume_control_t vol_ctrl_t;   /* Optional */
+} generic_scb_t;
+
+
+typedef struct _spos_control_block_t {
+	/* WARNING: Certain items in this structure are modified by the host
+	            Any dword that can be modified by the host, must not be
+		    modified by the SP as the host can only do atomic dword
+		    writes, and to do otherwise, even a read modify write, 
+		    may lead to corrupted data on the SP.
+  
+		    This rule does not apply to one off boot time initialisation prior to starting the SP
+	*/
+
+ 
+	/* First element on the Hyper forground task tree */
+	u16 hfg_tree_root_ptr;   /* HOST */			    
+	/* First 3 dwords are written by the host and read-only on the DSP */
+	u16 hfg_stack_base;     /* HOST */
+
+	/* Point to this data structure to enable easy access */
+	u16 spos_cb_ptr;		   /* SP */
+	u16 prev_task_tree_ptr;  /* SP && HOST */
+
+
+	/* Currently Unused */
+	u16 xxinterval_timer_period;   
+	/* Enable extension of SPOS data structure */
+	u16 HFGSPB_ptr;
+
+
+	u16 xxnum_HFG_ticks_thisInterval; 
+	/* Modified by the DSP */
+	u16 xxnum_tntervals;
+
+
+	/* Set by DSP upon encountering a trap (breakpoint) or a spurious
+	   interrupt.  The host must clear this dword after reading it
+	   upon receiving spInt1. */
+	u16 spurious_int_flag;	 /* (Host & SP) Nature of the spurious interrupt */
+	u16 trap_flag;             /* (Host & SP) Nature of detected Trap */
+
+
+	u16 unused2;					
+	u16 invalid_IP_flag;       /* (Host & SP ) Indicate detection of invalid instruction pointer */
+
+
+	/* pointer to forground task tree header for use in next task search */
+	u16 fg_task_tree_hdr_ptr;	  /* HOST */		
+	/* Data structure for controlling synchronous link update */
+	u16  hfg_sync_update_ptr;   /* HOST */
+  
+	u16  begin_foreground_FCNT;  /* SP */
+	/* Place holder for holding sleep timing */
+	u16  last_FCNT_before_sleep; /* SP */
+
+	u16 unused7;           /* SP */
+	u16 next_task_treePtr; /* SP */
+
+	u32  nused5;        
+
+	u16 active_flags;	   /* SP */
+	/* State flags, used to assist control of execution of Hyper Forground */
+	u16 HFG_flags;       /* SP */
+
+	u16 unused9;
+	u16 unused8;
+                              
+	/* Space for saving enough context so that we can set up enough 
+	   to save some more context.
+	*/
+	u32 rFE_save_for_invalid_IP;
+	u32 r32_save_for_spurious_int;
+	u32 r32_save_for_trap;
+	u32 r32_save_for_HFG;
+} spos_control_block_t;
+
+/* SPB for MIX_TO_OSTREAM algorithm family */
+typedef struct _mix2_ostream_spb_t
+{
+	/* 16b.16b integer.frac approximation to the
+	   number of 3 sample triplets to output each
+	   frame. (approximation must be floor, to
+	   insure that the fractional error is always
+	   positive)
+	*/
+	long outTripletsPerFrame;
+
+	/* 16b.16b integer.frac accumulated number of
+	   output triplets since the start of group 
+	*/
+	long accumOutTriplets;  
+} mix2_ostream_spb_t;
+
+/* SCB for Timing master algorithm */
+typedef struct _timing_master_scb_t {
+	/* First 12 dwords from generic_scb_t */
+	basic_dma_req_t  basic_req;  /* Optional */
+	scatter_gather_ext_t sg_ext;  /* Optional */
+	u16 next_scb;     /* REQUIRED */
+	u16 sub_list_ptr; /* REQUIRED */
+
+	u16 entry_point;  /* REQUIRED */
+	u16 this_spb;     /* REQUIRED */
+
+
+	/* Initial values are 0000:xxxx */
+	u16 reserved;  
+	u16 extra_sample_accum;
+
+  
+	/* Initial values are xxxx:0000
+	   hi: Current CODEC output FIFO pointer
+	       (0 to 0x0f)
+           lo: Flag indicating that the CODEC
+	       FIFO is sync'd (host clears to
+	       resynchronize the FIFO pointer
+	       upon start/restart) 
+	*/
+	u16 codec_FIFO_syncd; 
+	u16 codec_FIFO_ptr;
+
+  
+	/* Init. 8000:0005 for 44.1k
+                 8000:0001 for 48k
+	   hi: Fractional sample accumulator 0.16b
+	   lo: Number of frames remaining to be
+	       processed in the current group of
+	       frames
+	*/
+	u16 frac_samp_accum_qm1;
+	u16 TM_frms_left_in_group; 
+
+	/* Init. 0001:0005 for 44.1k
+                 0000:0001 for 48k
+	   hi: Fractional sample correction factor 0.16b
+	       to be added every frameGroupLength frames
+	       to correct for truncation error in
+	       nsamp_per_frm_q15
+	   lo: Number of frames in the group
+	*/
+	u16 frac_samp_correction_qm1;
+	u16 TM_frm_group_length; 
+
+	/* Init. 44.1k*65536/8k = 0x00058333 for 44.1k
+                 48k*65536/8k = 0x00060000 for 48k
+	   16b.16b integer.frac approximation to the
+	   number of samples to output each frame.
+	   (approximation must be floor, to insure */
+	u32 nsamp_per_frm_q15;
+} timing_master_scb_t;
+
+/* SCB for CODEC output algorithm */
+typedef struct _codec_output_scb_t {
+	/* First 13 dwords from generic_scb_t */
+	basic_dma_req_t  basic_req;  /* Optional */
+	scatter_gather_ext_t sg_ext;  /* Optional */
+	u16 next_scb;       /* REQUIRED */
+	u16 sub_list_ptr;   /* REQUIRED */
+
+	u16 entry_point;    /* REQUIRED */
+	u16 this_spb;       /* REQUIRED */
+
+	u32 strm_rs_config; /* REQUIRED */
+	u32 strm_buf_ptr;   /* REQUIRED */
+
+	/* NOTE: The CODEC output task reads samples from the first task on its
+                 sublist at the stream buffer pointer (init. to lag DMA destination
+		 address word).  After the required number of samples is transferred,
+		 the CODEC output task advances sub_list_ptr->strm_buf_ptr past the samples
+		 consumed.
+	*/
+
+	/* Init. 0000:0010 for SDout
+                 0060:0010 for SDout2
+		 0080:0010 for SDout3
+	   hi: Base IO address of FIFO to which
+	       the left-channel samples are to
+	       be written.
+	   lo: Displacement for the base IO
+	       address for left-channel to obtain
+	       the base IO address for the FIFO
+	       to which the right-channel samples
+	       are to be written.
+	*/
+	u16 left_chan_base_IO_addr;
+	u16 right_chan_IO_disp; 
+
+
+	/* Init: 0x0080:0004 for non-AC-97
+	   Init: 0x0080:0000 for AC-97
+	   hi: Exponential volume change rate
+	       for input stream
+	   lo: Positive shift count to shift the
+	       16-bit input sample to obtain the
+	       32-bit output word
+	*/
+	u16 CO_scale_shift_count; 
+	u16 CO_exp_vol_change_rate;
+
+	/* Pointer to SCB at end of input chain */
+	u16 reserved;
+	u16 last_sub_ptr;
+} codec_output_scb_t;
+
+/* SCB for CODEC input algorithm */
+typedef struct _codec_input_scb_t {
+	/* First 13 dwords from generic_scb_t */
+	basic_dma_req_t  basic_req;  /* Optional */
+	scatter_gather_ext_t sg_ext;  /* Optional */
+	u16 next_scb;       /* REQUIRED */
+	u16 sub_list_ptr;   /* REQUIRED */
+
+	u16 entry_point;    /* REQUIRED */
+	u16 this_spb;       /* REQUIRED */
+
+	u32 strm_rs_config; /* REQUIRED */
+	u32 strm_buf_ptr;   /* REQUIRED */
+
+	/* NOTE: The CODEC input task reads samples from the hardware FIFO 
+                 sublist at the DMA source address word (sub_list_ptr->basic_req.saw).
+                 After the required number of samples is transferred, the CODEC
+                 output task advances sub_list_ptr->basic_req.saw past the samples
+                 consumed.  SPuD must initialize the sub_list_ptr->basic_req.saw
+                 to point half-way around from the initial sub_list_ptr->strm_nuf_ptr
+                 to allow for lag/lead.
+	*/
+
+	/* Init. 0000:0010 for SDout
+                 0060:0010 for SDout2
+		 0080:0010 for SDout3
+	   hi: Base IO address of FIFO to which
+	       the left-channel samples are to
+	       be written.
+	   lo: Displacement for the base IO
+	       address for left-channel to obtain
+	       the base IO address for the FIFO
+	       to which the right-channel samples
+	       are to be written.
+	*/
+	u16 rightChanINdisp; 
+	u16 left_chan_base_IN_addr;
+
+	/* Init. ?:fffc
+	   lo: Negative shift count to shift the
+	       32-bit input dword to obtain the
+	       16-bit sample msb-aligned (count
+	       is negative to shift left)
+	*/
+	u16 scaleShiftCount; 
+	u16 reserver1;
+
+	u32  reserved2;
+} codec_input_scb_t;
+
+
+typedef struct _pcm_serial_input_scb_t {
+	/* First 13 dwords from generic_scb_t */
+	basic_dma_req_t  basic_req;  /* Optional */
+	scatter_gather_ext_t sg_ext;  /* Optional */
+	u16 next_scb;       /* REQUIRED */
+	u16 sub_list_ptr;   /* REQUIRED */
+
+	u16 entry_point;    /* REQUIRED */
+	u16 this_spb;       /* REQUIRED */
+
+	u32 strm_buf_ptr;   /* REQUIRED */
+	u32 strm_rs_config; /* REQUIRED */
+  
+	/* Init. Ptr to CODEC input SCB
+	   hi: Pointer to the SCB containing the
+	       input buffer to which CODEC input
+	       samples are written
+	   lo: Flag indicating the link to the CODEC
+	       input task is to be initialized
+	*/
+	u16 init_codec_input_link; 
+	u16 codec_input_buf_scb;
+
+	/* Initialized by the host (host updates target volumes) */
+	volume_control_t psi_vol_ctrl;   
+  
+} pcm_serial_input_scb_t;
+
+typedef struct _src_task_scb_t {
+	u16 frames_left_in_gof;
+	u16 gofs_left_in_sec;
+
+	u16 const2_thirds;
+	u16 num_extra_tnput_samples;
+
+	u16 cor_per_gof;
+	u16 correction_per_sec;
+
+	u16 output_buf_producer_ptr;  
+	u16 junk_DMA_MID;
+
+	u16 gof_length;  
+	u16 gofs_per_sec;
+  
+	u32 input_buf_strm_config;
+
+	u16 reserved_for_SRC_use;
+	u16 input_buf_consumer_ptr;
+
+	u32 accum_phi;
+
+	u16 exp_src_vol_change_rate;
+	u16 input_buf_producer_ptr;
+  
+	u16 src_next_scb;
+	u16 src_sub_list_ptr;
+
+	u16 src_entry_point;
+	u16 src_this_sbp;
+
+	u32  src_strm_rs_config;
+	u32  src_strm_buf_ptr;
+  
+	u32   phiIncr6int_26frac;
+  
+	volume_control_t src_vol_ctrl;
+} src_task_scb_t;
+
+typedef struct _decimate_by_pow2_scb_t {
+	/* decimationFactor = 2, 4, or 8 (larger factors waste too much memory
+	                                  when compared to cascading decimators)
+	*/
+	u16 dec2_coef_base_ptr;
+	u16 dec2_coef_increment;
+	/* coefIncrement = 128 / decimationFactor (for our ROM filter)
+	   coefBasePtr = 0x8000 (for our ROM filter)
+	*/
+
+	u16 dec2_in_samples_per_out_triplet;
+	u16 dec2_extra_in_samples;
+	/* extraInSamples: # of accumulated, unused input samples (init. to 0)
+	   inSamplesPerOutTriplet = 3 * decimationFactor
+	*/
+
+	u16 dec2_const2_thirds;
+	u16 dec2_half_num_taps_mp5;
+	/* halfNumTapsM5: (1/2 number of taps in decimation filter) minus 5
+	   const2thirds: constant 2/3 in 16Q0 format (sign.15)
+	*/
+
+	u16 dec2_output_buf_producer_ptr;
+	u16 dec2_junkdma_mid;
+
+	u32  dec2_reserved2;
+
+	u32  dec2_input_nuf_strm_config;
+	/* inputBufStrmConfig: rsConfig for the input buffer to the decimator
+	   (buffer size = decimationFactor * 32 dwords)
+	*/
+
+	u16 dec2_phi_incr;
+	u16 dec2_input_buf_consumer_ptr;
+	/* inputBufConsumerPtr: Input buffer read pointer (into SRC filter)
+	   phiIncr = decimationFactor * 4
+	*/
+
+	u32 dec2_reserved3;
+
+	u16 dec2_exp_vol_change_rate;
+	u16 dec2_input_buf_producer_ptr;
+	/* inputBufProducerPtr: Input buffer write pointer
+	   expVolChangeRate: Exponential volume change rate for possible
+	                     future mixer on input streams
+	*/
+
+	u16 dec2_next_scb;
+	u16 dec2_sub_list_ptr;
+
+	u16 dec2_entry_point;
+	u16 dec2_this_spb;
+
+	u32  dec2_strm_rs_config;
+	u32  dec2_strm_buf_ptr;
+
+	u32  dec2_reserved4;
+
+	volume_control_t dec2_vol_ctrl; /* Not used! */
+} decimate_by_pow2_scb_t;
+
+typedef struct _vari_decimate_scb_t {
+	u16 vdec_frames_left_in_gof;
+	u16 vdec_gofs_left_in_sec;
+
+	u16 vdec_const2_thirds;
+	u16 vdec_extra_in_samples;
+	/* extraInSamples: # of accumulated, unused input samples (init. to 0)
+	   const2thirds: constant 2/3 in 16Q0 format (sign.15) */
+
+	u16 vdec_cor_per_gof;
+	u16 vdec_correction_per_sec;
+
+	u16 vdec_output_buf_producer_ptr;
+	u16 vdec_input_buf_consumer_ptr;
+	/* inputBufConsumerPtr: Input buffer read pointer (into SRC filter) */
+
+	u16 vdec_gof_length;
+	u16 vdec_gofs_per_sec;
+
+	u32  vdec_input_buf_strm_config;
+	/* inputBufStrmConfig: rsConfig for the input buffer to the decimator
+	   (buffer size = 64 dwords) */
+	long  vdec_coef_increment;
+	/* coefIncrement = - 128.0 / decimationFactor (as a 32Q15 number) */
+
+	long  vdec_accumphi;
+	/* accumPhi: accumulated fractional phase increment (6.26) */
+
+	u16 vdec_exp_vol_change_rate;
+	u16 vdec_input_buf_producer_ptr;
+	/* inputBufProducerPtr: Input buffer write pointer
+	   expVolChangeRate: Exponential volume change rate for possible
+	   future mixer on input streams */
+
+	u16 vdec_next_scb;
+	u16 vdec_sub_list_ptr;
+
+	u16 vdec_entry_point;
+	u16 vdec_this_spb;
+
+	u32 vdec_strm_rs_config;
+	u32 vdec_strm_buf_ptr;
+
+	u32 vdec_phi_incr_6int_26frac;
+
+	volume_control_t vdec_vol_ctrl;
+} vari_decimate_scb_t;
+
+
+/* SCB for MIX_TO_OSTREAM algorithm family */
+typedef struct _mix2_ostream_scb_t {
+	/* First 13 dwords from generic_scb_t */
+	basic_dma_req_t  basic_req;  /* Optional */
+	scatter_gather_ext_t sg_ext;  /* Optional */
+	u16 next_scb;       /* REQUIRED */
+	u16 sub_list_ptr;   /* REQUIRED */
+
+	u16 entry_point;    /* REQUIRED */
+	u16 this_spb;       /* REQUIRED */
+
+	u32 strm_rs_config; /* REQUIRED */
+	u32 strm_buf_ptr;   /* REQUIRED */
+
+
+	/* hi: Number of mixed-down input triplets
+	       computed since start of group
+	   lo: Number of frames remaining to be
+	       processed in the current group of
+	       frames
+	*/
+	u16 frames_left_in_group;
+	u16 accum_input_triplets;
+
+	/* hi: Exponential volume change rate
+	       for mixer on input streams
+	   lo: Number of frames in the group
+	*/
+	u16 frame_group_length;
+	u16 exp_vol_change_rate;
+  
+	u16 const_FFFF;
+	u16 const_zero;
+} mix2_ostream_scb_t;
+
+
+/* SCB for S16_MIX algorithm */
+typedef struct _mix_only_scb_t {
+	/* First 13 dwords from generic_scb_t */
+	basic_dma_req_t  basic_req;  /* Optional */
+	scatter_gather_ext_t sg_ext;  /* Optional */
+	u16 next_scb;       /* REQUIRED */
+	u16 sub_list_ptr;   /* REQUIRED */
+
+	u16 entry_point;    /* REQUIRED */
+	u16 this_spb;       /* REQUIRED */
+
+	u32 strm_rs_config; /* REQUIRED */
+	u32 strm_buf_ptr;   /* REQUIRED */
+
+	u32 reserved;
+	volume_control_t vol_ctrl;
+} mix_only_scb_t;
+
+/* SCB for the async. CODEC input algorithm */
+typedef struct _async_codec_input_scb_t {		 
+	u32 io_free2;     
+  
+	u32 io_current_total;
+	u32 io_previous_total;
+  
+	u16 io_count;
+	u16 io_count_limit;
+  
+	u16 o_fifo_base_addr;            
+	u16 ost_mo_format;
+	/* 1 = stereo; 0 = mono 
+	   xxx for ASER 1 (not allowed); 118 for ASER2 */
+
+	u32  ostrm_rs_config;
+	u32  ostrm_buf_ptr;
+  
+	u16 io_sclks_per_lr_clk;
+	u16 io_io_enable;
+
+	u32  io_free4;
+  
+	u16 io_next_scb;
+	u16 io_sub_list_ptr;
+
+	u16 io_entry_point;
+	u16 io_this_spb;
+
+	u32 istrm_rs_config;
+	u32 istrm_buf_ptr;
+
+	/* Init. 0000:8042: for ASER1
+                 0000:8044: for ASER2  */
+	u16 io_stat_reg_addr;
+	u16 iofifo_pointer;
+
+	/* Init 1 stero:100 ASER1
+	   Init 0 mono:110 ASER2 
+	*/
+	u16 ififo_base_addr;            
+	u16 ist_mo_format;
+
+	u32 i_free;
+} async_codec_input_scb_t;
+
+
+/* SCB for the SP/DIF CODEC input and output */
+typedef struct _spdifiscb_t {
+	u16 status_ptr;     
+	u16 status_start_ptr;
+  
+	u32 current_total;
+	u32 previous_total;
+
+	u16 count;
+	u16 count_limit;
+  
+	u32 status_data;
+  
+	u16 status;
+	u16 free4;
+
+	u32 free3;
+  
+	u16 free2;
+	u16 bit_count;
+
+	u32  temp_status;
+  
+	u16 next_SCB;
+	u16 sub_list_ptr;
+
+	u16 entry_point;
+	u16 this_spb;
+  
+	u32  strm_rs_config;
+	u32  strm_buf_ptr;
+  
+	u16 stat_reg_addr; 
+	u16 fifo_pointer;
+  
+	u16 fifo_base_addr; 
+	u16 st_mo_format;
+  
+	u32  Free1;
+} spdifiscb_t;
+
+
+/* SCB for the SP/DIF CODEC input and output  */
+typedef struct _spdifoscb_t {		 
+
+
+	u32 free2;     
+
+	u32 free3[4];             
+
+	/* Need to be here for compatibility with AsynchFGTxCode */
+	u32 strm_rs_config;
+                               
+	u32 strm_buf_ptr;
+  
+	u16 status;
+	u16 free5;
+
+	u32 free4;
+  
+	u16 next_scb;
+	u16 sub_list_ptr;
+
+	u16 entry_point;
+	u16 this_spb;
+  
+	u32 free6[2];
+  
+	u16 stat_reg_addr; 
+	u16 fifo_pointer;
+  
+	u16 fifo_base_addr;
+	u16 st_mo_format;
+  
+	u32  free1;                                         
+} spdifoscb_t;
+
+
+
+typedef struct _asynch_fg_rx_scb_t {
+
+	u16 bot_buf_mask;
+	u16 buf_Mask;
+
+	u16 max;
+	u16 min;
+  
+	u16 old_producer_pointer;
+	u16 hfg_scb_ptr;
+	
+	u16 delta;
+	u16 adjust_count;
+     
+	u32 unused2[5];  
+  
+	u16 sibling_ptr;  
+	u16 child_ptr;
+  
+	u16 code_ptr;
+	u16 this_ptr;
+  
+	u32 strm_rs_config; 
+
+	u32 strm_buf_ptr;
+  
+	u32 unused_phi_incr;
+  
+	u16 righttarg;   
+	u16 left_targ;
+
+	u16 rightVol;
+	u16 leftVol;
+} asynch_fg_rx_scb_t;
+
+
+
+typedef struct _asynch_fg_tx_scb_t {
+	u16 not_buf_mask;
+	u16 buf_mask;
+
+	u16 Max;                   
+	u16 min;
+
+	u16 unused1;
+	u16 hfg_scb_ptr;
+
+	u16 delta;
+	u16 adjust_count;
+
+	u32 accum_phi;
+
+	u16 unused2;
+	u16 const_one_third;
+
+	u32 unused3[3];
+
+	u16 sibling_ptr;
+	u16 child_ptr;
+
+	u16 codePtr;
+	u16 this_ptr;
+
+	u32 strm_rs_config;
+
+	u32 strm_buf_ptr;
+
+	u32 phi_incr;
+
+	u16 unused_right_targ;
+	u16 unused_left_targ;
+
+	u16 unused_right_vol;
+	u16 unused_left_vol;
+} asynch_fg_tx_scb_t;
+
+
+typedef struct _output_snoop_scb_t {
+	/* First 13 dwords from generic_scb_t */
+	basic_dma_req_t  basic_req;  /* Optional */
+	scatter_gather_ext_t sg_ext;  /* Optional */
+	u16 next_scb;       /* REQUIRED */
+	u16 sub_list_ptr;   /* REQUIRED */
+
+	u16 entry_point;    /* REQUIRED */
+	u16 this_spb;       /* REQUIRED */
+
+	u32 strm_rs_config; /* REQUIRED */
+	u32 strm_buf_ptr;   /* REQUIRED */
+
+	u16 init_snoop_input_link;
+	u16 snoop_child_input_scb;
+
+	u32 snoop_input_buf_ptr;
+
+	u16 reserved;
+	u16 input_scb;
+} output_snoop_scb_t;
+
+typedef struct _spio_write_scb_t {
+	u16 address1;
+	u16 address2;
+
+	u32 data1;
+
+	u32 data2;
+
+	u16 address3;
+	u16 address4;
+
+	u32 data3;
+
+	u32 data4;
+
+	u16 unused1;
+	u16 data_ptr;
+
+	u32 unused2[2];
+
+	u16 sibling_ptr;
+	u16 child_ptr;
+
+	u16 entry_point;
+	u16 this_ptr;
+
+	u32 unused3[5];
+} spio_write_scb_t;
+
+typedef struct _magic_snoop_task_t {
+	u32 i0;
+	u32 i1;
+
+	u32 strm_buf_ptr1;
+  
+	u16 i2;
+	u16 snoop_scb;
+
+	u32 i3;
+	u32 i4;
+	u32 i5;
+	u32 i6;
+
+	u32 i7;
+
+	u16 next_scb;
+	u16 sub_list_ptr;
+
+	u16 entry_point;
+	u16 this_ptr;
+
+	u32 strm_buf_config;
+	u32 strm_buf_ptr2;
+
+	u32 i8;
+
+	volume_control_t vdec_vol_ctrl;
+} magic_snoop_task_t;
+#endif /* __DSP_SCB_TYPES_H__ */
diff -Nru a/include/sound/cs46xx_dsp_spos.h b/include/sound/cs46xx_dsp_spos.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/sound/cs46xx_dsp_spos.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,183 @@
+/*
+ *  The driver for the Cirrus Logic's Sound Fusion CS46XX based soundcards
+ *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *
+ *
+ *   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
+ *
+ */
+
+#ifndef __CS46XX_DSP_SPOS_H__
+#define __CS46XX_DSP_SPOS_H__
+
+#include "cs46xx_dsp_scb_types.h"
+#include "cs46xx_dsp_task_types.h"
+
+#define SYMBOL_CONSTANT  0x0
+#define SYMBOL_SAMPLE    0x1
+#define SYMBOL_PARAMETER 0x2
+#define SYMBOL_CODE      0x3
+
+#define SEGTYPE_SP_PROGRAM              0x00000001
+#define SEGTYPE_SP_PARAMETER            0x00000002
+#define SEGTYPE_SP_SAMPLE               0x00000003
+#define SEGTYPE_SP_COEFFICIENT          0x00000004
+
+#define DSP_SPOS_UU      0x0deadul     /* unused */
+#define DSP_SPOS_DC      0x0badul     /* dont care */
+#define DSP_SPOS_DC_DC   0x0bad0badul     /* dont care */
+#define DSP_SPOS_UUUU    0xdeadc0edul  /* unused */
+#define DSP_SPOS_UUHI    0xdeadul
+#define DSP_SPOS_UULO    0xc0edul
+#define DSP_SPOS_DCDC    0x0badf1d0ul /* dont care */
+#define DSP_SPOS_DCDCHI  0x0badul
+#define DSP_SPOS_DCDCLO  0xf1d0ul
+
+#define DSP_MAX_TASK_NAME 60
+#define DSP_MAX_SYMBOL_NAME 100
+#define DSP_MAX_SCB_NAME  60
+#define DSP_MAX_SCB_DESC  200
+#define DSP_MAX_TASK_DESC 50
+
+#define DSP_MAX_PCM_CHANNELS 32
+#define DSP_MAX_SRC_NR       6
+
+struct _dsp_module_desc_t;
+
+typedef struct _symbol_entry_t {
+	u32 address;
+	char symbol_name[DSP_MAX_SYMBOL_NAME];
+	int symbol_type;
+
+	/* initialized by driver */
+	struct _dsp_module_desc_t * module;
+	int deleted;
+} symbol_entry_t;
+
+typedef struct _symbol_desc_t {
+	int nsymbols;
+
+	symbol_entry_t * symbols;
+
+	/* initialized by driver */
+	int highest_frag_index;
+} symbol_desc_t;
+
+
+typedef struct _segment_desc_t {
+	int segment_type;
+	u32 offset;
+	u32 size;
+	u32 * data;
+} segment_desc_t;
+
+typedef struct _dsp_module_desc_t {
+	char * module_name;
+	symbol_desc_t symbol_table;
+	int nsegments;
+	segment_desc_t * segments;
+
+	/* initialized by driver */
+	u32 overlay_begin_address;
+	u32 load_address;
+	int nfixups;
+} dsp_module_desc_t;
+
+typedef struct _dsp_scb_descriptor_t {
+	char scb_name[DSP_MAX_SCB_NAME];
+	u32 address;
+	int index;
+
+	struct _dsp_scb_descriptor_t * sub_list_ptr;
+	struct _dsp_scb_descriptor_t * next_scb_ptr;
+	struct _dsp_scb_descriptor_t * parent_scb_ptr;
+
+	symbol_entry_t * task_entry;
+	symbol_entry_t * scb_symbol;
+
+	snd_info_entry_t *proc_info;
+	int ref_count;
+
+	int deleted;
+} dsp_scb_descriptor_t;
+
+typedef struct _dsp_task_descriptor_t {
+	char task_name[DSP_MAX_TASK_NAME];
+	int size;
+	u32 address;
+	int index;
+} dsp_task_descriptor_t;
+
+typedef struct _pcm_channel_descriptor_t {
+	int active;
+	int src_slot;
+	int pcm_slot;
+	u32 sample_rate;
+	u32 unlinked;
+	dsp_scb_descriptor_t * pcm_reader_scb;
+	dsp_scb_descriptor_t * src_scb;
+
+	void * private_data;
+} pcm_channel_descriptor_t;
+
+typedef struct _dsp_spos_instance_t {
+	symbol_desc_t symbol_table; /* currently availble loaded symbols in SP */
+
+	int nmodules;
+	dsp_module_desc_t * modules; /* modules loaded into SP */
+
+	segment_desc_t code;
+
+	/* PCM playback */
+	struct semaphore pcm_mutex;
+
+	dsp_scb_descriptor_t * master_mix_scb;
+	int npcm_channels;
+	int nsrc_scb;
+	pcm_channel_descriptor_t pcm_channels[DSP_MAX_PCM_CHANNELS];
+	int src_scb_slots[DSP_MAX_SRC_NR];
+
+	/* cache this symbols */
+	symbol_entry_t * null_algorithm; /* used by PCMreaderSCB's */
+	symbol_entry_t * s16_up;         /* used by SRCtaskSCB's */
+
+	/* proc fs */  
+	snd_card_t * snd_card;
+	snd_info_entry_t * proc_dsp_dir;
+	snd_info_entry_t * proc_sym_info_entry;
+	snd_info_entry_t * proc_modules_info_entry;
+	snd_info_entry_t * proc_parameter_dump_info_entry;
+	snd_info_entry_t * proc_sample_dump_info_entry;
+
+	/* SCB's descriptors */
+	struct semaphore scb_mutex;
+	int nscb;
+	int scb_highest_frag_index;
+	dsp_scb_descriptor_t scbs[DSP_MAX_SCB_DESC];
+	snd_info_entry_t * proc_scb_info_entry;
+	dsp_scb_descriptor_t * the_null_scb;
+
+	/* Task's descriptors */
+	int ntask;
+	dsp_task_descriptor_t tasks[DSP_MAX_TASK_DESC];
+	snd_info_entry_t * proc_task_info_entry;
+
+	/* SPDIF status */
+	int spdif_status_out;
+	int spdif_status_in;
+} dsp_spos_instance_t;
+
+#endif /* __DSP_SPOS_H__ */
+
diff -Nru a/include/sound/cs46xx_dsp_task_types.h b/include/sound/cs46xx_dsp_task_types.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/sound/cs46xx_dsp_task_types.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,215 @@
+/*
+ *  The driver for the Cirrus Logic's Sound Fusion CS46XX based soundcards
+ *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *
+ *
+ *   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
+ *
+ *
+ * NOTE: comments are copy/paste from cwcemb80.lst 
+ * provided by Tom Woller at Cirrus (my only
+ * documentation about the SP OS running inside
+ * the DSP) 
+ */
+
+#ifndef __CS46XX_DSP_TASK_TYPES_H__
+#define __CS46XX_DSP_TASK_TYPES_H__
+
+/*********************************************************************************************
+Example hierarchy of stream control blocks in the SP
+
+hfgTree
+Ptr____Call (c)
+       \
+ -------+------         -------------      -------------      -------------      -----
+| SBlaster IF  |______\| Foreground  |___\| Middlegr'nd |___\| Background  |___\| Nul |
+|              |Goto  /| tree header |g  /| tree header |g  /| tree header |g  /| SCB |r
+ -------------- (g)     -------------      -------------      -------------      -----
+       |c                     |c                 |c                 |c
+       |                      |                  |                  |
+      \/                  -------------      -------------      -------------   
+                       | Foreground  |_\  | Middlegr'nd |_\  | Background  |_\
+                       |     tree    |g/  |    tree     |g/  |     tree    |g/
+                        -------------      -------------      -------------   
+                              |c                 |c                 |c
+                              |                  |                  | 
+                             \/                 \/                 \/ 
+
+*********************************************************************************************/
+
+#define		HFG_FIRST_EXECUTE_MODE			0x0001
+#define		HFG_FIRST_EXECUTE_MODE_BIT		0
+#define		HFG_CONTEXT_SWITCH_MODE			0x0002
+#define		HFG_CONTEXT_SWITCH_MODE_BIT		1
+
+#define MAX_FG_STACK_SIZE 	32				// THESE NEED TO BE COMPUTED PROPERLY
+#define MAX_MG_STACK_SIZE 	16
+#define MAX_BG_STACK_SIZE 	9
+#define MAX_HFG_STACK_SIZE	4
+
+#define SLEEP_ACTIVE_INCREMENT		0		/* Enable task tree thread to go to sleep
+											   This should only ever be used on the Background thread */
+#define STANDARD_ACTIVE_INCREMENT	1		/* Task tree thread normal operation */
+#define SUSPEND_ACTIVE_INCREMENT	2		/* Cause execution to suspend in the task tree thread
+                                               This should only ever be used on the Background thread */
+
+#define HOSTFLAGS_DISABLE_BG_SLEEP  0       /* Host-controlled flag that determines whether we go to sleep
+                                               at the end of BG */
+
+/* Minimal context save area for Hyper Forground */
+typedef struct _hf_save_area_t {
+	u32	r10_save;
+	u32	r54_save;
+	u32	r98_save;
+
+	u16 status_save;
+	u16 ind_save;
+
+	u16 rci1_save;
+	u16 rci0_save;
+
+	u32	r32_save;
+	u32	r76_save;
+	u32	rsd2_save;
+
+	u16   rsi2_save;	  /* See TaskTreeParameterBlock for 
+				     remainder of registers  */
+	u16	rsa2Save;
+	/* saved as part of HFG context  */
+} hf_save_area_t;
+
+
+/* Task link data structure */
+typedef struct _tree_link_t {
+	/* Pointer to sibling task control block */
+	u16 next_scb;
+	/* Pointer to child task control block */
+	u16 sub_ptr;
+  
+	/* Pointer to code entry point */
+	u16 entry_point; 
+	/* Pointer to local data */
+	u16 this_spb;
+} tree_link_t;
+
+
+typedef struct _task_tree_data_t {
+	/* Initial tock count; controls task tree execution rate */
+	u16 tock_count_limit;
+	/* Tock down counter */
+	u16 tock_count;
+  
+	/* Add to ActiveCount when TockCountLimit reached: 
+	   Subtract on task tree termination */
+	u16 active_tncrement;		
+	/* Number of pending activations for task tree */
+	u16 active_count;
+
+	/* BitNumber to enable modification of correct bit in ActiveTaskFlags */
+	u16 active_bit;	    
+	/* Pointer to OS location for indicating current activity on task level */
+	u16 active_task_flags_ptr;
+
+	/* Data structure for controlling movement of memory blocks:- 
+	   currently unused */
+	u16 mem_upd_ptr;
+	/* Data structure for controlling synchronous link update */
+	u16 link_upd_ptr;
+  
+	/* Save area for remainder of full context. */
+	u16 save_area;  
+	/* Address of start of local stack for data storage */
+	u16 data_stack_base_ptr;
+
+} task_tree_data_t;
+
+
+
+typedef struct _interval_timer_data_t
+{
+	/* These data items have the same relative locations to those */
+	u16  interval_timer_period;
+	u16  itd_unused;
+
+	/* used for this data in the SPOS control block for SPOS 1.0 */
+	u16  num_FG_ticks_this_interval;        
+	u16  num_intervals;
+} interval_timer_data_t;    
+
+
+/* This structure contains extra storage for the task tree
+   Currently, this additional data is related only to a full context save */
+typedef struct _task_tree_context_block_t {
+	/* Up to 10 values are saved onto the stack.  8 for the task tree, 1 for
+	   The access to the context switch (call or interrupt), and 1 spare that
+	   users should never use.  This last may be required by the system */
+	u16       stack1;		
+	u16		stack0;
+	u16       stack3;		
+	u16		stack2;
+	u16       stack5;		
+	u16		stack4;
+	u16       stack7;
+	u16		stack6;
+	u16       stack9;
+	u16		stack8;
+
+	u32		saverfe;					
+
+	/* Value may be overwriten by stack save algorithm.
+	   Retain the size of the stack data saved here if used */
+	u16       reserved1;	
+	u16		stack_size;
+	u32		saverba;		  /* (HFG) */
+	u32		saverdc;
+	u32		savers_config_23; /* (HFG) */
+	u32		savers_DMA23;	  /* (HFG) */
+	u32		saversa0;
+	u32		saversi0;
+	u32		saversa1;
+	u32		saversi1;
+	u32		saversa3;
+	u32		saversd0;
+	u32		saversd1;
+	u32		saversd3;
+	u32		savers_config01;
+	u32		savers_DMA01;
+	u32		saveacc0hl;
+	u32		saveacc1hl;
+	u32		saveacc0xacc1x;
+	u32		saveacc2hl;
+	u32		saveacc3hl;
+	u32		saveacc2xacc3x;
+	u32		saveaux0hl;
+	u32		saveaux1hl;
+	u32		saveaux0xaux1x;
+	u32		saveaux2hl;
+	u32		saveaux3hl;
+	u32		saveaux2xaux3x;
+	u32		savershouthl;
+	u32		savershoutxmacmode;
+} task_tree_context_block_t;						  
+                
+
+typedef struct _task_tree_control_block_t	{
+	hf_save_area_t		 	context;
+	tree_link_t				links;
+	task_tree_data_t			data;
+	task_tree_context_block_t	context_blk;
+	interval_timer_data_t		int_timer;
+} task_tree_control_block_t;
+
+
+#endif /* __DSP_TASK_TYPES_H__ */
diff -Nru a/include/sound/driver.h b/include/sound/driver.h
--- a/include/sound/driver.h	Tue Oct  1 00:08:16 2002
+++ b/include/sound/driver.h	Tue Oct  1 00:08:16 2002
@@ -50,7 +50,7 @@
  */
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0)
-#if defined(__i386__) || defined(__ppc__)
+#if defined(__i386__) || defined(__ppc__) || defined(__x86_64__)
 /*
  * Here a dirty hack for 2.4 kernels.. See sound/core/memory.c.
  */
diff -Nru a/include/sound/emu10k1.h b/include/sound/emu10k1.h
--- a/include/sound/emu10k1.h	Tue Oct  1 00:08:16 2002
+++ b/include/sound/emu10k1.h	Tue Oct  1 00:08:16 2002
@@ -26,6 +26,7 @@
 #ifdef __KERNEL__
 
 #include "pcm.h"
+#include "pcm_sgbuf.h"
 #include "rawmidi.h"
 #include "hwdep.h"
 #include "ac97_codec.h"
@@ -1043,7 +1044,7 @@
 unsigned char snd_emu10k1_sum_vol_attn(unsigned int value);
 
 /* memory allocation */
-snd_util_memblk_t *snd_emu10k1_alloc_pages(emu10k1_t *emu, dma_addr_t addr, unsigned long size);
+snd_util_memblk_t *snd_emu10k1_alloc_pages(emu10k1_t *emu, struct snd_sg_buf *sgbuf);
 int snd_emu10k1_free_pages(emu10k1_t *emu, snd_util_memblk_t *blk);
 snd_util_memblk_t *snd_emu10k1_synth_alloc(emu10k1_t *emu, unsigned int size);
 int snd_emu10k1_synth_free(emu10k1_t *emu, snd_util_memblk_t *blk);
diff -Nru a/include/sound/info.h b/include/sound/info.h
--- a/include/sound/info.h	Tue Oct  1 00:08:15 2002
+++ b/include/sound/info.h	Tue Oct  1 00:08:15 2002
@@ -151,8 +151,8 @@
 
 static inline int snd_info_get_line(snd_info_buffer_t * buffer, char *line, int len) { return 0; }
 static inline char *snd_info_get_str(char *dest, char *src, int len) { return NULL; }
-static inline snd_info_entry_t *snd_info_create_module_entry(struct module * module, const char *name) { return NULL; }
-static inline snd_info_entry_t *snd_info_create_card_entry(snd_card_t * card, const char *name) { return NULL; }
+static inline snd_info_entry_t *snd_info_create_module_entry(struct module * module, const char *name, snd_info_entry_t * parent) { return NULL; }
+static inline snd_info_entry_t *snd_info_create_card_entry(snd_card_t * card, const char *name, snd_info_entry_t * parent) { return NULL; }
 static inline void snd_info_free_entry(snd_info_entry_t * entry) { ; }
 static inline snd_info_entry_t *snd_info_create_device(const char *name,
 						       unsigned int number,
diff -Nru a/include/sound/pcm.h b/include/sound/pcm.h
--- a/include/sound/pcm.h	Tue Oct  1 00:08:17 2002
+++ b/include/sound/pcm.h	Tue Oct  1 00:08:17 2002
@@ -48,6 +48,7 @@
 typedef struct sndrv_pcm_status snd_pcm_status_t;
 typedef struct sndrv_pcm_mmap_status snd_pcm_mmap_status_t;
 typedef struct sndrv_pcm_mmap_control snd_pcm_mmap_control_t;
+typedef struct sndrv_mask snd_mask_t;
 
 #define _snd_pcm_substream_chip(substream) ((substream)->pcm->private_data)
 #define snd_pcm_substream_chip(substream) snd_magic_cast1(chip_t, _snd_pcm_substream_chip(substream), return -ENXIO)
@@ -67,7 +68,7 @@
 
 typedef struct _snd_pcm_hardware {
 	unsigned int info;		/* SNDRV_PCM_INFO_* */
-	unsigned int formats;		/* SNDRV_PCM_FMTBIT_* */
+	u64 formats;			/* SNDRV_PCM_FMTBIT_* */
 	unsigned int rates;		/* SNDRV_PCM_RATE_* */
 	unsigned int rate_min;		/* min rate */
 	unsigned int rate_max;		/* max rate */
@@ -95,6 +96,7 @@
 		    void *buf, snd_pcm_uframes_t count);
 	int (*silence)(snd_pcm_substream_t *substream, int channel, 
 		       snd_pcm_uframes_t pos, snd_pcm_uframes_t count);
+	void *(*page)(snd_pcm_substream_t *substream, unsigned long offset);
 } snd_pcm_ops_t;
 
 /*
@@ -121,6 +123,7 @@
 #define SNDRV_PCM_DMA_TYPE_CONTINUOUS	0	/* continuous no-DMA memory */
 #define SNDRV_PCM_DMA_TYPE_ISA		1	/* ISA continuous */
 #define SNDRV_PCM_DMA_TYPE_PCI		2	/* PCI continuous */
+#define SNDRV_PCM_DMA_TYPE_SBUS		3	/* SBUS continuous */
 
 /* If you change this don't forget to changed snd_pcm_rates table in pcm_lib.c */
 #define SNDRV_PCM_RATE_5512		(1<<0)		/* 5512Hz */
@@ -148,32 +151,44 @@
 					 SNDRV_PCM_RATE_88200|SNDRV_PCM_RATE_96000)
 #define SNDRV_PCM_RATE_8000_192000	(SNDRV_PCM_RATE_8000_96000|SNDRV_PCM_RATE_176400|\
 					 SNDRV_PCM_RATE_192000)
-#define SNDRV_PCM_FMTBIT_S8		(1 << SNDRV_PCM_FORMAT_S8)
-#define SNDRV_PCM_FMTBIT_U8		(1 << SNDRV_PCM_FORMAT_U8)
-#define SNDRV_PCM_FMTBIT_S16_LE		(1 << SNDRV_PCM_FORMAT_S16_LE)
-#define SNDRV_PCM_FMTBIT_S16_BE		(1 << SNDRV_PCM_FORMAT_S16_BE)
-#define SNDRV_PCM_FMTBIT_U16_LE		(1 << SNDRV_PCM_FORMAT_U16_LE)
-#define SNDRV_PCM_FMTBIT_U16_BE		(1 << SNDRV_PCM_FORMAT_U16_BE)
-#define SNDRV_PCM_FMTBIT_S24_LE		(1 << SNDRV_PCM_FORMAT_S24_LE)
-#define SNDRV_PCM_FMTBIT_S24_BE		(1 << SNDRV_PCM_FORMAT_S24_BE)
-#define SNDRV_PCM_FMTBIT_U24_LE		(1 << SNDRV_PCM_FORMAT_U24_LE)
-#define SNDRV_PCM_FMTBIT_U24_BE		(1 << SNDRV_PCM_FORMAT_U24_BE)
-#define SNDRV_PCM_FMTBIT_S32_LE		(1 << SNDRV_PCM_FORMAT_S32_LE)
-#define SNDRV_PCM_FMTBIT_S32_BE		(1 << SNDRV_PCM_FORMAT_S32_BE)
-#define SNDRV_PCM_FMTBIT_U32_LE		(1 << SNDRV_PCM_FORMAT_U32_LE)
-#define SNDRV_PCM_FMTBIT_U32_BE		(1 << SNDRV_PCM_FORMAT_U32_BE)
-#define SNDRV_PCM_FMTBIT_FLOAT_LE	(1 << SNDRV_PCM_FORMAT_FLOAT_LE)
-#define SNDRV_PCM_FMTBIT_FLOAT_BE	(1 << SNDRV_PCM_FORMAT_FLOAT_BE)
-#define SNDRV_PCM_FMTBIT_FLOAT64_LE	(1 << SNDRV_PCM_FORMAT_FLOAT64_LE)
-#define SNDRV_PCM_FMTBIT_FLOAT64_BE	(1 << SNDRV_PCM_FORMAT_FLOAT64_BE)
-#define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE (1 << SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE)
-#define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE (1 << SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE)
-#define SNDRV_PCM_FMTBIT_MU_LAW		(1 << SNDRV_PCM_FORMAT_MU_LAW)
-#define SNDRV_PCM_FMTBIT_A_LAW		(1 << SNDRV_PCM_FORMAT_A_LAW)
-#define SNDRV_PCM_FMTBIT_IMA_ADPCM	(1 << SNDRV_PCM_FORMAT_IMA_ADPCM)
-#define SNDRV_PCM_FMTBIT_MPEG		(1 << SNDRV_PCM_FORMAT_MPEG)
-#define SNDRV_PCM_FMTBIT_GSM		(1 << SNDRV_PCM_FORMAT_GSM)
-#define SNDRV_PCM_FMTBIT_SPECIAL	(1 << SNDRV_PCM_FORMAT_SPECIAL)
+#define SNDRV_PCM_FMTBIT_S8		(1ULL << SNDRV_PCM_FORMAT_S8)
+#define SNDRV_PCM_FMTBIT_U8		(1ULL << SNDRV_PCM_FORMAT_U8)
+#define SNDRV_PCM_FMTBIT_S16_LE		(1ULL << SNDRV_PCM_FORMAT_S16_LE)
+#define SNDRV_PCM_FMTBIT_S16_BE		(1ULL << SNDRV_PCM_FORMAT_S16_BE)
+#define SNDRV_PCM_FMTBIT_U16_LE		(1ULL << SNDRV_PCM_FORMAT_U16_LE)
+#define SNDRV_PCM_FMTBIT_U16_BE		(1ULL << SNDRV_PCM_FORMAT_U16_BE)
+#define SNDRV_PCM_FMTBIT_S24_LE		(1ULL << SNDRV_PCM_FORMAT_S24_LE)
+#define SNDRV_PCM_FMTBIT_S24_BE		(1ULL << SNDRV_PCM_FORMAT_S24_BE)
+#define SNDRV_PCM_FMTBIT_U24_LE		(1ULL << SNDRV_PCM_FORMAT_U24_LE)
+#define SNDRV_PCM_FMTBIT_U24_BE		(1ULL << SNDRV_PCM_FORMAT_U24_BE)
+#define SNDRV_PCM_FMTBIT_S32_LE		(1ULL << SNDRV_PCM_FORMAT_S32_LE)
+#define SNDRV_PCM_FMTBIT_S32_BE		(1ULL << SNDRV_PCM_FORMAT_S32_BE)
+#define SNDRV_PCM_FMTBIT_U32_LE		(1ULL << SNDRV_PCM_FORMAT_U32_LE)
+#define SNDRV_PCM_FMTBIT_U32_BE		(1ULL << SNDRV_PCM_FORMAT_U32_BE)
+#define SNDRV_PCM_FMTBIT_FLOAT_LE	(1ULL << SNDRV_PCM_FORMAT_FLOAT_LE)
+#define SNDRV_PCM_FMTBIT_FLOAT_BE	(1ULL << SNDRV_PCM_FORMAT_FLOAT_BE)
+#define SNDRV_PCM_FMTBIT_FLOAT64_LE	(1ULL << SNDRV_PCM_FORMAT_FLOAT64_LE)
+#define SNDRV_PCM_FMTBIT_FLOAT64_BE	(1ULL << SNDRV_PCM_FORMAT_FLOAT64_BE)
+#define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE (1ULL << SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE)
+#define SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE (1ULL << SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE)
+#define SNDRV_PCM_FMTBIT_MU_LAW		(1ULL << SNDRV_PCM_FORMAT_MU_LAW)
+#define SNDRV_PCM_FMTBIT_A_LAW		(1ULL << SNDRV_PCM_FORMAT_A_LAW)
+#define SNDRV_PCM_FMTBIT_IMA_ADPCM	(1ULL << SNDRV_PCM_FORMAT_IMA_ADPCM)
+#define SNDRV_PCM_FMTBIT_MPEG		(1ULL << SNDRV_PCM_FORMAT_MPEG)
+#define SNDRV_PCM_FMTBIT_GSM		(1ULL << SNDRV_PCM_FORMAT_GSM)
+#define SNDRV_PCM_FMTBIT_SPECIAL	(1ULL << SNDRV_PCM_FORMAT_SPECIAL)
+#define SNDRV_PCM_FMTBIT_S24_3LE	(1ULL << SNDRV_PCM_FORMAT_S24_3LE)
+#define SNDRV_PCM_FMTBIT_U24_3LE	(1ULL << SNDRV_PCM_FORMAT_U24_3LE)
+#define SNDRV_PCM_FMTBIT_S24_3BE	(1ULL << SNDRV_PCM_FORMAT_S24_3BE)
+#define SNDRV_PCM_FMTBIT_U24_3BE	(1ULL << SNDRV_PCM_FORMAT_U24_3BE)
+#define SNDRV_PCM_FMTBIT_S20_3LE	(1ULL << SNDRV_PCM_FORMAT_S20_3LE)
+#define SNDRV_PCM_FMTBIT_U20_3LE	(1ULL << SNDRV_PCM_FORMAT_U20_3LE)
+#define SNDRV_PCM_FMTBIT_S20_3BE	(1ULL << SNDRV_PCM_FORMAT_S20_3BE)
+#define SNDRV_PCM_FMTBIT_U20_3BE	(1ULL << SNDRV_PCM_FORMAT_U20_3BE)
+#define SNDRV_PCM_FMTBIT_S18_3LE	(1ULL << SNDRV_PCM_FORMAT_S18_3LE)
+#define SNDRV_PCM_FMTBIT_U18_3LE	(1ULL << SNDRV_PCM_FORMAT_U18_3LE)
+#define SNDRV_PCM_FMTBIT_S18_3BE	(1ULL << SNDRV_PCM_FORMAT_S18_3BE)
+#define SNDRV_PCM_FMTBIT_U18_3BE	(1ULL << SNDRV_PCM_FORMAT_U18_3BE)
 
 #ifdef SNDRV_LITTLE_ENDIAN
 #define SNDRV_PCM_FMTBIT_S16		SNDRV_PCM_FMTBIT_S16_LE
@@ -217,8 +232,8 @@
 };
 
 typedef struct _snd_pcm_hw_constraints {
-	unsigned int masks[SNDRV_PCM_HW_PARAM_LAST_MASK - 
-			   SNDRV_PCM_HW_PARAM_FIRST_MASK + 1];
+	snd_mask_t masks[SNDRV_PCM_HW_PARAM_LAST_MASK - 
+			 SNDRV_PCM_HW_PARAM_FIRST_MASK + 1];
 	snd_interval_t intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL -
 			     SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1];
 	unsigned int rules_num;
@@ -226,8 +241,8 @@
 	snd_pcm_hw_rule_t *rules;
 } snd_pcm_hw_constraints_t;
 
-static inline unsigned int *constrs_mask(snd_pcm_hw_constraints_t *constrs,
-					snd_pcm_hw_param_t var)
+static inline snd_mask_t *constrs_mask(snd_pcm_hw_constraints_t *constrs,
+				       snd_pcm_hw_param_t var)
 {
 	return &constrs->masks[var - SNDRV_PCM_HW_PARAM_FIRST_MASK];
 }
@@ -648,13 +663,10 @@
 		var <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL;
 }
 
-typedef unsigned int snd_mask_t;
-#define SND_MASK_MAX 32
-
 static inline snd_mask_t *hw_param_mask(snd_pcm_hw_params_t *params,
 				     snd_pcm_hw_param_t var)
 {
-	return (snd_mask_t*)&params->masks[var - SNDRV_PCM_HW_PARAM_FIRST_MASK];
+	return &params->masks[var - SNDRV_PCM_HW_PARAM_FIRST_MASK];
 }
 
 static inline snd_interval_t *hw_param_interval(snd_pcm_hw_params_t *params,
@@ -675,9 +687,9 @@
 	return (const snd_interval_t *)hw_param_interval((snd_pcm_hw_params_t*) params, var);
 }
 
-#define params_access(p) (ffs(*hw_param_mask((p), SNDRV_PCM_HW_PARAM_ACCESS)) - 1)
-#define params_format(p) (ffs(*hw_param_mask((p), SNDRV_PCM_HW_PARAM_FORMAT)) - 1)
-#define params_subformat(p) (ffs(*hw_param_mask((p), SNDRV_PCM_HW_PARAM_SUBFORMAT)) - 1)
+#define params_access(p) snd_mask_min(hw_param_mask((p), SNDRV_PCM_HW_PARAM_ACCESS))
+#define params_format(p) snd_mask_min(hw_param_mask((p), SNDRV_PCM_HW_PARAM_FORMAT))
+#define params_subformat(p) snd_mask_min(hw_param_mask((p), SNDRV_PCM_HW_PARAM_SUBFORMAT))
 #define params_channels(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_CHANNELS)->min
 #define params_rate(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_RATE)->min
 #define params_period_size(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_PERIOD_SIZE)->min
@@ -735,7 +747,9 @@
 int snd_pcm_hw_constraints_complete(snd_pcm_substream_t *substream);
 
 int snd_pcm_hw_constraint_mask(snd_pcm_runtime_t *runtime, snd_pcm_hw_param_t var,
-			       unsigned int mask);
+			       u_int32_t mask);
+int snd_pcm_hw_constraint_mask64(snd_pcm_runtime_t *runtime, snd_pcm_hw_param_t var,
+				 u_int64_t mask);
 int snd_pcm_hw_constraint_minmax(snd_pcm_runtime_t *runtime, snd_pcm_hw_param_t var,
 				 unsigned int min, unsigned int max);
 int snd_pcm_hw_constraint_integer(snd_pcm_runtime_t *runtime, snd_pcm_hw_param_t var);
@@ -759,6 +773,9 @@
 			       unsigned int cond,
 			       snd_pcm_hw_param_t var,
 			       unsigned long step);
+int snd_pcm_hw_constraint_pow2(snd_pcm_runtime_t *runtime,
+			       unsigned int cond,
+			       snd_pcm_hw_param_t var);
 int snd_pcm_hw_rule_add(snd_pcm_runtime_t *runtime,
 			unsigned int cond,
 			int var,
@@ -847,6 +864,15 @@
 					      snd_pcm_t *pcm,
 					      size_t size,
 					      size_t max);
+#endif
+#ifdef CONFIG_SBUS
+int snd_pcm_lib_preallocate_sbus_pages(struct sbus_dev *sdev,
+				       snd_pcm_substream_t *substream,
+				       size_t size, size_t max);
+int snd_pcm_lib_preallocate_sbus_pages_for_all(struct sbus_dev *sdev,
+					       snd_pcm_t *pcm,
+					       size_t size,
+					       size_t max);
 #endif
 
 static inline void snd_pcm_limit_isa_dma_size(int dma, size_t *max)
diff -Nru a/include/sound/pcm_params.h b/include/sound/pcm_params.h
--- a/include/sound/pcm_params.h	Tue Oct  1 00:08:15 2002
+++ b/include/sound/pcm_params.h	Tue Oct  1 00:08:15 2002
@@ -36,10 +36,14 @@
 				 snd_pcm_hw_param_t var, unsigned int val, int dir);
 
 /* To share the same code we have  alsa-lib */
-#define snd_mask_bits(mask) (*(mask))
 #define INLINE static inline
 #define assert(a) (void)(a)
 
+#define SNDRV_MASK_BITS	64	/* we use so far 64bits only */
+#define SNDRV_MASK_SIZE	(SNDRV_MASK_BITS / 32)
+#define MASK_OFS(i)	((i) >> 5)
+#define MASK_BIT(i)	(1U << ((i) & 31))
+
 INLINE unsigned int ld2(u_int32_t v)
 {
         unsigned r = 0;
@@ -72,91 +76,119 @@
 
 INLINE void snd_mask_none(snd_mask_t *mask)
 {
-	snd_mask_bits(mask) = 0;
+	memset(mask, 0, sizeof(*mask));
 }
 
 INLINE void snd_mask_any(snd_mask_t *mask)
 {
-	snd_mask_bits(mask) = ~0U;
-}
-
-INLINE void snd_mask_load(snd_mask_t *mask, unsigned int msk)
-{
-	snd_mask_bits(mask) = msk;
+	memset(mask, 0xff, SNDRV_MASK_SIZE * sizeof(u_int32_t));
 }
 
 INLINE int snd_mask_empty(const snd_mask_t *mask)
 {
-	return snd_mask_bits(mask) == 0;
+	int i;
+	for (i = 0; i < SNDRV_MASK_SIZE; i++)
+		if (mask->bits[i])
+			return 0;
+	return 1;
 }
 
 INLINE unsigned int snd_mask_min(const snd_mask_t *mask)
 {
+	int i;
 	assert(!snd_mask_empty(mask));
-	return ffs(snd_mask_bits(mask)) - 1;
+	for (i = 0; i < SNDRV_MASK_SIZE; i++) {
+		if (mask->bits[i])
+			return ffs(mask->bits[i]) - 1 + (i << 5);
+	}
+	return 0;
 }
 
 INLINE unsigned int snd_mask_max(const snd_mask_t *mask)
 {
+	int i;
 	assert(!snd_mask_empty(mask));
-	return ld2(snd_mask_bits(mask));
+	for (i = SNDRV_MASK_SIZE - 1; i >= 0; i--) {
+		if (mask->bits[i])
+			return ld2(mask->bits[i]) + (i << 5);
+	}
+	return 0;
 }
 
 INLINE void snd_mask_set(snd_mask_t *mask, unsigned int val)
 {
-	assert(val <= SND_MASK_MAX);
-	snd_mask_bits(mask) |= (1U << val);
+	assert(val <= SNDRV_MASK_BITS);
+	mask->bits[MASK_OFS(val)] |= MASK_BIT(val);
 }
 
 INLINE void snd_mask_reset(snd_mask_t *mask, unsigned int val)
 {
-	assert(val <= SND_MASK_MAX);
-	snd_mask_bits(mask) &= ~(1U << val);
+	assert(val <= SNDRV_MASK_BITS);
+	mask->bits[MASK_OFS(val)] &= ~MASK_BIT(val);
 }
 
 INLINE void snd_mask_set_range(snd_mask_t *mask, unsigned int from, unsigned int to)
 {
-	assert(to <= SND_MASK_MAX && from <= to);
-	snd_mask_bits(mask) |= ((1U << (from - to + 1)) - 1) << from;
+	int i;
+	assert(to <= SNDRV_MASK_BITS && from <= to);
+	for (i = from; i <= to; i++)
+		mask->bits[MASK_OFS(i)] |= MASK_BIT(i);
 }
 
 INLINE void snd_mask_reset_range(snd_mask_t *mask, unsigned int from, unsigned int to)
 {
-	assert(to <= SND_MASK_MAX && from <= to);
-	snd_mask_bits(mask) &= ~(((1U << (from - to + 1)) - 1) << from);
+	int i;
+	assert(to <= SNDRV_MASK_BITS && from <= to);
+	for (i = from; i <= to; i++)
+		mask->bits[MASK_OFS(i)] &= ~MASK_BIT(i);
 }
 
 INLINE void snd_mask_leave(snd_mask_t *mask, unsigned int val)
 {
-	assert(val <= SND_MASK_MAX);
-	snd_mask_bits(mask) &= 1U << val;
+	unsigned int v;
+	assert(val <= SNDRV_MASK_BITS);
+	v = mask->bits[MASK_OFS(val)] & MASK_BIT(val);
+	snd_mask_none(mask);
+	mask->bits[MASK_OFS(val)] = v;
 }
 
 INLINE void snd_mask_intersect(snd_mask_t *mask, const snd_mask_t *v)
 {
-	snd_mask_bits(mask) &= snd_mask_bits(v);
+	int i;
+	for (i = 0; i < SNDRV_MASK_SIZE; i++)
+		mask->bits[i] &= v->bits[i];
 }
 
 INLINE int snd_mask_eq(const snd_mask_t *mask, const snd_mask_t *v)
 {
-	return snd_mask_bits(mask) == snd_mask_bits(v);
+	return ! memcmp(mask, v, SNDRV_MASK_SIZE * sizeof(u_int32_t));
 }
 
 INLINE void snd_mask_copy(snd_mask_t *mask, const snd_mask_t *v)
 {
-	snd_mask_bits(mask) = snd_mask_bits(v);
+	*mask = *v;
 }
 
 INLINE int snd_mask_test(const snd_mask_t *mask, unsigned int val)
 {
-	assert(val <= SND_MASK_MAX);
-	return snd_mask_bits(mask) & (1U << val);
+	assert(val <= SNDRV_MASK_BITS);
+	return mask->bits[MASK_OFS(val)] & MASK_BIT(val);
 }
 
 INLINE int snd_mask_single(const snd_mask_t *mask)
 {
+	int i, c = 0;
 	assert(!snd_mask_empty(mask));
-	return !(snd_mask_bits(mask) & (snd_mask_bits(mask) - 1));
+	for (i = 0; i < SNDRV_MASK_SIZE; i++) {
+		if (! mask->bits[i])
+			continue;
+		if (mask->bits[i] & (mask->bits[i] - 1))
+			return 0;
+		if (c)
+			return 0;
+		c++;
+	}
+	return 1;
 }
 
 INLINE int snd_mask_refine(snd_mask_t *mask, const snd_mask_t *v)
@@ -204,7 +236,7 @@
 	assert(!snd_mask_empty(mask));
 	if (snd_mask_max(mask) <= val)
 		return 0;
-	snd_mask_reset_range(mask, val + 1, SND_MASK_MAX);
+	snd_mask_reset_range(mask, val + 1, SNDRV_MASK_BITS);
 	if (snd_mask_empty(mask))
 		return -EINVAL;
 	return 1;
diff -Nru a/include/sound/pcm_sgbuf.h b/include/sound/pcm_sgbuf.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/sound/pcm_sgbuf.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,60 @@
+#ifndef __SOUND_PCM_SGBUF_H
+#define __SOUND_PCM_SGBUF_H
+
+/*
+ * Scatter-Gather PCM access
+ *
+ *  Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   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
+ *
+ */
+
+struct snd_sg_page {
+	void *buf;
+	dma_addr_t addr;
+};
+
+struct snd_sg_buf {
+	int size;	/* allocated byte size (= runtime->dma_bytes) */
+	int pages;	/* allocated pages */
+	int tblsize;	/* allocated table size */
+	struct snd_sg_page *table;
+	struct pci_dev *pci;
+};
+
+typedef struct snd_sg_buf snd_pcm_sgbuf_t; /* for magic cast */
+
+/*
+ * return the pages matching with the given byte size
+ */
+static inline unsigned int snd_pcm_sgbuf_pages(size_t size)
+{
+	return (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+}
+
+
+int snd_pcm_sgbuf_init(snd_pcm_substream_t *substream, struct pci_dev *pci, int tblsize);
+int snd_pcm_sgbuf_delete(snd_pcm_substream_t *substream);
+int snd_pcm_sgbuf_alloc(snd_pcm_substream_t *substream, size_t size);
+int snd_pcm_sgbuf_free(snd_pcm_substream_t *substream);
+
+int snd_pcm_sgbuf_ops_copy_playback(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t hwoff, void *buf, snd_pcm_uframes_t count);
+int snd_pcm_sgbuf_ops_copy_capture(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t hwoff, void *buf, snd_pcm_uframes_t count);
+int snd_pcm_sgbuf_ops_silence(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t hwoff, snd_pcm_uframes_t count);
+void *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset);
+
+
+#endif /* __SOUND_PCM_SGBUF_H */
diff -Nru a/include/sound/rawmidi.h b/include/sound/rawmidi.h
--- a/include/sound/rawmidi.h	Tue Oct  1 00:08:16 2002
+++ b/include/sound/rawmidi.h	Tue Oct  1 00:08:16 2002
@@ -23,6 +23,9 @@
  */
 
 #include <sound/asound.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <asm/semaphore.h>
 
 #if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
 #include "seq_device.h"
diff -Nru a/include/sound/sb.h b/include/sound/sb.h
--- a/include/sound/sb.h	Tue Oct  1 00:08:17 2002
+++ b/include/sound/sb.h	Tue Oct  1 00:08:17 2002
@@ -36,6 +36,7 @@
 	SB_HW_16CSP,		/* SB16 with CSP chip */
 	SB_HW_ALS100,		/* Avance Logic ALS100 chip */
 	SB_HW_ALS4000,		/* Avance Logic ALS4000 chip */
+	SB_HW_DT019X,		/* Diamond Tech. DT-019X / Avance Logic ALS-007 */
 };
 
 #define SB_OPEN_PCM		0x01
@@ -214,6 +215,24 @@
 #define SB_DSP4_MPUSETUP	0x84
 
 #define SB_DSP4_3DSE		0x90
+
+/* Registers for DT-019x / ALS-007 mixer */
+#define SB_DT019X_MASTER_DEV	0x62
+#define SB_DT019X_PCM_DEV	0x64
+#define SB_DT019X_SYNTH_DEV	0x66
+#define SB_DT019X_CD_DEV	0x68
+#define SB_DT019X_MIC_DEV	0x6a
+#define SB_DT019X_SPKR_DEV	0x6a
+#define SB_DT019X_LINE_DEV	0x6e
+#define SB_DT019X_OUTPUT_SW1	0x3c
+#define SB_DT019X_OUTPUT_SW2	0x4c
+#define SB_DT019X_CAPTURE_SW	0x6c
+
+#define SB_DT019X_CAP_CD	0x02
+#define SB_DT019X_CAP_MIC	0x04
+#define SB_DT019X_CAP_LINE	0x06
+#define SB_DT019X_CAP_SYNTH	0x07
+#define SB_DT019X_CAP_MAIN	0x07
 
 /* IRQ setting bitmap */
 #define SB_IRQSETUP_IRQ9	0x01
diff -Nru a/include/sound/seq_virmidi.h b/include/sound/seq_virmidi.h
--- a/include/sound/seq_virmidi.h	Tue Oct  1 00:08:20 2002
+++ b/include/sound/seq_virmidi.h	Tue Oct  1 00:08:20 2002
@@ -45,7 +45,7 @@
 	snd_rawmidi_substream_t *substream;
 } snd_virmidi_t;
 
-#define SNDRV_VIRMIDI_SUBSCRIBE	(1<<0)
+#define SNDRV_VIRMIDI_SUBSCRIBE		(1<<0)
 #define SNDRV_VIRMIDI_USE		(1<<1)
 
 /*
@@ -69,14 +69,16 @@
  * ATTACH = input/output events from midi device are routed to the
  *          attached sequencer port.  sequencer port is not created
  *          by virmidi itself.
+ *          the input to rawmidi must be processed by passing the
+ *          incoming events via snd_virmidi_receive()
  * DISPATCH = input/output events are routed to subscribers.
  *            sequencer port is created in virmidi.
  */
 #define SNDRV_VIRMIDI_SEQ_NONE		0
-#define SNDRV_VIRMIDI_SEQ_ATTACH		1
+#define SNDRV_VIRMIDI_SEQ_ATTACH	1
 #define SNDRV_VIRMIDI_SEQ_DISPATCH	2
 
 int snd_virmidi_new(snd_card_t *card, int device, snd_rawmidi_t **rrmidi);
+int snd_virmidi_receive(snd_rawmidi_t *rmidi, snd_seq_event_t *ev);
 
 #endif /* __SOUND_SEQ_VIRMIDI */
-
diff -Nru a/include/sound/sndmagic.h b/include/sound/sndmagic.h
--- a/include/sound/sndmagic.h	Tue Oct  1 00:08:16 2002
+++ b/include/sound/sndmagic.h	Tue Oct  1 00:08:16 2002
@@ -61,6 +61,7 @@
 #define snd_pcm_proc_private_t_magic		0xa15a0104
 #define snd_pcm_oss_file_t_magic		0xa15a0105
 #define snd_mixer_oss_t_magic			0xa15a0106
+#define snd_pcm_sgbuf_t_magic			0xa15a0107
 
 #define snd_info_private_data_t_magic		0xa15a0201
 #define snd_ctl_file_t_magic			0xa15a0301
@@ -78,6 +79,7 @@
 #define trident_t_magic				0xa15a1201
 #define es1938_t_magic				0xa15a1301
 #define cs46xx_t_magic				0xa15a1401
+#define cs46xx_pcm_t_magic			0xa15a1402
 #define ensoniq_t_magic				0xa15a1501
 #define sonicvibes_t_magic			0xa15a1601
 #define mpu401_t_magic				0xa15a1701
diff -Nru a/include/sound/version.h b/include/sound/version.h
--- a/include/sound/version.h	Tue Oct  1 00:08:16 2002
+++ b/include/sound/version.h	Tue Oct  1 00:08:16 2002
@@ -1,3 +1,3 @@
 /* include/version.h.  Generated automatically by configure.  */
 #define CONFIG_SND_VERSION "0.9.0rc2"
-#define CONFIG_SND_DATE " (Wed Jun 19 08:56:25 2002 UTC)"
+#define CONFIG_SND_DATE " (Mon Aug 05 14:24:05 2002 UTC)"
diff -Nru a/include/sound/ymfpci.h b/include/sound/ymfpci.h
--- a/include/sound/ymfpci.h	Tue Oct  1 00:08:16 2002
+++ b/include/sound/ymfpci.h	Tue Oct  1 00:08:16 2002
@@ -358,7 +358,7 @@
 int snd_ymfpci_pcm2(ymfpci_t *chip, int device, snd_pcm_t **rpcm);
 int snd_ymfpci_pcm_spdif(ymfpci_t *chip, int device, snd_pcm_t **rpcm);
 int snd_ymfpci_pcm_4ch(ymfpci_t *chip, int device, snd_pcm_t **rpcm);
-int snd_ymfpci_mixer(ymfpci_t *chip);
+int snd_ymfpci_mixer(ymfpci_t *chip, int rear_switch);
 int snd_ymfpci_joystick(ymfpci_t *chip);
 
 int snd_ymfpci_voice_alloc(ymfpci_t *chip, ymfpci_voice_type_t type, int pair, ymfpci_voice_t **rvoice);
diff -Nru a/kernel/Makefile b/kernel/Makefile
--- a/kernel/Makefile	Tue Oct  1 00:08:15 2002
+++ b/kernel/Makefile	Tue Oct  1 00:08:15 2002
@@ -3,7 +3,7 @@
 #
 
 export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o \
-	      printk.o platform.o suspend.o dma.o module.o
+	      printk.o platform.o suspend.o dma.o module.o cpufreq.o
 
 obj-y     = sched.o fork.o exec_domain.o panic.o printk.o \
 	    module.o exit.o itimer.o time.o softirq.o resource.o \
@@ -16,6 +16,7 @@
 obj-$(CONFIG_MODULES) += ksyms.o
 obj-$(CONFIG_KALLSYMS) += kallsyms.o
 obj-$(CONFIG_PM) += pm.o
+obj-$(CONFIG_CPU_FREQ) += cpufreq.o
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
 obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend.o
 
diff -Nru a/kernel/context.c b/kernel/context.c
--- a/kernel/context.c	Tue Oct  1 00:08:17 2002
+++ b/kernel/context.c	Tue Oct  1 00:08:17 2002
@@ -28,6 +28,60 @@
 static int keventd_running;
 static struct task_struct *keventd_task;
 
+static spinlock_t tqueue_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
+
+typedef struct list_head task_queue;
+
+/*
+ * Queue a task on a tq.  Return non-zero if it was successfully
+ * added.
+ */
+static inline int queue_task(struct tq_struct *tq, task_queue *list)
+{
+	int ret = 0;
+	unsigned long flags;
+
+	if (!test_and_set_bit(0, &tq->sync)) {
+		spin_lock_irqsave(&tqueue_lock, flags);
+		list_add_tail(&tq->list, list);
+		spin_unlock_irqrestore(&tqueue_lock, flags);
+		ret = 1;
+	}
+	return ret;
+}
+
+#define TQ_ACTIVE(q)	(!list_empty(&q))
+
+static inline void run_task_queue(task_queue *list)
+{
+	struct list_head head, *next;
+	unsigned long flags;
+
+	if (!TQ_ACTIVE(*list))
+		return;
+
+	spin_lock_irqsave(&tqueue_lock, flags);
+	list_add(&head, list);
+	list_del_init(list);
+	spin_unlock_irqrestore(&tqueue_lock, flags);
+
+	next = head.next;
+	while (next != &head) {
+		void (*f) (void *);
+		struct tq_struct *p;
+		void *data;
+
+		p = list_entry(next, struct tq_struct, list);
+		next = next->next;
+		f = p->routine;
+		data = p->data;
+		wmb();
+		p->sync = 0;
+		if (f)
+			f(data);
+	}
+}
+
 static int need_keventd(const char *who)
 {
 	if (keventd_running == 0)
@@ -77,10 +131,10 @@
 	keventd_running = 1;
 	keventd_task = curtask;
 
-	spin_lock_irq(&curtask->sigmask_lock);
+	spin_lock_irq(&curtask->sig->siglock);
 	siginitsetinv(&curtask->blocked, sigmask(SIGCHLD));
 	recalc_sigpending();
-	spin_unlock_irq(&curtask->sigmask_lock);
+	spin_unlock_irq(&curtask->sig->siglock);
 
 	complete((struct completion *)startup);
 
@@ -106,10 +160,10 @@
 		if (signal_pending(curtask)) {
 			while (waitpid(-1, (unsigned int *)0, __WALL|WNOHANG) > 0)
 				;
-			spin_lock_irq(&curtask->sigmask_lock);
+			spin_lock_irq(&curtask->sig->siglock);
 			flush_signals(curtask);
 			recalc_sigpending();
-			spin_unlock_irq(&curtask->sigmask_lock);
+			spin_unlock_irq(&curtask->sig->siglock);
 		}
 	}
 }
diff -Nru a/kernel/cpufreq.c b/kernel/cpufreq.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/kernel/cpufreq.c	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,1104 @@
+/*
+ *  linux/kernel/cpufreq.c
+ *
+ *  Copyright (C) 2001 Russell King
+ *            (C) 2002 Dominik Brodowski <linux@brodo.de>
+ *
+ *  $Id: cpufreq.c,v 1.43 2002/09/21 09:05:29 db Exp $
+ *
+ * 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/notifier.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/ctype.h>
+
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_CPU_FREQ_26_API
+#include <linux/proc_fs.h>
+#endif
+
+#ifdef CONFIG_CPU_FREQ_24_API
+#include <linux/sysctl.h>
+#endif
+
+
+/**
+ * The "cpufreq driver" - the arch- or hardware-dependend low
+ * level driver of CPUFreq support, and its locking mutex. 
+ * cpu_max_freq is in kHz.
+ */
+static struct cpufreq_driver   	*cpufreq_driver;
+static DECLARE_MUTEX            (cpufreq_driver_sem);
+
+
+/**
+ * Two notifier lists: the "policy" list is involved in the 
+ * validation process for a new CPU frequency policy; the 
+ * "transition" list for kernel code that needs to handle
+ * changes to devices when the CPU clock speed changes.
+ * The mutex locks both lists. If both cpufreq_driver_sem
+ * and cpufreq_notifier_sem need to be hold, get cpufreq_driver_sem
+ * first.
+ */
+static struct notifier_block    *cpufreq_policy_notifier_list;
+static struct notifier_block    *cpufreq_transition_notifier_list;
+static DECLARE_MUTEX            (cpufreq_notifier_sem);
+
+
+/**
+ * The cpufreq default policy. Can be set by a "cpufreq=..." command
+ * line option.
+ */
+static struct cpufreq_policy default_policy = {
+	.cpu    = CPUFREQ_ALL_CPUS,
+	.min    = 0,
+	.max    = 0,
+	.policy = 0,
+};
+
+
+#ifdef CONFIG_CPU_FREQ_24_API
+/**
+ * A few values needed by the 2.4.-compatible API
+ */
+static unsigned int     cpu_max_freq;
+static unsigned int     cpu_min_freq;
+static unsigned int     cpu_cur_freq[NR_CPUS];
+#endif
+
+
+
+/*********************************************************************
+ *                              2.6. API                             *
+ *********************************************************************/
+
+/**
+ * cpufreq_parse_policy - parse a policy string
+ * @input_string: the string to parse.
+ * @policy: the policy written inside input_string
+ *
+ * This function parses a "policy string" - something the user echo'es into
+ * /proc/cpufreq or gives as boot parameter - into a struct cpufreq_policy.
+ * If there are invalid/missing entries, they are replaced with current
+ * cpufreq policy.
+ */
+static int cpufreq_parse_policy(char input_string[42], struct cpufreq_policy *policy)
+{
+	unsigned int            min = 0;
+	unsigned int            max = 0;
+	unsigned int            cpu = 0;
+	char			policy_string[42] = {'\0'};
+	struct cpufreq_policy   current_policy;
+	unsigned int            result = -EFAULT;
+	unsigned int            i = 0;
+
+	if (!policy)
+		return -EINVAL;
+
+	policy->min = 0;
+	policy->max = 0;
+	policy->policy = 0;
+	policy->cpu = CPUFREQ_ALL_CPUS;
+
+	if (sscanf(input_string, "%d:%d:%d:%s", &cpu, &min, &max, policy_string) == 4) 
+	{
+		policy->min = min;
+		policy->max = max;
+		policy->cpu = cpu;
+		result = 0;
+		goto scan_policy;
+	}
+	if (sscanf(input_string, "%d%%%d%%%d%%%s", &cpu, &min, &max, policy_string) == 4)
+	{
+		if (!cpufreq_get_policy(&current_policy, cpu)) {
+			policy->min = (min * current_policy.max_cpu_freq) / 100;
+			policy->max = (max * current_policy.max_cpu_freq) / 100;
+			policy->cpu = cpu;
+			result = 0;
+			goto scan_policy;
+		}
+	}
+
+	if (sscanf(input_string, "%d:%d:%s", &min, &max, policy_string) == 3) 
+	{
+		policy->min = min;
+		policy->max = max;
+		result = 0;
+		goto scan_policy;
+	}
+
+	if (sscanf(input_string, "%d%%%d%%%s", &min, &max, policy_string) == 3)
+	{
+		if (!cpufreq_get_policy(&current_policy, cpu)) {
+			policy->min = (min * current_policy.max_cpu_freq) / 100;
+			policy->max = (max * current_policy.max_cpu_freq) / 100;
+			result = 0;
+			goto scan_policy;
+		}
+	}
+
+	return -EINVAL;
+
+scan_policy:
+
+	for (i=0;i<sizeof(policy_string);i++){
+		if (policy_string[i]=='\0')
+			break;
+		policy_string[i] = tolower(policy_string[i]);
+	}
+
+	if (!strncmp(policy_string, "powersave", 6) ||  
+            !strncmp(policy_string, "eco", 3) ||       
+	    !strncmp(policy_string, "batter", 6) ||
+	    !strncmp(policy_string, "low", 3)) 
+	{
+		result = 0;
+		policy->policy = CPUFREQ_POLICY_POWERSAVE;
+	}
+	else if (!strncmp(policy_string, "performance",6) ||
+	    !strncmp(policy_string, "high",4) ||
+	    !strncmp(policy_string, "full",4))
+	{
+		result = 0;
+		policy->policy = CPUFREQ_POLICY_PERFORMANCE;
+	}
+	else if (!cpufreq_get_policy(&current_policy, policy->cpu))
+	{
+		policy->policy = current_policy.policy;
+	}
+	else
+	{
+		policy->policy = 0;
+	}
+
+	return result;
+}
+
+
+/*
+ * cpufreq command line parameter.  Must be hard values (kHz)
+ *  cpufreq=1000000:2000000:PERFORMANCE   
+ * to set the default CPUFreq policy.
+ */
+static int __init cpufreq_setup(char *str)
+{
+	cpufreq_parse_policy(str, &default_policy);
+	default_policy.cpu = CPUFREQ_ALL_CPUS;
+	return 1;
+}
+__setup("cpufreq=", cpufreq_setup);
+
+
+#ifdef CONFIG_CPU_FREQ_26_API
+#ifdef CONFIG_PROC_FS
+
+/**
+ * cpufreq_proc_read - read /proc/cpufreq
+ *
+ * This function prints out the current cpufreq policy.
+ */
+static int cpufreq_proc_read (
+	char			*page,
+	char			**start,
+	off_t			off,
+	int 			count,
+	int 			*eof,
+	void			*data)
+{
+	char			*p = page;
+	int			len = 0;
+	struct cpufreq_policy   policy;
+	unsigned int            min_pctg = 0;
+	unsigned int            max_pctg = 0;
+	unsigned int            i = 0;
+
+	if (off != 0)
+		goto end;
+
+	p += sprintf(p, "          minimum CPU frequency  -  maximum CPU frequency  -  policy\n");
+	for (i=0;i<NR_CPUS;i++) {
+		if (!cpu_online(i))
+			continue;
+
+		cpufreq_get_policy(&policy, i);
+		min_pctg = (policy.min * 100) / policy.max_cpu_freq;
+		max_pctg = (policy.max * 100) / policy.max_cpu_freq;
+
+		p += sprintf(p, "CPU%3d    %9d kHz (%3d %%)  -  %9d kHz (%3d %%)  -  ",
+			     i , policy.min, min_pctg, policy.max, max_pctg);
+		switch (policy.policy) {
+		case CPUFREQ_POLICY_POWERSAVE:
+			p += sprintf(p, "powersave\n");
+			break;
+		case CPUFREQ_POLICY_PERFORMANCE:
+			p += sprintf(p, "performance\n");
+			break;
+		default:
+			p += sprintf(p, "INVALID\n");
+			break;
+		}
+	}
+end:
+	len = (p - page);
+	if (len <= off+count) 
+		*eof = 1;
+	*start = page + off;
+	len -= off;
+	if (len>count) 
+		len = count;
+	if (len<0) 
+		len = 0;
+
+	return len;
+}
+
+
+/**
+ * cpufreq_proc_write - handles writing into /proc/cpufreq
+ *
+ * This function calls the parsing script and then sets the policy
+ * accordingly.
+ */
+static int cpufreq_proc_write (
+        struct file		*file,
+        const char		*buffer,
+        unsigned long		count,
+        void			*data)
+{
+	int                     result = 0;
+	char			proc_string[42] = {'\0'};
+	struct cpufreq_policy   policy;
+
+
+	if ((count > sizeof(proc_string) - 1))
+		return -EINVAL;
+	
+	if (copy_from_user(proc_string, buffer, count))
+		return -EFAULT;
+	
+	proc_string[count] = '\0';
+
+	result = cpufreq_parse_policy(proc_string, &policy);
+	if (result)
+		return -EFAULT;
+
+	cpufreq_set_policy(&policy);
+
+	return count;
+}
+
+
+/**
+ * cpufreq_proc_init - add "cpufreq" to the /proc root directory
+ *
+ * This function adds "cpufreq" to the /proc root directory.
+ */
+static unsigned int cpufreq_proc_init (void)
+{
+	struct proc_dir_entry *entry = NULL;
+
+        /* are these acceptable values? */
+	entry = create_proc_entry("cpufreq", S_IFREG|S_IRUGO|S_IWUSR, 
+				  &proc_root);
+
+	if (!entry) {
+		printk(KERN_ERR "unable to create /proc/cpufreq entry\n");
+		return -EIO;
+	} else {
+		entry->read_proc = cpufreq_proc_read;
+		entry->write_proc = cpufreq_proc_write;
+	}
+
+	return 0;
+}
+
+
+/**
+ * cpufreq_proc_exit - removes "cpufreq" from the /proc root directory.
+ *
+ * This function removes "cpufreq" from the /proc root directory.
+ */
+static void cpufreq_proc_exit (void)
+{
+	remove_proc_entry("cpufreq", &proc_root);
+	return;
+}
+#endif /* CONFIG_PROC_FS */
+#endif /* CONFIG_CPU_FREQ_26_API */
+
+
+
+/*********************************************************************
+ *                        2.4. COMPATIBLE API                        *
+ *********************************************************************/
+
+#ifdef CONFIG_CPU_FREQ_24_API
+/* NOTE #1: when you use this API, you may not use any other calls,
+ * except cpufreq_[un]register_notifier, of course.
+ */
+
+/** 
+ * cpufreq_set - set the CPU frequency
+ * @freq: target frequency in kHz
+ * @cpu: CPU for which the frequency is to be set
+ *
+ * Sets the CPU frequency to freq.
+ */
+int cpufreq_set(unsigned int freq, unsigned int cpu)
+{
+	struct cpufreq_policy policy;
+	down(&cpufreq_driver_sem);
+	if (!cpufreq_driver || !cpu_max_freq) {
+		up(&cpufreq_driver_sem);
+		return -EINVAL;
+	}
+
+	policy.min = freq;
+	policy.max = freq;
+	policy.policy = CPUFREQ_POLICY_POWERSAVE;
+	policy.cpu = cpu;
+	
+	up(&cpufreq_driver_sem);
+
+	return cpufreq_set_policy(&policy);
+}
+EXPORT_SYMBOL_GPL(cpufreq_set);
+
+
+/** 
+ * cpufreq_setmax - set the CPU to the maximum frequency
+ * @cpu - affected cpu;
+ *
+ * Sets the CPU frequency to the maximum frequency supported by
+ * this CPU.
+ */
+int cpufreq_setmax(unsigned int cpu)
+{
+	if (!cpu_online(cpu) && (cpu != CPUFREQ_ALL_CPUS))
+		return -EINVAL;
+	return cpufreq_set(cpu_max_freq, cpu);
+}
+EXPORT_SYMBOL_GPL(cpufreq_setmax);
+
+
+/** 
+ * cpufreq_get - get the current CPU frequency (in kHz)
+ * @cpu: CPU number - currently without effect.
+ *
+ * Get the CPU current (static) CPU frequency
+ */
+unsigned int cpufreq_get(unsigned int cpu)
+{
+	if (!cpu_online(cpu))
+		return -EINVAL;
+	return cpu_cur_freq[cpu];
+}
+EXPORT_SYMBOL(cpufreq_get);
+
+
+#ifdef CONFIG_SYSCTL
+
+
+/*********************** cpufreq_sysctl interface ********************/
+static int
+cpufreq_procctl(ctl_table *ctl, int write, struct file *filp,
+		void *buffer, size_t *lenp)
+{
+	char buf[16], *p;
+	int cpu = (int) ctl->extra1;
+	int len, left = *lenp;
+
+	if (!left || (filp->f_pos && !write) || !cpu_online(cpu)) {
+		*lenp = 0;
+		return 0;
+	}
+
+	if (write) {
+		unsigned int freq;
+
+		len = left;
+		if (left > sizeof(buf))
+			left = sizeof(buf);
+		if (copy_from_user(buf, buffer, left))
+			return -EFAULT;
+		buf[sizeof(buf) - 1] = '\0';
+
+		freq = simple_strtoul(buf, &p, 0);
+		cpufreq_set(freq, cpu);
+	} else {
+		len = sprintf(buf, "%d\n", cpufreq_get(cpu));
+		if (len > left)
+			len = left;
+		if (copy_to_user(buffer, buf, len))
+			return -EFAULT;
+	}
+
+	*lenp = len;
+	filp->f_pos += len;
+	return 0;
+}
+
+static int
+cpufreq_sysctl(ctl_table *table, int *name, int nlen,
+	       void *oldval, size_t *oldlenp,
+	       void *newval, size_t newlen, void **context)
+{
+	int cpu = (int) table->extra1;
+
+	if (!cpu_online(cpu))
+		return -EINVAL;
+
+	if (oldval && oldlenp) {
+		size_t oldlen;
+
+		if (get_user(oldlen, oldlenp))
+			return -EFAULT;
+
+		if (oldlen != sizeof(unsigned int))
+			return -EINVAL;
+
+		if (put_user(cpufreq_get(cpu), (unsigned int *)oldval) ||
+		    put_user(sizeof(unsigned int), oldlenp))
+			return -EFAULT;
+	}
+	if (newval && newlen) {
+		unsigned int freq;
+
+		if (newlen != sizeof(unsigned int))
+			return -EINVAL;
+
+		if (get_user(freq, (unsigned int *)newval))
+			return -EFAULT;
+
+		cpufreq_set(freq, cpu);
+	}
+	return 1;
+}
+
+/* ctl_table ctl_cpu_vars_{0,1,...,(NR_CPUS-1)} */
+/* due to NR_CPUS tweaking, a lot of if/endifs are required, sorry */
+        CTL_TABLE_CPU_VARS(0);
+#if NR_CPUS > 1
+	CTL_TABLE_CPU_VARS(1);
+#endif
+#if NR_CPUS > 2
+	CTL_TABLE_CPU_VARS(2);
+#endif
+#if NR_CPUS > 3
+	CTL_TABLE_CPU_VARS(3);
+#endif
+#if NR_CPUS > 4
+	CTL_TABLE_CPU_VARS(4);
+#endif
+#if NR_CPUS > 5
+	CTL_TABLE_CPU_VARS(5);
+#endif
+#if NR_CPUS > 6
+	CTL_TABLE_CPU_VARS(6);
+#endif
+#if NR_CPUS > 7
+	CTL_TABLE_CPU_VARS(7);
+#endif
+#if NR_CPUS > 8
+	CTL_TABLE_CPU_VARS(8);
+#endif
+#if NR_CPUS > 9
+	CTL_TABLE_CPU_VARS(9);
+#endif
+#if NR_CPUS > 10
+	CTL_TABLE_CPU_VARS(10);
+#endif
+#if NR_CPUS > 11
+	CTL_TABLE_CPU_VARS(11);
+#endif
+#if NR_CPUS > 12
+	CTL_TABLE_CPU_VARS(12);
+#endif
+#if NR_CPUS > 13
+	CTL_TABLE_CPU_VARS(13);
+#endif
+#if NR_CPUS > 14
+	CTL_TABLE_CPU_VARS(14);
+#endif
+#if NR_CPUS > 15
+	CTL_TABLE_CPU_VARS(15);
+#endif
+#if NR_CPUS > 16
+	CTL_TABLE_CPU_VARS(16);
+#endif
+#if NR_CPUS > 17
+	CTL_TABLE_CPU_VARS(17);
+#endif
+#if NR_CPUS > 18
+	CTL_TABLE_CPU_VARS(18);
+#endif
+#if NR_CPUS > 19
+	CTL_TABLE_CPU_VARS(19);
+#endif
+#if NR_CPUS > 20
+	CTL_TABLE_CPU_VARS(20);
+#endif
+#if NR_CPUS > 21
+	CTL_TABLE_CPU_VARS(21);
+#endif
+#if NR_CPUS > 22
+	CTL_TABLE_CPU_VARS(22);
+#endif
+#if NR_CPUS > 23
+	CTL_TABLE_CPU_VARS(23);
+#endif
+#if NR_CPUS > 24
+	CTL_TABLE_CPU_VARS(24);
+#endif
+#if NR_CPUS > 25
+	CTL_TABLE_CPU_VARS(25);
+#endif
+#if NR_CPUS > 26
+	CTL_TABLE_CPU_VARS(26);
+#endif
+#if NR_CPUS > 27
+	CTL_TABLE_CPU_VARS(27);
+#endif
+#if NR_CPUS > 28
+	CTL_TABLE_CPU_VARS(28);
+#endif
+#if NR_CPUS > 29
+	CTL_TABLE_CPU_VARS(29);
+#endif
+#if NR_CPUS > 30
+	CTL_TABLE_CPU_VARS(30);
+#endif
+#if NR_CPUS > 31
+	CTL_TABLE_CPU_VARS(31);
+#endif
+#if NR_CPUS > 32
+#error please extend CPU enumeration
+#endif
+
+/* due to NR_CPUS tweaking, a lot of if/endifs are required, sorry */
+static ctl_table ctl_cpu_table[NR_CPUS + 1] = {
+	CPU_ENUM(0),
+#if NR_CPUS > 1
+	CPU_ENUM(1),
+#endif
+#if NR_CPUS > 2
+	CPU_ENUM(2),
+#endif
+#if NR_CPUS > 3
+	CPU_ENUM(3),
+#endif
+#if NR_CPUS > 4
+	CPU_ENUM(4),
+#endif
+#if NR_CPUS > 5
+	CPU_ENUM(5),
+#endif
+#if NR_CPUS > 6
+	CPU_ENUM(6),
+#endif
+#if NR_CPUS > 7
+	CPU_ENUM(7),
+#endif
+#if NR_CPUS > 8
+	CPU_ENUM(8),
+#endif
+#if NR_CPUS > 9
+	CPU_ENUM(9),
+#endif
+#if NR_CPUS > 10
+	CPU_ENUM(10),
+#endif
+#if NR_CPUS > 11
+	CPU_ENUM(11),
+#endif
+#if NR_CPUS > 12
+	CPU_ENUM(12),
+#endif
+#if NR_CPUS > 13
+	CPU_ENUM(13),
+#endif
+#if NR_CPUS > 14
+	CPU_ENUM(14),
+#endif
+#if NR_CPUS > 15
+	CPU_ENUM(15),
+#endif
+#if NR_CPUS > 16
+	CPU_ENUM(16),
+#endif
+#if NR_CPUS > 17
+	CPU_ENUM(17),
+#endif
+#if NR_CPUS > 18
+	CPU_ENUM(18),
+#endif
+#if NR_CPUS > 19
+	CPU_ENUM(19),
+#endif
+#if NR_CPUS > 20
+	CPU_ENUM(20),
+#endif
+#if NR_CPUS > 21
+	CPU_ENUM(21),
+#endif
+#if NR_CPUS > 22
+	CPU_ENUM(22),
+#endif
+#if NR_CPUS > 23
+	CPU_ENUM(23),
+#endif
+#if NR_CPUS > 24
+	CPU_ENUM(24),
+#endif
+#if NR_CPUS > 25
+	CPU_ENUM(25),
+#endif
+#if NR_CPUS > 26
+	CPU_ENUM(26),
+#endif
+#if NR_CPUS > 27
+	CPU_ENUM(27),
+#endif
+#if NR_CPUS > 28
+	CPU_ENUM(28),
+#endif
+#if NR_CPUS > 29
+	CPU_ENUM(29),
+#endif
+#if NR_CPUS > 30
+	CPU_ENUM(30),
+#endif
+#if NR_CPUS > 31
+	CPU_ENUM(31),
+#endif
+#if NR_CPUS > 32
+#error please extend CPU enumeration
+#endif
+	{
+		ctl_name:	0,
+	}
+};
+
+static ctl_table ctl_cpu[2] = {
+	{
+		ctl_name:	CTL_CPU,
+		procname:	"cpu",
+		mode:		0555,
+		child:		ctl_cpu_table,
+	},
+	{
+		ctl_name:	0,
+	}
+};
+
+struct ctl_table_header *cpufreq_sysctl_table;
+
+static inline void cpufreq_sysctl_init(void)
+{
+	cpufreq_sysctl_table = register_sysctl_table(ctl_cpu, 0);
+}
+
+static inline void cpufreq_sysctl_exit(void)
+{
+	unregister_sysctl_table(cpufreq_sysctl_table);
+}
+
+#else
+#define cpufreq_sysctl_init()
+#define cpufreq_sysctl_exit()
+#endif /* CONFIG_SYSCTL */
+#endif /* CONFIG_CPU_FREQ_24_API */
+
+
+
+/*********************************************************************
+ *                     NOTIFIER LISTS INTERFACE                      *
+ *********************************************************************/
+
+/**
+ *	cpufreq_register_notifier - register a driver with cpufreq
+ *	@nb: notifier function to register
+ *      @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER
+ *
+ *	Add a driver to one of two lists: either a list of drivers that 
+ *      are notified about clock rate changes (once before and once after
+ *      the transition), or a list of drivers that are notified about
+ *      changes in cpufreq policy.
+ *
+ *	This function may sleep, and has the same return conditions as
+ *	notifier_chain_register.
+ */
+int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list)
+{
+	int ret;
+
+	down(&cpufreq_notifier_sem);
+	switch (list) {
+	case CPUFREQ_TRANSITION_NOTIFIER:
+		ret = notifier_chain_register(&cpufreq_transition_notifier_list, nb);
+		break;
+	case CPUFREQ_POLICY_NOTIFIER:
+		ret = notifier_chain_register(&cpufreq_policy_notifier_list, nb);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	up(&cpufreq_notifier_sem);
+
+	return ret;
+}
+EXPORT_SYMBOL(cpufreq_register_notifier);
+
+
+/**
+ *	cpufreq_unregister_notifier - unregister a driver with cpufreq
+ *	@nb: notifier block to be unregistered
+ *      @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER
+ *
+ *	Remove a driver from the CPU frequency notifier list.
+ *
+ *	This function may sleep, and has the same return conditions as
+ *	notifier_chain_unregister.
+ */
+int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list)
+{
+	int ret;
+
+	down(&cpufreq_notifier_sem);
+	switch (list) {
+	case CPUFREQ_TRANSITION_NOTIFIER:
+		ret = notifier_chain_unregister(&cpufreq_transition_notifier_list, nb);
+		break;
+	case CPUFREQ_POLICY_NOTIFIER:
+		ret = notifier_chain_unregister(&cpufreq_policy_notifier_list, nb);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	up(&cpufreq_notifier_sem);
+
+	return ret;
+}
+EXPORT_SYMBOL(cpufreq_unregister_notifier);
+
+
+
+/*********************************************************************
+ *                          POLICY INTERFACE                         *
+ *********************************************************************/
+
+/**
+ * cpufreq_get_policy - get the current cpufreq_policy
+ * @policy: struct cpufreq_policy into which the current cpufreq_policy is written
+ *
+ * Reads the current cpufreq policy.
+ */
+int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu)
+{
+	down(&cpufreq_driver_sem);
+	if (!cpufreq_driver  || !policy || 
+	    (cpu >= NR_CPUS) || (!cpu_online(cpu))) {
+		up(&cpufreq_driver_sem);
+		return -EINVAL;
+	}
+	
+	policy->min    = cpufreq_driver->policy[cpu].min;
+	policy->max    = cpufreq_driver->policy[cpu].max;
+	policy->policy = cpufreq_driver->policy[cpu].policy;
+	policy->max_cpu_freq = cpufreq_driver->policy[0].max_cpu_freq;
+	policy->cpu    = cpu;
+
+	up(&cpufreq_driver_sem);
+
+	return 0;
+}
+
+
+/**
+ *	cpufreq_set_policy - set a new CPUFreq policy
+ *	@policy: policy to be set.
+ *
+ *	Sets a new CPU frequency and voltage scaling policy.
+ */
+int cpufreq_set_policy(struct cpufreq_policy *policy)
+{
+	unsigned int i;
+
+	down(&cpufreq_driver_sem);
+	if (!cpufreq_driver || !cpufreq_driver->verify || 
+	    !cpufreq_driver->setpolicy || !policy ||
+	    (policy->cpu > NR_CPUS)) {
+		up(&cpufreq_driver_sem);
+		return -EINVAL;
+	}
+
+	down(&cpufreq_notifier_sem);
+
+	policy->max_cpu_freq = cpufreq_driver->policy[0].max_cpu_freq;
+
+	/* verify the cpu speed can be set within this limit */
+	cpufreq_driver->verify(policy);
+
+	/* adjust if neccessary - all reasons */
+	notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_ADJUST,
+			    policy);
+
+	/* adjust if neccessary - hardware incompatibility*/
+	notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_INCOMPATIBLE,
+			    policy);
+
+	/* verify the cpu speed can be set within this limit,
+	   which might be different to the first one */
+	cpufreq_driver->verify(policy);
+
+	/* notification of the new policy */
+	notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_NOTIFY,
+			    policy);
+
+	up(&cpufreq_notifier_sem);
+
+	if (policy->cpu == CPUFREQ_ALL_CPUS) {
+		for (i=0;i<NR_CPUS;i++) {
+			cpufreq_driver->policy[i].min    = policy->min;
+			cpufreq_driver->policy[i].max    = policy->max;
+			cpufreq_driver->policy[i].policy = policy->policy;
+		} 
+	} else {
+		cpufreq_driver->policy[policy->cpu].min    = policy->min;
+		cpufreq_driver->policy[policy->cpu].max    = policy->max;
+		cpufreq_driver->policy[policy->cpu].policy = policy->policy;
+	}
+	
+#ifdef CONFIG_CPU_FREQ_24_API
+	if (policy->cpu == CPUFREQ_ALL_CPUS) {
+		for (i=0;i<NR_CPUS;i++)
+			cpu_cur_freq[i] = policy->max;
+	} else
+		cpu_cur_freq[policy->cpu] = policy->max;
+#endif
+
+	cpufreq_driver->setpolicy(policy);
+	
+	up(&cpufreq_driver_sem);
+
+	return 0;
+}
+EXPORT_SYMBOL(cpufreq_set_policy);
+
+
+
+/*********************************************************************
+ *                    DYNAMIC CPUFREQ SWITCHING                      *
+ *********************************************************************/
+#ifdef CONFIG_CPU_FREQ_DYNAMIC
+/* TBD */
+#endif /* CONFIG_CPU_FREQ_DYNAMIC */
+
+
+
+/*********************************************************************
+ *            EXTERNALLY AFFECTING FREQUENCY CHANGES                 *
+ *********************************************************************/
+
+/**
+ * adjust_jiffies - adjust the system "loops_per_jiffy"
+ *
+ * This function alters the system "loops_per_jiffy" for the clock
+ * speed change. Note that loops_per_jiffy is only updated if all
+ * CPUs are affected - else there is a need for per-CPU loops_per_jiffy
+ * values which are provided by various architectures. 
+ */
+static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
+{
+	if ((val == CPUFREQ_PRECHANGE  && ci->old < ci->new) ||
+	    (val == CPUFREQ_POSTCHANGE && ci->old > ci->new))
+		if (ci->cpu == CPUFREQ_ALL_CPUS)
+			loops_per_jiffy = cpufreq_scale(loops_per_jiffy, ci->old, ci->new);
+}
+
+
+/**
+ * cpufreq_notify_transition - call notifier chain and adjust_jiffies on frequency transition
+ *
+ * This function calls the transition notifiers and the "adjust_jiffies" function. It is called
+ * twice on all CPU frequency changes that have external effects. 
+ */
+void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
+{
+	down(&cpufreq_notifier_sem);
+	switch (state) {
+	case CPUFREQ_PRECHANGE:
+		notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_PRECHANGE, freqs);
+		adjust_jiffies(CPUFREQ_PRECHANGE, freqs);		
+		break;
+	case CPUFREQ_POSTCHANGE:
+		adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
+		notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_POSTCHANGE, freqs);
+		break;
+	}
+	up(&cpufreq_notifier_sem);
+}
+EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
+
+
+
+/*********************************************************************
+ *               REGISTER / UNREGISTER CPUFREQ DRIVER                *
+ *********************************************************************/
+
+/**
+ * cpufreq_register - register a CPU Frequency driver
+ * @driver_data: A struct cpufreq_driver containing the values submitted by the CPU Frequency driver.
+ *
+ *   Registers a CPU Frequency driver to this core code. This code 
+ * returns zero on success, -EBUSY when another driver got here first
+ * (and isn't unregistered in the meantime). 
+ *
+ */
+int cpufreq_register(struct cpufreq_driver *driver_data)
+{
+	unsigned int            ret;
+
+	if (cpufreq_driver)
+		return -EBUSY;
+	
+	if (!driver_data || !driver_data->verify || 
+	    !driver_data->setpolicy)
+		return -EINVAL;
+
+	down(&cpufreq_driver_sem);
+	cpufreq_driver        = driver_data;
+	
+	if (!default_policy.policy)
+		default_policy.policy = driver_data->policy[0].policy;
+	if (!default_policy.min)
+		default_policy.min = driver_data->policy[0].min;
+	if (!default_policy.max)
+		default_policy.max = driver_data->policy[0].max;
+	default_policy.cpu = CPUFREQ_ALL_CPUS;
+
+	up(&cpufreq_driver_sem);
+
+	ret = cpufreq_set_policy(&default_policy);
+
+#ifdef CONFIG_CPU_FREQ_26_API
+	cpufreq_proc_init();
+#endif
+
+#ifdef CONFIG_CPU_FREQ_24_API
+	down(&cpufreq_driver_sem);
+	cpu_min_freq          = driver_data->cpu_min_freq;
+	cpu_max_freq          = driver_data->policy[0].max_cpu_freq;
+	{
+		unsigned int i;
+		for (i=0; i<NR_CPUS; i++) {
+			cpu_cur_freq[i] = driver_data->cpu_cur_freq[i];
+		}
+	}
+	up(&cpufreq_driver_sem);
+
+	cpufreq_sysctl_init();
+#endif
+	if (ret) {
+		down(&cpufreq_driver_sem);
+		cpufreq_driver = NULL;
+		up(&cpufreq_driver_sem);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(cpufreq_register);
+
+
+/**
+ * cpufreq_unregister - unregister the current CPUFreq driver
+ *
+ *    Unregister the current CPUFreq driver. Only call this if you have 
+ * the right to do so, i.e. if you have succeeded in initialising before!
+ * Returns zero if successful, and -EINVAL if the cpufreq_driver is
+ * currently not initialised.
+ */
+int cpufreq_unregister(void)
+{
+	down(&cpufreq_driver_sem);
+
+	if (!cpufreq_driver) {
+		up(&cpufreq_driver_sem);
+		return -EINVAL;
+	}
+
+	cpufreq_driver = NULL;
+
+	up(&cpufreq_driver_sem);
+
+#ifdef CONFIG_CPU_FREQ_26_API
+	cpufreq_proc_exit();
+#endif
+
+#ifdef CONFIG_CPU_FREQ_24_API
+	cpufreq_sysctl_exit();
+#endif
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cpufreq_unregister);
+
+
+#ifdef CONFIG_PM
+/**
+ *	cpufreq_restore - restore the CPU clock frequency after resume
+ *
+ *	Restore the CPU clock frequency so that our idea of the current
+ *	frequency reflects the actual hardware.
+ */
+int cpufreq_restore(void)
+{
+	struct cpufreq_policy policy;
+	unsigned int i;
+
+	if (in_interrupt())
+		panic("cpufreq_restore() called from interrupt context!");
+
+	for (i=0;i<NR_CPUS;i++) {
+		if (!cpu_online(i))
+			continue;
+
+		down(&cpufreq_driver_sem);
+		if (!cpufreq_driver) {
+			up(&cpufreq_driver_sem);
+			return 0;
+		}
+	
+		policy.min    = cpufreq_driver->policy[i].min;
+		policy.max    = cpufreq_driver->policy[i].max;
+		policy.policy = cpufreq_driver->policy[i].policy;
+		policy.cpu    = i;
+		up(&cpufreq_driver_sem);
+
+#ifdef CONFIG_CPU_FREQ_26_API
+		cpufreq_set_policy(&policy);
+#endif
+
+#ifdef CONFIG_CPU_FREQ_24_API
+		cpufreq_set(cpu_cur_freq[i], i);
+#endif
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cpufreq_restore);
+#else
+#define cpufreq_restore()
+#endif /* CONFIG_PM */
+
diff -Nru a/kernel/fork.c b/kernel/fork.c
--- a/kernel/fork.c	Tue Oct  1 00:08:15 2002
+++ b/kernel/fork.c	Tue Oct  1 00:08:15 2002
@@ -246,6 +246,7 @@
 		tmp->vm_mm = mm;
 		tmp->vm_next = NULL;
 		file = tmp->vm_file;
+		INIT_LIST_HEAD(&tmp->shared);
 		if (file) {
 			struct inode *inode = file->f_dentry->d_inode;
 			get_file(file);
@@ -756,7 +757,6 @@
 		/* ?? should we just memset this ?? */
 		for(i = 0; i < NR_CPUS; i++)
 			p->per_cpu_utime[i] = p->per_cpu_stime[i] = 0;
-		spin_lock_init(&p->sigmask_lock);
 	}
 #endif
 	p->array = NULL;
diff -Nru a/kernel/futex.c b/kernel/futex.c
--- a/kernel/futex.c	Tue Oct  1 00:08:16 2002
+++ b/kernel/futex.c	Tue Oct  1 00:08:16 2002
@@ -151,13 +151,13 @@
 	struct futex_q *q = container_of(vcache, struct futex_q, vcache);
 	struct list_head *head = hash_futex(new_page, q->offset);
 
-	BUG_ON(list_empty(&q->list));
-
 	spin_lock(&futex_lock);
 
-	q->page = new_page;
-	list_del_init(&q->list);
-	list_add_tail(&q->list, head);
+	if (!list_empty(&q->list)) {
+		q->page = new_page;
+		list_del(&q->list);
+		list_add_tail(&q->list, head);
+	}
 
 	spin_unlock(&futex_lock);
 }
diff -Nru a/kernel/kmod.c b/kernel/kmod.c
--- a/kernel/kmod.c	Tue Oct  1 00:08:16 2002
+++ b/kernel/kmod.c	Tue Oct  1 00:08:16 2002
@@ -110,12 +110,12 @@
 	   as the super user right after the execve fails if you time
 	   the signal just right.
 	*/
-	spin_lock_irq(&curtask->sigmask_lock);
+	spin_lock_irq(&curtask->sig->siglock);
 	sigemptyset(&curtask->blocked);
 	flush_signals(curtask);
 	flush_signal_handlers(curtask);
 	recalc_sigpending();
-	spin_unlock_irq(&curtask->sigmask_lock);
+	spin_unlock_irq(&curtask->sig->siglock);
 
 	for (i = 0; i < curtask->files->max_fds; i++ ) {
 		if (curtask->files->fd[i]) close(i);
@@ -238,20 +238,20 @@
 	}
 
 	/* Block everything but SIGKILL/SIGSTOP */
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	tmpsig = current->blocked;
 	siginitsetinv(&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP));
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	waitpid_result = waitpid(pid, NULL, __WCLONE);
 	atomic_dec(&kmod_concurrent);
 
 	/* Allow signals again.. */
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	current->blocked = tmpsig;
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	if (waitpid_result != pid) {
 		printk(KERN_ERR "request_module[%s]: waitpid(%d,...) failed, errno %d\n",
diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c
--- a/kernel/ksyms.c	Tue Oct  1 00:08:14 2002
+++ b/kernel/ksyms.c	Tue Oct  1 00:08:14 2002
@@ -343,7 +343,6 @@
 EXPORT_SYMBOL(blkdev_get);
 EXPORT_SYMBOL(blkdev_put);
 EXPORT_SYMBOL(ioctl_by_bdev);
-EXPORT_SYMBOL(register_disk);
 EXPORT_SYMBOL(read_dev_sector);
 EXPORT_SYMBOL(init_buffer);
 EXPORT_SYMBOL_GPL(generic_file_direct_IO);
@@ -420,12 +419,8 @@
 EXPORT_SYMBOL(del_timer_sync);
 #endif
 EXPORT_SYMBOL(mod_timer);
-EXPORT_SYMBOL(tq_timer);
-EXPORT_SYMBOL(tq_immediate);
 
 #ifdef CONFIG_SMP
-/* Various random spinlocks we want to export */
-EXPORT_SYMBOL(tqueue_lock);
 
 /* Big-Reader lock implementation */
 EXPORT_SYMBOL(__brlock_array);
@@ -592,12 +587,8 @@
 EXPORT_SYMBOL(strsep);
 
 /* software interrupts */
-EXPORT_SYMBOL(bh_task_vec);
-EXPORT_SYMBOL(init_bh);
-EXPORT_SYMBOL(remove_bh);
 EXPORT_SYMBOL(tasklet_init);
 EXPORT_SYMBOL(tasklet_kill);
-EXPORT_SYMBOL(__run_task_queue);
 EXPORT_SYMBOL(do_softirq);
 EXPORT_SYMBOL(raise_softirq);
 EXPORT_SYMBOL(open_softirq);
diff -Nru a/kernel/sched.c b/kernel/sched.c
--- a/kernel/sched.c	Tue Oct  1 00:08:19 2002
+++ b/kernel/sched.c	Tue Oct  1 00:08:19 2002
@@ -29,6 +29,7 @@
 #include <linux/security.h>
 #include <linux/notifier.h>
 #include <linux/delay.h>
+#include <linux/timer.h>
 
 /*
  * Convert user-nice values [ -20 ... 0 ... 19 ]
@@ -860,6 +861,7 @@
 	runqueue_t *rq = this_rq();
 	task_t *p = current;
 
+	run_local_timers();
 	if (p == rq->idle) {
 		/* note: this timer irq context must be accounted for as well */
 		if (irq_count() - HARDIRQ_OFFSET >= SOFTIRQ_OFFSET)
@@ -1161,6 +1163,7 @@
 
 void wait_for_completion(struct completion *x)
 {
+	might_sleep();
 	spin_lock_irq(&x->wait.lock);
 	if (!x->done) {
 		DECLARE_WAITQUEUE(wait, current);
@@ -2101,10 +2104,7 @@
 spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 #endif
 
-extern void init_timervecs(void);
-extern void timer_bh(void);
-extern void tqueue_bh(void);
-extern void immediate_bh(void);
+extern void init_timers(void);
 
 void __init sched_init(void)
 {
@@ -2140,10 +2140,7 @@
 	set_task_cpu(current, smp_processor_id());
 	wake_up_process(current);
 
-	init_timervecs();
-	init_bh(TIMER_BH, timer_bh);
-	init_bh(TQUEUE_BH, tqueue_bh);
-	init_bh(IMMEDIATE_BH, immediate_bh);
+	init_timers();
 
 	/*
 	 * The boot idle thread does lazy MMU switching as well:
@@ -2162,7 +2159,7 @@
 		if (time_before(jiffies, prev_jiffy + HZ))
 			return;
 		prev_jiffy = jiffies;
-		printk("Sleeping function called from illegal"
+		printk(KERN_ERR "Debug: sleeping function called from illegal"
 				" context at %s:%d\n", file, line);
 		dump_stack();
 	}
diff -Nru a/kernel/signal.c b/kernel/signal.c
--- a/kernel/signal.c	Tue Oct  1 00:08:16 2002
+++ b/kernel/signal.c	Tue Oct  1 00:08:16 2002
@@ -155,16 +155,8 @@
 	(((sig) != SIGCHLD) && \
 		((t)->sig->action[(sig)-1].sa.sa_handler == SIG_IGN))
 
-void __init signals_init(void)
-{
-	sigqueue_cachep =
-		kmem_cache_create("sigqueue",
-				  sizeof(struct sigqueue),
-				  __alignof__(struct sigqueue),
-				  0, NULL, NULL);
-	if (!sigqueue_cachep)
-		panic("signals_init(): cannot create sigqueue SLAB cache");
-}
+static int
+__send_sig_info(int sig, struct siginfo *info, struct task_struct *p);
 
 #define PENDING(p,b) has_pending_signals(&(p)->signal, (b))
 
@@ -250,23 +242,6 @@
 	flush_sigqueue(&t->pending);
 }
 
-static inline void __remove_thread_group(struct task_struct *tsk, struct signal_struct *sig)
-{
-	if (tsk == sig->curr_target)
-		sig->curr_target = next_thread(tsk);
-}
-
-void remove_thread_group(struct task_struct *tsk, struct signal_struct *sig)
-{
-	write_lock_irq(&tasklist_lock);
-	spin_lock(&tsk->sig->siglock);
-
-	__remove_thread_group(tsk, sig);
-
-	spin_unlock(&tsk->sig->siglock);
-	write_unlock_irq(&tasklist_lock);
-}
-
 /*
  * This function expects the tasklist_lock write-locked.
  */
@@ -279,9 +254,9 @@
 	if (!atomic_read(&sig->count))
 		BUG();
 	spin_lock(&sig->siglock);
-	spin_lock(&tsk->sigmask_lock);
 	if (atomic_dec_and_test(&sig->count)) {
-		__remove_thread_group(tsk, sig);
+		if (tsk == sig->curr_target)
+			sig->curr_target = next_thread(tsk);
 		tsk->sig = NULL;
 		spin_unlock(&sig->siglock);
 		flush_sigqueue(&sig->shared_pending);
@@ -295,14 +270,13 @@
 			wake_up_process(sig->group_exit_task);
 			sig->group_exit_task = NULL;
 		}
-		__remove_thread_group(tsk, sig);
+		if (tsk == sig->curr_target)
+			sig->curr_target = next_thread(tsk);
 		tsk->sig = NULL;
 		spin_unlock(&sig->siglock);
 	}
 	clear_tsk_thread_flag(tsk,TIF_SIGPENDING);
 	flush_sigqueue(&tsk->pending);
-
-	spin_unlock(&tsk->sigmask_lock);
 }
 
 void exit_sighand(struct task_struct *tsk)
@@ -361,11 +335,11 @@
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&current->sigmask_lock, flags);
+	spin_lock_irqsave(&current->sig->siglock, flags);
 	current->notifier_mask = mask;
 	current->notifier_data = priv;
 	current->notifier = notifier;
-	spin_unlock_irqrestore(&current->sigmask_lock, flags);
+	spin_unlock_irqrestore(&current->sig->siglock, flags);
 }
 
 /* Notify the system that blocking has ended. */
@@ -375,11 +349,11 @@
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&current->sigmask_lock, flags);
+	spin_lock_irqsave(&current->sig->siglock, flags);
 	current->notifier = NULL;
 	current->notifier_data = NULL;
 	recalc_sigpending();
-	spin_unlock_irqrestore(&current->sigmask_lock, flags);
+	spin_unlock_irqrestore(&current->sig->siglock, flags);
 }
 
 static inline int collect_signal(int sig, struct sigpending *list, siginfo_t *info)
@@ -435,7 +409,7 @@
  * Dequeue a signal and return the element to the caller, which is 
  * expected to free it.
  *
- * All callers have to hold the siglock and the sigmask_lock.
+ * All callers have to hold the siglock.
  */
 
 int dequeue_signal(struct sigpending *pending, sigset_t *mask, siginfo_t *info)
@@ -492,7 +466,7 @@
  * Remove signal sig from t->pending.
  * Returns 1 if sig was found.
  *
- * All callers must be holding t->sigmask_lock.
+ * All callers must be holding the siglock.
  */
 static int rm_sig_from_queue(int sig, struct task_struct *t)
 {
@@ -661,7 +635,7 @@
  *
  * NOTE! we rely on the previous spin_lock to
  * lock interrupts for us! We can only be called with
- * "sigmask_lock" held, and the local interrupt must
+ * "siglock" held, and the local interrupt must
  * have been disabled when that got acquired!
  *
  * No need to set need_resched since signal event passing
@@ -700,7 +674,7 @@
 }
 
 static int
-__send_sig_info(int sig, struct siginfo *info, struct task_struct *t, int shared)
+specific_send_sig_info(int sig, struct siginfo *info, struct task_struct *t, int shared)
 {
 	int ret;
 
@@ -712,22 +686,21 @@
 #endif
 	ret = -EINVAL;
 	if (sig < 0 || sig > _NSIG)
-		goto out_nolock;
+		goto out;
 	/* The somewhat baroque permissions check... */
 	ret = -EPERM;
 	if (bad_signal(sig, info, t))
-		goto out_nolock;
+		goto out;
 	ret = security_ops->task_kill(t, info, sig);
 	if (ret)
-		goto out_nolock;
+		goto out;
 
 	/* The null signal is a permissions and process existence probe.
 	   No signal is actually delivered.  Same goes for zombies. */
 	ret = 0;
 	if (!sig || !t->sig)
-		goto out_nolock;
+		goto out;
 
-	spin_lock(&t->sigmask_lock);
 	handle_stop_signal(sig, t);
 
 	/* Optimize away the signal, if it's a signal that can be
@@ -754,8 +727,6 @@
 		ret = send_signal(sig, info, &t->sig->shared_pending);
 	}
 out:
-	spin_unlock(&t->sigmask_lock);
-out_nolock:
 	return ret;
 }
 
@@ -768,40 +739,31 @@
 force_sig_info(int sig, struct siginfo *info, struct task_struct *t)
 {
 	unsigned long int flags;
+	int ret;
 
-	spin_lock_irqsave(&t->sigmask_lock, flags);
-	if (t->sig == NULL) {
-		spin_unlock_irqrestore(&t->sigmask_lock, flags);
-		return -ESRCH;
-	}
-
+	spin_lock_irqsave(&t->sig->siglock, flags);
 	if (t->sig->action[sig-1].sa.sa_handler == SIG_IGN)
 		t->sig->action[sig-1].sa.sa_handler = SIG_DFL;
 	sigdelset(&t->blocked, sig);
 	recalc_sigpending_tsk(t);
-	spin_unlock_irqrestore(&t->sigmask_lock, flags);
+	ret = __send_sig_info(sig, info, t);
+	spin_unlock_irqrestore(&t->sig->siglock, flags);
 
-	return send_sig_info(sig, (void *)1, t);
+	return ret;
 }
 
 static int
-__force_sig_info(int sig, struct task_struct *t)
+specific_force_sig_info(int sig, struct task_struct *t)
 {
-	unsigned long int flags;
-
-	spin_lock_irqsave(&t->sigmask_lock, flags);
-	if (t->sig == NULL) {
-		spin_unlock_irqrestore(&t->sigmask_lock, flags);
+	if (!t->sig)
 		return -ESRCH;
-	}
 
 	if (t->sig->action[sig-1].sa.sa_handler == SIG_IGN)
 		t->sig->action[sig-1].sa.sa_handler = SIG_DFL;
 	sigdelset(&t->blocked, sig);
 	recalc_sigpending_tsk(t);
-	spin_unlock_irqrestore(&t->sigmask_lock, flags);
 
-	return __send_sig_info(sig, (void *)2, t, 0);
+	return specific_send_sig_info(sig, (void *)2, t, 0);
 }
 
 #define can_take_signal(p, sig)	\
@@ -820,7 +782,7 @@
 	 * then deliver it.
 	 */
 	if (can_take_signal(p, sig))
-		return __send_sig_info(sig, info, p, 0);
+		return specific_send_sig_info(sig, info, p, 0);
 
 	/*
 	 * Otherwise try to find a suitable thread.
@@ -851,14 +813,14 @@
 				break;
 			continue;
 		}
-		ret = __send_sig_info(sig, info, tmp, 0);
+		ret = specific_send_sig_info(sig, info, tmp, 0);
 		return ret;
 	}
 	/*
 	 * No suitable thread was found - put the signal
 	 * into the shared-pending queue.
 	 */
-	return __send_sig_info(sig, info, p, 1);
+	return specific_send_sig_info(sig, info, p, 1);
 }
 
 int __broadcast_thread_group(struct task_struct *p, int sig)
@@ -869,23 +831,34 @@
 	int err = 0;
 
 	for_each_task_pid(p->tgid, PIDTYPE_TGID, tmp, l, pid)
-		err = __force_sig_info(sig, tmp);
+		err = specific_force_sig_info(sig, tmp);
 
 	return err;
 }
 
-int
-send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
+struct task_struct * find_unblocked_thread(struct task_struct *p, int signr)
 {
-	unsigned long flags;
+	struct task_struct *tmp;
+	struct list_head *l;
+	struct pid *pid;
+
+	for_each_task_pid(p->tgid, PIDTYPE_TGID, tmp, l, pid)
+		if (!sigismember(&tmp->blocked, signr) &&
+					!sigismember(&tmp->real_blocked, signr))
+			return tmp;
+	return NULL;
+}
+
+static int
+__send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
+{
+	struct task_struct *t;
 	int ret = 0;
 
-	if (!p)
-		BUG();
-	if (!p->sig)
+#if CONFIG_SMP
+	if (!spin_is_locked(&p->sig->siglock))
 		BUG();
-	spin_lock_irqsave(&p->sig->siglock, flags);
-
+#endif
 	/* not a thread group - normal signal behavior */
 	if (thread_group_empty(p) || !sig)
 		goto out_send;
@@ -905,28 +878,38 @@
 	if (sig_ignored(p, sig))
 		goto out_unlock;
 
-	/* blocked (or ptraced) signals get posted */
-	spin_lock(&p->sigmask_lock);
-	if ((p->ptrace & PT_PTRACED) || sigismember(&p->blocked, sig) ||
-					sigismember(&p->real_blocked, sig)) {
-		spin_unlock(&p->sigmask_lock);
+	if (sig_kernel_specific(sig))
 		goto out_send;
-	}
-	spin_unlock(&p->sigmask_lock);
 
+	/* Does any of the threads unblock the signal? */
+	t = find_unblocked_thread(p, sig);
+	if (!t) {
+		ret = specific_send_sig_info(sig, info, p, 1);
+		goto out_unlock;
+	}
 	if (sig_kernel_broadcast(sig) || sig_kernel_coredump(sig)) {
 		ret = __broadcast_thread_group(p, sig);
 		goto out_unlock;
 	}
-	if (sig_kernel_specific(sig))
-		goto out_send;
 
 	/* must not happen */
 	BUG();
 out_send:
-	ret = __send_sig_info(sig, info, p, 0);
+	ret = specific_send_sig_info(sig, info, p, 0);
 out_unlock:
+	return ret;
+}
+
+int
+send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&p->sig->siglock, flags);
+	ret = __send_sig_info(sig, info, p);
 	spin_unlock_irqrestore(&p->sig->siglock, flags);
+
 	return ret;
 }
 
@@ -1084,9 +1067,8 @@
  * Joy. Or not. Pthread wants us to wake up every thread
  * in our parent group.
  */
-static inline void wake_up_parent(struct task_struct *p)
+static inline void __wake_up_parent(struct task_struct *p)
 {
-	unsigned long flags;
 	struct task_struct *parent = p->parent, *tsk = parent;
 
 	/*
@@ -1096,14 +1078,13 @@
 		wake_up_interruptible(&tsk->wait_chldexit);
 		return;
 	}
-	spin_lock_irqsave(&parent->sig->siglock, flags);
+
 	do {
 		wake_up_interruptible(&tsk->wait_chldexit);
 		tsk = next_thread(tsk);
 		if (tsk->sig != parent->sig)
 			BUG();
 	} while (tsk != parent);
-	spin_unlock_irqrestore(&parent->sig->siglock, flags);
 }
 
 /*
@@ -1113,10 +1094,9 @@
 void do_notify_parent(struct task_struct *tsk, int sig)
 {
 	struct siginfo info;
+	unsigned long flags;
 	int why, status;
 
-	if (!tsk->ptrace && delay_group_leader(tsk))
-		return;
 	if (sig == -1)
 		BUG();
 
@@ -1154,8 +1134,10 @@
 	info.si_code = why;
 	info.si_status = status;
 
-	send_sig_info(sig, &info, tsk->parent);
-	wake_up_parent(tsk);
+	spin_lock_irqsave(&tsk->parent->sig->siglock, flags);
+	__send_sig_info(sig, &info, tsk->parent);
+	__wake_up_parent(tsk);
+	spin_unlock_irqrestore(&tsk->parent->sig->siglock, flags);
 }
 
 
@@ -1186,18 +1168,12 @@
 		unsigned long signr = 0;
 		struct k_sigaction *ka;
 
-		local_irq_disable();
-		if (current->sig->shared_pending.head) {
-			spin_lock(&current->sig->siglock);
+		spin_lock_irq(&current->sig->siglock);
+		if (current->sig->shared_pending.head)
 			signr = dequeue_signal(&current->sig->shared_pending, mask, info);
-			spin_unlock(&current->sig->siglock);
-		}
-		if (!signr) {
-			spin_lock(&current->sigmask_lock);
+		if (!signr)
 			signr = dequeue_signal(&current->pending, mask, info);
-			spin_unlock(&current->sigmask_lock);
-		}
-		local_irq_enable();
+		spin_unlock_irq(&current->sig->siglock);
 
 		if (!signr)
 			break;
@@ -1335,7 +1311,7 @@
 			goto out;
 		sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP));
 
-		spin_lock_irq(&current->sigmask_lock);
+		spin_lock_irq(&current->sig->siglock);
 		old_set = current->blocked;
 
 		error = 0;
@@ -1355,15 +1331,15 @@
 
 		current->blocked = new_set;
 		recalc_sigpending();
-		spin_unlock_irq(&current->sigmask_lock);
+		spin_unlock_irq(&current->sig->siglock);
 		if (error)
 			goto out;
 		if (oset)
 			goto set_old;
 	} else if (oset) {
-		spin_lock_irq(&current->sigmask_lock);
+		spin_lock_irq(&current->sig->siglock);
 		old_set = current->blocked;
-		spin_unlock_irq(&current->sigmask_lock);
+		spin_unlock_irq(&current->sig->siglock);
 
 	set_old:
 		error = -EFAULT;
@@ -1383,9 +1359,9 @@
 	if (sigsetsize > sizeof(sigset_t))
 		goto out;
 
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	sigandsets(&pending, &current->blocked, &current->pending.signal);
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	error = -EFAULT;
 	if (!copy_to_user(set, &pending, sigsetsize))
@@ -1493,7 +1469,6 @@
 	}
 
 	spin_lock_irq(&current->sig->siglock);
-	spin_lock(&current->sigmask_lock);
 	sig = dequeue_signal(&current->sig->shared_pending, &these, &info);
 	if (!sig)
 		sig = dequeue_signal(&current->pending, &these, &info);
@@ -1510,14 +1485,12 @@
 			current->real_blocked = current->blocked;
 			sigandsets(&current->blocked, &current->blocked, &these);
 			recalc_sigpending();
-			spin_unlock(&current->sigmask_lock);
 			spin_unlock_irq(&current->sig->siglock);
 
 			current->state = TASK_INTERRUPTIBLE;
 			timeout = schedule_timeout(timeout);
 
 			spin_lock_irq(&current->sig->siglock);
-			spin_lock(&current->sigmask_lock);
 			sig = dequeue_signal(&current->sig->shared_pending, &these, &info);
 			if (!sig)
 				sig = dequeue_signal(&current->pending, &these, &info);
@@ -1526,7 +1499,6 @@
 			recalc_sigpending();
 		}
 	}
-	spin_unlock(&current->sigmask_lock);
 	spin_unlock_irq(&current->sig->siglock);
 
 	if (sig) {
@@ -1583,7 +1555,7 @@
 	error = -ESRCH;
 	if (p) {
 		spin_lock_irq(&p->sig->siglock);
-		error = __send_sig_info(sig, &info, p, 0);
+		error = specific_send_sig_info(sig, &info, p, 0);
 		spin_unlock_irq(&p->sig->siglock);
 	}
 	read_unlock(&tasklist_lock);
@@ -1650,10 +1622,8 @@
 			    sig == SIGCHLD ||
 			    sig == SIGWINCH ||
 			    sig == SIGURG))) {
-			spin_lock_irq(&current->sigmask_lock);
 			if (rm_sig_from_queue(sig, current))
 				recalc_sigpending();
-			spin_unlock_irq(&current->sigmask_lock);
 		}
 	}
 
@@ -1746,7 +1716,7 @@
 			goto out;
 		new_set &= ~(sigmask(SIGKILL)|sigmask(SIGSTOP));
 
-		spin_lock_irq(&current->sigmask_lock);
+		spin_lock_irq(&current->sig->siglock);
 		old_set = current->blocked.sig[0];
 
 		error = 0;
@@ -1766,7 +1736,7 @@
 		}
 
 		recalc_sigpending();
-		spin_unlock_irq(&current->sigmask_lock);
+		spin_unlock_irq(&current->sig->siglock);
 		if (error)
 			goto out;
 		if (oset)
@@ -1828,13 +1798,13 @@
 {
 	int old;
 
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	old = current->blocked.sig[0];
 
 	siginitset(&current->blocked, newmask & ~(sigmask(SIGKILL)|
 						  sigmask(SIGSTOP)));
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	return old;
 }
@@ -1871,3 +1841,15 @@
 }
 
 #endif /* HAVE_ARCH_SYS_PAUSE */
+
+void __init signals_init(void)
+{
+	sigqueue_cachep =
+		kmem_cache_create("sigqueue",
+				  sizeof(struct sigqueue),
+				  __alignof__(struct sigqueue),
+				  0, NULL, NULL);
+	if (!sigqueue_cachep)
+		panic("signals_init(): cannot create sigqueue SLAB cache");
+}
+
diff -Nru a/kernel/softirq.c b/kernel/softirq.c
--- a/kernel/softirq.c	Tue Oct  1 00:08:16 2002
+++ b/kernel/softirq.c	Tue Oct  1 00:08:16 2002
@@ -3,21 +3,15 @@
  *
  *	Copyright (C) 1992 Linus Torvalds
  *
- * Fixed a disable_bh()/enable_bh() race (was causing a console lockup)
- * due bh_mask_count not atomic handling. Copyright (C) 1998  Andrea Arcangeli
- *
  * Rewritten. Old one was good in 2.2, but in 2.3 it was immoral. --ANK (990903)
  */
 
-#include <linux/config.h>
-#include <linux/mm.h>
 #include <linux/kernel_stat.h>
 #include <linux/interrupt.h>
-#include <linux/smp_lock.h>
-#include <linux/init.h>
-#include <linux/tqueue.h>
-#include <linux/percpu.h>
 #include <linux/notifier.h>
+#include <linux/percpu.h>
+#include <linux/init.h>
+#include <linux/mm.h>
 
 /*
    - No shared variables, all the data are CPU local.
@@ -35,7 +29,6 @@
      it is logically serialized per device, but this serialization
      is invisible to common code.
    - Tasklets: serialized wrt itself.
-   - Bottom halves: globally serialized, grr...
  */
 
 irq_cpustat_t irq_stat[NR_CPUS];
@@ -115,10 +108,10 @@
 	__cpu_raise_softirq(cpu, nr);
 
 	/*
-	 * If we're in an interrupt or bh, we're done
-	 * (this also catches bh-disabled code). We will
+	 * If we're in an interrupt or softirq, we're done
+	 * (this also catches softirq-disabled code). We will
 	 * actually run the softirq once we return from
-	 * the irq or bh.
+	 * the irq or softirq.
 	 *
 	 * Otherwise we wake up ksoftirqd to make sure we
 	 * schedule the softirq soon.
@@ -267,89 +260,10 @@
 	clear_bit(TASKLET_STATE_SCHED, &t->state);
 }
 
-
-
-/* Old style BHs */
-
-static void (*bh_base[32])(void);
-struct tasklet_struct bh_task_vec[32];
-
-/* BHs are serialized by spinlock global_bh_lock.
-
-   It is still possible to make synchronize_bh() as
-   spin_unlock_wait(&global_bh_lock). This operation is not used
-   by kernel now, so that this lock is not made private only
-   due to wait_on_irq().
-
-   It can be removed only after auditing all the BHs.
- */
-spinlock_t global_bh_lock = SPIN_LOCK_UNLOCKED;
-
-static void bh_action(unsigned long nr)
-{
-	if (!spin_trylock(&global_bh_lock))
-		goto resched;
-
-	if (bh_base[nr])
-		bh_base[nr]();
-
-	hardirq_endlock();
-	spin_unlock(&global_bh_lock);
-	return;
-
-	spin_unlock(&global_bh_lock);
-resched:
-	mark_bh(nr);
-}
-
-void init_bh(int nr, void (*routine)(void))
-{
-	bh_base[nr] = routine;
-	mb();
-}
-
-void remove_bh(int nr)
-{
-	tasklet_kill(bh_task_vec+nr);
-	bh_base[nr] = NULL;
-}
-
 void __init softirq_init()
 {
-	int i;
-
-	for (i=0; i<32; i++)
-		tasklet_init(bh_task_vec+i, bh_action, i);
-
 	open_softirq(TASKLET_SOFTIRQ, tasklet_action, NULL);
 	open_softirq(HI_SOFTIRQ, tasklet_hi_action, NULL);
-}
-
-void __run_task_queue(task_queue *list)
-{
-	struct list_head head, *next;
-	unsigned long flags;
-
-	spin_lock_irqsave(&tqueue_lock, flags);
-	list_add(&head, list);
-	list_del_init(list);
-	spin_unlock_irqrestore(&tqueue_lock, flags);
-
-	next = head.next;
-	while (next != &head) {
-		void (*f) (void *);
-		struct tq_struct *p;
-		void *data;
-
-		p = list_entry(next, struct tq_struct, list);
-		next = next->next;
-		f = p->routine;
-		data = p->data;
-		wmb();
-		p->sync = 0;
-		if (f)
-			f(data);
-	}
 }
 
 static int ksoftirqd(void * __bind_cpu)
diff -Nru a/kernel/suspend.c b/kernel/suspend.c
--- a/kernel/suspend.c	Tue Oct  1 00:08:16 2002
+++ b/kernel/suspend.c	Tue Oct  1 00:08:16 2002
@@ -219,9 +219,9 @@
 			/* FIXME: smp problem here: we may not access other process' flags
 			   without locking */
 			p->flags |= PF_FREEZE;
-			spin_lock_irqsave(&p->sigmask_lock, flags);
+			spin_lock_irqsave(&p->sig->siglock, flags);
 			signal_wake_up(p);
-			spin_unlock_irqrestore(&p->sigmask_lock, flags);
+			spin_unlock_irqrestore(&p->sig->siglock, flags);
 			todo++;
 		} while_each_thread(g, p);
 		read_unlock(&tasklist_lock);
diff -Nru a/kernel/timer.c b/kernel/timer.c
--- a/kernel/timer.c	Tue Oct  1 00:08:16 2002
+++ b/kernel/timer.c	Tue Oct  1 00:08:16 2002
@@ -14,74 +14,21 @@
  *                              Copyright (C) 1998  Andrea Arcangeli
  *  1999-03-10  Improved NTP compatibility by Ulrich Windl
  *  2002-05-31	Move sys_sysinfo here and make its locking sane, Robert Love
+ *  2000-10-05  Implemented scalable SMP per-CPU timer handling.
+ *                              Copyright (C) 2000, 2001, 2002  Ingo Molnar
+ *              Designed by David S. Miller, Alexey Kuznetsov and Ingo Molnar
  */
 
-#include <linux/config.h>
-#include <linux/mm.h>
-#include <linux/timex.h>
-#include <linux/delay.h>
-#include <linux/smp_lock.h>
-#include <linux/interrupt.h>
-#include <linux/tqueue.h>
 #include <linux/kernel_stat.h>
+#include <linux/interrupt.h>
+#include <linux/percpu.h>
+#include <linux/init.h>
+#include <linux/mm.h>
 
 #include <asm/uaccess.h>
 
-struct kernel_stat kstat;
-
-/*
- * Timekeeping variables
- */
-
-unsigned long tick_usec = TICK_USEC; 		/* ACTHZ          period (usec) */
-unsigned long tick_nsec = TICK_NSEC(TICK_USEC);	/* USER_HZ period (nsec) */
-
-/* The current time */
-struct timespec xtime __attribute__ ((aligned (16)));
-
-/* Don't completely fail for HZ > 500.  */
-int tickadj = 500/HZ ? : 1;		/* microsecs */
-
-DECLARE_TASK_QUEUE(tq_timer);
-DECLARE_TASK_QUEUE(tq_immediate);
-
 /*
- * phase-lock loop variables
- */
-/* TIME_ERROR prevents overwriting the CMOS clock */
-int time_state = TIME_OK;		/* clock synchronization status	*/
-int time_status = STA_UNSYNC;		/* clock status bits		*/
-long time_offset;			/* time adjustment (us)		*/
-long time_constant = 2;			/* pll time constant		*/
-long time_tolerance = MAXFREQ;		/* frequency tolerance (ppm)	*/
-long time_precision = 1;		/* clock precision (us)		*/
-long time_maxerror = NTP_PHASE_LIMIT;	/* maximum error (us)		*/
-long time_esterror = NTP_PHASE_LIMIT;	/* estimated error (us)		*/
-long time_phase;			/* phase offset (scaled us)	*/
-long time_freq = ((1000000 + HZ/2) % HZ - HZ/2) << SHIFT_USEC;
-					/* frequency offset (scaled ppm)*/
-long time_adj;				/* tick adjust (scaled 1 / HZ)	*/
-long time_reftime;			/* time at last adjustment (s)	*/
-
-long time_adjust;
-
-unsigned long event;
-
-extern int do_setitimer(int, struct itimerval *, struct itimerval *);
-
-/*
- * The 64-bit jiffies value is not atomic - you MUST NOT read it
- * without holding read_lock_irq(&xtime_lock).
- * jiffies is defined in the linker script...
- */
-
-
-unsigned int * prof_buffer;
-unsigned long prof_len;
-unsigned long prof_shift;
-
-/*
- * Event timer code
+ * per-CPU timer vector definitions:
  */
 #define TVN_BITS 6
 #define TVR_BITS 8
@@ -90,115 +37,88 @@
 #define TVN_MASK (TVN_SIZE - 1)
 #define TVR_MASK (TVR_SIZE - 1)
 
-struct timer_vec {
+typedef struct tvec_s {
 	int index;
 	struct list_head vec[TVN_SIZE];
-};
+} tvec_t;
 
-struct timer_vec_root {
+typedef struct tvec_root_s {
 	int index;
 	struct list_head vec[TVR_SIZE];
-};
+} tvec_root_t;
 
-static struct timer_vec tv5;
-static struct timer_vec tv4;
-static struct timer_vec tv3;
-static struct timer_vec tv2;
-static struct timer_vec_root tv1;
+struct tvec_t_base_s {
+	spinlock_t lock;
+	unsigned long timer_jiffies;
+	volatile timer_t * volatile running_timer;
+	tvec_root_t tv1;
+	tvec_t tv2;
+	tvec_t tv3;
+	tvec_t tv4;
+	tvec_t tv5;
+} ____cacheline_aligned_in_smp;
 
-static struct timer_vec * const tvecs[] = {
-	(struct timer_vec *)&tv1, &tv2, &tv3, &tv4, &tv5
-};
+typedef struct tvec_t_base_s tvec_base_t;
 
-#define NOOF_TVECS (sizeof(tvecs) / sizeof(tvecs[0]))
+static tvec_base_t tvec_bases[NR_CPUS] __cacheline_aligned;
 
-void init_timervecs (void)
-{
-	int i;
+/* Fake initialization needed to avoid compiler breakage */
+static DEFINE_PER_CPU(struct tasklet_struct, timer_tasklet) = { NULL };
 
-	for (i = 0; i < TVN_SIZE; i++) {
-		INIT_LIST_HEAD(tv5.vec + i);
-		INIT_LIST_HEAD(tv4.vec + i);
-		INIT_LIST_HEAD(tv3.vec + i);
-		INIT_LIST_HEAD(tv2.vec + i);
-	}
-	for (i = 0; i < TVR_SIZE; i++)
-		INIT_LIST_HEAD(tv1.vec + i);
-}
-
-static unsigned long timer_jiffies;
-
-static inline void internal_add_timer(struct timer_list *timer)
+static inline void internal_add_timer(tvec_base_t *base, timer_t *timer)
 {
-	/*
-	 * must be cli-ed when calling this
-	 */
 	unsigned long expires = timer->expires;
-	unsigned long idx = expires - timer_jiffies;
+	unsigned long idx = expires - base->timer_jiffies;
 	struct list_head * vec;
 
 	if (idx < TVR_SIZE) {
 		int i = expires & TVR_MASK;
-		vec = tv1.vec + i;
+		vec = base->tv1.vec + i;
 	} else if (idx < 1 << (TVR_BITS + TVN_BITS)) {
 		int i = (expires >> TVR_BITS) & TVN_MASK;
-		vec = tv2.vec + i;
+		vec = base->tv2.vec + i;
 	} else if (idx < 1 << (TVR_BITS + 2 * TVN_BITS)) {
 		int i = (expires >> (TVR_BITS + TVN_BITS)) & TVN_MASK;
-		vec =  tv3.vec + i;
+		vec = base->tv3.vec + i;
 	} else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS)) {
 		int i = (expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK;
-		vec = tv4.vec + i;
+		vec = base->tv4.vec + i;
 	} else if ((signed long) idx < 0) {
-		/* can happen if you add a timer with expires == jiffies,
+		/*
+		 * Can happen if you add a timer with expires == jiffies,
 		 * or you set a timer to go off in the past
 		 */
-		vec = tv1.vec + tv1.index;
+		vec = base->tv1.vec + base->tv1.index;
 	} else if (idx <= 0xffffffffUL) {
 		int i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK;
-		vec = tv5.vec + i;
+		vec = base->tv5.vec + i;
 	} else {
 		/* Can only get here on architectures with 64-bit jiffies */
 		INIT_LIST_HEAD(&timer->list);
 		return;
 	}
 	/*
-	 * Timers are FIFO!
+	 * Timers are FIFO:
 	 */
-	list_add(&timer->list, vec->prev);
+	list_add_tail(&timer->list, vec);
 }
 
-/* Initialize both explicitly - let's try to have them in the same cache line */
-spinlock_t timerlist_lock ____cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
-
-#ifdef CONFIG_SMP
-volatile struct timer_list * volatile running_timer;
-#define timer_enter(t) do { running_timer = t; mb(); } while (0)
-#define timer_exit() do { running_timer = NULL; } while (0)
-#define timer_is_running(t) (running_timer == t)
-#define timer_synchronize(t) while (timer_is_running(t)) barrier()
-#else
-#define timer_enter(t)		do { } while (0)
-#define timer_exit()		do { } while (0)
-#endif
-
-void add_timer(struct timer_list *timer)
+void add_timer(timer_t *timer)
 {
-	unsigned long flags;
+	int cpu = get_cpu();
+	tvec_base_t *base = tvec_bases + cpu;
+  	unsigned long flags;
+  
+  	BUG_ON(timer_pending(timer));
 
-	spin_lock_irqsave(&timerlist_lock, flags);
-	if (unlikely(timer_pending(timer)))
-		goto bug;
-	internal_add_timer(timer);
-	spin_unlock_irqrestore(&timerlist_lock, flags);
-	return;
-bug:
-	spin_unlock_irqrestore(&timerlist_lock, flags);
-	printk(KERN_ERR "BUG: kernel timer added twice at %p.\n",
-			__builtin_return_address(0));
+	spin_lock_irqsave(&base->lock, flags);
+	internal_add_timer(base, timer);
+	timer->base = base;
+	spin_unlock_irqrestore(&base->lock, flags);
+	put_cpu();
 }
 
-static inline int detach_timer (struct timer_list *timer)
+static inline int detach_timer (timer_t *timer)
 {
 	if (!timer_pending(timer))
 		return 0;
@@ -206,28 +126,78 @@
 	return 1;
 }
 
-int mod_timer(struct timer_list *timer, unsigned long expires)
+/*
+ * mod_timer() has subtle locking semantics because parallel
+ * calls to it must happen serialized.
+ */
+int mod_timer(timer_t *timer, unsigned long expires)
 {
-	int ret;
+	tvec_base_t *old_base, *new_base;
 	unsigned long flags;
+	int ret;
+
+	if (timer_pending(timer) && timer->expires == expires)
+		return 1;
+
+	local_irq_save(flags);
+	new_base = tvec_bases + smp_processor_id();
+repeat:
+	old_base = timer->base;
+
+	/*
+	 * Prevent deadlocks via ordering by old_base < new_base.
+	 */
+	if (old_base && (new_base != old_base)) {
+		if (old_base < new_base) {
+			spin_lock(&new_base->lock);
+			spin_lock(&old_base->lock);
+		} else {
+			spin_lock(&old_base->lock);
+			spin_lock(&new_base->lock);
+		}
+		/*
+		 * Subtle, we rely on timer->base being always
+		 * valid and being updated atomically.
+		 */
+		if (timer->base != old_base) {
+			spin_unlock(&new_base->lock);
+			spin_unlock(&old_base->lock);
+			goto repeat;
+		}
+	} else
+		spin_lock(&new_base->lock);
 
-	spin_lock_irqsave(&timerlist_lock, flags);
 	timer->expires = expires;
 	ret = detach_timer(timer);
-	internal_add_timer(timer);
-	spin_unlock_irqrestore(&timerlist_lock, flags);
+	internal_add_timer(new_base, timer);
+	timer->base = new_base;
+
+	if (old_base && (new_base != old_base))
+		spin_unlock(&old_base->lock);
+	spin_unlock_irqrestore(&new_base->lock, flags);
+
 	return ret;
 }
 
-int del_timer(struct timer_list * timer)
+int del_timer(timer_t * timer)
 {
-	int ret;
 	unsigned long flags;
+	tvec_base_t * base;
+	int ret;
 
-	spin_lock_irqsave(&timerlist_lock, flags);
+	if (!timer->base)
+		return 0;
+repeat:
+ 	base = timer->base;
+	spin_lock_irqsave(&base->lock, flags);
+	if (base != timer->base) {
+		spin_unlock_irqrestore(&base->lock, flags);
+		goto repeat;
+	}
 	ret = detach_timer(timer);
 	timer->list.next = timer->list.prev = NULL;
-	spin_unlock_irqrestore(&timerlist_lock, flags);
+	spin_unlock_irqrestore(&base->lock, flags);
+
 	return ret;
 }
 
@@ -240,24 +210,33 @@
  * (for reference counting).
  */
 
-int del_timer_sync(struct timer_list * timer)
+int del_timer_sync(timer_t * timer)
 {
+	tvec_base_t * base;
 	int ret = 0;
 
+	if (!timer->base)
+		return 0;
 	for (;;) {
 		unsigned long flags;
 		int running;
 
-		spin_lock_irqsave(&timerlist_lock, flags);
+repeat:
+	 	base = timer->base;
+		spin_lock_irqsave(&base->lock, flags);
+		if (base != timer->base) {
+			spin_unlock_irqrestore(&base->lock, flags);
+			goto repeat;
+		}
 		ret += detach_timer(timer);
 		timer->list.next = timer->list.prev = 0;
-		running = timer_is_running(timer);
-		spin_unlock_irqrestore(&timerlist_lock, flags);
+		running = timer_is_running(base, timer);
+		spin_unlock_irqrestore(&base->lock, flags);
 
 		if (!running)
 			break;
 
-		timer_synchronize(timer);
+		timer_synchronize(base, timer);
 	}
 
 	return ret;
@@ -265,7 +244,7 @@
 #endif
 
 
-static inline void cascade_timers(struct timer_vec *tv)
+static void cascade(tvec_base_t *base, tvec_t *tv)
 {
 	/* cascade all the timers from tv up one level */
 	struct list_head *head, *curr, *next;
@@ -277,67 +256,107 @@
 	 * detach them individually, just clear the list afterwards.
 	 */
 	while (curr != head) {
-		struct timer_list *tmp;
+		timer_t *tmp;
 
-		tmp = list_entry(curr, struct timer_list, list);
+		tmp = list_entry(curr, timer_t, list);
+		if (tmp->base != base)
+			BUG();
 		next = curr->next;
 		list_del(curr); // not needed
-		internal_add_timer(tmp);
+		internal_add_timer(base, tmp);
 		curr = next;
 	}
 	INIT_LIST_HEAD(head);
 	tv->index = (tv->index + 1) & TVN_MASK;
 }
 
-static inline void run_timer_list(void)
+static void __run_timers(tvec_base_t *base)
 {
-	spin_lock_irq(&timerlist_lock);
-	while ((long)(jiffies - timer_jiffies) >= 0) {
+	unsigned long flags;
+
+	spin_lock_irqsave(&base->lock, flags);
+	while ((long)(jiffies - base->timer_jiffies) >= 0) {
 		struct list_head *head, *curr;
-		if (!tv1.index) {
-			int n = 1;
-			do {
-				cascade_timers(tvecs[n]);
-			} while (tvecs[n]->index == 1 && ++n < NOOF_TVECS);
+
+		/*
+		 * 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);
+				}
+			}
 		}
 repeat:
-		head = tv1.vec + tv1.index;
+		head = base->tv1.vec + base->tv1.index;
 		curr = head->next;
 		if (curr != head) {
-			struct timer_list *timer;
 			void (*fn)(unsigned long);
 			unsigned long data;
+			timer_t *timer;
 
-			timer = list_entry(curr, struct timer_list, list);
+			timer = list_entry(curr, timer_t, list);
  			fn = timer->function;
- 			data= timer->data;
+ 			data = timer->data;
 
 			detach_timer(timer);
 			timer->list.next = timer->list.prev = NULL;
-			timer_enter(timer);
-			spin_unlock_irq(&timerlist_lock);
+			timer_enter(base, timer);
+			spin_unlock_irq(&base->lock);
 			fn(data);
-			spin_lock_irq(&timerlist_lock);
-			timer_exit();
+			spin_lock_irq(&base->lock);
+			timer_exit(base);
 			goto repeat;
 		}
-		++timer_jiffies; 
-		tv1.index = (tv1.index + 1) & TVR_MASK;
+		++base->timer_jiffies; 
+		base->tv1.index = (base->tv1.index + 1) & TVR_MASK;
 	}
-	spin_unlock_irq(&timerlist_lock);
+	spin_unlock_irqrestore(&base->lock, flags);
 }
 
-spinlock_t tqueue_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
+/******************************************************************/
 
-void tqueue_bh(void)
-{
-	run_task_queue(&tq_timer);
-}
+/*
+ * Timekeeping variables
+ */
+unsigned long tick_usec = TICK_USEC; 		/* ACTHZ   period (usec) */
+unsigned long tick_nsec = TICK_NSEC(TICK_USEC);	/* USER_HZ period (nsec) */
 
-void immediate_bh(void)
-{
-	run_task_queue(&tq_immediate);
-}
+/* The current time */
+struct timespec xtime __attribute__ ((aligned (16)));
+
+/* Don't completely fail for HZ > 500.  */
+int tickadj = 500/HZ ? : 1;		/* microsecs */
+
+struct kernel_stat kstat;
+
+/*
+ * phase-lock loop variables
+ */
+/* TIME_ERROR prevents overwriting the CMOS clock */
+int time_state = TIME_OK;		/* clock synchronization status	*/
+int time_status = STA_UNSYNC;		/* clock status bits		*/
+long time_offset;			/* time adjustment (us)		*/
+long time_constant = 2;			/* pll time constant		*/
+long time_tolerance = MAXFREQ;		/* frequency tolerance (ppm)	*/
+long time_precision = 1;		/* clock precision (us)		*/
+long time_maxerror = NTP_PHASE_LIMIT;	/* maximum error (us)		*/
+long time_esterror = NTP_PHASE_LIMIT;	/* estimated error (us)		*/
+long time_phase;			/* phase offset (scaled us)	*/
+long time_freq = ((1000000 + HZ/2) % HZ - HZ/2) << SHIFT_USEC;
+					/* frequency offset (scaled ppm)*/
+long time_adj;				/* tick adjust (scaled 1 / HZ)	*/
+long time_reftime;			/* time at last adjustment (s)	*/
+long time_adjust;
+
+unsigned int * prof_buffer;
+unsigned long prof_len;
+unsigned long prof_shift;
 
 /*
  * this routine handles the overflow of the microsecond field
@@ -638,17 +657,33 @@
 rwlock_t xtime_lock __cacheline_aligned_in_smp = RW_LOCK_UNLOCKED;
 unsigned long last_time_offset;
 
+/*
+ * This function runs timers and the timer-tq in softirq context.
+ */
+static void run_timer_tasklet(unsigned long data)
+{
+	tvec_base_t *base = tvec_bases + smp_processor_id();
+
+	if ((long)(jiffies - base->timer_jiffies) >= 0)
+		__run_timers(base);
+}
+
+/*
+ * Called by the local, per-CPU timer interrupt on SMP.
+ */
+void run_local_timers(void)
+{
+	tasklet_hi_schedule(&per_cpu(timer_tasklet, smp_processor_id()));
+}
+
+/*
+ * Called by the timer interrupt. xtime_lock must already be taken
+ * by the timer IRQ!
+ */
 static inline void update_times(void)
 {
 	unsigned long ticks;
 
-	/*
-	 * update_times() is run from the raw timer_bh handler so we
-	 * just know that the irqs are locally enabled and so we don't
-	 * need to save/restore the flags of the local CPU here. -arca
-	 */
-	write_lock_irq(&xtime_lock);
-
 	ticks = jiffies - wall_jiffies;
 	if (ticks) {
 		wall_jiffies += ticks;
@@ -656,14 +691,13 @@
 	}
 	last_time_offset = 0;
 	calc_load(ticks);
-	write_unlock_irq(&xtime_lock);
-}
-
-void timer_bh(void)
-{
-	update_times();
-	run_timer_list();
 }
+  
+/*
+ * The 64-bit jiffies value is not atomic - you MUST NOT read it
+ * without holding read_lock_irq(&xtime_lock).
+ * jiffies is defined in the linker script...
+ */
 
 void do_timer(struct pt_regs *regs)
 {
@@ -673,13 +707,13 @@
 
 	update_process_times(user_mode(regs));
 #endif
-	mark_bh(TIMER_BH);
-	if (TQ_ACTIVE(tq_timer))
-		mark_bh(TQUEUE_BH);
+	update_times();
 }
 
 #if !defined(__alpha__) && !defined(__ia64__)
 
+extern int do_setitimer(int, struct itimerval *, struct itimerval *);
+
 /*
  * For backwards compatibility?  This can be done in libc so Alpha
  * and all newer ports shouldn't need it.
@@ -821,7 +855,7 @@
  */
 signed long schedule_timeout(signed long timeout)
 {
-	struct timer_list timer;
+	timer_t timer;
 	unsigned long expire;
 
 	switch (timeout)
@@ -973,4 +1007,25 @@
 		return -EFAULT;
 
 	return 0;
+}
+
+void __init init_timers(void)
+{
+	int i, j;
+
+	for (i = 0; i < NR_CPUS; i++) {
+		tvec_base_t *base;
+	       
+		base = tvec_bases + i;
+		spin_lock_init(&base->lock);
+		for (j = 0; j < TVN_SIZE; j++) {
+			INIT_LIST_HEAD(base->tv5.vec + j);
+			INIT_LIST_HEAD(base->tv4.vec + j);
+			INIT_LIST_HEAD(base->tv3.vec + j);
+			INIT_LIST_HEAD(base->tv2.vec + j);
+		}
+		for (j = 0; j < TVR_SIZE; j++)
+			INIT_LIST_HEAD(base->tv1.vec + j);
+		tasklet_init(&per_cpu(timer_tasklet, i), run_timer_tasklet, 0);
+	}
 }
diff -Nru a/lib/bust_spinlocks.c b/lib/bust_spinlocks.c
--- a/lib/bust_spinlocks.c	Tue Oct  1 00:08:15 2002
+++ b/lib/bust_spinlocks.c	Tue Oct  1 00:08:15 2002
@@ -14,11 +14,9 @@
 #include <linux/wait.h>
 #include <linux/vt_kern.h>
 
-extern spinlock_t timerlist_lock;
 
 void bust_spinlocks(int yes)
 {
-	spin_lock_init(&timerlist_lock);
 	if (yes) {
 		oops_in_progress = 1;
 	} else {
diff -Nru a/mm/memory.c b/mm/memory.c
--- a/mm/memory.c	Tue Oct  1 00:08:17 2002
+++ b/mm/memory.c	Tue Oct  1 00:08:17 2002
@@ -571,7 +571,8 @@
 					i = -EFAULT;
 					goto out;
 				}
-				page_cache_get(pages[i]);
+				if (!PageReserved(pages[i]))
+					page_cache_get(pages[i]);
 			}
 			if (vmas)
 				vmas[i] = vma;
diff -Nru a/mm/mmap.c b/mm/mmap.c
--- a/mm/mmap.c	Tue Oct  1 00:08:15 2002
+++ b/mm/mmap.c	Tue Oct  1 00:08:15 2002
@@ -553,6 +553,7 @@
 	vma->vm_file = NULL;
 	vma->vm_private_data = NULL;
 	vma->vm_raend = 0;
+	INIT_LIST_HEAD(&vma->shared);
 
 	if (file) {
 		error = -EINVAL;
@@ -1052,6 +1053,8 @@
 	/* most fields are the same, copy all, and then fixup */
 	*new = *vma;
 
+	INIT_LIST_HEAD(&new->shared);
+
 	if (new_below) {
 		new->vm_end = addr;
 		vma->vm_start = addr;
@@ -1215,6 +1218,7 @@
 	vma->vm_pgoff = 0;
 	vma->vm_file = NULL;
 	vma->vm_private_data = NULL;
+	INIT_LIST_HEAD(&vma->shared);
 
 	vma_link(mm, vma, prev, rb_link, rb_parent);
 
diff -Nru a/mm/mremap.c b/mm/mremap.c
--- a/mm/mremap.c	Tue Oct  1 00:08:17 2002
+++ b/mm/mremap.c	Tue Oct  1 00:08:17 2002
@@ -53,6 +53,22 @@
 	return pte;
 }
 
+#ifdef CONFIG_HIGHPTE	/* Save a few cycles on the sane machines */
+static inline int page_table_present(struct mm_struct *mm, unsigned long addr)
+{
+	pgd_t *pgd;
+	pmd_t *pmd;
+
+	pgd = pgd_offset(mm, addr);
+	if (pgd_none(*pgd))
+		return 0;
+	pmd = pmd_offset(pgd, addr);
+	return pmd_present(*pmd);
+}
+#else
+#define page_table_present(mm, addr)	(1)
+#endif
+
 static inline pte_t *alloc_one_pte_map(struct mm_struct *mm, unsigned long addr)
 {
 	pmd_t * pmd;
@@ -98,7 +114,18 @@
 	spin_lock(&mm->page_table_lock);
 	src = get_one_pte_map_nested(mm, old_addr);
 	if (src) {
+		/*
+		 * Look to see whether alloc_one_pte_map needs to perform a
+		 * memory allocation.  If it does then we need to drop the
+		 * atomic kmap
+		 */
+		if (!page_table_present(mm, new_addr)) {
+			pte_unmap_nested(src);
+			src = NULL;
+		}
 		dst = alloc_one_pte_map(mm, new_addr);
+		if (src == NULL)
+			src = get_one_pte_map_nested(mm, old_addr);
 		error = copy_one_pte(mm, src, dst);
 		pte_unmap_nested(src);
 		pte_unmap(dst);
@@ -200,6 +227,7 @@
 	if (!move_page_tables(vma, new_addr, addr, old_len)) {
 		if (allocated_vma) {
 			*new_vma = *vma;
+			INIT_LIST_HEAD(&new_vma->shared);
 			new_vma->vm_start = new_addr;
 			new_vma->vm_end = new_addr+new_len;
 			new_vma->vm_pgoff += (addr - vma->vm_start) >> PAGE_SHIFT;
diff -Nru a/mm/page_alloc.c b/mm/page_alloc.c
--- a/mm/page_alloc.c	Tue Oct  1 00:08:15 2002
+++ b/mm/page_alloc.c	Tue Oct  1 00:08:15 2002
@@ -82,7 +82,7 @@
 void __free_pages_ok (struct page *page, unsigned int order)
 {
 	unsigned long index, page_idx, mask, flags;
-	free_area_t *area;
+	struct free_area *area;
 	struct page *base;
 	struct zone *zone;
 
@@ -155,7 +155,7 @@
 
 static inline struct page *
 expand(struct zone *zone, struct page *page,
-	 unsigned long index, int low, int high, free_area_t * area)
+	 unsigned long index, int low, int high, struct free_area *area)
 {
 	unsigned long size = 1 << high;
 
@@ -194,7 +194,7 @@
 
 static struct page *rmqueue(struct zone *zone, unsigned int order)
 {
-	free_area_t * area = zone->free_area + order;
+	struct free_area *area = zone->free_area + order;
 	unsigned int curr_order = order;
 	struct list_head *head, *curr;
 	unsigned long flags;
@@ -348,8 +348,12 @@
 	classzone->need_balance = 1;
 	mb();
 	/* we're somewhat low on memory, failed to find what we needed */
-	if (waitqueue_active(&kswapd_wait))
-		wake_up_interruptible(&kswapd_wait);
+	for (i = 0; zones[i] != NULL; i++) {
+		struct zone *z = zones[i];
+		if (z->free_pages <= z->pages_low &&
+		    waitqueue_active(&z->zone_pgdat->kswapd_wait))
+			wake_up_interruptible(&z->zone_pgdat->kswapd_wait);
+	}
 
 	/* Go through the zonelist again, taking __GFP_HIGH into account */
 	min = 1UL << order;
@@ -836,6 +840,8 @@
 	unsigned long zone_start_pfn = pgdat->node_start_pfn;
 
 	pgdat->nr_zones = 0;
+	init_waitqueue_head(&pgdat->kswapd_wait);
+	
 	local_offset = 0;                /* offset within lmem_map */
 	for (j = 0; j < MAX_NR_ZONES; j++) {
 		struct zone *zone = pgdat->node_zones + j;
@@ -975,3 +981,71 @@
 }
 
 __setup("memfrac=", setup_mem_frac);
+
+#ifdef CONFIG_PROC_FS
+
+#include <linux/seq_file.h>
+
+static void *frag_start(struct seq_file *m, loff_t *pos)
+{
+	pg_data_t *pgdat;
+	loff_t node = *pos;
+
+	for (pgdat = pgdat_list; pgdat && node; pgdat = pgdat->pgdat_next)
+		--node;
+
+	return pgdat;
+}
+
+static void *frag_next(struct seq_file *m, void *arg, loff_t *pos)
+{
+	pg_data_t *pgdat = (pg_data_t *)arg;
+
+	(*pos)++;
+	return pgdat->pgdat_next;
+}
+
+static void frag_stop(struct seq_file *m, void *arg)
+{
+}
+
+/* 
+ * This walks the freelist for each zone. Whilst this is slow, I'd rather 
+ * be slow here than slow down the fast path by keeping stats - mjbligh
+ */
+static int frag_show(struct seq_file *m, void *arg)
+{
+	pg_data_t *pgdat = (pg_data_t *)arg;
+	struct zone *zone;
+	struct zone *node_zones = pgdat->node_zones;
+	unsigned long flags;
+	int order;
+
+	for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; ++zone) {
+		if (!zone->size)
+			continue;
+
+		spin_lock_irqsave(&zone->lock, flags);
+		seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name);
+		for (order = 0; order < MAX_ORDER; ++order) {
+			unsigned long nr_bufs = 0;
+			struct list_head *elem;
+
+			list_for_each(elem, &(zone->free_area[order].free_list))
+				++nr_bufs;
+			seq_printf(m, "%6lu ", nr_bufs);
+		}
+		spin_unlock_irqrestore(&zone->lock, flags);
+		seq_putc(m, '\n');
+	}
+	return 0;
+}
+
+struct seq_operations fragmentation_op = {
+	.start	= frag_start,
+	.next	= frag_next,
+	.stop	= frag_stop,
+	.show	= frag_show,
+};
+
+#endif /* CONFIG_PROC_FS */
diff -Nru a/mm/pdflush.c b/mm/pdflush.c
--- a/mm/pdflush.c	Tue Oct  1 00:08:22 2002
+++ b/mm/pdflush.c	Tue Oct  1 00:08:22 2002
@@ -91,10 +91,10 @@
 	strcpy(current->comm, "pdflush");
 
 	/* interruptible sleep, so block all signals */
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	siginitsetinv(&current->blocked, 0);
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	current->flags |= PF_FLUSHER;
 	my_work->fn = NULL;
diff -Nru a/mm/slab.c b/mm/slab.c
--- a/mm/slab.c	Tue Oct  1 00:08:19 2002
+++ b/mm/slab.c	Tue Oct  1 00:08:19 2002
@@ -1499,9 +1499,9 @@
 		if (unlikely(!--slabp->inuse)) {
 			/* Was partial or full, now empty. */
 			list_del(&slabp->list);
-/*			list_add(&slabp->list, &cachep->slabs_free); 		*/
-			if (unlikely(list_empty(&cachep->slabs_partial)))
-				list_add(&slabp->list, &cachep->slabs_partial);
+			/* We only buffer a single page */
+			if (list_empty(&cachep->slabs_free))
+				list_add(&slabp->list, &cachep->slabs_free);
 			else
 				kmem_slab_destroy(cachep, slabp);
 		} else if (unlikely(inuse == cachep->num)) {
@@ -1977,8 +1977,7 @@
 	}
 	list_for_each(q,&cachep->slabs_partial) {
 		slabp = list_entry(q, slab_t, list);
-		if (slabp->inuse == cachep->num)
-			BUG();
+		BUG_ON(slabp->inuse == cachep->num || !slabp->inuse);
 		active_objs += slabp->inuse;
 		active_slabs++;
 	}
diff -Nru a/mm/swap_state.c b/mm/swap_state.c
--- a/mm/swap_state.c	Tue Oct  1 00:08:17 2002
+++ b/mm/swap_state.c	Tue Oct  1 00:08:17 2002
@@ -43,6 +43,8 @@
 	.a_ops			= &swap_aops,
 	.backing_dev_info	= &swap_backing_dev_info,
 	.i_shared_lock		= SPIN_LOCK_UNLOCKED,
+	.i_mmap			= LIST_HEAD_INIT(swapper_space.i_mmap),
+	.i_mmap_shared		= LIST_HEAD_INIT(swapper_space.i_mmap_shared),
 	.private_lock		= SPIN_LOCK_UNLOCKED,
 	.private_list		= LIST_HEAD_INIT(swapper_space.private_list),
 };
diff -Nru a/mm/vmscan.c b/mm/vmscan.c
--- a/mm/vmscan.c	Tue Oct  1 00:08:15 2002
+++ b/mm/vmscan.c	Tue Oct  1 00:08:15 2002
@@ -30,6 +30,8 @@
 
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
+#include <asm/topology.h>
+
 #include <linux/swapops.h>
 
 /*
@@ -667,8 +669,6 @@
 	return 0;
 }
 
-DECLARE_WAIT_QUEUE_HEAD(kswapd_wait);
-
 static int check_classzone_need_balance(struct zone *classzone)
 {
 	struct zone *first_classzone;
@@ -707,20 +707,6 @@
 	return need_more_balance;
 }
 
-static void kswapd_balance(void)
-{
-	int need_more_balance;
-	pg_data_t * pgdat;
-
-	do {
-		need_more_balance = 0;
-		pgdat = pgdat_list;
-		do
-			need_more_balance |= kswapd_balance_pgdat(pgdat);
-		while ((pgdat = pgdat->pgdat_next));
-	} while (need_more_balance);
-}
-
 static int kswapd_can_sleep_pgdat(pg_data_t * pgdat)
 {
 	struct zone *zone;
@@ -728,28 +714,13 @@
 
 	for (i = pgdat->nr_zones-1; i >= 0; i--) {
 		zone = pgdat->node_zones + i;
-		if (!zone->need_balance)
-			continue;
-		return 0;
+		if (zone->need_balance)
+			return 0;
 	}
 
 	return 1;
 }
 
-static int kswapd_can_sleep(void)
-{
-	pg_data_t * pgdat;
-
-	pgdat = pgdat_list;
-	do {
-		if (kswapd_can_sleep_pgdat(pgdat))
-			continue;
-		return 0;
-	} while ((pgdat = pgdat->pgdat_next));
-
-	return 1;
-}
-
 /*
  * The background pageout daemon, started as a kernel thread
  * from the init process. 
@@ -763,13 +734,15 @@
  * If there are applications that are active memory-allocators
  * (most normal use), this basically shouldn't matter.
  */
-int kswapd(void *unused)
+int kswapd(void *p)
 {
+	pg_data_t *pgdat = (pg_data_t*)p;
 	struct task_struct *tsk = current;
 	DECLARE_WAITQUEUE(wait, tsk);
 
 	daemonize();
-	strcpy(tsk->comm, "kswapd");
+	set_cpus_allowed(tsk, __node_to_cpu_mask(pgdat->node_id));
+	sprintf(tsk->comm, "kswapd%d", pgdat->node_id);
 	sigfillset(&tsk->blocked);
 	
 	/*
@@ -793,30 +766,32 @@
 		if (current->flags & PF_FREEZE)
 			refrigerator(PF_IOTHREAD);
 		__set_current_state(TASK_INTERRUPTIBLE);
-		add_wait_queue(&kswapd_wait, &wait);
+		add_wait_queue(&pgdat->kswapd_wait, &wait);
 
 		mb();
-		if (kswapd_can_sleep())
+		if (kswapd_can_sleep_pgdat(pgdat))
 			schedule();
 
 		__set_current_state(TASK_RUNNING);
-		remove_wait_queue(&kswapd_wait, &wait);
+		remove_wait_queue(&pgdat->kswapd_wait, &wait);
 
 		/*
 		 * If we actually get into a low-memory situation,
 		 * the processes needing more memory will wake us
 		 * up on a more timely basis.
 		 */
-		kswapd_balance();
+		kswapd_balance_pgdat(pgdat);
 		blk_run_queues();
 	}
 }
 
 static int __init kswapd_init(void)
 {
+	pg_data_t *pgdat;
 	printk("Starting kswapd\n");
 	swap_setup();
-	kernel_thread(kswapd, NULL, CLONE_KERNEL);
+	for_each_pgdat(pgdat)
+		kernel_thread(kswapd, pgdat, CLONE_KERNEL);
 	return 0;
 }
 
diff -Nru a/net/Config.in b/net/Config.in
--- a/net/Config.in	Tue Oct  1 00:08:16 2002
+++ b/net/Config.in	Tue Oct  1 00:08:16 2002
@@ -47,9 +47,9 @@
 fi
 tristate '802.1Q VLAN Support' CONFIG_VLAN_8021Q
 
-tristate 'ANSI/IEEE 802.2 Data link layer protocol' CONFIG_LLC
+tristate 'ANSI/IEEE 802.2 Data link layer protocol (IPX, Appletalk)' CONFIG_LLC
 if [ "$CONFIG_LLC" != "n" ]; then
-   tristate '  LLC sockets interface' CONFIG_LLC_UI
+   bool '  LLC sockets interface' CONFIG_LLC_UI
 fi
 
 dep_tristate 'The IPX protocol' CONFIG_IPX $CONFIG_LLC
diff -Nru a/net/Makefile b/net/Makefile
--- a/net/Makefile	Tue Oct  1 00:08:17 2002
+++ b/net/Makefile	Tue Oct  1 00:08:17 2002
@@ -9,6 +9,8 @@
 
 obj-y	:= socket.o core/
 
+# LLC has to be linked before the files in net/802/
+obj-$(CONFIG_LLC)		+= llc/
 obj-$(CONFIG_NET)		+= ethernet/ 802/ sched/ netlink/
 obj-$(CONFIG_INET)		+= ipv4/
 obj-$(CONFIG_UNIX)		+= unix/
@@ -31,7 +33,6 @@
 obj-$(CONFIG_DECNET)		+= decnet/
 obj-$(CONFIG_ECONET)		+= econet/
 obj-$(CONFIG_VLAN_8021Q)	+= 8021q/
-obj-$(CONFIG_LLC)		+= llc/
 obj-$(CONFIG_IP_SCTP)		+= sctp/
 
 ifeq ($(CONFIG_NET),y)
diff -Nru a/net/bridge/br_input.c b/net/bridge/br_input.c
--- a/net/bridge/br_input.c	Tue Oct  1 00:08:16 2002
+++ b/net/bridge/br_input.c	Tue Oct  1 00:08:16 2002
@@ -149,8 +149,10 @@
 		goto handle_special_frame;
 
 	if (p->state == BR_STATE_FORWARDING) {
-		if (br_should_route_hook && br_should_route_hook(&skb))
+		if (br_should_route_hook && br_should_route_hook(&skb)) {
+			read_unlock(&br->lock);
 			return -1;
+		}
 
 		NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
 			br_handle_frame_finish);
diff -Nru a/net/core/dev.c b/net/core/dev.c
--- a/net/core/dev.c	Tue Oct  1 00:08:17 2002
+++ b/net/core/dev.c	Tue Oct  1 00:08:17 2002
@@ -1296,7 +1296,6 @@
 static int deliver_to_old_ones(struct packet_type *pt,
 			       struct sk_buff *skb, int last)
 {
-	static spinlock_t net_bh_lock = SPIN_LOCK_UNLOCKED;
 	int ret = NET_RX_DROP;
 
 	if (!last) {
@@ -1307,20 +1306,13 @@
 	if (skb_is_nonlinear(skb) && skb_linearize(skb, GFP_ATOMIC))
 		goto out_kfree;
 
-	/* The assumption (correct one) is that old protocols
-	   did not depened on BHs different of NET_BH and TIMER_BH.
+#if CONFIG_SMP
+	/* Old protocols did not depened on BHs different of NET_BH and
+	   TIMER_BH - they need to be fixed for the new assumptions.
 	 */
-
-	/* Emulate NET_BH with special spinlock */
-	spin_lock(&net_bh_lock);
-
-	/* Disable timers and wait for all timers completion */
-	tasklet_disable(bh_task_vec+TIMER_BH);
-
+	print_symbol("fix old protocol handler %s!\n", (unsigned long)pt->func);
+#endif
 	ret = pt->func(skb, skb->dev, pt);
-
-	tasklet_hi_enable(bh_task_vec+TIMER_BH);
-	spin_unlock(&net_bh_lock);
 out:
 	return ret;
 out_kfree:
diff -Nru a/net/ipv4/proc.c b/net/ipv4/proc.c
--- a/net/ipv4/proc.c	Tue Oct  1 00:08:14 2002
+++ b/net/ipv4/proc.c	Tue Oct  1 00:08:14 2002
@@ -128,7 +128,7 @@
 	len += sprintf (buffer + len,
 		"\nIcmp: InMsgs InErrors InDestUnreachs InTimeExcds InParmProbs InSrcQuenchs InRedirects InEchos InEchoReps InTimestamps InTimestampReps InAddrMasks InAddrMaskReps OutMsgs OutErrors OutDestUnreachs OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects OutEchos OutEchoReps OutTimestamps OutTimestampReps OutAddrMasks OutAddrMaskReps\n"
 		  "Icmp:");
-	for (i=0; i<offsetof(struct icmp_mib, __pad)/sizeof(unsigned long); i++)
+	for (i=0; i<offsetof(struct icmp_mib, dummy)/sizeof(unsigned long); i++)
 		len += sprintf(buffer+len, " %lu", fold_field((unsigned long*)icmp_statistics, sizeof(struct icmp_mib), i));
 
 	len += sprintf (buffer + len,
diff -Nru a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
--- a/net/ipv6/addrconf.c	Tue Oct  1 00:08:20 2002
+++ b/net/ipv6/addrconf.c	Tue Oct  1 00:08:20 2002
@@ -26,6 +26,8 @@
  *						packets.
  *	yoshfuji@USAGI			:       Fixed interval between DAD
  *						packets.
+ *	YOSHIFUJI Hideaki @USAGI	:	improved accuracy of
+ *						address validation timer.
  */
 
 #include <linux/config.h>
@@ -93,6 +95,7 @@
 static void addrconf_verify(unsigned long);
 
 static struct timer_list addr_chk_timer = { function: addrconf_verify };
+static spinlock_t addrconf_verify_lock = SPIN_LOCK_UNLOCKED;
 
 static int addrconf_ifdown(struct net_device *dev, int how);
 
@@ -1616,9 +1619,15 @@
 static void addrconf_verify(unsigned long foo)
 {
 	struct inet6_ifaddr *ifp;
-	unsigned long now = jiffies;
+	unsigned long now, next;
 	int i;
 
+	spin_lock_bh(&addrconf_verify_lock);
+	now = jiffies;
+	next = now + ADDR_CHECK_FREQUENCY;
+
+	del_timer(&addr_chk_timer);
+
 	for (i=0; i < IN6_ADDR_HSIZE; i++) {
 
 restart:
@@ -1629,21 +1638,27 @@
 			if (ifp->flags & IFA_F_PERMANENT)
 				continue;
 
+			spin_lock(&ifp->lock);
 			age = (now - ifp->tstamp) / HZ;
 
-			if (age > ifp->valid_lft) {
+			if (age >= ifp->valid_lft) {
+				spin_unlock(&ifp->lock);
 				in6_ifa_hold(ifp);
 				write_unlock(&addrconf_hash_lock);
 				ipv6_del_addr(ifp);
 				goto restart;
-			} else if (age > ifp->prefered_lft) {
+			} else if (age >= ifp->prefered_lft) {
+				/* jiffies - ifp->tsamp > age >= ifp->prefered_lft */
 				int deprecate = 0;
 
-				spin_lock(&ifp->lock);
 				if (!(ifp->flags&IFA_F_DEPRECATED)) {
 					deprecate = 1;
 					ifp->flags |= IFA_F_DEPRECATED;
 				}
+
+				if (time_before(ifp->tstamp + ifp->valid_lft * HZ, next))
+					next = ifp->tstamp + ifp->valid_lft * HZ;
+
 				spin_unlock(&ifp->lock);
 
 				if (deprecate) {
@@ -1654,12 +1669,19 @@
 					in6_ifa_put(ifp);
 					goto restart;
 				}
+			} else {
+				/* ifp->prefered_lft <= ifp->valid_lft */
+				if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next))
+					next = ifp->tstamp + ifp->prefered_lft * HZ;
+				spin_unlock(&ifp->lock);
 			}
 		}
 		write_unlock(&addrconf_hash_lock);
 	}
 
-	mod_timer(&addr_chk_timer, jiffies + ADDR_CHECK_FREQUENCY);
+	addr_chk_timer.expires = time_before(next, jiffies + HZ) ? jiffies + HZ : next;
+	add_timer(&addr_chk_timer);
+	spin_unlock_bh(&addrconf_verify_lock);
 }
 
 static int
@@ -2033,8 +2055,7 @@
 	proc_net_create("if_inet6", 0, iface_proc_info);
 #endif
 	
-	addr_chk_timer.expires = jiffies + ADDR_CHECK_FREQUENCY;
-	add_timer(&addr_chk_timer);
+	addrconf_verify(0);
 	rtnetlink_links[PF_INET6] = inet6_rtnetlink_table;
 #ifdef CONFIG_SYSCTL
 	addrconf_sysctl.sysctl_header =
diff -Nru a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
--- a/net/ipv6/ip6_fib.c	Tue Oct  1 00:08:16 2002
+++ b/net/ipv6/ip6_fib.c	Tue Oct  1 00:08:16 2002
@@ -13,6 +13,12 @@
  *      2 of the License, or (at your option) any later version.
  */
 
+/*
+ * 	Changes:
+ * 	Yuji SEKIYA @USAGI:	Support default route on router node;
+ * 				remove ip6_null_entry from the top of
+ * 				routing table.
+ */
 #include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/types.h>
@@ -248,9 +254,6 @@
 
 	fn = root;
 
-	if (plen == 0)
-		return fn;
-
 	do {
 		key = (struct rt6key *)((u8 *)fn->leaf + offset);
 
@@ -427,6 +430,17 @@
 
 	ins = &fn->leaf;
 
+	if (fn->fn_flags&RTN_TL_ROOT &&
+	    fn->leaf == &ip6_null_entry &&
+	    !(rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF | RTF_ALLONLINK)) ){
+		/*
+		 * The top fib of ip6 routing table includes ip6_null_entry.
+		 */
+		fn->leaf = rt;
+		rt->u.next = NULL;
+		goto out;
+	}
+
 	for (iter = fn->leaf; iter; iter=iter->u.next) {
 		/*
 		 *	Search for duplicates
@@ -462,6 +476,7 @@
 	 *	insert node
 	 */
 
+out:
 	rt->u.next = iter;
 	*ins = rt;
 	rt->rt6i_node = fn;
@@ -675,7 +690,7 @@
 
 	fn = fib6_lookup_1(root, args);
 
-	if (fn == NULL)
+	if (fn == NULL || fn->fn_flags & RTN_TL_ROOT)
 		fn = root;
 
 	return fn;
@@ -896,6 +911,9 @@
 	read_unlock(&fib6_walker_lock);
 
 	rt->u.next = NULL;
+
+	if (fn->leaf == NULL && fn->fn_flags&RTN_TL_ROOT)
+		fn->leaf = &ip6_null_entry;
 
 	/* If it was last route, expunge its radix tree node */
 	if (fn->leaf == NULL) {
diff -Nru a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
--- a/net/ipv6/ndisc.c	Tue Oct  1 00:08:17 2002
+++ b/net/ipv6/ndisc.c	Tue Oct  1 00:08:17 2002
@@ -22,6 +22,7 @@
  *	Alexey Kuznetsov		:	state machine reworked
  *						and moved to net/core.
  *	Pekka Savola			:	RFC2461 validation
+ *	YOSHIFUJI Hideaki @USAGI	:	Verify ND options properly
  */
 
 /* Set to 3 to get tracing... */
diff -Nru a/net/lapb/lapb_iface.c b/net/lapb/lapb_iface.c
--- a/net/lapb/lapb_iface.c	Tue Oct  1 00:08:17 2002
+++ b/net/lapb/lapb_iface.c	Tue Oct  1 00:08:17 2002
@@ -39,87 +39,93 @@
 #include <linux/init.h>
 #include <net/lapb.h>
 
-static lapb_cb *volatile lapb_list /* = NULL initially */;
+static struct list_head lapb_list = LIST_HEAD_INIT(lapb_list);
+static rwlock_t lapb_list_lock = RW_LOCK_UNLOCKED;
 
 /*
  *	Free an allocated lapb control block. This is done to centralise
  *	the MOD count code.
  */
-static void lapb_free_cb(lapb_cb *lapb)
+static void lapb_free_cb(struct lapb_cb *lapb)
 {
 	kfree(lapb);
-
 	MOD_DEC_USE_COUNT;
 }
 
+static __inline__ void lapb_hold(struct lapb_cb *lapb)
+{
+	atomic_inc(&lapb->refcnt);
+}
+
+static __inline__ void lapb_put(struct lapb_cb *lapb)
+{
+	if (atomic_dec_and_test(&lapb->refcnt))
+		lapb_free_cb(lapb);
+}
+
 /*
  *	Socket removal during an interrupt is now safe.
  */
-static void lapb_remove_cb(lapb_cb *lapb)
+static void __lapb_remove_cb(struct lapb_cb *lapb)
 {
-	lapb_cb *s;
-	unsigned long flags;
-
-	save_flags(flags); cli();
-
-	if ((s = lapb_list) == lapb) {
-		lapb_list = s->next;
-		restore_flags(flags);
-		return;
+	if (lapb->node.next) {
+		list_del(&lapb->node);
+		lapb_put(lapb);
 	}
-
-	while (s != NULL && s->next != NULL) {
-		if (s->next == lapb) {
-			s->next = lapb->next;
-			restore_flags(flags);
-			return;
-		}
-
-		s = s->next;
-	}
-
-	restore_flags(flags);
 }
 
 /*
  *	Add a socket to the bound sockets list.
  */
-static void lapb_insert_cb(lapb_cb *lapb)
+static void __lapb_insert_cb(struct lapb_cb *lapb)
 {
-	unsigned long flags;
-
-	save_flags(flags); cli();
-
-	lapb->next = lapb_list;
-	lapb_list  = lapb;
-
-	restore_flags(flags);
+	list_add(&lapb->node, &lapb_list);
+	lapb_hold(lapb);
 }
 
 /*
  *	Convert the integer token used by the device driver into a pointer
  *	to a LAPB control structure.
  */
-static lapb_cb *lapb_tokentostruct(void *token)
+static struct lapb_cb *__lapb_tokentostruct(void *token)
 {
-	lapb_cb *lapb;
+	struct list_head *entry;
+	struct lapb_cb *lapb, *use = NULL;
 
-	for (lapb = lapb_list; lapb != NULL; lapb = lapb->next)
-		if (lapb->token == token)
-			return lapb;
+	list_for_each(entry, &lapb_list) {
+		lapb = list_entry(entry, struct lapb_cb, node);
+		if (lapb->token == token) {
+			use = lapb;
+			break;
+		}
+	}
 
-	return NULL;
+	if (use)
+		lapb_hold(use);
+
+	return use;
 }
 
+static struct lapb_cb *lapb_tokentostruct(void *token)
+{
+	struct lapb_cb *rc;
+
+	read_lock_bh(&lapb_list_lock);
+	rc = __lapb_tokentostruct(token);
+	read_unlock_bh(&lapb_list_lock);
+
+	return rc;
+}
 /*
  *	Create an empty LAPB control block.
  */
-static lapb_cb *lapb_create_cb(void)
+static struct lapb_cb *lapb_create_cb(void)
 {
-	lapb_cb *lapb;
+	struct lapb_cb *lapb = kmalloc(sizeof(*lapb), GFP_ATOMIC);
 
-	if ((lapb = kmalloc(sizeof(*lapb), GFP_ATOMIC)) == NULL)
-		return NULL;
+
+	if (!lapb)
+		goto out;
 
 	MOD_INC_USE_COUNT;
 
@@ -137,55 +143,73 @@
 	lapb->mode    = LAPB_DEFAULT_MODE;
 	lapb->window  = LAPB_DEFAULT_WINDOW;
 	lapb->state   = LAPB_STATE_0;
-
+	atomic_set(&lapb->refcnt, 1);
+out:
 	return lapb;
 }
 
 int lapb_register(void *token, struct lapb_register_struct *callbacks)
 {
-	lapb_cb *lapb;
+	struct lapb_cb *lapb;
+	int rc = LAPB_BADTOKEN;
 
-	if (lapb_tokentostruct(token) != NULL)
-		return LAPB_BADTOKEN;
+	write_lock_bh(&lapb_list_lock);
 
-	if ((lapb = lapb_create_cb()) == NULL)
-		return LAPB_NOMEM;
+	lapb = __lapb_tokentostruct(token);
+	if (lapb) {
+		lapb_put(lapb);
+		goto out;
+	}
+
+	lapb = lapb_create_cb();
+	rc = LAPB_NOMEM;
+	if (!lapb)
+		goto out;
 
 	lapb->token     = token;
 	lapb->callbacks = *callbacks;
 
-	lapb_insert_cb(lapb);
+	__lapb_insert_cb(lapb);
 
 	lapb_start_t1timer(lapb);
 
-	return LAPB_OK;
+	rc = LAPB_OK;
+out:
+	write_unlock_bh(&lapb_list_lock);
+	return rc;
 }
 
 int lapb_unregister(void *token)
 {
-	lapb_cb *lapb;
+	struct lapb_cb *lapb;
+	int rc = LAPB_BADTOKEN;
 
-	if ((lapb = lapb_tokentostruct(token)) == NULL)
-		return LAPB_BADTOKEN;
+	write_unlock_bh(&lapb_list_lock);
+	lapb = __lapb_tokentostruct(token);
+	if (!lapb)
+		goto out;
 
 	lapb_stop_t1timer(lapb);
 	lapb_stop_t2timer(lapb);
 
 	lapb_clear_queues(lapb);
 
-	lapb_remove_cb(lapb);
-
-	lapb_free_cb(lapb);
+	__lapb_remove_cb(lapb);
 
-	return LAPB_OK;
+	lapb_put(lapb);
+	rc = LAPB_OK;
+out:
+	write_unlock_bh(&lapb_list_lock);
+	return rc;
 }
 
 int lapb_getparms(void *token, struct lapb_parms_struct *parms)
 {
-	lapb_cb *lapb;
+	int rc = LAPB_BADTOKEN;
+	struct lapb_cb *lapb = lapb_tokentostruct(token);
 
-	if ((lapb = lapb_tokentostruct(token)) == NULL)
-		return LAPB_BADTOKEN;
+	if (!lapb)
+		goto out;
 
 	parms->t1      = lapb->t1 / HZ;
 	parms->t2      = lapb->t2 / HZ;
@@ -205,33 +229,29 @@
 	else
 		parms->t2timer = (lapb->t2timer.expires - jiffies) / HZ;
 
-	return LAPB_OK;
+	lapb_put(lapb);
+	rc = LAPB_OK;
+out:
+	return rc;
 }
 
 int lapb_setparms(void *token, struct lapb_parms_struct *parms)
 {
-	lapb_cb *lapb;
-
-	if ((lapb = lapb_tokentostruct(token)) == NULL)
-		return LAPB_BADTOKEN;
+	int rc = LAPB_BADTOKEN;
+	struct lapb_cb *lapb = lapb_tokentostruct(token);
 
-	if (parms->t1 < 1)
-		return LAPB_INVALUE;
+	if (!lapb)
+		goto out;
 
-	if (parms->t2 < 1)
-		return LAPB_INVALUE;
-
-	if (parms->n2 < 1)
-		return LAPB_INVALUE;
+	rc = LAPB_INVALUE;
+	if (parms->t1 < 1 || parms->t2 < 1 || parms->n2 < 1)
+		goto out_put;
 
 	if (lapb->state == LAPB_STATE_0) {
-		if (parms->mode & LAPB_EXTENDED) {
-			if (parms->window < 1 || parms->window > 127)
-				return LAPB_INVALUE;
-		} else {
-			if (parms->window < 1 || parms->window > 7)
-				return LAPB_INVALUE;
-		}
+		if (((parms->mode & LAPB_EXTENDED) &&
+		     (parms->window < 1 || parms->window > 127)) ||
+		    (parms->window < 1 || parms->window > 7))
+			goto out_put;
 
 		lapb->mode    = parms->mode;
 		lapb->window  = parms->window;
@@ -241,45 +261,55 @@
 	lapb->t2    = parms->t2 * HZ;
 	lapb->n2    = parms->n2;
 
-	return LAPB_OK;
+	rc = LAPB_OK;
+out_put:
+	lapb_put(lapb);
+out:
+	return rc;
 }
 
 int lapb_connect_request(void *token)
 {
-	lapb_cb *lapb;
+	struct lapb_cb *lapb = lapb_tokentostruct(token);
+	int rc = LAPB_BADTOKEN;
 
-	if ((lapb = lapb_tokentostruct(token)) == NULL)
-		return LAPB_BADTOKEN;
+	if (!lapb)
+		goto out;
 
-	switch (lapb->state) {
-		case LAPB_STATE_1:
-			return LAPB_OK;
-		case LAPB_STATE_3:
-		case LAPB_STATE_4:
-			return LAPB_CONNECTED;
-	}
+	rc = LAPB_OK;
+	if (lapb->state == LAPB_STATE_1)
+		goto out_put;
+
+	rc = LAPB_CONNECTED;
+	if (lapb->state == LAPB_STATE_3 || lapb->state == LAPB_STATE_4)
+		goto out_put;
 
 	lapb_establish_data_link(lapb);
 
 #if LAPB_DEBUG > 0
 	printk(KERN_DEBUG "lapb: (%p) S0 -> S1\n", lapb->token);
 #endif
-
 	lapb->state = LAPB_STATE_1;
 
-	return LAPB_OK;
+	rc = LAPB_OK;
+out_put:
+	lapb_put(lapb);
+out:
+	return rc;
 }
 
 int lapb_disconnect_request(void *token)
 {
-	lapb_cb *lapb;
+	struct lapb_cb *lapb = lapb_tokentostruct(token);
+	int rc = LAPB_BADTOKEN;
 
-	if ((lapb = lapb_tokentostruct(token)) == NULL)
-		return LAPB_BADTOKEN;
+	if (!lapb)
+		goto out;
 
 	switch (lapb->state) {
 		case LAPB_STATE_0:
-			return LAPB_NOTCONNECTED;
+			rc = LAPB_NOTCONNECTED;
+			goto out_put;
 
 		case LAPB_STATE_1:
 #if LAPB_DEBUG > 1
@@ -291,10 +321,12 @@
 			lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND);
 			lapb->state = LAPB_STATE_0;
 			lapb_start_t1timer(lapb);
-			return LAPB_NOTCONNECTED;
+			rc = LAPB_NOTCONNECTED;
+			goto out_put;
 
 		case LAPB_STATE_2:
-			return LAPB_OK;
+			rc = LAPB_OK;
+			goto out_put;
 	}
 
 	lapb_clear_queues(lapb);
@@ -311,77 +343,87 @@
 	printk(KERN_DEBUG "lapb: (%p) S3 -> S2\n", lapb->token);
 #endif
 
-	return LAPB_OK;
+	rc = LAPB_OK;
+out_put:
+	lapb_put(lapb);
+out:
+	return rc;
 }
 
 int lapb_data_request(void *token, struct sk_buff *skb)
 {
-	lapb_cb *lapb;
+	struct lapb_cb *lapb = lapb_tokentostruct(token);
+	int rc = LAPB_BADTOKEN;
 
-	if ((lapb = lapb_tokentostruct(token)) == NULL)
-		return LAPB_BADTOKEN;
+	if (!lapb)
+		goto out;
 
+	rc = LAPB_NOTCONNECTED;
 	if (lapb->state != LAPB_STATE_3 && lapb->state != LAPB_STATE_4)
-		return LAPB_NOTCONNECTED;
+		goto out_put;
 
 	skb_queue_tail(&lapb->write_queue, skb);
-
 	lapb_kick(lapb);
-
-	return LAPB_OK;
+	rc = LAPB_OK;
+out_put:
+	lapb_put(lapb);
+out:
+	return rc;
 }
 
 int lapb_data_received(void *token, struct sk_buff *skb)
 {
-	lapb_cb *lapb;
-
-	if ((lapb = lapb_tokentostruct(token)) == NULL)
-		return LAPB_BADTOKEN;
+	struct lapb_cb *lapb = lapb_tokentostruct(token);
+	int rc = LAPB_BADTOKEN;
 
-	lapb_data_input(lapb, skb);
+	if (lapb) {
+		lapb_data_input(lapb, skb);
+		lapb_put(lapb);
+		rc = LAPB_OK;
+	}
 
-	return LAPB_OK;
+	return rc;
 }
 
-void lapb_connect_confirmation(lapb_cb *lapb, int reason)
+void lapb_connect_confirmation(struct lapb_cb *lapb, int reason)
 {
-	if (lapb->callbacks.connect_confirmation != NULL)
-		(lapb->callbacks.connect_confirmation)(lapb->token, reason);
+	if (lapb->callbacks.connect_confirmation)
+		lapb->callbacks.connect_confirmation(lapb->token, reason);
 }
 
-void lapb_connect_indication(lapb_cb *lapb, int reason)
+void lapb_connect_indication(struct lapb_cb *lapb, int reason)
 {
-	if (lapb->callbacks.connect_indication != NULL)
-		(lapb->callbacks.connect_indication)(lapb->token, reason);
+	if (lapb->callbacks.connect_indication)
+		lapb->callbacks.connect_indication(lapb->token, reason);
 }
 
-void lapb_disconnect_confirmation(lapb_cb *lapb, int reason)
+void lapb_disconnect_confirmation(struct lapb_cb *lapb, int reason)
 {
-	if (lapb->callbacks.disconnect_confirmation != NULL)
-		(lapb->callbacks.disconnect_confirmation)(lapb->token, reason);
+	if (lapb->callbacks.disconnect_confirmation)
+		lapb->callbacks.disconnect_confirmation(lapb->token, reason);
 }
 
-void lapb_disconnect_indication(lapb_cb *lapb, int reason)
+void lapb_disconnect_indication(struct lapb_cb *lapb, int reason)
 {
-	if (lapb->callbacks.disconnect_indication != NULL)
-		(lapb->callbacks.disconnect_indication)(lapb->token, reason);
+	if (lapb->callbacks.disconnect_indication)
+		lapb->callbacks.disconnect_indication(lapb->token, reason);
 }
 
-int lapb_data_indication(lapb_cb *lapb, struct sk_buff *skb)
+int lapb_data_indication(struct lapb_cb *lapb, struct sk_buff *skb)
 {
-	if (lapb->callbacks.data_indication != NULL) {
-		return (lapb->callbacks.data_indication)(lapb->token, skb);
-	}
+	if (lapb->callbacks.data_indication)
+		return lapb->callbacks.data_indication(lapb->token, skb);
+
 	kfree_skb(skb);
 	return NET_RX_CN_HIGH; /* For now; must be != NET_RX_DROP */ 
 }
 
-int lapb_data_transmit(lapb_cb *lapb, struct sk_buff *skb)
+int lapb_data_transmit(struct lapb_cb *lapb, struct sk_buff *skb)
 {
 	int used = 0;
 
-	if (lapb->callbacks.data_transmit != NULL) {
-		(lapb->callbacks.data_transmit)(lapb->token, skb);
+	if (lapb->callbacks.data_transmit) {
+		lapb->callbacks.data_transmit(lapb->token, skb);
 		used = 1;
 	}
 
diff -Nru a/net/lapb/lapb_in.c b/net/lapb/lapb_in.c
--- a/net/lapb/lapb_in.c	Tue Oct  1 00:08:17 2002
+++ b/net/lapb/lapb_in.c	Tue Oct  1 00:08:17 2002
@@ -40,26 +40,33 @@
  *	State machine for state 0, Disconnected State.
  *	The handling of the timer(s) is in file lapb_timer.c.
  */
-static void lapb_state0_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame)
+static void lapb_state0_machine(struct lapb_cb *lapb, struct sk_buff *skb,
+				struct lapb_frame *frame)
 {
 	switch (frame->type) {
 		case LAPB_SABM:
 #if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S0 RX SABM(%d)\n", lapb->token, frame->pf);
+			printk(KERN_DEBUG "lapb: (%p) S0 RX SABM(%d)\n",
+			       lapb->token, frame->pf);
 #endif
 			if (lapb->mode & LAPB_EXTENDED) {
 #if LAPB_DEBUG > 1
-				printk(KERN_DEBUG "lapb: (%p) S0 TX DM(%d)\n", lapb->token, frame->pf);
+				printk(KERN_DEBUG "lapb: (%p) S0 TX DM(%d)\n",
+				       lapb->token, frame->pf);
 #endif
-				lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE);
+				lapb_send_control(lapb, LAPB_DM, frame->pf,
+						  LAPB_RESPONSE);
 			} else {
 #if LAPB_DEBUG > 1
-				printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n", lapb->token, frame->pf);
+				printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n",
+				       lapb->token, frame->pf);
 #endif
 #if LAPB_DEBUG > 0
-				printk(KERN_DEBUG "lapb: (%p) S0 -> S3\n", lapb->token);
+				printk(KERN_DEBUG "lapb: (%p) S0 -> S3\n",
+				       lapb->token);
 #endif
-				lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
+				lapb_send_control(lapb, LAPB_UA, frame->pf,
+						  LAPB_RESPONSE);
 				lapb_stop_t1timer(lapb);
 				lapb_stop_t2timer(lapb);
 				lapb->state     = LAPB_STATE_3;
@@ -74,16 +81,20 @@
 
 		case LAPB_SABME:
 #if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S0 RX SABME(%d)\n", lapb->token, frame->pf);
+			printk(KERN_DEBUG "lapb: (%p) S0 RX SABME(%d)\n",
+			       lapb->token, frame->pf);
 #endif
 			if (lapb->mode & LAPB_EXTENDED) {
 #if LAPB_DEBUG > 1
-				printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n", lapb->token, frame->pf);
+				printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n",
+				       lapb->token, frame->pf);
 #endif
 #if LAPB_DEBUG > 0
-				printk(KERN_DEBUG "lapb: (%p) S0 -> S3\n", lapb->token);
+				printk(KERN_DEBUG "lapb: (%p) S0 -> S3\n",
+				       lapb->token);
 #endif
-				lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
+				lapb_send_control(lapb, LAPB_UA, frame->pf,
+						  LAPB_RESPONSE);
 				lapb_stop_t1timer(lapb);
 				lapb_stop_t2timer(lapb);
 				lapb->state     = LAPB_STATE_3;
@@ -95,18 +106,23 @@
 				lapb_connect_indication(lapb, LAPB_OK);
 			} else {
 #if LAPB_DEBUG > 1
-				printk(KERN_DEBUG "lapb: (%p) S0 TX DM(%d)\n", lapb->token, frame->pf);
+				printk(KERN_DEBUG "lapb: (%p) S0 TX DM(%d)\n",
+				       lapb->token, frame->pf);
 #endif
-				lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE);
+				lapb_send_control(lapb, LAPB_DM, frame->pf,
+						  LAPB_RESPONSE);
 			}
 			break;
 
 		case LAPB_DISC:
 #if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S0 RX DISC(%d)\n", lapb->token, frame->pf);
-			printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n", lapb->token, frame->pf);
+			printk(KERN_DEBUG "lapb: (%p) S0 RX DISC(%d)\n",
+			       lapb->token, frame->pf);
+			printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n",
+			       lapb->token, frame->pf);
 #endif
-			lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
+			lapb_send_control(lapb, LAPB_UA, frame->pf,
+					  LAPB_RESPONSE);
 			break;
 
 		default:
@@ -120,58 +136,74 @@
  *	State machine for state 1, Awaiting Connection State.
  *	The handling of the timer(s) is in file lapb_timer.c.
  */
-static void lapb_state1_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame)
+static void lapb_state1_machine(struct lapb_cb *lapb, struct sk_buff *skb,
+				struct lapb_frame *frame)
 {
 	switch (frame->type) {
 		case LAPB_SABM:
 #if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S1 RX SABM(%d)\n", lapb->token, frame->pf);
+			printk(KERN_DEBUG "lapb: (%p) S1 RX SABM(%d)\n",
+			       lapb->token, frame->pf);
 #endif
 			if (lapb->mode & LAPB_EXTENDED) {
 #if LAPB_DEBUG > 1
-				printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n", lapb->token, frame->pf);
+				printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n",
+				       lapb->token, frame->pf);
 #endif
-				lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE);
+				lapb_send_control(lapb, LAPB_DM, frame->pf,
+						  LAPB_RESPONSE);
 			} else {
 #if LAPB_DEBUG > 1
-				printk(KERN_DEBUG "lapb: (%p) S1 TX UA(%d)\n", lapb->token, frame->pf);
+				printk(KERN_DEBUG "lapb: (%p) S1 TX UA(%d)\n",
+				       lapb->token, frame->pf);
 #endif
-				lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
+				lapb_send_control(lapb, LAPB_UA, frame->pf,
+						  LAPB_RESPONSE);
 			}
 			break;
 
 		case LAPB_SABME:
 #if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S1 RX SABME(%d)\n", lapb->token, frame->pf);
+			printk(KERN_DEBUG "lapb: (%p) S1 RX SABME(%d)\n",
+			       lapb->token, frame->pf);
 #endif
 			if (lapb->mode & LAPB_EXTENDED) {
 #if LAPB_DEBUG > 1
-				printk(KERN_DEBUG "lapb: (%p) S1 TX UA(%d)\n", lapb->token, frame->pf);
+				printk(KERN_DEBUG "lapb: (%p) S1 TX UA(%d)\n",
+				       lapb->token, frame->pf);
 #endif
-				lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
+				lapb_send_control(lapb, LAPB_UA, frame->pf,
+						  LAPB_RESPONSE);
 			} else {
 #if LAPB_DEBUG > 1
-				printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n", lapb->token, frame->pf);
+				printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n",
+				       lapb->token, frame->pf);
 #endif
-				lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE);
+				lapb_send_control(lapb, LAPB_DM, frame->pf,
+						  LAPB_RESPONSE);
 			}
 			break;
 
 		case LAPB_DISC:
 #if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S1 RX DISC(%d)\n", lapb->token, frame->pf);
-			printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n", lapb->token, frame->pf);
+			printk(KERN_DEBUG "lapb: (%p) S1 RX DISC(%d)\n",
+			       lapb->token, frame->pf);
+			printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n",
+			       lapb->token, frame->pf);
 #endif
-			lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE);
+			lapb_send_control(lapb, LAPB_DM, frame->pf,
+					  LAPB_RESPONSE);
 			break;
 
 		case LAPB_UA:
 #if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S1 RX UA(%d)\n", lapb->token, frame->pf);
+			printk(KERN_DEBUG "lapb: (%p) S1 RX UA(%d)\n",
+			       lapb->token, frame->pf);
 #endif
 			if (frame->pf) {
 #if LAPB_DEBUG > 0
-				printk(KERN_DEBUG "lapb: (%p) S1 -> S3\n", lapb->token);
+				printk(KERN_DEBUG "lapb: (%p) S1 -> S3\n",
+				       lapb->token);
 #endif
 				lapb_stop_t1timer(lapb);
 				lapb_stop_t2timer(lapb);
@@ -187,11 +219,13 @@
 
 		case LAPB_DM:
 #if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S1 RX DM(%d)\n", lapb->token, frame->pf);
+			printk(KERN_DEBUG "lapb: (%p) S1 RX DM(%d)\n",
+			       lapb->token, frame->pf);
 #endif
 			if (frame->pf) {
 #if LAPB_DEBUG > 0
-				printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", lapb->token);
+				printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n",
+				       lapb->token);
 #endif
 				lapb_clear_queues(lapb);
 				lapb->state = LAPB_STATE_0;
@@ -200,9 +234,6 @@
 				lapb_disconnect_indication(lapb, LAPB_REFUSED);
 			}
 			break;
-
-		default:
-			break;
 	}
 
 	kfree_skb(skb);
@@ -212,33 +243,42 @@
  *	State machine for state 2, Awaiting Release State.
  *	The handling of the timer(s) is in file lapb_timer.c
  */
-static void lapb_state2_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame)
+static void lapb_state2_machine(struct lapb_cb *lapb, struct sk_buff *skb,
+				struct lapb_frame *frame)
 {
 	switch (frame->type) {
 		case LAPB_SABM:
 		case LAPB_SABME:
 #if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S2 RX {SABM,SABME}(%d)\n", lapb->token, frame->pf);
-			printk(KERN_DEBUG "lapb: (%p) S2 TX DM(%d)\n", lapb->token, frame->pf);
+			printk(KERN_DEBUG "lapb: (%p) S2 RX {SABM,SABME}(%d)\n",
+			       lapb->token, frame->pf);
+			printk(KERN_DEBUG "lapb: (%p) S2 TX DM(%d)\n",
+			       lapb->token, frame->pf);
 #endif
-			lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE);
+			lapb_send_control(lapb, LAPB_DM, frame->pf,
+					  LAPB_RESPONSE);
 			break;
 
 		case LAPB_DISC:
 #if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S2 RX DISC(%d)\n", lapb->token, frame->pf);
-			printk(KERN_DEBUG "lapb: (%p) S2 TX UA(%d)\n", lapb->token, frame->pf);
+			printk(KERN_DEBUG "lapb: (%p) S2 RX DISC(%d)\n",
+			       lapb->token, frame->pf);
+			printk(KERN_DEBUG "lapb: (%p) S2 TX UA(%d)\n",
+			       lapb->token, frame->pf);
 #endif
-			lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
+			lapb_send_control(lapb, LAPB_UA, frame->pf,
+					  LAPB_RESPONSE);
 			break;
 
 		case LAPB_UA:
 #if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S2 RX UA(%d)\n", lapb->token, frame->pf);
+			printk(KERN_DEBUG "lapb: (%p) S2 RX UA(%d)\n",
+			       lapb->token, frame->pf);
 #endif
 			if (frame->pf) {
 #if LAPB_DEBUG > 0
-				printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", lapb->token);
+				printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n",
+				       lapb->token);
 #endif
 				lapb->state = LAPB_STATE_0;
 				lapb_start_t1timer(lapb);
@@ -249,16 +289,19 @@
 
 		case LAPB_DM:
 #if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S2 RX DM(%d)\n", lapb->token, frame->pf);
+			printk(KERN_DEBUG "lapb: (%p) S2 RX DM(%d)\n",
+			       lapb->token, frame->pf);
 #endif
 			if (frame->pf) {
 #if LAPB_DEBUG > 0
-				printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", lapb->token);
+				printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n",
+				       lapb->token);
 #endif
 				lapb->state = LAPB_STATE_0;
 				lapb_start_t1timer(lapb);
 				lapb_stop_t2timer(lapb);
-				lapb_disconnect_confirmation(lapb, LAPB_NOTCONNECTED);
+				lapb_disconnect_confirmation(lapb,
+							     LAPB_NOTCONNECTED);
 			}
 			break;
 
@@ -267,13 +310,14 @@
 		case LAPB_RNR:
 		case LAPB_RR:
 #if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S2 RX {I,REJ,RNR,RR}(%d)\n", lapb->token, frame->pf);
-			printk(KERN_DEBUG "lapb: (%p) S2 RX DM(%d)\n", lapb->token, frame->pf);
-#endif
-			if (frame->pf) lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE);
-			break;
-				
-		default:
+			printk(KERN_DEBUG "lapb: (%p) S2 RX {I,REJ,RNR,RR}"
+			       "(%d)\n", lapb->token, frame->pf);
+			printk(KERN_DEBUG "lapb: (%p) S2 RX DM(%d)\n",
+			       lapb->token, frame->pf);
+#endif
+			if (frame->pf)
+				lapb_send_control(lapb, LAPB_DM, frame->pf,
+						  LAPB_RESPONSE);
 			break;
 	}
 
@@ -284,28 +328,33 @@
  *	State machine for state 3, Connected State.
  *	The handling of the timer(s) is in file lapb_timer.c
  */
-static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame)
+static void lapb_state3_machine(struct lapb_cb *lapb, struct sk_buff *skb,
+				struct lapb_frame *frame)
 {
 	int queued = 0;
-	int modulus;
-	
-	modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : LAPB_SMODULUS;
+	int modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS :
+						     LAPB_SMODULUS;
 
 	switch (frame->type) {
 		case LAPB_SABM:
 #if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S3 RX SABM(%d)\n", lapb->token, frame->pf);
+			printk(KERN_DEBUG "lapb: (%p) S3 RX SABM(%d)\n",
+			       lapb->token, frame->pf);
 #endif
 			if (lapb->mode & LAPB_EXTENDED) {
 #if LAPB_DEBUG > 1
-				printk(KERN_DEBUG "lapb: (%p) S3 TX DM(%d)\n", lapb->token, frame->pf);
+				printk(KERN_DEBUG "lapb: (%p) S3 TX DM(%d)\n",
+				       lapb->token, frame->pf);
 #endif
-				lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE);
+				lapb_send_control(lapb, LAPB_DM, frame->pf,
+						  LAPB_RESPONSE);
 			} else {
 #if LAPB_DEBUG > 1
-				printk(KERN_DEBUG "lapb: (%p) S3 TX UA(%d)\n", lapb->token, frame->pf);
+				printk(KERN_DEBUG "lapb: (%p) S3 TX UA(%d)\n",
+				       lapb->token, frame->pf);
 #endif
-				lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
+				lapb_send_control(lapb, LAPB_UA, frame->pf,
+						  LAPB_RESPONSE);
 				lapb_stop_t1timer(lapb);
 				lapb_stop_t2timer(lapb);
 				lapb->condition = 0x00;
@@ -319,13 +368,16 @@
 
 		case LAPB_SABME:
 #if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S3 RX SABME(%d)\n", lapb->token, frame->pf);
+			printk(KERN_DEBUG "lapb: (%p) S3 RX SABME(%d)\n",
+			       lapb->token, frame->pf);
 #endif
 			if (lapb->mode & LAPB_EXTENDED) {
 #if LAPB_DEBUG > 1
-				printk(KERN_DEBUG "lapb: (%p) S3 TX UA(%d)\n", lapb->token, frame->pf);
+				printk(KERN_DEBUG "lapb: (%p) S3 TX UA(%d)\n",
+				       lapb->token, frame->pf);
 #endif
-				lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
+				lapb_send_control(lapb, LAPB_UA, frame->pf,
+						  LAPB_RESPONSE);
 				lapb_stop_t1timer(lapb);
 				lapb_stop_t2timer(lapb);
 				lapb->condition = 0x00;
@@ -336,21 +388,26 @@
 				lapb_requeue_frames(lapb);
 			} else {
 #if LAPB_DEBUG > 1
-				printk(KERN_DEBUG "lapb: (%p) S3 TX DM(%d)\n", lapb->token, frame->pf);
+				printk(KERN_DEBUG "lapb: (%p) S3 TX DM(%d)\n",
+				       lapb->token, frame->pf);
 #endif
-				lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE);
+				lapb_send_control(lapb, LAPB_DM, frame->pf,
+						  LAPB_RESPONSE);
 			}
 			break;
 
 		case LAPB_DISC:
 #if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S3 RX DISC(%d)\n", lapb->token, frame->pf);
+			printk(KERN_DEBUG "lapb: (%p) S3 RX DISC(%d)\n",
+			       lapb->token, frame->pf);
 #endif
 #if LAPB_DEBUG > 0
-			printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n", lapb->token);
+			printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n",
+			       lapb->token);
 #endif
 			lapb_clear_queues(lapb);
-			lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
+			lapb_send_control(lapb, LAPB_UA, frame->pf,
+					  LAPB_RESPONSE);
 			lapb_start_t1timer(lapb);
 			lapb_stop_t2timer(lapb);
 			lapb->state = LAPB_STATE_0;
@@ -359,10 +416,12 @@
 
 		case LAPB_DM:
 #if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S3 RX DM(%d)\n", lapb->token, frame->pf);
+			printk(KERN_DEBUG "lapb: (%p) S3 RX DM(%d)\n",
+			       lapb->token, frame->pf);
 #endif
 #if LAPB_DEBUG > 0
-			printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n", lapb->token);
+			printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n",
+			       lapb->token);
 #endif
 			lapb_clear_queues(lapb);
 			lapb->state = LAPB_STATE_0;
@@ -373,7 +432,8 @@
 
 		case LAPB_RNR:
 #if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S3 RX RNR(%d) R%d\n", lapb->token, frame->pf, frame->nr);
+			printk(KERN_DEBUG "lapb: (%p) S3 RX RNR(%d) R%d\n",
+			       lapb->token, frame->pf, frame->nr);
 #endif
 			lapb->condition |= LAPB_PEER_RX_BUSY_CONDITION;
 			lapb_check_need_response(lapb, frame->cr, frame->pf);
@@ -384,7 +444,8 @@
 				lapb->frmr_type = LAPB_FRMR_Z;
 				lapb_transmit_frmr(lapb);
 #if LAPB_DEBUG > 0
-				printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token);
+				printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n",
+				       lapb->token);
 #endif
 				lapb_start_t1timer(lapb);
 				lapb_stop_t2timer(lapb);
@@ -395,7 +456,8 @@
 
 		case LAPB_RR:
 #if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S3 RX RR(%d) R%d\n", lapb->token, frame->pf, frame->nr);
+			printk(KERN_DEBUG "lapb: (%p) S3 RX RR(%d) R%d\n",
+			       lapb->token, frame->pf, frame->nr);
 #endif
 			lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION;
 			lapb_check_need_response(lapb, frame->cr, frame->pf);
@@ -406,7 +468,8 @@
 				lapb->frmr_type = LAPB_FRMR_Z;
 				lapb_transmit_frmr(lapb);
 #if LAPB_DEBUG > 0
-				printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token);
+				printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n",
+				       lapb->token);
 #endif
 				lapb_start_t1timer(lapb);
 				lapb_stop_t2timer(lapb);
@@ -417,7 +480,8 @@
 
 		case LAPB_REJ:
 #if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S3 RX REJ(%d) R%d\n", lapb->token, frame->pf, frame->nr);
+			printk(KERN_DEBUG "lapb: (%p) S3 RX REJ(%d) R%d\n",
+			       lapb->token, frame->pf, frame->nr);
 #endif
 			lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION;
 			lapb_check_need_response(lapb, frame->cr, frame->pf);
@@ -431,7 +495,8 @@
 				lapb->frmr_type = LAPB_FRMR_Z;
 				lapb_transmit_frmr(lapb);
 #if LAPB_DEBUG > 0
-				printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token);
+				printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n",
+				       lapb->token);
 #endif
 				lapb_start_t1timer(lapb);
 				lapb_stop_t2timer(lapb);
@@ -442,14 +507,16 @@
 
 		case LAPB_I:
 #if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S3 RX I(%d) S%d R%d\n", lapb->token, frame->pf, frame->ns, frame->nr);
+			printk(KERN_DEBUG "lapb: (%p) S3 RX I(%d) S%d R%d\n",
+			       lapb->token, frame->pf, frame->ns, frame->nr);
 #endif
 			if (!lapb_validate_nr(lapb, frame->nr)) {
 				lapb->frmr_data = *frame;
 				lapb->frmr_type = LAPB_FRMR_Z;
 				lapb_transmit_frmr(lapb);
 #if LAPB_DEBUG > 0
-				printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token);
+				printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n",
+				       lapb->token);
 #endif
 				lapb_start_t1timer(lapb);
 				lapb_stop_t2timer(lapb);
@@ -457,11 +524,11 @@
 				lapb->n2count = 0;
 				break;
 			}
-			if (lapb->condition & LAPB_PEER_RX_BUSY_CONDITION) {
+			if (lapb->condition & LAPB_PEER_RX_BUSY_CONDITION)
 				lapb_frames_acked(lapb, frame->nr);
-			} else {
+			else
 				lapb_check_iframes_acked(lapb, frame->nr);
-			}
+
 			if (frame->ns == lapb->vr) {
 				int cn;
 				cn = lapb_data_indication(lapb, skb);
@@ -473,16 +540,18 @@
 				 * to re-transmit the frame later like
 				 * a frame lost on the wire.
 				 */
-				if(cn == NET_RX_DROP){
-					printk(KERN_DEBUG "LAPB: rx congestion\n");
+				if (cn == NET_RX_DROP) {
+					printk(KERN_DEBUG
+					       "LAPB: rx congestion\n");
 					break;
 				}
 				lapb->vr = (lapb->vr + 1) % modulus;
 				lapb->condition &= ~LAPB_REJECT_CONDITION;
-				if (frame->pf) {
+				if (frame->pf)
 					lapb_enquiry_response(lapb);
-				} else {
-					if (!(lapb->condition & LAPB_ACK_PENDING_CONDITION)) {
+				else {
+					if (!(lapb->condition &
+					      LAPB_ACK_PENDING_CONDITION)) {
 						lapb->condition |= LAPB_ACK_PENDING_CONDITION;
 						lapb_start_t2timer(lapb);
 					}
@@ -493,10 +562,14 @@
 						lapb_enquiry_response(lapb);
 				} else {
 #if LAPB_DEBUG > 1
-					printk(KERN_DEBUG "lapb: (%p) S3 TX REJ(%d) R%d\n", lapb->token, frame->pf, lapb->vr);
+					printk(KERN_DEBUG
+					       "lapb: (%p) S3 TX REJ(%d) R%d\n",
+					       lapb->token, frame->pf, lapb->vr);
 #endif
 					lapb->condition |= LAPB_REJECT_CONDITION;
-					lapb_send_control(lapb, LAPB_REJ, frame->pf, LAPB_RESPONSE);
+					lapb_send_control(lapb, LAPB_REJ,
+							  frame->pf,
+							  LAPB_RESPONSE);
 					lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
 				}
 			}
@@ -504,11 +577,15 @@
 
 		case LAPB_FRMR:
 #if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S3 RX FRMR(%d) %02X %02X %02X %02X %02X\n", lapb->token, frame->pf, skb->data[0], skb->data[1], skb->data[2], skb->data[3], skb->data[4]);
+			printk(KERN_DEBUG "lapb: (%p) S3 RX FRMR(%d) %02X "
+			       "%02X %02X %02X %02X\n", lapb->token, frame->pf,
+			       skb->data[0], skb->data[1], skb->data[2],
+			       skb->data[3], skb->data[4]);
 #endif
 			lapb_establish_data_link(lapb);
 #if LAPB_DEBUG > 0
-			printk(KERN_DEBUG "lapb: (%p) S3 -> S1\n", lapb->token);
+			printk(KERN_DEBUG "lapb: (%p) S3 -> S1\n",
+			       lapb->token);
 #endif
 			lapb_requeue_frames(lapb);
 			lapb->state = LAPB_STATE_1;
@@ -516,7 +593,8 @@
 
 		case LAPB_ILLEGAL:
 #if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S3 RX ILLEGAL(%d)\n", lapb->token, frame->pf);
+			printk(KERN_DEBUG "lapb: (%p) S3 RX ILLEGAL(%d)\n",
+			       lapb->token, frame->pf);
 #endif
 			lapb->frmr_data = *frame;
 			lapb->frmr_type = LAPB_FRMR_W;
@@ -529,9 +607,6 @@
 			lapb->state   = LAPB_STATE_4;
 			lapb->n2count = 0;
 			break;
-
-		default:
-			break;
 	}
 
 	if (!queued)
@@ -542,26 +617,33 @@
  *	State machine for state 4, Frame Reject State.
  *	The handling of the timer(s) is in file lapb_timer.c.
  */
-static void lapb_state4_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame)
+static void lapb_state4_machine(struct lapb_cb *lapb, struct sk_buff *skb,
+				struct lapb_frame *frame)
 {
 	switch (frame->type) {
 		case LAPB_SABM:
 #if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S4 RX SABM(%d)\n", lapb->token, frame->pf);
+			printk(KERN_DEBUG "lapb: (%p) S4 RX SABM(%d)\n",
+			       lapb->token, frame->pf);
 #endif
 			if (lapb->mode & LAPB_EXTENDED) {
 #if LAPB_DEBUG > 1
-				printk(KERN_DEBUG "lapb: (%p) S4 TX DM(%d)\n", lapb->token, frame->pf);
+				printk(KERN_DEBUG "lapb: (%p) S4 TX DM(%d)\n",
+				       lapb->token, frame->pf);
 #endif
-				lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE);
+				lapb_send_control(lapb, LAPB_DM, frame->pf,
+						  LAPB_RESPONSE);
 			} else {
 #if LAPB_DEBUG > 1
-				printk(KERN_DEBUG "lapb: (%p) S4 TX UA(%d)\n", lapb->token, frame->pf);
+				printk(KERN_DEBUG "lapb: (%p) S4 TX UA(%d)\n",
+				       lapb->token, frame->pf);
 #endif
 #if LAPB_DEBUG > 0
-				printk(KERN_DEBUG "lapb: (%p) S4 -> S3\n", lapb->token);
+				printk(KERN_DEBUG "lapb: (%p) S4 -> S3\n",
+				       lapb->token);
 #endif
-				lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
+				lapb_send_control(lapb, LAPB_UA, frame->pf,
+						  LAPB_RESPONSE);
 				lapb_stop_t1timer(lapb);
 				lapb_stop_t2timer(lapb);
 				lapb->state     = LAPB_STATE_3;
@@ -576,16 +658,20 @@
 
 		case LAPB_SABME:
 #if LAPB_DEBUG > 1
-			printk(KERN_DEBUG "lapb: (%p) S4 RX SABME(%d)\n", lapb->token, frame->pf);
+			printk(KERN_DEBUG "lapb: (%p) S4 RX SABME(%d)\n",
+			       lapb->token, frame->pf);
 #endif
 			if (lapb->mode & LAPB_EXTENDED) {
 #if LAPB_DEBUG > 1
-				printk(KERN_DEBUG "lapb: (%p) S4 TX UA(%d)\n", lapb->token, frame->pf);
+				printk(KERN_DEBUG "lapb: (%p) S4 TX UA(%d)\n",
+				       lapb->token, frame->pf);
 #endif
 #if LAPB_DEBUG > 0
-				printk(KERN_DEBUG "lapb: (%p) S4 -> S3\n", lapb->token);
+				printk(KERN_DEBUG "lapb: (%p) S4 -> S3\n",
+				       lapb->token);
 #endif
-				lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE);
+				lapb_send_control(lapb, LAPB_UA, frame->pf,
+						  LAPB_RESPONSE);
 				lapb_stop_t1timer(lapb);
 				lapb_stop_t2timer(lapb);
 				lapb->state     = LAPB_STATE_3;
@@ -597,14 +683,13 @@
 				lapb_connect_indication(lapb, LAPB_OK);
 			} else {
 #if LAPB_DEBUG > 1
-				printk(KERN_DEBUG "lapb: (%p) S4 TX DM(%d)\n", lapb->token, frame->pf);
+				printk(KERN_DEBUG "lapb: (%p) S4 TX DM(%d)\n",
+				       lapb->token, frame->pf);
 #endif
-				lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE);
+				lapb_send_control(lapb, LAPB_DM, frame->pf,
+						  LAPB_RESPONSE);
 			}
 			break;
-
-		default:
-			break;
 	}
 
 	kfree_skb(skb);
@@ -613,28 +698,23 @@
 /*
  *	Process an incoming LAPB frame
  */
-void lapb_data_input(lapb_cb *lapb, struct sk_buff *skb)
+void lapb_data_input(struct lapb_cb *lapb, struct sk_buff *skb)
 {
 	struct lapb_frame frame;
 
 	lapb_decode(lapb, skb, &frame);
 
 	switch (lapb->state) {
-		case LAPB_STATE_0:
-			lapb_state0_machine(lapb, skb, &frame);
-			break;
-		case LAPB_STATE_1:
-			lapb_state1_machine(lapb, skb, &frame);
-			break;
-		case LAPB_STATE_2:
-			lapb_state2_machine(lapb, skb, &frame);
-			break;
-		case LAPB_STATE_3:
-			lapb_state3_machine(lapb, skb, &frame);
-			break;
-		case LAPB_STATE_4:
-			lapb_state4_machine(lapb, skb, &frame);
-			break;
+	case LAPB_STATE_0:
+		lapb_state0_machine(lapb, skb, &frame); break;
+	case LAPB_STATE_1:
+		lapb_state1_machine(lapb, skb, &frame); break;
+	case LAPB_STATE_2:
+		lapb_state2_machine(lapb, skb, &frame); break;
+	case LAPB_STATE_3:
+		lapb_state3_machine(lapb, skb, &frame); break;
+	case LAPB_STATE_4:
+		lapb_state4_machine(lapb, skb, &frame); break;
 	}
 
 	lapb_kick(lapb);
diff -Nru a/net/lapb/lapb_out.c b/net/lapb/lapb_out.c
--- a/net/lapb/lapb_out.c	Tue Oct  1 00:08:18 2002
+++ b/net/lapb/lapb_out.c	Tue Oct  1 00:08:18 2002
@@ -38,56 +38,54 @@
  *  This procedure is passed a buffer descriptor for an iframe. It builds
  *  the rest of the control part of the frame and then writes it out.
  */
-static void lapb_send_iframe(lapb_cb *lapb, struct sk_buff *skb, int poll_bit)
+static void lapb_send_iframe(struct lapb_cb *lapb, struct sk_buff *skb, int poll_bit)
 {
 	unsigned char *frame;
 
-	if (skb == NULL)
+	if (!skb)
 		return;
 
 	if (lapb->mode & LAPB_EXTENDED) {
 		frame = skb_push(skb, 2);
 
 		frame[0] = LAPB_I;
-		frame[0] |= (lapb->vs << 1);
-		frame[1] = (poll_bit) ? LAPB_EPF : 0;
-		frame[1] |= (lapb->vr << 1);
+		frame[0] |= lapb->vs << 1;
+		frame[1] = poll_bit ? LAPB_EPF : 0;
+		frame[1] |= lapb->vr << 1;
 	} else {
 		frame = skb_push(skb, 1);
 
 		*frame = LAPB_I;
-		*frame |= (poll_bit) ? LAPB_SPF : 0;
-		*frame |= (lapb->vr << 5);
-		*frame |= (lapb->vs << 1);
+		*frame |= poll_bit ? LAPB_SPF : 0;
+		*frame |= lapb->vr << 5;
+		*frame |= lapb->vs << 1;
 	}
 
 #if LAPB_DEBUG > 1
-	printk(KERN_DEBUG "lapb: (%p) S%d TX I(%d) S%d R%d\n", lapb->token, lapb->state, poll_bit, lapb->vs, lapb->vr);
+	printk(KERN_DEBUG "lapb: (%p) S%d TX I(%d) S%d R%d\n",
+	       lapb->token, lapb->state, poll_bit, lapb->vs, lapb->vr);
 #endif
 
 	lapb_transmit_buffer(lapb, skb, LAPB_COMMAND);	
 }
 
-void lapb_kick(lapb_cb *lapb)
+void lapb_kick(struct lapb_cb *lapb)
 {
 	struct sk_buff *skb, *skbn;
 	unsigned short modulus, start, end;
 
 	modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : LAPB_SMODULUS;
-
-	start = (skb_peek(&lapb->ack_queue) == NULL) ? lapb->va : lapb->vs;
+	start = !skb_peek(&lapb->ack_queue) ? lapb->va : lapb->vs;
 	end   = (lapb->va + lapb->window) % modulus;
 
 	if (!(lapb->condition & LAPB_PEER_RX_BUSY_CONDITION) &&
-	    start != end                                &&
-	    skb_peek(&lapb->write_queue) != NULL) {
-
+	    start != end && skb_peek(&lapb->write_queue)) {
 		lapb->vs = start;
 
 		/*
 		 * Dequeue the frame and copy it.
 		 */
-		skb  = skb_dequeue(&lapb->write_queue);
+		skb = skb_dequeue(&lapb->write_queue);
 
 		do {
 			if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
@@ -95,7 +93,7 @@
 				break;
 			}
 
-			if (skb->sk != NULL)
+			if (skb->sk)
 				skb_set_owner_w(skbn, skb->sk);
 
 			/*
@@ -119,7 +117,7 @@
 	}
 }
 
-void lapb_transmit_buffer(lapb_cb *lapb, struct sk_buff *skb, int type)
+void lapb_transmit_buffer(struct lapb_cb *lapb, struct sk_buff *skb, int type)
 {
 	unsigned char *ptr;
 
@@ -152,26 +150,30 @@
 	}
 
 #if LAPB_DEBUG > 2
-	printk(KERN_DEBUG "lapb: (%p) S%d TX %02X %02X %02X\n", lapb->token, lapb->state, skb->data[0], skb->data[1], skb->data[2]);
+	printk(KERN_DEBUG "lapb: (%p) S%d TX %02X %02X %02X\n",
+	       lapb->token, lapb->state,
+	       skb->data[0], skb->data[1], skb->data[2]);
 #endif
 
 	if (!lapb_data_transmit(lapb, skb))
 		kfree_skb(skb);
 }
 
-void lapb_establish_data_link(lapb_cb *lapb)
+void lapb_establish_data_link(struct lapb_cb *lapb)
 {
 	lapb->condition = 0x00;
 	lapb->n2count   = 0;
 
 	if (lapb->mode & LAPB_EXTENDED) {
 #if LAPB_DEBUG > 1
-		printk(KERN_DEBUG "lapb: (%p) S%d TX SABME(1)\n", lapb->token, lapb->state);
+		printk(KERN_DEBUG "lapb: (%p) S%d TX SABME(1)\n",
+		       lapb->token, lapb->state);
 #endif
 		lapb_send_control(lapb, LAPB_SABME, LAPB_POLLON, LAPB_COMMAND);
 	} else {
 #if LAPB_DEBUG > 1
-		printk(KERN_DEBUG "lapb: (%p) S%d TX SABM(1)\n", lapb->token, lapb->state);
+		printk(KERN_DEBUG "lapb: (%p) S%d TX SABM(1)\n",
+		       lapb->token, lapb->state);
 #endif
 		lapb_send_control(lapb, LAPB_SABM, LAPB_POLLON, LAPB_COMMAND);
 	}
@@ -180,10 +182,11 @@
 	lapb_stop_t2timer(lapb);
 }
 
-void lapb_enquiry_response(lapb_cb *lapb)
+void lapb_enquiry_response(struct lapb_cb *lapb)
 {
 #if LAPB_DEBUG > 1
-	printk(KERN_DEBUG "lapb: (%p) S%d TX RR(1) R%d\n", lapb->token, lapb->state, lapb->vr);
+	printk(KERN_DEBUG "lapb: (%p) S%d TX RR(1) R%d\n",
+	       lapb->token, lapb->state, lapb->vr);
 #endif
 
 	lapb_send_control(lapb, LAPB_RR, LAPB_POLLON, LAPB_RESPONSE);
@@ -191,32 +194,30 @@
 	lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
 }
 
-void lapb_timeout_response(lapb_cb *lapb)
+void lapb_timeout_response(struct lapb_cb *lapb)
 {
 #if LAPB_DEBUG > 1
-	printk(KERN_DEBUG "lapb: (%p) S%d TX RR(0) R%d\n", lapb->token, lapb->state, lapb->vr);
+	printk(KERN_DEBUG "lapb: (%p) S%d TX RR(0) R%d\n",
+	       lapb->token, lapb->state, lapb->vr);
 #endif
-
 	lapb_send_control(lapb, LAPB_RR, LAPB_POLLOFF, LAPB_RESPONSE);
 
 	lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
 }
 
-void lapb_check_iframes_acked(lapb_cb *lapb, unsigned short nr)
+void lapb_check_iframes_acked(struct lapb_cb *lapb, unsigned short nr)
 {
 	if (lapb->vs == nr) {
 		lapb_frames_acked(lapb, nr);
 		lapb_stop_t1timer(lapb);
 		lapb->n2count = 0;
-	} else {
-		if (lapb->va != nr) {
-			lapb_frames_acked(lapb, nr);
-			lapb_start_t1timer(lapb);
-		}
+	} else if (lapb->va != nr) {
+		lapb_frames_acked(lapb, nr);
+		lapb_start_t1timer(lapb);
 	}
 }
 
-void lapb_check_need_response(lapb_cb *lapb, int type, int pf)
+void lapb_check_need_response(struct lapb_cb *lapb, int type, int pf)
 {
 	if (type == LAPB_COMMAND && pf)
 		lapb_enquiry_response(lapb);
diff -Nru a/net/lapb/lapb_subr.c b/net/lapb/lapb_subr.c
--- a/net/lapb/lapb_subr.c	Tue Oct  1 00:08:16 2002
+++ b/net/lapb/lapb_subr.c	Tue Oct  1 00:08:16 2002
@@ -36,7 +36,7 @@
 /*
  *	This routine purges all the queues of frames.
  */
-void lapb_clear_queues(lapb_cb *lapb)
+void lapb_clear_queues(struct lapb_cb *lapb)
 {
 	skb_queue_purge(&lapb->write_queue);
 	skb_queue_purge(&lapb->ack_queue);
@@ -47,7 +47,7 @@
  * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the
  * SDL diagram.
  */
-void lapb_frames_acked(lapb_cb *lapb, unsigned short nr)
+void lapb_frames_acked(struct lapb_cb *lapb, unsigned short nr)
 {
 	struct sk_buff *skb;
 	int modulus;
@@ -57,16 +57,15 @@
 	/*
 	 * Remove all the ack-ed frames from the ack queue.
 	 */
-	if (lapb->va != nr) {
-		while (skb_peek(&lapb->ack_queue) != NULL && lapb->va != nr) {
+	if (lapb->va != nr)
+		while (skb_peek(&lapb->ack_queue) && lapb->va != nr) {
 		        skb = skb_dequeue(&lapb->ack_queue);
 			kfree_skb(skb);
 			lapb->va = (lapb->va + 1) % modulus;
 		}
-	}
 }
 
-void lapb_requeue_frames(lapb_cb *lapb)
+void lapb_requeue_frames(struct lapb_cb *lapb)
 {
         struct sk_buff *skb, *skb_prev = NULL;
 
@@ -76,7 +75,7 @@
 	 * possibility of an empty output queue.
 	 */
 	while ((skb = skb_dequeue(&lapb->ack_queue)) != NULL) {
-		if (skb_prev == NULL)
+		if (!skb_prev)
 			skb_queue_head(&lapb->write_queue, skb);
 		else
 			skb_append(skb_prev, skb);
@@ -88,7 +87,7 @@
  *	Validate that the value of nr is between va and vs. Return true or
  *	false for testing.
  */
-int lapb_validate_nr(lapb_cb *lapb, unsigned short nr)
+int lapb_validate_nr(struct lapb_cb *lapb, unsigned short nr)
 {
 	unsigned short vc = lapb->va;
 	int modulus;
@@ -96,25 +95,27 @@
 	modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : LAPB_SMODULUS;
 
 	while (vc != lapb->vs) {
-		if (nr == vc) return 1;
+		if (nr == vc)
+			return 1;
 		vc = (vc + 1) % modulus;
 	}
 	
-	if (nr == lapb->vs) return 1;
-
-	return 0;
+	return nr == lapb->vs;
 }
 
 /*
  *	This routine is the centralised routine for parsing the control
  *	information for the different frame formats.
  */
-void lapb_decode(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame)
+void lapb_decode(struct lapb_cb *lapb, struct sk_buff *skb,
+		 struct lapb_frame *frame)
 {
 	frame->type = LAPB_ILLEGAL;
 
 #if LAPB_DEBUG > 2
-	printk(KERN_DEBUG "lapb: (%p) S%d RX %02X %02X %02X\n", lapb->token, lapb->state, skb->data[0], skb->data[1], skb->data[2]);
+	printk(KERN_DEBUG "lapb: (%p) S%d RX %02X %02X %02X\n",
+	       lapb->token, lapb->state,
+	       skb->data[0], skb->data[1], skb->data[2]);
 #endif
 
 	if (lapb->mode & LAPB_MLP) {
@@ -146,22 +147,31 @@
 	skb_pull(skb, 1);
 
 	if (lapb->mode & LAPB_EXTENDED) {
-		if ((skb->data[0] & LAPB_S) == 0) {
-			frame->type       = LAPB_I;			/* I frame - carries NR/NS/PF */
+		if (!(skb->data[0] & LAPB_S)) {
+			/*
+			 * I frame - carries NR/NS/PF
+			 */
+			frame->type       = LAPB_I;
 			frame->ns         = (skb->data[0] >> 1) & 0x7F;
 			frame->nr         = (skb->data[1] >> 1) & 0x7F;
 			frame->pf         = skb->data[1] & LAPB_EPF;
 			frame->control[0] = skb->data[0];
 			frame->control[1] = skb->data[1];
 			skb_pull(skb, 2);
-		} else if ((skb->data[0] & LAPB_U) == 1) { 	/* S frame - take out PF/NR */
+		} else if ((skb->data[0] & LAPB_U) == 1) {
+			/*
+			 * S frame - take out PF/NR
+			 */
 			frame->type       = skb->data[0] & 0x0F;
 			frame->nr         = (skb->data[1] >> 1) & 0x7F;
 			frame->pf         = skb->data[1] & LAPB_EPF;
 			frame->control[0] = skb->data[0];
 			frame->control[1] = skb->data[1];
 			skb_pull(skb, 2);
-		} else if ((skb->data[0] & LAPB_U) == 3) { 	/* U frame - take out PF */
+		} else if ((skb->data[0] & LAPB_U) == 3) {
+			/*
+			 * U frame - take out PF
+			 */
 			frame->type       = skb->data[0] & ~LAPB_SPF;
 			frame->pf         = skb->data[0] & LAPB_SPF;
 			frame->control[0] = skb->data[0];
@@ -169,16 +179,25 @@
 			skb_pull(skb, 1);
 		}
 	} else {
-		if ((skb->data[0] & LAPB_S) == 0) {
-			frame->type = LAPB_I;			/* I frame - carries NR/NS/PF */
+		if (!(skb->data[0] & LAPB_S)) {
+			/*
+			 * I frame - carries NR/NS/PF
+			 */
+			frame->type = LAPB_I;
 			frame->ns   = (skb->data[0] >> 1) & 0x07;
 			frame->nr   = (skb->data[0] >> 5) & 0x07;
 			frame->pf   = skb->data[0] & LAPB_SPF;
-		} else if ((skb->data[0] & LAPB_U) == 1) { 	/* S frame - take out PF/NR */
+		} else if ((skb->data[0] & LAPB_U) == 1) {
+			/*
+			 * S frame - take out PF/NR
+			 */
 			frame->type = skb->data[0] & 0x0F;
 			frame->nr   = (skb->data[0] >> 5) & 0x07;
 			frame->pf   = skb->data[0] & LAPB_SPF;
-		} else if ((skb->data[0] & LAPB_U) == 3) { 	/* U frame - take out PF */
+		} else if ((skb->data[0] & LAPB_U) == 3) {
+			/*
+			 * U frame - take out PF
+			 */
 			frame->type = skb->data[0] & ~LAPB_SPF;
 			frame->pf   = skb->data[0] & LAPB_SPF;
 		}
@@ -195,7 +214,8 @@
  *	Only supervisory or unnumbered frames are processed, FRMRs are handled
  *	by lapb_transmit_frmr below.
  */
-void lapb_send_control(lapb_cb *lapb, int frametype, int poll_bit, int type)
+void lapb_send_control(struct lapb_cb *lapb, int frametype,
+		       int poll_bit, int type)
 {
 	struct sk_buff *skb;
 	unsigned char  *dptr;
@@ -209,18 +229,18 @@
 		if ((frametype & LAPB_U) == LAPB_U) {
 			dptr   = skb_put(skb, 1);
 			*dptr  = frametype;
-			*dptr |= (poll_bit) ? LAPB_SPF : 0;
+			*dptr |= poll_bit ? LAPB_SPF : 0;
 		} else {
 			dptr     = skb_put(skb, 2);
 			dptr[0]  = frametype;
 			dptr[1]  = (lapb->vr << 1);
-			dptr[1] |= (poll_bit) ? LAPB_EPF : 0;
+			dptr[1] |= poll_bit ? LAPB_EPF : 0;
 		}
 	} else {
 		dptr   = skb_put(skb, 1);
 		*dptr  = frametype;
-		*dptr |= (poll_bit) ? LAPB_SPF : 0;
-		if ((frametype & LAPB_U) == LAPB_S)		/* S frames carry NR */
+		*dptr |= poll_bit ? LAPB_SPF : 0;
+		if ((frametype & LAPB_U) == LAPB_S)	/* S frames carry NR */
 			*dptr |= (lapb->vr << 5);
 	}
 
@@ -231,7 +251,7 @@
  *	This routine generates FRMRs based on information previously stored in
  *	the LAPB control block.
  */
-void lapb_transmit_frmr(lapb_cb *lapb)
+void lapb_transmit_frmr(struct lapb_cb *lapb)
 {
 	struct sk_buff *skb;
 	unsigned char  *dptr;
@@ -254,7 +274,10 @@
 		*dptr++ = lapb->frmr_type;
 
 #if LAPB_DEBUG > 1
-	printk(KERN_DEBUG "lapb: (%p) S%d TX FRMR %02X %02X %02X %02X %02X\n", lapb->token, lapb->state, skb->data[1], skb->data[2], skb->data[3], skb->data[4], skb->data[5]);
+	printk(KERN_DEBUG "lapb: (%p) S%d TX FRMR %02X %02X %02X %02X %02X\n",
+	       lapb->token, lapb->state,
+	       skb->data[1], skb->data[2], skb->data[3],
+	       skb->data[4], skb->data[5]);
 #endif
 	} else {
 		dptr    = skb_put(skb, 4);
@@ -268,7 +291,9 @@
 		*dptr++ = lapb->frmr_type;
 
 #if LAPB_DEBUG > 1
-	printk(KERN_DEBUG "lapb: (%p) S%d TX FRMR %02X %02X %02X\n", lapb->token, lapb->state, skb->data[1], skb->data[2], skb->data[3]);
+	printk(KERN_DEBUG "lapb: (%p) S%d TX FRMR %02X %02X %02X\n",
+	       lapb->token, lapb->state, skb->data[1],
+	       skb->data[2], skb->data[3]);
 #endif
 	}
 
diff -Nru a/net/lapb/lapb_timer.c b/net/lapb/lapb_timer.c
--- a/net/lapb/lapb_timer.c	Tue Oct  1 00:08:16 2002
+++ b/net/lapb/lapb_timer.c	Tue Oct  1 00:08:16 2002
@@ -37,7 +37,7 @@
 static void lapb_t1timer_expiry(unsigned long);
 static void lapb_t2timer_expiry(unsigned long);
 
-void lapb_start_t1timer(lapb_cb *lapb)
+void lapb_start_t1timer(struct lapb_cb *lapb)
 {
 	del_timer(&lapb->t1timer);
 
@@ -48,7 +48,7 @@
 	add_timer(&lapb->t1timer);
 }
 
-void lapb_start_t2timer(lapb_cb *lapb)
+void lapb_start_t2timer(struct lapb_cb *lapb)
 {
 	del_timer(&lapb->t2timer);
 
@@ -59,24 +59,24 @@
 	add_timer(&lapb->t2timer);
 }
 
-void lapb_stop_t1timer(lapb_cb *lapb)
+void lapb_stop_t1timer(struct lapb_cb *lapb)
 {
 	del_timer(&lapb->t1timer);
 }
 
-void lapb_stop_t2timer(lapb_cb *lapb)
+void lapb_stop_t2timer(struct lapb_cb *lapb)
 {
 	del_timer(&lapb->t2timer);
 }
 
-int lapb_t1timer_running(lapb_cb *lapb)
+int lapb_t1timer_running(struct lapb_cb *lapb)
 {
 	return timer_pending(&lapb->t1timer);
 }
 
 static void lapb_t2timer_expiry(unsigned long param)
 {
-	lapb_cb *lapb = (lapb_cb *)param;
+	struct lapb_cb *lapb = (struct lapb_cb *)param;
 
 	if (lapb->condition & LAPB_ACK_PENDING_CONDITION) {
 		lapb->condition &= ~LAPB_ACK_PENDING_CONDITION;
@@ -86,7 +86,7 @@
 
 static void lapb_t1timer_expiry(unsigned long param)
 {
-	lapb_cb *lapb = (lapb_cb *)param;
+	struct lapb_cb *lapb = (struct lapb_cb *)param;
 
 	switch (lapb->state) {
 
diff -Nru a/net/llc/Makefile b/net/llc/Makefile
--- a/net/llc/Makefile	Tue Oct  1 00:08:19 2002
+++ b/net/llc/Makefile	Tue Oct  1 00:08:19 2002
@@ -2,7 +2,7 @@
 # Makefile for the Linux 802.2 LLC (fully-functional) layer.
 #
 # Copyright (c) 1997 by Procom Technology,Inc.
-#		2001 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+#		2001, 2002 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
 #
 # This program can be redistributed or modified under the terms of the 
 # GNU General Public License as published by the Free Software Foundation.
@@ -17,7 +17,7 @@
 llc-y := llc_if.o llc_c_ev.o llc_c_ac.o llc_mac.o llc_sap.o llc_s_st.o \
 	 llc_main.o llc_s_ac.o llc_conn.o llc_c_st.o llc_stat.o llc_actn.o \
 	 llc_s_ev.o llc_evnt.o llc_pdu.o
-llc-$(CONFIG_LLC_UI)	+= llc_sock.o
+llc-$(CONFIG_LLC_UI)	+= af_llc.o
 llc-objs	 	:= $(llc-y)
 
 # Objects that export symbols.
diff -Nru a/net/llc/af_llc.c b/net/llc/af_llc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/llc/af_llc.c	Tue Oct  1 00:08:14 2002
@@ -0,0 +1,1152 @@
+/*
+ * af_llc.c - LLC User Interface SAPs
+ * Description:
+ *   Functions in this module are implementation of socket based llc
+ *   communications for the Linux operating system. Support of llc class
+ *   one and class two is provided via SOCK_DGRAM and SOCK_STREAM
+ *   respectively.
+ *
+ *   An llc2 connection is (mac + sap), only one llc2 sap connection
+ *   is allowed per mac. Though one sap may have multiple mac + sap
+ *   connections.
+ *
+ * Copyright (c) 2001 by Jay Schulist <jschlst@samba.org>
+ *		 2002 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *
+ * This program can be redistributed or modified under the terms of the
+ * GNU General Public License as published by the Free Software Foundation.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <asm/uaccess.h>
+#include <asm/ioctls.h>
+#include <linux/proc_fs.h>
+#include <linux/in.h>
+#include <linux/tcp.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/errno.h>
+#include <net/sock.h>
+#include <net/llc_if.h>
+#include <net/llc_sap.h>
+#include <net/llc_pdu.h>
+#include <net/llc_conn.h>
+#include <net/llc_mac.h>
+#include <net/llc_main.h>
+#include <linux/llc.h>
+#include <linux/if_arp.h>
+#include <linux/rtnetlink.h>
+#include <linux/init.h>
+
+/* remember: uninitialized global data is zeroed because its in .bss */
+static u16 llc_ui_sap_last_autoport = LLC_SAP_DYN_START;
+static u16 llc_ui_sap_link_no_max[256];
+static struct sockaddr_llc llc_ui_addrnull;
+static struct proto_ops llc_ui_ops;
+
+static int llc_ui_wait_for_conn(struct sock *sk, int timeout);
+static int llc_ui_wait_for_disc(struct sock *sk, int timeout);
+static int llc_ui_wait_for_data(struct sock *sk, int timeout);
+static int llc_ui_wait_for_busy_core(struct sock *sk, int timeout);
+
+#if 0
+#define dprintk(args...) printk(KERN_DEBUG args)
+#else
+#define dprintk(args...)
+#endif
+
+/**
+ *	llc_ui_next_link_no - return the next unused link number for a sap
+ *	@sap: Address of sap to get link number from.
+ *
+ *	Return the next unused link number for a given sap.
+ */
+static __inline__ u16 llc_ui_next_link_no(int sap)
+{
+	return llc_ui_sap_link_no_max[sap]++;
+}
+
+/**
+ *	llc_proto_type - return eth protocol for ARP header type
+ *	@arphrd: ARP header type.
+ *
+ *	Given an ARP header type return the corresponding ethernet protocol.
+ */
+static __inline__ u16 llc_proto_type(u16 arphrd)
+{
+	return arphrd == ARPHRD_IEEE802_TR ?
+		         htons(ETH_P_TR_802_2) : htons(ETH_P_802_2);
+}
+
+/**
+ *	llc_ui_addr_null - determines if a address structure is null
+ *	@addr: Address to test if null.
+ */
+static __inline__ u8 llc_ui_addr_null(struct sockaddr_llc *addr)
+{
+	return !memcmp(addr, &llc_ui_addrnull, sizeof(*addr));
+}
+
+/**
+ *	llc_ui_header_len - return length of llc header based on operation
+ *	@sk: Socket which contains a valid llc socket type.
+ *	@addr: Complete sockaddr_llc structure received from the user.
+ *
+ *	Provide the length of the llc header depending on what kind of
+ *	operation the user would like to perform and the type of socket.
+ *	Returns the correct llc header length.
+ */
+static __inline__ u8 llc_ui_header_len(struct sock *sk,
+				       struct sockaddr_llc *addr)
+{
+	u8 rc = LLC_PDU_LEN_U;
+
+	if (addr->sllc_test || addr->sllc_xid)
+		rc = LLC_PDU_LEN_U;
+	else if (sk->type == SOCK_STREAM)
+		rc = LLC_PDU_LEN_I;
+	return rc;
+}
+
+/**
+ *	llc_ui_send_data - send data via reliable llc2 connection
+ *	@sk: Connection the socket is using.
+ *	@skb: Data the user wishes to send.
+ *	@addr: Source and destination fields provided by the user.
+ *	@noblock: can we block waiting for data?
+ *
+ *	Send data via reliable llc2 connection.
+ *	Returns 0 upon success, non-zero if action did not succeed.
+ */
+static int llc_ui_send_data(struct sock* sk, struct sk_buff *skb, int noblock)
+{
+	struct llc_opt* llc = llc_sk(sk);
+	int rc = 0;
+
+	if (llc_data_accept_state(llc->state) || llc->p_flag) {
+		int timeout = sock_sndtimeo(sk, noblock);
+
+		rc = llc_ui_wait_for_busy_core(sk, timeout);
+	}
+	if (!rc)
+		rc = llc_build_and_send_pkt(sk, skb);
+	return rc;
+}
+
+static void llc_ui_sk_init(struct socket *sock, struct sock *sk)
+{
+	sk->type   = sock->type;
+	sk->sleep  = &sock->wait;
+	sk->socket = sock;
+	sock->sk   = sk;
+	sock->ops  = &llc_ui_ops;
+}
+
+/**
+ *	llc_ui_create - alloc and init a new llc_ui socket
+ *	@sock: Socket to initialize and attach allocated sk to.
+ *	@protocol: Unused.
+ *
+ *	Allocate and initialize a new llc_ui socket, validate the user wants a
+ *	socket type we have available.
+ *	Returns 0 upon success, negative upon failure.
+ */
+static int llc_ui_create(struct socket *sock, int protocol)
+{
+	struct sock *sk;
+	int rc = -ESOCKTNOSUPPORT;
+
+	if (sock->type == SOCK_DGRAM || sock->type == SOCK_STREAM) {
+		rc = -ENOMEM;
+		sk = llc_sk_alloc(PF_LLC, GFP_KERNEL);
+		if (sk) {
+			rc = 0;
+			llc_ui_sk_init(sock, sk);
+		}
+	}
+	return rc;
+}
+
+/**
+ *	llc_ui_release - shutdown socket
+ *	@sock: Socket to release.
+ *
+ *	Shutdown and deallocate an existing socket.
+ */
+static int llc_ui_release(struct socket *sock)
+{
+	struct sock *sk = sock->sk;
+	struct llc_opt *llc;
+
+	if (!sk)
+		goto out;
+	sock_hold(sk);
+	lock_sock(sk);
+	llc = llc_sk(sk);
+	dprintk("%s: closing local(%02X) remote(%02X)\n", __FUNCTION__,
+		llc->laddr.lsap, llc->daddr.lsap);
+	if (!llc_send_disc(sk))
+		llc_ui_wait_for_disc(sk, sk->rcvtimeo);
+	if (!sk->zapped)
+		llc_sap_unassign_sock(llc->sap, sk);
+	release_sock(sk);
+	if (llc->sap && !llc->sap->sk_list.list)
+		llc_sap_close(llc->sap);
+	sock_put(sk);
+	llc_sk_free(sk);
+out:
+	return 0;
+}
+
+/**
+ *	llc_ui_autoport - provide dynamicly allocate SAP number
+ *
+ *	Provide the caller with a dynamicly allocated SAP number according
+ *	to the rules that are set in this function. Returns: 0, upon failure,
+ *	SAP number otherwise.
+ */
+static int llc_ui_autoport(void)
+{
+	struct llc_sap *sap;
+	int i, tries = 0;
+
+	while (tries < LLC_SAP_DYN_TRIES) {
+		for (i = llc_ui_sap_last_autoport;
+		     i < LLC_SAP_DYN_STOP; i += 2) {
+			sap = llc_sap_find(i);
+			if (!sap) {
+				llc_ui_sap_last_autoport = i + 2;
+				goto out;
+			}
+		}
+		llc_ui_sap_last_autoport = LLC_SAP_DYN_START;
+		tries++;
+	}
+	i = 0;
+out:
+	return i;
+}
+
+/**
+ *	llc_ui_autobind - Bind a socket to a specific address.
+ *	@sk: Socket to bind an address to.
+ *	@addr: Address the user wants the socket bound to.
+ *
+ *	Bind a socket to a specific address. For llc a user is able to bind to
+ *	a specific sap only or mac + sap. If the user only specifies a sap and
+ *	a null dmac (all zeros) the user is attempting to bind to an entire
+ *	sap. This will stop anyone else on the local system from using that
+ *	sap.  If someone else has a mac + sap open the bind to null + sap will
+ *	fail.
+ *	If the user desires to bind to a specific mac + sap, it is possible to
+ *	have multiple sap connections via multiple macs.
+ *	Bind and autobind for that matter must enforce the correct sap usage
+ *	otherwise all hell will break loose.
+ *	Returns: 0 upon success, negative otherwise.
+ */
+static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
+{
+	struct sock *sk = sock->sk;
+	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sap *sap;
+	struct net_device *dev = NULL;
+	int rc = -EINVAL;
+
+	if (!sk->zapped)
+		goto out;
+	/* bind to a specific mac, optional. */
+	if (!llc_mac_null(addr->sllc_smac)) {
+		rtnl_lock();
+		dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_smac);
+		rtnl_unlock();
+		rc = -ENETUNREACH;
+		if (!dev)
+			goto out;
+		llc->dev = dev;
+	}
+	/* bind to a specific sap, optional. */
+	if (!addr->sllc_ssap) {
+		rc = -EUSERS;
+		addr->sllc_ssap = llc_ui_autoport();
+		if (!addr->sllc_ssap)
+			goto out;
+	}
+	sap = llc_sap_find(addr->sllc_ssap);
+	if (!sap) {
+		sap = llc_sap_open(addr->sllc_ssap, NULL);
+		rc = -EBUSY; /* some other network layer is using the sap */
+		if (!sap)
+			goto out;
+	} else {
+		struct llc_addr laddr, daddr;
+		struct sock *ask;
+
+		rc = -EUSERS; /* can't get exclusive use of sap */
+		if (!dev && llc_mac_null(addr->sllc_mmac))
+			goto out;
+		memset(&laddr, 0, sizeof(laddr));
+		memset(&daddr, 0, sizeof(daddr));
+		if (!llc_mac_null(addr->sllc_mmac)) {
+			if (sk->type != SOCK_DGRAM) {
+				rc = -EOPNOTSUPP;
+				goto out;
+			}
+			memcpy(laddr.mac, addr->sllc_mmac, IFHWADDRLEN);
+		} else
+			memcpy(laddr.mac, addr->sllc_smac, IFHWADDRLEN);
+		laddr.lsap = addr->sllc_ssap;
+		rc = -EADDRINUSE; /* mac + sap clash. */
+		ask = llc_lookup_established(sap, &daddr, &laddr);
+		if (ask) {
+			sock_put(ask);
+			goto out;
+		}
+	}
+	llc->laddr.lsap = addr->sllc_ssap;
+	if (llc->dev)
+		memcpy(llc->laddr.mac, llc->dev->dev_addr, IFHWADDRLEN);
+	llc->daddr.lsap = addr->sllc_dsap;
+	memcpy(llc->daddr.mac, addr->sllc_dmac, IFHWADDRLEN);
+	memcpy(&llc->addr, addr, sizeof(llc->addr));
+	/* assign new connection to it's SAP */
+	llc_sap_assign_sock(sap, sk);
+	rc = sk->zapped = 0;
+out:
+	return rc;
+}
+
+/**
+ *	llc_ui_bind - bind a socket to a specific address.
+ *	@sock: Socket to bind an address to.
+ *	@uaddr: Address the user wants the socket bound to.
+ *	@addrlen: Length of the uaddr structure.
+ *
+ *	Bind a socket to a specific address. For llc a user is able to bind to
+ *	a specific sap only or mac + sap. If the user only specifies a sap and
+ *	a null dmac (all zeros) the user is attempting to bind to an entire
+ *	sap. This will stop anyone else on the local system from using that
+ *	sap. If someone else has a mac + sap open the bind to null + sap will
+ *	fail.
+ *	If the user desires to bind to a specific mac + sap, it is possible to
+ *	have multiple sap connections via multiple macs.
+ *	Bind and autobind for that matter must enforce the correct sap usage
+ *	otherwise all hell will break loose.
+ *	Returns: 0 upon success, negative otherwise.
+ */
+static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
+{
+	struct sockaddr_llc *addr = (struct sockaddr_llc *)uaddr;
+	struct sock *sk = sock->sk;
+	int rc = -EINVAL;
+
+	dprintk("%s: binding %02X\n", __FUNCTION__, addr->sllc_ssap);
+	if (!sk->zapped || addrlen != sizeof(*addr))
+		goto out;
+	rc = -EAFNOSUPPORT;
+	if (addr->sllc_family != AF_LLC)
+		goto out;
+	/* use autobind, to avoid code replication. */
+	rc = llc_ui_autobind(sock, addr);
+out:
+	return rc;
+}
+
+/**
+ *	llc_ui_shutdown - shutdown a connect llc2 socket.
+ *	@sock: Socket to shutdown.
+ *	@how: What part of the socket to shutdown.
+ *
+ *	Shutdown a connected llc2 socket. Currently this function only supports
+ *	shutting down both sends and receives (2), we could probably make this
+ *	function such that a user can shutdown only half the connection but not
+ *	right now.
+ *	Returns: 0 upon success, negative otherwise.
+ */
+static int llc_ui_shutdown(struct socket *sock, int how)
+{
+	struct sock *sk = sock->sk;
+	int rc = -ENOTCONN;
+
+	lock_sock(sk);
+	if (sk->state != TCP_ESTABLISHED)
+		goto out;
+	rc = -EINVAL;
+	if (how != 2)
+		goto out;
+	rc = llc_send_disc(sk);
+	if (!rc)
+		rc = llc_ui_wait_for_disc(sk, sk->rcvtimeo);
+	/* Wake up anyone sleeping in poll */
+	sk->state_change(sk);
+out:
+	release_sock(sk);
+	return rc;
+}
+
+/**
+ *	llc_ui_connect - Connect to a remote llc2 mac + sap.
+ *	@sock: Socket which will be connected to the remote destination.
+ *	@uaddr: Remote and possibly the local address of the new connection.
+ *	@addrlen: Size of uaddr structure.
+ *	@flags: Operational flags specified by the user.
+ *
+ *	Connect to a remote llc2 mac + sap. The caller must specify the
+ *	destination mac and address to connect to. If the user previously
+ *	called bind(2) with a smac the user does not need to specify the source
+ *	address and mac.
+ *	This function will autobind if user did not previously call bind.
+ *	Returns: 0 upon success, negative otherwise.
+ */
+static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr,
+			  int addrlen, int flags)
+{
+	struct sock *sk = sock->sk;
+	struct llc_opt *llc = llc_sk(sk);
+	struct sockaddr_llc *addr = (struct sockaddr_llc *)uaddr;
+	struct net_device *dev;
+	int rc = -EINVAL;
+
+	lock_sock(sk);
+	if (addrlen != sizeof(*addr))
+		goto out;
+	rc = -EAFNOSUPPORT;
+	if (addr->sllc_family != AF_LLC)
+		goto out;
+	/* bind connection to sap if user hasn't done it. */
+	if (sk->zapped) {
+		/* bind to sap with null dev, exclusive */
+		rc = llc_ui_autobind(sock, addr);
+		if (rc)
+			goto out;
+	}
+	if (!llc->dev) {
+		rtnl_lock();
+		dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_smac);
+		rtnl_unlock();
+		if (!dev)
+			goto out;
+		llc->dev = dev;
+	} else
+		dev = llc->dev;
+	if (sk->type != SOCK_STREAM)
+		goto out;
+	rc = -EALREADY;
+	if (sock->state == SS_CONNECTING)
+		goto out;
+	sock->state = SS_CONNECTING;
+	sk->state   = TCP_SYN_SENT;
+	llc->link   = llc_ui_next_link_no(llc->sap->laddr.lsap);
+	rc = llc_establish_connection(sk, dev->dev_addr,
+				      addr->sllc_dmac, addr->sllc_dsap);
+	if (rc) {
+		dprintk("%s: llc_ui_send_conn failed :-(\n", __FUNCTION__);
+		sock->state = SS_UNCONNECTED;
+		sk->state   = TCP_CLOSE;
+		goto out;
+	}
+	rc = llc_ui_wait_for_conn(sk, sk->rcvtimeo);
+	if (rc)
+		dprintk("%s: llc_ui_wait_for_conn failed=%d\n", __FUNCTION__, rc);
+out:
+	release_sock(sk);
+	return rc;
+}
+
+/**
+ *	llc_ui_listen - allow a normal socket to accept incoming connections
+ *	@sock: Socket to allow incoming connections on.
+ *	@backlog: Number of connections to queue.
+ *
+ *	Allow a normal socket to accept incoming connections.
+ *	Returns 0 upon success, negative otherwise.
+ */
+static int llc_ui_listen(struct socket *sock, int backlog)
+{
+	struct sock *sk = sock->sk;
+	int rc = -EINVAL;
+
+	lock_sock(sk);
+	if (sock->state != SS_UNCONNECTED)
+		goto out;
+	rc = -EOPNOTSUPP;
+	if (sk->type != SOCK_STREAM)
+		goto out;
+	rc = -EAGAIN;
+	if (sk->zapped)
+		goto out;
+	rc = 0;
+	if (!(unsigned)backlog)	/* BSDism */
+		backlog = 1;
+	sk->max_ack_backlog = backlog;
+	if (sk->state != TCP_LISTEN) {
+		sk->ack_backlog = 0;
+		sk->state = TCP_LISTEN;
+	}
+	sk->socket->flags |= __SO_ACCEPTCON;
+out:
+	release_sock(sk);
+	return rc;
+}
+
+static int llc_ui_wait_for_disc(struct sock *sk, int timeout)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	int rc;
+
+	add_wait_queue_exclusive(sk->sleep, &wait);
+	for (;;) {
+		__set_current_state(TASK_INTERRUPTIBLE);
+		rc = -ERESTARTSYS;
+		if (signal_pending(current))
+			break;
+		rc = -EAGAIN;
+		if (!timeout)
+			break;
+		rc = 0;
+		if (sk->state != TCP_CLOSE) {
+			release_sock(sk);
+			timeout = schedule_timeout(timeout);
+			lock_sock(sk);
+		} else
+			break;
+	}
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(sk->sleep, &wait);
+	return rc;
+}
+
+static int llc_ui_wait_for_conn(struct sock *sk, int timeout)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	int rc;
+
+	add_wait_queue_exclusive(sk->sleep, &wait);
+	for (;;) {
+		__set_current_state(TASK_INTERRUPTIBLE);
+		rc = -EAGAIN;
+		if (sk->state == TCP_CLOSE)
+			break;
+		rc = -ERESTARTSYS;
+		if (signal_pending(current))
+			break;
+		rc = -EAGAIN;
+		if (!timeout)
+			break;
+		rc = 0;
+		if (sk->state != TCP_ESTABLISHED) {
+			release_sock(sk);
+			timeout = schedule_timeout(timeout);
+			lock_sock(sk);
+		} else
+			break;
+	}
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(sk->sleep, &wait);
+	return rc;
+}
+
+static int llc_ui_wait_for_data(struct sock *sk, int timeout)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	int rc = 0;
+
+	add_wait_queue_exclusive(sk->sleep, &wait);
+	for (;;) {
+		__set_current_state(TASK_INTERRUPTIBLE);
+		if (sk->shutdown & RCV_SHUTDOWN)
+			break;
+		rc = -ERESTARTSYS;
+		if (signal_pending(current))
+			break;
+		rc = -EAGAIN;
+		if (!timeout)
+			break;
+		rc = 0;
+		if (skb_queue_empty(&sk->receive_queue)) {
+			release_sock(sk);
+			timeout = schedule_timeout(timeout);
+			lock_sock(sk);
+		} else
+			break;
+	}
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(sk->sleep, &wait);
+	return rc;
+}
+
+static int llc_ui_wait_for_busy_core(struct sock *sk, int timeout)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	struct llc_opt *llc = llc_sk(sk);
+	int rc;
+
+	add_wait_queue_exclusive(sk->sleep, &wait);
+	for (;;) {
+		dprintk("%s: looping...\n", __FUNCTION__);
+		__set_current_state(TASK_INTERRUPTIBLE);
+		rc = -ENOTCONN;
+		if (sk->shutdown & RCV_SHUTDOWN)
+			break;
+		rc = -ERESTARTSYS;
+		if (signal_pending(current))
+			break;
+		rc = -EAGAIN;
+		if (!timeout)
+			break;
+		rc = 0;
+		if (llc_data_accept_state(llc->state) || llc->p_flag) {
+			release_sock(sk);
+			timeout = schedule_timeout(timeout);
+			lock_sock(sk);
+		} else
+			break;
+	}
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(sk->sleep, &wait);
+	return rc;
+}
+
+/**
+ *	llc_ui_accept - accept a new incoming connection.
+ *	@sock: Socket which connections arrive on.
+ *	@newsock: Socket to move incoming connection to.
+ *	@flags: User specified operational flags.
+ *
+ *	Accept a new incoming connection.
+ *	Returns 0 upon success, negative otherwise.
+ */
+static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags)
+{
+	struct sock *sk = sock->sk, *newsk;
+	struct llc_opt *llc, *newllc;
+	struct sk_buff *skb;
+	int rc = -EOPNOTSUPP;
+
+	dprintk("%s: accepting on %02X\n", __FUNCTION__, llc_sk(sk)->addr.sllc_ssap);
+	lock_sock(sk);
+	if (sk->type != SOCK_STREAM)
+		goto out;
+	rc = -EINVAL;
+	if (sock->state != SS_UNCONNECTED || sk->state != TCP_LISTEN)
+		goto out;
+	/* wait for a connection to arrive. */
+	rc = llc_ui_wait_for_data(sk, sk->rcvtimeo);
+	if (rc)
+		goto out;
+	dprintk("%s: got a new connection on %02X\n", __FUNCTION__, llc_sk(sk)->addr.sllc_ssap);
+	skb = skb_dequeue(&sk->receive_queue);
+	rc = -EINVAL;
+	if (!skb->sk)
+		goto frees;
+	rc = 0;
+	newsk = skb->sk;
+	/* attach connection to a new socket. */
+	llc_ui_sk_init(newsock, newsk);
+	newsk->pair		= NULL;
+	newsk->zapped		= 0;
+	newsk->state		= TCP_ESTABLISHED;
+	newsock->state		= SS_CONNECTED;
+	llc			= llc_sk(sk);
+	newllc			= llc_sk(newsk);
+	memcpy(&newllc->addr, &llc->addr, sizeof(newllc->addr));
+	memcpy(newllc->addr.sllc_dmac, newllc->daddr.mac, IFHWADDRLEN);
+	newllc->addr.sllc_dsap = newllc->daddr.lsap;
+	newllc->link = llc_ui_next_link_no(newllc->laddr.lsap);
+
+	/* put original socket back into a clean listen state. */
+	sk->state = TCP_LISTEN;
+	sk->ack_backlog--;
+	skb->sk = NULL;
+	dprintk("%s: ok success on %02X, client on %02X\n", __FUNCTION__,
+		llc_sk(sk)->addr.sllc_ssap, newllc->addr.sllc_dsap);
+frees:
+	kfree_skb(skb);
+out:
+	release_sock(sk);
+	return rc;
+}
+
+/**
+ *	llc_ui_recvmsg - copy received data to the socket user.
+ *	@sock: Socket to copy data from.
+ *	@msg: Various user space related information.
+ *	@size: Size of user buffer.
+ *	@flags: User specified flags.
+ *	@scm: Unknown.
+ *
+ *	Copy received data to the socket user.
+ *	Returns non-negative upon success, negative otherwise.
+ */
+static int llc_ui_recvmsg(struct socket *sock, struct msghdr *msg, int size,
+			  int flags, struct scm_cookie *scm)
+{
+	struct sock *sk = sock->sk;
+	struct sockaddr_llc *uaddr = (struct sockaddr_llc *)msg->msg_name;
+	struct sk_buff *skb;
+	int rc = -ENOMEM, copied = 0, timeout;
+	int noblock = flags & MSG_DONTWAIT;
+
+	dprintk("%s: receiving in %02X from %02X\n", __FUNCTION__,
+		llc_sk(sk)->laddr.lsap, llc_sk(sk)->daddr.lsap);
+	lock_sock(sk);
+	timeout = sock_rcvtimeo(sk, noblock);
+	rc = llc_ui_wait_for_data(sk, timeout);
+	if (rc) {
+		dprintk("%s: llc_ui_wait_for_data failed recv in %02X from %02X\n",
+			__FUNCTION__, llc_sk(sk)->laddr.lsap, llc_sk(sk)->daddr.lsap);
+		goto out;
+	}
+	skb = skb_dequeue(&sk->receive_queue);
+	if (!skb) /* shutdown */
+		goto out;
+	copied = skb->len;
+	if (copied > size)
+		copied = size;
+	rc = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+	if (rc)
+		goto dgram_free;
+	if (skb->len > copied) {
+		skb_pull(skb, copied);
+		skb_queue_head(&sk->receive_queue, skb);
+	}
+	if (uaddr)
+		memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr));
+	msg->msg_namelen = sizeof(*uaddr);
+	if (!skb->list) {
+dgram_free:
+		kfree_skb(skb);
+	}
+out:
+	release_sock(sk);
+	return rc ? : copied;
+}
+
+/**
+ *	llc_ui_sendmsg - Transmit data provided by the socket user.
+ *	@sock: Socket to transmit data from.
+ *	@msg: Various user related information.
+ *	@len: Length of data to transmit.
+ *	@scm: Unknown.
+ *
+ *	Transmit data provided by the socket user.
+ *	Returns non-negative upon success, negative otherwise.
+ */
+static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len,
+			  struct scm_cookie *scm)
+{
+	struct sock *sk = sock->sk;
+	struct llc_opt *llc = llc_sk(sk);
+	struct sockaddr_llc *addr = (struct sockaddr_llc *)msg->msg_name;
+	int flags = msg->msg_flags;
+	int noblock = flags & MSG_DONTWAIT;
+	struct net_device *dev;
+	struct sk_buff *skb;
+	int rc = -EINVAL, size = 0, copied = 0, hdrlen;
+
+	dprintk("%s: sending from %02X to %02X\n", __FUNCTION__, llc->laddr.lsap, llc->daddr.lsap);
+	lock_sock(sk);
+	if (addr) {
+		if (msg->msg_namelen < sizeof(*addr))
+			goto release;
+	} else {
+		if (llc_ui_addr_null(&llc->addr))
+			goto release;
+		addr = &llc->addr;
+	}
+	/* must bind connection to sap if user hasn't done it. */
+	if (sk->zapped) {
+		/* bind to sap with null dev, exclusive. */
+		rc = llc_ui_autobind(sock, addr);
+		if (rc)
+			goto release;
+	}
+	if (!llc->dev) {
+		rtnl_lock();
+		dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_smac);
+		rtnl_unlock();
+		rc = -ENETUNREACH;
+		if (!dev)
+			goto release;
+	} else
+		dev = llc->dev;
+	hdrlen = dev->hard_header_len + llc_ui_header_len(sk, addr);
+	size = hdrlen + len;
+	if (size > dev->mtu)
+		size = dev->mtu;
+	copied = size - hdrlen;
+	release_sock(sk);
+	skb = sock_alloc_send_skb(sk, size, noblock, &rc);
+	lock_sock(sk);
+	if (!skb)
+		goto release;
+	skb->sk	      = sk;
+	skb->dev      = dev;
+	skb->protocol = llc_proto_type(addr->sllc_arphrd);
+	skb_reserve(skb, hdrlen); 
+	rc = memcpy_fromiovec(skb_put(skb, copied), msg->msg_iov, copied);
+	if (rc)
+		goto out;
+	if (sk->type == SOCK_DGRAM || addr->sllc_ua) {
+		llc_build_and_send_ui_pkt(llc->sap, skb, addr->sllc_dmac,
+					  addr->sllc_dsap);
+		goto out;
+	}
+	if (addr->sllc_test) {
+		llc_build_and_send_test_pkt(llc->sap, skb, addr->sllc_dmac,
+					    addr->sllc_dsap);
+		goto out;
+	}
+	if (addr->sllc_xid) {
+		llc_build_and_send_xid_pkt(llc->sap, skb, addr->sllc_dmac,
+					   addr->sllc_dsap);
+		goto out;
+	}
+	rc = -ENOPROTOOPT;
+	if (!(sk->type == SOCK_STREAM && !addr->sllc_ua))
+		goto out;
+	rc = llc_ui_send_data(sk, skb, noblock);
+	if (rc)
+		dprintk("%s: llc_ui_send_data failed: %d\n", __FUNCTION__, rc);
+out:
+	if (rc)
+		kfree_skb(skb);
+release:
+	if (rc)
+		dprintk("%s: failed sending from %02X to %02X: %d\n",
+			__FUNCTION__, llc->laddr.lsap, llc->daddr.lsap, rc);
+	release_sock(sk);
+	return rc ? : copied;
+}
+
+/**
+ *	llc_ui_getname - return the address info of a socket
+ *	@sock: Socket to get address of.
+ *	@uaddr: Address structure to return information.
+ *	@uaddrlen: Length of address structure.
+ *	@peer: Does user want local or remote address information.
+ *
+ *	Return the address information of a socket.
+ */
+static int llc_ui_getname(struct socket *sock, struct sockaddr *uaddr,
+			  int *uaddrlen, int peer)
+{
+	struct sockaddr_llc sllc;
+	struct sock *sk = sock->sk;
+	struct llc_opt *llc = llc_sk(sk);
+	int rc = 0;
+
+	lock_sock(sk);
+	if (sk->zapped)
+		goto out;
+	*uaddrlen = sizeof(sllc);
+	memset(uaddr, 0, *uaddrlen);
+	if (peer) {
+		rc = -ENOTCONN;
+		if (sk->state != TCP_ESTABLISHED)
+			goto out;
+		if(llc->dev)
+			sllc.sllc_arphrd = llc->dev->type;
+		sllc.sllc_dsap = llc->daddr.lsap;
+		memcpy(&sllc.sllc_dmac, &llc->daddr.mac, IFHWADDRLEN);
+	} else {
+		rc = -EINVAL;
+		if (!llc->sap)
+			goto out;
+		sllc.sllc_ssap = llc->sap->laddr.lsap;
+
+		if (llc->dev) {
+			sllc.sllc_arphrd = llc->dev->type;
+			memcpy(&sllc.sllc_smac, &llc->dev->dev_addr,
+			       IFHWADDRLEN);
+		}
+	}
+	rc = 0;
+	sllc.sllc_family = AF_LLC;
+	memcpy(uaddr, &sllc, sizeof(sllc));
+out:
+	release_sock(sk);
+	return rc;
+}
+
+/**
+ *	llc_ui_ioctl - io controls for PF_LLC
+ *	@sock: Socket to get/set info
+ *	@cmd: command
+ *	@arg: optional argument for cmd
+ *
+ *	get/set info on llc sockets
+ */
+static int llc_ui_ioctl(struct socket *sock, unsigned int cmd,
+			unsigned long arg)
+{
+	return dev_ioctl(cmd, (void *)arg);
+}
+
+/**
+ *	llc_ui_setsockopt - set various connection specific parameters.
+ *	@sock: Socket to set options on.
+ *	@level: Socket level user is requesting operations on.
+ *	@optname: Operation name.
+ *	@optval User provided operation data.
+ *	@optlen: Length of optval.
+ *
+ *	Set various connection specific parameters.
+ */
+static int llc_ui_setsockopt(struct socket *sock, int level, int optname,
+			     char *optval, int optlen)
+{
+	struct sock *sk = sock->sk;
+	struct llc_opt *llc = llc_sk(sk);
+	int rc = -EINVAL, opt;
+
+	lock_sock(sk);
+	if (level != SOL_LLC || optlen != sizeof(int))
+		goto out;
+	rc = get_user(opt, (int *)optval);
+	if (rc)
+		goto out;
+	rc = -EINVAL;
+	switch (optname) {
+		case LLC_OPT_RETRY:
+			if (opt > LLC_OPT_MAX_RETRY)
+				goto out;
+			llc->n2 = opt;
+			break;
+		case LLC_OPT_SIZE:
+			if (opt > LLC_OPT_MAX_SIZE)
+				goto out;
+			llc->n1 = opt;
+			break;
+		case LLC_OPT_ACK_TMR_EXP:
+			if (opt > LLC_OPT_MAX_ACK_TMR_EXP)
+				goto out;
+			llc->ack_timer.expire = opt;
+			break;
+		case LLC_OPT_P_TMR_EXP:
+			if (opt > LLC_OPT_MAX_P_TMR_EXP)
+				goto out;
+			llc->pf_cycle_timer.expire = opt;
+			break;
+		case LLC_OPT_REJ_TMR_EXP:
+			if (opt > LLC_OPT_MAX_REJ_TMR_EXP)
+				goto out;
+			llc->rej_sent_timer.expire = opt;
+			break;
+		case LLC_OPT_BUSY_TMR_EXP:
+			if (opt > LLC_OPT_MAX_BUSY_TMR_EXP)
+				goto out;
+			llc->busy_state_timer.expire = opt;
+			break;
+		case LLC_OPT_TX_WIN:
+			if (opt > LLC_OPT_MAX_WIN)
+				goto out;
+			llc->k = opt;
+			break;
+		case LLC_OPT_RX_WIN:
+			if (opt > LLC_OPT_MAX_WIN)
+				goto out;
+			llc->rw = opt;
+			break;
+		default:
+			rc = -ENOPROTOOPT;
+			goto out;
+	}
+	rc = 0;
+out:
+	release_sock(sk);
+	return rc;
+}
+
+/**
+ *	llc_ui_getsockopt - get connection specific socket info
+ *	@sock: Socket to get information from.
+ *	@level: Socket level user is requesting operations on.
+ *	@optname: Operation name.
+ *	@optval: Variable to return operation data in.
+ *	@optlen: Length of optval.
+ *
+ *	Get connection specific socket information.
+ */
+static int llc_ui_getsockopt(struct socket *sock, int level, int optname,
+			     char *optval, int *optlen)
+{
+	struct sock *sk = sock->sk;
+	struct llc_opt *llc = llc_sk(sk);
+	int val = 0, len = 0, rc = -EINVAL;
+
+	lock_sock(sk);
+	if (level != SOL_LLC)
+		goto out;
+	rc = get_user(len, optlen);
+	if (rc)
+		goto out;
+	rc = -EINVAL;
+	if (len != sizeof(int))
+		goto out;
+	switch (optname) {
+		case LLC_OPT_RETRY:
+			val = llc->n2;				break;
+		case LLC_OPT_SIZE:
+			val = llc->n1;				break;
+		case LLC_OPT_ACK_TMR_EXP:
+			val = llc->ack_timer.expire;		break;
+		case LLC_OPT_P_TMR_EXP:
+			val = llc->pf_cycle_timer.expire;	break;
+		case LLC_OPT_REJ_TMR_EXP:
+			val = llc->rej_sent_timer.expire;	break;
+		case LLC_OPT_BUSY_TMR_EXP:
+			val = llc->busy_state_timer.expire;	break;
+		case LLC_OPT_TX_WIN:
+			val = llc->k;				break;
+		case LLC_OPT_RX_WIN:
+			val = llc->rw;				break;
+		default:
+			rc = -ENOPROTOOPT;
+			goto out;
+	}
+	rc = 0;
+	if (put_user(len, optlen) || copy_to_user(optval, &val, len))
+		rc = -EFAULT;
+out:
+	release_sock(sk);
+	return rc;
+}
+
+#ifdef CONFIG_PROC_FS
+#define MAC_FORMATTED_SIZE 17
+static void llc_ui_format_mac(char *bf, unsigned char *mac)
+{
+	sprintf(bf, "%02X:%02X:%02X:%02X:%02X:%02X",
+		mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+}
+
+/**
+ *	llc_ui_get_info - return info to procfs
+ *	@buffer: where to put the formatted output
+ *	@start: starting from
+ *	@offset: offset into buffer.
+ *	@length: size of the buffer
+ *
+ *	Get the output of the local llc ui socket list to the caller.
+ *	Returns the length of data wrote to buffer.
+ */
+static int llc_ui_get_info(char *buffer, char **start, off_t offset, int length)
+{
+	off_t pos = 0;
+	off_t begin = 0;
+	struct llc_sap *sap;
+	struct sock *sk;
+	struct list_head *sap_entry;
+	struct llc_station *station = llc_station_get();
+	int len = sprintf(buffer, "SKt Mc local_mac_sap        "
+				  "remote_mac_sap       tx_queue rx_queue st uid "
+				  "link\n");
+
+	/* Output the LLC socket data for the /proc filesystem */
+	read_lock_bh(&station->sap_list.lock);
+	list_for_each(sap_entry, &station->sap_list.list) {
+		sap = list_entry(sap_entry, struct llc_sap, node);
+
+		read_lock_bh(&sap->sk_list.lock);
+		for (sk = sap->sk_list.list; sk; sk = sk->next) {
+			struct llc_opt *llc = llc_sk(sk);
+
+			len += sprintf(buffer + len, "%2X  %2X ", sk->type,
+				       !llc_mac_null(llc->addr.sllc_mmac));
+			if (llc->dev && llc_mac_null(llc->addr.sllc_mmac))
+				llc_ui_format_mac(buffer + len,
+						  llc->dev->dev_addr);
+			else {
+				if (!llc_mac_null(llc->addr.sllc_mmac))
+					llc_ui_format_mac(buffer + len,
+							  llc->addr.sllc_mmac);
+				else
+					sprintf(buffer + len,
+						"00:00:00:00:00:00");
+			}
+			len += MAC_FORMATTED_SIZE;
+			len += sprintf(buffer + len, "@%02X ", sap->laddr.lsap);
+			llc_ui_format_mac(buffer + len, llc->addr.sllc_dmac);
+			len += MAC_FORMATTED_SIZE;
+			len += sprintf(buffer + len,
+					"@%02X %8d %8d %2d %3d ",
+					llc->addr.sllc_dsap,
+					atomic_read(&sk->wmem_alloc),
+					atomic_read(&sk->rmem_alloc),
+					sk->state,
+					sk->socket ?
+					  SOCK_INODE(sk->socket)->i_uid : -1);
+			len += sprintf(buffer + len, "%4d\n", llc->link);
+			/* Are we still dumping unwanted data then discard the record */
+			pos = begin + len;
+
+			if (pos < offset) {
+				len = 0; /* Keep dumping into the buffer start */
+				begin = pos;
+			}
+			if (pos > offset + length) /* We have dumped enough */
+				break;
+		}
+		read_unlock_bh(&sap->sk_list.lock);
+	}
+	read_unlock_bh(&station->sap_list.lock);
+
+	/* The data in question runs from begin to begin + len */
+	*start = buffer + offset - begin; /* Start of wanted data */
+	len -= offset - begin; /* Remove unwanted header data from length */
+	if (len > length)
+		len = length; /* Remove unwanted tail data from length */
+	return len;
+}
+#endif /* CONFIG_PROC_FS */
+
+static struct net_proto_family llc_ui_family_ops = {
+	.family = PF_LLC,
+	.create = llc_ui_create,
+};
+
+static struct proto_ops llc_ui_ops = {
+	.family	     = PF_LLC,
+	.release     = llc_ui_release,
+	.bind	     = llc_ui_bind,
+	.connect     = llc_ui_connect,
+	.socketpair  = sock_no_socketpair,
+	.accept      = llc_ui_accept,
+	.getname     = llc_ui_getname,
+	.poll	     = datagram_poll,
+	.ioctl       = llc_ui_ioctl,
+	.listen      = llc_ui_listen,
+	.shutdown    = llc_ui_shutdown,
+	.setsockopt  = llc_ui_setsockopt,
+	.getsockopt  = llc_ui_getsockopt,
+	.sendmsg     = llc_ui_sendmsg,
+	.recvmsg     = llc_ui_recvmsg,
+	.mmap	     = sock_no_mmap,
+	.sendpage    = sock_no_sendpage,
+};
+
+static char llc_ui_banner[] __initdata =
+	KERN_INFO "NET4.0 IEEE 802.2 BSD sockets, Jay Schulist, 2001, Arnaldo C. Melo, 2002\n";
+
+int __init llc_ui_init(void)
+{
+	llc_ui_sap_last_autoport = LLC_SAP_DYN_START;
+	sock_register(&llc_ui_family_ops);
+	proc_net_create("llc", 0, llc_ui_get_info);
+	printk(llc_ui_banner);
+	return 0;
+}
+
+void __exit llc_ui_exit(void)
+{
+	proc_net_remove("llc");
+	sock_unregister(PF_LLC);
+}
diff -Nru a/net/llc/llc_conn.c b/net/llc/llc_conn.c
--- a/net/llc/llc_conn.c	Tue Oct  1 00:08:15 2002
+++ b/net/llc/llc_conn.c	Tue Oct  1 00:08:15 2002
@@ -340,12 +340,15 @@
 		struct llc_pdu_sn *pdu = (struct llc_pdu_sn *)skb->nh.raw;
 
 		if (!LLC_PDU_TYPE_IS_I(pdu) &&
-		    !(skb->dev->flags & IFF_LOOPBACK))
+		    !(skb->dev->flags & IFF_LOOPBACK)) {
+			struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
+
 			skb_queue_tail(&llc_sk(sk)->pdu_unack_q, skb);
-		mac_send_pdu(skb);
-		if (LLC_PDU_TYPE_IS_I(pdu) ||
-		    (skb->dev && skb->dev->flags & IFF_LOOPBACK))
-			kfree_skb(skb);
+			if (!skb2)
+				break;
+			skb = skb2;
+		}
+		dev_queue_xmit(skb);
 	}
 }
 
diff -Nru a/net/llc/llc_mac.c b/net/llc/llc_mac.c
--- a/net/llc/llc_mac.c	Tue Oct  1 00:08:19 2002
+++ b/net/llc/llc_mac.c	Tue Oct  1 00:08:19 2002
@@ -40,36 +40,6 @@
 static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb);
 
 /**
- *	mac_send_pdu - Sends PDU to specific device.
- *	@skb: pdu which must be sent
- *
- *	If module is not initialized then returns failure, else figures out
- *	where to direct this PDU. Sends PDU to specific device, at this point a
- *	device must has been assigned to the PDU; If not, can't transmit the
- *	PDU. PDU sent to MAC layer, is free to re-send at a later time. Returns
- *	0 on success, 1 for failure.
- */
-int mac_send_pdu(struct sk_buff *skb)
-{
-	struct sk_buff *skb2;
-	int pri = GFP_ATOMIC, rc = -1;
-
-	if (!skb->dev) {
-		dprintk("%s: skb->dev == NULL!", __FUNCTION__);
-		goto out;
-	}
-	if (skb->sk)
-		pri = (int)skb->sk->priority;
-	skb2 = skb_clone(skb, pri);
-	if (!skb2)
-		goto out;
-	rc = 0;
-	dev_queue_xmit(skb2);
-out:
-	return rc;
-}
-
-/**
  *	llc_rcv - 802.2 entry point from net lower layers
  *	@skb: received pdu
  *	@dev: device that receive pdu
diff -Nru a/net/llc/llc_main.c b/net/llc/llc_main.c
--- a/net/llc/llc_main.c	Tue Oct  1 00:08:16 2002
+++ b/net/llc/llc_main.c	Tue Oct  1 00:08:16 2002
@@ -70,7 +70,7 @@
 		memset(sap, 0, sizeof(*sap));
 		sap->state = LLC_SAP_STATE_ACTIVE;
 		memcpy(sap->laddr.mac, llc_main_station.mac_sa, ETH_ALEN);
-		spin_lock_init(&sap->sk_list.lock);
+		rwlock_init(&sap->sk_list.lock);
 	}
 	return sap;
 }
@@ -387,13 +387,9 @@
 {
 	struct sk_buff *skb;
 
-	while ((skb = skb_dequeue(&station->mac_pdu_q)) != NULL) {
-		int rc = mac_send_pdu(skb);
-
-		kfree_skb(skb);
-		if (rc)
+	while ((skb = skb_dequeue(&station->mac_pdu_q)) != NULL)
+		if (dev_queue_xmit(skb))
 			break;
-	}
 }
 
 /**
@@ -639,7 +635,7 @@
 
 	printk(llc_banner);
 	INIT_LIST_HEAD(&llc_main_station.sap_list.list);
-	spin_lock_init(&llc_main_station.sap_list.lock);
+	rwlock_init(&llc_main_station.sap_list.lock);
 	skb_queue_head_init(&llc_main_station.mac_pdu_q);
 	skb_queue_head_init(&llc_main_station.ev_q.list);
 	spin_lock_init(&llc_main_station.ev_q.lock);
diff -Nru a/net/llc/llc_s_ac.c b/net/llc/llc_s_ac.c
--- a/net/llc/llc_s_ac.c	Tue Oct  1 00:08:19 2002
+++ b/net/llc/llc_s_ac.c	Tue Oct  1 00:08:19 2002
@@ -58,7 +58,7 @@
 	llc_pdu_init_as_ui_cmd(skb);
 	rc = lan_hdrs_init(skb, ev->saddr.mac, ev->daddr.mac);
 	if (!rc)
-		llc_sap_send_pdu(sap, skb);
+		rc = dev_queue_xmit(skb);
 	return rc;
 }
 
@@ -81,7 +81,7 @@
 	llc_pdu_init_as_xid_cmd(skb, LLC_XID_NULL_CLASS_2, 0);
 	rc = lan_hdrs_init(skb, ev->saddr.mac, ev->daddr.mac);
 	if (!rc)
-		llc_sap_send_pdu(sap, skb);
+		rc = dev_queue_xmit(skb);
 	return rc;
 }
 
@@ -111,7 +111,7 @@
 	llc_pdu_init_as_xid_rsp(nskb, LLC_XID_NULL_CLASS_2, 0);
 	rc = lan_hdrs_init(nskb, mac_sa, mac_da);
 	if (!rc)
-		llc_sap_send_pdu(sap, nskb);
+		rc = dev_queue_xmit(nskb);
 out:
 	return rc;
 }
@@ -135,7 +135,7 @@
 	llc_pdu_init_as_test_cmd(skb);
 	rc = lan_hdrs_init(skb, ev->saddr.mac, ev->daddr.mac);
 	if (!rc)
-		llc_sap_send_pdu(sap, skb);
+		rc = dev_queue_xmit(skb);
 	return rc;
 }
 
@@ -157,7 +157,7 @@
 	llc_pdu_init_as_test_rsp(nskb, skb);
 	rc = lan_hdrs_init(nskb, mac_sa, mac_da);
 	if (!rc)
-		llc_sap_send_pdu(sap, nskb);
+		rc = dev_queue_xmit(nskb);
 out:
 	return rc;
 }
diff -Nru a/net/llc/llc_sap.c b/net/llc/llc_sap.c
--- a/net/llc/llc_sap.c	Tue Oct  1 00:08:18 2002
+++ b/net/llc/llc_sap.c	Tue Oct  1 00:08:18 2002
@@ -133,17 +133,6 @@
 }
 
 /**
- *	llc_sap_send_pdu - Sends a frame to MAC layer for transmition
- *	@sap: pointer to SAP
- *	@skb: pdu that must be sent
- */
-void llc_sap_send_pdu(struct llc_sap *sap, struct sk_buff *skb)
-{
-	mac_send_pdu(skb);
-	kfree_skb(skb);
-}
-
-/**
  *	llc_sap_next_state - finds transition, execs actions & change SAP state
  *	@sap: pointer to SAP
  *	@skb: happened event
diff -Nru a/net/llc/llc_sock.c b/net/llc/llc_sock.c
--- a/net/llc/llc_sock.c	Tue Oct  1 00:08:14 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,1152 +0,0 @@
-/*
- * llc_sock.c - LLC User Interface SAPs
- * Description:
- *   Functions in this module are implementation of socket based llc
- *   communications for the Linux operating system. Support of llc class
- *   one and class two is provided via SOCK_DGRAM and SOCK_STREAM
- *   respectively.
- *
- *   An llc2 connection is (mac + sap), only one llc2 sap connection
- *   is allowed per mac. Though one sap may have multiple mac + sap
- *   connections.
- *
- * Copyright (c) 2001 by Jay Schulist <jschlst@samba.org>
- *		 2002 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
- *
- * This program can be redistributed or modified under the terms of the
- * GNU General Public License as published by the Free Software Foundation.
- * This program is distributed without any warranty or implied warranty
- * of merchantability or fitness for a particular purpose.
- *
- * See the GNU General Public License for more details.
- */
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <asm/uaccess.h>
-#include <asm/ioctls.h>
-#include <linux/proc_fs.h>
-#include <linux/in.h>
-#include <linux/tcp.h>
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/errno.h>
-#include <net/sock.h>
-#include <net/llc_if.h>
-#include <net/llc_sap.h>
-#include <net/llc_pdu.h>
-#include <net/llc_conn.h>
-#include <net/llc_mac.h>
-#include <net/llc_main.h>
-#include <linux/llc.h>
-#include <linux/if_arp.h>
-#include <linux/rtnetlink.h>
-#include <linux/init.h>
-
-/* remember: uninitialized global data is zeroed because its in .bss */
-static u16 llc_ui_sap_last_autoport = LLC_SAP_DYN_START;
-static u16 llc_ui_sap_link_no_max[256];
-static struct sockaddr_llc llc_ui_addrnull;
-static struct proto_ops llc_ui_ops;
-
-static int llc_ui_wait_for_conn(struct sock *sk, int timeout);
-static int llc_ui_wait_for_disc(struct sock *sk, int timeout);
-static int llc_ui_wait_for_data(struct sock *sk, int timeout);
-static int llc_ui_wait_for_busy_core(struct sock *sk, int timeout);
-
-#if 0
-#define dprintk(args...) printk(KERN_DEBUG args)
-#else
-#define dprintk(args...)
-#endif
-
-/**
- *	llc_ui_next_link_no - return the next unused link number for a sap
- *	@sap: Address of sap to get link number from.
- *
- *	Return the next unused link number for a given sap.
- */
-static __inline__ u16 llc_ui_next_link_no(int sap)
-{
-	return llc_ui_sap_link_no_max[sap]++;
-}
-
-/**
- *	llc_proto_type - return eth protocol for ARP header type
- *	@arphrd: ARP header type.
- *
- *	Given an ARP header type return the corresponding ethernet protocol.
- */
-static __inline__ u16 llc_proto_type(u16 arphrd)
-{
-	return arphrd == ARPHRD_IEEE802_TR ?
-		         htons(ETH_P_TR_802_2) : htons(ETH_P_802_2);
-}
-
-/**
- *	llc_ui_addr_null - determines if a address structure is null
- *	@addr: Address to test if null.
- */
-static __inline__ u8 llc_ui_addr_null(struct sockaddr_llc *addr)
-{
-	return !memcmp(addr, &llc_ui_addrnull, sizeof(*addr));
-}
-
-/**
- *	llc_ui_header_len - return length of llc header based on operation
- *	@sk: Socket which contains a valid llc socket type.
- *	@addr: Complete sockaddr_llc structure received from the user.
- *
- *	Provide the length of the llc header depending on what kind of
- *	operation the user would like to perform and the type of socket.
- *	Returns the correct llc header length.
- */
-static __inline__ u8 llc_ui_header_len(struct sock *sk,
-				       struct sockaddr_llc *addr)
-{
-	u8 rc = LLC_PDU_LEN_U;
-
-	if (addr->sllc_test || addr->sllc_xid)
-		rc = LLC_PDU_LEN_U;
-	else if (sk->type == SOCK_STREAM)
-		rc = LLC_PDU_LEN_I;
-	return rc;
-}
-
-/**
- *	llc_ui_send_data - send data via reliable llc2 connection
- *	@sk: Connection the socket is using.
- *	@skb: Data the user wishes to send.
- *	@addr: Source and destination fields provided by the user.
- *	@noblock: can we block waiting for data?
- *
- *	Send data via reliable llc2 connection.
- *	Returns 0 upon success, non-zero if action did not succeed.
- */
-static int llc_ui_send_data(struct sock* sk, struct sk_buff *skb, int noblock)
-{
-	struct llc_opt* llc = llc_sk(sk);
-	int rc = 0;
-
-	if (llc_data_accept_state(llc->state) || llc->p_flag) {
-		int timeout = sock_sndtimeo(sk, noblock);
-
-		rc = llc_ui_wait_for_busy_core(sk, timeout);
-	}
-	if (!rc)
-		rc = llc_build_and_send_pkt(sk, skb);
-	return rc;
-}
-
-static void llc_ui_sk_init(struct socket *sock, struct sock *sk)
-{
-	sk->type   = sock->type;
-	sk->sleep  = &sock->wait;
-	sk->socket = sock;
-	sock->sk   = sk;
-	sock->ops  = &llc_ui_ops;
-}
-
-/**
- *	llc_ui_create - alloc and init a new llc_ui socket
- *	@sock: Socket to initialize and attach allocated sk to.
- *	@protocol: Unused.
- *
- *	Allocate and initialize a new llc_ui socket, validate the user wants a
- *	socket type we have available.
- *	Returns 0 upon success, negative upon failure.
- */
-static int llc_ui_create(struct socket *sock, int protocol)
-{
-	struct sock *sk;
-	int rc = -ESOCKTNOSUPPORT;
-
-	if (sock->type == SOCK_DGRAM || sock->type == SOCK_STREAM) {
-		rc = -ENOMEM;
-		sk = llc_sk_alloc(PF_LLC, GFP_KERNEL);
-		if (sk) {
-			rc = 0;
-			llc_ui_sk_init(sock, sk);
-		}
-	}
-	return rc;
-}
-
-/**
- *	llc_ui_release - shutdown socket
- *	@sock: Socket to release.
- *
- *	Shutdown and deallocate an existing socket.
- */
-static int llc_ui_release(struct socket *sock)
-{
-	struct sock *sk = sock->sk;
-	struct llc_opt *llc;
-
-	if (!sk)
-		goto out;
-	sock_hold(sk);
-	lock_sock(sk);
-	llc = llc_sk(sk);
-	dprintk("%s: closing local(%02X) remote(%02X)\n", __FUNCTION__,
-		llc->laddr.lsap, llc->daddr.lsap);
-	if (!llc_send_disc(sk))
-		llc_ui_wait_for_disc(sk, sk->rcvtimeo);
-	if (!sk->zapped)
-		llc_sap_unassign_sock(llc->sap, sk);
-	release_sock(sk);
-	if (llc->sap && !llc->sap->sk_list.list)
-		llc_sap_close(llc->sap);
-	sock_put(sk);
-	llc_sk_free(sk);
-out:
-	return 0;
-}
-
-/**
- *	llc_ui_autoport - provide dynamicly allocate SAP number
- *
- *	Provide the caller with a dynamicly allocated SAP number according
- *	to the rules that are set in this function. Returns: 0, upon failure,
- *	SAP number otherwise.
- */
-static int llc_ui_autoport(void)
-{
-	struct llc_sap *sap;
-	int i, tries = 0;
-
-	while (tries < LLC_SAP_DYN_TRIES) {
-		for (i = llc_ui_sap_last_autoport;
-		     i < LLC_SAP_DYN_STOP; i += 2) {
-			sap = llc_sap_find(i);
-			if (!sap) {
-				llc_ui_sap_last_autoport = i + 2;
-				goto out;
-			}
-		}
-		llc_ui_sap_last_autoport = LLC_SAP_DYN_START;
-		tries++;
-	}
-	i = 0;
-out:
-	return i;
-}
-
-/**
- *	llc_ui_autobind - Bind a socket to a specific address.
- *	@sk: Socket to bind an address to.
- *	@addr: Address the user wants the socket bound to.
- *
- *	Bind a socket to a specific address. For llc a user is able to bind to
- *	a specific sap only or mac + sap. If the user only specifies a sap and
- *	a null dmac (all zeros) the user is attempting to bind to an entire
- *	sap. This will stop anyone else on the local system from using that
- *	sap.  If someone else has a mac + sap open the bind to null + sap will
- *	fail.
- *	If the user desires to bind to a specific mac + sap, it is possible to
- *	have multiple sap connections via multiple macs.
- *	Bind and autobind for that matter must enforce the correct sap usage
- *	otherwise all hell will break loose.
- *	Returns: 0 upon success, negative otherwise.
- */
-static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
-{
-	struct sock *sk = sock->sk;
-	struct llc_opt *llc = llc_sk(sk);
-	struct llc_sap *sap;
-	struct net_device *dev = NULL;
-	int rc = -EINVAL;
-
-	if (!sk->zapped)
-		goto out;
-	/* bind to a specific mac, optional. */
-	if (!llc_mac_null(addr->sllc_smac)) {
-		rtnl_lock();
-		dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_smac);
-		rtnl_unlock();
-		rc = -ENETUNREACH;
-		if (!dev)
-			goto out;
-		llc->dev = dev;
-	}
-	/* bind to a specific sap, optional. */
-	if (!addr->sllc_ssap) {
-		rc = -EUSERS;
-		addr->sllc_ssap = llc_ui_autoport();
-		if (!addr->sllc_ssap)
-			goto out;
-	}
-	sap = llc_sap_find(addr->sllc_ssap);
-	if (!sap) {
-		sap = llc_sap_open(addr->sllc_ssap, NULL);
-		rc = -EBUSY; /* some other network layer is using the sap */
-		if (!sap)
-			goto out;
-	} else {
-		struct llc_addr laddr, daddr;
-		struct sock *ask;
-
-		rc = -EUSERS; /* can't get exclusive use of sap */
-		if (!dev && llc_mac_null(addr->sllc_mmac))
-			goto out;
-		memset(&laddr, 0, sizeof(laddr));
-		memset(&daddr, 0, sizeof(daddr));
-		if (!llc_mac_null(addr->sllc_mmac)) {
-			if (sk->type != SOCK_DGRAM) {
-				rc = -EOPNOTSUPP;
-				goto out;
-			}
-			memcpy(laddr.mac, addr->sllc_mmac, IFHWADDRLEN);
-		} else
-			memcpy(laddr.mac, addr->sllc_smac, IFHWADDRLEN);
-		laddr.lsap = addr->sllc_ssap;
-		rc = -EADDRINUSE; /* mac + sap clash. */
-		ask = llc_lookup_established(sap, &daddr, &laddr);
-		if (ask) {
-			sock_put(ask);
-			goto out;
-		}
-	}
-	llc->laddr.lsap = addr->sllc_ssap;
-	if (llc->dev)
-		memcpy(llc->laddr.mac, llc->dev->dev_addr, IFHWADDRLEN);
-	llc->daddr.lsap = addr->sllc_dsap;
-	memcpy(llc->daddr.mac, addr->sllc_dmac, IFHWADDRLEN);
-	memcpy(&llc->addr, addr, sizeof(llc->addr));
-	/* assign new connection to it's SAP */
-	llc_sap_assign_sock(sap, sk);
-	rc = sk->zapped = 0;
-out:
-	return rc;
-}
-
-/**
- *	llc_ui_bind - bind a socket to a specific address.
- *	@sock: Socket to bind an address to.
- *	@uaddr: Address the user wants the socket bound to.
- *	@addrlen: Length of the uaddr structure.
- *
- *	Bind a socket to a specific address. For llc a user is able to bind to
- *	a specific sap only or mac + sap. If the user only specifies a sap and
- *	a null dmac (all zeros) the user is attempting to bind to an entire
- *	sap. This will stop anyone else on the local system from using that
- *	sap. If someone else has a mac + sap open the bind to null + sap will
- *	fail.
- *	If the user desires to bind to a specific mac + sap, it is possible to
- *	have multiple sap connections via multiple macs.
- *	Bind and autobind for that matter must enforce the correct sap usage
- *	otherwise all hell will break loose.
- *	Returns: 0 upon success, negative otherwise.
- */
-static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
-{
-	struct sockaddr_llc *addr = (struct sockaddr_llc *)uaddr;
-	struct sock *sk = sock->sk;
-	int rc = -EINVAL;
-
-	dprintk("%s: binding %02X\n", __FUNCTION__, addr->sllc_ssap);
-	if (!sk->zapped || addrlen != sizeof(*addr))
-		goto out;
-	rc = -EAFNOSUPPORT;
-	if (addr->sllc_family != AF_LLC)
-		goto out;
-	/* use autobind, to avoid code replication. */
-	rc = llc_ui_autobind(sock, addr);
-out:
-	return rc;
-}
-
-/**
- *	llc_ui_shutdown - shutdown a connect llc2 socket.
- *	@sock: Socket to shutdown.
- *	@how: What part of the socket to shutdown.
- *
- *	Shutdown a connected llc2 socket. Currently this function only supports
- *	shutting down both sends and receives (2), we could probably make this
- *	function such that a user can shutdown only half the connection but not
- *	right now.
- *	Returns: 0 upon success, negative otherwise.
- */
-static int llc_ui_shutdown(struct socket *sock, int how)
-{
-	struct sock *sk = sock->sk;
-	int rc = -ENOTCONN;
-
-	lock_sock(sk);
-	if (sk->state != TCP_ESTABLISHED)
-		goto out;
-	rc = -EINVAL;
-	if (how != 2)
-		goto out;
-	rc = llc_send_disc(sk);
-	if (!rc)
-		rc = llc_ui_wait_for_disc(sk, sk->rcvtimeo);
-	/* Wake up anyone sleeping in poll */
-	sk->state_change(sk);
-out:
-	release_sock(sk);
-	return rc;
-}
-
-/**
- *	llc_ui_connect - Connect to a remote llc2 mac + sap.
- *	@sock: Socket which will be connected to the remote destination.
- *	@uaddr: Remote and possibly the local address of the new connection.
- *	@addrlen: Size of uaddr structure.
- *	@flags: Operational flags specified by the user.
- *
- *	Connect to a remote llc2 mac + sap. The caller must specify the
- *	destination mac and address to connect to. If the user previously
- *	called bind(2) with a smac the user does not need to specify the source
- *	address and mac.
- *	This function will autobind if user did not previously call bind.
- *	Returns: 0 upon success, negative otherwise.
- */
-static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr,
-			  int addrlen, int flags)
-{
-	struct sock *sk = sock->sk;
-	struct llc_opt *llc = llc_sk(sk);
-	struct sockaddr_llc *addr = (struct sockaddr_llc *)uaddr;
-	struct net_device *dev;
-	int rc = -EINVAL;
-
-	lock_sock(sk);
-	if (addrlen != sizeof(*addr))
-		goto out;
-	rc = -EAFNOSUPPORT;
-	if (addr->sllc_family != AF_LLC)
-		goto out;
-	/* bind connection to sap if user hasn't done it. */
-	if (sk->zapped) {
-		/* bind to sap with null dev, exclusive */
-		rc = llc_ui_autobind(sock, addr);
-		if (rc)
-			goto out;
-	}
-	if (!llc->dev) {
-		rtnl_lock();
-		dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_smac);
-		rtnl_unlock();
-		if (!dev)
-			goto out;
-		llc->dev = dev;
-	} else
-		dev = llc->dev;
-	if (sk->type != SOCK_STREAM)
-		goto out;
-	rc = -EALREADY;
-	if (sock->state == SS_CONNECTING)
-		goto out;
-	sock->state = SS_CONNECTING;
-	sk->state   = TCP_SYN_SENT;
-	llc->link   = llc_ui_next_link_no(llc->sap->laddr.lsap);
-	rc = llc_establish_connection(sk, dev->dev_addr,
-				      addr->sllc_dmac, addr->sllc_dsap);
-	if (rc) {
-		dprintk("%s: llc_ui_send_conn failed :-(\n", __FUNCTION__);
-		sock->state = SS_UNCONNECTED;
-		sk->state   = TCP_CLOSE;
-		goto out;
-	}
-	rc = llc_ui_wait_for_conn(sk, sk->rcvtimeo);
-	if (rc)
-		dprintk("%s: llc_ui_wait_for_conn failed=%d\n", __FUNCTION__, rc);
-out:
-	release_sock(sk);
-	return rc;
-}
-
-/**
- *	llc_ui_listen - allow a normal socket to accept incoming connections
- *	@sock: Socket to allow incoming connections on.
- *	@backlog: Number of connections to queue.
- *
- *	Allow a normal socket to accept incoming connections.
- *	Returns 0 upon success, negative otherwise.
- */
-static int llc_ui_listen(struct socket *sock, int backlog)
-{
-	struct sock *sk = sock->sk;
-	int rc = -EINVAL;
-
-	lock_sock(sk);
-	if (sock->state != SS_UNCONNECTED)
-		goto out;
-	rc = -EOPNOTSUPP;
-	if (sk->type != SOCK_STREAM)
-		goto out;
-	rc = -EAGAIN;
-	if (sk->zapped)
-		goto out;
-	rc = 0;
-	if (!(unsigned)backlog)	/* BSDism */
-		backlog = 1;
-	sk->max_ack_backlog = backlog;
-	if (sk->state != TCP_LISTEN) {
-		sk->ack_backlog = 0;
-		sk->state = TCP_LISTEN;
-	}
-	sk->socket->flags |= __SO_ACCEPTCON;
-out:
-	release_sock(sk);
-	return rc;
-}
-
-static int llc_ui_wait_for_disc(struct sock *sk, int timeout)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	int rc;
-
-	add_wait_queue_exclusive(sk->sleep, &wait);
-	for (;;) {
-		__set_current_state(TASK_INTERRUPTIBLE);
-		rc = -ERESTARTSYS;
-		if (signal_pending(current))
-			break;
-		rc = -EAGAIN;
-		if (!timeout)
-			break;
-		rc = 0;
-		if (sk->state != TCP_CLOSE) {
-			release_sock(sk);
-			timeout = schedule_timeout(timeout);
-			lock_sock(sk);
-		} else
-			break;
-	}
-	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(sk->sleep, &wait);
-	return rc;
-}
-
-static int llc_ui_wait_for_conn(struct sock *sk, int timeout)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	int rc;
-
-	add_wait_queue_exclusive(sk->sleep, &wait);
-	for (;;) {
-		__set_current_state(TASK_INTERRUPTIBLE);
-		rc = -EAGAIN;
-		if (sk->state == TCP_CLOSE)
-			break;
-		rc = -ERESTARTSYS;
-		if (signal_pending(current))
-			break;
-		rc = -EAGAIN;
-		if (!timeout)
-			break;
-		rc = 0;
-		if (sk->state != TCP_ESTABLISHED) {
-			release_sock(sk);
-			timeout = schedule_timeout(timeout);
-			lock_sock(sk);
-		} else
-			break;
-	}
-	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(sk->sleep, &wait);
-	return rc;
-}
-
-static int llc_ui_wait_for_data(struct sock *sk, int timeout)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	int rc = 0;
-
-	add_wait_queue_exclusive(sk->sleep, &wait);
-	for (;;) {
-		__set_current_state(TASK_INTERRUPTIBLE);
-		if (sk->shutdown & RCV_SHUTDOWN)
-			break;
-		rc = -ERESTARTSYS;
-		if (signal_pending(current))
-			break;
-		rc = -EAGAIN;
-		if (!timeout)
-			break;
-		rc = 0;
-		if (skb_queue_empty(&sk->receive_queue)) {
-			release_sock(sk);
-			timeout = schedule_timeout(timeout);
-			lock_sock(sk);
-		} else
-			break;
-	}
-	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(sk->sleep, &wait);
-	return rc;
-}
-
-static int llc_ui_wait_for_busy_core(struct sock *sk, int timeout)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	struct llc_opt *llc = llc_sk(sk);
-	int rc;
-
-	add_wait_queue_exclusive(sk->sleep, &wait);
-	for (;;) {
-		dprintk("%s: looping...\n", __FUNCTION__);
-		__set_current_state(TASK_INTERRUPTIBLE);
-		rc = -ENOTCONN;
-		if (sk->shutdown & RCV_SHUTDOWN)
-			break;
-		rc = -ERESTARTSYS;
-		if (signal_pending(current))
-			break;
-		rc = -EAGAIN;
-		if (!timeout)
-			break;
-		rc = 0;
-		if (llc_data_accept_state(llc->state) || llc->p_flag) {
-			release_sock(sk);
-			timeout = schedule_timeout(timeout);
-			lock_sock(sk);
-		} else
-			break;
-	}
-	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(sk->sleep, &wait);
-	return rc;
-}
-
-/**
- *	llc_ui_accept - accept a new incoming connection.
- *	@sock: Socket which connections arrive on.
- *	@newsock: Socket to move incoming connection to.
- *	@flags: User specified operational flags.
- *
- *	Accept a new incoming connection.
- *	Returns 0 upon success, negative otherwise.
- */
-static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags)
-{
-	struct sock *sk = sock->sk, *newsk;
-	struct llc_opt *llc, *newllc;
-	struct sk_buff *skb;
-	int rc = -EOPNOTSUPP;
-
-	dprintk("%s: accepting on %02X\n", __FUNCTION__, llc_sk(sk)->addr.sllc_ssap);
-	lock_sock(sk);
-	if (sk->type != SOCK_STREAM)
-		goto out;
-	rc = -EINVAL;
-	if (sock->state != SS_UNCONNECTED || sk->state != TCP_LISTEN)
-		goto out;
-	/* wait for a connection to arrive. */
-	rc = llc_ui_wait_for_data(sk, sk->rcvtimeo);
-	if (rc)
-		goto out;
-	dprintk("%s: got a new connection on %02X\n", __FUNCTION__, llc_sk(sk)->addr.sllc_ssap);
-	skb = skb_dequeue(&sk->receive_queue);
-	rc = -EINVAL;
-	if (!skb->sk)
-		goto frees;
-	rc = 0;
-	newsk = skb->sk;
-	/* attach connection to a new socket. */
-	llc_ui_sk_init(newsock, newsk);
-	newsk->pair		= NULL;
-	newsk->zapped		= 0;
-	newsk->state		= TCP_ESTABLISHED;
-	newsock->state		= SS_CONNECTED;
-	llc			= llc_sk(sk);
-	newllc			= llc_sk(newsk);
-	memcpy(&newllc->addr, &llc->addr, sizeof(newllc->addr));
-	memcpy(newllc->addr.sllc_dmac, newllc->daddr.mac, IFHWADDRLEN);
-	newllc->addr.sllc_dsap = newllc->daddr.lsap;
-	newllc->link = llc_ui_next_link_no(newllc->laddr.lsap);
-
-	/* put original socket back into a clean listen state. */
-	sk->state = TCP_LISTEN;
-	sk->ack_backlog--;
-	skb->sk = NULL;
-	dprintk("%s: ok success on %02X, client on %02X\n", __FUNCTION__,
-		llc_sk(sk)->addr.sllc_ssap, newllc->addr.sllc_dsap);
-frees:
-	kfree_skb(skb);
-out:
-	release_sock(sk);
-	return rc;
-}
-
-/**
- *	llc_ui_recvmsg - copy received data to the socket user.
- *	@sock: Socket to copy data from.
- *	@msg: Various user space related information.
- *	@size: Size of user buffer.
- *	@flags: User specified flags.
- *	@scm: Unknown.
- *
- *	Copy received data to the socket user.
- *	Returns non-negative upon success, negative otherwise.
- */
-static int llc_ui_recvmsg(struct socket *sock, struct msghdr *msg, int size,
-			  int flags, struct scm_cookie *scm)
-{
-	struct sock *sk = sock->sk;
-	struct sockaddr_llc *uaddr = (struct sockaddr_llc *)msg->msg_name;
-	struct sk_buff *skb;
-	int rc = -ENOMEM, copied = 0, timeout;
-	int noblock = flags & MSG_DONTWAIT;
-
-	dprintk("%s: receiving in %02X from %02X\n", __FUNCTION__,
-		llc_sk(sk)->laddr.lsap, llc_sk(sk)->daddr.lsap);
-	lock_sock(sk);
-	timeout = sock_rcvtimeo(sk, noblock);
-	rc = llc_ui_wait_for_data(sk, timeout);
-	if (rc) {
-		dprintk("%s: llc_ui_wait_for_data failed recv in %02X from %02X\n",
-			__FUNCTION__, llc_sk(sk)->laddr.lsap, llc_sk(sk)->daddr.lsap);
-		goto out;
-	}
-	skb = skb_dequeue(&sk->receive_queue);
-	if (!skb) /* shutdown */
-		goto out;
-	copied = skb->len;
-	if (copied > size)
-		copied = size;
-	rc = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
-	if (rc)
-		goto dgram_free;
-	if (skb->len > copied) {
-		skb_pull(skb, copied);
-		skb_queue_head(&sk->receive_queue, skb);
-	}
-	if (uaddr)
-		memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr));
-	msg->msg_namelen = sizeof(*uaddr);
-	if (!skb->list) {
-dgram_free:
-		kfree_skb(skb);
-	}
-out:
-	release_sock(sk);
-	return rc ? : copied;
-}
-
-/**
- *	llc_ui_sendmsg - Transmit data provided by the socket user.
- *	@sock: Socket to transmit data from.
- *	@msg: Various user related information.
- *	@len: Length of data to transmit.
- *	@scm: Unknown.
- *
- *	Transmit data provided by the socket user.
- *	Returns non-negative upon success, negative otherwise.
- */
-static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len,
-			  struct scm_cookie *scm)
-{
-	struct sock *sk = sock->sk;
-	struct llc_opt *llc = llc_sk(sk);
-	struct sockaddr_llc *addr = (struct sockaddr_llc *)msg->msg_name;
-	int flags = msg->msg_flags;
-	int noblock = flags & MSG_DONTWAIT;
-	struct net_device *dev;
-	struct sk_buff *skb;
-	int rc = -EINVAL, size = 0, copied = 0, hdrlen;
-
-	dprintk("%s: sending from %02X to %02X\n", __FUNCTION__, llc->laddr.lsap, llc->daddr.lsap);
-	lock_sock(sk);
-	if (addr) {
-		if (msg->msg_namelen < sizeof(*addr))
-			goto release;
-	} else {
-		if (llc_ui_addr_null(&llc->addr))
-			goto release;
-		addr = &llc->addr;
-	}
-	/* must bind connection to sap if user hasn't done it. */
-	if (sk->zapped) {
-		/* bind to sap with null dev, exclusive. */
-		rc = llc_ui_autobind(sock, addr);
-		if (rc)
-			goto release;
-	}
-	if (!llc->dev) {
-		rtnl_lock();
-		dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_smac);
-		rtnl_unlock();
-		rc = -ENETUNREACH;
-		if (!dev)
-			goto release;
-	} else
-		dev = llc->dev;
-	hdrlen = dev->hard_header_len + llc_ui_header_len(sk, addr);
-	size = hdrlen + len;
-	if (size > dev->mtu)
-		size = dev->mtu;
-	copied = size - hdrlen;
-	release_sock(sk);
-	skb = sock_alloc_send_skb(sk, size, noblock, &rc);
-	lock_sock(sk);
-	if (!skb)
-		goto release;
-	skb->sk	      = sk;
-	skb->dev      = dev;
-	skb->protocol = llc_proto_type(addr->sllc_arphrd);
-	skb_reserve(skb, hdrlen); 
-	rc = memcpy_fromiovec(skb_put(skb, copied), msg->msg_iov, copied);
-	if (rc)
-		goto out;
-	if (sk->type == SOCK_DGRAM || addr->sllc_ua) {
-		llc_build_and_send_ui_pkt(llc->sap, skb, addr->sllc_dmac,
-					  addr->sllc_dsap);
-		goto out;
-	}
-	if (addr->sllc_test) {
-		llc_build_and_send_test_pkt(llc->sap, skb, addr->sllc_dmac,
-					    addr->sllc_dsap);
-		goto out;
-	}
-	if (addr->sllc_xid) {
-		llc_build_and_send_xid_pkt(llc->sap, skb, addr->sllc_dmac,
-					   addr->sllc_dsap);
-		goto out;
-	}
-	rc = -ENOPROTOOPT;
-	if (!(sk->type == SOCK_STREAM && !addr->sllc_ua))
-		goto out;
-	rc = llc_ui_send_data(sk, skb, noblock);
-	if (rc)
-		dprintk("%s: llc_ui_send_data failed: %d\n", __FUNCTION__, rc);
-out:
-	if (rc)
-		kfree_skb(skb);
-release:
-	if (rc)
-		dprintk("%s: failed sending from %02X to %02X: %d\n",
-			__FUNCTION__, llc->laddr.lsap, llc->daddr.lsap, rc);
-	release_sock(sk);
-	return rc ? : copied;
-}
-
-/**
- *	llc_ui_getname - return the address info of a socket
- *	@sock: Socket to get address of.
- *	@uaddr: Address structure to return information.
- *	@uaddrlen: Length of address structure.
- *	@peer: Does user want local or remote address information.
- *
- *	Return the address information of a socket.
- */
-static int llc_ui_getname(struct socket *sock, struct sockaddr *uaddr,
-			  int *uaddrlen, int peer)
-{
-	struct sockaddr_llc sllc;
-	struct sock *sk = sock->sk;
-	struct llc_opt *llc = llc_sk(sk);
-	int rc = 0;
-
-	lock_sock(sk);
-	if (sk->zapped)
-		goto out;
-	*uaddrlen = sizeof(sllc);
-	memset(uaddr, 0, *uaddrlen);
-	if (peer) {
-		rc = -ENOTCONN;
-		if (sk->state != TCP_ESTABLISHED)
-			goto out;
-		if(llc->dev)
-			sllc.sllc_arphrd = llc->dev->type;
-		sllc.sllc_dsap = llc->daddr.lsap;
-		memcpy(&sllc.sllc_dmac, &llc->daddr.mac, IFHWADDRLEN);
-	} else {
-		rc = -EINVAL;
-		if (!llc->sap)
-			goto out;
-		sllc.sllc_ssap = llc->sap->laddr.lsap;
-
-		if (llc->dev) {
-			sllc.sllc_arphrd = llc->dev->type;
-			memcpy(&sllc.sllc_smac, &llc->dev->dev_addr,
-			       IFHWADDRLEN);
-		}
-	}
-	rc = 0;
-	sllc.sllc_family = AF_LLC;
-	memcpy(uaddr, &sllc, sizeof(sllc));
-out:
-	release_sock(sk);
-	return rc;
-}
-
-/**
- *	llc_ui_ioctl - io controls for PF_LLC
- *	@sock: Socket to get/set info
- *	@cmd: command
- *	@arg: optional argument for cmd
- *
- *	get/set info on llc sockets
- */
-static int llc_ui_ioctl(struct socket *sock, unsigned int cmd,
-			unsigned long arg)
-{
-	return dev_ioctl(cmd, (void *)arg);
-}
-
-/**
- *	llc_ui_setsockopt - set various connection specific parameters.
- *	@sock: Socket to set options on.
- *	@level: Socket level user is requesting operations on.
- *	@optname: Operation name.
- *	@optval User provided operation data.
- *	@optlen: Length of optval.
- *
- *	Set various connection specific parameters.
- */
-static int llc_ui_setsockopt(struct socket *sock, int level, int optname,
-			     char *optval, int optlen)
-{
-	struct sock *sk = sock->sk;
-	struct llc_opt *llc = llc_sk(sk);
-	int rc = -EINVAL, opt;
-
-	lock_sock(sk);
-	if (level != SOL_LLC || optlen != sizeof(int))
-		goto out;
-	rc = get_user(opt, (int *)optval);
-	if (rc)
-		goto out;
-	rc = -EINVAL;
-	switch (optname) {
-		case LLC_OPT_RETRY:
-			if (opt > LLC_OPT_MAX_RETRY)
-				goto out;
-			llc->n2 = opt;
-			break;
-		case LLC_OPT_SIZE:
-			if (opt > LLC_OPT_MAX_SIZE)
-				goto out;
-			llc->n1 = opt;
-			break;
-		case LLC_OPT_ACK_TMR_EXP:
-			if (opt > LLC_OPT_MAX_ACK_TMR_EXP)
-				goto out;
-			llc->ack_timer.expire = opt;
-			break;
-		case LLC_OPT_P_TMR_EXP:
-			if (opt > LLC_OPT_MAX_P_TMR_EXP)
-				goto out;
-			llc->pf_cycle_timer.expire = opt;
-			break;
-		case LLC_OPT_REJ_TMR_EXP:
-			if (opt > LLC_OPT_MAX_REJ_TMR_EXP)
-				goto out;
-			llc->rej_sent_timer.expire = opt;
-			break;
-		case LLC_OPT_BUSY_TMR_EXP:
-			if (opt > LLC_OPT_MAX_BUSY_TMR_EXP)
-				goto out;
-			llc->busy_state_timer.expire = opt;
-			break;
-		case LLC_OPT_TX_WIN:
-			if (opt > LLC_OPT_MAX_WIN)
-				goto out;
-			llc->k = opt;
-			break;
-		case LLC_OPT_RX_WIN:
-			if (opt > LLC_OPT_MAX_WIN)
-				goto out;
-			llc->rw = opt;
-			break;
-		default:
-			rc = -ENOPROTOOPT;
-			goto out;
-	}
-	rc = 0;
-out:
-	release_sock(sk);
-	return rc;
-}
-
-/**
- *	llc_ui_getsockopt - get connection specific socket info
- *	@sock: Socket to get information from.
- *	@level: Socket level user is requesting operations on.
- *	@optname: Operation name.
- *	@optval: Variable to return operation data in.
- *	@optlen: Length of optval.
- *
- *	Get connection specific socket information.
- */
-static int llc_ui_getsockopt(struct socket *sock, int level, int optname,
-			     char *optval, int *optlen)
-{
-	struct sock *sk = sock->sk;
-	struct llc_opt *llc = llc_sk(sk);
-	int val = 0, len = 0, rc = -EINVAL;
-
-	lock_sock(sk);
-	if (level != SOL_LLC)
-		goto out;
-	rc = get_user(len, optlen);
-	if (rc)
-		goto out;
-	rc = -EINVAL;
-	if (len != sizeof(int))
-		goto out;
-	switch (optname) {
-		case LLC_OPT_RETRY:
-			val = llc->n2;				break;
-		case LLC_OPT_SIZE:
-			val = llc->n1;				break;
-		case LLC_OPT_ACK_TMR_EXP:
-			val = llc->ack_timer.expire;		break;
-		case LLC_OPT_P_TMR_EXP:
-			val = llc->pf_cycle_timer.expire;	break;
-		case LLC_OPT_REJ_TMR_EXP:
-			val = llc->rej_sent_timer.expire;	break;
-		case LLC_OPT_BUSY_TMR_EXP:
-			val = llc->busy_state_timer.expire;	break;
-		case LLC_OPT_TX_WIN:
-			val = llc->k;				break;
-		case LLC_OPT_RX_WIN:
-			val = llc->rw;				break;
-		default:
-			rc = -ENOPROTOOPT;
-			goto out;
-	}
-	rc = 0;
-	if (put_user(len, optlen) || copy_to_user(optval, &val, len))
-		rc = -EFAULT;
-out:
-	release_sock(sk);
-	return rc;
-}
-
-#ifdef CONFIG_PROC_FS
-#define MAC_FORMATTED_SIZE 17
-static void llc_ui_format_mac(char *bf, unsigned char *mac)
-{
-	sprintf(bf, "%02X:%02X:%02X:%02X:%02X:%02X",
-		mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
-}
-
-/**
- *	llc_ui_get_info - return info to procfs
- *	@buffer: where to put the formatted output
- *	@start: starting from
- *	@offset: offset into buffer.
- *	@length: size of the buffer
- *
- *	Get the output of the local llc ui socket list to the caller.
- *	Returns the length of data wrote to buffer.
- */
-static int llc_ui_get_info(char *buffer, char **start, off_t offset, int length)
-{
-	off_t pos = 0;
-	off_t begin = 0;
-	struct llc_sap *sap;
-	struct sock *sk;
-	struct list_head *sap_entry;
-	struct llc_station *station = llc_station_get();
-	int len = sprintf(buffer, "SKt Mc local_mac_sap        "
-				  "remote_mac_sap       tx_queue rx_queue st uid "
-				  "link\n");
-
-	/* Output the LLC socket data for the /proc filesystem */
-	read_lock_bh(&station->sap_list.lock);
-	list_for_each(sap_entry, &station->sap_list.list) {
-		sap = list_entry(sap_entry, struct llc_sap, node);
-
-		read_lock_bh(&sap->sk_list.lock);
-		for (sk = sap->sk_list.list; sk; sk = sk->next) {
-			struct llc_opt *llc = llc_sk(sk);
-
-			len += sprintf(buffer + len, "%2X  %2X ", sk->type,
-				       !llc_mac_null(llc->addr.sllc_mmac));
-			if (llc->dev && llc_mac_null(llc->addr.sllc_mmac))
-				llc_ui_format_mac(buffer + len,
-						  llc->dev->dev_addr);
-			else {
-				if (!llc_mac_null(llc->addr.sllc_mmac))
-					llc_ui_format_mac(buffer + len,
-							  llc->addr.sllc_mmac);
-				else
-					sprintf(buffer + len,
-						"00:00:00:00:00:00");
-			}
-			len += MAC_FORMATTED_SIZE;
-			len += sprintf(buffer + len, "@%02X ", sap->laddr.lsap);
-			llc_ui_format_mac(buffer + len, llc->addr.sllc_dmac);
-			len += MAC_FORMATTED_SIZE;
-			len += sprintf(buffer + len,
-					"@%02X %8d %8d %2d %3d ",
-					llc->addr.sllc_dsap,
-					atomic_read(&sk->wmem_alloc),
-					atomic_read(&sk->rmem_alloc),
-					sk->state,
-					sk->socket ?
-					  SOCK_INODE(sk->socket)->i_uid : -1);
-			len += sprintf(buffer + len, "%4d\n", llc->link);
-			/* Are we still dumping unwanted data then discard the record */
-			pos = begin + len;
-
-			if (pos < offset) {
-				len = 0; /* Keep dumping into the buffer start */
-				begin = pos;
-			}
-			if (pos > offset + length) /* We have dumped enough */
-				break;
-		}
-		read_unlock_bh(&sap->sk_list.lock);
-	}
-	read_unlock_bh(&station->sap_list.lock);
-
-	/* The data in question runs from begin to begin + len */
-	*start = buffer + offset - begin; /* Start of wanted data */
-	len -= offset - begin; /* Remove unwanted header data from length */
-	if (len > length)
-		len = length; /* Remove unwanted tail data from length */
-	return len;
-}
-#endif /* CONFIG_PROC_FS */
-
-static struct net_proto_family llc_ui_family_ops = {
-	.family = PF_LLC,
-	.create = llc_ui_create,
-};
-
-static struct proto_ops llc_ui_ops = {
-	.family	     = PF_LLC,
-	.release     = llc_ui_release,
-	.bind	     = llc_ui_bind,
-	.connect     = llc_ui_connect,
-	.socketpair  = sock_no_socketpair,
-	.accept      = llc_ui_accept,
-	.getname     = llc_ui_getname,
-	.poll	     = datagram_poll,
-	.ioctl       = llc_ui_ioctl,
-	.listen      = llc_ui_listen,
-	.shutdown    = llc_ui_shutdown,
-	.setsockopt  = llc_ui_setsockopt,
-	.getsockopt  = llc_ui_getsockopt,
-	.sendmsg     = llc_ui_sendmsg,
-	.recvmsg     = llc_ui_recvmsg,
-	.mmap	     = sock_no_mmap,
-	.sendpage    = sock_no_sendpage,
-};
-
-static char llc_ui_banner[] __initdata =
-	KERN_INFO "NET4.0 IEEE 802.2 BSD sockets, Jay Schulist, 2001, Arnaldo C. Melo, 2002\n";
-
-int __init llc_ui_init(void)
-{
-	llc_ui_sap_last_autoport = LLC_SAP_DYN_START;
-	sock_register(&llc_ui_family_ops);
-	proc_net_create("llc", 0, llc_ui_get_info);
-	printk(llc_ui_banner);
-	return 0;
-}
-
-void __exit llc_ui_exit(void)
-{
-	proc_net_remove("llc");
-	sock_unregister(PF_LLC);
-}
diff -Nru a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
--- a/net/sunrpc/clnt.c	Tue Oct  1 00:08:16 2002
+++ b/net/sunrpc/clnt.c	Tue Oct  1 00:08:16 2002
@@ -226,21 +226,21 @@
 		if (action[SIGQUIT-1].sa.sa_handler == SIG_DFL)
 			sigallow |= sigmask(SIGQUIT);
 	}
-	spin_lock_irqsave(&current->sigmask_lock, irqflags);
+	spin_lock_irqsave(&current->sig->siglock, irqflags);
 	*oldset = current->blocked;
 	siginitsetinv(&current->blocked, sigallow & ~oldset->sig[0]);
 	recalc_sigpending();
-	spin_unlock_irqrestore(&current->sigmask_lock, irqflags);
+	spin_unlock_irqrestore(&current->sig->siglock, irqflags);
 }
 
 void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset)
 {
 	unsigned long	irqflags;
 	
-	spin_lock_irqsave(&current->sigmask_lock, irqflags);
+	spin_lock_irqsave(&current->sig->siglock, irqflags);
 	current->blocked = *oldset;
 	recalc_sigpending();
-	spin_unlock_irqrestore(&current->sigmask_lock, irqflags);
+	spin_unlock_irqrestore(&current->sig->siglock, irqflags);
 }
 
 /*
diff -Nru a/net/sunrpc/sched.c b/net/sunrpc/sched.c
--- a/net/sunrpc/sched.c	Tue Oct  1 00:08:17 2002
+++ b/net/sunrpc/sched.c	Tue Oct  1 00:08:17 2002
@@ -992,10 +992,10 @@
 
 	daemonize();
 
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	siginitsetinv(&current->blocked, sigmask(SIGKILL));
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	strcpy(current->comm, "rpciod");
 
@@ -1050,9 +1050,9 @@
 		}
 	}
 
-	spin_lock_irqsave(&current->sigmask_lock, flags);
+	spin_lock_irqsave(&current->sig->siglock, flags);
 	recalc_sigpending();
-	spin_unlock_irqrestore(&current->sigmask_lock, flags);
+	spin_unlock_irqrestore(&current->sig->siglock, flags);
 }
 
 /*
@@ -1128,9 +1128,9 @@
 		}
 		interruptible_sleep_on(&rpciod_killer);
 	}
-	spin_lock_irqsave(&current->sigmask_lock, flags);
+	spin_lock_irqsave(&current->sig->siglock, flags);
 	recalc_sigpending();
-	spin_unlock_irqrestore(&current->sigmask_lock, flags);
+	spin_unlock_irqrestore(&current->sig->siglock, flags);
 out:
 	up(&rpciod_sema);
 	MOD_DEC_USE_COUNT;
diff -Nru a/net/sunrpc/svc.c b/net/sunrpc/svc.c
--- a/net/sunrpc/svc.c	Tue Oct  1 00:08:20 2002
+++ b/net/sunrpc/svc.c	Tue Oct  1 00:08:20 2002
@@ -213,9 +213,9 @@
 	}
 
 	if (!port) {
-		spin_lock_irqsave(&current->sigmask_lock, flags);
+		spin_lock_irqsave(&current->sig->siglock, flags);
 		recalc_sigpending();
-		spin_unlock_irqrestore(&current->sigmask_lock, flags);
+		spin_unlock_irqrestore(&current->sig->siglock, flags);
 	}
 
 	return error;
diff -Nru a/net/x25/af_x25.c b/net/x25/af_x25.c
--- a/net/x25/af_x25.c	Tue Oct  1 00:08:20 2002
+++ b/net/x25/af_x25.c	Tue Oct  1 00:08:20 2002
@@ -65,7 +65,8 @@
 int sysctl_x25_clear_request_timeout   = X25_DEFAULT_T23;
 int sysctl_x25_ack_holdback_timeout    = X25_DEFAULT_T2;
 
-static struct sock *volatile x25_list /* = NULL initially */;
+static struct sock *x25_list;
+static rwlock_t x25_list_lock = RW_LOCK_UNLOCKED;
 
 static struct proto_ops x25_proto_ops;
 
@@ -152,22 +153,22 @@
 static void x25_remove_socket(struct sock *sk)
 {
 	struct sock *s;
-	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	write_lock_bh(&x25_list_lock);
 
 	if ((s = x25_list) == sk)
 		x25_list = s->next;
 	else while (s && s->next) {
 		if (s->next == sk) {
 			s->next = sk->next;
+			sock_put(sk);
 			break;
 		}
 
 		s = s->next;
 	}
-	restore_flags(flags);
+
+	write_unlock_bh(&x25_list_lock);
 }
 
 /*
@@ -177,18 +178,23 @@
 {
 	struct sock *s;
 
+	write_lock_bh(&x25_list_lock);
+
 	for (s = x25_list; s; s = s->next)
 		if (x25_sk(s)->neighbour && x25_sk(s)->neighbour->dev == dev)
 			x25_disconnect(s, ENETUNREACH, 0, 0);
+
+	write_unlock_bh(&x25_list_lock);
 }
 
 /*
  *	Handle device status changes.
  */
-static int x25_device_event(struct notifier_block *this, unsigned long event, void *ptr)
+static int x25_device_event(struct notifier_block *this, unsigned long event,
+			    void *ptr)
 {
 	struct net_device *dev = ptr;
-	struct x25_neigh *neigh;
+	struct x25_neigh *nb;
 
 	if (dev->type == ARPHRD_X25
 #if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE)
@@ -200,8 +206,11 @@
 				x25_link_device_up(dev);
 				break;
 			case NETDEV_GOING_DOWN:
-				if ((neigh = x25_get_neigh(dev)))
-					x25_terminate_link(neigh);
+				nb = x25_get_neigh(dev);
+				if (nb) {
+					x25_terminate_link(nb);
+					x25_neigh_put(nb);
+				}
 				break;
 			case NETDEV_DOWN:
 				x25_kill_by_device(dev);
@@ -219,15 +228,11 @@
  */
 static void x25_insert_socket(struct sock *sk)
 {
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-
+	write_lock_bh(&x25_list_lock);
 	sk->next = x25_list;
 	x25_list = sk;
-
-	restore_flags(flags);
+	sock_hold(sk);
+	write_unlock_bh(&x25_list_lock);
 }
 
 /*
@@ -236,11 +241,9 @@
  */
 static struct sock *x25_find_listener(struct x25_address *addr)
 {
-	unsigned long flags;
 	struct sock *s;
 
-	save_flags(flags);
-	cli();
+	read_lock_bh(&x25_list_lock);
 
 	for (s = x25_list; s; s = s->next)
 		if ((!strcmp(addr->x25_addr, x25_sk(s)->source_addr.x25_addr) ||
@@ -248,42 +251,56 @@
 		     s->state == TCP_LISTEN)
 			break;
 
-	restore_flags(flags);
+	if (s)
+		sock_hold(s);
+	read_unlock_bh(&x25_list_lock);
 	return s;
 }
 
 /*
  *	Find a connected X.25 socket given my LCI and neighbour.
  */
-struct sock *x25_find_socket(unsigned int lci, struct x25_neigh *neigh)
+struct sock *__x25_find_socket(unsigned int lci, struct x25_neigh *nb)
 {
 	struct sock *s;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
 
 	for (s = x25_list; s; s = s->next)
-		if (x25_sk(s)->lci == lci && x25_sk(s)->neighbour == neigh)
+		if (x25_sk(s)->lci == lci && x25_sk(s)->neighbour == nb)
 			break;
+	if (s)
+		sock_hold(s);
+	return s;
+}
 
-	restore_flags(flags);
+struct sock *x25_find_socket(unsigned int lci, struct x25_neigh *nb)
+{
+	struct sock *s;
+
+	read_lock_bh(&x25_list_lock);
+	s = __x25_find_socket(lci, nb);
+	read_unlock_bh(&x25_list_lock);
 	return s;
 }
 
 /*
  *	Find a unique LCI for a given device.
  */
-unsigned int x25_new_lci(struct x25_neigh *neigh)
+unsigned int x25_new_lci(struct x25_neigh *nb)
 {
 	unsigned int lci = 1;
+	struct sock *sk;
 
-	while (x25_find_socket(lci, neigh))
+	read_lock_bh(&x25_list_lock);
+
+	while ((sk = __x25_find_socket(lci, nb)) != NULL) {
+		sock_put(sk);
 		if (++lci == 4096) {
 			lci = 0;
 			break;
 		}
+	}
 
+	read_unlock_bh(&x25_list_lock);
 	return lci;
 }
 
@@ -309,11 +326,9 @@
 void x25_destroy_socket(struct sock *sk)	/* Not static as it's used by the timer */
 {
 	struct sk_buff *skb;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
 
+	sock_hold(sk);
+	lock_sock(sk);
 	x25_stop_heartbeat(sk);
 	x25_stop_timer(sk);
 
@@ -341,8 +356,8 @@
 		sk_free(sk);
 		MOD_DEC_USE_COUNT;
 	}
-
-	restore_flags(flags);
+	release_sock(sk);
+	sock_put(sk);
 }
 
 /*
@@ -421,7 +436,7 @@
 static struct sock *x25_alloc_socket(void)
 {
 	struct sock *sk;
-	x25_cb *x25;
+	struct x25_opt *x25;
 
 	MOD_INC_USE_COUNT;
 
@@ -455,7 +470,7 @@
 static int x25_create(struct socket *sock, int protocol)
 {
 	struct sock *sk;
-	x25_cb *x25;
+	struct x25_opt *x25;
 	int rc = -ESOCKTNOSUPPORT;
 
 	if (sock->type != SOCK_SEQPACKET || protocol)
@@ -495,7 +510,7 @@
 static struct sock *x25_make_new(struct sock *osk)
 {
 	struct sock *sk = NULL;
-	x25_cb *x25, *ox25;
+	struct x25_opt *x25, *ox25;
 
 	if (osk->type != SOCK_SEQPACKET)
 		goto out;
@@ -533,7 +548,7 @@
 static int x25_release(struct socket *sock)
 {
 	struct sock *sk = sock->sk;
-	x25_cb *x25;
+	struct x25_opt *x25;
 
 	if (!sk)
 		goto out;
@@ -587,14 +602,44 @@
 	return 0;
 }
 
+static int x25_wait_for_connection_establishment(struct sock *sk)
+{
+	DECLARE_WAITQUEUE(wait, current);
+        int rc;
+
+	add_wait_queue_exclusive(sk->sleep, &wait);
+	for (;;) {
+		__set_current_state(TASK_INTERRUPTIBLE);
+		rc = -ERESTARTSYS;
+		if (signal_pending(current))
+			break;
+		rc = sock_error(sk);
+		if (rc) {
+			sk->socket->state = SS_UNCONNECTED;
+			break;
+		}
+		rc = 0;
+		if (sk->state != TCP_ESTABLISHED) {
+			release_sock(sk);
+			schedule();
+			lock_sock(sk);
+		} else
+			break;
+	}
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(sk->sleep, &wait);
+	return rc;
+}
+
 static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags)
 {
 	struct sock *sk = sock->sk;
-	x25_cb *x25 = x25_sk(sk);
+	struct x25_opt *x25 = x25_sk(sk);
 	struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr;
-	struct net_device *dev;
+	struct x25_route *rt;
 	int rc = 0;
 
+	lock_sock(sk);
 	if (sk->state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
 		sock->state = SS_CONNECTED;
 		goto out;	/* Connect completed during a ERESTARTSYS event */
@@ -619,23 +664,23 @@
 		goto out;
 
 	rc = -ENETUNREACH;
-	dev = x25_get_route(&addr->sx25_addr);
-	if (!dev)
+	rt = x25_get_route(&addr->sx25_addr);
+	if (!rt)
 		goto out;
 
-	x25->neighbour = x25_get_neigh(dev);
+	x25->neighbour = x25_get_neigh(rt->dev);
 	if (!x25->neighbour)
-		goto out;
+		goto out_put_route;
 
 	x25_limit_facilities(&x25->facilities, x25->neighbour);
 
 	x25->lci = x25_new_lci(x25->neighbour);
 	if (!x25->lci)
-		goto out;
+		goto out_put_neigh;
 
 	rc = -EINVAL;
 	if (sk->zapped)		/* Must bind first - autobinding does not work */
-		goto out;
+		goto out_put_neigh;
 
 	if (!strcmp(x25->source_addr.x25_addr, null_x25_address.x25_addr))
 		memset(&x25->source_addr, '\0', X25_ADDR_LEN);
@@ -656,32 +701,50 @@
 	/* Now the loop */
 	rc = -EINPROGRESS;
 	if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
-		goto out;
-
-	cli();	/* To avoid races on the sleep */
+		goto out_put_neigh;
 
-	/*
-	 * A Clear Request or timeout or failed routing will go to closed.
-	 */
-	rc = -ERESTARTSYS;
-	while (sk->state == TCP_SYN_SENT) {
-		/* FIXME: going to sleep with interrupts disabled */
-		interruptible_sleep_on(sk->sleep);
-		if (signal_pending(current))
-			goto out_unlock;
-	}
-
-	if (sk->state != TCP_ESTABLISHED) {
-		sock->state = SS_UNCONNECTED;
-		rc = sock_error(sk);	/* Always set at this point */
-		goto out_unlock;
-	}
+	rc = x25_wait_for_connection_establishment(sk);
+	if (rc)
+		goto out_put_neigh;
 
 	sock->state = SS_CONNECTED;
 	rc = 0;
-out_unlock:
-	sti();
+out_put_neigh:
+	if (rc)
+		x25_neigh_put(x25->neighbour);
+out_put_route:
+	x25_route_put(rt);
 out:
+	release_sock(sk);
+	return rc;
+}
+
+static int x25_wait_for_data(struct sock *sk, int timeout)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	int rc = 0;
+
+	add_wait_queue_exclusive(sk->sleep, &wait);
+	for (;;) {
+		__set_current_state(TASK_INTERRUPTIBLE);
+		if (sk->shutdown & RCV_SHUTDOWN)
+			break;
+		rc = -ERESTARTSYS;
+		if (signal_pending(current))
+			break;
+		rc = -EAGAIN;
+		if (!timeout)
+			break;
+		rc = 0;
+		if (skb_queue_empty(&sk->receive_queue)) {
+			release_sock(sk);
+			timeout = schedule_timeout(timeout);
+			lock_sock(sk);
+		} else
+			break;
+	}
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(sk->sleep, &wait);
 	return rc;
 }
 	
@@ -699,29 +762,17 @@
 	if (sk->type != SOCK_SEQPACKET)
 		goto out;
 
-	/*
-	 *	The write queue this time is holding sockets ready to use
-	 *	hooked into the CALL INDICATION we saved
-	 */
-	do {
-		cli();
-		if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) {
-			rc = -EWOULDBLOCK;
-			if (flags & O_NONBLOCK)
-				goto out_unlock;
-			/* FIXME: going to sleep with interrupts disabled */
-			interruptible_sleep_on(sk->sleep);
-			rc = -ERESTARTSYS;
-			if (signal_pending(current))
-				goto out_unlock;
-		}
-	} while (!skb);
-
+	rc = x25_wait_for_data(sk, sk->rcvtimeo);
+	if (rc)
+		goto out;
+	skb = skb_dequeue(&sk->receive_queue);
+	rc = -EINVAL;
+	if (!skb->sk)
+		goto out;
 	newsk	      = skb->sk;
 	newsk->pair   = NULL;
 	newsk->socket = newsock;
 	newsk->sleep  = &newsock->wait;
-	sti();
 
 	/* Now attach up the new socket */
 	skb->sk = NULL;
@@ -732,16 +783,13 @@
 	rc = 0;
 out:
 	return rc;
-out_unlock:
-	sti();
-	goto out;
 }
 
 static int x25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer)
 {
 	struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)uaddr;
 	struct sock *sk = sock->sk;
-	x25_cb *x25 = x25_sk(sk);
+	struct x25_opt *x25 = x25_sk(sk);
 
 	if (peer) {
 		if (sk->state != TCP_ESTABLISHED)
@@ -756,11 +804,11 @@
 	return 0;
 }
  
-int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned int lci)
+int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb, unsigned int lci)
 {
 	struct sock *sk;
 	struct sock *make;
-	x25_cb *makex25;
+	struct x25_opt *makex25;
 	struct x25_address source_addr, dest_addr;
 	struct x25_facilities facilities;
 	int len, rc;
@@ -791,21 +839,21 @@
 	 *	Try to reach a compromise on the requested facilities.
 	 */
 	if ((len = x25_negotiate_facilities(skb, sk, &facilities)) == -1)
-		goto out_clear_request;
+		goto out_sock_put;
 
 	/*
 	 * current neighbour/link might impose additional limits
 	 * on certain facilties
 	 */
 
-	x25_limit_facilities(&facilities,neigh);
+	x25_limit_facilities(&facilities, nb);
 
 	/*
 	 *	Try to create a new socket.
 	 */
 	make = x25_make_new(sk);
 	if (!make)
-		goto out_clear_request;
+		goto out_sock_put;
 
 	/*
 	 *	Remove the facilities, leaving any Call User Data.
@@ -819,7 +867,7 @@
 	makex25->lci           = lci;
 	makex25->dest_addr     = dest_addr;
 	makex25->source_addr   = source_addr;
-	makex25->neighbour     = neigh;
+	makex25->neighbour     = nb;
 	makex25->facilities    = facilities;
 	makex25->vc_facil_mask = x25_sk(sk)->vc_facil_mask;
 
@@ -847,18 +895,21 @@
 	if (!sk->dead)
 		sk->data_ready(sk, skb->len);
 	rc = 1;
+	sock_put(sk);
 out:
 	return rc;
+out_sock_put:
+	sock_put(sk);
 out_clear_request:
 	rc = 0;
-	x25_transmit_clear_request(neigh, lci, 0x01);
+	x25_transmit_clear_request(nb, lci, 0x01);
 	goto out;
 }
 
 static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
-	x25_cb *x25 = x25_sk(sk);
+	struct x25_opt *x25 = x25_sk(sk);
 	struct sockaddr_x25 *usx25 = (struct sockaddr_x25 *)msg->msg_name;
 	struct sockaddr_x25 sx25;
 	struct sk_buff *skb;
@@ -1033,7 +1084,7 @@
 		       int flags, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
-	x25_cb *x25 = x25_sk(sk);
+	struct x25_opt *x25 = x25_sk(sk);
 	struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)msg->msg_name;
 	int copied, qbit;
 	struct sk_buff *skb;
@@ -1119,7 +1170,7 @@
 static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
 	struct sock *sk = sock->sk;
-	x25_cb *x25 = x25_sk(sk);
+	struct x25_opt *x25 = x25_sk(sk);
 	int rc;
 
 	switch (cmd) {
@@ -1256,17 +1307,15 @@
 	struct sock *s;
 	struct net_device *dev;
 	const char *devname;
-	int len;
 	off_t pos = 0;
 	off_t begin = 0;
+	int len = sprintf(buffer, "dest_addr  src_addr   dev   lci st vs vr "
+				  "va   t  t2 t21 t22 t23 Snd-Q Rcv-Q inode\n");
 
-	cli();
-
-	len = sprintf(buffer, "dest_addr  src_addr   dev   lci st vs vr va   "
-			      "t  t2 t21 t22 t23 Snd-Q Rcv-Q inode\n");
+	read_lock_bh(&x25_list_lock);
 
 	for (s = x25_list; s; s = s->next) {
-		x25_cb *x25 = x25_sk(s);
+		struct x25_opt *x25 = x25_sk(s);
 
 		if (!x25->neighbour || (dev = x25->neighbour->dev) == NULL)
 			devname = "???";
@@ -1306,7 +1355,7 @@
 			break;
 	}
 
-	sti();
+	read_unlock_bh(&x25_list_lock);
 
 	*start = buffer + (offset - begin);
 	len   -= (offset - begin);
@@ -1356,13 +1405,17 @@
 	.notifier_call = x25_device_event,
 };
 
-void x25_kill_by_neigh(struct x25_neigh *neigh)
+void x25_kill_by_neigh(struct x25_neigh *nb)
 {
 	struct sock *s;
 
+	write_lock_bh(&x25_list_lock);
+
 	for (s = x25_list; s; s = s->next)
-		if (x25_sk(s)->neighbour == neigh)
+		if (x25_sk(s)->neighbour == nb)
 			x25_disconnect(s, ENETUNREACH, 0, 0);
+
+	write_unlock_bh(&x25_list_lock);
 }
 
 static int __init x25_init(void)
diff -Nru a/net/x25/x25_dev.c b/net/x25/x25_dev.c
--- a/net/x25/x25_dev.c	Tue Oct  1 00:08:17 2002
+++ b/net/x25/x25_dev.c	Tue Oct  1 00:08:17 2002
@@ -44,7 +44,7 @@
 #include <linux/if_arp.h>
 #include <net/x25.h>
 
-static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *neigh)
+static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *nb)
 {
 	struct sock *sk;
 	unsigned short frametype;
@@ -58,14 +58,14 @@
 	 *	frame.
 	 */
 	if (lci == 0) {
-		x25_link_control(skb, neigh, frametype);
+		x25_link_control(skb, nb, frametype);
 		return 0;
 	}
 
 	/*
 	 *	Find an existing socket.
 	 */
-	if ((sk = x25_find_socket(lci, neigh)) != NULL) {
+	if ((sk = x25_find_socket(lci, nb)) != NULL) {
 		int queued = 1;
 
 		skb->h.raw = skb->data;
@@ -83,91 +83,87 @@
 	 *	Is is a Call Request ? if so process it.
 	 */
 	if (frametype == X25_CALL_REQUEST)
-		return x25_rx_call_request(skb, neigh, lci);
+		return x25_rx_call_request(skb, nb, lci);
 
 	/*
 	 *	Its not a Call Request, nor is it a control frame.
 	 *      Let caller throw it away.
 	 */
 /*
-	x25_transmit_clear_request(neigh, lci, 0x0D);
+	x25_transmit_clear_request(nb, lci, 0x0D);
 */
 	printk(KERN_DEBUG "x25_receive_data(): unknown frame type %2x\n",frametype);
 
 	return 0;
 }
 
-int x25_lapb_receive_frame(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype)
+int x25_lapb_receive_frame(struct sk_buff *skb, struct net_device *dev,
+			   struct packet_type *ptype)
 {
-	struct x25_neigh *neigh;
-	int queued;
+	struct x25_neigh *nb;
 
 	skb->sk = NULL;
 
 	/*
-	 *	Packet received from unrecognised device, throw it away.
+	 * Packet received from unrecognised device, throw it away.
 	 */
-	if ((neigh = x25_get_neigh(dev)) == NULL) {
+	nb = x25_get_neigh(dev);
+	if (!nb) {
 		printk(KERN_DEBUG "X.25: unknown neighbour - %s\n", dev->name);
-		kfree_skb(skb);
-		return 0;
+		goto drop;
 	}
 
 	switch (skb->data[0]) {
 		case 0x00:
 			skb_pull(skb, 1);
-			queued = x25_receive_data(skb, neigh);
-			if( ! queued )
-				/* We need to free the skb ourselves because
-				 * net_bh() won't care about our return code.
-				 */
-				kfree_skb(skb);
-			return 0;
-
+			if (x25_receive_data(skb, nb)) {
+				x25_neigh_put(nb);
+				goto out;
+			}
+			break;
 		case 0x01:
-			x25_link_established(neigh);
-			kfree_skb(skb);
-			return 0;
-
+			x25_link_established(nb);
+			break;
 		case 0x02:
-			x25_link_terminated(neigh);
-			kfree_skb(skb);
-			return 0;
-
-		case 0x03:
-			kfree_skb(skb);
-			return 0;
-
-		default:
-			kfree_skb(skb);
-			return 0;
+			x25_link_terminated(nb);
+			break;
 	}
+	x25_neigh_put(nb);
+drop:
+	kfree_skb(skb);
+out:
+	return 0;
 }
 
-int x25_llc_receive_frame(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype)
+int x25_llc_receive_frame(struct sk_buff *skb, struct net_device *dev,
+			  struct packet_type *ptype)
 {
-	struct x25_neigh *neigh;
+	struct x25_neigh *nb;
+	int rc = 0;
 
 	skb->sk = NULL;
 
 	/*
-	 *	Packet received from unrecognised device, throw it away.
+	 * Packet received from unrecognised device, throw it away.
 	 */
-	if ((neigh = x25_get_neigh(dev)) == NULL) {
+	nb = x25_get_neigh(dev);
+	if (!nb) {
 		printk(KERN_DEBUG "X.25: unknown_neighbour - %s\n", dev->name);
 		kfree_skb(skb);
-		return 0;
+	} else {
+		rc = x25_receive_data(skb, nb);
+		x25_neigh_put(nb);
 	}
 
-	return x25_receive_data(skb, neigh);
+	return rc;
 }
 
-void x25_establish_link(struct x25_neigh *neigh)
+void x25_establish_link(struct x25_neigh *nb)
 {
 	struct sk_buff *skb;
 	unsigned char *ptr;
 
-	switch (neigh->dev->type) {
+	switch (nb->dev->type) {
 		case ARPHRD_X25:
 			if ((skb = alloc_skb(1, GFP_ATOMIC)) == NULL) {
 				printk(KERN_ERR "x25_dev: out of memory\n");
@@ -186,47 +182,44 @@
 	}
 
 	skb->protocol = htons(ETH_P_X25);
-	skb->dev      = neigh->dev;
+	skb->dev      = nb->dev;
 
 	dev_queue_xmit(skb);
 }
 
-void x25_terminate_link(struct x25_neigh *neigh)
+void x25_terminate_link(struct x25_neigh *nb)
 {
 	struct sk_buff *skb;
 	unsigned char *ptr;
 
-	switch (neigh->dev->type) {
-		case ARPHRD_X25:
-			if ((skb = alloc_skb(1, GFP_ATOMIC)) == NULL) {
-				printk(KERN_ERR "x25_dev: out of memory\n");
-				return;
-			}
-			ptr  = skb_put(skb, 1);
-			*ptr = 0x02;
-			break;
-
 #if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE)
-		case ARPHRD_ETHER:
-			return;
+	if (nb->dev->type == ARPHRD_ETHER)
+		return;
 #endif
-		default:
-			return;
+	if (nb->dev->type != ARPHRD_X25)
+		return;
+
+	skb = alloc_skb(1, GFP_ATOMIC);
+	if (!skb) {
+		printk(KERN_ERR "x25_dev: out of memory\n");
+		return;
 	}
 
-	skb->protocol = htons(ETH_P_X25);
-	skb->dev      = neigh->dev;
+	ptr  = skb_put(skb, 1);
+	*ptr = 0x02;
 
+	skb->protocol = htons(ETH_P_X25);
+	skb->dev      = nb->dev;
 	dev_queue_xmit(skb);
 }
 
-void x25_send_frame(struct sk_buff *skb, struct x25_neigh *neigh)
+void x25_send_frame(struct sk_buff *skb, struct x25_neigh *nb)
 {
 	unsigned char *dptr;
 
 	skb->nh.raw = skb->data;
 
-	switch (neigh->dev->type) {
+	switch (nb->dev->type) {
 		case ARPHRD_X25:
 			dptr  = skb_push(skb, 1);
 			*dptr = 0x00;
@@ -243,7 +236,7 @@
 	}
 
 	skb->protocol = htons(ETH_P_X25);
-	skb->dev      = neigh->dev;
+	skb->dev      = nb->dev;
 
 	dev_queue_xmit(skb);
 }
diff -Nru a/net/x25/x25_facilities.c b/net/x25/x25_facilities.c
--- a/net/x25/x25_facilities.c	Tue Oct  1 00:08:17 2002
+++ b/net/x25/x25_facilities.c	Tue Oct  1 00:08:17 2002
@@ -1,8 +1,9 @@
 /*
  *	X.25 Packet Layer release 002
  *
- *	This is ALPHA test software. This code may break your machine, randomly fail to work with new 
- *	releases, misbehave and/or generally screw up. It might even work. 
+ *	This is ALPHA test software. This code may break your machine,
+ *	randomly fail to work with new releases, misbehave and/or generally
+ *	screw up. It might even work. 
  *
  *	This code REQUIRES 2.1.15 or higher
  *
@@ -42,65 +43,71 @@
  *	Parse a set of facilities into the facilities structure. Unrecognised
  *	facilities are written to the debug log file.
  */
-int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities, unsigned long *vc_fac_mask)
+int x25_parse_facilities(struct sk_buff *skb,
+			 struct x25_facilities *facilities,
+			 unsigned long *vc_fac_mask)
 {
-	unsigned int len;
 	unsigned char *p = skb->data;
+	unsigned int len = *p++;
 
-	len = *p++;
 	*vc_fac_mask = 0;
 
 	while (len > 0) {
 		switch (*p & X25_FAC_CLASS_MASK) {
-			case X25_FAC_CLASS_A:
-				switch (*p) {
-					case X25_FAC_REVERSE:
-						facilities->reverse = (p[1] & 0x01);
-						*vc_fac_mask |= X25_MASK_REVERSE;
-						break;
-					case X25_FAC_THROUGHPUT:
-						facilities->throughput = p[1];
-						*vc_fac_mask |= X25_MASK_THROUGHPUT;
-						break;
-					default:
-						printk(KERN_DEBUG "X.25: unknown facility %02X, value %02X\n", p[0], p[1]);
-						break;
-				}
-				p   += 2;
-				len -= 2;
-				break;
-
-			case X25_FAC_CLASS_B:
-				switch (*p) {
-					case X25_FAC_PACKET_SIZE:
-						facilities->pacsize_in  = p[1];
-						facilities->pacsize_out = p[2];
-						*vc_fac_mask |= X25_MASK_PACKET_SIZE;
-						break;
-					case X25_FAC_WINDOW_SIZE:
-						facilities->winsize_in  = p[1];
-						facilities->winsize_out = p[2];
-						*vc_fac_mask |= X25_MASK_WINDOW_SIZE;
-						break;
-					default:
-						printk(KERN_DEBUG "X.25: unknown facility %02X, values %02X, %02X\n", p[0], p[1], p[2]);
-						break;
-				}
-				p   += 3;
-				len -= 3;
-				break;
-
-			case X25_FAC_CLASS_C:
-				printk(KERN_DEBUG "X.25: unknown facility %02X, values %02X, %02X, %02X\n", p[0], p[1], p[2], p[3]);
-				p   += 4;
-				len -= 4;
-				break;
-
-			case X25_FAC_CLASS_D:
-				printk(KERN_DEBUG "X.25: unknown facility %02X, length %d, values %02X, %02X, %02X, %02X\n", p[0], p[1], p[2], p[3], p[4], p[5]);
-				p   += p[1] + 2;
-				len -= p[1] + 2;
+		case X25_FAC_CLASS_A:
+			switch (*p) {
+			case X25_FAC_REVERSE:
+				facilities->reverse = p[1] & 0x01;
+				*vc_fac_mask |= X25_MASK_REVERSE;
 				break;
+			case X25_FAC_THROUGHPUT:
+				facilities->throughput = p[1];
+				*vc_fac_mask |= X25_MASK_THROUGHPUT;
+				break;
+			default:
+				printk(KERN_DEBUG "X.25: unknown facility "
+				       "%02X, value %02X\n",
+				       p[0], p[1]);
+				break;
+			}
+			p   += 2;
+			len -= 2;
+			break;
+		case X25_FAC_CLASS_B:
+			switch (*p) {
+			case X25_FAC_PACKET_SIZE:
+				facilities->pacsize_in  = p[1];
+				facilities->pacsize_out = p[2];
+				*vc_fac_mask |= X25_MASK_PACKET_SIZE;
+				break;
+			case X25_FAC_WINDOW_SIZE:
+				facilities->winsize_in  = p[1];
+				facilities->winsize_out = p[2];
+				*vc_fac_mask |= X25_MASK_WINDOW_SIZE;
+				break;
+			default:
+				printk(KERN_DEBUG "X.25: unknown facility "
+				       "%02X, values %02X, %02X\n",
+				       p[0], p[1], p[2]);
+				break;
+			}
+			p   += 3;
+			len -= 3;
+			break;
+		case X25_FAC_CLASS_C:
+			printk(KERN_DEBUG "X.25: unknown facility %02X, "
+			       "values %02X, %02X, %02X\n",
+			       p[0], p[1], p[2], p[3]);
+			p   += 4;
+			len -= 4;
+			break;
+		case X25_FAC_CLASS_D:
+			printk(KERN_DEBUG "X.25: unknown facility %02X, "
+			       "length %d, values %02X, %02X, %02X, %02X\n",
+			       p[0], p[1], p[2], p[3], p[4], p[5]);
+			p   += p[1] + 2;
+			len -= p[1] + 2;
+			break;
 		}
 	}
 
@@ -110,37 +117,45 @@
 /*
  *	Create a set of facilities.
  */
-int x25_create_facilities(unsigned char *buffer, struct x25_facilities *facilities, unsigned long facil_mask)
+int x25_create_facilities(unsigned char *buffer,
+			  struct x25_facilities *facilities,
+			  unsigned long facil_mask)
 {
 	unsigned char *p = buffer + 1;
 	int len;
 
-	if (facil_mask == 0) {
-		buffer [0] = 0; /* length of the facilities field in call_req or call_accept packets */
+	if (!facil_mask) {
+		/*
+		 * Length of the facilities field in call_req or
+		 * call_accept packets
+		 */
+		buffer[0] = 0;
 		len = 1; /* 1 byte for the length field */
 		return len;
 	}
 
-	if ((facilities->reverse != 0) && (facil_mask & X25_MASK_REVERSE)) {
+	if (facilities->reverse && (facil_mask & X25_MASK_REVERSE)) {
 		*p++ = X25_FAC_REVERSE;
-		*p++ = (facilities->reverse) ? 0x01 : 0x00;
+		*p++ = !!facilities->reverse;
 	}
 
-	if ((facilities->throughput != 0) && (facil_mask & X25_MASK_THROUGHPUT)) {
+	if (facilities->throughput && (facil_mask & X25_MASK_THROUGHPUT)) {
 		*p++ = X25_FAC_THROUGHPUT;
 		*p++ = facilities->throughput;
 	}
 
-	if ((facilities->pacsize_in != 0 || facilities->pacsize_out != 0) && (facil_mask & X25_MASK_PACKET_SIZE)) {
+	if ((facilities->pacsize_in || facilities->pacsize_out) &&
+	    (facil_mask & X25_MASK_PACKET_SIZE)) {
 		*p++ = X25_FAC_PACKET_SIZE;
-		*p++ = (facilities->pacsize_in  == 0) ? facilities->pacsize_out : facilities->pacsize_in;
-		*p++ = (facilities->pacsize_out == 0) ? facilities->pacsize_in  : facilities->pacsize_out;
+		*p++ = facilities->pacsize_in ? : facilities->pacsize_out;
+		*p++ = facilities->pacsize_out ? : facilities->pacsize_in;
 	}
 
-	if ((facilities->winsize_in != 0 || facilities->winsize_out != 0) && (facil_mask & X25_MASK_WINDOW_SIZE)) {
+	if ((facilities->winsize_in || facilities->winsize_out) &&
+	    (facil_mask & X25_MASK_WINDOW_SIZE)) {
 		*p++ = X25_FAC_WINDOW_SIZE;
-		*p++ = (facilities->winsize_in  == 0) ? facilities->winsize_out : facilities->winsize_in;
-		*p++ = (facilities->winsize_out == 0) ? facilities->winsize_in  : facilities->winsize_out;
+		*p++ = facilities->winsize_in ? : facilities->winsize_out;
+		*p++ = facilities->winsize_out ? : facilities->winsize_in;
 	}
 
 	len       = p - buffer;
@@ -154,39 +169,37 @@
  *
  *	The only real problem is with reverse charging.
  */
-int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk, struct x25_facilities *new)
+int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk,
+			     struct x25_facilities *new)
 {
-	x25_cb *x25 = x25_sk(sk);
-	struct x25_facilities *ours;
+	struct x25_opt *x25 = x25_sk(sk);
+	struct x25_facilities *ours = &x25->facilities;
 	struct x25_facilities theirs;
 	int len;
 
-	memset(&theirs, 0x00, sizeof(struct x25_facilities));
-
-	ours = &x25->facilities;
-
-	*new = *ours;
+	memset(&theirs, 0, sizeof(theirs));
+	memcpy(new, ours, sizeof(*new));
 
 	len = x25_parse_facilities(skb, &theirs, &x25->vc_facil_mask);
 
 	/*
 	 *	They want reverse charging, we won't accept it.
 	 */
-	if (theirs.reverse != 0 && ours->reverse == 0) {
+	if (theirs.reverse && ours->reverse) {
 		SOCK_DEBUG(sk, "X.25: rejecting reverse charging request");
 		return -1;
 	}
 
 	new->reverse = theirs.reverse;
 
-	if (theirs.throughput != 0) {
+	if (theirs.throughput) {
 		if (theirs.throughput < ours->throughput) {
 			SOCK_DEBUG(sk, "X.25: throughput negotiated down");
 			new->throughput = theirs.throughput;
 		}
 	}
 
-	if (theirs.pacsize_in != 0 && theirs.pacsize_out != 0) {
+	if (theirs.pacsize_in && theirs.pacsize_out) {
 		if (theirs.pacsize_in < ours->pacsize_in) {
 			SOCK_DEBUG(sk, "X.25: packet size inwards negotiated down");
 			new->pacsize_in = theirs.pacsize_in;
@@ -197,7 +210,7 @@
 		}
 	}
 
-	if (theirs.winsize_in != 0 && theirs.winsize_out != 0) {
+	if (theirs.winsize_in && theirs.winsize_out) {
 		if (theirs.winsize_in < ours->winsize_in) {
 			SOCK_DEBUG(sk, "X.25: window size inwards negotiated down");
 			new->winsize_in = theirs.winsize_in;
@@ -216,15 +229,15 @@
  *      currently attached x25 link.
  */
 void x25_limit_facilities(struct x25_facilities *facilities,
-			  struct x25_neigh *neighbour)
+			  struct x25_neigh *nb)
 {
 
-	if( ! neighbour->extended ){
-		if( facilities->winsize_in  > 7 ){
+	if (!nb->extended) {
+		if (facilities->winsize_in  > 7) {
 			printk(KERN_DEBUG "X.25: incoming winsize limited to 7\n");
 			facilities->winsize_in = 7;
 		}
-		if( facilities->winsize_out > 7 ){
+		if (facilities->winsize_out > 7) {
 			facilities->winsize_out = 7;
 			printk( KERN_DEBUG "X.25: outgoing winsize limited to 7\n");
 		}
diff -Nru a/net/x25/x25_in.c b/net/x25/x25_in.c
--- a/net/x25/x25_in.c	Tue Oct  1 00:08:21 2002
+++ b/net/x25/x25_in.c	Tue Oct  1 00:08:21 2002
@@ -48,7 +48,7 @@
 static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
 {
 	struct sk_buff *skbo, *skbn = skb;
-	x25_cb *x25 = x25_sk(sk);
+	struct x25_opt *x25 = x25_sk(sk);
 
 	if (more) {
 		x25->fraglen += skb->len;
@@ -103,7 +103,7 @@
 
 	switch (frametype) {
 		case X25_CALL_ACCEPTED: {
-			x25_cb *x25 = x25_sk(sk);
+			struct x25_opt *x25 = x25_sk(sk);
 
 			x25_stop_timer(sk);
 			x25->condition = 0x00;
@@ -179,7 +179,7 @@
 {
 	int queued = 0;
 	int modulus;
-	x25_cb *x25 = x25_sk(sk);
+	struct x25_opt *x25 = x25_sk(sk);
 	
 	modulus = (x25->neighbour->extended) ? X25_EMODULUS : X25_SMODULUS;
 
@@ -308,7 +308,7 @@
 		case X25_RESET_REQUEST:
 			x25_write_internal(sk, X25_RESET_CONFIRMATION);
 		case X25_RESET_CONFIRMATION: {
-			x25_cb *x25 = x25_sk(sk);
+			struct x25_opt *x25 = x25_sk(sk);
 
 			x25_stop_timer(sk);
 			x25->condition = 0x00;
@@ -335,7 +335,7 @@
 /* Higher level upcall for a LAPB frame */
 int x25_process_rx_frame(struct sock *sk, struct sk_buff *skb)
 {
-	x25_cb *x25 = x25_sk(sk);
+	struct x25_opt *x25 = x25_sk(sk);
 	int queued = 0, frametype, ns, nr, q, d, m;
 
 	if (x25->state == X25_STATE_0)
diff -Nru a/net/x25/x25_link.c b/net/x25/x25_link.c
--- a/net/x25/x25_link.c	Tue Oct  1 00:08:15 2002
+++ b/net/x25/x25_link.c	Tue Oct  1 00:08:15 2002
@@ -1,8 +1,9 @@
 /*
  *	X.25 Packet Layer release 002
  *
- *	This is ALPHA test software. This code may break your machine, randomly fail to work with new 
- *	releases, misbehave and/or generally screw up. It might even work. 
+ *	This is ALPHA test software. This code may break your machine,
+ *	randomly fail to work with new releases, misbehave and/or generally
+ *	screw up. It might even work. 
  *
  *	This code REQUIRES 2.1.15 or higher
  *
@@ -42,98 +43,102 @@
 #include <linux/init.h>
 #include <net/x25.h>
 
-static struct x25_neigh *x25_neigh_list /* = NULL initially */;
+static struct list_head x25_neigh_list = LIST_HEAD_INIT(x25_neigh_list);
+static rwlock_t x25_neigh_list_lock = RW_LOCK_UNLOCKED;
 
 static void x25_t20timer_expiry(unsigned long);
 
 /*
  *	Linux set/reset timer routines
  */
-static void x25_start_t20timer(struct x25_neigh *neigh)
+static void x25_start_t20timer(struct x25_neigh *nb)
 {
-	del_timer(&neigh->t20timer);
+	del_timer(&nb->t20timer);
 
-	neigh->t20timer.data     = (unsigned long)neigh;
-	neigh->t20timer.function = &x25_t20timer_expiry;
-	neigh->t20timer.expires  = jiffies + neigh->t20;
+	nb->t20timer.data     = (unsigned long)nb;
+	nb->t20timer.function = &x25_t20timer_expiry;
+	nb->t20timer.expires  = jiffies + nb->t20;
 
-	add_timer(&neigh->t20timer);
+	add_timer(&nb->t20timer);
 }
 
 static void x25_t20timer_expiry(unsigned long param)
 {
-	struct x25_neigh *neigh = (struct x25_neigh *)param;
+	struct x25_neigh *nb = (struct x25_neigh *)param;
 
-	x25_transmit_restart_request(neigh);
+	x25_transmit_restart_request(nb);
 
-	x25_start_t20timer(neigh);
+	x25_start_t20timer(nb);
 }
 
-static void x25_stop_t20timer(struct x25_neigh *neigh)
+static void x25_stop_t20timer(struct x25_neigh *nb)
 {
-	del_timer(&neigh->t20timer);
+	del_timer(&nb->t20timer);
 }
 
-static int x25_t20timer_pending(struct x25_neigh *neigh)
+static int x25_t20timer_pending(struct x25_neigh *nb)
 {
-	return timer_pending(&neigh->t20timer);
+	return timer_pending(&nb->t20timer);
 }
 
 /*
  *	This handles all restart and diagnostic frames.
  */
-void x25_link_control(struct sk_buff *skb, struct x25_neigh *neigh, unsigned short frametype)
+void x25_link_control(struct sk_buff *skb, struct x25_neigh *nb,
+		      unsigned short frametype)
 {
 	struct sk_buff *skbn;
 	int confirm;
 
 	switch (frametype) {
 		case X25_RESTART_REQUEST:
-			confirm = !x25_t20timer_pending(neigh);
-			x25_stop_t20timer(neigh);
-			neigh->state = X25_LINK_STATE_3;
-			if (confirm) x25_transmit_restart_confirmation(neigh);
+			confirm = !x25_t20timer_pending(nb);
+			x25_stop_t20timer(nb);
+			nb->state = X25_LINK_STATE_3;
+			if (confirm)
+				x25_transmit_restart_confirmation(nb);
 			break;
 
 		case X25_RESTART_CONFIRMATION:
-			x25_stop_t20timer(neigh);
-			neigh->state = X25_LINK_STATE_3;
+			x25_stop_t20timer(nb);
+			nb->state = X25_LINK_STATE_3;
 			break;
 
 		case X25_DIAGNOSTIC:
-			printk(KERN_WARNING "x25: diagnostic #%d - %02X %02X %02X\n", skb->data[3], skb->data[4], skb->data[5], skb->data[6]);
+			printk(KERN_WARNING "x25: diagnostic #%d - "
+			       "%02X %02X %02X\n",
+			       skb->data[3], skb->data[4],
+			       skb->data[5], skb->data[6]);
 			break;
 			
 		default:
-			printk(KERN_WARNING "x25: received unknown %02X with LCI 000\n", frametype);
+			printk(KERN_WARNING "x25: received unknown %02X "
+			       "with LCI 000\n", frametype);
 			break;
 	}
 
-	if (neigh->state == X25_LINK_STATE_3) {
-		while ((skbn = skb_dequeue(&neigh->queue)) != NULL)
-			x25_send_frame(skbn, neigh);
-	}
+	if (nb->state == X25_LINK_STATE_3)
+		while ((skbn = skb_dequeue(&nb->queue)) != NULL)
+			x25_send_frame(skbn, nb);
 }
 
 /*
  *	This routine is called when a Restart Request is needed
  */
-void x25_transmit_restart_request(struct x25_neigh *neigh)
+void x25_transmit_restart_request(struct x25_neigh *nb)
 {
-	struct sk_buff *skb;
 	unsigned char *dptr;
-	int len;
-
-	len = X25_MAX_L2_LEN + X25_STD_MIN_LEN + 2;
+	int len = X25_MAX_L2_LEN + X25_STD_MIN_LEN + 2;
+	struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);
 
-	if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
+	if (!skb)
 		return;
 
 	skb_reserve(skb, X25_MAX_L2_LEN);
 
 	dptr = skb_put(skb, X25_STD_MIN_LEN + 2);
 
-	*dptr++ = (neigh->extended) ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ;
+	*dptr++ = nb->extended ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ;
 	*dptr++ = 0x00;
 	*dptr++ = X25_RESTART_REQUEST;
 	*dptr++ = 0x00;
@@ -141,108 +146,104 @@
 
 	skb->sk = NULL;
 
-	x25_send_frame(skb, neigh);
+	x25_send_frame(skb, nb);
 }
 
 /*
  * This routine is called when a Restart Confirmation is needed
  */
-void x25_transmit_restart_confirmation(struct x25_neigh *neigh)
+void x25_transmit_restart_confirmation(struct x25_neigh *nb)
 {
-	struct sk_buff *skb;
 	unsigned char *dptr;
-	int len;
-
-	len = X25_MAX_L2_LEN + X25_STD_MIN_LEN;
+	int len = X25_MAX_L2_LEN + X25_STD_MIN_LEN;
+	struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);
 
-	if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
+	if (!skb)
 		return;
 
 	skb_reserve(skb, X25_MAX_L2_LEN);
 
 	dptr = skb_put(skb, X25_STD_MIN_LEN);
 
-	*dptr++ = (neigh->extended) ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ;
+	*dptr++ = nb->extended ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ;
 	*dptr++ = 0x00;
 	*dptr++ = X25_RESTART_CONFIRMATION;
 
 	skb->sk = NULL;
 
-	x25_send_frame(skb, neigh);
+	x25_send_frame(skb, nb);
 }
 
 /*
  * This routine is called when a Diagnostic is required.
  */
-void x25_transmit_diagnostic(struct x25_neigh *neigh, unsigned char diag)
+void x25_transmit_diagnostic(struct x25_neigh *nb, unsigned char diag)
 {
-	struct sk_buff *skb;
 	unsigned char *dptr;
-	int len;
+	int len = X25_MAX_L2_LEN + X25_STD_MIN_LEN + 1;
+	struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);
 
-	len = X25_MAX_L2_LEN + X25_STD_MIN_LEN + 1;
-
-	if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
+	if (!skb)
 		return;
 
 	skb_reserve(skb, X25_MAX_L2_LEN);
 
 	dptr = skb_put(skb, X25_STD_MIN_LEN + 1);
 
-	*dptr++ = (neigh->extended) ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ;
+	*dptr++ = nb->extended ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ;
 	*dptr++ = 0x00;
 	*dptr++ = X25_DIAGNOSTIC;
 	*dptr++ = diag;
 
 	skb->sk = NULL;
 
-	x25_send_frame(skb, neigh);
+	x25_send_frame(skb, nb);
 }
 
 /*
  *	This routine is called when a Clear Request is needed outside of the context
  *	of a connected socket.
  */
-void x25_transmit_clear_request(struct x25_neigh *neigh, unsigned int lci, unsigned char cause)
+void x25_transmit_clear_request(struct x25_neigh *nb, unsigned int lci,
+				unsigned char cause)
 {
-	struct sk_buff *skb;
 	unsigned char *dptr;
-	int len;
-
-	len = X25_MAX_L2_LEN + X25_STD_MIN_LEN + 2;
+	int len = X25_MAX_L2_LEN + X25_STD_MIN_LEN + 2;
+	struct sk_buff *skb = alloc_skb(len, GFP_ATOMIC);
 
-	if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
+	if (!skb)
 		return;
 
 	skb_reserve(skb, X25_MAX_L2_LEN);
 
 	dptr = skb_put(skb, X25_STD_MIN_LEN + 2);
 
-	*dptr++ = ((lci >> 8) & 0x0F) | (neigh->extended) ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ;
-	*dptr++ = ((lci >> 0) & 0xFF);
+	*dptr++ = ((lci >> 8) & 0x0F) | nb->extended ? X25_GFI_EXTSEQ :
+							  X25_GFI_STDSEQ;
+	*dptr++ = (lci >> 0) & 0xFF;
 	*dptr++ = X25_CLEAR_REQUEST;
 	*dptr++ = cause;
 	*dptr++ = 0x00;
 
 	skb->sk = NULL;
 
-	x25_send_frame(skb, neigh);
+	x25_send_frame(skb, nb);
 }
 
-void x25_transmit_link(struct sk_buff *skb, struct x25_neigh *neigh)
+void x25_transmit_link(struct sk_buff *skb, struct x25_neigh *nb)
 {
-	switch (neigh->state) {
+	switch (nb->state) {
 		case X25_LINK_STATE_0:
-			skb_queue_tail(&neigh->queue, skb);
-			neigh->state = X25_LINK_STATE_1;
-			x25_establish_link(neigh);
+			skb_queue_tail(&nb->queue, skb);
+			nb->state = X25_LINK_STATE_1;
+			x25_establish_link(nb);
 			break;
 		case X25_LINK_STATE_1:
 		case X25_LINK_STATE_2:
-			skb_queue_tail(&neigh->queue, skb);
+			skb_queue_tail(&nb->queue, skb);
 			break;
 		case X25_LINK_STATE_3:
-			x25_send_frame(skb, neigh);
+			x25_send_frame(skb, nb);
 			break;
 	}
 }
@@ -250,16 +251,16 @@
 /*
  *	Called when the link layer has become established.
  */
-void x25_link_established(struct x25_neigh *neigh)
+void x25_link_established(struct x25_neigh *nb)
 {
-	switch (neigh->state) {
+	switch (nb->state) {
 		case X25_LINK_STATE_0:
-			neigh->state = X25_LINK_STATE_2;
+			nb->state = X25_LINK_STATE_2;
 			break;
 		case X25_LINK_STATE_1:
-			x25_transmit_restart_request(neigh);
-			neigh->state = X25_LINK_STATE_2;
-			x25_start_t20timer(neigh);
+			x25_transmit_restart_request(nb);
+			nb->state = X25_LINK_STATE_2;
+			x25_start_t20timer(nb);
 			break;
 	}
 }
@@ -269,11 +270,11 @@
  *	request has failed.
  */
 
-void x25_link_terminated(struct x25_neigh *neigh)
+void x25_link_terminated(struct x25_neigh *nb)
 {
-	neigh->state = X25_LINK_STATE_0;
+	nb->state = X25_LINK_STATE_0;
 	/* Out of order: clear existing virtual calls (X.25 03/93 4.6.3) */
-	x25_kill_by_neigh(neigh);
+	x25_kill_by_neigh(nb);
 }
 
 /*
@@ -281,59 +282,50 @@
  */
 void x25_link_device_up(struct net_device *dev)
 {
-	struct x25_neigh *x25_neigh;
-	unsigned long flags;
+	struct x25_neigh *nb = kmalloc(sizeof(*nb), GFP_ATOMIC);
 
-	if ((x25_neigh = kmalloc(sizeof(*x25_neigh), GFP_ATOMIC)) == NULL)
+	if (!nb)
 		return;
 
-	skb_queue_head_init(&x25_neigh->queue);
+	skb_queue_head_init(&nb->queue);
 
-	init_timer(&x25_neigh->t20timer);
+	init_timer(&nb->t20timer);
 
 	dev_hold(dev);
-	x25_neigh->dev      = dev;
-	x25_neigh->state    = X25_LINK_STATE_0;
-	x25_neigh->extended = 0;
-	x25_neigh->global_facil_mask = (X25_MASK_REVERSE | X25_MASK_THROUGHPUT | X25_MASK_PACKET_SIZE | X25_MASK_WINDOW_SIZE); /* enables negotiation */
-	x25_neigh->t20      = sysctl_x25_restart_request_timeout;
-
-	save_flags(flags); cli();
-	x25_neigh->next = x25_neigh_list;
-	x25_neigh_list  = x25_neigh;
-	restore_flags(flags);
-}
-
-static void x25_remove_neigh(struct x25_neigh *x25_neigh)
+	nb->dev      = dev;
+	nb->state    = X25_LINK_STATE_0;
+	nb->extended = 0;
+	/*
+	 * Enables negotiation
+	 */
+	nb->global_facil_mask = X25_MASK_REVERSE |
+				       X25_MASK_THROUGHPUT |
+				       X25_MASK_PACKET_SIZE |
+				       X25_MASK_WINDOW_SIZE;
+	nb->t20      = sysctl_x25_restart_request_timeout;
+	atomic_set(&nb->refcnt, 1);
+
+	write_lock_bh(&x25_neigh_list_lock);
+	list_add(&nb->node, &x25_neigh_list);
+	write_unlock_bh(&x25_neigh_list_lock);
+}
+
+/**
+ *	__x25_remove_neigh - remove neighbour from x25_neigh_list
+ *	@nb - neigh to remove
+ *
+ *	Remove neighbour from x25_neigh_list. If it was there.
+ *	Caller must hold x25_neigh_list_lock.
+ */
+static void __x25_remove_neigh(struct x25_neigh *nb)
 {
-	struct x25_neigh *s;
-	unsigned long flags;
-
-	skb_queue_purge(&x25_neigh->queue);
-
-	x25_stop_t20timer(x25_neigh);
-
-	save_flags(flags); cli();
-
-	if ((s = x25_neigh_list) == x25_neigh) {
-		x25_neigh_list = x25_neigh->next;
-		restore_flags(flags);
-		kfree(x25_neigh);
-		return;
-	}
-
-	while (s != NULL && s->next != NULL) {
-		if (s->next == x25_neigh) {
-			s->next = x25_neigh->next;
-			restore_flags(flags);
-			kfree(x25_neigh);
-			return;
-		}
+	skb_queue_purge(&nb->queue);
+	x25_stop_t20timer(nb);
 
-		s = s->next;
+	if (nb->node.next) {
+		list_del(&nb->node);
+		x25_neigh_put(nb);
 	}
-
-	restore_flags(flags);
 }
 
 /*
@@ -341,17 +333,21 @@
  */
 void x25_link_device_down(struct net_device *dev)
 {
-	struct x25_neigh *neigh, *x25_neigh = x25_neigh_list;
+	struct x25_neigh *nb;
+	struct list_head *entry, *tmp;
+
+	write_lock_bh(&x25_neigh_list_lock);
 
-	while (x25_neigh != NULL) {
-		neigh     = x25_neigh;
-		x25_neigh = x25_neigh->next;
+	list_for_each_safe(entry, tmp, &x25_neigh_list) {
+		nb = list_entry(entry, struct x25_neigh, node);
 
-		if (neigh->dev == dev){
-			x25_remove_neigh(neigh);
+		if (nb->dev == dev) {
+			__x25_remove_neigh(nb);
 			dev_put(dev);
 		}
 	}
+
+	write_unlock_bh(&x25_neigh_list_lock);
 }
 
 /*
@@ -359,13 +355,23 @@
  */
 struct x25_neigh *x25_get_neigh(struct net_device *dev)
 {
-	struct x25_neigh *x25_neigh;
+	struct x25_neigh *nb, *use = NULL;
+	struct list_head *entry;
 
-	for (x25_neigh = x25_neigh_list; x25_neigh != NULL; x25_neigh = x25_neigh->next)
-		if (x25_neigh->dev == dev)
-			return x25_neigh;
+	read_lock_bh(&x25_neigh_list_lock);
+	list_for_each(entry, &x25_neigh_list) {
+		nb = list_entry(entry, struct x25_neigh, node);
 
-	return NULL;
+		if (nb->dev == dev) {
+			use = nb;
+			break;
+		}
+	}
+
+	if (use)
+		x25_neigh_hold(use);
+	read_unlock_bh(&x25_neigh_list_lock);
+	return use;
 }
 
 /*
@@ -374,48 +380,45 @@
 int x25_subscr_ioctl(unsigned int cmd, void *arg)
 {
 	struct x25_subscrip_struct x25_subscr;
-	struct x25_neigh *x25_neigh;
+	struct x25_neigh *nb;
 	struct net_device *dev;
+	int rc = -EINVAL;
 
-	switch (cmd) {
+	if (cmd != SIOCX25GSUBSCRIP && cmd != SIOCX25SSUBSCRIP)
+		goto out;
 
-		case SIOCX25GSUBSCRIP:
-			if (copy_from_user(&x25_subscr, arg, sizeof(struct x25_subscrip_struct)))
-				return -EFAULT;
-			if ((dev = x25_dev_get(x25_subscr.device)) == NULL)
-				return -EINVAL;
-			if ((x25_neigh = x25_get_neigh(dev)) == NULL) {
-				dev_put(dev);
-				return -EINVAL;
-			}
-			dev_put(dev);
-			x25_subscr.extended = x25_neigh->extended;
-			x25_subscr.global_facil_mask = x25_neigh->global_facil_mask;
-			if (copy_to_user(arg, &x25_subscr, sizeof(struct x25_subscrip_struct)))
-				return -EFAULT;
-			break;
-
-		case SIOCX25SSUBSCRIP:
-			if (copy_from_user(&x25_subscr, arg, sizeof(struct x25_subscrip_struct)))
-				return -EFAULT;
-			if ((dev = x25_dev_get(x25_subscr.device)) == NULL)
-				return -EINVAL;
-			if ((x25_neigh = x25_get_neigh(dev)) == NULL) {
-				dev_put(dev);
-				return -EINVAL;
-			}
-			dev_put(dev);
-			if (x25_subscr.extended != 0 && x25_subscr.extended != 1)
-				return -EINVAL;
-			x25_neigh->extended = x25_subscr.extended;
-			x25_neigh->global_facil_mask = x25_subscr.global_facil_mask;
-			break;
-
-		default:
-			return -EINVAL;
+	rc = -EFAULT;
+	if (copy_from_user(&x25_subscr, arg, sizeof(x25_subscr)))
+		goto out;
+
+	rc = -EINVAL;
+	if ((dev = x25_dev_get(x25_subscr.device)) == NULL)
+		goto out;
+
+	if ((nb = x25_get_neigh(dev)) == NULL)
+		goto out_dev_put;
+
+	dev_put(dev);
+
+	if (cmd == SIOCX25GSUBSCRIP) {
+		x25_subscr.extended	     = nb->extended;
+		x25_subscr.global_facil_mask = nb->global_facil_mask;
+		rc = copy_to_user(arg, &x25_subscr,
+				  sizeof(x25_subscr)) ? -EFAULT : 0;
+	} else {
+		rc = -EINVAL;
+		if (!(x25_subscr.extended && x25_subscr.extended != 1)) {
+			rc = 0;
+			nb->extended	     = x25_subscr.extended;
+			nb->global_facil_mask = x25_subscr.global_facil_mask;
+		}
 	}
-
-	return 0;
+	x25_neigh_put(nb);
+out:
+	return rc;
+out_dev_put:
+	dev_put(dev);
+	goto out;
 }
 
 
@@ -424,12 +427,14 @@
  */
 void __exit x25_link_free(void)
 {
-	struct x25_neigh *neigh, *x25_neigh = x25_neigh_list;
+	struct x25_neigh *nb;
+	struct list_head *entry, *tmp;
 
-	while (x25_neigh != NULL) {
-		neigh     = x25_neigh;
-		x25_neigh = x25_neigh->next;
+	write_lock_bh(&x25_neigh_list_lock);
 
-		x25_remove_neigh(neigh);
+	list_for_each_safe(entry, tmp, &x25_neigh_list) {
+		nb = list_entry(entry, struct x25_neigh, node);
+		__x25_remove_neigh(nb);
 	}
+	write_unlock_bh(&x25_neigh_list_lock);
 }
diff -Nru a/net/x25/x25_out.c b/net/x25/x25_out.c
--- a/net/x25/x25_out.c	Tue Oct  1 00:08:15 2002
+++ b/net/x25/x25_out.c	Tue Oct  1 00:08:15 2002
@@ -1,8 +1,9 @@
 /*
  *	X.25 Packet Layer release 002
  *
- *	This is ALPHA test software. This code may break your machine, randomly fail to work with new 
- *	releases, misbehave and/or generally screw up. It might even work. 
+ *	This is ALPHA test software. This code may break your machine,
+ *	randomly fail to work with new releases, misbehave and/or generally
+ *	screw up. It might even work. 
  *
  *	This code REQUIRES 2.1.15 or higher
  *
@@ -45,7 +46,7 @@
 {
 	int bytes = 1;
 
-	if (pacsize == 0)
+	if (!pacsize)
 		return 128;
 
 	while (pacsize-- > 0)
@@ -66,7 +67,7 @@
 	unsigned char header[X25_EXT_MIN_LEN];
 	int err, frontlen, len;
 	int sent=0, noblock = X25_SKB_CB(skb)->flags & MSG_DONTWAIT;
-	x25_cb *x25 = x25_sk(sk);
+	struct x25_opt *x25 = x25_sk(sk);
 	int header_len = x25->neighbour->extended ? X25_EXT_MIN_LEN :
 						    X25_STD_MIN_LEN;
 	int max_len = x25_pacsize_to_bytes(x25->facilities.pacsize_out);
@@ -79,18 +80,21 @@
 		frontlen = skb_headroom(skb);
 
 		while (skb->len > 0) {
-			if ((skbn = sock_alloc_send_skb(sk, frontlen + max_len, noblock, &err)) == NULL){
-				if(err == -EWOULDBLOCK && noblock){
+			if ((skbn = sock_alloc_send_skb(sk, frontlen + max_len,
+							noblock, &err)) == NULL){
+				if (err == -EWOULDBLOCK && noblock){
 					kfree_skb(skb);
 					return sent;
 				}
-				SOCK_DEBUG(sk, "x25_output: fragment allocation failed, err=%d, %d bytes sent\n", err, sent);
+				SOCK_DEBUG(sk, "x25_output: fragment alloc"
+					       " failed, err=%d, %d bytes "
+					       "sent\n", err, sent);
 				return err;
 			}
 				
 			skb_reserve(skbn, frontlen);
 
-			len = (max_len > skb->len) ? skb->len : max_len;
+			len = max_len > skb->len ? skb->len : max_len;
 
 			/* Copy the user data */
 			memcpy(skb_put(skbn, len), skb->data, len);
@@ -125,9 +129,9 @@
  */
 static void x25_send_iframe(struct sock *sk, struct sk_buff *skb)
 {
-	x25_cb *x25 = x25_sk(sk);
+	struct x25_opt *x25 = x25_sk(sk);
 
-	if (skb == NULL)
+	if (!skb)
 		return;
 
 	if (x25->neighbour->extended) {
@@ -148,7 +152,7 @@
 	struct sk_buff *skb, *skbn;
 	unsigned short start, end;
 	int modulus;
-	x25_cb *x25 = x25_sk(sk);
+	struct x25_opt *x25 = x25_sk(sk);
 
 	if (x25->state != X25_STATE_3)
 		return;
@@ -168,9 +172,9 @@
 	if (skb_peek(&sk->write_queue) == NULL)
 		return;
 
-	modulus = (x25->neighbour->extended) ? X25_EMODULUS : X25_SMODULUS;
+	modulus = x25->neighbour->extended ? X25_EMODULUS : X25_SMODULUS;
 
-	start   = (skb_peek(&x25->ack_queue) == NULL) ? x25->va : x25->vs;
+	start   = skb_peek(&x25->ack_queue) ? x25->vs : x25->va;
 	end     = (x25->va + x25->facilities.winsize_out) % modulus;
 
 	if (start == end)
@@ -220,7 +224,7 @@
 
 void x25_enquiry_response(struct sock *sk)
 {
-	x25_cb *x25 = x25_sk(sk);
+	struct x25_opt *x25 = x25_sk(sk);
 
 	if (x25->condition & X25_COND_OWN_RX_BUSY)
 		x25_write_internal(sk, X25_RNR);
diff -Nru a/net/x25/x25_route.c b/net/x25/x25_route.c
--- a/net/x25/x25_route.c	Tue Oct  1 00:08:18 2002
+++ b/net/x25/x25_route.c	Tue Oct  1 00:08:18 2002
@@ -44,7 +44,8 @@
 #include <linux/init.h>
 #include <net/x25.h>
 
-static struct x25_route *x25_route_list; /* = NULL initially */
+static struct list_head x25_route_list = LIST_HEAD_INIT(x25_route_list);
+static rwlock_t x25_route_list_lock = RW_LOCK_UNLOCKED;
 
 /*
  *	Add a new route.
@@ -52,80 +53,75 @@
 static int x25_add_route(struct x25_address *address, unsigned int sigdigits,
 			 struct net_device *dev)
 {
-	struct x25_route *x25_route;
-	unsigned long flags;
+	struct x25_route *rt;
+	struct list_head *entry;
 	int rc = -EINVAL;
 
-	for (x25_route = x25_route_list; x25_route; x25_route = x25_route->next)
-		if (!memcmp(&x25_route->address, address, sigdigits) &&
-		    x25_route->sigdigits == sigdigits)
+	write_lock_bh(&x25_route_list_lock);
+
+	list_for_each(entry, &x25_route_list) {
+		rt = list_entry(entry, struct x25_route, node);
+
+		if (!memcmp(&rt->address, address, sigdigits) &&
+		    rt->sigdigits == sigdigits)
 			goto out;
+	}
 
-	x25_route = kmalloc(sizeof(*x25_route), GFP_ATOMIC);
+	rt = kmalloc(sizeof(*rt), GFP_ATOMIC);
 	rc = -ENOMEM;
-	if (!x25_route)
+	if (!rt)
 		goto out;
 
-	strcpy(x25_route->address.x25_addr, "000000000000000");
-	memcpy(x25_route->address.x25_addr, address->x25_addr, sigdigits);
+	strcpy(rt->address.x25_addr, "000000000000000");
+	memcpy(rt->address.x25_addr, address->x25_addr, sigdigits);
 
-	x25_route->sigdigits = sigdigits;
-	x25_route->dev       = dev;
+	rt->sigdigits = sigdigits;
+	rt->dev       = dev;
+	atomic_set(&rt->refcnt, 1);
 
-	save_flags(flags); cli();
-	x25_route->next = x25_route_list;
-	x25_route_list  = x25_route;
-	restore_flags(flags);
+	list_add(&rt->node, &x25_route_list);
 	rc = 0;
 out:
+	write_unlock_bh(&x25_route_list_lock);
 	return rc;
 }
 
-static void x25_remove_route(struct x25_route *x25_route)
-{
-	struct x25_route *s;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-
-	if ((s = x25_route_list) == x25_route) {
-		x25_route_list = x25_route->next;
-		restore_flags(flags);
-		return;
+/**
+ * __x25_remove_route - remove route from x25_route_list
+ * @rt - route to remove
+ *
+ * Remove route from x25_route_list. If it was there.
+ * Caller must hold x25_route_list_lock.
+ */
+static void __x25_remove_route(struct x25_route *rt)
+{
+	if (rt->node.next) {
+		list_del(&rt->node);
+		x25_route_put(rt);
 	}
-
-	while (s && s->next) {
-		if (s->next == x25_route) {
-			s->next = x25_route->next;
-			goto out_kfree_route;
-		}
-
-		s = s->next;
-	}
-out:
-	restore_flags(flags);
-	return;
-out_kfree_route:
-	kfree(x25_route);
-	goto out;
 }
 
 static int x25_del_route(struct x25_address *address, unsigned int sigdigits,
 			 struct net_device *dev)
 {
-	struct x25_route *x25_route = x25_route_list;
+	struct x25_route *rt;
+	struct list_head *entry;
 	int rc = -EINVAL;
 
-	for (; x25_route; x25_route = x25_route->next)
-		if (!memcmp(&x25_route->address, address, sigdigits) &&
-		    x25_route->sigdigits == sigdigits &&
-		    x25_route->dev == dev) {
-			x25_remove_route(x25_route);
+	write_lock_bh(&x25_route_list_lock);
+
+	list_for_each(entry, &x25_route_list) {
+		rt = list_entry(entry, struct x25_route, node);
+
+		if (!memcmp(&rt->address, address, sigdigits) &&
+		    rt->sigdigits == sigdigits && rt->dev == dev) {
+			__x25_remove_route(rt);
 			rc = 0;
 			break;
 		}
+	}
 
+	write_unlock_bh(&x25_route_list_lock);
 	return rc;
 }
 
@@ -134,15 +130,18 @@
  */
 void x25_route_device_down(struct net_device *dev)
 {
-	struct x25_route *route, *x25_route = x25_route_list;
+	struct x25_route *rt;
+	struct list_head *entry, *tmp;
 
-	while (x25_route) {
-		route     = x25_route;
-		x25_route = x25_route->next;
+	write_lock_bh(&x25_route_list_lock);
 
-		if (route->dev == dev)
-			x25_remove_route(route);
+	list_for_each_safe(entry, tmp, &x25_route_list) {
+		rt = list_entry(entry, struct x25_route, node);
+
+		if (rt->dev == dev)
+			__x25_remove_route(rt);
 	}
+	write_unlock_bh(&x25_route_list_lock);
 }
 
 /*
@@ -163,22 +162,35 @@
 	return dev;
 }
 
-/*
- *	Find a device given an X.25 address.
+/**
+ * 	x25_get_route -	Find a route given an X.25 address.
+ * 	@addr - address to find a route for
+ *
+ * 	Find a route given an X.25 address.
  */
-struct net_device *x25_get_route(struct x25_address *addr)
+struct x25_route *x25_get_route(struct x25_address *addr)
 {
-	struct x25_route *route, *use = NULL;
+	struct x25_route *rt, *use = NULL;
+	struct list_head *entry;
+
+	read_lock_bh(&x25_route_list_lock);
 
-	for (route = x25_route_list; route; route = route->next)
-		if (!memcmp(&route->address, addr, route->sigdigits)) {
+	list_for_each(entry, &x25_route_list) {
+		rt = list_entry(entry, struct x25_route, node);
+
+		if (!memcmp(&rt->address, addr, rt->sigdigits)) {
 			if (!use)
-				use = route;
-			else if (route->sigdigits > use->sigdigits)
-				use = route;
+				use = rt;
+			else if (rt->sigdigits > use->sigdigits)
+				use = rt;
 		}
+	}
+
+	if (use)
+		x25_route_hold(use);
 
-	return use ? use->dev : NULL;
+	read_unlock_bh(&x25_route_list_lock);
+	return use;
 }
 
 /*
@@ -186,7 +198,7 @@
  */
 int x25_route_ioctl(unsigned int cmd, void *arg)
 {
-	struct x25_route_struct x25_route;
+	struct x25_route_struct rt;
 	struct net_device *dev;
 	int rc = -EINVAL;
 
@@ -194,21 +206,21 @@
 		goto out;
 
 	rc = -EFAULT;
-	if (copy_from_user(&x25_route, arg, sizeof(x25_route)))
+	if (copy_from_user(&rt, arg, sizeof(rt)))
 		goto out;
 
 	rc = -EINVAL;
-	if (x25_route.sigdigits < 0 || x25_route.sigdigits > 15)
+	if (rt.sigdigits < 0 || rt.sigdigits > 15)
 		goto out;
 
-	dev = x25_dev_get(x25_route.device);
+	dev = x25_dev_get(rt.device);
 	if (!dev)
 		goto out;
 
 	if (cmd == SIOCADDRT)
-		rc = x25_add_route(&x25_route.address, x25_route.sigdigits, dev);
+		rc = x25_add_route(&rt.address, rt.sigdigits, dev);
 	else
-		rc = x25_del_route(&x25_route.address, x25_route.sigdigits, dev);
+		rc = x25_del_route(&rt.address, rt.sigdigits, dev);
 	dev_put(dev);
 out:
 	return rc;
@@ -216,20 +228,20 @@
 
 int x25_routes_get_info(char *buffer, char **start, off_t offset, int length)
 {
-	struct x25_route *x25_route;
-	int len;
+	struct x25_route *rt;
+	struct list_head *entry;
 	off_t pos   = 0;
 	off_t begin = 0;
+	int len = sprintf(buffer, "address          digits  device\n");
 
-	cli();
+	read_lock_bh(&x25_route_list_lock);
 
-	len = sprintf(buffer, "address          digits  device\n");
-
-	for (x25_route = x25_route_list; x25_route; x25_route = x25_route->next) {
+	list_for_each(entry, &x25_route_list) {
+		rt = list_entry(entry, struct x25_route, node);
 		len += sprintf(buffer + len, "%-15s  %-6d  %-5s\n",
-			       x25_route->address.x25_addr,
-			       x25_route->sigdigits,
-			       x25_route->dev ? x25_route->dev->name : "???");
+			       rt->address.x25_addr,
+			       rt->sigdigits,
+			       rt->dev ? rt->dev->name : "???");
 
 		pos = begin + len;
 
@@ -242,7 +254,7 @@
 			break;
 	}
 
-	sti();
+	read_unlock_bh(&x25_route_list_lock);
 
 	*start = buffer + (offset - begin);
 	len   -= (offset - begin);
@@ -258,12 +270,13 @@
  */
 void __exit x25_route_free(void)
 {
-	struct x25_route *route, *x25_route = x25_route_list;
-
-	while (x25_route) {
-		route     = x25_route;
-		x25_route = x25_route->next;
+	struct x25_route *rt;
+	struct list_head *entry, *tmp;
 
-		x25_remove_route(route);
+	write_lock_bh(&x25_route_list_lock);
+	list_for_each_safe(entry, tmp, &x25_route_list) {
+		rt = list_entry(entry, struct x25_route, node);
+		__x25_remove_route(rt);
 	}
+	write_unlock_bh(&x25_route_list_lock);
 }
diff -Nru a/net/x25/x25_subr.c b/net/x25/x25_subr.c
--- a/net/x25/x25_subr.c	Tue Oct  1 00:08:16 2002
+++ b/net/x25/x25_subr.c	Tue Oct  1 00:08:16 2002
@@ -1,8 +1,9 @@
 /*
  *	X.25 Packet Layer release 002
  *
- *	This is ALPHA test software. This code may break your machine, randomly fail to work with new 
- *	releases, misbehave and/or generally screw up. It might even work. 
+ *	This is ALPHA test software. This code may break your machine,
+ *	randomly fail to work with new releases, misbehave and/or generally
+ *	screw up. It might even work.
  *
  *	This code REQUIRES 2.1.15 or higher
  *
@@ -15,7 +16,7 @@
  *	History
  *	X.25 001	Jonathan Naylor	  Started coding.
  *	X.25 002	Jonathan Naylor	  Centralised disconnection processing.
- *	mar/20/00	Daniela Squassoni Disabling/enabling of facilities 
+ *	mar/20/00	Daniela Squassoni Disabling/enabling of facilities
  *					  negotiation.
  *	jun/24/01	Arnaldo C. Melo	  use skb_queue_purge, cleanups
  */
@@ -46,7 +47,7 @@
  */
 void x25_clear_queues(struct sock *sk)
 {
-	x25_cb *x25 = x25_sk(sk);
+	struct x25_opt *x25 = x25_sk(sk);
 
 	skb_queue_purge(&sk->write_queue);
 	skb_queue_purge(&x25->ack_queue);
@@ -64,7 +65,7 @@
 void x25_frames_acked(struct sock *sk, unsigned short nr)
 {
 	struct sk_buff *skb;
-	x25_cb *x25 = x25_sk(sk);
+	struct x25_opt *x25 = x25_sk(sk);
 	int modulus = x25->neighbour->extended ? X25_EMODULUS : X25_SMODULUS;
 
 	/*
@@ -88,7 +89,7 @@
 	 * output queue.
 	 */
 	while ((skb = skb_dequeue(&x25_sk(sk)->ack_queue)) != NULL) {
-		if (skb_prev == NULL)
+		if (!skb_prev)
 			skb_queue_head(&sk->write_queue, skb);
 		else
 			skb_append(skb_prev, skb);
@@ -102,36 +103,35 @@
  */
 int x25_validate_nr(struct sock *sk, unsigned short nr)
 {
-	x25_cb *x25 = x25_sk(sk);
+	struct x25_opt *x25 = x25_sk(sk);
 	unsigned short vc = x25->va;
 	int modulus = x25->neighbour->extended ? X25_EMODULUS : X25_SMODULUS;
 
 	while (vc != x25->vs) {
-		if (nr == vc) return 1;
+		if (nr == vc)
+			return 1;
 		vc = (vc + 1) % modulus;
 	}
 
 	return nr == x25->vs ? 1 : 0;
 }
 
-/* 
+/*
  *  This routine is called when the packet layer internally generates a
  *  control frame.
  */
 void x25_write_internal(struct sock *sk, int frametype)
 {
-	x25_cb *x25 = x25_sk(sk);
+	struct x25_opt *x25 = x25_sk(sk);
 	struct sk_buff *skb;
 	unsigned char  *dptr;
 	unsigned char  facilities[X25_MAX_FAC_LEN];
 	unsigned char  addresses[1 + X25_ADDR_LEN];
 	unsigned char  lci1, lci2;
-	int len;
-
 	/*
 	 *	Default safe frame size.
 	 */
-	len = X25_MAX_L2_LEN + X25_EXT_MIN_LEN;
+	int len = X25_MAX_L2_LEN + X25_EXT_MIN_LEN;
 
 	/*
 	 *	Adjust frame size.
@@ -262,7 +262,7 @@
 int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q,
 	       int *d, int *m)
 {
-	x25_cb *x25 = x25_sk(sk);
+	struct x25_opt *x25 = x25_sk(sk);
 	unsigned char *frame = skb->data;
 
 	*ns = *nr = *q = *d = *m = 0;
@@ -329,7 +329,7 @@
 void x25_disconnect(struct sock *sk, int reason, unsigned char cause,
 		    unsigned char diagnostic)
 {
-	x25_cb *x25 = x25_sk(sk);
+	struct x25_opt *x25 = x25_sk(sk);
 
 	x25_clear_queues(sk);
 	x25_stop_timer(sk);
@@ -356,7 +356,7 @@
  */
 void x25_check_rbuf(struct sock *sk)
 {
-	x25_cb *x25 = x25_sk(sk);
+	struct x25_opt *x25 = x25_sk(sk);
 
 	if (atomic_read(&sk->rmem_alloc) < (sk->rcvbuf / 2) &&
 	    (x25->condition & X25_COND_OWN_RX_BUSY)) {
diff -Nru a/net/x25/x25_timer.c b/net/x25/x25_timer.c
--- a/net/x25/x25_timer.c	Tue Oct  1 00:08:15 2002
+++ b/net/x25/x25_timer.c	Tue Oct  1 00:08:15 2002
@@ -1,8 +1,9 @@
 /*
  *	X.25 Packet Layer release 002
  *
- *	This is ALPHA test software. This code may break your machine, randomly fail to work with new 
- *	releases, misbehave and/or generally screw up. It might even work. 
+ *	This is ALPHA test software. This code may break your machine,
+ *	randomly fail to work with new releases, misbehave and/or generally
+ *	screw up. It might even work. 
  *
  *	This code REQUIRES 2.1.15 or higher
  *
@@ -60,7 +61,7 @@
 
 void x25_start_t2timer(struct sock *sk)
 {
-	x25_cb *x25 = x25_sk(sk);
+	struct x25_opt *x25 = x25_sk(sk);
 
 	del_timer(&x25->timer);
 
@@ -73,7 +74,7 @@
 
 void x25_start_t21timer(struct sock *sk)
 {
-	x25_cb *x25 = x25_sk(sk);
+	struct x25_opt *x25 = x25_sk(sk);
 
 	del_timer(&x25->timer);
 
@@ -86,7 +87,7 @@
 
 void x25_start_t22timer(struct sock *sk)
 {
-	x25_cb *x25 = x25_sk(sk);
+	struct x25_opt *x25 = x25_sk(sk);
 
 	del_timer(&x25->timer);
 
@@ -99,7 +100,7 @@
 
 void x25_start_t23timer(struct sock *sk)
 {
-	x25_cb *x25 = x25_sk(sk);
+	struct x25_opt *x25 = x25_sk(sk);
 
 	del_timer(&x25->timer);
 
@@ -117,7 +118,7 @@
 
 unsigned long x25_display_timer(struct sock *sk)
 {
-	x25_cb *x25 = x25_sk(sk);
+	struct x25_opt *x25 = x25_sk(sk);
 
 	if (!timer_pending(&x25->timer))
 		return 0;
@@ -130,9 +131,8 @@
 	struct sock *sk = (struct sock *)param;
 
         bh_lock_sock(sk);
-        if (sk->lock.users) { /* can currently only occur in state 3 */ 
+        if (sk->lock.users) /* can currently only occur in state 3 */ 
 		goto restart_heartbeat;
-	}
 
 	switch (x25_sk(sk)->state) {
 
@@ -152,9 +152,9 @@
 			x25_check_rbuf(sk);
 			break;
 	}
- restart_heartbeat:
+restart_heartbeat:
 	x25_start_heartbeat(sk);
- unlock:
+unlock:
 	bh_unlock_sock(sk);
 }
 
@@ -164,7 +164,7 @@
  */
 static inline void x25_do_timer_expiry(struct sock * sk)
 {
-	x25_cb *x25 = x25_sk(sk);
+	struct x25_opt *x25 = x25_sk(sk);
 
 	switch (x25->state) {
 
@@ -194,11 +194,9 @@
 
 	bh_lock_sock(sk);
 	if (sk->lock.users) { /* can currently only occur in state 3 */
-		if (x25_sk(sk)->state == X25_STATE_3) {
+		if (x25_sk(sk)->state == X25_STATE_3)
 			x25_start_t2timer(sk);
-		}
-	} else {
+	} else
 		x25_do_timer_expiry(sk);
-	}
 	bh_unlock_sock(sk);
 }
diff -Nru a/scripts/Configure b/scripts/Configure
--- a/scripts/Configure	Tue Oct  1 00:08:15 2002
+++ b/scripts/Configure	Tue Oct  1 00:08:15 2002
@@ -415,25 +415,15 @@
 #
 # int processes an integer argument with optional limits
 #
-#	int question define default [min max]
+#	int question define default
 #
 function int () {
 	old=$(eval echo "\${$2}")
 	def=${old:-$3}
-	if [ $# -gt 3 ]; then
-	  min=$4
-	else
-	  min=-10000000    # !!
-	fi
-	if [ $# -gt 4 ]; then
-	  max=$5
-	else
-	  max=10000000     # !!
-	fi
 	rndval $2
 	while :; do
 	  readln "$1 ($2) [$def] " "$def" "$old"
-	  if expr \( \( $ans + 0 \) \>= $min \) \& \( $ans \<= $max \) >/dev/null 2>&1 ; then
+	  if expr "$ans" : '[0-9]*$' > /dev/null; then
             define_int "$2" "$ans"
 	    break
           else
diff -Nru a/sound/Config.in b/sound/Config.in
--- a/sound/Config.in	Tue Oct  1 00:08:16 2002
+++ b/sound/Config.in	Tue Oct  1 00:08:16 2002
@@ -31,5 +31,11 @@
 if [ "$CONFIG_SND" != "n" -a "$CONFIG_ARM" = "y" ]; then
   source sound/arm/Config.in
 fi
+if [ "$CONFIG_SND" != "n" -a "$CONFIG_SPARC32" = "y" ]; then
+  source sound/sparc/Config.in
+fi
+if [ "$CONFIG_SND" != "n" -a "$CONFIG_SPARC64" = "y" ]; then
+  source sound/sparc/Config.in
+fi
 
 endmenu
diff -Nru a/sound/Makefile b/sound/Makefile
--- a/sound/Makefile	Tue Oct  1 00:08:16 2002
+++ b/sound/Makefile	Tue Oct  1 00:08:16 2002
@@ -5,7 +5,7 @@
 
 obj-$(CONFIG_SOUND) += soundcore.o
 obj-$(CONFIG_SOUND_PRIME) += oss/
-obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/
+obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ sparc/
 
 ifeq ($(CONFIG_SND),y)
   obj-y += last.o
diff -Nru a/sound/core/Makefile b/sound/core/Makefile
--- a/sound/core/Makefile	Tue Oct  1 00:08:15 2002
+++ b/sound/core/Makefile	Tue Oct  1 00:08:15 2002
@@ -3,7 +3,8 @@
 # Copyright (c) 1999,2001 by Jaroslav Kysela <perex@suse.cz>
 #
 
-export-objs  := sound.o pcm.o pcm_lib.o rawmidi.o timer.o hwdep.o
+export-objs  := sound.o pcm.o pcm_lib.o rawmidi.o timer.o hwdep.o \
+                pcm_sgbuf.o
 
 snd-objs     := sound.o init.o isadma.o memory.o info.o control.o misc.o \
                 device.o wrappers.o
@@ -12,7 +13,7 @@
 endif
 
 snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \
-		pcm_memory.o
+		pcm_memory.o pcm_sgbuf.o
 
 snd-rawmidi-objs  := rawmidi.o
 snd-timer-objs    := timer.o
@@ -40,7 +41,7 @@
 obj-$(CONFIG_SND_ALS100) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
 obj-$(CONFIG_SND_AZT2320) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
 obj-$(CONFIG_SND_CMI8330) += snd-pcm.o snd-timer.o snd.o
-obj-$(CONFIG_SND_DT0197H) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
+obj-$(CONFIG_SND_DT019X) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
 obj-$(CONFIG_SND_ES18XX) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
 obj-$(CONFIG_SND_OPL3SA2) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
 obj-$(CONFIG_SND_SGALAXY) += snd-pcm.o snd-timer.o snd.o
diff -Nru a/sound/core/control.c b/sound/core/control.c
--- a/sound/core/control.c	Tue Oct  1 00:08:15 2002
+++ b/sound/core/control.c	Tue Oct  1 00:08:15 2002
@@ -21,6 +21,7 @@
 
 #define __NO_VERSION__
 #include <sound/driver.h>
+#include <linux/threads.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
@@ -659,7 +660,7 @@
 		snd_kctl_event_t *kev;
 		while (list_empty(&ctl->events)) {
 			wait_queue_t wait;
-			if (file->f_flags & O_NONBLOCK) {
+			if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) {
 				err = -EAGAIN;
 				goto __end;
 			}
diff -Nru a/sound/core/device.c b/sound/core/device.c
--- a/sound/core/device.c	Tue Oct  1 00:08:17 2002
+++ b/sound/core/device.c	Tue Oct  1 00:08:17 2002
@@ -23,6 +23,7 @@
 #include <sound/driver.h>
 #include <linux/slab.h>
 #include <linux/time.h>
+#include <linux/errno.h>
 #include <sound/core.h>
 
 int snd_device_new(snd_card_t *card, snd_device_type_t type,
diff -Nru a/sound/core/ioctl32/Makefile b/sound/core/ioctl32/Makefile
--- a/sound/core/ioctl32/Makefile	Tue Oct  1 00:08:18 2002
+++ b/sound/core/ioctl32/Makefile	Tue Oct  1 00:08:18 2002
@@ -4,7 +4,7 @@
 #
 
 snd-ioctl32-objs := ioctl32.o pcm32.o rawmidi32.o timer32.o hwdep32.o
-ifeq ($(CONFIG_SND_SEQUENCER),y)
+ifneq ($(CONFIG_SND_SEQUENCER),n)
   snd-ioctl32-objs += seq32.o
 endif
 
diff -Nru a/sound/core/ioctl32/ioctl32.c b/sound/core/ioctl32/ioctl32.c
--- a/sound/core/ioctl32/ioctl32.c	Tue Oct  1 00:08:15 2002
+++ b/sound/core/ioctl32/ioctl32.c	Tue Oct  1 00:08:15 2002
@@ -20,8 +20,11 @@
 
 #define __NO_VERSION__
 #include <sound/driver.h>
+#include <linux/sched.h>
 #include <linux/smp_lock.h>
+#include <linux/init.h>
 #include <linux/time.h>
+#include <linux/init.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <asm/uaccess.h>
@@ -32,6 +35,10 @@
  * exported for other modules
  */
 
+MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
+MODULE_DESCRIPTION("ioctl32 wrapper for ALSA");
+MODULE_LICENSE("GPL");
+
 int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *));
 int unregister_ioctl32_conversion(unsigned int cmd);
 
@@ -79,7 +86,7 @@
 	u32 count;
 	u32 pids;
 	unsigned char reserved[50];
-};
+} /* don't set packed attribute here */;
 
 #define CVT_sndrv_ctl_elem_list()\
 {\
@@ -90,8 +97,43 @@
 	CPTR(pids);\
 }
 
-DEFINE_ALSA_IOCTL(ctl_elem_list);
+static int _snd_ioctl32_ctl_elem_list(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
+{
+	struct sndrv_ctl_elem_list32 data32;
+	struct sndrv_ctl_elem_list data;
+	mm_segment_t oldseg = get_fs();
+	int err;
+
+	set_fs(KERNEL_DS);
+	if (copy_from_user(&data32, (void*)arg, sizeof(data32))) {
+		err = -EFAULT;
+		goto __err;
+	}
+	memset(&data, 0, sizeof(data));
+	data.offset = data32.offset;
+	data.space = data32.space;
+	data.used = data32.used;
+	data.count = data32.count;
+	data.pids = A(data32.pids);
+	err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data);
+	if (err < 0)
+		goto __err;
+	/* copy the result */
+	data32.offset = data.offset;
+	data32.space = data.space;
+	data32.used = data.used;
+	data32.count = data.count;
+	//data.pids = data.pids;
+	if (copy_to_user((void*)arg, &data32, sizeof(data32))) {
+		err = -EFAULT;
+		goto __err;
+	}
+ __err:
+	set_fs(oldseg);
+	return err;
+}
 
+DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_list, ctl_elem_list, SNDRV_CTL_IOCTL_ELEM_LIST);
 
 /*
  * control element info
@@ -123,22 +165,31 @@
 		unsigned char reserved[128];
 	} value;
 	unsigned char reserved[64];
-};
+} __attribute__((packed));
 
-static int snd_ioctl32_ctl_elem_info(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file)
+static int _snd_ioctl32_ctl_elem_info(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
 {
 	struct sndrv_ctl_elem_info data;
 	struct sndrv_ctl_elem_info32 data32;
 	int err;
+	mm_segment_t oldseg = get_fs();
 
-	if (copy_from_user(&data32, (void*)arg, sizeof(data32)))
-		return -EFAULT;
+	set_fs(KERNEL_DS);
+	if (copy_from_user(&data32, (void*)arg, sizeof(data32))) {
+		err = -EFAULT;
+		goto __err;
+	}
 	memset(&data, 0, sizeof(data));
 	data.id = data32.id;
-	err = file->f_op->ioctl(file->f_dentry->d_inode, file, cmd, (unsigned long)&data);
+	/* we need to copy the item index.
+	 * hope this doesn't break anything..
+	 */
+	data.value.enumerated.item = data32.value.enumerated.item;
+	err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data);
 	if (err < 0)
-		return err;
+		goto __err;
 	/* restore info to 32bit */
+	data32.id = data.id;
 	data32.type = data.type;
 	data32.access = data.access;
 	data32.count = data.count;
@@ -147,12 +198,12 @@
 	case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
 	case SNDRV_CTL_ELEM_TYPE_INTEGER:
 		data32.value.integer.min = data.value.integer.min;
-		data32.value.integer.max = data.value.integer.min;
+		data32.value.integer.max = data.value.integer.max;
 		data32.value.integer.step = data.value.integer.step;
 		break;
 	case SNDRV_CTL_ELEM_TYPE_INTEGER64:
 		data32.value.integer64.min = data.value.integer64.min;
-		data32.value.integer64.max = data.value.integer64.min;
+		data32.value.integer64.max = data.value.integer64.max;
 		data32.value.integer64.step = data.value.integer64.step;
 		break;
 	case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
@@ -165,14 +216,17 @@
 		break;
 	}
 	if (copy_to_user((void*)arg, &data32, sizeof(data32)))
-		return -EFAULT;
+		err = -EFAULT;
+ __err:
+	set_fs(oldseg);
 	return err;
 }
 
+DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_info, ctl_elem_info, SNDRV_CTL_IOCTL_ELEM_INFO);
 
 struct sndrv_ctl_elem_value32 {
 	struct sndrv_ctl_elem_id id;
-	unsigned int indirect: 1;
+	unsigned int indirect;	/* bit-field causes misalignment */
         union {
 		union {
 			s32 value[128];
@@ -193,7 +247,7 @@
 		struct sndrv_aes_iec958 iec958;
         } value;
         unsigned char reserved[128];
-};
+} __attribute__((packed));
 
 
 /* hmm, it's so hard to retrieve the value type from the control id.. */
@@ -221,25 +275,33 @@
 }
 
 
-static int snd_ioctl32_ctl_elem_value(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file)
+static int _snd_ioctl32_ctl_elem_value(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
 {
 	// too big?
 	struct sndrv_ctl_elem_value data;
 	struct sndrv_ctl_elem_value32 data32;
 	int err, i;
 	int type;
+	mm_segment_t oldseg = get_fs();
+
+	set_fs(KERNEL_DS);
+
 	/* FIXME: check the sane ioctl.. */
 
-	if (copy_from_user(&data32, (void*)arg, sizeof(data32)))
-		return -EFAULT;
+	if (copy_from_user(&data32, (void*)arg, sizeof(data32))) {
+		err = -EFAULT;
+		goto __err;
+	}
 	memset(&data, 0, sizeof(data));
 	data.id = data32.id;
 	data.indirect = data32.indirect;
 	if (data.indirect) /* FIXME: this is not correct for long arrays */
 		data.value.integer.value_ptr = (void*)TO_PTR(data32.value.integer.value_ptr);
 	type = get_ctl_type(file, &data.id);
-	if (type < 0)
-		return type;
+	if (type < 0) {
+		err = type;
+		goto __err;
+	}
 	if (! data.indirect) {
 		switch (type) {
 		case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
@@ -263,45 +325,50 @@
 			data.value.iec958 = data32.value.iec958;
 			break;
 		default:
+			printk("unknown type %d\n", type);
 			break;
 		}
 	}
 
-	err = file->f_op->ioctl(file->f_dentry->d_inode, file, cmd, (unsigned long)&data);
+	err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data);
 	if (err < 0)
-		return err;
+		goto __err;
 	/* restore info to 32bit */
 	if (! data.indirect) {
 		switch (type) {
 		case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
 		case SNDRV_CTL_ELEM_TYPE_INTEGER:
 			for (i = 0; i < 128; i++)
-				data.value.integer.value[i] = data32.value.integer.value[i];
+				data32.value.integer.value[i] = data.value.integer.value[i];
 			break;
 		case SNDRV_CTL_ELEM_TYPE_INTEGER64:
 			for (i = 0; i < 64; i++)
-				data.value.integer64.value[i] = data32.value.integer64.value[i];
+				data32.value.integer64.value[i] = data.value.integer64.value[i];
 			break;
 		case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
 			for (i = 0; i < 128; i++)
-				data.value.enumerated.item[i] = data32.value.enumerated.item[i];
+				data32.value.enumerated.item[i] = data.value.enumerated.item[i];
 			break;
 		case SNDRV_CTL_ELEM_TYPE_BYTES:
-			memcpy(data.value.bytes.data, data32.value.bytes.data,
+			memcpy(data32.value.bytes.data, data.value.bytes.data,
 			       sizeof(data.value.bytes.data));
 			break;
 		case SNDRV_CTL_ELEM_TYPE_IEC958:
-			data.value.iec958 = data32.value.iec958;
+			data32.value.iec958 = data.value.iec958;
 			break;
 		default:
 			break;
 		}
 	}
 	if (copy_to_user((void*)arg, &data32, sizeof(data32)))
-		return -EFAULT;
+		err = -EFAULT;
+ __err:
+	set_fs(oldseg);
 	return err;
 }
 
+DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_read, ctl_elem_value, SNDRV_CTL_IOCTL_ELEM_READ);
+DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_write, ctl_elem_value, SNDRV_CTL_IOCTL_ELEM_WRITE);
 
 /*
  */
@@ -321,8 +388,8 @@
 	{ SNDRV_CTL_IOCTL_CARD_INFO , NULL },
 	{ SNDRV_CTL_IOCTL_ELEM_LIST32, AP(ctl_elem_list) },
 	{ SNDRV_CTL_IOCTL_ELEM_INFO32, AP(ctl_elem_info) },
-	{ SNDRV_CTL_IOCTL_ELEM_READ32, AP(ctl_elem_value) },
-	{ SNDRV_CTL_IOCTL_ELEM_WRITE32, AP(ctl_elem_value) },
+	{ SNDRV_CTL_IOCTL_ELEM_READ32, AP(ctl_elem_read) },
+	{ SNDRV_CTL_IOCTL_ELEM_WRITE32, AP(ctl_elem_write) },
 	{ SNDRV_CTL_IOCTL_ELEM_LOCK, NULL },
 	{ SNDRV_CTL_IOCTL_ELEM_UNLOCK, NULL },
 	{ SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS, NULL },
@@ -393,6 +460,8 @@
 		return err;
 	}
 #endif
+
+	return 0;
 }
 
 module_init(snd_ioctl32_init)
diff -Nru a/sound/core/ioctl32/ioctl32.h b/sound/core/ioctl32/ioctl32.h
--- a/sound/core/ioctl32/ioctl32.h	Tue Oct  1 00:08:17 2002
+++ b/sound/core/ioctl32/ioctl32.h	Tue Oct  1 00:08:17 2002
@@ -26,6 +26,15 @@
 #ifndef __ALSA_IOCTL32_H
 #define __ALSA_IOCTL32_H
 
+#ifndef A
+#ifdef CONFIG_PPC64
+#include <asm/ppc32.h>
+#else
+/* x86-64, sparc64 */
+#define A(__x) ((void *)(unsigned long)(__x))
+#endif
+#endif
+
 #define TO_PTR(x)  A(x)
 
 #define COPY(x)  (dst->x = src->x)
@@ -47,25 +56,38 @@
 
 
 #define DEFINE_ALSA_IOCTL(type) \
-static int snd_ioctl32_##type(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file)\
+static int _snd_ioctl32_##type(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)\
 {\
 	struct sndrv_##type##32 data32;\
 	struct sndrv_##type data;\
+	mm_segment_t oldseg = get_fs();\
 	int err;\
-	if (copy_from_user(&data32, (void*)arg, sizeof(data32)))\
-		return -EFAULT;\
+	set_fs(KERNEL_DS);\
+	if (copy_from_user(&data32, (void*)arg, sizeof(data32))) {\
+		err = -EFAULT;\
+		goto __err;\
+	}\
 	memset(&data, 0, sizeof(data));\
 	convert_from_32(type, &data, &data32);\
-	err = file->f_op->ioctl(file->f_dentry->d_inode, file, cmd, (unsigned long)&data);\
-	if (err < 0)\
-		return err;\
-	if (cmd & (_IOC_READ << _IOC_DIRSHIFT)) {\
+	err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data);\
+	if (err < 0) \
+		goto __err;\
+	if (native_ctl & (_IOC_READ << _IOC_DIRSHIFT)) {\
 		convert_to_32(type, &data32, &data);\
-		if (copy_to_user((void*)arg, &data32, sizeof(data32)))\
-			return -EFAULT;\
+		if (copy_to_user((void*)arg, &data32, sizeof(data32))) {\
+			err = -EFAULT;\
+			goto __err;\
+		}\
 	}\
+ __err: set_fs(oldseg);\
 	return err;\
 }
+
+#define DEFINE_ALSA_IOCTL_ENTRY(name,type,native_ctl) \
+static int snd_ioctl32_##name(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file) {\
+	return _snd_ioctl32_##type(fd, cmd, arg, file, native_ctl);\
+}
+
 
 struct ioctl32_mapper {
 	unsigned int cmd;
diff -Nru a/sound/core/ioctl32/pcm32.c b/sound/core/ioctl32/pcm32.c
--- a/sound/core/ioctl32/pcm32.c	Tue Oct  1 00:08:17 2002
+++ b/sound/core/ioctl32/pcm32.c	Tue Oct  1 00:08:17 2002
@@ -54,8 +54,10 @@
 
 struct sndrv_pcm_hw_params32 {
 	u32 flags;
-	u32 masks[SNDRV_PCM_HW_PARAM_LAST_MASK - SNDRV_PCM_HW_PARAM_FIRST_MASK + 1];
+	struct sndrv_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK - SNDRV_PCM_HW_PARAM_FIRST_MASK + 1]; /* this must be identical */
+	struct sndrv_mask mres[5];	/* reserved masks */
 	struct sndrv_interval32 intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1];
+	struct sndrv_interval ires[9];	/* reserved intervals */
 	u32 rmask;
 	u32 cmask;
 	u32 info;
@@ -64,7 +66,7 @@
 	u32 rate_den;
 	u32 fifo_size;
 	unsigned char reserved[64];
-};
+} __attribute__((packed));
 
 #define numberof(array)  (sizeof(array)/sizeof(array[0]))
 
@@ -103,7 +105,7 @@
 	u32 silence_size;
 	u32 boundary;
 	unsigned char reserved[64];
-};
+} __attribute__((packed));
 
 #define CVT_sndrv_pcm_sw_params()\
 {\
@@ -124,7 +126,7 @@
 	u32 offset;
 	u32 first;
 	u32 step;
-};
+} __attribute__((packed));
 
 #define CVT_sndrv_pcm_channel_info()\
 {\
@@ -137,7 +139,7 @@
 struct timeval32 {
 	s32 tv_sec;
 	s32 tv_usec;
-};
+} __attribute__((packed));
 
 struct sndrv_pcm_status32 {
 	s32 state;
@@ -151,7 +153,7 @@
 	u32 overrange;
 	s32 suspended_state;
 	unsigned char reserved[60];
-};
+} __attribute__((packed));
 
 #define CVT_sndrv_pcm_status()\
 {\
@@ -169,33 +171,58 @@
 	COPY(suspended_state);\
 }
 
+DEFINE_ALSA_IOCTL(pcm_uframes_str);
+DEFINE_ALSA_IOCTL(pcm_sframes_str);
+DEFINE_ALSA_IOCTL(pcm_hw_params);
+DEFINE_ALSA_IOCTL(pcm_sw_params);
+DEFINE_ALSA_IOCTL(pcm_channel_info);
+DEFINE_ALSA_IOCTL(pcm_status);
+
+/*
+ */
 struct sndrv_xferi32 {
 	s32 result;
 	u32 buf;
 	u32 frames;
-};
+} __attribute__((packed));
 
-#define CVT_sndrv_xferi()\
-{\
-	COPY(result);\
-	CPTR(buf);\
-	COPY(frames);\
+static int _snd_ioctl32_xferi(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
+{
+	struct sndrv_xferi32 data32;
+	struct sndrv_xferi data;
+	mm_segment_t oldseg = get_fs();
+	int err;
+
+	set_fs(KERNEL_DS);
+	if (copy_from_user(&data32, (void*)arg, sizeof(data32))) {
+		err = -EFAULT;
+		goto __err;
+	}
+	memset(&data, 0, sizeof(data));
+	data.result = data32.result;
+	data.buf = A(data32.buf);
+	data.frames = data32.frames;
+	err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data);
+	if (err < 0)
+		goto __err;
+	/* copy the result */
+	data32.result = data.result;
+	if (copy_to_user((void*)arg, &data32, sizeof(data32))) {
+		err = -EFAULT;
+		goto __err;
+	}
+ __err:
+	set_fs(oldseg);
+	return err;
 }
 
-DEFINE_ALSA_IOCTL(pcm_uframes_str);
-DEFINE_ALSA_IOCTL(pcm_sframes_str);
-DEFINE_ALSA_IOCTL(pcm_hw_params);
-DEFINE_ALSA_IOCTL(pcm_sw_params);
-DEFINE_ALSA_IOCTL(pcm_channel_info);
-DEFINE_ALSA_IOCTL(pcm_status);
-DEFINE_ALSA_IOCTL(xferi);
 
 /* snd_xfern needs remapping of bufs */
 struct sndrv_xfern32 {
 	s32 result;
 	u32 bufs;  /* this is void **; */
 	u32 frames;
-};
+} __attribute__((packed));
 
 /*
  * xfern ioctl nees to copy (up to) 128 pointers on stack.
@@ -203,7 +230,7 @@
  * handler there expands again the same 128 pointers on stack, so it is better
  * to handle the function (calling pcm_readv/writev) directly in this handler.
  */
-static int snd_ioctl32_xfern(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file)
+static int _snd_ioctl32_xfern(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
 {
 	snd_pcm_file_t *pcm_file;
 	snd_pcm_substream_t *substream;
@@ -211,6 +238,9 @@
 	void *bufs[128];
 	int err = 0, ch, i;
 	u32 *bufptr;
+	mm_segment_t oldseg = get_fs();
+
+	set_fs(KERNEL_DS);
 
 	/* FIXME: need to check whether fop->ioctl is sane */
 
@@ -219,31 +249,44 @@
 	snd_assert(substream != NULL && substream->runtime, return -ENXIO);
 
 	/* check validty of the command */
-	switch (cmd) {
+	switch (native_ctl) {
 	case SNDRV_PCM_IOCTL_WRITEN_FRAMES:
-		if (substream->stream  != SNDRV_PCM_STREAM_PLAYBACK)
-			return -EINVAL;
-		if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
-			return -EBADFD;
+		if (substream->stream  != SNDRV_PCM_STREAM_PLAYBACK) {
+			err = -EINVAL;
+			goto __err;
+		}
+		if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
+			err = -EBADFD;
+			goto __err;
+		}
+		break;
 	case SNDRV_PCM_IOCTL_READN_FRAMES:
-		if (substream->stream  != SNDRV_PCM_STREAM_CAPTURE)
-			return -EINVAL;
+		if (substream->stream  != SNDRV_PCM_STREAM_CAPTURE) {
+			err = -EINVAL;
+			goto __err;
+		}
 		break;
 	}
-	if ((ch = substream->runtime->channels) > 128)
-		return -EINVAL;
-	if (get_user(data32.frames, &srcptr->frames))
-		return -EFAULT;
+	if ((ch = substream->runtime->channels) > 128) {
+		err = -EINVAL;
+		goto __err;
+	}
+	if (get_user(data32.frames, &srcptr->frames)) {
+		err = -EFAULT;
+		goto __err;
+	}
 	__get_user(data32.bufs, &srcptr->bufs);
 	bufptr = (u32*)TO_PTR(data32.bufs);
 	for (i = 0; i < ch; i++) {
 		u32 ptr;
-		if (get_user(ptr, bufptr))
-			return -EFAULT;
+		if (get_user(ptr, bufptr)) {
+			err = -EFAULT;
+			goto __err;
+		}
 		bufs[ch] = (void*)TO_PTR(ptr);
 		bufptr++;
 	}
-	switch (cmd) {
+	switch (native_ctl) {
 	case SNDRV_PCM_IOCTL_WRITEN_FRAMES:
 		err = snd_pcm_lib_writev(substream, bufs, data32.frames);
 		break;
@@ -253,13 +296,115 @@
 	}
 	
 	if (err < 0)
-		return err;
+		goto __err;
 	if (put_user(err, &srcptr->result))
-		return -EFAULT;
+		err = -EFAULT;
+ __err:
+	set_fs(oldseg);
 	return err < 0 ? err : 0;
 }
 
 
+struct sndrv_pcm_hw_params_old32 {
+	u32 flags;
+	u32 masks[SNDRV_PCM_HW_PARAM_SUBFORMAT -
+			   SNDRV_PCM_HW_PARAM_ACCESS + 1];
+	struct sndrv_interval32 intervals[SNDRV_PCM_HW_PARAM_TICK_TIME -
+					SNDRV_PCM_HW_PARAM_SAMPLE_BITS + 1];
+	u32 rmask;
+	u32 cmask;
+	u32 info;
+	u32 msbits;
+	u32 rate_num;
+	u32 rate_den;
+	u32 fifo_size;
+	unsigned char reserved[64];
+} __attribute__((packed));
+
+#define __OLD_TO_NEW_MASK(x) ((x&7)|((x&0x07fffff8)<<5))
+#define __NEW_TO_OLD_MASK(x) ((x&7)|((x&0xffffff00)>>5))
+
+static void snd_pcm_hw_convert_from_old_params(snd_pcm_hw_params_t *params, struct sndrv_pcm_hw_params_old32 *oparams)
+{
+	unsigned int i;
+
+	memset(params, 0, sizeof(*params));
+	params->flags = oparams->flags;
+	for (i = 0; i < sizeof(oparams->masks) / sizeof(unsigned int); i++)
+		params->masks[i].bits[0] = oparams->masks[i];
+	memcpy(params->intervals, oparams->intervals, sizeof(oparams->intervals));
+	params->rmask = __OLD_TO_NEW_MASK(oparams->rmask);
+	params->cmask = __OLD_TO_NEW_MASK(oparams->cmask);
+	params->info = oparams->info;
+	params->msbits = oparams->msbits;
+	params->rate_num = oparams->rate_num;
+	params->rate_den = oparams->rate_den;
+	params->fifo_size = oparams->fifo_size;
+}
+
+static void snd_pcm_hw_convert_to_old_params(struct sndrv_pcm_hw_params_old32 *oparams, snd_pcm_hw_params_t *params)
+{
+	unsigned int i;
+
+	memset(oparams, 0, sizeof(*oparams));
+	oparams->flags = params->flags;
+	for (i = 0; i < sizeof(oparams->masks) / sizeof(unsigned int); i++)
+		oparams->masks[i] = params->masks[i].bits[0];
+	memcpy(oparams->intervals, params->intervals, sizeof(oparams->intervals));
+	oparams->rmask = __NEW_TO_OLD_MASK(params->rmask);
+	oparams->cmask = __NEW_TO_OLD_MASK(params->cmask);
+	oparams->info = params->info;
+	oparams->msbits = params->msbits;
+	oparams->rate_num = params->rate_num;
+	oparams->rate_den = params->rate_den;
+	oparams->fifo_size = params->fifo_size;
+}
+
+static int _snd_ioctl32_pcm_hw_params_old(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
+{
+	struct sndrv_pcm_hw_params_old32 data32;
+	struct sndrv_pcm_hw_params data;
+	mm_segment_t oldseg = get_fs();
+	int err;
+	set_fs(KERNEL_DS);
+	if (copy_from_user(&data32, (void*)arg, sizeof(data32))) {
+		err = -EFAULT;
+		goto __err;
+	}
+	snd_pcm_hw_convert_from_old_params(&data, &data32);
+	err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data);
+	if (err < 0)
+		goto __err;
+	snd_pcm_hw_convert_to_old_params(&data32, &data);
+	if (copy_to_user((void*)arg, &data32, sizeof(data32))) {
+	  err = -EFAULT;
+	  goto __err;
+	}
+ __err: set_fs(oldseg);
+	return err;
+}
+
+
+/*
+ */
+
+DEFINE_ALSA_IOCTL_ENTRY(pcm_hw_refine, pcm_hw_params, SNDRV_PCM_IOCTL_HW_REFINE);
+DEFINE_ALSA_IOCTL_ENTRY(pcm_hw_params, pcm_hw_params, SNDRV_PCM_IOCTL_HW_PARAMS);
+DEFINE_ALSA_IOCTL_ENTRY(pcm_sw_params, pcm_sw_params, SNDRV_PCM_IOCTL_SW_PARAMS);
+DEFINE_ALSA_IOCTL_ENTRY(pcm_hw_refine_old, pcm_hw_params_old, SNDRV_PCM_IOCTL_HW_REFINE);
+DEFINE_ALSA_IOCTL_ENTRY(pcm_hw_params_old, pcm_hw_params_old, SNDRV_PCM_IOCTL_HW_PARAMS);
+DEFINE_ALSA_IOCTL_ENTRY(pcm_status, pcm_status, SNDRV_PCM_IOCTL_STATUS);
+DEFINE_ALSA_IOCTL_ENTRY(pcm_delay, pcm_sframes_str, SNDRV_PCM_IOCTL_DELAY);
+DEFINE_ALSA_IOCTL_ENTRY(pcm_channel_info, pcm_channel_info, SNDRV_PCM_IOCTL_CHANNEL_INFO);
+DEFINE_ALSA_IOCTL_ENTRY(pcm_rewind, pcm_uframes_str, SNDRV_PCM_IOCTL_REWIND);
+DEFINE_ALSA_IOCTL_ENTRY(pcm_readi, xferi, SNDRV_PCM_IOCTL_READI_FRAMES);
+DEFINE_ALSA_IOCTL_ENTRY(pcm_writei, xferi, SNDRV_PCM_IOCTL_WRITEI_FRAMES);
+DEFINE_ALSA_IOCTL_ENTRY(pcm_readn, xfern, SNDRV_PCM_IOCTL_READN_FRAMES);
+DEFINE_ALSA_IOCTL_ENTRY(pcm_writen, xfern, SNDRV_PCM_IOCTL_WRITEN_FRAMES);
+
+
+/*
+ */
 #define AP(x) snd_ioctl32_##x
 
 enum {
@@ -274,17 +419,22 @@
 	SNDRV_PCM_IOCTL_READI_FRAMES32 = _IOR('A', 0x51, struct sndrv_xferi32),
 	SNDRV_PCM_IOCTL_WRITEN_FRAMES32 = _IOW('A', 0x52, struct sndrv_xfern32),
 	SNDRV_PCM_IOCTL_READN_FRAMES32 = _IOR('A', 0x53, struct sndrv_xfern32),
+	SNDRV_PCM_IOCTL_HW_REFINE_OLD32 = _IOWR('A', 0x10, struct sndrv_pcm_hw_params_old32),
+	SNDRV_PCM_IOCTL_HW_PARAMS_OLD32 = _IOWR('A', 0x11, struct sndrv_pcm_hw_params_old32),
+
 };
 
 struct ioctl32_mapper pcm_mappers[] = {
 	{ SNDRV_PCM_IOCTL_PVERSION, NULL },
 	{ SNDRV_PCM_IOCTL_INFO, NULL },
-	{ SNDRV_PCM_IOCTL_HW_REFINE32, AP(pcm_hw_params) },
+	{ SNDRV_PCM_IOCTL_HW_REFINE32, AP(pcm_hw_refine) },
 	{ SNDRV_PCM_IOCTL_HW_PARAMS32, AP(pcm_hw_params) },
+	{ SNDRV_PCM_IOCTL_HW_REFINE_OLD32, AP(pcm_hw_refine_old) },
+	{ SNDRV_PCM_IOCTL_HW_PARAMS_OLD32, AP(pcm_hw_params_old) },
 	{ SNDRV_PCM_IOCTL_HW_FREE, NULL },
 	{ SNDRV_PCM_IOCTL_SW_PARAMS32, AP(pcm_sw_params) },
 	{ SNDRV_PCM_IOCTL_STATUS32, AP(pcm_status) },
-	{ SNDRV_PCM_IOCTL_DELAY32, AP(pcm_sframes_str) },
+	{ SNDRV_PCM_IOCTL_DELAY32, AP(pcm_delay) },
 	{ SNDRV_PCM_IOCTL_CHANNEL_INFO32, AP(pcm_channel_info) },
 	{ SNDRV_PCM_IOCTL_PREPARE, NULL },
 	{ SNDRV_PCM_IOCTL_RESET, NULL },
@@ -292,13 +442,13 @@
 	{ SNDRV_PCM_IOCTL_DROP, NULL },
 	{ SNDRV_PCM_IOCTL_DRAIN, NULL },
 	{ SNDRV_PCM_IOCTL_PAUSE, NULL },
-	{ SNDRV_PCM_IOCTL_REWIND32, AP(pcm_uframes_str) },
+	{ SNDRV_PCM_IOCTL_REWIND32, AP(pcm_rewind) },
 	{ SNDRV_PCM_IOCTL_RESUME, NULL },
 	{ SNDRV_PCM_IOCTL_XRUN, NULL },
-	{ SNDRV_PCM_IOCTL_WRITEI_FRAMES32, AP(xferi) },
-	{ SNDRV_PCM_IOCTL_READI_FRAMES32, AP(xferi) },
-	{ SNDRV_PCM_IOCTL_WRITEN_FRAMES32, AP(xfern) },
-	{ SNDRV_PCM_IOCTL_READN_FRAMES32, AP(xfern) },
+	{ SNDRV_PCM_IOCTL_WRITEI_FRAMES32, AP(pcm_writei) },
+	{ SNDRV_PCM_IOCTL_READI_FRAMES32, AP(pcm_readi) },
+	{ SNDRV_PCM_IOCTL_WRITEN_FRAMES32, AP(pcm_writen) },
+	{ SNDRV_PCM_IOCTL_READN_FRAMES32, AP(pcm_readn) },
 	{ SNDRV_PCM_IOCTL_LINK, NULL },
 	{ SNDRV_PCM_IOCTL_UNLINK, NULL },
 
diff -Nru a/sound/core/ioctl32/rawmidi32.c b/sound/core/ioctl32/rawmidi32.c
--- a/sound/core/ioctl32/rawmidi32.c	Tue Oct  1 00:08:17 2002
+++ b/sound/core/ioctl32/rawmidi32.c	Tue Oct  1 00:08:17 2002
@@ -30,9 +30,9 @@
 	s32 stream;
 	u32 buffer_size;
 	u32 avail_min;
-	unsigned int no_active_sensing: 1;
+	unsigned int no_active_sensing; /* avoid bit-field */
 	unsigned char reserved[16];
-};
+} __attribute__((packed));
 
 #define CVT_sndrv_rawmidi_params()\
 {\
@@ -45,7 +45,7 @@
 struct timeval32 {
 	s32 tv_sec;
 	s32 tv_usec;
-};
+} __attribute__((packed));
 
 struct sndrv_rawmidi_status32 {
 	s32 stream;
@@ -53,7 +53,7 @@
 	u32 avail;
 	u32 xruns;
 	unsigned char reserved[16];
-};
+} __attribute__((packed));
 
 #define CVT_sndrv_rawmidi_status()\
 {\
@@ -67,6 +67,8 @@
 DEFINE_ALSA_IOCTL(rawmidi_params);
 DEFINE_ALSA_IOCTL(rawmidi_status);
 
+DEFINE_ALSA_IOCTL_ENTRY(rawmidi_params, rawmidi_params, SNDRV_RAWMIDI_IOCTL_PARAMS);
+DEFINE_ALSA_IOCTL_ENTRY(rawmidi_status, rawmidi_status, SNDRV_RAWMIDI_IOCTL_STATUS);
 
 #define AP(x) snd_ioctl32_##x
 
diff -Nru a/sound/core/ioctl32/seq32.c b/sound/core/ioctl32/seq32.c
--- a/sound/core/ioctl32/seq32.c	Tue Oct  1 00:08:21 2002
+++ b/sound/core/ioctl32/seq32.c	Tue Oct  1 00:08:21 2002
@@ -27,16 +27,67 @@
 #include <sound/asequencer.h>
 #include "ioctl32.h"
 
+struct sndrv_seq_port_info32 {
+	struct sndrv_seq_addr addr;	/* client/port numbers */
+	char name[64];			/* port name */
+
+	u32 capability;	/* port capability bits */
+	u32 type;		/* port type bits */
+	s32 midi_channels;		/* channels per MIDI port */
+	s32 midi_voices;		/* voices per MIDI port */
+	s32 synth_voices;		/* voices per SYNTH port */
+
+	s32 read_use;			/* R/O: subscribers for output (from this port) */
+	s32 write_use;			/* R/O: subscribers for input (to this port) */
+
+	u32 kernel;			/* reserved for kernel use (must be NULL) */
+	u32 flags;		/* misc. conditioning */
+	char reserved[60];		/* for future use */
+};
+
+#define CVT_sndrv_seq_port_info()\
+{\
+	COPY(addr);\
+	memcpy(dst->name, src->name, sizeof(dst->name));\
+	COPY(capability);\
+	COPY(type);\
+	COPY(midi_channels);\
+	COPY(midi_voices);\
+	COPY(synth_voices);\
+	COPY(read_use);\
+	COPY(write_use);\
+	COPY(flags);\
+}
+
+DEFINE_ALSA_IOCTL(seq_port_info);
+DEFINE_ALSA_IOCTL_ENTRY(create_port, seq_port_info, SNDRV_SEQ_IOCTL_CREATE_PORT);
+DEFINE_ALSA_IOCTL_ENTRY(delete_port, seq_port_info, SNDRV_SEQ_IOCTL_DELETE_PORT);
+DEFINE_ALSA_IOCTL_ENTRY(get_port_info, seq_port_info, SNDRV_SEQ_IOCTL_GET_PORT_INFO);
+DEFINE_ALSA_IOCTL_ENTRY(set_port_info, seq_port_info, SNDRV_SEQ_IOCTL_SET_PORT_INFO);
+DEFINE_ALSA_IOCTL_ENTRY(query_next_port, seq_port_info, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT);
+
+/*
+ */
+#define AP(x) snd_ioctl32_##x
+
+enum {
+  SNDRV_SEQ_IOCTL_CREATE_PORT32 = _IOWR('S', 0x20, struct sndrv_seq_port_info32),
+  SNDRV_SEQ_IOCTL_DELETE_PORT32 = _IOW ('S', 0x21, struct sndrv_seq_port_info32),
+  SNDRV_SEQ_IOCTL_GET_PORT_INFO32 = _IOWR('S', 0x22, struct sndrv_seq_port_info32),
+  SNDRV_SEQ_IOCTL_SET_PORT_INFO32 = _IOW ('S', 0x23, struct sndrv_seq_port_info32),
+  SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT32 = _IOWR('S', 0x52, struct sndrv_seq_port_info32),
+};
+
 struct ioctl32_mapper seq_mappers[] = {
 	{ SNDRV_SEQ_IOCTL_PVERSION, NULL },
 	{ SNDRV_SEQ_IOCTL_CLIENT_ID, NULL },
 	{ SNDRV_SEQ_IOCTL_SYSTEM_INFO, NULL },
 	{ SNDRV_SEQ_IOCTL_GET_CLIENT_INFO, NULL },
 	{ SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, NULL },
-	{ SNDRV_SEQ_IOCTL_CREATE_PORT, NULL },
-	{ SNDRV_SEQ_IOCTL_DELETE_PORT, NULL },
-	{ SNDRV_SEQ_IOCTL_GET_PORT_INFO, NULL },
-	{ SNDRV_SEQ_IOCTL_SET_PORT_INFO, NULL },
+	{ SNDRV_SEQ_IOCTL_CREATE_PORT32, AP(create_port) },
+	{ SNDRV_SEQ_IOCTL_DELETE_PORT32, AP(delete_port) },
+	{ SNDRV_SEQ_IOCTL_GET_PORT_INFO32, AP(get_port_info) },
+	{ SNDRV_SEQ_IOCTL_SET_PORT_INFO32, AP(set_port_info) },
 	{ SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, NULL },
 	{ SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT, NULL },
 	{ SNDRV_SEQ_IOCTL_CREATE_QUEUE, NULL },
@@ -47,8 +98,6 @@
 	{ SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS, NULL },
 	{ SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO, NULL },
 	{ SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO, NULL },
-	{ SNDRV_SEQ_IOCTL_GET_QUEUE_OWNER, NULL },
-	{ SNDRV_SEQ_IOCTL_SET_QUEUE_OWNER, NULL },
 	{ SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER, NULL },
 	{ SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER, NULL },
 	{ SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT, NULL },
@@ -59,6 +108,7 @@
 	{ SNDRV_SEQ_IOCTL_QUERY_SUBS, NULL },
 	{ SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION, NULL },
 	{ SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT, NULL },
-	{ SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, NULL },
+	{ SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT32, AP(query_next_port) },
+	{ SNDRV_SEQ_IOCTL_RUNNING_MODE, NULL },
 	{ 0 },
 };
diff -Nru a/sound/core/ioctl32/timer32.c b/sound/core/ioctl32/timer32.c
--- a/sound/core/ioctl32/timer32.c	Tue Oct  1 00:08:17 2002
+++ b/sound/core/ioctl32/timer32.c	Tue Oct  1 00:08:17 2002
@@ -73,6 +73,8 @@
 DEFINE_ALSA_IOCTL(timer_info);
 DEFINE_ALSA_IOCTL(timer_status);
 
+DEFINE_ALSA_IOCTL_ENTRY(timer_info, timer_info, SNDRV_TIMER_IOCTL_INFO);
+DEFINE_ALSA_IOCTL_ENTRY(timer_status, timer_status, SNDRV_TIMER_IOCTL_STATUS);
 
 /*
  */
diff -Nru a/sound/core/memory.c b/sound/core/memory.c
--- a/sound/core/memory.c	Tue Oct  1 00:08:15 2002
+++ b/sound/core/memory.c	Tue Oct  1 00:08:15 2002
@@ -29,6 +29,9 @@
 #include <linux/pci.h>
 #include <sound/core.h>
 #include <sound/info.h>
+#ifdef CONFIG_SBUS
+#include <asm/sbus.h>
+#endif
 
 /*
  *  memory allocation helpers and debug routines
@@ -405,6 +408,72 @@
 
 #endif /* CONFIG_PCI */
 
+#ifdef CONFIG_SBUS
+
+void *snd_malloc_sbus_pages(struct sbus_dev *sdev,
+			    unsigned long size,
+			    dma_addr_t *dma_addr)
+{
+	int pg;
+	void *res;
+
+	snd_assert(size > 0, return NULL);
+	snd_assert(dma_addr != NULL, return NULL);
+	for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
+	res = sbus_alloc_consistent(sdev, PAGE_SIZE * (1 << pg), dma_addr);
+	if (res != NULL) {
+		struct page *page = virt_to_page(res);
+		struct page *last_page = page + (1 << pg);
+		while (page < last_page)
+			SetPageReserved(page++);
+#ifdef CONFIG_SND_DEBUG_MEMORY
+		snd_alloc_pages += 1 << pg;
+#endif
+	}
+	return res;
+}
+
+void *snd_malloc_sbus_pages_fallback(struct sbus_dev *sdev,
+				     unsigned long size,
+				     dma_addr_t *dma_addr,
+				     unsigned long *res_size)
+{
+	void *res;
+
+	snd_assert(res_size != NULL, return NULL);
+	do {
+		if ((res = snd_malloc_sbus_pages(sdev, size, dma_addr)) != NULL) {
+			*res_size = size;
+			return res;
+		}
+		size >>= 1;
+	} while (size >= PAGE_SIZE);
+	return NULL;
+}
+
+void snd_free_sbus_pages(struct sbus_dev *sdev,
+			 unsigned long size,
+			 void *ptr,
+			 dma_addr_t dma_addr)
+{
+	int pg;
+	struct page *page, *last_page;
+
+	if (ptr == NULL)
+		return;
+	for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
+	page = virt_to_page(ptr);
+	last_page = page + (1 << pg);
+	while (page < last_page)
+		ClearPageReserved(page++);
+	sbus_free_consistent(sdev, PAGE_SIZE * (1 << pg), ptr, dma_addr);
+#ifdef CONFIG_SND_DEBUG_MEMORY
+	snd_alloc_pages -= 1 << pg;
+#endif
+}
+
+#endif /* CONFIG_SBUS */
+
 void *snd_kcalloc(size_t size, int flags)
 {
 	void *ptr;
@@ -439,7 +508,7 @@
 		size_t c = count;
 		if (c > sizeof(buf))
 			c = sizeof(buf);
-		memcpy_fromio(buf, src, c);
+		memcpy_fromio(buf, (void*)src, c);
 		if (copy_to_user(dst, buf, c))
 			return -EFAULT;
 		count -= c;
@@ -462,7 +531,7 @@
 			c = sizeof(buf);
 		if (copy_from_user(buf, src, c))
 			return -EFAULT;
-		memcpy_toio(dst, buf, c);
+		memcpy_toio((void*)dst, buf, c);
 		count -= c;
 		dst += c;
 		src += c;
@@ -484,7 +553,7 @@
  */
 #ifdef __i386__
 #define get_phys_addr(x) virt_to_phys(x)
-#else /* ppc */
+#else /* ppc and x86-64 */
 #define get_phys_addr(x) virt_to_bus(x)
 #endif
 void *snd_pci_hack_alloc_consistent(struct pci_dev *hwdev, size_t size,
diff -Nru a/sound/core/oss/io.c b/sound/core/oss/io.c
--- a/sound/core/oss/io.c	Tue Oct  1 00:08:16 2002
+++ b/sound/core/oss/io.c	Tue Oct  1 00:08:16 2002
@@ -24,6 +24,7 @@
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
+#include <sound/pcm_params.h>
 #include "pcm_plugin.h"
 
 #define pcm_write(plug,buf,count) snd_pcm_oss_write3(plug,buf,count,1)
diff -Nru a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
--- a/sound/core/oss/mixer_oss.c	Tue Oct  1 00:08:18 2002
+++ b/sound/core/oss/mixer_oss.c	Tue Oct  1 00:08:18 2002
@@ -341,14 +341,14 @@
 			return put_user(tmp, (int *)arg) ? -EFAULT : 0;
 		}
 	}
-	if (cmd & IOC_IN) {
+	if (cmd & SIOC_IN) {
 		if (get_user(tmp, (int *)arg))
 			return -EFAULT;
 		tmp = snd_mixer_oss_set_volume(fmixer, cmd & 0xff, tmp);
 		if (tmp < 0)
 			return tmp;
 		return put_user(tmp, (int *)arg) ? -EFAULT : 0;
-	} else if (cmd & IOC_OUT) {
+	} else if (cmd & SIOC_OUT) {
 		tmp = snd_mixer_oss_get_volume(fmixer, cmd & 0xff);
 		if (tmp < 0)
 			return tmp;
diff -Nru a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
--- a/sound/core/oss/pcm_oss.c	Tue Oct  1 00:08:19 2002
+++ b/sound/core/oss/pcm_oss.c	Tue Oct  1 00:08:19 2002
@@ -267,8 +267,8 @@
 	int err;
 	int direct;
 	int format, sformat, n;
-	unsigned int sformat_mask;
-	unsigned int mask;
+	snd_mask_t sformat_mask;
+	snd_mask_t mask;
 
 	if (atomic_read(&runtime->mmap_count)) {
 		direct = 1;
@@ -280,12 +280,13 @@
 	_snd_pcm_hw_params_any(&sparams);
 	_snd_pcm_hw_param_setinteger(&sparams, SNDRV_PCM_HW_PARAM_PERIODS);
 	_snd_pcm_hw_param_min(&sparams, SNDRV_PCM_HW_PARAM_PERIODS, 2, 0);
+	snd_mask_none(&mask);
 	if (atomic_read(&runtime->mmap_count))
-		mask = 1 << SNDRV_PCM_ACCESS_MMAP_INTERLEAVED;
+		snd_mask_set(&mask, SNDRV_PCM_ACCESS_MMAP_INTERLEAVED);
 	else {
-		mask = 1 << SNDRV_PCM_ACCESS_RW_INTERLEAVED;
+		snd_mask_set(&mask, SNDRV_PCM_ACCESS_RW_INTERLEAVED);
 		if (!direct)
-			mask |= 1 << SNDRV_PCM_ACCESS_RW_NONINTERLEAVED;
+			snd_mask_set(&mask, SNDRV_PCM_ACCESS_RW_NONINTERLEAVED);
 	}
 	err = snd_pcm_hw_param_mask(substream, &sparams, SNDRV_PCM_HW_PARAM_ACCESS, &mask);
 	if (err < 0) {
@@ -301,11 +302,11 @@
 	if (direct)
 		sformat = format;
 	else
-		sformat = snd_pcm_plug_slave_format(format, sformat_mask);
+		sformat = snd_pcm_plug_slave_format(format, &sformat_mask);
 
-	if (sformat < 0 || !(sformat_mask & (1 << sformat))) {
+	if (sformat < 0 || !snd_mask_test(&sformat_mask, sformat)) {
 		for (sformat = 0; sformat <= SNDRV_PCM_FORMAT_LAST; sformat++) {
-			if ((sformat_mask & (1 << sformat)) &&
+			if (snd_mask_test(&sformat_mask, sformat) &&
 			    snd_pcm_oss_format_to(sformat) >= 0)
 				break;
 		}
@@ -935,7 +936,7 @@
 	int direct;
 	snd_pcm_hw_params_t params;
 	unsigned int formats = 0;
-	unsigned int format_mask;
+	snd_mask_t format_mask;
 	int fmt;
 	if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
 		return err;
@@ -955,7 +956,7 @@
 	snd_assert(err >= 0, return err);
 	format_mask = *hw_param_mask(&params, SNDRV_PCM_HW_PARAM_FORMAT); 
 	for (fmt = 0; fmt < 32; ++fmt) {
-		if (format_mask & (1 << fmt)) {
+		if (snd_mask_test(&format_mask, fmt)) {
 			int f = snd_pcm_oss_format_to(fmt);
 			if (f >= 0)
 				formats |= f;
diff -Nru a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c
--- a/sound/core/oss/pcm_plugin.c	Tue Oct  1 00:08:16 2002
+++ b/sound/core/oss/pcm_plugin.c	Tue Oct  1 00:08:16 2002
@@ -31,6 +31,7 @@
 #include <linux/vmalloc.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
+#include <sound/pcm_params.h>
 #include "pcm_plugin.h"
 
 #define snd_pcm_plug_first(plug) ((plug)->runtime->oss.plugin_first)
@@ -280,20 +281,23 @@
 	return frames;
 }
 
-unsigned int snd_pcm_plug_formats(unsigned int formats)
+static int snd_pcm_plug_formats(snd_mask_t *mask, int format)
 {
-	int linfmts = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 |
+	snd_mask_t formats = *mask;
+	u64 linfmts = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 |
 		       SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_S16_LE |
 		       SNDRV_PCM_FMTBIT_U16_BE | SNDRV_PCM_FMTBIT_S16_BE |
 		       SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_S24_LE |
 		       SNDRV_PCM_FMTBIT_U24_BE | SNDRV_PCM_FMTBIT_S24_BE |
 		       SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_S32_LE |
 		       SNDRV_PCM_FMTBIT_U32_BE | SNDRV_PCM_FMTBIT_S32_BE);
-	formats |= SNDRV_PCM_FMTBIT_MU_LAW;
+	snd_mask_set(&formats, SNDRV_PCM_FORMAT_MU_LAW);
 	
-	if (formats & linfmts)
-		formats |= linfmts;
-	return formats;
+	if (formats.bits[0] & (u32)linfmts)
+		formats.bits[0] |= (u32)linfmts;
+	if (formats.bits[1] & (u32)(linfmts >> 32))
+		formats.bits[1] |= (u32)(linfmts >> 32);
+	return snd_mask_test(&formats, format);
 }
 
 static int preferred_formats[] = {
@@ -313,11 +317,11 @@
 	SNDRV_PCM_FORMAT_U8
 };
 
-int snd_pcm_plug_slave_format(int format, unsigned int format_mask)
+int snd_pcm_plug_slave_format(int format, snd_mask_t *format_mask)
 {
-	if (format_mask & (1 << format))
+	if (snd_mask_test(format_mask, format))
 		return format;
-	if ((snd_pcm_plug_formats(format_mask) & (1 << format)) == 0)
+	if (! snd_pcm_plug_formats(format_mask, format))
 		return -EINVAL;
 	if (snd_pcm_format_linear(format)) {
 		int width = snd_pcm_format_width(format);
@@ -333,7 +337,7 @@
 				for (sgn = 0; sgn < 2; ++sgn) {
 					format1 = snd_pcm_build_linear_format(width1, unsignd1, big1);
 					if (format1 >= 0 &&
-					    format_mask & (1 << format1))
+					    snd_mask_test(format_mask, format1))
 						goto _found;
 					unsignd1 = !unsignd1;
 				}
@@ -354,7 +358,7 @@
 		case SNDRV_PCM_FORMAT_MU_LAW:
 			for (i = 0; i < sizeof(preferred_formats) / sizeof(preferred_formats[0]); ++i) {
 				int format1 = preferred_formats[i];
-				if (format_mask & (1 << format1))
+				if (snd_mask_test(format_mask, format1))
 					return format1;
 			}
 		default:
diff -Nru a/sound/core/oss/pcm_plugin.h b/sound/core/oss/pcm_plugin.h
--- a/sound/core/oss/pcm_plugin.h	Tue Oct  1 00:08:19 2002
+++ b/sound/core/oss/pcm_plugin.h	Tue Oct  1 00:08:19 2002
@@ -197,13 +197,11 @@
 			      snd_pcm_plugin_format_t *dst_format,
 			      snd_pcm_plugin_t **r_plugin);
 
-unsigned int snd_pcm_plug_formats(unsigned int formats);
-
 int snd_pcm_plug_format_plugins(snd_pcm_plug_t *substream,
 				snd_pcm_hw_params_t *params,
 				snd_pcm_hw_params_t *slave_params);
 
-int snd_pcm_plug_slave_format(int format, unsigned int format_mask);
+int snd_pcm_plug_slave_format(int format, snd_mask_t *format_mask);
 
 int snd_pcm_plugin_append(snd_pcm_plugin_t *plugin);
 
diff -Nru a/sound/core/pcm.c b/sound/core/pcm.c
--- a/sound/core/pcm.c	Tue Oct  1 00:08:21 2002
+++ b/sound/core/pcm.c	Tue Oct  1 00:08:21 2002
@@ -184,6 +184,18 @@
 	FORMAT(MPEG),
 	FORMAT(GSM),
 	FORMAT(SPECIAL),
+	FORMAT(S24_3LE),
+	FORMAT(S24_3BE),
+	FORMAT(U24_3LE),
+	FORMAT(U24_3BE),
+	FORMAT(S20_3LE),
+	FORMAT(S20_3BE),
+	FORMAT(U20_3LE),
+	FORMAT(U20_3BE),
+	FORMAT(S18_3LE),
+	FORMAT(S18_3BE),
+	FORMAT(U18_3LE),
+	FORMAT(U18_3BE),
 };
 
 char *snd_pcm_subformat_names[] = {
@@ -741,16 +753,15 @@
 		kfree(runtime);
 		return -ENOMEM;
 	}
+	memset((void*)runtime->status, 0, size);
 
 	size = PAGE_ALIGN(sizeof(snd_pcm_mmap_control_t));
 	runtime->control = snd_malloc_pages(size, GFP_KERNEL);
 	if (runtime->control == NULL) {
-		kfree((void *)runtime->status);
+		snd_free_pages((void*)runtime->status, PAGE_ALIGN(sizeof(snd_pcm_mmap_status_t)));
 		kfree(runtime);
 		return -ENOMEM;
 	}
-
-	memset((void*)runtime->status, 0, size);
 	memset((void*)runtime->control, 0, size);
 
 	init_waitqueue_head(&runtime->sleep);
@@ -828,8 +839,7 @@
 	list_for_each(list, &snd_pcm_notify_list) {
 		snd_pcm_notify_t *notify;
 		notify = list_entry(list, snd_pcm_notify_t, list);
-		if (notify->n_register)
-			notify->n_register(-1 /* idx + SNDRV_MINOR_PCM */, pcm);
+		notify->n_register(-1 /* idx + SNDRV_MINOR_PCM */, pcm);
 	}
 	snd_pcm_lock(1);
 	return 0;
@@ -866,8 +876,7 @@
 	list_for_each(list, &snd_pcm_notify_list) {
 		snd_pcm_notify_t *notify;
 		notify = list_entry(list, snd_pcm_notify_t, list);
-		if (notify->n_unregister)
-			notify->n_unregister(-1 /* SNDRV_MINOR_PCM + idx */, pcm);
+		notify->n_unregister(-1 /* SNDRV_MINOR_PCM + idx */, pcm);
 	}
 	snd_pcm_devices[idx] = NULL;
 	snd_pcm_lock(1);
diff -Nru a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
--- a/sound/core/pcm_lib.c	Tue Oct  1 00:08:17 2002
+++ b/sound/core/pcm_lib.c	Tue Oct  1 00:08:17 2002
@@ -810,12 +810,26 @@
 }				    
 
 int snd_pcm_hw_constraint_mask(snd_pcm_runtime_t *runtime, snd_pcm_hw_param_t var,
-			       unsigned int mask)
+			       u_int32_t mask)
 {
 	snd_pcm_hw_constraints_t *constrs = &runtime->hw_constraints;
-	unsigned int *maskp = constrs_mask(constrs, var);
-	*maskp &= mask;
-	if (*maskp == 0)
+	snd_mask_t *maskp = constrs_mask(constrs, var);
+	*maskp->bits &= mask;
+	memset(maskp->bits + 1, 0, (SNDRV_MASK_MAX-32) / 8); /* clear rest */
+	if (*maskp->bits == 0)
+		return -EINVAL;
+	return 0;
+}
+
+int snd_pcm_hw_constraint_mask64(snd_pcm_runtime_t *runtime, snd_pcm_hw_param_t var,
+				 u_int64_t mask)
+{
+	snd_pcm_hw_constraints_t *constrs = &runtime->hw_constraints;
+	snd_mask_t *maskp = constrs_mask(constrs, var);
+	maskp->bits[0] &= (u_int32_t)mask;
+	maskp->bits[1] &= (u_int32_t)(mask >> 32);
+	memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX-64) / 8); /* clear rest */
+	if (! maskp->bits[0] && ! maskp->bits[1])
 		return -EINVAL;
 	return 0;
 }
@@ -946,6 +960,26 @@
 				   var, -1);
 }
 
+static int snd_pcm_hw_rule_pow2(snd_pcm_hw_params_t *params, snd_pcm_hw_rule_t *rule)
+{
+	static int pow2_sizes[] = {
+		1<<0, 1<<1, 1<<2, 1<<3, 1<<4, 1<<5, 1<<6, 1<<7,
+		1<<8, 1<<9, 1<<10, 1<<11, 1<<12, 1<<13, 1<<14, 1<<15,
+		1<<16, 1<<17, 1<<18, 1<<19, 1<<20, 1<<21, 1<<22, 1<<23,
+		1<<24, 1<<25, 1<<26, 1<<27, 1<<28, 1<<29, 1<<30
+	};
+	return snd_interval_list(hw_param_interval(params, rule->var),
+				 sizeof(pow2_sizes)/sizeof(int), pow2_sizes, 0);
+}		
+
+int snd_pcm_hw_constraint_pow2(snd_pcm_runtime_t *runtime,
+			       unsigned int cond,
+			       snd_pcm_hw_param_t var)
+{
+	return snd_pcm_hw_rule_add(runtime, cond, var, 
+				   snd_pcm_hw_rule_pow2, NULL,
+				   var, -1);
+}
 
 /* To use the same code we have in alsa-lib */
 #define snd_pcm_t snd_pcm_substream_t
@@ -982,7 +1016,9 @@
 {
 	unsigned int k;
 	memset(params, 0, sizeof(*params));
-	for (k = 0; k <= SNDRV_PCM_HW_PARAM_LAST; k++)
+	for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++)
+		_snd_pcm_hw_param_any(params, k);
+	for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++)
 		_snd_pcm_hw_param_any(params, k);
 	params->info = ~0U;
 }
@@ -1883,7 +1919,7 @@
 			frames = cont;
 		if (frames == 0 && runtime->status->state == SNDRV_PCM_STATE_PAUSED) {
 			err = -EPIPE;
-			goto _end;
+			goto _end_unlock;
 		}
 		snd_assert(frames != 0,
 			   spin_unlock_irq(&runtime->lock);
@@ -2348,6 +2384,7 @@
 EXPORT_SYMBOL(snd_pcm_hw_constraint_msbits);
 EXPORT_SYMBOL(snd_pcm_hw_constraint_minmax);
 EXPORT_SYMBOL(snd_pcm_hw_constraint_integer);
+EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2);
 EXPORT_SYMBOL(snd_pcm_hw_rule_add);
 EXPORT_SYMBOL(snd_pcm_set_ops);
 EXPORT_SYMBOL(snd_pcm_set_sync);
@@ -2378,4 +2415,8 @@
 #ifdef CONFIG_PCI
 EXPORT_SYMBOL(snd_pcm_lib_preallocate_pci_pages);
 EXPORT_SYMBOL(snd_pcm_lib_preallocate_pci_pages_for_all);
+#endif
+#ifdef CONFIG_SBUS
+EXPORT_SYMBOL(snd_pcm_lib_preallocate_sbus_pages);
+EXPORT_SYMBOL(snd_pcm_lib_preallocate_sbus_pages_for_all);
 #endif
diff -Nru a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c
--- a/sound/core/pcm_memory.c	Tue Oct  1 00:08:18 2002
+++ b/sound/core/pcm_memory.c	Tue Oct  1 00:08:18 2002
@@ -59,6 +59,11 @@
 		snd_free_pci_pages((struct pci_dev *)substream->dma_private, substream->dma_bytes, substream->dma_area, substream->dma_addr);
 		break;
 #endif
+#ifdef CONFIG_SBUS
+	case SNDRV_PCM_DMA_TYPE_SBUS:
+		snd_free_sbus_pages((struct sbus_dev *)substream->dma_private, substream->dma_bytes, substream->dma_area, substream->dma_addr);
+		break;
+#endif
 	}
 	substream->dma_area = NULL;
 }
@@ -129,6 +134,11 @@
 				dma_area = snd_malloc_pci_pages((struct pci_dev *)substream->dma_private, size, &dma_addr);
 				break;
 #endif
+#ifdef CONFIG_SBUS
+			case SNDRV_PCM_DMA_TYPE_SBUS:
+				dma_area = snd_malloc_sbus_pages((struct sbus_dev *)substream->dma_private, size, &dma_addr);
+				break;
+#endif
 			default:
 				dma_area = NULL;
 				dma_addr = 0UL;
@@ -177,6 +187,11 @@
 			dma_area = snd_malloc_pci_pages_fallback((struct pci_dev *)substream->dma_private, size, &dma_addr, &rsize);
 			break;
 #endif
+#ifdef CONFIG_SBUS
+		case SNDRV_PCM_DMA_TYPE_SBUS:
+			dma_area = snd_malloc_sbus_pages_fallback((struct sbus_dev *)substream->dma_private, size, &dma_addr, &rsize);
+			break;
+#endif
 		default:
 			size = 0;
 		}
@@ -288,6 +303,11 @@
 			dma_area = snd_malloc_pci_pages((struct pci_dev *)substream->dma_private, size, &dma_addr);
 			break;
 #endif
+#ifdef CONFIG_SBUS
+		case SNDRV_PCM_DMA_TYPE_SBUS:
+			dma_area = snd_malloc_sbus_pages((struct sbus_dev *)substream->dma_private, size, &dma_addr);
+			break;
+#endif
 		default:
 			return -ENXIO;
 		}
@@ -321,6 +341,11 @@
 			snd_free_pci_pages((struct pci_dev *)substream->dma_private, runtime->dma_bytes, runtime->dma_area, runtime->dma_addr);
 			break;
 #endif
+#ifdef CONFIG_SBUS
+		case SNDRV_PCM_DMA_TYPE_SBUS:
+			snd_free_sbus_pages((struct sbus_dev *)substream->dma_private, runtime->dma_bytes, runtime->dma_area, runtime->dma_addr);
+			break;
+#endif
 		}
 	}
 	runtime->dma_area = NULL;
@@ -355,3 +380,30 @@
 }
 
 #endif /* CONFIG_PCI */
+
+#ifdef CONFIG_SBUS
+
+int snd_pcm_lib_preallocate_sbus_pages(struct sbus_dev *sdev,
+				       snd_pcm_substream_t *substream,
+				       size_t size, size_t max)
+{
+	substream->dma_type = SNDRV_PCM_DMA_TYPE_SBUS;
+	substream->dma_private = sdev;
+	return snd_pcm_lib_preallocate_pages1(substream, size, max);
+}
+
+int snd_pcm_lib_preallocate_sbus_pages_for_all(struct sbus_dev *sdev,
+					       snd_pcm_t *pcm,
+					       size_t size, size_t max)
+{
+	snd_pcm_substream_t *substream;
+	int stream, err;
+
+	for (stream = 0; stream < 2; stream++)
+		for (substream = pcm->streams[stream].substream; substream; substream = substream->next)
+			if ((err = snd_pcm_lib_preallocate_sbus_pages(sdev, substream, size, max)) < 0)
+				return err;
+	return 0;
+}
+
+#endif /* CONFIG_SBUS */
diff -Nru a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c
--- a/sound/core/pcm_misc.c	Tue Oct  1 00:08:19 2002
+++ b/sound/core/pcm_misc.c	Tue Oct  1 00:08:19 2002
@@ -41,6 +41,12 @@
 	case SNDRV_PCM_FORMAT_S24_BE:
 	case SNDRV_PCM_FORMAT_S32_LE:
 	case SNDRV_PCM_FORMAT_S32_BE:
+	case SNDRV_PCM_FORMAT_S24_3LE:
+	case SNDRV_PCM_FORMAT_S24_3BE:
+	case SNDRV_PCM_FORMAT_S20_3LE:
+	case SNDRV_PCM_FORMAT_S20_3BE:
+	case SNDRV_PCM_FORMAT_S18_3LE:
+	case SNDRV_PCM_FORMAT_S18_3BE:
 		return 1;
 	case SNDRV_PCM_FORMAT_U8:
 	case SNDRV_PCM_FORMAT_U16_LE:
@@ -49,6 +55,12 @@
 	case SNDRV_PCM_FORMAT_U24_BE:
 	case SNDRV_PCM_FORMAT_U32_LE:
 	case SNDRV_PCM_FORMAT_U32_BE:
+	case SNDRV_PCM_FORMAT_U24_3LE:
+	case SNDRV_PCM_FORMAT_U24_3BE:
+	case SNDRV_PCM_FORMAT_U20_3LE:
+	case SNDRV_PCM_FORMAT_U20_3BE:
+	case SNDRV_PCM_FORMAT_U18_3LE:
+	case SNDRV_PCM_FORMAT_U18_3BE:
 		return 0;
 	default:
 		return -EINVAL;
@@ -82,6 +94,12 @@
 	case SNDRV_PCM_FORMAT_FLOAT_LE:
 	case SNDRV_PCM_FORMAT_FLOAT64_LE:
 	case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
+	case SNDRV_PCM_FORMAT_S24_3LE:
+	case SNDRV_PCM_FORMAT_S20_3LE:
+	case SNDRV_PCM_FORMAT_S18_3LE:
+	case SNDRV_PCM_FORMAT_U24_3LE:
+	case SNDRV_PCM_FORMAT_U20_3LE:
+	case SNDRV_PCM_FORMAT_U18_3LE:
 		return 1;
 	case SNDRV_PCM_FORMAT_S16_BE:
 	case SNDRV_PCM_FORMAT_U16_BE:
@@ -92,6 +110,12 @@
 	case SNDRV_PCM_FORMAT_FLOAT_BE:
 	case SNDRV_PCM_FORMAT_FLOAT64_BE:
 	case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE:
+	case SNDRV_PCM_FORMAT_S24_3BE:
+	case SNDRV_PCM_FORMAT_S20_3BE:
+	case SNDRV_PCM_FORMAT_S18_3BE:
+	case SNDRV_PCM_FORMAT_U24_3BE:
+	case SNDRV_PCM_FORMAT_U20_3BE:
+	case SNDRV_PCM_FORMAT_U18_3BE:
 		return 0;
 	default:
 		return -EINVAL;
@@ -128,10 +152,24 @@
 	case SNDRV_PCM_FORMAT_U16_LE:
 	case SNDRV_PCM_FORMAT_U16_BE:
 		return 16;
+	case SNDRV_PCM_FORMAT_S18_3LE:
+	case SNDRV_PCM_FORMAT_S18_3BE:
+	case SNDRV_PCM_FORMAT_U18_3LE:
+	case SNDRV_PCM_FORMAT_U18_3BE:
+		return 18;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+	case SNDRV_PCM_FORMAT_S20_3BE:
+	case SNDRV_PCM_FORMAT_U20_3LE:
+	case SNDRV_PCM_FORMAT_U20_3BE:
+		return 20;
 	case SNDRV_PCM_FORMAT_S24_LE:
 	case SNDRV_PCM_FORMAT_S24_BE:
 	case SNDRV_PCM_FORMAT_U24_LE:
 	case SNDRV_PCM_FORMAT_U24_BE:
+	case SNDRV_PCM_FORMAT_S24_3LE:
+	case SNDRV_PCM_FORMAT_S24_3BE:
+	case SNDRV_PCM_FORMAT_U24_3LE:
+	case SNDRV_PCM_FORMAT_U24_3BE:
 		return 24;
 	case SNDRV_PCM_FORMAT_S32_LE:
 	case SNDRV_PCM_FORMAT_S32_BE:
@@ -167,6 +205,19 @@
 	case SNDRV_PCM_FORMAT_U16_LE:
 	case SNDRV_PCM_FORMAT_U16_BE:
 		return 16;
+	case SNDRV_PCM_FORMAT_S18_3LE:
+	case SNDRV_PCM_FORMAT_S18_3BE:
+	case SNDRV_PCM_FORMAT_U18_3LE:
+	case SNDRV_PCM_FORMAT_U18_3BE:
+	case SNDRV_PCM_FORMAT_S20_3LE:
+	case SNDRV_PCM_FORMAT_S20_3BE:
+	case SNDRV_PCM_FORMAT_U20_3LE:
+	case SNDRV_PCM_FORMAT_U20_3BE:
+	case SNDRV_PCM_FORMAT_S24_3LE:
+	case SNDRV_PCM_FORMAT_S24_3BE:
+	case SNDRV_PCM_FORMAT_U24_3LE:
+	case SNDRV_PCM_FORMAT_U24_3BE:
+		return 24;
 	case SNDRV_PCM_FORMAT_S24_LE:
 	case SNDRV_PCM_FORMAT_S24_BE:
 	case SNDRV_PCM_FORMAT_U24_LE:
@@ -204,6 +255,19 @@
 	case SNDRV_PCM_FORMAT_U16_LE:
 	case SNDRV_PCM_FORMAT_U16_BE:
 		return samples * 2;
+	case SNDRV_PCM_FORMAT_S18_3LE:
+	case SNDRV_PCM_FORMAT_S18_3BE:
+	case SNDRV_PCM_FORMAT_U18_3LE:
+	case SNDRV_PCM_FORMAT_U18_3BE:
+	case SNDRV_PCM_FORMAT_S20_3LE:
+	case SNDRV_PCM_FORMAT_S20_3BE:
+	case SNDRV_PCM_FORMAT_U20_3LE:
+	case SNDRV_PCM_FORMAT_U20_3BE:
+	case SNDRV_PCM_FORMAT_S24_3LE:
+	case SNDRV_PCM_FORMAT_S24_3BE:
+	case SNDRV_PCM_FORMAT_U24_3LE:
+	case SNDRV_PCM_FORMAT_U24_3BE:
+		return samples * 3;
 	case SNDRV_PCM_FORMAT_S24_LE:
 	case SNDRV_PCM_FORMAT_S24_BE:
 	case SNDRV_PCM_FORMAT_U24_LE:
@@ -243,6 +307,12 @@
 	case SNDRV_PCM_FORMAT_S24_BE:
 	case SNDRV_PCM_FORMAT_S32_LE:
 	case SNDRV_PCM_FORMAT_S32_BE:
+	case SNDRV_PCM_FORMAT_S24_3LE:
+	case SNDRV_PCM_FORMAT_S24_3BE:
+	case SNDRV_PCM_FORMAT_S20_3LE:
+	case SNDRV_PCM_FORMAT_S20_3BE:
+	case SNDRV_PCM_FORMAT_S18_3LE:
+	case SNDRV_PCM_FORMAT_S18_3BE:
 		return 0;
 	case SNDRV_PCM_FORMAT_U8:
 		return 0x8080808080808080ULL;
@@ -273,6 +343,15 @@
 	case SNDRV_PCM_FORMAT_U32_BE:
 		return 0x8000000080000000ULL;
 #endif
+	case SNDRV_PCM_FORMAT_U24_3LE:
+	case SNDRV_PCM_FORMAT_U24_3BE:
+		return 0x0000800000800000ULL;
+	case SNDRV_PCM_FORMAT_U20_3LE:
+	case SNDRV_PCM_FORMAT_U20_3BE:
+		return 0x0000080000080000ULL;
+	case SNDRV_PCM_FORMAT_U18_3LE:
+	case SNDRV_PCM_FORMAT_U18_3BE:
+		return 0x0000020000020000ULL;
 	case SNDRV_PCM_FORMAT_FLOAT_LE:
 	{
 		union {
@@ -379,20 +458,45 @@
 	}
 	case 16: {
 		u_int16_t silence = snd_pcm_format_silence_64(format);
-		while (samples-- > 0)
-			*((u_int16_t *)data)++ = silence;
+		if (! silence)
+			memset(data, 0, samples * 2);
+		else {
+			while (samples-- > 0)
+				*((u_int16_t *)data)++ = silence;
+		}
 		break;
 	}
+	case 24: {
+		u_int32_t silence = snd_pcm_format_silence_64(format);
+		if (! silence)
+			memset(data, 0, samples * 3);
+		else {
+			/* FIXME: rewrite in the more better way.. */
+			int i;
+			while (samples-- > 0) {
+				for (i = 0; i < 3; i++)
+					*((u_int8_t *)data)++ = silence >> (i * 8);
+			}
+		}
+	}
 	case 32: {
 		u_int32_t silence = snd_pcm_format_silence_64(format);
-		while (samples-- > 0)
-			*((u_int32_t *)data)++ = silence;
+		if (! silence)
+			memset(data, 0, samples * 4);
+		else {
+			while (samples-- > 0)
+				*((u_int32_t *)data)++ = silence;
+		}
 		break;
 	}
 	case 64: {
 		u_int64_t silence = snd_pcm_format_silence_64(format);
-		while (samples-- > 0)
-			*((u_int64_t *)data)++ = silence;
+		if (! silence)
+			memset(data, 0, samples * 8);
+		else {
+			while (samples-- > 0)
+				*((u_int64_t *)data)++ = silence;
+		}
 		break;
 	}
 	default:
diff -Nru a/sound/core/pcm_native.c b/sound/core/pcm_native.c
--- a/sound/core/pcm_native.c	Tue Oct  1 00:08:16 2002
+++ b/sound/core/pcm_native.c	Tue Oct  1 00:08:16 2002
@@ -32,6 +32,36 @@
 #include <sound/pcm_params.h>
 #include <sound/minors.h>
 
+/*
+ *  Compatibility
+ */
+
+struct sndrv_pcm_hw_params_old {
+	unsigned int flags;
+	unsigned int masks[SNDRV_PCM_HW_PARAM_SUBFORMAT -
+			   SNDRV_PCM_HW_PARAM_ACCESS + 1];
+	struct sndrv_interval intervals[SNDRV_PCM_HW_PARAM_TICK_TIME -
+					SNDRV_PCM_HW_PARAM_SAMPLE_BITS + 1];
+	unsigned int rmask;
+	unsigned int cmask;
+	unsigned int info;
+	unsigned int msbits;
+	unsigned int rate_num;
+	unsigned int rate_den;
+	sndrv_pcm_uframes_t fifo_size;
+	unsigned char reserved[64];
+};
+
+#define SNDRV_PCM_IOCTL_HW_REFINE_OLD _IOWR('A', 0x10, struct sndrv_pcm_hw_params_old)
+#define SNDRV_PCM_IOCTL_HW_PARAMS_OLD _IOWR('A', 0x11, struct sndrv_pcm_hw_params_old)
+
+static int snd_pcm_hw_refine_old_user(snd_pcm_substream_t * substream, struct sndrv_pcm_hw_params_old * _oparams);
+static int snd_pcm_hw_params_old_user(snd_pcm_substream_t * substream, struct sndrv_pcm_hw_params_old * _oparams);
+
+/*
+ *
+ */
+
 static rwlock_t pcm_link_lock = RW_LOCK_UNLOCKED;
 
 static inline mm_segment_t snd_enter_user(void)
@@ -52,6 +82,8 @@
 		__MOD_DEC_USE_COUNT(module);
 }
 
+
+
 int snd_pcm_info(snd_pcm_substream_t * substream, snd_pcm_info_t *info)
 {
 	snd_pcm_runtime_t * runtime;
@@ -121,7 +153,7 @@
 	snd_mask_t *m = NULL;
 	snd_pcm_hw_constraints_t *constrs = &substream->runtime->hw_constraints;
 	unsigned int rstamps[constrs->rules_num];
-	unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST + 1];
+	unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1];
 	unsigned int stamp = 2;
 	int changed, again;
 
@@ -187,7 +219,7 @@
 
 	for (k = 0; k < constrs->rules_num; k++)
 		rstamps[k] = 0;
-	for (k = 0; k <= SNDRV_PCM_HW_PARAM_LAST; k++) 
+	for (k = 0; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) 
 		vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0;
 	do {
 		again = 0;
@@ -211,7 +243,7 @@
 				printk("%s = ", snd_pcm_hw_param_names[r->var]);
 				if (hw_is_mask(r->var)) {
 					m = hw_param_mask(params, r->var);
-					printk("%x", *m);
+					printk("%x", *m->bits);
 				} else {
 					i = hw_param_interval(params, r->var);
 					if (i->empty)
@@ -228,7 +260,7 @@
 			if (r->var >= 0) {
 				printk(" -> ");
 				if (hw_is_mask(r->var))
-					printk("%x", *m);
+					printk("%x", *m->bits);
 				else {
 					if (i->empty)
 						printk("empty");
@@ -1369,16 +1401,17 @@
 {
 	unsigned int k;
 	snd_interval_t *i = hw_param_interval(params, rule->deps[0]);
-	unsigned int m = ~0U;
-	unsigned int *mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+	snd_mask_t m;
+	snd_mask_t *mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+	snd_mask_any(&m);
 	for (k = 0; k <= SNDRV_PCM_FORMAT_LAST; ++k) {
 		int bits;
-		if (!(*mask & (1U << k)))
+		if (! snd_mask_test(mask, k))
 			continue;
 		bits = snd_pcm_format_physical_width(k);
 		snd_assert(bits > 0, continue);
 		if ((unsigned)bits < i->min || (unsigned)bits > i->max)
-			m &= ~(1U << k);
+			snd_mask_reset(&m, k);
 	}
 	return snd_mask_refine(mask, &m);
 }
@@ -1394,7 +1427,7 @@
 	t.openmax = 0;
 	for (k = 0; k <= SNDRV_PCM_FORMAT_LAST; ++k) {
 		int bits;
-		if (!(*hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT) & (1U << k)))
+		if (! snd_mask_test(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), k))
 			continue;
 		bits = snd_pcm_format_physical_width(k);
 		snd_assert(bits > 0, continue);
@@ -1582,7 +1615,8 @@
 	err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_ACCESS, mask);
 	snd_assert(err >= 0, return -EINVAL);
 
-	err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_FORMAT, hw->formats);
+	err = snd_pcm_hw_constraint_mask64(runtime, SNDRV_PCM_HW_PARAM_FORMAT, hw->formats);
+	//err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_FORMAT, hw->formats);
 	snd_assert(err >= 0, return -EINVAL);
 
 	err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_SUBFORMAT, 1 << SNDRV_PCM_SUBFORMAT_STD);
@@ -1808,12 +1842,7 @@
 	snd_assert(substream != NULL, return -ENXIO);
 	snd_assert(!atomic_read(&substream->runtime->mmap_count), );
 	pcm = substream->pcm;
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		if ((substream->ffile->f_flags & O_NONBLOCK) ||
-		    snd_pcm_playback_drain(substream) == -ERESTARTSYS)
-			snd_pcm_playback_drop(substream);
-	} else
-		snd_pcm_capture_drop(substream);
+	snd_pcm_capture_drop(substream);
 	fasync_helper(-1, file, 0, &substream->runtime->fasync);
 	down(&pcm->open_mutex);
 	snd_pcm_release_file(pcm_file);
@@ -2053,6 +2082,10 @@
 		return snd_pcm_resume(substream);
 	case SNDRV_PCM_IOCTL_XRUN:
 		return snd_pcm_xrun(substream);
+	case SNDRV_PCM_IOCTL_HW_REFINE_OLD:
+		return snd_pcm_hw_refine_old_user(substream, (struct sndrv_pcm_hw_params_old *) arg);
+	case SNDRV_PCM_IOCTL_HW_PARAMS_OLD:
+		return snd_pcm_hw_params_old_user(substream, (struct sndrv_pcm_hw_params_old *) arg);
 	}
 	snd_printd("unknown ioctl = 0x%x\n", cmd);
 	return -ENOTTY;
@@ -2598,6 +2631,7 @@
 	snd_pcm_runtime_t *runtime;
 	unsigned long offset;
 	struct page * page;
+	void *vaddr;
 	size_t dma_bytes;
 	
 	if (substream == NULL)
@@ -2613,7 +2647,13 @@
 	dma_bytes = PAGE_ALIGN(runtime->dma_bytes);
 	if (offset > dma_bytes - PAGE_SIZE)
 		return NOPAGE_SIGBUS;
-	page = virt_to_page(runtime->dma_area + offset);
+	if (substream->ops->page) {
+		vaddr = substream->ops->page(substream, offset);
+		if (! vaddr)
+			return NOPAGE_OOM;
+	} else
+		vaddr = runtime->dma_area + offset;
+	page = virt_to_page(vaddr);
 	get_page(page);
 #ifndef LINUX_2_2
 	return page;
@@ -2723,6 +2763,79 @@
 	if (err < 0)
 		return err;
 	return 0;
+}
+
+/*
+ *  To be removed helpers to keep binary compatibility
+ */
+
+#define __OLD_TO_NEW_MASK(x) ((x&7)|((x&0x07fffff8)<<5))
+#define __NEW_TO_OLD_MASK(x) ((x&7)|((x&0xffffff00)>>5))
+
+static void snd_pcm_hw_convert_from_old_params(snd_pcm_hw_params_t *params, struct sndrv_pcm_hw_params_old *oparams)
+{
+	unsigned int i;
+
+	memset(params, 0, sizeof(*params));
+	params->flags = oparams->flags;
+	for (i = 0; i < sizeof(oparams->masks) / sizeof(unsigned int); i++)
+		params->masks[i].bits[0] = oparams->masks[i];
+	memcpy(params->intervals, oparams->intervals, sizeof(oparams->intervals));
+	params->rmask = __OLD_TO_NEW_MASK(oparams->rmask);
+	params->cmask = __OLD_TO_NEW_MASK(oparams->cmask);
+	params->info = oparams->info;
+	params->msbits = oparams->msbits;
+	params->rate_num = oparams->rate_num;
+	params->rate_den = oparams->rate_den;
+	params->fifo_size = oparams->fifo_size;
+}
+
+static void snd_pcm_hw_convert_to_old_params(struct sndrv_pcm_hw_params_old *oparams, snd_pcm_hw_params_t *params)
+{
+	unsigned int i;
+
+	memset(oparams, 0, sizeof(*oparams));
+	oparams->flags = params->flags;
+	for (i = 0; i < sizeof(oparams->masks) / sizeof(unsigned int); i++)
+		oparams->masks[i] = params->masks[i].bits[0];
+	memcpy(oparams->intervals, params->intervals, sizeof(oparams->intervals));
+	oparams->rmask = __NEW_TO_OLD_MASK(params->rmask);
+	oparams->cmask = __NEW_TO_OLD_MASK(params->cmask);
+	oparams->info = params->info;
+	oparams->msbits = params->msbits;
+	oparams->rate_num = params->rate_num;
+	oparams->rate_den = params->rate_den;
+	oparams->fifo_size = params->fifo_size;
+}
+
+static int snd_pcm_hw_refine_old_user(snd_pcm_substream_t * substream, struct sndrv_pcm_hw_params_old * _oparams)
+{
+	snd_pcm_hw_params_t params;
+	struct sndrv_pcm_hw_params_old oparams;
+	int err;
+	if (copy_from_user(&oparams, _oparams, sizeof(oparams)))
+		return -EFAULT;
+	snd_pcm_hw_convert_from_old_params(&params, &oparams);
+	err = snd_pcm_hw_refine(substream, &params);
+	snd_pcm_hw_convert_to_old_params(&oparams, &params);
+	if (copy_to_user(_oparams, &oparams, sizeof(oparams)))
+		return -EFAULT;
+	return err;
+}
+
+static int snd_pcm_hw_params_old_user(snd_pcm_substream_t * substream, struct sndrv_pcm_hw_params_old * _oparams)
+{
+	snd_pcm_hw_params_t params;
+	struct sndrv_pcm_hw_params_old oparams;
+	int err;
+	if (copy_from_user(&oparams, _oparams, sizeof(oparams)))
+		return -EFAULT;
+	snd_pcm_hw_convert_from_old_params(&params, &oparams);
+	err = snd_pcm_hw_params(substream, &params);
+	snd_pcm_hw_convert_to_old_params(&oparams, &params);
+	if (copy_to_user(_oparams, &oparams, sizeof(oparams)))
+		return -EFAULT;
+	return err;
 }
 
 /*
diff -Nru a/sound/core/pcm_sgbuf.c b/sound/core/pcm_sgbuf.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/core/pcm_sgbuf.c	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,321 @@
+/*
+ * Scatter-Gather PCM access
+ *
+ *  Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   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 __NO_VERSION__
+#include <sound/driver.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_sgbuf.h>
+
+
+/* table entries are align to 32 */
+#define SGBUF_TBL_ALIGN		32
+#define sgbuf_align_table(tbl)	((((tbl) + SGBUF_TBL_ALIGN - 1) / SGBUF_TBL_ALIGN) * SGBUF_TBL_ALIGN)
+
+/*
+ * shrink to the given pages.
+ * free the unused pages
+ */
+static void sgbuf_shrink(struct snd_sg_buf *sgbuf, int pages)
+{
+	snd_assert(sgbuf, return);
+	if (! sgbuf->table)
+		return;
+	while (sgbuf->pages > pages) {
+		sgbuf->pages--;
+		snd_free_pci_pages(sgbuf->pci, PAGE_SIZE,
+				   sgbuf->table[sgbuf->pages].buf,
+				   sgbuf->table[sgbuf->pages].addr);
+	}
+}
+
+/*
+ * initialize the sg buffer
+ * assigned to substream->dma_private.
+ * initialize the table with the given size.
+ */
+int snd_pcm_sgbuf_init(snd_pcm_substream_t *substream, struct pci_dev *pci, int tblsize)
+{
+	struct snd_sg_buf *sgbuf;
+
+	tblsize = sgbuf_align_table(tblsize);
+	sgbuf = snd_magic_kcalloc(snd_pcm_sgbuf_t, 0, GFP_KERNEL);
+	if (! sgbuf)
+		return -ENOMEM;
+	substream->dma_private = sgbuf;
+	sgbuf->pci = pci;
+	sgbuf->pages = 0;
+	sgbuf->tblsize = tblsize;
+	sgbuf->table = kmalloc(sizeof(struct snd_sg_page) * tblsize, GFP_KERNEL);
+	if (! sgbuf->table) {
+		snd_pcm_sgbuf_free(substream);
+		return -ENOMEM;
+	}
+	memset(sgbuf->table, 0, sizeof(struct snd_sg_page) * tblsize);
+	return 0;
+}
+
+/*
+ * release all pages and free the sgbuf instance
+ */
+int snd_pcm_sgbuf_delete(snd_pcm_substream_t *substream)
+{
+	struct snd_sg_buf *sgbuf;
+
+	sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL);
+	sgbuf_shrink(sgbuf, 0);
+	if (sgbuf->table)
+		kfree(sgbuf->table);
+	snd_magic_kfree(sgbuf);
+	substream->dma_private = NULL;
+	return 0;
+}
+
+/*
+ * allocate sg buffer table with the given byte size.
+ * if the buffer table already exists, try to resize it.
+ * call this from hw_params callback.
+ */
+int snd_pcm_sgbuf_alloc(snd_pcm_substream_t *substream, size_t size)
+{
+	struct snd_sg_buf *sgbuf;
+	unsigned int pages;
+	unsigned int tblsize;
+	int changed = 0;
+
+	sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL);
+	pages = snd_pcm_sgbuf_pages(size);
+	tblsize = sgbuf_align_table(pages);
+	if (pages < sgbuf->pages) {
+		/* release unsed pages */
+		sgbuf_shrink(sgbuf, pages);
+		substream->runtime->dma_bytes = size;
+		return 1; /* changed */
+	} else if (pages > sgbuf->tblsize) {
+		/* bigger than existing one.  reallocate the table. */
+		struct snd_sg_page *table;
+		table = kmalloc(sizeof(*table) * tblsize, GFP_KERNEL);
+		if (! table)
+			return -ENOMEM;
+		memcpy(table, sgbuf->table, sizeof(*table) * sgbuf->tblsize);
+		kfree(sgbuf->table);
+		sgbuf->table = table;
+		sgbuf->tblsize = tblsize;
+	}
+	/* allocate each page */
+	while (sgbuf->pages < pages) {
+		void *ptr;
+		dma_addr_t addr;
+		ptr = snd_malloc_pci_pages(sgbuf->pci, PAGE_SIZE, &addr);
+		if (! ptr)
+			return -ENOMEM;
+		sgbuf->table[sgbuf->pages].buf = ptr;
+		sgbuf->table[sgbuf->pages].addr = addr;
+		sgbuf->pages++;
+		changed = 1;
+	}
+	sgbuf->size = size;
+	substream->runtime->dma_bytes = size;
+	return changed;
+}
+
+/*
+ * free the sg buffer
+ * the table is kept.
+ * call this from hw_free callback.
+ */
+int snd_pcm_sgbuf_free(snd_pcm_substream_t *substream)
+{
+	struct snd_sg_buf *sgbuf;
+
+	sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL);
+	sgbuf_shrink(sgbuf, 0);
+	return 0;
+}
+
+/*
+ * get the page pointer on the given offset
+ * used as the page callback of pcm ops
+ */
+void *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset)
+{
+	struct snd_sg_buf *sgbuf;
+	unsigned int idx;
+
+	sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return NULL);
+	idx = offset >> PAGE_SHIFT;
+	if (idx >= sgbuf->pages)
+		return 0;
+	return sgbuf->table[idx].buf;
+}
+
+/*
+ * do copy_from_user to the sg buffer
+ */
+static int copy_from_user_sg_buf(snd_pcm_substream_t *substream,
+				 char *buf, size_t hwoff, ssize_t bytes)
+{
+	int len;
+	char *addr;
+	size_t p = (hwoff >> PAGE_SHIFT) << PAGE_SHIFT;
+	hwoff -= p;
+	len = PAGE_SIZE - hwoff;
+	for (;;) {
+		addr = snd_pcm_sgbuf_ops_page(substream, p);
+		if (! addr)
+			return -EFAULT;
+		if (len > bytes)
+			len = bytes;
+		if (copy_from_user(addr + hwoff, buf, len))
+			return -EFAULT;
+		bytes -= len;
+		if (bytes <= 0)
+			break;
+		buf += len;
+		p += PAGE_SIZE;
+		len = PAGE_SIZE;
+		hwoff = 0;
+	}
+	return 0;
+}
+
+/*
+ * do copy_to_user from the sg buffer
+ */
+static int copy_to_user_sg_buf(snd_pcm_substream_t *substream,
+			       char *buf, size_t hwoff, ssize_t bytes)
+{
+	int len;
+	char *addr;
+	size_t p = (hwoff >> PAGE_SHIFT) << PAGE_SHIFT;
+	hwoff -= p;
+	len = PAGE_SIZE - hwoff;
+	for (;;) {
+		addr = snd_pcm_sgbuf_ops_page(substream, p);
+		if (! addr)
+			return -EFAULT;
+		if (len > bytes)
+			len = bytes;
+		if (copy_to_user(buf, addr + hwoff, len))
+			return -EFAULT;
+		bytes -= len;
+		if (bytes <= 0)
+			break;
+		buf += len;
+		p += PAGE_SIZE;
+		len = PAGE_SIZE;
+		hwoff = 0;
+	}
+	return 0;
+}
+
+/*
+ * set silence on the sg buffer
+ */
+static int set_silence_sg_buf(snd_pcm_substream_t *substream,
+			      size_t hwoff, ssize_t samples)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	int len, page_len;
+	char *addr;
+	size_t p = (hwoff >> PAGE_SHIFT) << PAGE_SHIFT;
+	hwoff -= p;
+	len = bytes_to_samples(substream->runtime, PAGE_SIZE - hwoff);
+	page_len = bytes_to_samples(substream->runtime, PAGE_SIZE);
+	for (;;) {
+		addr = snd_pcm_sgbuf_ops_page(substream, p);
+		if (! addr)
+			return -EFAULT;
+		if (len > samples)
+			len = samples;
+		snd_pcm_format_set_silence(runtime->format, addr + hwoff, len);
+		samples -= len;
+		if (samples <= 0)
+			break;
+		p += PAGE_SIZE;
+		len = page_len;
+		hwoff = 0;
+	}
+	return 0;
+}
+
+/*
+ * copy callback for playback pcm ops
+ */
+int snd_pcm_sgbuf_ops_copy_playback(snd_pcm_substream_t *substream, int channel,
+				    snd_pcm_uframes_t hwoff, void *buf, snd_pcm_uframes_t count)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	if (channel < 0) {
+		return copy_from_user_sg_buf(substream, buf, frames_to_bytes(runtime, hwoff), frames_to_bytes(runtime, count));
+	} else {
+		size_t dma_csize = runtime->dma_bytes / runtime->channels;
+		size_t c_ofs = (channel * dma_csize) + samples_to_bytes(runtime, hwoff);
+		return copy_from_user_sg_buf(substream, buf, c_ofs, samples_to_bytes(runtime, count));
+	}
+}
+
+/*
+ * copy callback for capture pcm ops
+ */
+int snd_pcm_sgbuf_ops_copy_capture(snd_pcm_substream_t *substream, int channel,
+				   snd_pcm_uframes_t hwoff, void *buf, snd_pcm_uframes_t count)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	if (channel < 0) {
+		return copy_to_user_sg_buf(substream, buf, frames_to_bytes(runtime, hwoff), frames_to_bytes(runtime, count));
+	} else {
+		size_t dma_csize = runtime->dma_bytes / runtime->channels;
+		size_t c_ofs = (channel * dma_csize) + samples_to_bytes(runtime, hwoff);
+		return copy_to_user_sg_buf(substream, buf, c_ofs, samples_to_bytes(runtime, count));
+	}
+}
+
+/*
+ * silence callback for pcm ops
+ */
+int snd_pcm_sgbuf_ops_silence(snd_pcm_substream_t *substream, int channel,
+			      snd_pcm_uframes_t hwoff, snd_pcm_uframes_t count)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	if (channel < 0) {
+		return set_silence_sg_buf(substream, frames_to_bytes(runtime, hwoff),
+					  frames_to_bytes(runtime, count));
+	} else {
+		size_t dma_csize = runtime->dma_bytes / runtime->channels;
+		size_t c_ofs = (channel * dma_csize) + samples_to_bytes(runtime, hwoff);
+		return set_silence_sg_buf(substream, c_ofs, samples_to_bytes(runtime, count));
+	}
+}
+
+
+/*
+ *  Exported symbols
+ */
+EXPORT_SYMBOL(snd_pcm_sgbuf_init);
+EXPORT_SYMBOL(snd_pcm_sgbuf_delete);
+EXPORT_SYMBOL(snd_pcm_sgbuf_alloc);
+EXPORT_SYMBOL(snd_pcm_sgbuf_free);
+EXPORT_SYMBOL(snd_pcm_sgbuf_ops_copy_playback);
+EXPORT_SYMBOL(snd_pcm_sgbuf_ops_copy_capture);
+EXPORT_SYMBOL(snd_pcm_sgbuf_ops_silence);
+EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);
diff -Nru a/sound/core/rawmidi.c b/sound/core/rawmidi.c
--- a/sound/core/rawmidi.c	Tue Oct  1 00:08:15 2002
+++ b/sound/core/rawmidi.c	Tue Oct  1 00:08:15 2002
@@ -943,7 +943,7 @@
 		spin_lock_irq(&runtime->lock);
 		while (!snd_rawmidi_ready(substream)) {
 			wait_queue_t wait;
-			if (file->f_flags & O_NONBLOCK) {
+			if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) {
 				spin_unlock_irq(&runtime->lock);
 				return result > 0 ? result : -EAGAIN;
 			}
diff -Nru a/sound/core/rtctimer.c b/sound/core/rtctimer.c
--- a/sound/core/rtctimer.c	Tue Oct  1 00:08:16 2002
+++ b/sound/core/rtctimer.c	Tue Oct  1 00:08:16 2002
@@ -23,6 +23,7 @@
 #include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/time.h>
+#include <linux/threads.h>
 #include <linux/interrupt.h>
 #include <sound/core.h>
 #include <sound/timer.h>
diff -Nru a/sound/core/seq/Makefile b/sound/core/seq/Makefile
--- a/sound/core/seq/Makefile	Tue Oct  1 00:08:19 2002
+++ b/sound/core/seq/Makefile	Tue Oct  1 00:08:19 2002
@@ -35,7 +35,7 @@
 obj-$(CONFIG_SND_MPU401) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
 obj-$(CONFIG_SND_ALS100) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
 obj-$(CONFIG_SND_AZT2320) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
-obj-$(CONFIG_SND_DT0197H) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
+obj-$(CONFIG_SND_DT019X) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
 obj-$(CONFIG_SND_ES18XX) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
 obj-$(CONFIG_SND_OPL3SA2) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
 obj-$(CONFIG_SND_AD1816A) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
diff -Nru a/sound/core/seq/instr/Makefile b/sound/core/seq/instr/Makefile
--- a/sound/core/seq/instr/Makefile	Tue Oct  1 00:08:16 2002
+++ b/sound/core/seq/instr/Makefile	Tue Oct  1 00:08:16 2002
@@ -13,7 +13,7 @@
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_ALS100) += snd-ainstr-fm.o
 obj-$(CONFIG_SND_AZT2320) += snd-ainstr-fm.o
-obj-$(CONFIG_SND_DT0197H) += snd-ainstr-fm.o
+obj-$(CONFIG_SND_DT019X) += snd-ainstr-fm.o
 obj-$(CONFIG_SND_ES18XX) += snd-ainstr-fm.o
 obj-$(CONFIG_SND_OPL3SA2) += snd-ainstr-fm.o
 obj-$(CONFIG_SND_AD1816A) += snd-ainstr-fm.o
diff -Nru a/sound/core/seq/oss/Makefile b/sound/core/seq/oss/Makefile
--- a/sound/core/seq/oss/Makefile	Tue Oct  1 00:08:17 2002
+++ b/sound/core/seq/oss/Makefile	Tue Oct  1 00:08:17 2002
@@ -7,8 +7,8 @@
 		     seq_oss_event.o seq_oss_rw.o seq_oss_synth.o \
 		     seq_oss_midi.o seq_oss_readq.o seq_oss_writeq.o
 
-obj-$(CONFIG_SND_SEQUENCER) += snd-seq-oss.o
-
 ifeq ($(CONFIG_SND_SEQUENCER_OSS),y)
-  include $(TOPDIR)/Rules.make
+  obj-$(CONFIG_SND_SEQUENCER) += snd-seq-oss.o
 endif
+
+include $(TOPDIR)/Rules.make
diff -Nru a/sound/core/seq/seq.c b/sound/core/seq/seq.c
--- a/sound/core/seq/seq.c	Tue Oct  1 00:08:18 2002
+++ b/sound/core/seq/seq.c	Tue Oct  1 00:08:18 2002
@@ -48,7 +48,7 @@
 MODULE_CLASSES("{sound}");
 MODULE_SUPPORTED_DEVICE("sound");
 
-MODULE_PARM(snd_seq_client_load, "i");
+MODULE_PARM(snd_seq_client_load, "1-64i");
 MODULE_PARM_DESC(snd_seq_client_load, "The numbers of global (system) clients to load through kmod.");
 MODULE_PARM(snd_seq_default_timer_class, "i");
 MODULE_PARM_DESC(snd_seq_default_timer_class, "The default timer class.");
diff -Nru a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
--- a/sound/core/seq/seq_clientmgr.c	Tue Oct  1 00:08:15 2002
+++ b/sound/core/seq/seq_clientmgr.c	Tue Oct  1 00:08:15 2002
@@ -37,6 +37,9 @@
 #include "seq_info.h"
 #include "seq_system.h"
 #include <sound/seq_device.h>
+#if defined(CONFIG_SND_BIT32_EMUL) || defined(CONFIG_SND_BIT32_EMUL_MODULE)
+#include "../ioctl32/ioctl32.h"
+#endif
 
 /* Client Manager
 
@@ -1018,6 +1021,13 @@
 			event.data.ext.len = extlen | SNDRV_SEQ_EXT_USRPTR;
 			event.data.ext.ptr = (char*)buf + sizeof(snd_seq_event_t);
 			len += extlen; /* increment data length */
+		} else {
+#if defined(CONFIG_SND_BIT32_EMUL) || defined(CONFIG_SND_BIT32_EMUL_MODULE)
+			if (client->convert32 && snd_seq_ev_is_varusr(&event)) {
+				void *ptr = (void*)A(event.data.raw32.d[1]);
+				event.data.ext.ptr = ptr;
+			}
+#endif
 		}
 
 		/* ok, enqueue it */
@@ -1092,6 +1102,43 @@
 }
 
 
+/* RUNNING_MODE ioctl() */
+static int snd_seq_ioctl_running_mode(client_t *client, unsigned long arg)
+{
+	struct sndrv_seq_running_info info;
+	client_t *cptr;
+	int err = 0;
+
+	if (copy_from_user(&info, (void*)arg, sizeof(info)))
+		return -EFAULT;
+
+	/* requested client number */
+	cptr = snd_seq_client_use_ptr(info.client);
+	if (cptr == NULL)
+		return -ENOENT;		/* don't change !!! */
+
+#ifdef SNDRV_BIG_ENDIAN
+	if (! info.big_endian) {
+		err = -EINVAL;
+		goto __err;
+	}
+#else
+	if (info.big_endian) {
+		err = -EINVAL;
+		goto __err;
+	}
+
+#endif
+	if (info.cpu_mode > sizeof(long)) {
+		err = -EINVAL;
+		goto __err;
+	}
+	cptr->convert32 = (info.cpu_mode < sizeof(long));
+ __err:
+	snd_seq_client_unlock(cptr);
+	return err;
+}
+
 /* CLIENT_INFO ioctl() */
 static void get_client_info(client_t *cptr, snd_seq_client_info_t *info)
 {
@@ -2042,6 +2089,7 @@
 	int (*func)(client_t *client, unsigned long arg);
 } ioctl_tables[] = {
 	{ SNDRV_SEQ_IOCTL_SYSTEM_INFO, snd_seq_ioctl_system_info },
+	{ SNDRV_SEQ_IOCTL_RUNNING_MODE, snd_seq_ioctl_running_mode },
 	{ SNDRV_SEQ_IOCTL_GET_CLIENT_INFO, snd_seq_ioctl_get_client_info },
 	{ SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, snd_seq_ioctl_set_client_info },
 	{ SNDRV_SEQ_IOCTL_CREATE_PORT, snd_seq_ioctl_create_port },
diff -Nru a/sound/core/seq/seq_clientmgr.h b/sound/core/seq/seq_clientmgr.h
--- a/sound/core/seq/seq_clientmgr.h	Tue Oct  1 00:08:19 2002
+++ b/sound/core/seq/seq_clientmgr.h	Tue Oct  1 00:08:19 2002
@@ -61,6 +61,7 @@
 	struct list_head ports_list_head;
 	rwlock_t ports_lock;
 	struct semaphore ports_mutex;
+	int convert32;		/* convert 32->64bit */
 
 	/* output pool */
 	pool_t *pool;		/* memory pool for this client */
diff -Nru a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
--- a/sound/core/seq/seq_memory.c	Tue Oct  1 00:08:15 2002
+++ b/sound/core/seq/seq_memory.c	Tue Oct  1 00:08:15 2002
@@ -128,14 +128,14 @@
  * expand the variable length event to linear buffer space.
  */
 
-static int copy_in_kernel(char **bufptr, const void *src, int size)
+static int seq_copy_in_kernel(char **bufptr, const void *src, int size)
 {
 	memcpy(*bufptr, src, size);
 	*bufptr += size;
 	return 0;
 }
 
-static int copy_in_user(char **bufptr, const void *src, int size)
+static int seq_copy_in_user(char **bufptr, const void *src, int size)
 {
 	if (copy_to_user(*bufptr, src, size))
 		return -EFAULT;
@@ -164,8 +164,8 @@
 		return newlen;
 	}
 	err = snd_seq_dump_var_event(event,
-				     in_kernel ? (snd_seq_dump_func_t)copy_in_kernel :
-				     (snd_seq_dump_func_t)copy_in_user,
+				     in_kernel ? (snd_seq_dump_func_t)seq_copy_in_kernel :
+				     (snd_seq_dump_func_t)seq_copy_in_user,
 				     &buf);
 	return err < 0 ? err : newlen;
 }
diff -Nru a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c
--- a/sound/core/seq/seq_midi.c	Tue Oct  1 00:08:19 2002
+++ b/sound/core/seq/seq_midi.c	Tue Oct  1 00:08:19 2002
@@ -30,6 +30,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
+#include <linux/string.h>
 #include <asm/semaphore.h>
 #include <sound/core.h>
 #include <sound/rawmidi.h>
diff -Nru a/sound/core/seq/seq_midi_emul.c b/sound/core/seq/seq_midi_emul.c
--- a/sound/core/seq/seq_midi_emul.c	Tue Oct  1 00:08:20 2002
+++ b/sound/core/seq/seq_midi_emul.c	Tue Oct  1 00:08:20 2002
@@ -32,6 +32,7 @@
 #include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/string.h>
 #include <sound/core.h>
 #include <sound/seq_kernel.h>
 #include <sound/seq_midi_emul.h>
diff -Nru a/sound/core/seq/seq_midi_event.c b/sound/core/seq/seq_midi_event.c
--- a/sound/core/seq/seq_midi_event.c	Tue Oct  1 00:08:14 2002
+++ b/sound/core/seq/seq_midi_event.c	Tue Oct  1 00:08:14 2002
@@ -22,6 +22,7 @@
 #include <sound/driver.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
+#include <linux/string.h>
 #include <sound/core.h>
 #include <sound/seq_kernel.h>
 #include <sound/seq_midi_event.h>
diff -Nru a/sound/core/seq/seq_prioq.c b/sound/core/seq/seq_prioq.c
--- a/sound/core/seq/seq_prioq.c	Tue Oct  1 00:08:14 2002
+++ b/sound/core/seq/seq_prioq.c	Tue Oct  1 00:08:14 2002
@@ -146,20 +146,15 @@
 }
 
 /* enqueue cell to prioq */
-void snd_seq_prioq_cell_in(prioq_t * f, snd_seq_event_cell_t * cell)
+int snd_seq_prioq_cell_in(prioq_t * f, snd_seq_event_cell_t * cell)
 {
 	snd_seq_event_cell_t *cur, *prev;
 	unsigned long flags;
+	int count;
 	int prior;
 
-	if (f == NULL) {
-		snd_printd("oops: snd_seq_prioq_cell_in() called with NULL prioq\n");
-		return;
-	}
-	if (cell == NULL) {
-		snd_printd("oops: snd_seq_prioq_cell_in() called with NULL cell\n");
-		return;
-	}
+	snd_assert(f, return -EINVAL);
+	snd_assert(cell, return -EINVAL);
 	
 	/* check flags */
 	prior = (cell->event.flags & SNDRV_SEQ_PRIORITY_MASK);
@@ -177,7 +172,7 @@
 			cell->next = NULL;
 			f->cells++;
 			spin_unlock_irqrestore(&f->lock, flags);
-			return;
+			return 0;
 		}
 	}
 	/* traverse list of elements to find the place where the new cell is
@@ -186,6 +181,7 @@
 	prev = NULL;		/* previous cell */
 	cur = f->head;		/* cursor */
 
+	count = 10000; /* FIXME: enough big, isn't it? */
 	while (cur != NULL) {
 		/* compare timestamps */
 		int rel = compare_timestamp_rel(&cell->event, &cur->event);
@@ -199,6 +195,11 @@
 		/* move cursor to next cell */
 		prev = cur;
 		cur = cur->next;
+		if (! --count) {
+			spin_unlock_irqrestore(&f->lock, flags);
+			snd_printk(KERN_ERR "cannot find a pointer.. infinite loop?\n");
+			return -EINVAL;
+		}
 	}
 
 	/* insert it before cursor */
@@ -212,6 +213,7 @@
 		f->tail = cell;
 	f->cells++;
 	spin_unlock_irqrestore(&f->lock, flags);
+	return 0;
 }
 
 /* dequeue cell from prioq */
diff -Nru a/sound/core/seq/seq_prioq.h b/sound/core/seq/seq_prioq.h
--- a/sound/core/seq/seq_prioq.h	Tue Oct  1 00:08:21 2002
+++ b/sound/core/seq/seq_prioq.h	Tue Oct  1 00:08:21 2002
@@ -41,7 +41,7 @@
 extern void snd_seq_prioq_delete(prioq_t **fifo);
 
 /* enqueue cell to prioq */
-extern void snd_seq_prioq_cell_in(prioq_t *f, snd_seq_event_cell_t *cell);
+extern int snd_seq_prioq_cell_in(prioq_t *f, snd_seq_event_cell_t *cell);
 
 /* dequeue cell from prioq */ 
 extern snd_seq_event_cell_t *snd_seq_prioq_cell_out(prioq_t *f);
diff -Nru a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c
--- a/sound/core/seq/seq_queue.c	Tue Oct  1 00:08:19 2002
+++ b/sound/core/seq/seq_queue.c	Tue Oct  1 00:08:19 2002
@@ -149,7 +149,7 @@
 static void queue_delete(queue_t *q)
 {
 	/* stop and release the timer */
-	snd_seq_timer_stop(q->timer);
+	snd_seq_timer_stop(q->timer, 0);
 	snd_seq_timer_close(q);
 	/* wait until access free */
 	snd_use_lock_sync(&q->use_lock);
@@ -348,7 +348,7 @@
 /* enqueue a event to singe queue */
 int snd_seq_enqueue_event(snd_seq_event_cell_t *cell, int atomic, int hop)
 {
-	int dest;
+	int dest, err;
 	queue_t *q;
 
 	snd_assert(cell != NULL, return -EINVAL);
@@ -373,14 +373,20 @@
 	/* enqueue event in the real-time or midi queue */
 	switch (cell->event.flags & SNDRV_SEQ_TIME_STAMP_MASK) {
 	case SNDRV_SEQ_TIME_STAMP_TICK:
-		snd_seq_prioq_cell_in(q->tickq, cell);
+		err = snd_seq_prioq_cell_in(q->tickq, cell);
 		break;
 
 	case SNDRV_SEQ_TIME_STAMP_REAL:
-		snd_seq_prioq_cell_in(q->timeq, cell);
+	default:
+		err = snd_seq_prioq_cell_in(q->timeq, cell);
 		break;
 	}
 
+	if (err < 0) {
+		queuefree(q); /* unlock */
+		return err;
+	}
+
 	/* trigger dispatching */
 	snd_seq_check_queue(q, atomic, hop);
 
@@ -601,7 +607,7 @@
 		spin_unlock_irqrestore(&q->owner_lock, flags);
 		if (q->owner == client) {
 			if (q->timer->running)
-				snd_seq_timer_stop(q->timer);
+				snd_seq_timer_stop(q->timer, 0);
 			snd_seq_timer_reset(q->timer);
 		}
 		queuefree(q);
@@ -711,17 +717,17 @@
 	case SNDRV_SEQ_EVENT_START:
 		snd_seq_prioq_leave(q->tickq, ev->source.client, 1);
 		snd_seq_prioq_leave(q->timeq, ev->source.client, 1);
-		snd_seq_timer_start(q->timer);
-		queue_broadcast_event(q, ev, from_timer_port, atomic, hop);
+		if (! snd_seq_timer_start(q->timer, atomic))
+			queue_broadcast_event(q, ev, from_timer_port, atomic, hop);
 		break;
 
 	case SNDRV_SEQ_EVENT_CONTINUE:
-		snd_seq_timer_continue(q->timer);
-		queue_broadcast_event(q, ev, from_timer_port, atomic, hop);
+		if (! snd_seq_timer_continue(q->timer, atomic))
+			queue_broadcast_event(q, ev, from_timer_port, atomic, hop);
 		break;
 
 	case SNDRV_SEQ_EVENT_STOP:
-		snd_seq_timer_stop(q->timer);
+		snd_seq_timer_stop(q->timer, atomic);
 		queue_broadcast_event(q, ev, from_timer_port, atomic, hop);
 		break;
 
diff -Nru a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c
--- a/sound/core/seq/seq_timer.c	Tue Oct  1 00:08:18 2002
+++ b/sound/core/seq/seq_timer.c	Tue Oct  1 00:08:18 2002
@@ -89,7 +89,7 @@
 	t->running = 0;
 
 	/* reset time */
-	snd_seq_timer_stop(t);
+	snd_seq_timer_stop(t, 0);
 	snd_seq_timer_reset(t);
 
 	kfree(t);
@@ -313,14 +313,18 @@
 	return 0;
 }
 
-void snd_seq_timer_stop(seq_timer_t * tmr)
+int snd_seq_timer_stop(seq_timer_t * tmr, int in_callback)
 {
 	if (! tmr->timeri)
-		return;
+		return -EINVAL;
 	if (!tmr->running)
-		return;
+		return 0;
 	tmr->running = 0;
-	snd_timer_stop(tmr->timeri);
+	if (in_callback)
+		snd_timer_del(tmr->timeri);
+	else
+		snd_timer_stop(tmr->timeri);
+	return 0;
 }
 
 static int initialize_timer(seq_timer_t *tmr)
@@ -345,32 +349,36 @@
 	return 0;
 }
 
-void snd_seq_timer_start(seq_timer_t * tmr)
+int snd_seq_timer_start(seq_timer_t * tmr, int in_callback)
 {
 	if (! tmr->timeri)
-		return;
+		return -EINVAL;
 	if (tmr->running)
-		snd_seq_timer_stop(tmr);
+		snd_seq_timer_stop(tmr, in_callback);
 	snd_seq_timer_reset(tmr);
 	if (initialize_timer(tmr) < 0)
-		return;
+		return -EINVAL;
 	snd_timer_start(tmr->timeri, tmr->ticks);
 	tmr->running = 1;
 	do_gettimeofday(&tmr->last_update);
+	return 0;
 }
 
-void snd_seq_timer_continue(seq_timer_t * tmr)
+int snd_seq_timer_continue(seq_timer_t * tmr, int in_callback)
 {
 	if (! tmr->timeri)
-		return;
+		return -EINVAL;
 	if (tmr->running)
-		return;
-	if (! tmr->initialized)
+		return -EBUSY;
+	if (! tmr->initialized) {
+		snd_seq_timer_reset(tmr);
 		if (initialize_timer(tmr) < 0)
-			return;
+			return -EINVAL;
+	}
 	snd_timer_start(tmr->timeri, tmr->ticks);
 	tmr->running = 1;
 	do_gettimeofday(&tmr->last_update);
+	return 0;
 }
 
 /* return current 'real' time. use timeofday() to get better granularity. */
diff -Nru a/sound/core/seq/seq_timer.h b/sound/core/seq/seq_timer.h
--- a/sound/core/seq/seq_timer.h	Tue Oct  1 00:08:15 2002
+++ b/sound/core/seq/seq_timer.h	Tue Oct  1 00:08:15 2002
@@ -127,9 +127,9 @@
 int snd_seq_timer_midi_close(queue_t *q);
 void snd_seq_timer_defaults(seq_timer_t *tmr);
 void snd_seq_timer_reset(seq_timer_t *tmr);
-void snd_seq_timer_stop(seq_timer_t *tmr);
-void snd_seq_timer_start(seq_timer_t *tmr);
-void snd_seq_timer_continue(seq_timer_t *tmr);
+int snd_seq_timer_stop(seq_timer_t *tmr, int in_callback);
+int snd_seq_timer_start(seq_timer_t *tmr, int in_callback);
+int snd_seq_timer_continue(seq_timer_t *tmr, int in_callback);
 int snd_seq_timer_set_tempo(seq_timer_t *tmr, int tempo);
 int snd_seq_timer_set_ppq(seq_timer_t *tmr, int ppq);
 int snd_seq_timer_set_position_tick(seq_timer_t *tmr, snd_seq_tick_time_t position);
diff -Nru a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c
--- a/sound/core/seq/seq_virmidi.c	Tue Oct  1 00:08:18 2002
+++ b/sound/core/seq/seq_virmidi.c	Tue Oct  1 00:08:18 2002
@@ -89,11 +89,6 @@
 	unsigned char msg[4];
 	int len;
 
-	snd_assert(rdev != NULL, return -EINVAL);
-
-	if (!(rdev->flags & SNDRV_VIRMIDI_USE))
-		return 0; /* ignored */
-
 	read_lock(&rdev->filelist_lock);
 	list_for_each(list, &rdev->filelist) {
 		vmidi = list_entry(list, snd_virmidi_t, list);
@@ -115,14 +110,32 @@
 }
 
 /*
- * event_input callback from sequencer
+ * receive an event from the remote virmidi port
+ *
+ * for rawmidi inputs, you can call this function from the event
+ * handler of a remote port which is attached to the virmidi via
+ * SNDRV_VIRMIDI_SEQ_ATTACH.
+ */
+/* exported */
+int snd_virmidi_receive(snd_rawmidi_t *rmidi, snd_seq_event_t *ev)
+{
+	snd_virmidi_dev_t *rdev;
+
+	rdev = snd_magic_cast(snd_virmidi_dev_t, rmidi->private_data, return -EINVAL);
+	return snd_virmidi_dev_receive_event(rdev, ev);
+}
+
+/*
+ * event handler of virmidi port
  */
-int snd_virmidi_receive(snd_seq_event_t *ev, int direct,
-			void *private_data, int atomic, int hop)
+static int snd_virmidi_event_input(snd_seq_event_t *ev, int direct,
+				   void *private_data, int atomic, int hop)
 {
 	snd_virmidi_dev_t *rdev;
 
 	rdev = snd_magic_cast(snd_virmidi_dev_t, private_data, return -EINVAL);
+	if (!(rdev->flags & SNDRV_VIRMIDI_USE))
+		return 0; /* ignored */
 	return snd_virmidi_dev_receive_event(rdev, ev);
 }
 
@@ -387,7 +400,7 @@
 	pcallbacks.unsubscribe = snd_virmidi_unsubscribe;
 	pcallbacks.use = snd_virmidi_use;
 	pcallbacks.unuse = snd_virmidi_unuse;
-	pcallbacks.event_input = snd_virmidi_receive;
+	pcallbacks.event_input = snd_virmidi_event_input;
 	pinfo.kernel = &pcallbacks;
 	err = snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_CREATE_PORT, &pinfo);
 	if (err < 0) {
@@ -470,7 +483,9 @@
 
 /*
  * create a new device
+ *
  */
+/* exported */
 int snd_virmidi_new(snd_card_t *card, int device, snd_rawmidi_t **rrmidi)
 {
 	snd_rawmidi_t *rmidi;
@@ -525,3 +540,4 @@
 module_exit(alsa_virmidi_exit)
 
 EXPORT_SYMBOL(snd_virmidi_new);
+EXPORT_SYMBOL(snd_virmidi_receive);
diff -Nru a/sound/core/sound.c b/sound/core/sound.c
--- a/sound/core/sound.c	Tue Oct  1 00:08:18 2002
+++ b/sound/core/sound.c	Tue Oct  1 00:08:18 2002
@@ -429,6 +429,11 @@
 EXPORT_SYMBOL(snd_malloc_pci_pages_fallback);
 EXPORT_SYMBOL(snd_free_pci_pages);
 #endif
+#ifdef CONFIG_SBUS
+EXPORT_SYMBOL(snd_malloc_sbus_pages);
+EXPORT_SYMBOL(snd_malloc_sbus_pages_fallback);
+EXPORT_SYMBOL(snd_free_sbus_pages);
+#endif
 EXPORT_SYMBOL(copy_to_user_fromio);
 EXPORT_SYMBOL(copy_from_user_toio);
   /* init.c */
@@ -501,6 +506,8 @@
 #ifdef CONFIG_SND_DEBUG_MEMORY
 EXPORT_SYMBOL(snd_wrapper_kmalloc);
 EXPORT_SYMBOL(snd_wrapper_kfree);
+EXPORT_SYMBOL(snd_wrapper_vmalloc);
+EXPORT_SYMBOL(snd_wrapper_vfree);
 #endif
 #ifdef HACK_PCI_ALLOC_CONSISTENT
 EXPORT_SYMBOL(snd_pci_hack_alloc_consistent);
diff -Nru a/sound/core/timer.c b/sound/core/timer.c
--- a/sound/core/timer.c	Tue Oct  1 00:08:18 2002
+++ b/sound/core/timer.c	Tue Oct  1 00:08:18 2002
@@ -35,13 +35,19 @@
 #include <linux/kerneld.h>
 #endif
 
-int snd_timer_limit = 1;
+#if !defined(CONFIG_SND_RTCTIMER) && !defined(CONFIG_SND_RTCTIMER_MODULE)
+#define DEFAULT_TIMER_LIMIT 1
+#else
+#define DEFAULT_TIMER_LIMIT 2
+#endif
+
+int snd_timer_limit = DEFAULT_TIMER_LIMIT;
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Takashi Iwai <tiwai@suse.de>");
 MODULE_DESCRIPTION("ALSA timer interface");
 MODULE_LICENSE("GPL");
 MODULE_CLASSES("{sound}");
 MODULE_PARM(snd_timer_limit, "i");
-MODULE_PARM_DESC(snd_timer_limit, "Maximum global timers in system. (1 by default)");
+MODULE_PARM_DESC(snd_timer_limit, "Maximum global timers in system.");
 
 typedef struct {
 	snd_timer_instance_t *timeri;
@@ -146,10 +152,14 @@
 	
 	switch (tid->dev_class) {
 	case SNDRV_TIMER_CLASS_GLOBAL:
+		if (tid->device >= snd_timer_limit)
+			return;
 		sprintf(str, "snd-timer-%i", tid->device);
 		break;
 	case SNDRV_TIMER_CLASS_CARD:
 	case SNDRV_TIMER_CLASS_PCM:
+		if (tid->card >= snd_ecards_limit)
+			return;
 		sprintf(str, "snd-card-%i", tid->card);
 		break;
 	default:
@@ -876,7 +886,7 @@
 		}
 		snd_iprintf(buffer, "%s :", timer->name);
 		if (timer->hw.resolution)
-			snd_iprintf(buffer, " %lu.%luus (%lu ticks)", timer->hw.resolution / 1000, timer->hw.resolution % 1000, timer->hw.ticks);
+			snd_iprintf(buffer, " %lu.%03luus (%lu ticks)", timer->hw.resolution / 1000, timer->hw.resolution % 1000, timer->hw.ticks);
 		if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
 			snd_iprintf(buffer, " SLAVE");
 		snd_iprintf(buffer, "\n");
@@ -1260,7 +1270,7 @@
 		while (!tu->qused) {
 			wait_queue_t wait;
 
-			if (file->f_flags & O_NONBLOCK) {
+			if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) {
 				spin_unlock_irq(&tu->qlock);
 				err = -EAGAIN;
 				break;
@@ -1275,6 +1285,7 @@
 			spin_lock_irq(&tu->qlock);
 
 			remove_wait_queue(&tu->qchange_sleep, &wait);
+			set_current_state(TASK_RUNNING);
 
 			if (signal_pending(current)) {
 				err = -ERESTARTSYS;
@@ -1297,7 +1308,7 @@
 		result += sizeof(snd_timer_read_t);
 		buffer += sizeof(snd_timer_read_t);
 	}
-	return err? err: result;
+	return result > 0 ? result : err;
 }
 
 static unsigned int snd_timer_user_poll(struct file *file, poll_table * wait)
diff -Nru a/sound/drivers/mpu401/Makefile b/sound/drivers/mpu401/Makefile
--- a/sound/drivers/mpu401/Makefile	Tue Oct  1 00:08:21 2002
+++ b/sound/drivers/mpu401/Makefile	Tue Oct  1 00:08:21 2002
@@ -12,7 +12,7 @@
 obj-$(CONFIG_SND_MPU401) += snd-mpu401.o snd-mpu401-uart.o
 obj-$(CONFIG_SND_ALS100) += snd-mpu401-uart.o
 obj-$(CONFIG_SND_AZT2320) += snd-mpu401-uart.o
-obj-$(CONFIG_SND_DT0197H) += snd-mpu401-uart.o
+obj-$(CONFIG_SND_DT019X) += snd-mpu401-uart.o
 obj-$(CONFIG_SND_ES18XX) += snd-mpu401-uart.o
 obj-$(CONFIG_SND_OPL3SA2) += snd-mpu401-uart.o
 obj-$(CONFIG_SND_AD1816A) += snd-mpu401-uart.o
diff -Nru a/sound/drivers/opl3/Makefile b/sound/drivers/opl3/Makefile
--- a/sound/drivers/opl3/Makefile	Tue Oct  1 00:08:14 2002
+++ b/sound/drivers/opl3/Makefile	Tue Oct  1 00:08:14 2002
@@ -16,7 +16,7 @@
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_ALS100) += snd-opl3-lib.o
 obj-$(CONFIG_SND_AZT2320) += snd-opl3-lib.o
-obj-$(CONFIG_SND_DT0197H) += snd-opl3-lib.o
+obj-$(CONFIG_SND_DT019X) += snd-opl3-lib.o
 obj-$(CONFIG_SND_ES18XX) += snd-opl3-lib.o
 obj-$(CONFIG_SND_OPL3SA2) += snd-opl3-lib.o
 obj-$(CONFIG_SND_AD1816A) += snd-opl3-lib.o
@@ -41,7 +41,7 @@
 ifeq ($(subst m,y,$(CONFIG_SND_SEQUENCER)),y)
   obj-$(CONFIG_SND_ALS100) += snd-opl3-synth.o
   obj-$(CONFIG_SND_AZT2320) += snd-opl3-synth.o
-  obj-$(CONFIG_SND_DT0197H) += snd-opl3-synth.o
+  obj-$(CONFIG_SND_DT019X) += snd-opl3-synth.o
   obj-$(CONFIG_SND_ES18XX) += snd-opl3-synth.o
   obj-$(CONFIG_SND_OPL3SA2) += snd-opl3-synth.o
   obj-$(CONFIG_SND_AD1816A) += snd-opl3-synth.o
diff -Nru a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c
--- a/sound/drivers/serial-u16550.c	Tue Oct  1 00:08:15 2002
+++ b/sound/drivers/serial-u16550.c	Tue Oct  1 00:08:15 2002
@@ -51,12 +51,14 @@
 #define SNDRV_SERIAL_MS124T 1      /* Midiator MS-124T */
 #define SNDRV_SERIAL_MS124W_SA 2   /* Midiator MS-124W in S/A mode */
 #define SNDRV_SERIAL_MS124W_MB 3   /* Midiator MS-124W in M/B mode */
-#define SNDRV_SERIAL_MAX_ADAPTOR SNDRV_SERIAL_MS124W_MB
+#define SNDRV_SERIAL_GENERIC 4     /* Generic Interface */
+#define SNDRV_SERIAL_MAX_ADAPTOR SNDRV_SERIAL_GENERIC
 static char *adaptor_names[] = {
 	"Soundcanvas",
         "MS-124T",
 	"MS-124W S/A",
-	"MS-124W M/B"
+	"MS-124W M/B",
+	"Generic"
 };
 
 static int snd_index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
@@ -67,6 +69,7 @@
 static int snd_speed[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 38400}; /* 9600,19200,38400,57600,115200 */
 static int snd_base[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 115200}; /* baud base */
 static int snd_outs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};	 /* 1 to 16 */
+static int snd_ins[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};	/* 1 to 16 */
 static int snd_adaptor[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = SNDRV_SERIAL_SOUNDCANVAS};
 
 MODULE_PARM(snd_index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
@@ -92,17 +95,21 @@
 MODULE_PARM_SYNTAX(snd_base, SNDRV_ENABLED ",allows:{57600,115200,230400,460800},dialog:list");
 MODULE_PARM(snd_outs, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
 MODULE_PARM_DESC(snd_outs, "Number of MIDI outputs.");
+MODULE_PARM(snd_ins, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(snd_ins, "Number of MIDI inputs.");
 
 MODULE_PARM_SYNTAX(snd_outs, SNDRV_ENABLED ",allows:{{1,16}},dialog:list");
+MODULE_PARM_SYNTAX(snd_ins, SNDRV_ENABLED ",allows:{{1,16}},dialog:list");
 MODULE_PARM(snd_adaptor, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
 MODULE_PARM_DESC(snd_adaptor, "Type of adaptor.");
-MODULE_PARM_SYNTAX(snd_adaptor, SNDRV_ENABLED ",allows:{{0=Soundcanvas,1=MS-124T,2=MS-124W S/A,3=MS-124W M/B}},dialog:list");
+MODULE_PARM_SYNTAX(snd_adaptor, SNDRV_ENABLED ",allows:{{0=Soundcanvas,1=MS-124T,2=MS-124W S/A,3=MS-124W M/B,4=Generic}},dialog:list");
 
 /*#define SNDRV_SERIAL_MS124W_MB_NOCOMBO 1*/  /* Address outs as 0-3 instead of bitmap */
 
 #define SNDRV_SERIAL_MAX_OUTS	16		/* max 64, min 16 */
+#define SNDRV_SERIAL_MAX_INS	16		/* max 64, min 16 */
 
-#define TX_BUFF_SIZE		(1<<9)		/* Must be 2^n */
+#define TX_BUFF_SIZE		(1<<15)		/* Must be 2^n */
 #define TX_BUFF_MASK		(TX_BUFF_SIZE - 1)
 
 #define SERIAL_MODE_NOT_OPENED 		(0)
@@ -115,7 +122,7 @@
 	snd_card_t *card;
 	snd_rawmidi_t *rmidi;
 	snd_rawmidi_substream_t *midi_output[SNDRV_SERIAL_MAX_OUTS];
-	snd_rawmidi_substream_t *midi_input;
+	snd_rawmidi_substream_t *midi_input[SNDRV_SERIAL_MAX_INS];
 
 	int filemode;		//open status of file
 
@@ -141,6 +148,10 @@
 	// type of adaptor
 	int adaptor;
 
+	// inputs
+	int prev_in;
+	unsigned char rstatus;
+
 	// outputs
 	int prev_out;
 	unsigned char prev_status[SNDRV_SERIAL_MAX_OUTS];
@@ -196,26 +207,52 @@
 static void snd_uart16550_io_loop(snd_uart16550_t * uart)
 {
 	unsigned char c, status;
+	int substream;
+
+	/* recall previous stream */
+	substream = uart->prev_in;
 
 	/* Read Loop */
 	while ((status = inb(uart->base + UART_LSR)) & UART_LSR_DR) {
 		/* while receive data ready */
 		c = inb(uart->base + UART_RX);
-		if (uart->filemode & SERIAL_MODE_INPUT_OPEN) {
-			snd_rawmidi_receive(uart->midi_input, &c, 1);
+
+		/* keep track of last status byte */
+		if (c & 0x80) {
+			uart->rstatus = c;
+		}
+
+		/* handle stream switch */
+		if (uart->adaptor == SNDRV_SERIAL_GENERIC) {
+			if (uart->rstatus == 0xf5) {
+				if (c <= SNDRV_SERIAL_MAX_INS && c > 0)
+					substream = c - 1;
+				if (c != 0xf5)
+					uart->rstatus = 0; /* prevent future bytes from being interpreted as streams */
+			}
+			else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN) && (uart->midi_input[substream] != NULL)) {
+				snd_rawmidi_receive(uart->midi_input[substream], &c, 1);
+		}
+		} else if ((uart->filemode & SERIAL_MODE_INPUT_OPEN) && (uart->midi_input[substream] != NULL)) {
+			snd_rawmidi_receive(uart->midi_input[substream], &c, 1);
 		}
+
 		if (status & UART_LSR_OE)
 			snd_printk("%s: Overrun on device at 0x%lx\n",
 			       uart->rmidi->name, uart->base);
 	}
 
+	/* remember the last stream */
+	uart->prev_in = substream;
+
 	/* no need of check SERIAL_MODE_OUTPUT_OPEN because if not,
 	   buffer is never filled. */
 	/* Check write status */
 	if (status & UART_LSR_THRE) {
 		uart->fifo_count = 0;
 	}
-	if (uart->adaptor == SNDRV_SERIAL_MS124W_SA) {
+	if (uart->adaptor == SNDRV_SERIAL_MS124W_SA
+	   || uart->adaptor == SNDRV_SERIAL_GENERIC) {
 		/* Can't use FIFO, must send only when CTS is true */
 		status = inb(uart->base + UART_MSR);
 		if (uart->fifo_count == 0 && (status & UART_MSR_CTS)
@@ -395,6 +432,11 @@
 		byte = UART_IER_RDI	/* Enable Receiver data interrupt */
 		    | UART_IER_MSI	/* Enable Modem status interrupt */
 		    ;
+	} else if (uart->adaptor == SNDRV_SERIAL_GENERIC) {
+		byte = UART_IER_RDI	/* Enable Receiver data interrupt */
+		    | UART_IER_MSI	/* Enable Modem status interrupt */
+		    | UART_IER_THRI	/* Enable Transmitter holding register empty interupt */
+		    ;
 	} else {
 		byte = UART_IER_RDI	/* Enable Receiver data interupt */
 		    | UART_IER_THRI	/* Enable Transmitter holding register empty interupt */
@@ -467,7 +509,7 @@
 	if (uart->filemode == SERIAL_MODE_NOT_OPENED)
 		snd_uart16550_do_open(uart);
 	uart->filemode |= SERIAL_MODE_INPUT_OPEN;
-	uart->midi_input = substream;
+	uart->midi_input[substream->number] = substream;
 	spin_unlock_irqrestore(&uart->open_lock, flags);
 	return 0;
 }
@@ -479,7 +521,7 @@
 
 	spin_lock_irqsave(&uart->open_lock, flags);
 	uart->filemode &= ~SERIAL_MODE_INPUT_OPEN;
-	uart->midi_input = NULL;
+	uart->midi_input[substream->number] = NULL;
 	if (uart->filemode == SERIAL_MODE_NOT_OPENED)
 		snd_uart16550_do_close(uart);
 	spin_unlock_irqrestore(&uart->open_lock, flags);
@@ -543,7 +585,8 @@
 static void snd_uart16550_output_byte(snd_uart16550_t *uart, snd_rawmidi_substream_t * substream, unsigned char midi_byte)
 {
 	if (uart->buff_in_count == 0                            /* Buffer empty? */
-	    && (uart->adaptor != SNDRV_SERIAL_MS124W_SA ||
+	    && ((uart->adaptor != SNDRV_SERIAL_MS124W_SA &&
+	    uart->adaptor != SNDRV_SERIAL_GENERIC) ||
 		(uart->fifo_count == 0                               /* FIFO empty? */
 		 && (inb(uart->base + UART_MSR) & UART_MSR_CTS)))) { /* CTS? */
 
@@ -577,6 +620,7 @@
 	unsigned char midi_byte, addr_byte;
 	snd_uart16550_t *uart = snd_magic_cast(snd_uart16550_t, substream->rmidi->private_data, return);
 	char first;
+	static unsigned long lasttime=0;
 	
 	/* Interupts are disabled during the updating of the tx_buff,
 	 * since it is 'bad' to have two processes updating the same
@@ -612,13 +656,17 @@
 	} else {
 		first = 0;
 		while (1) {
-			/* buffer full? */
-			if (uart->buff_in_count >= TX_BUFF_SIZE)
-				break;
 			if (snd_rawmidi_transmit(substream, &midi_byte, 1) != 1)
 				break;
-			if (first == 0 && uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS &&
-			    uart->prev_out != substream->number) {
+			/* Also send F5 after 3 seconds with no data to handle device disconnect */
+			if (first == 0 && (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS ||
+				uart->adaptor == SNDRV_SERIAL_GENERIC) &&
+			   (uart->prev_out != substream->number || jiffies-lasttime > 3*HZ)) {
+
+				/* We will need three bytes of data here (worst case). */
+				if (uart->buff_in_count >= TX_BUFF_SIZE - 3)
+					break;
+
 				/* Roland Soundcanvas part selection */
 				/* If this substream of the data is different previous
 				   substream in this uart, send the change part event */
@@ -628,15 +676,21 @@
 				/* data */
 				snd_uart16550_output_byte(uart, substream, uart->prev_out + 1);
 				/* If midi_byte is a data byte, send the previous status byte */
-				if (midi_byte < 0x80)
+				if ((midi_byte < 0x80) && (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS))
 					snd_uart16550_output_byte(uart, substream, uart->prev_status[uart->prev_out]);
 			}
+
+			/* buffer full? */
+			if (uart->buff_in_count >= TX_BUFF_SIZE)
+				break;
+
 			/* send midi byte */
 			snd_uart16550_output_byte(uart, substream, midi_byte);
 			if (midi_byte >= 0x80 && midi_byte < 0xf0)
 				uart->prev_status[uart->prev_out] = midi_byte;
 			first = 1;
 		}
+		lasttime = jiffies;
 	}
 	spin_unlock_irqrestore(&uart->open_lock, flags);
 }
@@ -728,6 +782,8 @@
 	uart->speed = base / (unsigned int)uart->divisor;
 	uart->speed_base = base;
 	uart->prev_out = -1;
+	uart->prev_in = 0;
+	uart->rstatus = 0;
 	memset(uart->prev_status, 0x80, sizeof(unsigned char) * SNDRV_SERIAL_MAX_OUTS);
 	uart->buffer_timer.function = snd_uart16550_buffer_timer;
 	uart->buffer_timer.data = (unsigned long)uart;
@@ -761,12 +817,12 @@
 	return 0;
 }
 
-static int __init snd_uart16550_rmidi(snd_uart16550_t *uart, int device, int outs, snd_rawmidi_t **rmidi)
+static int __init snd_uart16550_rmidi(snd_uart16550_t *uart, int device, int outs, int ins, snd_rawmidi_t **rmidi)
 {
 	snd_rawmidi_t *rrawmidi;
 	int err;
 
-	if ((err = snd_rawmidi_new(uart->card, "UART Serial MIDI", device, outs, 1, &rrawmidi)) < 0)
+	if ((err = snd_rawmidi_new(uart->card, "UART Serial MIDI", device, outs, ins, &rrawmidi)) < 0)
 		return err;
 	snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_uart16550_input);
 	snd_rawmidi_set_ops(rrawmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_uart16550_output);
@@ -791,13 +847,18 @@
 
 	switch (snd_adaptor[dev]) {
 	case SNDRV_SERIAL_SOUNDCANVAS:
+		snd_ins[dev] = 1;
 		break;
 	case SNDRV_SERIAL_MS124T:
 	case SNDRV_SERIAL_MS124W_SA:
 		snd_outs[dev] = 1;
+		snd_ins[dev] = 1;
 		break;
 	case SNDRV_SERIAL_MS124W_MB:
 		snd_outs[dev] = 16;
+		snd_ins[dev] = 1;
+		break;
+	case SNDRV_SERIAL_GENERIC:
 		break;
 	default:
 		snd_printk("Adaptor type is out of range 0-%d (%d)\n",
@@ -811,6 +872,12 @@
 		return -ENODEV;
 	}
 
+	if (snd_ins[dev] < 1 || snd_ins[dev] > SNDRV_SERIAL_MAX_INS) {
+		snd_printk("Count of inputs is out of range 1-%d (%d)\n",
+			   SNDRV_SERIAL_MAX_INS, snd_ins[dev]);
+		return -ENODEV;
+	}
+
 	card  = snd_card_new(snd_index[dev], snd_id[dev], THIS_MODULE, 0);
 	if (card == NULL)
 		return -ENOMEM;
@@ -835,18 +902,19 @@
 		return err;
 	}
 
-	if ((err = snd_uart16550_rmidi(uart, 0, snd_outs[dev], &uart->rmidi)) < 0) {
+	if ((err = snd_uart16550_rmidi(uart, 0, snd_outs[dev], snd_ins[dev], &uart->rmidi)) < 0) {
 		snd_card_free(card);
 		return err;
 	}
 
-	sprintf(card->longname, "%s at 0x%lx, irq %d speed %d div %d outs %d adaptor %s",
+	sprintf(card->longname, "%s at 0x%lx, irq %d speed %d div %d outs %d ins %d adaptor %s",
 		card->shortname,
 		uart->base,
 		uart->irq,
 		uart->speed,
 		(int)uart->divisor,
 		snd_outs[dev],
+		snd_ins[dev],
 		adaptor_names[uart->adaptor]);
 
 	if ((err = snd_card_register(card)) < 0) {
@@ -892,7 +960,8 @@
 #ifndef MODULE
 
 /* format is: snd-serial=snd_enable,snd_index,snd_id,
-			 snd_port,snd_irq,snd_speed,snd_base,snd_outs */
+			 snd_port,snd_irq,snd_speed,snd_base,snd_outs,
+ 			 snd_ins,snd_adaptor */
 
 static int __init alsa_card_serial_setup(char *str)
 {
@@ -908,6 +977,7 @@
 	       get_option(&str,&snd_speed[nr_dev]) == 2 &&
 	       get_option(&str,&snd_base[nr_dev]) == 2 &&
 	       get_option(&str,&snd_outs[nr_dev]) == 2 &&
+	       get_option(&str,&snd_ins[nr_dev]) == 2 &&
 	       get_option(&str,&snd_adaptor[nr_dev]) == 2);
 	nr_dev++;
 	return 1;
diff -Nru a/sound/i2c/i2c.c b/sound/i2c/i2c.c
--- a/sound/i2c/i2c.c	Tue Oct  1 00:08:17 2002
+++ b/sound/i2c/i2c.c	Tue Oct  1 00:08:17 2002
@@ -23,6 +23,8 @@
 #include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
 #include <sound/core.h>
 #include <sound/i2c.h>
 
diff -Nru a/sound/isa/Config.help b/sound/isa/Config.help
--- a/sound/isa/Config.help	Tue Oct  1 00:08:15 2002
+++ b/sound/isa/Config.help	Tue Oct  1 00:08:15 2002
@@ -88,9 +88,9 @@
 CONFIG_SND_CMI8330
   Say 'Y' or 'M' to include support for C-Media CMI8330 based soundcards.
 
-CONFIG_SND_DT0197H
-  Say 'Y' or 'M' to include support for Diamond Technologies DT-0197H
-  soundcards.
+CONFIG_SND_DT019X
+  Say 'Y' or 'M' to include support for Diamond Technologies DT-019X and
+  Avance Logic ALS-007 soundcards.
 
 CONFIG_SND_OPL3SA2
   Say 'Y' or 'M' to include support for Yamaha OPL3SA2 or OPL3SA3 chips.
diff -Nru a/sound/isa/Config.in b/sound/isa/Config.in
--- a/sound/isa/Config.in	Tue Oct  1 00:08:15 2002
+++ b/sound/isa/Config.in	Tue Oct  1 00:08:15 2002
@@ -29,7 +29,7 @@
 dep_tristate 'Avance Logic ALS100/ALS120' CONFIG_SND_ALS100 $CONFIG_SND $CONFIG_ISAPNP
 dep_tristate 'Aztech Systems AZT2320' CONFIG_SND_AZT2320 $CONFIG_SND $CONFIG_ISAPNP
 dep_tristate 'C-Media CMI8330' CONFIG_SND_CMI8330 $CONFIG_SND
-dep_tristate 'Diamond Technologies DT-0197H' CONFIG_SND_DT0197H $CONFIG_SND $CONFIG_ISAPNP
+dep_tristate 'Diamond Technologies DT-019X, Avance Logic ALS-007' CONFIG_SND_DT019X $CONFIG_SND $CONFIG_ISAPNP
 dep_tristate 'Yamaha OPL3-SA2/SA3' CONFIG_SND_OPL3SA2 $CONFIG_SND
 dep_tristate 'Aztech Sound Galaxy' CONFIG_SND_SGALAXY $CONFIG_SND
 
diff -Nru a/sound/isa/Makefile b/sound/isa/Makefile
--- a/sound/isa/Makefile	Tue Oct  1 00:08:16 2002
+++ b/sound/isa/Makefile	Tue Oct  1 00:08:16 2002
@@ -3,12 +3,10 @@
 # Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
 #
 
-mod-subdirs  := ad1816a ad1848 cs423x es1688 gus opti9xx sb wavefront
-
 snd-als100-objs := als100.o
 snd-azt2320-objs := azt2320.o
 snd-cmi8330-objs := cmi8330.o
-snd-dt0197h-objs := dt0197h.o
+snd-dt019x-objs := dt019x.o
 snd-es18xx-objs := es18xx.o
 snd-opl3sa2-objs := opl3sa2.o
 snd-sgalaxy-objs := sgalaxy.o
@@ -17,7 +15,7 @@
 obj-$(CONFIG_SND_ALS100) += snd-als100.o
 obj-$(CONFIG_SND_AZT2320) += snd-azt2320.o
 obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o
-obj-$(CONFIG_SND_DT0197H) += snd-dt0197h.o
+obj-$(CONFIG_SND_DT019X) += snd-dt019x.o
 obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o
 obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o
 obj-$(CONFIG_SND_SGALAXY) += snd-sgalaxy.o
diff -Nru a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c
--- a/sound/isa/ad1816a/ad1816a_lib.c	Tue Oct  1 00:08:15 2002
+++ b/sound/isa/ad1816a/ad1816a_lib.c	Tue Oct  1 00:08:15 2002
@@ -908,7 +908,7 @@
 AD1816A_DOUBLE("FM Playback Switch", AD1816A_FM_ATT, 15, 7, 1, 1),
 AD1816A_DOUBLE("FM Playback Volume", AD1816A_FM_ATT, 8, 0, 63, 1),
 AD1816A_SINGLE("Mic Playback Switch", AD1816A_MIC_GAIN_ATT, 15, 1, 1),
-AD1816A_SINGLE("Mic Playback Volume", AD1816A_MIC_GAIN_ATT, 8, 63, 1),
+AD1816A_SINGLE("Mic Playback Volume", AD1816A_MIC_GAIN_ATT, 8, 31, 1),
 AD1816A_SINGLE("Mic Boost", AD1816A_MIC_GAIN_ATT, 14, 1, 0),
 AD1816A_DOUBLE("Video Playback Switch", AD1816A_VID_GAIN_ATT, 15, 7, 1, 1),
 AD1816A_DOUBLE("Video Playback Volume", AD1816A_VID_GAIN_ATT, 8, 0, 31, 1),
diff -Nru a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c
--- a/sound/isa/ad1848/ad1848_lib.c	Tue Oct  1 00:08:17 2002
+++ b/sound/isa/ad1848/ad1848_lib.c	Tue Oct  1 00:08:17 2002
@@ -24,11 +24,13 @@
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <linux/delay.h>
+#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <sound/core.h>
 #include <sound/ad1848.h>
+#include <sound/pcm_params.h>
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
 MODULE_DESCRIPTION("Routines for control of AD1848/AD1847/CS4248");
diff -Nru a/sound/isa/cs423x/cs4231_lib.c b/sound/isa/cs423x/cs4231_lib.c
--- a/sound/isa/cs423x/cs4231_lib.c	Tue Oct  1 00:08:15 2002
+++ b/sound/isa/cs423x/cs4231_lib.c	Tue Oct  1 00:08:15 2002
@@ -35,6 +35,7 @@
 #include <linux/ioport.h>
 #include <sound/core.h>
 #include <sound/cs4231.h>
+#include <sound/pcm_params.h>
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
 MODULE_DESCRIPTION("Routines for control of CS4231(A)/CS4232/InterWave & compatible chips");
diff -Nru a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c
--- a/sound/isa/cs423x/cs4236.c	Tue Oct  1 00:08:15 2002
+++ b/sound/isa/cs423x/cs4236.c	Tue Oct  1 00:08:15 2002
@@ -227,6 +227,8 @@
 	ISAPNP_CS4232('C','S','C',0x4336,0x0000,0x0010,0x0003),
 	/* Typhoon Soundsystem PnP - CS4236B */
 	ISAPNP_CS4232('C','S','C',0x4536,0x0000,0x0010,0x0003),
+	/* Crystal CX4235-XQ3 EP - CS4235 */
+	ISAPNP_CS4232('C','S','C',0x4625,0x0100,0x0110,0x0103),
 	/* TerraTec AudioSystem EWS64XL - CS4236B */
 	ISAPNP_CS4232('C','S','C',0xa836,0xa800,0xa810,0xa803),
 	/* TerraTec AudioSystem EWS64XL - CS4236B */
diff -Nru a/sound/isa/dt0197h.c b/sound/isa/dt0197h.c
--- a/sound/isa/dt0197h.c	Tue Oct  1 00:08:17 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,391 +0,0 @@
-
-/*
-    card-dt0197h.c - driver for Diamond Technologies DT-0197H based soundcards.
-    Copyright (C) 1999 by Massimo Piccioni <dafastidio@libero.it>
-
-    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 <sound/driver.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#ifndef LINUX_ISAPNP_H
-#include <linux/isapnp.h>
-#define isapnp_card pci_bus
-#define isapnp_dev pci_dev
-#endif
-#include <sound/core.h>
-#define SNDRV_GET_ID
-#include <sound/initval.h>
-#include <sound/mpu401.h>
-#include <sound/opl3.h>
-#include <sound/sb.h>
-
-#define chip_t sb_t
-
-#define PFX "dt0197h: "
-
-MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
-MODULE_DESCRIPTION("Diamond Technologies DT-0197H");
-MODULE_LICENSE("GPL");
-MODULE_CLASSES("{sound}");
-MODULE_DEVICES("{{Diamond Technologies,DT-0197H}}");
-
-static int snd_index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
-static char *snd_id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
-static int snd_enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;	/* Enable this card */
-static long snd_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */
-static long snd_mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */
-static long snd_fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */
-static int snd_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* PnP setup */
-static int snd_mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* PnP setup */
-static int snd_dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* PnP setup */
-
-MODULE_PARM(snd_index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
-MODULE_PARM_DESC(snd_index, "Index value for dt0197h based soundcard.");
-MODULE_PARM_SYNTAX(snd_index, SNDRV_INDEX_DESC);
-MODULE_PARM(snd_id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
-MODULE_PARM_DESC(snd_id, "ID string for dt0197h based soundcard.");
-MODULE_PARM_SYNTAX(snd_id, SNDRV_ID_DESC);
-MODULE_PARM(snd_enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
-MODULE_PARM_DESC(snd_enable, "Enable dt0197h based soundcard.");
-MODULE_PARM_SYNTAX(snd_enable, SNDRV_ENABLE_DESC);
-MODULE_PARM(snd_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
-MODULE_PARM_DESC(snd_port, "Port # for dt0197h driver.");
-MODULE_PARM_SYNTAX(snd_port, SNDRV_PORT12_DESC);
-MODULE_PARM(snd_mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
-MODULE_PARM_DESC(snd_mpu_port, "MPU-401 port # for dt0197h driver.");
-MODULE_PARM_SYNTAX(snd_mpu_port, SNDRV_PORT12_DESC);
-MODULE_PARM(snd_fm_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
-MODULE_PARM_DESC(snd_fm_port, "FM port # for dt0197h driver.");
-MODULE_PARM_SYNTAX(snd_fm_port, SNDRV_PORT12_DESC);
-MODULE_PARM(snd_irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
-MODULE_PARM_DESC(snd_irq, "IRQ # for dt0197h driver.");
-MODULE_PARM_SYNTAX(snd_irq, SNDRV_IRQ_DESC);
-MODULE_PARM(snd_mpu_irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
-MODULE_PARM_DESC(snd_mpu_irq, "MPU-401 IRQ # for dt0197h driver.");
-MODULE_PARM_SYNTAX(snd_mpu_irq, SNDRV_IRQ_DESC);
-MODULE_PARM(snd_dma8, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
-MODULE_PARM_DESC(snd_dma8, "8-bit DMA # for dt0197h driver.");
-MODULE_PARM_SYNTAX(snd_dma8, SNDRV_DMA8_DESC);
-
-struct snd_card_dt0197h {
-#ifdef __ISAPNP__
-	struct isapnp_dev *dev;
-	struct isapnp_dev *devmpu;
-	struct isapnp_dev *devopl;
-#endif	/* __ISAPNP__ */
-};
-
-static snd_card_t *snd_dt0197h_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
-
-#ifdef __ISAPNP__
-static struct isapnp_card *snd_dt0197h_isapnp_cards[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PTR;
-static const struct isapnp_card_id *snd_dt0197h_isapnp_id[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PTR;
-
-static struct isapnp_card_id snd_dt0197h_pnpids[] __devinitdata = {
-	/* DT197A30 */
-	{
-		ISAPNP_CARD_ID('R','W','B',0x1688),
-		devs: { ISAPNP_DEVICE_ID('@','@','@',0x0001),
-			ISAPNP_DEVICE_ID('@','X','@',0x0001),
-			ISAPNP_DEVICE_ID('@','H','@',0x0001) }
-	},
-	{ ISAPNP_CARD_END, }
-};
-
-ISAPNP_CARD_TABLE(snd_dt0197h_pnpids);
-
-#endif	/* __ISAPNP__ */
-
-#define DRIVER_NAME	"snd-card-dt0197h"
-
-
-#ifdef __ISAPNP__
-static int __init snd_card_dt0197h_isapnp(int dev, struct snd_card_dt0197h *acard)
-{
-	const struct isapnp_card_id *id = snd_dt0197h_isapnp_id[dev];
-	struct isapnp_card *card = snd_dt0197h_isapnp_cards[dev];
-	struct isapnp_dev *pdev;
-
-	acard->dev = isapnp_find_dev(card, id->devs[0].vendor, id->devs[0].function, NULL);
-	if (acard->dev->active) {
-		acard->dev = NULL;
-		return -EBUSY;
-	}
-	acard->devmpu = isapnp_find_dev(card, id->devs[1].vendor, id->devs[1].function, NULL);
-	if (acard->devmpu->active) {
-		acard->dev = acard->devmpu = NULL;
-		return -EBUSY;
-	}
-	acard->devopl = isapnp_find_dev(card, id->devs[2].vendor, id->devs[2].function, NULL);
-	if (acard->devopl->active) {
-		acard->dev = acard->devmpu = acard->devopl = NULL;
-		return -EBUSY;
-	}
-
-	pdev = acard->dev;
-	if (pdev->prepare(pdev)<0)
-		return -EAGAIN;
-
-	if (snd_port[dev] != SNDRV_AUTO_PORT)
-		isapnp_resource_change(&pdev->resource[0], snd_port[dev], 16);
-	if (snd_dma8[dev] != SNDRV_AUTO_DMA)
-		isapnp_resource_change(&pdev->dma_resource[0], snd_dma8[dev],
-			1);
-	if (snd_irq[dev] != SNDRV_AUTO_IRQ)
-		isapnp_resource_change(&pdev->irq_resource[0], snd_irq[dev], 1);
-
-	if (pdev->activate(pdev)<0) {
-		printk(KERN_ERR PFX "AUDIO isapnp configure failure\n");
-		return -EBUSY;
-	}
-
-	snd_port[dev] = pdev->resource[0].start;
-	snd_dma8[dev] = pdev->dma_resource[0].start;
-	snd_irq[dev] = pdev->irq_resource[0].start;
-
-	pdev = acard->devmpu;
-	if (pdev || pdev->prepare(pdev)<0)
-		return 0;
-
-	if (snd_mpu_port[dev] != SNDRV_AUTO_PORT)
-		isapnp_resource_change(&pdev->resource[0], snd_mpu_port[dev],
-			2);
-	if (snd_mpu_irq[dev] != SNDRV_AUTO_IRQ)
-		isapnp_resource_change(&pdev->irq_resource[0], snd_mpu_irq[dev],
-			1);
-
-	if (pdev->activate(pdev)<0) {
-		printk(KERN_ERR PFX "MPU-401 isapnp configure failure\n");
-		snd_mpu_port[dev] = -1;
-		acard->devmpu = NULL;
-	} else {
-		snd_mpu_port[dev] = pdev->resource[0].start;
-		snd_mpu_irq[dev] = pdev->irq_resource[0].start;
-	}
-
-	pdev = acard->devopl;
-	if (pdev == NULL || pdev->prepare(pdev)<0)
-		return 0;
-
-	if (snd_fm_port[dev] != SNDRV_AUTO_PORT)
-		isapnp_resource_change(&pdev->resource[0], snd_fm_port[dev], 4);
-
-	if (pdev->activate(pdev)<0) {
-		printk(KERN_ERR PFX "OPL isapnp configure failure\n");
-		snd_fm_port[dev] = -1;
-		acard->devopl = NULL;
-	} else {
-		snd_fm_port[dev] = pdev->resource[0].start;
-	}
-
-	return 0;
-}
-
-static void snd_card_dt0197h_deactivate(struct snd_card_dt0197h *acard)
-{
-	if (acard->dev) {
-		acard->dev->deactivate(acard->dev);
-		acard->dev = NULL;
-	}
-	if (acard->devmpu) {
-		acard->devmpu->deactivate(acard->devmpu);
-		acard->devmpu = NULL;
-	}
-	if (acard->devopl) {
-		acard->devopl->deactivate(acard->devopl);
-		acard->devopl = NULL;
-	}
-}
-#endif	/* __ISAPNP__ */
-
-static void snd_card_dt0197h_free(snd_card_t *card)
-{
-	struct snd_card_dt0197h *acard = (struct snd_card_dt0197h *)card->private_data;
-
-	if (acard != NULL) {
-#ifdef __ISAPNP__
-		snd_card_dt0197h_deactivate(acard);
-#endif	/* __ISAPNP__ */
-	}
-}
-
-static int __init snd_card_dt0197h_probe(int dev)
-{
-	int error;
-	sb_t *chip;
-	snd_card_t *card;
-	struct snd_card_dt0197h *acard;
-	opl3_t *opl3;
-
-	if ((card = snd_card_new(snd_index[dev], snd_id[dev], THIS_MODULE,
-				 sizeof(struct snd_card_dt0197h))) == NULL)
-		return -ENOMEM;
-	acard = (struct snd_card_dt0197h *)card->private_data;
-	card->private_free = snd_card_dt0197h_free;
-
-#ifdef __ISAPNP__
-	if ((error = snd_card_dt0197h_isapnp(dev, acard))) {
-		snd_card_free(card);
-		return error;
-	}
-#else
-	printk(KERN_ERR PFX "you have to enable PnP support ...\n");
-	snd_card_free(card);
-	return -ENOSYS;
-#endif	/* __ISAPNP__ */
-
-	if ((error = snd_sbdsp_create(card, snd_port[dev],
-				      snd_irq[dev],
-				      snd_sb16dsp_interrupt,
-				      snd_dma8[dev],
-				      -1,
-				      SB_HW_AUTO,
-				      &chip)) < 0) {
-		snd_card_free(card);
-		return error;
-	}
-
-	if ((error = snd_sb16dsp_pcm(chip, 0, NULL)) < 0) {
-		snd_card_free(card);
-		return error;
-	}
-	if ((error = snd_sbmixer_new(chip)) < 0) {
-		snd_card_free(card);
-		return error;
-	}
-
-	if (snd_mpu_port[dev] > 0) {
-		if (snd_mpu401_uart_new(card, 0,
-					MPU401_HW_MPU401,
-					snd_mpu_port[dev], 0,
-					snd_mpu_irq[dev],
-					SA_INTERRUPT,
-					NULL) < 0)
-			printk(KERN_ERR PFX "no MPU-401 device at 0x%lx ?\n",
-				snd_mpu_port[dev]);
-	}
-
-	if (snd_fm_port[dev] > 0) {
-		if (snd_opl3_create(card,
-				    snd_fm_port[dev],
-				    snd_fm_port[dev] + 2,
-				    OPL3_HW_AUTO, 0, &opl3) < 0) {
-			printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx ?\n",
-				snd_fm_port[dev], snd_fm_port[dev] + 2);
-		} else {
-			if ((error = snd_opl3_timer_new(opl3, 0, 1)) < 0) {
-				snd_card_free(card);
-				return error;
-			}
-			if ((error = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
-				snd_card_free(card);
-				return error;
-			}
-		}
-	}
-
-	strcpy(card->driver, "DT-0197H");
-	strcpy(card->shortname, "Diamond Tech. DT-0197H");
-	sprintf(card->longname, "%s soundcard, %s at 0x%lx, irq %d, dma %d",
-		card->shortname, chip->name, chip->port,
-		snd_irq[dev], snd_dma8[dev]);
-	if ((error = snd_card_register(card)) < 0) {
-		snd_card_free(card);
-		return error;
-	}
-	snd_dt0197h_cards[dev] = card;
-	return 0;
-}
-
-#ifdef __ISAPNP__
-static int __init snd_dt0197h_isapnp_detect(struct isapnp_card *card,
-					    const struct isapnp_card_id *id)
-{
-	static int dev;
-	int res;
-
-	for ( ; dev < SNDRV_CARDS; dev++) {
-		if (!snd_enable[dev])
-			continue;
-		snd_dt0197h_isapnp_cards[dev] = card;
-		snd_dt0197h_isapnp_id[dev] = id;
-		res = snd_card_dt0197h_probe(dev);
-		if (res < 0)
-			return res;
-		dev++;
-		return 0;
-        }
-        return -ENODEV;
-}
-#endif /* __ISAPNP__ */
-
-static int __init alsa_card_dt0197h_init(void)
-{
-	int cards = 0;
-
-#ifdef __ISAPNP__
-	cards += isapnp_probe_cards(snd_dt0197h_pnpids, snd_dt0197h_isapnp_detect);
-#else
-	printk(KERN_ERR PFX "you have to enable ISA PnP support.\n");
-#endif
-#ifdef MODULE
-	if (!cards)
-		printk(KERN_ERR "no DT-0197H based soundcards found\n");
-#endif
-	return cards ? 0 : -ENODEV;
-}
-
-static void __exit alsa_card_dt0197h_exit(void)
-{
-	int dev;
-
-	for (dev = 0; dev < SNDRV_CARDS; dev++)
-		snd_card_free(snd_dt0197h_cards[dev]);
-}
-
-module_init(alsa_card_dt0197h_init)
-module_exit(alsa_card_dt0197h_exit)
-
-#ifndef MODULE
-
-/* format is: snd-dt0197h=snd_enable,snd_index,snd_id,snd_isapnp,
-			  snd_port,snd_mpu_port,snd_fm_port,
-			  snd_irq,snd_mpu_irq,snd_dma8,snd_dma8_size */
-
-static int __init alsa_card_dt0197h_setup(char *str)
-{
-	static unsigned __initdata nr_dev = 0;
-
-	if (nr_dev >= SNDRV_CARDS)
-		return 0;
-	(void)(get_option(&str,&snd_enable[nr_dev]) == 2 &&
-	       get_option(&str,&snd_index[nr_dev]) == 2 &&
-	       get_id(&str,&snd_id[nr_dev]) == 2 &&
-	       get_option(&str,(int *)&snd_port[nr_dev]) == 2 &&
-	       get_option(&str,(int *)&snd_mpu_port[nr_dev]) == 2 &&
-	       get_option(&str,(int *)&snd_fm_port[nr_dev]) == 2 &&
-	       get_option(&str,&snd_irq[nr_dev]) == 2 &&
-	       get_option(&str,&snd_mpu_irq[nr_dev]) == 2 &&
-	       get_option(&str,&snd_dma8[nr_dev]) == 2);
-	nr_dev++;
-	return 1;
-}
-
-__setup("snd-dt0197h=", alsa_card_dt0197h_setup);
-
-#endif /* ifndef MODULE */
diff -Nru a/sound/isa/dt019x.c b/sound/isa/dt019x.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/isa/dt019x.c	Tue Oct  1 00:08:17 2002
@@ -0,0 +1,407 @@
+
+/*
+    dt019x.c - driver for Diamond Technologies DT-0197H based soundcards.
+    Copyright (C) 1999, 2002 by Massimo Piccioni <dafastidio@libero.it>
+
+    Generalised for soundcards based on DT-0196 and ALS-007 chips 
+    by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>: June 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
+*/
+
+#include <sound/driver.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#ifndef LINUX_ISAPNP_H
+#include <linux/isapnp.h>
+#define isapnp_card pci_bus
+#define isapnp_dev pci_dev
+#endif
+#include <sound/core.h>
+#define SNDRV_GET_ID
+#include <sound/initval.h>
+#include <sound/mpu401.h>
+#include <sound/opl3.h>
+#include <sound/sb.h>
+
+#define chip_t sb_t
+
+#define PFX "dt019x: "
+
+MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
+MODULE_DESCRIPTION("Diamond Technologies DT-019X / Avance Logic ALS-007");
+MODULE_LICENSE("GPL");
+MODULE_CLASSES("{sound}");
+MODULE_DEVICES("{{Diamond Technologies DT-019X},"
+	       "{Avance Logic ALS-007}}");
+
+static int snd_index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
+static char *snd_id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
+static int snd_enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;	/* Enable this card */
+static long snd_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */
+static long snd_mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */
+static long snd_fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */
+static int snd_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* PnP setup */
+static int snd_mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* PnP setup */
+static int snd_dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* PnP setup */
+
+MODULE_PARM(snd_index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(snd_index, "Index value for DT-019X based soundcard.");
+MODULE_PARM_SYNTAX(snd_index, SNDRV_INDEX_DESC);
+MODULE_PARM(snd_id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+MODULE_PARM_DESC(snd_id, "ID string for DT-019X based soundcard.");
+MODULE_PARM_SYNTAX(snd_id, SNDRV_ID_DESC);
+MODULE_PARM(snd_enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(snd_enable, "Enable DT-019X based soundcard.");
+MODULE_PARM_SYNTAX(snd_enable, SNDRV_ENABLE_DESC);
+MODULE_PARM(snd_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+MODULE_PARM_DESC(snd_port, "Port # for dt019x driver.");
+MODULE_PARM_SYNTAX(snd_port, SNDRV_PORT12_DESC);
+MODULE_PARM(snd_mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+MODULE_PARM_DESC(snd_mpu_port, "MPU-401 port # for dt019x driver.");
+MODULE_PARM_SYNTAX(snd_mpu_port, SNDRV_PORT12_DESC);
+MODULE_PARM(snd_fm_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
+MODULE_PARM_DESC(snd_fm_port, "FM port # for dt019x driver.");
+MODULE_PARM_SYNTAX(snd_fm_port, SNDRV_PORT12_DESC);
+MODULE_PARM(snd_irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(snd_irq, "IRQ # for dt019x driver.");
+MODULE_PARM_SYNTAX(snd_irq, SNDRV_IRQ_DESC);
+MODULE_PARM(snd_mpu_irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(snd_mpu_irq, "MPU-401 IRQ # for dt019x driver.");
+MODULE_PARM_SYNTAX(snd_mpu_irq, SNDRV_IRQ_DESC);
+MODULE_PARM(snd_dma8, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(snd_dma8, "8-bit DMA # for dt019x driver.");
+MODULE_PARM_SYNTAX(snd_dma8, SNDRV_DMA8_DESC);
+
+struct snd_card_dt019x {
+#ifdef __ISAPNP__
+	struct isapnp_dev *dev;
+	struct isapnp_dev *devmpu;
+	struct isapnp_dev *devopl;
+#endif	/* __ISAPNP__ */
+};
+
+static snd_card_t *snd_dt019x_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
+
+#ifdef __ISAPNP__
+static struct isapnp_card *snd_dt019x_isapnp_cards[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PTR;
+static const struct isapnp_card_id *snd_dt019x_isapnp_id[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PTR;
+
+static struct isapnp_card_id snd_dt019x_pnpids[] __devinitdata = {
+	/* DT197A30 */
+	{
+		ISAPNP_CARD_ID('R','W','B',0x1688),
+		devs: { ISAPNP_DEVICE_ID('@','@','@',0x0001),
+			ISAPNP_DEVICE_ID('@','X','@',0x0001),
+			ISAPNP_DEVICE_ID('@','H','@',0x0001) }
+	},
+	/* DT0196 / ALS-007 */
+	{
+		ISAPNP_CARD_ID('A','L','S',0x0007),
+		devs: { ISAPNP_DEVICE_ID('@','@','@',0x0001),
+			ISAPNP_DEVICE_ID('@','X','@',0x0001),
+			ISAPNP_DEVICE_ID('@','H','@',0x0001) }
+	},
+	{ ISAPNP_CARD_END, }
+};
+
+ISAPNP_CARD_TABLE(snd_dt019x_pnpids);
+
+#endif	/* __ISAPNP__ */
+
+#define DRIVER_NAME	"snd-card-dt019x"
+
+
+#ifdef __ISAPNP__
+static int __init snd_card_dt019x_isapnp(int dev, struct snd_card_dt019x *acard)
+{
+	const struct isapnp_card_id *id = snd_dt019x_isapnp_id[dev];
+	struct isapnp_card *card = snd_dt019x_isapnp_cards[dev];
+	struct isapnp_dev *pdev;
+
+	acard->dev = isapnp_find_dev(card, id->devs[0].vendor, id->devs[0].function, NULL);
+	if (acard->dev->active) {
+		acard->dev = NULL;
+		return -EBUSY;
+	}
+	acard->devmpu = isapnp_find_dev(card, id->devs[1].vendor, id->devs[1].function, NULL);
+	if (acard->devmpu->active) {
+		acard->dev = acard->devmpu = NULL;
+		return -EBUSY;
+	}
+	acard->devopl = isapnp_find_dev(card, id->devs[2].vendor, id->devs[2].function, NULL);
+	if (acard->devopl->active) {
+		acard->dev = acard->devmpu = acard->devopl = NULL;
+		return -EBUSY;
+	}
+
+	pdev = acard->dev;
+	if (!pdev || pdev->prepare(pdev)<0)
+		return -EAGAIN;
+
+	if (snd_port[dev] != SNDRV_AUTO_PORT)
+		isapnp_resource_change(&pdev->resource[0], snd_port[dev], 16);
+	if (snd_dma8[dev] != SNDRV_AUTO_DMA)
+		isapnp_resource_change(&pdev->dma_resource[0], snd_dma8[dev],
+			1);
+	if (snd_irq[dev] != SNDRV_AUTO_IRQ)
+		isapnp_resource_change(&pdev->irq_resource[0], snd_irq[dev], 1);
+
+	if (pdev->activate(pdev)<0) {
+		printk(KERN_ERR PFX "DT-019X AUDIO isapnp configure failure\n");
+		return -EBUSY;
+	}
+	snd_port[dev] = pdev->resource[0].start;
+	snd_dma8[dev] = pdev->dma_resource[0].start;
+	snd_irq[dev] = pdev->irq_resource[0].start;
+	snd_printdd("dt019x: found audio interface: port=0x%lx, irq=0x%lx, dma=0x%lx\n",
+			snd_port[dev],snd_irq[dev],snd_dma8[dev]);
+
+	pdev = acard->devmpu;
+	if (!pdev || pdev->prepare(pdev)<0) 
+		return 0;
+
+	if (snd_mpu_port[dev] != SNDRV_AUTO_PORT)
+		isapnp_resource_change(&pdev->resource[0], snd_mpu_port[dev],
+			2);
+	if (snd_mpu_irq[dev] != SNDRV_AUTO_IRQ)
+		isapnp_resource_change(&pdev->irq_resource[0], snd_mpu_irq[dev],
+			1);
+
+	if (pdev->activate(pdev)<0) {
+		printk(KERN_ERR PFX "DT-019X MPU-401 isapnp configure failure\n");
+		snd_mpu_port[dev] = -1;
+		acard->devmpu = NULL;
+	} else {
+		snd_mpu_port[dev] = pdev->resource[0].start;
+		snd_mpu_irq[dev] = pdev->irq_resource[0].start;
+		snd_printdd("dt019x: found MPU-401: port=0x%lx, irq=0x%lx\n",
+			 	snd_mpu_port[dev],snd_mpu_irq[dev]);
+	}
+
+	pdev = acard->devopl;
+	if (!pdev || pdev->prepare(pdev)<0)
+		return 0;
+
+	if (snd_fm_port[dev] != SNDRV_AUTO_PORT)
+		isapnp_resource_change(&pdev->resource[0], snd_fm_port[dev], 4);
+
+	if (pdev->activate(pdev)<0) {
+		printk(KERN_ERR PFX "DT-019X OPL3 isapnp configure failure\n");
+		snd_fm_port[dev] = -1;
+		acard->devopl = NULL;
+	} else {
+		snd_fm_port[dev] = pdev->resource[0].start;
+		snd_printdd("dt019x: found OPL3 synth: port=0x%lx\n",snd_fm_port[dev]);
+	}
+
+	return 0;
+}
+
+static void snd_card_dt019x_deactivate(struct snd_card_dt019x *acard)
+{
+	if (acard->dev) {
+		acard->dev->deactivate(acard->dev);
+		acard->dev = NULL;
+	}
+	if (acard->devmpu) {
+		acard->devmpu->deactivate(acard->devmpu);
+		acard->devmpu = NULL;
+	}
+	if (acard->devopl) {
+		acard->devopl->deactivate(acard->devopl);
+		acard->devopl = NULL;
+	}
+}
+#endif	/* __ISAPNP__ */
+
+static void snd_card_dt019x_free(snd_card_t *card)
+{
+	struct snd_card_dt019x *acard = (struct snd_card_dt019x *)card->private_data;
+
+	if (acard != NULL) {
+#ifdef __ISAPNP__
+		snd_card_dt019x_deactivate(acard);
+#endif	/* __ISAPNP__ */
+	}
+}
+
+static int __init snd_card_dt019x_probe(int dev)
+{
+	int error;
+	sb_t *chip;
+	snd_card_t *card;
+	struct snd_card_dt019x *acard;
+	opl3_t *opl3;
+
+	if ((card = snd_card_new(snd_index[dev], snd_id[dev], THIS_MODULE,
+				 sizeof(struct snd_card_dt019x))) == NULL)
+		return -ENOMEM;
+	acard = (struct snd_card_dt019x *)card->private_data;
+	card->private_free = snd_card_dt019x_free;
+
+#ifdef __ISAPNP__
+	if ((error = snd_card_dt019x_isapnp(dev, acard))) {
+		snd_card_free(card);
+		return error;
+	}
+#else
+	printk(KERN_ERR PFX "you have to enable PnP support ...\n");
+	snd_card_free(card);
+	return -ENOSYS;
+#endif	/* __ISAPNP__ */
+
+	if ((error = snd_sbdsp_create(card, snd_port[dev],
+				      snd_irq[dev],
+				      snd_sb16dsp_interrupt,
+				      snd_dma8[dev],
+				      -1,
+				      SB_HW_DT019X,
+				      &chip)) < 0) {
+		snd_card_free(card);
+		return error;
+	}
+
+	if ((error = snd_sb16dsp_pcm(chip, 0, NULL)) < 0) {
+		snd_card_free(card);
+		return error;
+	}
+	if ((error = snd_sbmixer_new(chip)) < 0) {
+		snd_card_free(card);
+		return error;
+	}
+
+	if (snd_mpu_port[dev] > 0) {
+		if (snd_mpu401_uart_new(card, 0,
+/*					MPU401_HW_SB,*/
+					MPU401_HW_MPU401,
+					snd_mpu_port[dev], 0,
+					snd_mpu_irq[dev],
+					SA_INTERRUPT,
+					NULL) < 0)
+			printk(KERN_ERR PFX "no MPU-401 device at 0x%lx ?\n",
+				snd_mpu_port[dev]);
+	}
+
+	if (snd_fm_port[dev] > 0) {
+		if (snd_opl3_create(card,
+				    snd_fm_port[dev],
+				    snd_fm_port[dev] + 2,
+				    OPL3_HW_AUTO, 0, &opl3) < 0) {
+			printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx ?\n",
+				snd_fm_port[dev], snd_fm_port[dev] + 2);
+		} else {
+			if ((error = snd_opl3_timer_new(opl3, 0, 1)) < 0) {
+				snd_card_free(card);
+				return error;
+			}
+			if ((error = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
+				snd_card_free(card);
+				return error;
+			}
+		}
+	}
+
+	strcpy(card->driver, "DT-019X");
+	strcpy(card->shortname, "Diamond Tech. DT-019X");
+	sprintf(card->longname, "%s soundcard, %s at 0x%lx, irq %d, dma %d",
+		card->shortname, chip->name, chip->port,
+		snd_irq[dev], snd_dma8[dev]);
+	if ((error = snd_card_register(card)) < 0) {
+		snd_card_free(card);
+		return error;
+	}
+	snd_dt019x_cards[dev] = card;
+	return 0;
+}
+
+#ifdef __ISAPNP__
+static int __init snd_dt019x_isapnp_detect(struct isapnp_card *card,
+					    const struct isapnp_card_id *id)
+{
+	static int dev;
+	int res;
+
+	for ( ; dev < SNDRV_CARDS; dev++) {
+		if (!snd_enable[dev])
+			continue;
+		snd_dt019x_isapnp_cards[dev] = card;
+		snd_dt019x_isapnp_id[dev] = id;
+		res = snd_card_dt019x_probe(dev);
+		if (res < 0)
+			return res;
+		dev++;
+		return 0;
+        }
+        return -ENODEV;
+}
+#endif /* __ISAPNP__ */
+
+static int __init alsa_card_dt019x_init(void)
+{
+	int cards = 0;
+
+#ifdef __ISAPNP__
+	cards += isapnp_probe_cards(snd_dt019x_pnpids, snd_dt019x_isapnp_detect);
+#else
+	printk(KERN_ERR PFX "you have to enable ISA PnP support.\n");
+#endif
+#ifdef MODULE
+	if (!cards)
+		printk(KERN_ERR "no DT-019X / ALS-007 based soundcards found\n");
+#endif
+	return cards ? 0 : -ENODEV;
+}
+
+static void __exit alsa_card_dt019x_exit(void)
+{
+	int dev;
+
+	for (dev = 0; dev < SNDRV_CARDS; dev++)
+		snd_card_free(snd_dt019x_cards[dev]);
+}
+
+module_init(alsa_card_dt019x_init)
+module_exit(alsa_card_dt019x_exit)
+
+#ifndef MODULE
+
+/* format is: snd-dt019x=snd_enable,snd_index,snd_id,snd_isapnp,
+			  snd_port,snd_mpu_port,snd_fm_port,
+			  snd_irq,snd_mpu_irq,snd_dma8,snd_dma8_size */
+
+static int __init alsa_card_dt019x_setup(char *str)
+{
+	static unsigned __initdata nr_dev = 0;
+
+	if (nr_dev >= SNDRV_CARDS)
+		return 0;
+	(void)(get_option(&str,&snd_enable[nr_dev]) == 2 &&
+	       get_option(&str,&snd_index[nr_dev]) == 2 &&
+	       get_id(&str,&snd_id[nr_dev]) == 2 &&
+	       get_option(&str,(int *)&snd_port[nr_dev]) == 2 &&
+	       get_option(&str,(int *)&snd_mpu_port[nr_dev]) == 2 &&
+	       get_option(&str,(int *)&snd_fm_port[nr_dev]) == 2 &&
+	       get_option(&str,&snd_irq[nr_dev]) == 2 &&
+	       get_option(&str,&snd_mpu_irq[nr_dev]) == 2 &&
+	       get_option(&str,&snd_dma8[nr_dev]) == 2);
+	nr_dev++;
+	return 1;
+}
+
+__setup("snd-dt019x=", alsa_card_dt019x_setup);
+
+#endif /* ifndef MODULE */
diff -Nru a/sound/isa/es18xx.c b/sound/isa/es18xx.c
--- a/sound/isa/es18xx.c	Tue Oct  1 00:08:17 2002
+++ b/sound/isa/es18xx.c	Tue Oct  1 00:08:17 2002
@@ -78,6 +78,7 @@
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
+#include <sound/pcm_params.h>
 #include <sound/mpu401.h>
 #include <sound/opl3.h>
 #define SNDRV_LEGACY_AUTO_PROBE
diff -Nru a/sound/isa/gus/gus_mem_proc.c b/sound/isa/gus/gus_mem_proc.c
--- a/sound/isa/gus/gus_mem_proc.c	Tue Oct  1 00:08:18 2002
+++ b/sound/isa/gus/gus_mem_proc.c	Tue Oct  1 00:08:18 2002
@@ -68,8 +68,8 @@
 	case 1:	/* SEEK_CUR */
 		file->f_pos += offset;
 		break;
-	case 2: /* SEEK_END */
-		file->f_pos = priv->size - offset;
+	case 2: /* SEEK_END, offset is negative */
+		file->f_pos = priv->size + offset;
 		break;
 	default:
 		return -EINVAL;
diff -Nru a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c
--- a/sound/isa/gus/gus_pcm.c	Tue Oct  1 00:08:17 2002
+++ b/sound/isa/gus/gus_pcm.c	Tue Oct  1 00:08:17 2002
@@ -32,6 +32,7 @@
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/gus.h>
+#include <sound/pcm_params.h>
 #include "gus_tables.h"
 
 #define chip_t snd_gus_card_t
diff -Nru a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c
--- a/sound/isa/opl3sa2.c	Tue Oct  1 00:08:21 2002
+++ b/sound/isa/opl3sa2.c	Tue Oct  1 00:08:21 2002
@@ -71,9 +71,11 @@
 MODULE_PARM(snd_enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
 MODULE_PARM_DESC(snd_enable, "Enable OPL3-SA soundcard.");
 MODULE_PARM_SYNTAX(snd_enable, SNDRV_ENABLE_DESC);
+#ifdef __ISAPNP__
 MODULE_PARM(snd_isapnp, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
 MODULE_PARM_DESC(snd_isapnp, "ISA PnP detection for specified soundcard.");
 MODULE_PARM_SYNTAX(snd_isapnp, SNDRV_ISAPNP_DESC);
+#endif
 MODULE_PARM(snd_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
 MODULE_PARM_DESC(snd_port, "Port # for OPL3-SA driver.");
 MODULE_PARM_SYNTAX(snd_port, SNDRV_ENABLED ",allows:{{0xf86},{0x370},{0x100}},dialog:list");
diff -Nru a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c
--- a/sound/isa/opti9xx/opti92x-ad1848.c	Tue Oct  1 00:08:15 2002
+++ b/sound/isa/opti9xx/opti92x-ad1848.c	Tue Oct  1 00:08:15 2002
@@ -326,9 +326,13 @@
 
 static int __init snd_opti9xx_init(opti9xx_t *chip, unsigned short hardware)
 {
+	static int opti9xx_mc_size[] = {7, 7, 10, 10, 2, 2, 2};
+
 	chip->hardware = hardware;
 	strcpy(chip->name, snd_opti9xx_names[hardware]);
 
+	chip->mc_base_size = opti9xx_mc_size[hardware];  
+
 	spin_lock_init(&chip->lock);
 
 	chip->wss_base = -1;
@@ -600,7 +604,7 @@
 #endif	/* CS4231 || OPTi93X */
 
 	spin_lock_irqsave(&chip->lock, flags);
-	outb(irq_bits << 3 | dma_bits, chip->wss_base);
+	snd_opti9xx_write(chip, OPTi9XX_MC_REG(3), (irq_bits << 3 | dma_bits));
 	spin_unlock_irqrestore(&chip->lock, flags);
 
 __skip_resources:
@@ -972,7 +976,7 @@
 			s = s->link_next;
 		} while (s != substream);
 		spin_lock(&chip->lock);
-		if (SNDRV_PCM_TRIGGER_START)
+		if (cmd == SNDRV_PCM_TRIGGER_START)
 			snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, what, what);
 		else
 			snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, what, 0x00);
@@ -1178,7 +1182,6 @@
 	chip->playback_substream = substream;
 	runtime->hw = snd_opti93x_playback;
 	snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.buffer_bytes_max);
-	snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.period_bytes_max);
 	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
 	return error;
 }
@@ -1194,7 +1197,6 @@
 	runtime->hw = snd_opti93x_capture;
 	snd_pcm_set_sync(substream);
 	snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.buffer_bytes_max);
-	snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.period_bytes_max);
 	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
 	return error;
 }
@@ -1259,6 +1261,9 @@
 		disable_dma(chip->dma2);
 		free_dma(chip->dma2);
 	}
+	if (chip->irq >= 0) {
+	  free_irq(chip->irq, chip);
+	}
 	snd_magic_kfree(chip);
 	return 0;
 }
@@ -1312,6 +1317,11 @@
 	}
 	codec->dma2 = chip->dma2;
 
+	if (request_irq(chip->irq, snd_opti93x_interrupt, SA_INTERRUPT, DRIVER_NAME" - WSS", codec)) {
+	  snd_opti93x_free(codec);
+	  return -EBUSY;
+	}
+
 	codec->card = card;
 	codec->port = chip->wss_base + 4;
 	codec->irq = chip->irq;
@@ -1328,7 +1338,7 @@
 	snd_opti93x_init(codec);
 
 	/* Register device */
-	if ((error = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
+	if ((error = snd_device_new(card, SNDRV_DEV_LOWLEVEL, codec, &ops)) < 0) {
 		snd_opti93x_free(codec);
 		return error;
 	}
@@ -1439,8 +1449,8 @@
 	right = (chip->image[OPTi93X_MIXOUT_RIGHT] & ~OPTi93X_MIXOUT_MIXER) | right;
 	change = left != chip->image[OPTi93X_MIXOUT_LEFT] ||
 	         right != chip->image[OPTi93X_MIXOUT_RIGHT];
-	snd_opti93x_out(chip, OPTi93X_MIXOUT_LEFT, left);
-	snd_opti93x_out(chip, OPTi93X_MIXOUT_RIGHT, right);
+	snd_opti93x_out_image(chip, OPTi93X_MIXOUT_LEFT, left);
+	snd_opti93x_out_image(chip, OPTi93X_MIXOUT_RIGHT, right);
 	spin_unlock_irqrestore(&chip->lock, flags);
 	return change;
 }
@@ -1520,7 +1530,7 @@
 
 static int snd_opti93x_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
 {
-	int mask = (kcontrol->private_value >> 16) & 0xff;
+	int mask = (kcontrol->private_value >> 24) & 0xff;
 
 	uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
 	uinfo->count = 2;
@@ -1576,8 +1586,8 @@
 	val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
 	val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2;
 	change = val1 != chip->image[left_reg] || val2 != chip->image[right_reg];
-	snd_opti93x_out(chip, left_reg, val1);
-	snd_opti93x_out(chip, right_reg, val1);
+	snd_opti93x_out_image(chip, left_reg, val1);
+	snd_opti93x_out_image(chip, right_reg, val2);
 	spin_unlock_irqrestore(&chip->lock, flags);
 	return change;
 }
@@ -1586,20 +1596,20 @@
 
 static snd_kcontrol_new_t snd_opti93x_controls[] = {
 OPTi93X_DOUBLE("Master Playback Switch", 0, OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1),
-OPTi93X_DOUBLE("Master Playback Volume", 0, OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 0, 0, 31, 1),
+OPTi93X_DOUBLE("Master Playback Volume", 0, OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1), 
 OPTi93X_DOUBLE("PCM Playback Switch", 0, OPTi93X_DAC_LEFT, OPTi93X_DAC_RIGHT, 7, 7, 1, 1),
-OPTi93X_DOUBLE("PCM Playback Volume", 0, OPTi93X_DAC_LEFT, OPTi93X_DAC_RIGHT, 0, 0, 31, 0),
+OPTi93X_DOUBLE("PCM Playback Volume", 0, OPTi93X_DAC_LEFT, OPTi93X_DAC_RIGHT, 0, 0, 31, 1),
 OPTi93X_DOUBLE("FM Playback Switch", 0, OPTi931_FM_LEFT_INPUT, OPTi931_FM_RIGHT_INPUT, 7, 7, 1, 1),
-OPTi93X_DOUBLE("FM Playback Volume", 0, OPTi931_FM_LEFT_INPUT, OPTi931_FM_RIGHT_INPUT, 0, 0, 15, 1),
+OPTi93X_DOUBLE("FM Playback Volume", 0, OPTi931_FM_LEFT_INPUT, OPTi931_FM_RIGHT_INPUT, 1, 1, 15, 1),
 OPTi93X_DOUBLE("Line Playback Switch", 0, OPTi93X_LINE_LEFT_INPUT, OPTi93X_LINE_RIGHT_INPUT, 7, 7, 1, 1),
-OPTi93X_DOUBLE("Line Playback Volume", 0, OPTi93X_LINE_LEFT_INPUT, OPTi93X_LINE_RIGHT_INPUT, 0, 0, 15, 1),
+OPTi93X_DOUBLE("Line Playback Volume", 0, OPTi93X_LINE_LEFT_INPUT, OPTi93X_LINE_RIGHT_INPUT, 1, 1, 15, 1), 
 OPTi93X_DOUBLE("Mic Playback Switch", 0, OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1),
-OPTi93X_DOUBLE("Mic Playback Volume", 0, OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 0, 0, 15, 1),
+OPTi93X_DOUBLE("Mic Playback Volume", 0, OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1), 
 OPTi93X_DOUBLE("Mic Boost", 0, OPTi93X_MIXOUT_LEFT, OPTi93X_MIXOUT_RIGHT, 5, 5, 1, 1),
 OPTi93X_DOUBLE("CD Playback Switch", 0, OPTi93X_CD_LEFT_INPUT, OPTi93X_CD_RIGHT_INPUT, 7, 7, 1, 1),
-OPTi93X_DOUBLE("CD Playback Volume", 0, OPTi93X_CD_LEFT_INPUT, OPTi93X_CD_RIGHT_INPUT, 0, 0, 15, 1),
+OPTi93X_DOUBLE("CD Playback Volume", 0, OPTi93X_CD_LEFT_INPUT, OPTi93X_CD_RIGHT_INPUT, 1, 1, 15, 1),
 OPTi93X_DOUBLE("Aux Playback Switch", 0, OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1),
-OPTi93X_DOUBLE("Aux Playback Volume", 0, OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 0, 0, 15, 1),
+OPTi93X_DOUBLE("Aux Playback Volume", 0, OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1), 
 OPTi93X_DOUBLE("Capture Volume", 0, OPTi93X_MIXOUT_LEFT, OPTi93X_MIXOUT_RIGHT, 0, 0, 15, 0),
 {
 	iface: SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -1647,7 +1657,6 @@
 static int __init snd_card_opti9xx_detect(snd_card_t *card, opti9xx_t *chip)
 {
 	int i, err;
-	static int opti9xx_mc_size[] = {7, 7, 10, 10, 2, 2, 2};
 
 #ifndef OPTi93X
 	for (i = OPTi9XX_HW_82C928; i < OPTi9XX_HW_82C930; i++) {
@@ -1655,7 +1664,7 @@
 
 		if ((err = snd_opti9xx_init(chip, i)) < 0)
 			return err;
-		chip->mc_base_size = opti9xx_mc_size[i];
+
 		if (check_region(chip->mc_base, chip->mc_base_size))
 			continue;
 
@@ -1671,7 +1680,7 @@
 
 		if ((err = snd_opti9xx_init(chip, i)) < 0)
 			return err;
-		chip->mc_base_size = opti9xx_mc_size[i];
+
 		if (check_region(chip->mc_base, chip->mc_base_size))
 			continue;
 
@@ -1903,7 +1912,7 @@
 static int __init snd_card_opti9xx_probe(void)
 {
 	static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1};
-	static long possible_mpu_ports[] = {0x300, 0x310, 0x320, 0x310, -1};
+	static long possible_mpu_ports[] = {0x300, 0x310, 0x320, 0x330, -1};
 #ifdef OPTi93X
 	static int possible_irqs[] = {5, 9, 10, 11, 7, -1};
 #else
diff -Nru a/sound/isa/sb/Makefile b/sound/isa/sb/Makefile
--- a/sound/isa/sb/Makefile	Tue Oct  1 00:08:17 2002
+++ b/sound/isa/sb/Makefile	Tue Oct  1 00:08:17 2002
@@ -18,7 +18,7 @@
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_ALS100) += snd-sb16-dsp.o snd-sb-common.o
 obj-$(CONFIG_SND_CMI8330) += snd-sb16-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_DT0197H) += snd-sb16-dsp.o snd-sb-common.o
+obj-$(CONFIG_SND_DT019X) += snd-sb16-dsp.o snd-sb-common.o
 obj-$(CONFIG_SND_SB8) += snd-sb8.o snd-sb8-dsp.o snd-sb-common.o
 obj-$(CONFIG_SND_SB16) += snd-sb16.o snd-sb16-dsp.o snd-sb-common.o
 obj-$(CONFIG_SND_SBAWE) += snd-sbawe.o snd-sb16-dsp.o snd-sb-common.o
diff -Nru a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c
--- a/sound/isa/sb/sb16.c	Tue Oct  1 00:08:19 2002
+++ b/sound/isa/sb/sb16.c	Tue Oct  1 00:08:19 2002
@@ -220,6 +220,8 @@
 	/* Note: This card has also a CTL0051:StereoEnhance device!!! */
 	ISAPNP_SBAWE('C','T','L',0x0045,0x0031,0x0021),
 	/* Sound Blaster AWE 32 PnP */
+	ISAPNP_SBAWE('C','T','L',0x0046,0x0031,0x0021),
+	/* Sound Blaster AWE 32 PnP */
 	ISAPNP_SBAWE('C','T','L',0x0047,0x0031,0x0021),
 	/* Sound Blaster AWE 32 PnP */
 	ISAPNP_SBAWE('C','T','L',0x0048,0x0031,0x0021),
diff -Nru a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c
--- a/sound/isa/sb/sb_common.c	Tue Oct  1 00:08:21 2002
+++ b/sound/isa/sb/sb_common.c	Tue Oct  1 00:08:21 2002
@@ -166,6 +166,9 @@
 	case SB_HW_ALS4000:
 		str = "16 (ALS-4000)";
 		break;
+	case SB_HW_DT019X:
+		str = "(DT019X/ALS007)";
+		break;
 	default:
 		return -ENODEV;
 	}
diff -Nru a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c
--- a/sound/isa/sb/sb_mixer.c	Tue Oct  1 00:08:17 2002
+++ b/sound/isa/sb/sb_mixer.c	Tue Oct  1 00:08:17 2002
@@ -195,6 +195,98 @@
 }
 
 /*
+ * DT-019x / ALS-007 capture/input switch
+ */
+
+static int snd_dt019x_input_sw_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	static char *texts[5] = {
+		"CD", "Mic", "Line", "Synth", "Master"
+	};
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 5;
+	if (uinfo->value.enumerated.item > 4)
+		uinfo->value.enumerated.item = 4;
+	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int snd_dt019x_input_sw_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	sb_t *sb = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	unsigned char oval;
+	
+	spin_lock_irqsave(&sb->mixer_lock, flags);
+	oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW);
+	spin_unlock_irqrestore(&sb->mixer_lock, flags);
+	switch (oval & 0x07) {
+	case SB_DT019X_CAP_CD:
+		ucontrol->value.enumerated.item[0] = 0;
+		break;
+	case SB_DT019X_CAP_MIC:
+		ucontrol->value.enumerated.item[0] = 1;
+		break;
+	case SB_DT019X_CAP_LINE:
+		ucontrol->value.enumerated.item[0] = 2;
+		break;
+	case SB_DT019X_CAP_MAIN:
+		ucontrol->value.enumerated.item[0] = 4;
+		break;
+	/* To record the synth on these cards you must record the main.   */
+	/* Thus SB_DT019X_CAP_SYNTH == SB_DT019X_CAP_MAIN and would cause */
+	/* duplicate case labels if left uncommented. */
+	/* case SB_DT019X_CAP_SYNTH:
+	 *	ucontrol->value.enumerated.item[0] = 3;
+	 *	break;
+	 */
+	default:
+		ucontrol->value.enumerated.item[0] = 4;
+		break;
+	}
+	return 0;
+}
+
+static int snd_dt019x_input_sw_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	sb_t *sb = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	int change;
+	unsigned char nval, oval;
+	
+	if (ucontrol->value.enumerated.item[0] > 4)
+		return -EINVAL;
+	switch (ucontrol->value.enumerated.item[0]) {
+	case 0:
+		nval = SB_DT019X_CAP_CD;
+		break;
+	case 1:
+		nval = SB_DT019X_CAP_MIC;
+		break;
+	case 2:
+		nval = SB_DT019X_CAP_LINE;
+		break;
+	case 3:
+		nval = SB_DT019X_CAP_SYNTH;
+		break;
+	case 4:
+		nval = SB_DT019X_CAP_MAIN;
+		break;
+	default:
+		nval = SB_DT019X_CAP_MAIN;
+	}
+	spin_lock_irqsave(&sb->mixer_lock, flags);
+	oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW);
+	change = nval != oval;
+	if (change)
+		snd_sbmixer_write(sb, SB_DT019X_CAPTURE_SW, nval);
+	spin_unlock_irqrestore(&sb->mixer_lock, flags);
+	return change;
+}
+
+/*
  * SBPRO input multiplexer
  */
 
@@ -422,6 +514,44 @@
 	{ SB_DSP4_SPEAKER_DEV, 0 },
 };
 
+#define DT019X_CONTROLS (sizeof(snd_dt019x_controls)/sizeof(snd_kcontrol_new_t))
+
+static snd_kcontrol_new_t snd_dt019x_controls[] = {
+SB_DOUBLE("Master Playback Volume", SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4,0, 15),
+SB_DOUBLE("PCM Playback Volume", SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4,0, 15),
+SB_DOUBLE("Synth Playback Volume", SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4,0, 15),
+SB_DOUBLE("CD Playback Volume", SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4,0, 15),
+SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7),
+SB_SINGLE("PC Speaker Volume", SB_DT019X_SPKR_DEV, 0,  7),
+SB_DOUBLE("Line Playback Volume", SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4,0, 15),
+SB_SINGLE("Mic Playback Switch", SB_DT019X_OUTPUT_SW1, 0, 1),
+SB_DOUBLE("CD Playback Switch", SB_DT019X_OUTPUT_SW1, SB_DT019X_OUTPUT_SW1, 2,1, 1),
+SB_DOUBLE("Line Playback Switch", SB_DT019X_OUTPUT_SW1, SB_DT019X_OUTPUT_SW1, 4,3, 1),
+SB_DOUBLE("PCM Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2,1, 1),
+SB_DOUBLE("Synth Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4,3, 1),
+{
+	iface: SNDRV_CTL_ELEM_IFACE_MIXER,
+	name: "Capture Source",
+	info: snd_dt019x_input_sw_info,
+	get: snd_dt019x_input_sw_get,
+	put: snd_dt019x_input_sw_put,
+},
+};
+
+#define DT019X_INIT_VALUES (sizeof(snd_dt019x_init_values)/sizeof(unsigned char)/2)
+
+static unsigned char snd_dt019x_init_values[][2] = {
+        { SB_DT019X_MASTER_DEV, 0 },
+        { SB_DT019X_PCM_DEV, 0 },
+        { SB_DT019X_SYNTH_DEV, 0 },
+        { SB_DT019X_CD_DEV, 0 },
+        { SB_DT019X_MIC_DEV, 0 },	/* Includes PC-speaker in high nibble */
+        { SB_DT019X_LINE_DEV, 0 },
+        { SB_DT019X_OUTPUT_SW1, 0 },
+        { SB_DT019X_OUTPUT_SW2, 0 },
+        { SB_DT019X_CAPTURE_SW, 0x06 },
+};
+
 static int snd_sbmixer_init(sb_t *chip,
 			    snd_kcontrol_new_t *controls,
 			    int controls_count,
@@ -489,6 +619,12 @@
 					    snd_sb16_init_values, SB16_INIT_VALUES,
 					    "CTL1745")) < 0)
 			return err;
+		break;
+	case SB_HW_DT019X:
+		if ((err = snd_sbmixer_init(chip,
+					    snd_dt019x_controls, DT019X_CONTROLS,
+					    snd_dt019x_init_values, DT019X_INIT_VALUES,
+					    "DT019X")) < 0)
 		break;
 	default:
 		strcpy(card->mixername, "???");
diff -Nru a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c
--- a/sound/isa/wavefront/wavefront.c	Tue Oct  1 00:08:15 2002
+++ b/sound/isa/wavefront/wavefront.c	Tue Oct  1 00:08:15 2002
@@ -71,8 +71,8 @@
 MODULE_PARM_SYNTAX(snd_isapnp, SNDRV_ISAPNP_DESC);
 #endif
 MODULE_PARM(snd_cs4232_pcm_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
-MODULE_PARM_DESC(snd_4232_port, "Port # for CS4232 PCM interface.");
-MODULE_PARM_SYNTAX(snd_cs4232_port, SNDRV_PORT12_DESC);
+MODULE_PARM_DESC(snd_cs4232_pcm_port, "Port # for CS4232 PCM interface.");
+MODULE_PARM_SYNTAX(snd_cs4232_pcm_port, SNDRV_PORT12_DESC);
 MODULE_PARM(snd_cs4232_pcm_irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
 MODULE_PARM_DESC(snd_cs4232_pcm_irq, "IRQ # for CS4232 PCM interface.");
 MODULE_PARM_SYNTAX(snd_cs4232_pcm_irq, SNDRV_ENABLED ",allows:{{5},{7},{9},{11},{12},{15}},dialog:list");
diff -Nru a/sound/oss/audio.c b/sound/oss/audio.c
--- a/sound/oss/audio.c	Tue Oct  1 00:08:17 2002
+++ b/sound/oss/audio.c	Tue Oct  1 00:08:17 2002
@@ -826,37 +826,48 @@
 			if (!(audio_devs[dev]->flags & DMA_DUPLEX) && (bits & PCM_ENABLE_INPUT) &&
 				(bits & PCM_ENABLE_OUTPUT))
 				return -EINVAL;
-			spin_lock_irqsave(&dmap->lock,flags);
-			changed = audio_devs[dev]->enable_bits ^ bits;
-			if ((changed & bits) & PCM_ENABLE_INPUT && audio_devs[dev]->go) 
+
+			if (bits & PCM_ENABLE_INPUT)
 			{
-				reorganize_buffers(dev, dmap_in, 1);
-				if ((err = audio_devs[dev]->d->prepare_for_input(dev,
-					     dmap_in->fragment_size, dmap_in->nbufs)) < 0) {
-					spin_unlock_irqrestore(&dmap->lock,flags);
-					return -err;
-				}
-				dmap_in->dma_mode = DMODE_INPUT;
-				audio_devs[dev]->enable_bits = bits;
-				DMAbuf_activate_recording(dev, dmap_in);
+				spin_lock_irqsave(&dmap_in->lock,flags);
+				changed = (audio_devs[dev]->enable_bits ^ bits) & PCM_ENABLE_INPUT;
+				if (changed && audio_devs[dev]->go) 
+				{
+					reorganize_buffers(dev, dmap_in, 1);
+					if ((err = audio_devs[dev]->d->prepare_for_input(dev,
+						     dmap_in->fragment_size, dmap_in->nbufs)) < 0) {
+						spin_unlock_irqrestore(&dmap_in->lock,flags);
+						return -err;
+					}
+					dmap_in->dma_mode = DMODE_INPUT;
+					audio_devs[dev]->enable_bits |= PCM_ENABLE_INPUT;
+					DMAbuf_activate_recording(dev, dmap_in);
+				} else
+					audio_devs[dev]->enable_bits &= ~PCM_ENABLE_INPUT;
+				spin_unlock_irqrestore(&dmap_in->lock,flags);
 			}
-			if ((changed & bits) & PCM_ENABLE_OUTPUT &&
-			    (dmap_out->mapping_flags & DMA_MAP_MAPPED || dmap_out->qlen > 0) &&
-			    audio_devs[dev]->go) 
+			if (bits & PCM_ENABLE_OUTPUT)
 			{
-				if (!(dmap_out->flags & DMA_ALLOC_DONE))
-					reorganize_buffers(dev, dmap_out, 0);
-				dmap_out->dma_mode = DMODE_OUTPUT;
-				audio_devs[dev]->enable_bits = bits;
-				dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size;
-				DMAbuf_launch_output(dev, dmap_out);
+				spin_lock_irqsave(&dmap_out->lock,flags);
+				changed = (audio_devs[dev]->enable_bits ^ bits) & PCM_ENABLE_OUTPUT;
+				if (changed &&
+				    (dmap_out->mapping_flags & DMA_MAP_MAPPED || dmap_out->qlen > 0) &&
+				    audio_devs[dev]->go) 
+				{
+					if (!(dmap_out->flags & DMA_ALLOC_DONE))
+						reorganize_buffers(dev, dmap_out, 0);
+					dmap_out->dma_mode = DMODE_OUTPUT;
+					audio_devs[dev]->enable_bits |= PCM_ENABLE_OUTPUT;
+					dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size;
+					DMAbuf_launch_output(dev, dmap_out);
+				} else
+					audio_devs[dev]->enable_bits &= ~PCM_ENABLE_OUTPUT;
+				spin_unlock_irqrestore(&dmap_out->lock,flags);
 			}
-			audio_devs[dev]->enable_bits = bits;
 #if 0
 			if (changed && audio_devs[dev]->d->trigger)
 				audio_devs[dev]->d->trigger(dev, bits * audio_devs[dev]->go);
 #endif				
-			spin_unlock_irqrestore(&dmap->lock,flags);
 			/* Falls through... */
 
 		case SNDCTL_DSP_GETTRIGGER:
@@ -873,7 +884,7 @@
 		case SNDCTL_DSP_GETIPTR:
 			if (!(audio_devs[dev]->open_mode & OPEN_READ))
 				return -EINVAL;
-			spin_lock_irqsave(&dmap->lock,flags);
+			spin_lock_irqsave(&dmap_in->lock,flags);
 			cinfo.bytes = dmap_in->byte_counter;
 			cinfo.ptr = DMAbuf_get_buffer_pointer(dev, dmap_in, DMODE_INPUT) & ~3;
 			if (cinfo.ptr < dmap_in->fragment_size && dmap_in->qtail != 0)
@@ -882,7 +893,7 @@
 			cinfo.bytes += cinfo.ptr;
 			if (dmap_in->mapping_flags & DMA_MAP_MAPPED)
 				dmap_in->qlen = 0;	/* Reset interrupt counter */
-			spin_unlock_irqrestore(&dmap->lock,flags);
+			spin_unlock_irqrestore(&dmap_in->lock,flags);
 			if (copy_to_user(arg, &cinfo, sizeof(cinfo)))
 				return -EFAULT;
 			return 0;
@@ -891,7 +902,7 @@
 			if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
 				return -EINVAL;
 
-			spin_lock_irqsave(&dmap->lock,flags);
+			spin_lock_irqsave(&dmap_out->lock,flags);
 			cinfo.bytes = dmap_out->byte_counter;
 			cinfo.ptr = DMAbuf_get_buffer_pointer(dev, dmap_out, DMODE_OUTPUT) & ~3;
 			if (cinfo.ptr < dmap_out->fragment_size && dmap_out->qhead != 0)
@@ -900,7 +911,7 @@
 			cinfo.bytes += cinfo.ptr;
 			if (dmap_out->mapping_flags & DMA_MAP_MAPPED)
 				dmap_out->qlen = 0;	/* Reset interrupt counter */
-			spin_unlock_irqrestore(&dmap->lock,flags);
+			spin_unlock_irqrestore(&dmap_out->lock,flags);
 			if (copy_to_user(arg, &cinfo, sizeof(cinfo)))
 				return -EFAULT;
 			return 0;
@@ -913,7 +924,7 @@
 				ret=0;
 				break;
 			}
-			spin_lock_irqsave(&dmap->lock,flags);
+			spin_lock_irqsave(&dmap_out->lock,flags);
 			/* Compute number of bytes that have been played */
 			count = DMAbuf_get_buffer_pointer (dev, dmap_out, DMODE_OUTPUT);
 			if (count < dmap_out->fragment_size && dmap_out->qhead != 0)
@@ -923,7 +934,7 @@
 			count = dmap_out->user_counter - count;
 			if (count < 0)
 				count = 0;
-			spin_unlock_irqrestore(&dmap->lock,flags);
+			spin_unlock_irqrestore(&dmap_out->lock,flags);
 			ret = count;
 			break;
 
diff -Nru a/sound/oss/dmasound/dmasound.h b/sound/oss/dmasound/dmasound.h
--- a/sound/oss/dmasound/dmasound.h	Tue Oct  1 00:08:22 2002
+++ b/sound/oss/dmasound/dmasound.h	Tue Oct  1 00:08:22 2002
@@ -166,6 +166,7 @@
     int treble;
     int gain;
     int minDev;		/* minor device number currently open */
+    spinlock_t lock;
 };
 
 extern struct sound_settings dmasound;
diff -Nru a/sound/oss/dmasound/dmasound_atari.c b/sound/oss/dmasound/dmasound_atari.c
--- a/sound/oss/dmasound/dmasound_atari.c	Tue Oct  1 00:08:16 2002
+++ b/sound/oss/dmasound/dmasound_atari.c	Tue Oct  1 00:08:16 2002
@@ -19,7 +19,7 @@
 #include <linux/init.h>
 #include <linux/soundcard.h>
 #include <linux/mm.h>
-
+#include <linux/spinlock.h>
 #include <asm/pgalloc.h>
 #include <asm/uaccess.h>
 #include <asm/atariints.h>
@@ -1262,7 +1262,7 @@
 			return;
 		}
 #endif
-
+	spin_lock(&dmasound.lock);
 	if (write_sq_ignore_int && is_falcon) {
 		/* ++TeSche: Falcon only: ignore first irq because it comes
 		 * immediately after starting a frame. after that, irqs come
@@ -1314,6 +1314,7 @@
 	/* We are not playing after AtaPlay(), so there
 	   is nothing to play any more. Wake up a process
 	   waiting for audio output to drain. */
+	spin_unlock(&dmasound.lock);
 }
 
 
@@ -1349,14 +1350,15 @@
 static int AtaMixerIoctl(u_int cmd, u_long arg)
 {
 	int data;
+	unsigned long flags;
 	switch (cmd) {
 	    case SOUND_MIXER_READ_SPEAKER:
 		    if (is_falcon || MACH_IS_TT) {
 			    int porta;
-			    cli();
+			    spin_lock_irqsave(&dmasound.lock, flags);
 			    sound_ym.rd_data_reg_sel = 14;
 			    porta = sound_ym.rd_data_reg_sel;
-			    sti();
+			    spin_unlock_irqrestore(&dmasound.lock, flags);
 			    return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100);
 		    }
 		    break;
@@ -1367,12 +1369,12 @@
 		    if (is_falcon || MACH_IS_TT) {
 			    int porta;
 			    IOCTL_IN(arg, data);
-			    cli();
+			    spin_lock_irqsave(&dmasound.lock, flags);
 			    sound_ym.rd_data_reg_sel = 14;
 			    porta = (sound_ym.rd_data_reg_sel & ~0x40) |
 				    (data < 50 ? 0x40 : 0);
 			    sound_ym.wd_data = porta;
-			    sti();
+			    spin_unlock_irqrestore(&dmasound.lock, flags);
 			    return IOCTL_OUT(arg, porta & 0x40 ? 0 : 100);
 		    }
 	}
diff -Nru a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c
--- a/sound/oss/dmasound/dmasound_awacs.c	Tue Oct  1 00:08:16 2002
+++ b/sound/oss/dmasound/dmasound_awacs.c	Tue Oct  1 00:08:16 2002
@@ -66,6 +66,7 @@
 #include <linux/tty.h>
 #include <linux/vt_kern.h>
 #include <linux/irq.h>
+#include <linux/spinlock.h>
 #include <linux/kmod.h>
 #include <asm/semaphore.h>
 #ifdef CONFIG_ADB_CUDA
@@ -397,6 +398,7 @@
 static void
 headphone_intr(int irq, void *devid, struct pt_regs *regs)
 {
+	spin_lock(&dmasound.lock);
 	if (read_audio_gpio(gpio_headphone_detect) == gpio_headphone_detect_pol) {
 		printk(KERN_INFO "Audio jack plugged, muting speakers.\n");
 		write_audio_gpio(gpio_amp_mute, gpio_amp_mute_pol);
@@ -406,6 +408,7 @@
 		write_audio_gpio(gpio_amp_mute, !gpio_amp_mute_pol);
 		write_audio_gpio(gpio_headphone_mute, gpio_headphone_mute_pol);
 	}
+	spin_unlock(&dmasound.lock);
 }
 
 
@@ -804,7 +807,7 @@
 
 	/* CHECK: how much of this *really* needs IRQs masked? */
 
-	save_flags(flags); cli();
+	spin_lock_irqsave(&dmasound.lock, flags);
 	count = 300 ; /* > two cycles at the lowest sample rate */
 
 	/* what we want to send next */
@@ -871,7 +874,7 @@
 		out_le32(&awacs_txdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
 		++write_sq.active;
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&dmasound.lock, flags);
 }
 
 static void PMacPlay(void)
@@ -889,14 +892,14 @@
 	if (read_sq.active)
 		return;
 
-	save_flags(flags); cli();
+	spin_lock_irqsave(&dmasound.lock, flags);
 
 	/* This is all we have to do......Just start it up.
 	*/
 	out_le32(&awacs_rxdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
 	read_sq.active = 1;
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&dmasound.lock, flags);
 }
 
 /* if the TX status comes up "DEAD" - reported on some Power Computing machines
@@ -929,6 +932,7 @@
 	/* != 0 when we are dealing with a DEAD xfer */
 	static int emergency_in_use = 0 ;
 
+	spin_lock(&dmasound.lock);
 	while (write_sq.active > 0) { /* we expect to have done something*/
 		if (emergency_in_use) /* we are dealing with DEAD xfer */
 			cp = emergency_dbdma_cmd ;
@@ -1004,6 +1008,7 @@
 	/* make the wake-on-empty conditional on syncing */
 	if (!write_sq.active && (write_sq.syncing & 1))
 		WAKE_UP(write_sq.sync_queue); /* any time we're empty */
+	spin_unlock(&dmasound.lock);
 }
 
 
@@ -1025,6 +1030,7 @@
 	if (read_sq.active == 0)
 		return;
 
+	spin_lock(&dmasound.lock);
 	/* Check multiple buffers in case we were held off from
 	 * interrupt processing for a long time.  Geeze, I really hope
 	 * this doesn't happen.
@@ -1056,6 +1062,7 @@
 			/* should complete clearing the DEAD status */
 			out_le32(&awacs_rxdma->control,
 				((RUN|WAKE) << 16) + (RUN|WAKE));
+			spin_unlock(&dmasound.lock);
 			return; /* try this block again */
 		}
 		/* Clear status and move on to next buffer.
@@ -1083,13 +1090,16 @@
 	}
 
 	WAKE_UP(read_sq.action_queue);
+	spin_unlock(&dmasound.lock);
 }
 
 
 static void
 pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs)
 {
-	int ctrl = in_le32(&awacs->control);
+	int ctrl;
+	spin_lock(&dmasound.lock);
+	ctrl = in_le32(&awacs->control);
 
 	if (ctrl & MASK_PORTCHG) {
 		/* do something when headphone is plugged/unplugged? */
@@ -1102,6 +1112,7 @@
 	}
 	/* Writing 1s to the CNTLERR and PORTCHG bits clears them... */
 	out_le32(&awacs->control, ctrl);
+	spin_unlock(&dmasound.lock);
 }
 
 static void
@@ -1125,7 +1136,7 @@
 	unsigned long flags;
 	int count = 600 ; /* > four samples at lowest rate */
 
-	save_flags(flags); cli();
+	spin_lock_irqsave(&dmasound.lock, flags);
 	if (beep_playing) {
 		st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);
 		out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
@@ -1141,7 +1152,7 @@
 			out_le32(&awacs->byteswap, 0);
 		beep_playing = 0;
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&dmasound.lock, flags);
 }
 
 static struct timer_list beep_timer = {
@@ -1189,19 +1200,19 @@
 		return;
 #endif
 	}
-	save_flags(flags); cli();
+	spin_lock_irqsave(&dmasound.lock, flags);
 	del_timer(&beep_timer);
 	if (ticks) {
 		beep_timer.expires = jiffies + ticks;
 		add_timer(&beep_timer);
 	}
 	if (beep_playing || write_sq.active || beep_buf == NULL) {
-		restore_flags(flags);
+		spin_unlock_irqrestore(&dmasound.lock, flags);
 		return;		/* too hard, sorry :-( */
 	}
 	beep_playing = 1;
 	st_le16(&beep_dbdma_cmd->command, OUTPUT_MORE + BR_ALWAYS);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&dmasound.lock, flags);
 
 	if (hz == beep_hz_cache && beep_vol == beep_volume_cache) {
 		nsamples = beep_nsamples_cache;
@@ -1227,7 +1238,7 @@
 	st_le32(&beep_dbdma_cmd->phy_addr, virt_to_bus(beep_buf));
 	awacs_beep_state = 1;
 
-	save_flags(flags); cli();
+	spin_lock_irqsave(&dmasound.lock, flags);
 	if (beep_playing) {	/* i.e. haven't been terminated already */
 		int count = 300 ;
 		out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);
@@ -1242,7 +1253,7 @@
 		(void)in_le32(&awacs_txdma->status);
 		out_le32(&awacs_txdma->control, RUN | (RUN << 16));
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&dmasound.lock, flags);
 }
 
 /* used in init and for wake-up */
@@ -1430,7 +1441,7 @@
 	unsigned long flags;
 
 	/* should have timeouts here */
-	save_flags(flags); cli();
+	spin_lock_irqsave(&dmasound.lock, flags);
 
 	out_le32(&awacs->codec_ctrl, addr + 0x100000);
 	awacs_burgundy_busy_wait();
@@ -1452,7 +1463,7 @@
 	awacs_burgundy_extend_wait();
 	val += ((in_le32(&awacs->codec_stat)>>4) & 0xff) <<24;
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&dmasound.lock, flags);
 
 	return val;
 }
@@ -1472,14 +1483,14 @@
 	unsigned long flags;
 
 	/* should have timeouts here */
-	save_flags(flags); cli();
+	spin_lock_irqsave(&dmasound.lock, flags);
 
 	out_le32(&awacs->codec_ctrl, addr + 0x100000);
 	awacs_burgundy_busy_wait();
 	awacs_burgundy_extend_wait();
 	val += (in_le32(&awacs->codec_stat) >> 4) & 0xff;
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&dmasound.lock, flags);
 
 	return val;
 }
diff -Nru a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c
--- a/sound/oss/dmasound/dmasound_core.c	Tue Oct  1 00:08:15 2002
+++ b/sound/oss/dmasound/dmasound_core.c	Tue Oct  1 00:08:15 2002
@@ -597,9 +597,9 @@
 	   is drained - and if we get here in time then it does not apply.
 	*/
 
-	save_flags(flags) ; cli() ;
+	spin_lock_irqsave(&dmasound.lock, flags);
 	write_sq.syncing &= ~2 ; /* take out POST status */
-	restore_flags(flags) ;
+	spin_unlock_irqrestore(&dmasound.lock, flags);
 
 	if (write_sq.count > 0 &&
 	    (bLeft = write_sq.block_size-write_sq.rear_size) > 0) {
@@ -1347,6 +1347,7 @@
 	if (dmasound.mach.record)
 		sq_fops.read = sq_read ;
 #endif
+	spin_lock_init(&dmasound.lock);
 	sq_unit = register_sound_dsp(&sq_fops, -1);
 	if (sq_unit < 0) {
 		printk(KERN_ERR "dmasound_core: couldn't register fops\n") ;
diff -Nru a/sound/oss/dmasound/dmasound_q40.c b/sound/oss/dmasound/dmasound_q40.c
--- a/sound/oss/dmasound/dmasound_q40.c	Tue Oct  1 00:08:14 2002
+++ b/sound/oss/dmasound/dmasound_q40.c	Tue Oct  1 00:08:14 2002
@@ -459,28 +459,32 @@
 		  */
 	         return;
 	}
-	save_flags(flags); cli();
+	spin_lock_irqsave(&dmasound.lock, flags);
 	Q40PlayNextFrame(1);
-	restore_flags(flags);
+	spin_unlock_irqrestore_flags(&dmasound.lock, flags);
 }
 
 static void Q40StereoInterrupt(int irq, void *dummy, struct pt_regs *fp)
 {
+	spin_lock(&dmasound.lock);
         if (q40_sc>1){
             *DAC_LEFT=*q40_pp++;
 	    *DAC_RIGHT=*q40_pp++;
 	    q40_sc -=2;
 	    master_outb(1,SAMPLE_CLEAR_REG);
 	}else Q40Interrupt();
+	spin_unlock(&dmasound.lock);
 }
 static void Q40MonoInterrupt(int irq, void *dummy, struct pt_regs *fp)
 {
+	spin_lock(&dmasound.lock);
         if (q40_sc>0){
             *DAC_LEFT=*q40_pp;
 	    *DAC_RIGHT=*q40_pp++;
 	    q40_sc --;
 	    master_outb(1,SAMPLE_CLEAR_REG);
 	}else Q40Interrupt();
+	spin_unlock(&dmasound.lock);
 }
 static void Q40Interrupt(void)
 {
diff -Nru a/sound/oss/gus_midi.c b/sound/oss/gus_midi.c
--- a/sound/oss/gus_midi.c	Tue Oct  1 00:08:21 2002
+++ b/sound/oss/gus_midi.c	Tue Oct  1 00:08:21 2002
@@ -16,6 +16,7 @@
  */
 
 #include <linux/init.h>
+#include <linux/spinlock.h>
 #include "sound_config.h"
 
 #include "gus.h"
@@ -25,7 +26,7 @@
 static int      my_dev;
 static int      output_used = 0;
 static volatile unsigned char gus_midi_control;
-
+static spinlock_t lock=SPIN_LOCK_UNLOCKED;
 static void     (*midi_input_intr) (int dev, unsigned char data);
 
 static unsigned char tmp_queue[256];
@@ -75,8 +76,7 @@
 
 	output_used = 1;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&lock, flags);
 
 	if (GUS_MIDI_STATUS() & MIDI_XMIT_EMPTY)
 	{
@@ -92,7 +92,7 @@
 		outb((gus_midi_control), u_MidiControl);
 	}
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&lock,flags);
 	return ok;
 }
 
@@ -113,16 +113,14 @@
 	/*
 	 * Drain the local queue first
 	 */
-
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&lock, flags);
 
 	while (qlen && dump_to_midi(tmp_queue[qhead]))
 	{
 		qlen--;
 		qhead++;
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&lock,flags);
 
 	/*
 	 *	Output the byte if the local queue is empty.
@@ -142,14 +140,13 @@
 		return 0;	/*
 				 * Local queue full
 				 */
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&lock, flags);
 
 	tmp_queue[qtail] = midi_byte;
 	qlen++;
 	qtail++;
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&lock,flags);
 	return 1;
 }
 
@@ -174,15 +171,14 @@
 	if (!output_used)
 		return 0;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&lock, flags);
 
 	if (qlen && dump_to_midi(tmp_queue[qhead]))
 	{
 		qlen--;
 		qhead++;
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&lock,flags);
 	return (qlen > 0) | !(GUS_MIDI_STATUS() & MIDI_XMIT_EMPTY);
 }
 
@@ -226,11 +222,9 @@
 void gus_midi_interrupt(int dummy)
 {
 	volatile unsigned char stat, data;
-	unsigned long flags;
 	int timeout = 10;
 
-	save_flags(flags);
-	cli();
+	spin_lock(&lock);
 
 	while (timeout-- > 0 && (stat = GUS_MIDI_STATUS()) & (MIDI_RCV_FULL | MIDI_XMIT_EMPTY))
 	{
@@ -258,5 +252,5 @@
 			}
 		}
 	}
-	restore_flags(flags);
+	spin_unlock(&lock);
 }
diff -Nru a/sound/oss/gus_wave.c b/sound/oss/gus_wave.c
--- a/sound/oss/gus_wave.c	Tue Oct  1 00:08:16 2002
+++ b/sound/oss/gus_wave.c	Tue Oct  1 00:08:16 2002
@@ -19,6 +19,7 @@
  
 #include <linux/init.h> 
 #include <linux/config.h>
+#include <linux/spinlock.h>
 
 #define GUSPNP_AUTODETECT
 
@@ -138,6 +139,7 @@
 static unsigned long pcm_current_buf;
 static int      pcm_current_count;
 static int      pcm_current_intrflag;
+static spinlock_t lock=SPIN_LOCK_UNLOCKED;
 
 extern int     *gus_osp;
 
@@ -226,8 +228,6 @@
 {				/* Writes a byte to the DRAM */
 	unsigned long   flags;
 
-	save_flags(flags);
-	cli();
 	outb((0x43), u_Command);
 	outb((addr & 0xff), u_DataLo);
 	outb(((addr >> 8) & 0xff), u_DataHi);
@@ -235,16 +235,12 @@
 	outb((0x44), u_Command);
 	outb(((addr >> 16) & 0xff), u_DataHi);
 	outb((data), u_DRAMIO);
-	restore_flags(flags);
 }
 
 static unsigned char gus_peek(long addr)
 {				/* Reads a byte from the DRAM */
-	unsigned long   flags;
 	unsigned char   tmp;
 
-	save_flags(flags);
-	cli();
 	outb((0x43), u_Command);
 	outb((addr & 0xff), u_DataLo);
 	outb(((addr >> 8) & 0xff), u_DataHi);
@@ -252,35 +248,23 @@
 	outb((0x44), u_Command);
 	outb(((addr >> 16) & 0xff), u_DataHi);
 	tmp = inb(u_DRAMIO);
-	restore_flags(flags);
 
 	return tmp;
 }
 
 void gus_write8(int reg, unsigned int data)
 {				/* Writes to an indirect register (8 bit) */
-	unsigned long   flags;
-
-	save_flags(flags);
-	cli();
-
 	outb((reg), u_Command);
 	outb(((unsigned char) (data & 0xff)), u_DataHi);
-
-	restore_flags(flags);
 }
 
 static unsigned char gus_read8(int reg)
 {				
 	/* Reads from an indirect register (8 bit). Offset 0x80. */
-	unsigned long   flags;
 	unsigned char   val;
 
-	save_flags(flags);
-	cli();
 	outb((reg | 0x80), u_Command);
 	val = inb(u_DataHi);
-	restore_flags(flags);
 
 	return val;
 }
@@ -288,14 +272,10 @@
 static unsigned char gus_look8(int reg)
 {
 	/* Reads from an indirect register (8 bit). No additional offset. */
-	unsigned long   flags;
 	unsigned char   val;
 
-	save_flags(flags);
-	cli();
 	outb((reg), u_Command);
 	val = inb(u_DataHi);
-	restore_flags(flags);
 
 	return val;
 }
@@ -303,54 +283,35 @@
 static void gus_write16(int reg, unsigned int data)
 {
 	/* Writes to an indirect register (16 bit) */
-	unsigned long   flags;
-
-	save_flags(flags);
-	cli();
-
 	outb((reg), u_Command);
 
 	outb(((unsigned char) (data & 0xff)), u_DataLo);
 	outb(((unsigned char) ((data >> 8) & 0xff)), u_DataHi);
-
-	restore_flags(flags);
 }
 
 static unsigned short gus_read16(int reg)
 {
 	/* Reads from an indirect register (16 bit). Offset 0x80. */
-	unsigned long   flags;
 	unsigned char   hi, lo;
 
-	save_flags(flags);
-	cli();
-
 	outb((reg | 0x80), u_Command);
 
 	lo = inb(u_DataLo);
 	hi = inb(u_DataHi);
 
-	restore_flags(flags);
-
 	return ((hi << 8) & 0xff00) | lo;
 }
 
 static unsigned short gus_look16(int reg)
 {		
 	/* Reads from an indirect register (16 bit). No additional offset. */
-	unsigned long   flags;
 	unsigned char   hi, lo;
 
-	save_flags(flags);
-	cli();
-
 	outb((reg), u_Command);
 
 	lo = inb(u_DataLo);
 	hi = inb(u_DataHi);
 
-	restore_flags(flags);
-
 	return ((hi << 8) & 0xff00) | lo;
 }
 
@@ -358,10 +319,7 @@
 {
 	/* Writes an 24 bit memory address */
 	unsigned long   hold_address;
-	unsigned long   flags;
 
-	save_flags(flags);
-	cli();
 	if (is16bit)
 	{
 		if (iw_mode)
@@ -389,7 +347,6 @@
 	gus_write16(reg, (unsigned short) ((address >> 7) & 0xffff));
 	gus_write16(reg + 1, (unsigned short) ((address << 9) & 0xffff)
 		    + (frac << 5));
-	restore_flags(flags);
 }
 
 static void gus_select_voice(int voice)
@@ -514,8 +471,7 @@
 {
 	unsigned long   flags;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&lock,flags);
 	gus_select_voice(voice);
 	gus_voice_volume(0);
 	gus_voice_off();
@@ -524,7 +480,7 @@
 	gus_write8(0x0d, 0x03);	/* Ramping off */
 	voice_alloc->map[voice] = 0;
 	voice_alloc->alloc_times[voice] = 0;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&lock,flags);
 
 }
 
@@ -558,11 +514,10 @@
 
 	if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2)
 	{
-		save_flags(flags);
-		cli();
+		spin_lock_irqsave(&lock,flags);
 		gus_select_voice(voice);
 		gus_rampoff();
-		restore_flags(flags);
+		spin_unlock_irqrestore(&lock,flags);
 		return;
 		/*
 		 * Sustain phase begins. Continue envelope after receiving note off.
@@ -580,8 +535,7 @@
 	vol = voices[voice].initial_volume * voices[voice].env_offset[phase] / 255;
 	rate = voices[voice].env_rate[phase];
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&lock,flags);
 	gus_select_voice(voice);
 
 	gus_voice_volume(prev_vol);
@@ -593,7 +547,7 @@
 
 	if (((vol - prev_vol) / 64) == 0)	/* No significant volume change */
 	{
-		restore_flags(flags);
+		spin_unlock_irqrestore(&lock,flags);
 		step_envelope(voice);		/* Continue the envelope on the next step */
 		return;
 	}
@@ -612,7 +566,7 @@
 		gus_rampon(0x60);	/* Decreasing volume, with IRQ */
 	}
 	voices[voice].current_volume = vol;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&lock,flags);
 }
 
 static void init_envelope(int voice)
@@ -623,7 +577,7 @@
 	step_envelope(voice);
 }
 
-static void start_release(int voice, long int flags)
+static void start_release(int voice)
 {
 	if (gus_read8(0x00) & 0x03)
 		return;		/* Voice already stopped */
@@ -635,7 +589,6 @@
 
 	voices[voice].mode &= ~WAVE_SUSTAIN_ON;
 	gus_rampoff();
-	restore_flags(flags);
 	step_envelope(voice);
 }
 
@@ -644,23 +597,22 @@
 	int instr_no = sample_map[voice], is16bits;
 	long int flags;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&lock,flags);
 	gus_select_voice(voice);
 
 	if (instr_no < 0 || instr_no > MAX_SAMPLE)
 	{
 		gus_write8(0x00, 0x03);	/* Hard stop */
 		voice_alloc->map[voice] = 0;
-		restore_flags(flags);
+		spin_unlock_irqrestore(&lock,flags);
 		return;
 	}
 	is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0;	/* 8 or 16 bits */
 
 	if (voices[voice].mode & WAVE_ENVELOPES)
 	{
-		start_release(voice, flags);
-		restore_flags(flags);
+		start_release(voice);
+		spin_unlock_irqrestore(&lock,flags);
 		return;
 	}
 	/*
@@ -671,14 +623,14 @@
 		gus_voice_off();
 		gus_rampoff();
 		gus_voice_init(voice);
-		restore_flags(flags);
+		spin_unlock_irqrestore(&lock,flags);
 		return;
 	}
 	gus_ramp_range(65, 4030);
 	gus_ramp_rate(2, 4);
 	gus_rampon(0x40 | 0x20);	/* Down, once, with IRQ */
 	voices[voice].volume_irq_mode = VMODE_HALT;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&lock,flags);
 }
 
 static void gus_reset(void)
@@ -710,8 +662,7 @@
 		0, 1, 0, 2, 0, 3, 4, 5
 	};
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&lock,flags);
 	gus_write8(0x4c, 0);	/* Reset GF1 */
 	gus_delay();
 	gus_delay();
@@ -850,7 +801,7 @@
 
 	if (iw_mode)
 		gus_write8(0x19, gus_read8(0x19) | 0x01);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&lock,flags);
 }
 
 
@@ -1159,17 +1110,16 @@
 {
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&lock,flags);
 	/* voice_alloc->map[voice] = 0xffff; */
 	if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
 	{
 		voices[voice].kill_pending = 1;
-		restore_flags(flags);
+		spin_unlock_irqrestore(&lock,flags);
 	}
 	else
 	{
-		restore_flags(flags);
+		spin_unlock_irqrestore(&lock,flags);
 		gus_voice_fade(voice);
 	}
 
@@ -1227,8 +1177,7 @@
 	compute_volume(voice, volume);
 	voices[voice].current_volume = voices[voice].initial_volume;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&lock,flags);
 	/*
 	 * CAUTION! Interrupts disabled. Enable them before returning
 	 */
@@ -1242,7 +1191,7 @@
 	{
 		gus_rampoff();
 		gus_voice_volume(target);
-		restore_flags(flags);
+		spin_unlock_irqrestore(&lock,flags);
 		return;
 	}
 	if (ramp_time == FAST_RAMP)
@@ -1255,7 +1204,7 @@
 	{
 		gus_rampoff();
 		gus_voice_volume(target);
-		restore_flags(flags);
+		spin_unlock_irqrestore(&lock,flags);
 		return;
 	}
 	if (target > curr)
@@ -1273,7 +1222,7 @@
 		gus_ramp_range(target, curr);
 		gus_rampon(0x40);	/* Ramp down, once, no irq */
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&lock,flags);
 }
 
 static void dynamic_volume_change(int voice)
@@ -1281,11 +1230,10 @@
 	unsigned char status;
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&lock,flags);
 	gus_select_voice(voice);
 	status = gus_read8(0x00);	/* Get voice status */
-	restore_flags(flags);
+	spin_unlock_irqrestore(&lock,flags);
 
 	if (status & 0x03)
 		return;		/* Voice was not running */
@@ -1300,11 +1248,10 @@
 	 * Voice is running and has envelopes.
 	 */
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&lock,flags);
 	gus_select_voice(voice);
 	status = gus_read8(0x0d);	/* Ramping status */
-	restore_flags(flags);
+	spin_unlock_irqrestore(&lock,flags);
 
 	if (status & 0x03)	/* Sustain phase? */
 	{
@@ -1336,11 +1283,10 @@
 				freq = compute_finetune(voices[voice].orig_freq, value, voices[voice].bender_range, 0);
 				voices[voice].current_freq = freq;
 
-				save_flags(flags);
-				cli();
+				spin_lock_irqsave(&lock,flags);
 				gus_select_voice(voice);
 				gus_voice_freq(freq);
-				restore_flags(flags);
+				spin_unlock_irqrestore(&lock,flags);
 			}
 			break;
 
@@ -1497,17 +1443,12 @@
 			((sample_ptrs[sample] + samples[sample].len) / GUS_BANK_SIZE))
 				printk(KERN_ERR "GUS: Sample address error\n");
 	}
-	/*************************************************************************
-	 *    CAUTION!        Interrupts disabled. Don't return before enabling
-	 *************************************************************************/
-
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&lock,flags);
 	gus_select_voice(voice);
 	gus_voice_off();
 	gus_rampoff();
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&lock,flags);
 
 	if (voices[voice].mode & WAVE_ENVELOPES)
 	{
@@ -1519,8 +1460,7 @@
 		compute_and_set_volume(voice, volume, 0);
 	}
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&lock,flags);
 	gus_select_voice(voice);
 
 	if (samples[sample].mode & WAVE_LOOP_BACK)
@@ -1560,7 +1500,7 @@
 	gus_voice_freq(freq);
 	gus_voice_balance(pan);
 	gus_voice_on(mode);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&lock,flags);
 
 	return 0;
 }
@@ -1577,8 +1517,7 @@
 	int mode;
 	int ret_val = 0;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&lock,flags);
 	if (note_num == 255)
 	{
 		if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
@@ -1604,11 +1543,10 @@
 
 		if (voices[voice].sample_pending >= 0)
 		{
-			restore_flags(flags);	/* Run temporarily with interrupts enabled */
+			spin_unlock_irqrestore(&lock,flags);	/* Run temporarily with interrupts enabled */
 			guswave_set_instr(voices[voice].dev_pending, voice, voices[voice].sample_pending);
 			voices[voice].sample_pending = -1;
-			save_flags(flags);
-			cli();
+			spin_lock_irqsave(&lock,flags);
 			gus_select_voice(voice);	/* Reselect the voice (just to be sure) */
 		}
 		if ((mode & 0x01) || (int) ((gus_read16(0x09) >> 4) < (unsigned) 2065))
@@ -1628,7 +1566,7 @@
 			gus_rampon(0x20 | 0x40);	/* Ramp down, once, irq */
 		}
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&lock,flags);
 	return ret_val;
 }
 
@@ -1871,9 +1809,7 @@
 					   blk_sz))
 				return -EFAULT;
 
-			save_flags(flags);
-			cli();
-			/******** INTERRUPTS DISABLED NOW ********/
+			spin_lock_irqsave(&lock,flags);
 			gus_write8(0x41, 0);	/* Disable GF1 DMA */
 			DMAbuf_start_dma(gus_devnum, audio_devs[gus_devnum]->dmap_out->raw_buf_phys,
 				blk_sz, DMA_MODE_WRITE);
@@ -1924,16 +1860,15 @@
 			if (audio_devs[gus_devnum]->dmap_out->dma > 3)
 				dma_command |= 0x04;	/* 16 bit DMA _channel_ */
 			
-			gus_write8(0x41, dma_command);	/* Lets go luteet (=bugs) */
-
 			/*
 			 * Sleep here until the DRAM DMA done interrupt is served
 			 */
 			active_device = GUS_DEV_WAVE;
+			gus_write8(0x41, dma_command);	/* Lets go luteet (=bugs) */
 
+			spin_unlock_irqrestore(&lock,flags); /* opens a race */
 			if (!interruptible_sleep_on_timeout(&dram_sleeper, HZ))
 				printk("GUS: DMA Transfer timed out\n");
-			restore_flags(flags);
 		}
 
 		/*
@@ -1972,11 +1907,10 @@
 	switch (cmd)
 	{
 		case _GUS_NUMVOICES:
-			save_flags(flags);
-			cli();
+			spin_lock_irqsave(&lock,flags);
 			gus_select_voice(voice);
 			gus_select_max_voices(p1);
-			restore_flags(flags);
+			spin_unlock_irqrestore(&lock,flags);
 			break;
 
 		case _GUS_VOICESAMPLE:
@@ -1984,20 +1918,18 @@
 			break;
 
 		case _GUS_VOICEON:
-			save_flags(flags);
-			cli();
+			spin_lock_irqsave(&lock,flags);
 			gus_select_voice(voice);
 			p1 &= ~0x20;	/* Don't allow interrupts */
 			gus_voice_on(p1);
-			restore_flags(flags);
+			spin_unlock_irqrestore(&lock,flags);
 			break;
 
 		case _GUS_VOICEOFF:
-			save_flags(flags);
-			cli();
+			spin_lock_irqsave(&lock,flags);
 			gus_select_voice(voice);
 			gus_voice_off();
-			restore_flags(flags);
+			spin_unlock_irqrestore(&lock,flags);
 			break;
 
 		case _GUS_VOICEFADE:
@@ -2005,36 +1937,32 @@
 			break;
 
 		case _GUS_VOICEMODE:
-			save_flags(flags);
-			cli();
+			spin_lock_irqsave(&lock,flags);
 			gus_select_voice(voice);
 			p1 &= ~0x20;	/* Don't allow interrupts */
 			gus_voice_mode(p1);
-			restore_flags(flags);
+			spin_unlock_irqrestore(&lock,flags);
 			break;
 
 		case _GUS_VOICEBALA:
-			save_flags(flags);
-			cli();
+			spin_lock_irqsave(&lock,flags);
 			gus_select_voice(voice);
 			gus_voice_balance(p1);
-			restore_flags(flags);
+			spin_unlock_irqrestore(&lock,flags);
 			break;
 
 		case _GUS_VOICEFREQ:
-			save_flags(flags);
-			cli();
+			spin_lock_irqsave(&lock,flags);
 			gus_select_voice(voice);
 			gus_voice_freq(plong);
-			restore_flags(flags);
+			spin_unlock_irqrestore(&lock,flags);
 			break;
 
 		case _GUS_VOICEVOL:
-			save_flags(flags);
-			cli();
+			spin_lock_irqsave(&lock,flags);
 			gus_select_voice(voice);
 			gus_voice_volume(p1);
-			restore_flags(flags);
+			spin_unlock_irqrestore(&lock,flags);
 			break;
 
 		case _GUS_VOICEVOL2:	/* Just update the software voice level */
@@ -2044,53 +1972,48 @@
 		case _GUS_RAMPRANGE:
 			if (voices[voice].mode & WAVE_ENVELOPES)
 				break;	/* NO-NO */
-			save_flags(flags);
-			cli();
+			spin_lock_irqsave(&lock,flags);
 			gus_select_voice(voice);
 			gus_ramp_range(p1, p2);
-			restore_flags(flags);
+			spin_unlock_irqrestore(&lock,flags);
 			break;
 
 		case _GUS_RAMPRATE:
 			if (voices[voice].mode & WAVE_ENVELOPES)
 				break;	/* NJET-NJET */
-			save_flags(flags);
-			cli();
+			spin_lock_irqsave(&lock,flags);
 			gus_select_voice(voice);
 			gus_ramp_rate(p1, p2);
-			restore_flags(flags);
+			spin_unlock_irqrestore(&lock,flags);
 			break;
 
 		case _GUS_RAMPMODE:
 			if (voices[voice].mode & WAVE_ENVELOPES)
 				break;	/* NO-NO */
-			save_flags(flags);
-			cli();
+			spin_lock_irqsave(&lock,flags);
 			gus_select_voice(voice);
 			p1 &= ~0x20;	/* Don't allow interrupts */
 			gus_ramp_mode(p1);
-			restore_flags(flags);
+			spin_unlock_irqrestore(&lock,flags);
 			break;
 
 		case _GUS_RAMPON:
 			if (voices[voice].mode & WAVE_ENVELOPES)
 				break;	/* EI-EI */
-			save_flags(flags);
-			cli();
+			spin_lock_irqsave(&lock,flags);
 			gus_select_voice(voice);
 			p1 &= ~0x20;	/* Don't allow interrupts */
 			gus_rampon(p1);
-			restore_flags(flags);
+			spin_unlock_irqrestore(&lock,flags);
 			break;
 
 		case _GUS_RAMPOFF:
 			if (voices[voice].mode & WAVE_ENVELOPES)
 				break;	/* NEJ-NEJ */
-			save_flags(flags);
-			cli();
+			spin_lock_irqsave(&lock,flags);
 			gus_select_voice(voice);
 			gus_rampoff();
-			restore_flags(flags);
+			spin_unlock_irqrestore(&lock,flags);
 			break;
 
 		case _GUS_VOLUME_SCALE:
@@ -2099,11 +2022,10 @@
 			break;
 
 		case _GUS_VOICE_POS:
-			save_flags(flags);
-			cli();
+			spin_lock_irqsave(&lock,flags);
 			gus_select_voice(voice);
 			gus_set_voice_pos(voice, plong);
-			restore_flags(flags);
+			spin_unlock_irqrestore(&lock,flags);
 			break;
 
 		default:
@@ -2294,13 +2216,12 @@
 	if (pcm_active && pcm_opened)
 		for (voice = 0; voice < gus_audio_channels; voice++)
 		{
-			save_flags(flags);
-			cli();
+			spin_lock_irqsave(&lock,flags);
 			gus_select_voice(voice);
 			gus_rampoff();
 			gus_voice_volume(1530 + (25 * gus_pcm_volume));
 			gus_ramp_range(65, 1530 + (25 * gus_pcm_volume));
-			restore_flags(flags);
+			spin_unlock_irqrestore(&lock,flags);
 		}
 }
 
@@ -2348,8 +2269,7 @@
 			if (chn == 0)
 				ramp_mode[chn] = 0x04;	/* Enable rollover bit */
 		}
-		save_flags(flags);
-		cli();
+		spin_lock_irqsave(&lock,flags);
 		gus_select_voice(chn);
 		gus_voice_freq(speed);
 
@@ -2386,18 +2306,17 @@
 					 0, is16bits);	/* Loop end location */
 		else
 			mode[chn] |= 0x08;	/* Enable looping */
-		restore_flags(flags);
+		spin_unlock_irqrestore(&lock,flags);
 	}
 	for (chn = 0; chn < gus_audio_channels; chn++)
 	{
-		save_flags(flags);
-		cli();
+		spin_lock_irqsave(&lock,flags);
 		gus_select_voice(chn);
 		gus_write8(0x0d, ramp_mode[chn]);
 		if (iw_mode)
 			gus_write8(0x15, 0x00);	/* Reset voice deactivate bit of SMSI */
 		gus_voice_on(mode[chn]);
-		restore_flags(flags);
+		spin_unlock_irqrestore(&lock,flags);
 	}
 	pcm_active = 1;
 }
@@ -2419,8 +2338,7 @@
 	unsigned char dma_command;
 	unsigned long address, hold_address;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&lock,flags);
 
 	count = total_count / gus_audio_channels;
 
@@ -2485,7 +2403,7 @@
 		active_device = GUS_DEV_PCM_CONTINUE;
 	}
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&lock,flags);
 }
 
 static void gus_uninterleave8(char *buf, int l)
@@ -2547,8 +2465,7 @@
 	unsigned long flags;
 	unsigned char mode;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&lock,flags);
 
 	DMAbuf_start_dma(dev, buf, count, DMA_MODE_READ);
 	mode = 0xa0;		/* DMA IRQ enabled, invert MSB */
@@ -2560,7 +2477,7 @@
 	mode |= 0x01;		/* DMA enable */
 
 	gus_write8(0x49, mode);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&lock,flags);
 }
 
 static int gus_audio_prepare_for_input(int dev, int bsize, int bcount)
@@ -2656,11 +2573,10 @@
 	freq = compute_finetune(voices[voice].orig_freq, value - 8192, voices[voice].bender_range, 0);
 	voices[voice].current_freq = freq;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&lock,flags);
 	gus_select_voice(voice);
 	gus_voice_freq(freq);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&lock,flags);
 }
 
 static int guswave_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc)
@@ -2741,8 +2657,7 @@
 	if (have_gus_max)	/* Don't disturb GUS MAX */
 		return;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&lock,flags);
 
 	/*
 	 *    Enable channels having vol > 10%
@@ -2768,7 +2683,7 @@
 	mix_image |= mask & 0x07;
 	outb((mix_image), u_Mixer);
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&lock,flags);
 }
 
 #define MIX_DEVS	(SOUND_MASK_MIC|SOUND_MASK_LINE| \
@@ -2977,11 +2892,10 @@
 	 *  Versions < 3.6 don't have the digital ASIC. Try to probe it first.
 	 */
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&lock,flags);
 	outb((0x20), gus_base + 0x0f);
 	val = inb(gus_base + 0x0f);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&lock,flags);
 
 	if (gus_pnp_flag || (val != 0xff && (val & 0x06)))	/* Should be 0x02?? */
 	{
@@ -3206,15 +3120,13 @@
 		vfree(samples);
 	samples=NULL;
 }
-
+/* called in interrupt context */
 static void do_loop_irq(int voice)
 {
 	unsigned char   tmp;
 	int             mode, parm;
-	unsigned long   flags;
 
-	save_flags(flags);
-	cli();
+	spin_lock(&lock);
 	gus_select_voice(voice);
 
 	tmp = gus_read8(0x00);
@@ -3290,7 +3202,7 @@
 		default:
 			break;
 	}
-	restore_flags(flags);
+	spin_unlock(&lock);
 }
 
 static void do_volume_irq(int voice)
@@ -3299,8 +3211,7 @@
 	int mode, parm;
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&lock,flags);
 
 	gus_select_voice(voice);
 	tmp = gus_read8(0x0d);
@@ -3318,18 +3229,18 @@
 		case VMODE_HALT:	/* Decay phase finished */
 			if (iw_mode)
 				gus_write8(0x15, 0x02);	/* Set voice deactivate bit of SMSI */
-			restore_flags(flags);
+			spin_unlock_irqrestore(&lock,flags);
 			gus_voice_init(voice);
 			break;
 
 		case VMODE_ENVELOPE:
 			gus_rampoff();
-			restore_flags(flags);
+			spin_unlock_irqrestore(&lock,flags);
 			step_envelope(voice);
 			break;
 
 		case VMODE_START_NOTE:
-			restore_flags(flags);
+			spin_unlock_irqrestore(&lock,flags);
 			guswave_start_note2(voices[voice].dev_pending, voice,
 				      voices[voice].note_pending, voices[voice].volume_pending);
 			if (voices[voice].kill_pending)
@@ -3345,11 +3256,10 @@
 			break;
 
 		default:
-			restore_flags(flags);
+			spin_unlock_irqrestore(&lock,flags);
 	}
-	restore_flags(flags);
 }
-
+/* called in irq context */
 void gus_voice_irq(void)
 {
 	unsigned long wave_ignore = 0, volume_ignore = 0;
diff -Nru a/sound/oss/ics2101.c b/sound/oss/ics2101.c
--- a/sound/oss/ics2101.c	Tue Oct  1 00:08:15 2002
+++ b/sound/oss/ics2101.c	Tue Oct  1 00:08:15 2002
@@ -15,6 +15,7 @@
  * Bartlomiej Zolnierkiewicz : added __init to ics2101_mixer_init()
  */
 #include <linux/init.h>
+#include <linux/spinlock.h>
 #include "sound_config.h"
 
 #include <linux/ultrasound.h>
@@ -28,6 +29,7 @@
 
 extern int     *gus_osp;
 extern int      gus_base;
+extern spinlock_t lock;
 static int      volumes[ICS_MIXDEVS];
 static int      left_fix[ICS_MIXDEVS] =
 {1, 1, 1, 2, 1, 2};
@@ -85,13 +87,12 @@
 		attn_addr |= 0x03;
 	}
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&lock, flags);
 	outb((ctrl_addr), u_MixSelect);
 	outb((selector[dev]), u_MixData);
 	outb((attn_addr), u_MixSelect);
 	outb(((unsigned char) vol), u_MixData);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&lock,flags);
 }
 
 static int set_volumes(int dev, int vol)
diff -Nru a/sound/oss/v_midi.h b/sound/oss/v_midi.h
--- a/sound/oss/v_midi.h	Tue Oct  1 00:08:17 2002
+++ b/sound/oss/v_midi.h	Tue Oct  1 00:08:17 2002
@@ -3,7 +3,7 @@
 
 	/* State variables */
  	   int opened;
-
+	   spinlock_t lock;
 	
 	/* MIDI fields */
 	   int my_mididev;
diff -Nru a/sound/oss/wf_midi.c b/sound/oss/wf_midi.c
--- a/sound/oss/wf_midi.c	Tue Oct  1 00:08:15 2002
+++ b/sound/oss/wf_midi.c	Tue Oct  1 00:08:15 2002
@@ -50,6 +50,7 @@
  */
 
 #include <linux/init.h>
+#include <linux/spinlock.h>
 #include "sound_config.h"
 
 #include <linux/wavefront.h>
@@ -79,6 +80,7 @@
 static struct wf_mpu_config *virt_dev = &devs[1];
 
 static void start_uart_mode (void);
+static spinlock_t lock=SPIN_LOCK_UNLOCKED;
 
 #define	OUTPUT_READY	0x40
 #define	INPUT_AVAIL	0x80
@@ -365,8 +367,8 @@
 	}
 
 	if (mi->m_busy) return;
+	spin_lock(&lock);
 	mi->m_busy = 1;
-	sti (); 
 
 	if (!input_dev) {
 		input_dev = physical_dev;
@@ -406,6 +408,7 @@
 	} while (input_avail() && n-- > 0);
 
 	mi->m_busy = 0;
+	spin_unlock(&lock);
 }
 
 static int
@@ -486,18 +489,17 @@
 		for (timeout = 30000; timeout > 0 && !output_ready ();
 		     timeout--);
       
-		save_flags (flags);
-		cli ();
+		spin_lock_irqsave(&lock,flags);
       
 		if (!output_ready ()) {
 			printk (KERN_WARNING "WF-MPU: Send switch "
 				"byte timeout\n");
-			restore_flags (flags);
+			spin_unlock_irqrestore(&lock,flags);
 			return 0;
 		}
       
 		write_data (switchch);
-		restore_flags (flags);
+		spin_unlock_irqrestore(&lock,flags);
 	} 
 
 	lastoutdev = dev;
@@ -511,16 +513,15 @@
 
 	for (timeout = 30000; timeout > 0 && !output_ready (); timeout--);
 
-	save_flags (flags);
-	cli ();
+	spin_lock_irqsave(&lock,flags);
 	if (!output_ready ()) {
+		spin_unlock_irqrestore(&lock,flags);
 		printk (KERN_WARNING "WF-MPU: Send data timeout\n");
-		restore_flags (flags);
 		return 0;
 	}
 
 	write_data (midi_byte);
-	restore_flags (flags);
+	spin_unlock_irqrestore(&lock,flags);
 
 	return 1;
 }
@@ -768,14 +769,13 @@
 {
 	unsigned long flags;
 
-	save_flags (flags);
-	cli();
+	spin_lock_irqsave(&lock,flags);
 
 	wf_mpu_close (virt_dev->devno);
 	/* no synth on virt_dev, so no need to call wf_mpu_synth_close() */
 	phys_dev->isvirtual = 0;
 
-	restore_flags (flags);
+	spin_unlock_irqrestore(&lock,flags);
 
 	return 0;
 }
@@ -858,8 +858,7 @@
 	int             ok, i;
 	unsigned long   flags;
 
-	save_flags (flags);
-	cli ();
+	spin_lock_irqsave(&lock,flags);
 
 	/* XXX fix me */
 
@@ -875,6 +874,6 @@
 		}
 	}
 
-	restore_flags (flags);
+	spin_unlock_irqrestore(&lock,flags);
 }
 #endif
diff -Nru a/sound/pci/Config.help b/sound/pci/Config.help
--- a/sound/pci/Config.help	Tue Oct  1 00:08:16 2002
+++ b/sound/pci/Config.help	Tue Oct  1 00:08:16 2002
@@ -5,8 +5,11 @@
   Say 'Y' or 'M' to include support for Cirrus Logic CS4610 / CS4612 /
   CS4614 / CS4615 / CS4622 / CS4624 / CS4630 / CS4280 chips.
 
-CONFIG_SND_CS46XX_ACCEPT_VALID
-  Say 'Y' to allow sample resolution for mmap() transfers.
+CONFIG_SND_CS46XX_NEW_DSP
+  Say 'Y' to use a new DSP image for SPDIF and dual codecs.
+
+CONFIG_SND_CS4281
+  Say 'Y' or 'M' to include support for Cirrus Logic CS4281.
 
 CONFIG_SND_EMU10K1
   Say 'Y' or 'M' to include support for Sound Blaster PCI 512, Live!,
@@ -35,6 +38,8 @@
   soundcards.
 
 CONFIG_SND_TRIDENT
+  Say 'Y' or 'M' to include support for Trident 4D-Wave DX/NX and
+  SiS 7018 soundcards.
 
 CONFIG_SND_YMFPCI
   Say 'Y' or 'M' to include support for Yamaha PCI audio chips - 
@@ -71,7 +76,8 @@
   Say 'Y' or 'M' to include support for ICE1712 (Envy24) based soundcards.
 
 CONFIG_SND_INTEL8X0
-  Say 'Y' or 'M' to include support for Intel8x0 based soundcards.
+  Say 'Y' or 'M' to include support for Intel8x0 based soundcards,
+  SiS 7012, AMD768/8111 and NVidia NForce chips.
 
 CONFIG_SND_SONICVIBES
   Say 'Y' or 'M' to include support for S3 SonicVibes based soundcards.
diff -Nru a/sound/pci/Config.in b/sound/pci/Config.in
--- a/sound/pci/Config.in	Tue Oct  1 00:08:17 2002
+++ b/sound/pci/Config.in	Tue Oct  1 00:08:17 2002
@@ -5,10 +5,8 @@
 
 dep_tristate 'ALi PCI Audio M5451' CONFIG_SND_ALI5451 $CONFIG_SND
 dep_tristate 'Cirrus Logic (Sound Fusion) CS4280/CS461x/CS462x/CS463x' CONFIG_SND_CS46XX $CONFIG_SND
-if [ "$CONFIG_SND_CS46XX" != "n" ]; then
-  bool       '  Cirrus Logic (Sound Fusion) MMAP support for OSS' CONFIG_SND_CS46XX_ACCEPT_VALID
-fi
-dep_tristate 'Cirrus Logic (Sound Fusion) CS4281' CONFIG_SND_CS4281 $CONFIG_SND
+dep_mbool '  Cirrus Logic (Sound Fusion) New DSP support (EXPERIMENTAL)' CONFIG_SND_CS46XX_NEW_DSP $CONFIG_SND_CS46XX $CONFIG_EXPERIMENTAL
+dep_tristate 'Cirrus Logic CS4281' CONFIG_SND_CS4281 $CONFIG_SND
 dep_tristate 'EMU10K1 (SB Live!, E-mu APS)' CONFIG_SND_EMU10K1 $CONFIG_SND
 dep_tristate 'Korg 1212 IO' CONFIG_SND_KORG1212 $CONFIG_SND
 dep_tristate 'NeoMagic NM256AV/ZX' CONFIG_SND_NM256 $CONFIG_SND
diff -Nru a/sound/pci/ac97/Makefile b/sound/pci/ac97/Makefile
--- a/sound/pci/ac97/Makefile	Tue Oct  1 00:08:15 2002
+++ b/sound/pci/ac97/Makefile	Tue Oct  1 00:08:15 2002
@@ -5,7 +5,7 @@
 
 export-objs  := ac97_codec.o ak4531_codec.o
 
-snd-ac97-codec-objs := ac97_codec.o
+snd-ac97-codec-objs := ac97_codec.o ac97_patch.o
 snd-ak4531-codec-objs := ak4531_codec.o
 
 # Toplevel Module Dependency
diff -Nru a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
--- a/sound/pci/ac97/ac97_codec.c	Tue Oct  1 00:08:16 2002
+++ b/sound/pci/ac97/ac97_codec.c	Tue Oct  1 00:08:16 2002
@@ -31,6 +31,8 @@
 #include <sound/ac97_codec.h>
 #include <sound/asoundef.h>
 #include <sound/initval.h>
+#include "ac97_id.h"
+#include "ac97_patch.h"
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
 MODULE_DESCRIPTION("Universal interface for Audio Codec '97");
@@ -51,20 +53,6 @@
 static void snd_ac97_proc_init(snd_card_t * card, ac97_t * ac97);
 static void snd_ac97_proc_done(ac97_t * ac97);
 
-static int patch_wolfson00(ac97_t * ac97);
-static int patch_wolfson03(ac97_t * ac97);
-static int patch_wolfson04(ac97_t * ac97);
-static int patch_tritech_tr28028(ac97_t * ac97);
-static int patch_sigmatel_stac9708(ac97_t * ac97);
-static int patch_sigmatel_stac9721(ac97_t * ac97);
-static int patch_sigmatel_stac9744(ac97_t * ac97);
-static int patch_sigmatel_stac9756(ac97_t * ac97);
-static int patch_cirrus_cs4299(ac97_t * ac97);
-static int patch_cirrus_spdif(ac97_t * ac97);
-static int patch_ad1819(ac97_t * ac97);
-static int patch_ad1881(ac97_t * ac97);
-static int patch_ad1886(ac97_t * ac97);
-
 typedef struct {
 	unsigned int id;
 	unsigned int mask;
@@ -78,17 +66,19 @@
 { 0x414c4300, 0xffffff00, "Realtek",		NULL },
 { 0x414c4700, 0xffffff00, "Avance Logic",	NULL },
 { 0x43525900, 0xffffff00, "Cirrus Logic",	NULL },
+{ 0x43585400, 0xffffff00, "Conexant",           NULL },
+{ 0x45838300, 0xffffff00, "ESS Technology",	NULL },
 { 0x48525300, 0xffffff00, "Intersil",		NULL },
 { 0x49434500, 0xffffff00, "ICEnsemble",		NULL },
 { 0x4e534300, 0xffffff00, "National Semiconductor", NULL },
 { 0x53494c00, 0xffffff00, "Silicon Laboratory",	NULL },
 { 0x54524100, 0xffffff00, "TriTech",		NULL },
 { 0x54584e00, 0xffffff00, "Texas Instruments",	NULL },
+{ 0x56494100, 0xffffff00, "VIA Technologies",   NULL },
 { 0x57454300, 0xffffff00, "Winbond",		NULL },
 { 0x574d4c00, 0xffffff00, "Wolfson",		NULL },
 { 0x594d4800, 0xffffff00, "Yamaha",		NULL },
 { 0x83847600, 0xffffff00, "SigmaTel",		NULL },
-{ 0x45838300, 0xffffff00, "ESS Technology",	NULL },
 { 0,	      0, 	  NULL,			NULL }
 };
 
@@ -101,9 +91,10 @@
 { 0x41445303, 0xffffffff, "AD1819",		patch_ad1819 },
 { 0x41445340, 0xffffffff, "AD1881",		patch_ad1881 },
 { 0x41445348, 0xffffffff, "AD1881A",		patch_ad1881 },
-{ 0x41445360, 0xffffffff, "AD1885",		patch_ad1881 },
+{ 0x41445360, 0xffffffff, "AD1885",		patch_ad1885 },
 { 0x41445361, 0xffffffff, "AD1886",		patch_ad1886 },
 { 0x41445362, 0xffffffff, "AD1887",		patch_ad1881 },
+{ 0x41445372, 0xffffffff, "AD1981A",		patch_ad1881 },
 { 0x414c4300, 0xfffffff0, "RL5306",	 	NULL },
 { 0x414c4310, 0xfffffff0, "RL5382", 		NULL },
 { 0x414c4320, 0xfffffff0, "RL5383", 		NULL },
@@ -114,12 +105,14 @@
 { 0x414c4750, 0xfffffff0, "ALC250",		NULL },
 { 0x43525900, 0xfffffff8, "CS4297",		NULL },
 { 0x43525910, 0xfffffff8, "CS4297A",		patch_cirrus_spdif },
-{ 0x42525920, 0xfffffff8, "CS4294/4298",	NULL },
-{ 0x42525928, 0xfffffff8, "CS4294",		NULL },
+{ 0x43525920, 0xfffffff8, "CS4294/4298",	NULL },
+{ 0x43525928, 0xfffffff8, "CS4294",		NULL },
 { 0x43525930, 0xfffffff8, "CS4299",		patch_cirrus_cs4299 },
 { 0x43525948, 0xfffffff8, "CS4201",		NULL },
 { 0x43525958, 0xfffffff8, "CS4205",		patch_cirrus_spdif },
 { 0x43525960, 0xfffffff8, "CS4291",		NULL },
+{ 0x43585429, 0xffffffff, "Cx20468",		patch_conexant },
+{ 0x45838308, 0xffffffff, "ESS1988",		NULL },
 { 0x48525300, 0xffffff00, "HMP9701",		NULL },
 { 0x49434501, 0xffffffff, "ICE1230",		NULL },
 { 0x49434511, 0xffffffff, "ICE1232",		NULL }, // alias VIA VT1611A?
@@ -130,6 +123,7 @@
 { 0x54524108, 0xffffffff, "TR28028",		patch_tritech_tr28028 }, // added by xin jin [07/09/99]
 { 0x54524123, 0xffffffff, "TR28602",		NULL }, // only guess --jk [TR28023 = eMicro EM28023 (new CT1297)]
 { 0x54584e20, 0xffffffff, "TLC320AD9xC",	NULL },
+{ 0x56494161, 0xffffffff, "VIA1612A",		NULL }, // modified ICE1232 with S/PDIF
 { 0x57454301, 0xffffffff, "W83971D",		NULL },
 { 0x574d4c00, 0xffffffff, "WM9701A",		patch_wolfson00 },
 { 0x574d4c03, 0xffffffff, "WM9703/9707",	patch_wolfson03 },
@@ -142,31 +136,9 @@
 { 0x83847609, 0xffffffff, "STAC9721/23",	patch_sigmatel_stac9721 },
 { 0x83847644, 0xffffffff, "STAC9744",		patch_sigmatel_stac9744 },
 { 0x83847656, 0xffffffff, "STAC9756/57",	patch_sigmatel_stac9756 },
-{ 0x45838308, 0xffffffff, "ESS1988",		NULL },
 { 0, 	      0,	  NULL,			NULL }
 };
 
-#define AC97_ID_AK4540		0x414b4d00
-#define AC97_ID_AK4542		0x414b4d01
-#define AC97_ID_AD1819		0x41445303
-#define AC97_ID_AD1881		0x41445340
-#define AC97_ID_AD1881A		0x41445348
-#define AC97_ID_AD1885		0x41445360
-#define AC97_ID_AD1886		0x41445361
-#define AC97_ID_AD1887		0x41445362
-#define AC97_ID_TR28028		0x54524108
-#define AC97_ID_STAC9700	0x83847600
-#define AC97_ID_STAC9704	0x83847604
-#define AC97_ID_STAC9705	0x83847605
-#define AC97_ID_STAC9708	0x83847608
-#define AC97_ID_STAC9721	0x83847609
-#define AC97_ID_STAC9744	0x83847644
-#define AC97_ID_STAC9756	0x83847656
-#define AC97_ID_CS4297A		0x43525910
-#define AC97_ID_CS4299		0x43525930
-#define AC97_ID_CS4201		0x43525948
-#define AC97_ID_CS4205		0x43525958
-
 static const char *snd_ac97_stereo_enhancements[] =
 {
   /*   0 */ "No 3D Stereo Enhancement",
@@ -268,12 +240,11 @@
 	set_bit(reg, ac97->reg_accessed);
 }
 
-#ifndef CONFIG_SND_DEBUG
-#define snd_ac97_write_cache_test snd_ac97_write_cache
-#else
 static void snd_ac97_write_cache_test(ac97_t *ac97, unsigned short reg, unsigned short value)
 {
-	return snd_ac97_write_cache(ac97, reg, value);
+	if (ac97->limited_regs && ! test_bit(reg, ac97->reg_accessed))
+  		return;
+#if 0
 	if (!snd_ac97_valid_reg(ac97, reg))
 		return;
 	spin_lock(&ac97->reg_lock);
@@ -282,8 +253,9 @@
 	if (value != ac97->regs[reg])
 		snd_printk("AC97 reg=%02x val=%04x real=%04x\n", reg, value, ac97->regs[reg]);
 	spin_unlock(&ac97->reg_lock);
-}
 #endif
+	snd_ac97_write_cache(ac97, reg, value);
+}
 
 int snd_ac97_update(ac97_t *ac97, unsigned short reg, unsigned short value)
 {
@@ -766,6 +738,13 @@
 		default: x = 0; break; // illegal.
 		}
 		change = snd_ac97_update_bits(ac97, AC97_CSR_SPDIF, 0x3fff, ((val & 0xcfff) | (x << 12)));
+	} else if (ac97->flags & AC97_CX_SPDIF) {
+		int v;
+		v = ucontrol->value.iec958.status[0] & (IEC958_AES0_CON_EMPHASIS_5015|IEC958_AES0_CON_NOT_COPYRIGHT) ? 0 : AC97_CXR_COPYRGT;
+		v |= ucontrol->value.iec958.status[0] & IEC958_AES0_NONAUDIO ? AC97_CXR_SPDIF_AC3 : AC97_CXR_SPDIF_PCM;
+		change = snd_ac97_update_bits(ac97, AC97_CXR_AUDIO_MISC, 
+					      AC97_CXR_SPDIF_MASK | AC97_CXR_COPYRGT,
+					      v);
 	} else {
 		change = snd_ac97_update_bits(ac97, AC97_SPDIF, 0x3fff, val);
 	}
@@ -808,6 +787,10 @@
     AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "AC97-SPSA", AC97_CSR_ACMODE, 0, 3, 0)
 };
 
+static const snd_kcontrol_new_t snd_ac97_conexant_controls_spdif[2] = {
+    AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), AC97_CXR_AUDIO_MISC, 3, 1, 0),
+};
+
 #define AD18XX_PCM_BITS(xname, codec, shift, mask) \
 { iface: SNDRV_CTL_ELEM_IFACE_MIXER, name: xname, info: snd_ac97_ad18xx_pcm_info_bits, \
   get: snd_ac97_ad18xx_pcm_get_bits, put: snd_ac97_ad18xx_pcm_put_bits, \
@@ -928,6 +911,9 @@
 {
 	unsigned short val, mask = 0x8000;
 
+	if (ac97->limited_regs && ! test_bit(reg, ac97->reg_accessed))
+		return 0;
+
 	switch (reg) {
 	case AC97_MASTER_TONE:
 		return ac97->caps & 0x04 ? 1 : 0;
@@ -1342,6 +1328,17 @@
 			/* set default PCM S/PDIF params */
 			/* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original,48000Hz */
 			snd_ac97_write_cache(ac97, AC97_CSR_SPDIF, 0x0a20);
+		} else if (ac97->flags & AC97_CX_SPDIF) {
+			for (idx = 0; idx < 3; idx++)
+				if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_spdif[idx], ac97))) < 0)
+					return err;
+			if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_conexant_controls_spdif[0], ac97))) < 0)
+				return err;
+			/* set default PCM S/PDIF params */
+			/* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original,48000Hz */
+			snd_ac97_write_cache(ac97, AC97_CXR_AUDIO_MISC,
+					     snd_ac97_read(ac97, AC97_CXR_AUDIO_MISC) & ~(AC97_CXR_SPDIFEN|AC97_CXR_COPYRGT|AC97_CXR_SPDIF_MASK));
+			
 		} else {
 			for (idx = 0; idx < 5; idx++)
 				if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_spdif[idx], ac97))) < 0)
@@ -1467,6 +1464,12 @@
 	*ac97 = *_ac97;
 	ac97->card = card;
 	spin_lock_init(&ac97->reg_lock);
+
+	if (ac97->reset) {
+		ac97->reset(ac97);
+		goto __access_ok;
+	}
+
 	snd_ac97_write(ac97, AC97_RESET, 0);	/* reset to defaults */
 	if (ac97->wait)
 		ac97->wait(ac97);
@@ -1505,6 +1508,10 @@
 		snd_ac97_free(ac97);
 		return -EIO;
 	}
+
+	if (ac97->reset) // FIXME: always skipping?
+		goto __ready_ok;
+
 	/* FIXME: add powerdown control */
 	/* nothing should be in powerdown mode */
 	snd_ac97_write_cache_test(ac97, AC97_POWERDOWN, 0);
@@ -1546,6 +1553,7 @@
 		snd_ac97_determine_rates(ac97, AC97_PCM_LFE_DAC_RATE, &ac97->rates_lfe_dac);
 		ac97->scaps |= AC97_SCAP_CENTER_LFE_DAC;
 	}
+	/* additional initializations */
 	if (ac97->init)
 		ac97->init(ac97);
 	snd_ac97_get_name(ac97, ac97->id, name);
@@ -1744,7 +1752,10 @@
 	int reg, val;
 
 	for (reg = 0; reg < 0x80; reg += 2) {
-		val = snd_ac97_read(ac97, reg);
+		if (ac97->limited_regs && ! test_bit(reg, ac97->reg_accessed))
+			val = 0xffff;
+		else
+			val = snd_ac97_read(ac97, reg);
 		snd_iprintf(buffer, "%i:%02x = %04x\n", subidx, reg, val);
 	}
 }
@@ -1824,276 +1835,6 @@
 }
 
 /*
- *  Chip specific initialization
- */
-
-static int patch_wolfson00(ac97_t * ac97)
-{
-	/* This sequence is suspect because it was designed for
-	   the WM9704, and is known to fail when applied to the
-	   WM9707.  If you're having trouble initializing a
-	   WM9700, this is the place to start looking.
-	   Randolph Bentson <bentson@holmsjoen.com> */
-
-	// WM9701A
-	snd_ac97_write_cache(ac97, 0x72, 0x0808);
-	snd_ac97_write_cache(ac97, 0x74, 0x0808);
-
-	// patch for DVD noise
-	snd_ac97_write_cache(ac97, 0x5a, 0x0200);
-
-	// init vol
-	snd_ac97_write_cache(ac97, 0x70, 0x0808);
-
-	snd_ac97_write_cache(ac97, AC97_SURROUND_MASTER, 0x0000);
-	return 0;
-}
-
-static int patch_wolfson03(ac97_t * ac97)
-{
-	/* This is known to work for the ViewSonic ViewPad 1000
-	   Randolph Bentson <bentson@holmsjoen.com> */
-
-	// WM9703/9707
-	snd_ac97_write_cache(ac97, 0x72, 0x0808);
-	snd_ac97_write_cache(ac97, 0x20, 0x8000);
-	return 0;
-}
-
-static int patch_wolfson04(ac97_t * ac97)
-{
-	// WM9704
-	snd_ac97_write_cache(ac97, 0x72, 0x0808);
-	snd_ac97_write_cache(ac97, 0x74, 0x0808);
-
-	// patch for DVD noise
-	snd_ac97_write_cache(ac97, 0x5a, 0x0200);
-
-	// init vol
-	snd_ac97_write_cache(ac97, 0x70, 0x0808);
-
-	snd_ac97_write_cache(ac97, AC97_SURROUND_MASTER, 0x0000);
-	return 0;
-}
-
-static int patch_tritech_tr28028(ac97_t * ac97)
-{
-	snd_ac97_write_cache(ac97, 0x26, 0x0300);
-	snd_ac97_write_cache(ac97, 0x26, 0x0000);
-	snd_ac97_write_cache(ac97, AC97_SURROUND_MASTER, 0x0000);
-	snd_ac97_write_cache(ac97, AC97_SPDIF, 0x0000);
-	return 0;
-}
-
-static int patch_sigmatel_stac9708(ac97_t * ac97)
-{
-	unsigned int codec72, codec6c;
-
-	codec72 = snd_ac97_read(ac97, AC97_SIGMATEL_BIAS2) & 0x8000;
-	codec6c = snd_ac97_read(ac97, AC97_SIGMATEL_ANALOG);
-
-	if ((codec72==0) && (codec6c==0)) {
-		snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba);
-		snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC2, 0x1000);
-		snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS1, 0xabba);
-		snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS2, 0x0007);
-	} else if ((codec72==0x8000) && (codec6c==0)) {
-		snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba);
-		snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC2, 0x1001);
-		snd_ac97_write_cache(ac97, AC97_SIGMATEL_DAC2INVERT, 0x0008);
-	} else if ((codec72==0x8000) && (codec6c==0x0080)) {
-		/* nothing */
-	}
-	snd_ac97_write_cache(ac97, AC97_SIGMATEL_MULTICHN, 0x0000);
-	return 0;
-}
-
-static int patch_sigmatel_stac9721(ac97_t * ac97)
-{
-	if (snd_ac97_read(ac97, AC97_SIGMATEL_ANALOG) == 0) {
-		// patch for SigmaTel
-		snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba);
-		snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC2, 0x4000);
-		snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS1, 0xabba);
-		snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS2, 0x0002);
-	}
-	snd_ac97_write_cache(ac97, AC97_SIGMATEL_MULTICHN, 0x0000);
-	return 0;
-}
-
-static int patch_sigmatel_stac9744(ac97_t * ac97)
-{
-	// patch for SigmaTel
-	snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba);
-	snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC2, 0x0000);	/* is this correct? --jk */
-	snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS1, 0xabba);
-	snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS2, 0x0002);
-	snd_ac97_write_cache(ac97, AC97_SIGMATEL_MULTICHN, 0x0000);
-	return 0;
-}
-
-static int patch_sigmatel_stac9756(ac97_t * ac97)
-{
-	// patch for SigmaTel
-	snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba);
-	snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC2, 0x0000);	/* is this correct? --jk */
-	snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS1, 0xabba);
-	snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS2, 0x0002);
-	snd_ac97_write_cache(ac97, AC97_SIGMATEL_MULTICHN, 0x0000);
-	return 0;
-}
-
-static int patch_cirrus_spdif(ac97_t * ac97)
-{
-	/* Basically, the cs4201/cs4205/cs4297a has non-standard sp/dif registers.
-	   WHY CAN'T ANYONE FOLLOW THE BLOODY SPEC?  *sigh*
-	   - sp/dif EA ID is not set, but sp/dif is always present.
-	   - enable/disable is spdif register bit 15.
-	   - sp/dif control register is 0x68.  differs from AC97:
-	   - valid is bit 14 (vs 15)
-	   - no DRS
-	   - only 44.1/48k [00 = 48, 01=44,1] (AC97 is 00=44.1, 10=48)
-	   - sp/dif ssource select is in 0x5e bits 0,1.
-	*/
-
-	ac97->flags |= AC97_CS_SPDIF; 
-        ac97->ext_id |= AC97_EA_SPDIF;	/* force the detection of spdif */
-	snd_ac97_write_cache(ac97, AC97_CSR_ACMODE, 0x0080);
-	return 0;
-}
-
-static int patch_cirrus_cs4299(ac97_t * ac97)
-{
-	/* force the detection of PC Beep */
-	ac97->flags |= AC97_HAS_PC_BEEP;
-	
-	return patch_cirrus_spdif(ac97);
-}
-
-static int patch_ad1819(ac97_t * ac97)
-{
-	// patch for Analog Devices
-	snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, 0x7000); /* select all codecs */
-	return 0;
-}
-
-static unsigned short patch_ad1881_unchained(ac97_t * ac97, int idx, unsigned short mask)
-{
-	unsigned short val;
-
-	// test for unchained codec
-	snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, mask);
-	snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0000);	/* ID0C, ID1C, SDIE = off */
-	val = snd_ac97_read(ac97, AC97_VENDOR_ID2);
-	if ((val & 0xff40) != 0x5340)
-		return 0;
-	ac97->spec.ad18xx.unchained[idx] = mask;
-	ac97->spec.ad18xx.id[idx] = val;
-	return mask;
-}
-
-static int patch_ad1881_chained1(ac97_t * ac97, int idx, unsigned short codec_bits)
-{
-	static int cfg_bits[3] = { 1<<12, 1<<14, 1<<13 };
-	unsigned short val;
-	
-	snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, cfg_bits[idx]);
-	snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0004);	// SDIE
-	val = snd_ac97_read(ac97, AC97_VENDOR_ID2);
-	if ((val & 0xff40) != 0x5340)
-		return 0;
-	if (codec_bits)
-		snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, codec_bits);
-	ac97->spec.ad18xx.chained[idx] = cfg_bits[idx];
-	ac97->spec.ad18xx.id[idx] = val;
-	return 1;
-}
-
-static void patch_ad1881_chained(ac97_t * ac97, int unchained_idx, int cidx1, int cidx2)
-{
-	// already detected?
-	if (ac97->spec.ad18xx.unchained[cidx1] || ac97->spec.ad18xx.chained[cidx1])
-		cidx1 = -1;
-	if (ac97->spec.ad18xx.unchained[cidx2] || ac97->spec.ad18xx.chained[cidx2])
-		cidx2 = -1;
-	if (cidx1 < 0 && cidx2 < 0)
-		return;
-	// test for chained codecs
-	snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[unchained_idx]);
-	snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0002);		// ID1C
-	if (cidx1 >= 0) {
-		if (patch_ad1881_chained1(ac97, cidx1, 0x0006))		// SDIE | ID1C
-			patch_ad1881_chained1(ac97, cidx2, 0);
-		else if (patch_ad1881_chained1(ac97, cidx2, 0x0006))	// SDIE | ID1C
-			patch_ad1881_chained1(ac97, cidx1, 0);
-	} else if (cidx2 >= 0) {
-		patch_ad1881_chained1(ac97, cidx2, 0);
-	}
-}
-
-static int patch_ad1881(ac97_t * ac97)
-{
-	static const char cfg_idxs[3][2] = {
-		{2, 1},
-		{0, 2},
-		{0, 1}
-	};
-	
-	// patch for Analog Devices
-	unsigned short codecs[3];
-	int idx, num;
-
-	init_MUTEX(&ac97->spec.ad18xx.mutex);
-
-	codecs[0] = patch_ad1881_unchained(ac97, 0, (1<<12));
-	codecs[1] = patch_ad1881_unchained(ac97, 1, (1<<14));
-	codecs[2] = patch_ad1881_unchained(ac97, 2, (1<<13));
-
-	snd_runtime_check(codecs[0] | codecs[1] | codecs[2], goto __end);
-
-	for (idx = 0; idx < 3; idx++)
-		if (ac97->spec.ad18xx.unchained[idx])
-			patch_ad1881_chained(ac97, idx, cfg_idxs[idx][0], cfg_idxs[idx][1]);
-
-	if (ac97->spec.ad18xx.id[1]) {
-		ac97->flags |= AC97_AD_MULTI;
-		ac97->scaps |= AC97_SCAP_SURROUND_DAC;
-	}
-	if (ac97->spec.ad18xx.id[2]) {
-		ac97->flags |= AC97_AD_MULTI;
-		ac97->scaps |= AC97_SCAP_CENTER_LFE_DAC;
-	}
-
-      __end:
-	/* select all codecs */
-	snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, 0x7000);
-	/* check if only one codec is present */
-	for (idx = num = 0; idx < 3; idx++)
-		if (ac97->spec.ad18xx.id[idx])
-			num++;
-	if (num == 1) {
-		/* ok, deselect all ID bits */
-		snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0000);
-	}
-	/* required for AD1886/AD1885 combination */
-	ac97->ext_id = snd_ac97_read(ac97, AC97_EXTENDED_ID);
-	if (ac97->spec.ad18xx.id[0]) {
-		ac97->id &= 0xffff0000;
-		ac97->id |= ac97->spec.ad18xx.id[0];
-	}
-	return 0;
-}
-
-static int patch_ad1886(ac97_t * ac97)
-{
-	patch_ad1881(ac97);
-	/* Presario700 workaround */
-	/* for Jack Sense/SPDIF Register misetting causing */
-	snd_ac97_write_cache(ac97, AC97_AD_JACK_SPDIF, 0x0010);
-	return 0;
-}
-
-/*
  *  PCM support
  */
 
@@ -2179,6 +1920,11 @@
 {
 	int i;
 
+	if (ac97->reset) {
+		ac97->reset(ac97);
+		goto  __reset_ready;
+	}
+
 	snd_ac97_write(ac97, AC97_POWERDOWN, 0);
 	snd_ac97_write(ac97, AC97_RESET, 0);
 	udelay(100);
@@ -2192,6 +1938,7 @@
 			break;
 		mdelay(1);
 	}
+__reset_ready:
 
 	if (ac97->init)
 		ac97->init(ac97);
diff -Nru a/sound/pci/ac97/ac97_id.h b/sound/pci/ac97/ac97_id.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/ac97/ac97_id.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,44 @@
+/*
+ *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *  Universal interface for Audio Codec '97
+ *
+ *  For more details look to AC '97 component specification revision 2.2
+ *  by Intel Corporation (http://developer.intel.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 AC97_ID_AK4540		0x414b4d00
+#define AC97_ID_AK4542		0x414b4d01
+#define AC97_ID_AD1819		0x41445303
+#define AC97_ID_AD1881		0x41445340
+#define AC97_ID_AD1881A		0x41445348
+#define AC97_ID_AD1885		0x41445360
+#define AC97_ID_AD1886		0x41445361
+#define AC97_ID_AD1887		0x41445362
+#define AC97_ID_TR28028		0x54524108
+#define AC97_ID_STAC9700	0x83847600
+#define AC97_ID_STAC9704	0x83847604
+#define AC97_ID_STAC9705	0x83847605
+#define AC97_ID_STAC9708	0x83847608
+#define AC97_ID_STAC9721	0x83847609
+#define AC97_ID_STAC9744	0x83847644
+#define AC97_ID_STAC9756	0x83847656
+#define AC97_ID_CS4297A		0x43525910
+#define AC97_ID_CS4299		0x43525930
+#define AC97_ID_CS4201		0x43525948
+#define AC97_ID_CS4205		0x43525958
diff -Nru a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/ac97/ac97_patch.c	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,324 @@
+/*
+ *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *  Universal interface for Audio Codec '97
+ *
+ *  For more details look to AC '97 component specification revision 2.2
+ *  by Intel Corporation (http://developer.intel.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 <sound/driver.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/asoundef.h>
+#include <sound/initval.h>
+
+/*
+ *  Chip specific initialization
+ */
+
+int patch_wolfson00(ac97_t * ac97)
+{
+	/* This sequence is suspect because it was designed for
+	   the WM9704, and is known to fail when applied to the
+	   WM9707.  If you're having trouble initializing a
+	   WM9700, this is the place to start looking.
+	   Randolph Bentson <bentson@holmsjoen.com> */
+
+	// WM9701A
+	snd_ac97_write_cache(ac97, 0x72, 0x0808);
+	snd_ac97_write_cache(ac97, 0x74, 0x0808);
+
+	// patch for DVD noise
+	snd_ac97_write_cache(ac97, 0x5a, 0x0200);
+
+	// init vol
+	snd_ac97_write_cache(ac97, 0x70, 0x0808);
+
+	snd_ac97_write_cache(ac97, AC97_SURROUND_MASTER, 0x0000);
+	return 0;
+}
+
+int patch_wolfson03(ac97_t * ac97)
+{
+	/* This is known to work for the ViewSonic ViewPad 1000
+	   Randolph Bentson <bentson@holmsjoen.com> */
+
+	// WM9703/9707
+	snd_ac97_write_cache(ac97, 0x72, 0x0808);
+	snd_ac97_write_cache(ac97, 0x20, 0x8000);
+	return 0;
+}
+
+int patch_wolfson04(ac97_t * ac97)
+{
+	// WM9704
+	snd_ac97_write_cache(ac97, 0x72, 0x0808);
+	snd_ac97_write_cache(ac97, 0x74, 0x0808);
+
+	// patch for DVD noise
+	snd_ac97_write_cache(ac97, 0x5a, 0x0200);
+
+	// init vol
+	snd_ac97_write_cache(ac97, 0x70, 0x0808);
+
+	snd_ac97_write_cache(ac97, AC97_SURROUND_MASTER, 0x0000);
+	return 0;
+}
+
+int patch_tritech_tr28028(ac97_t * ac97)
+{
+	snd_ac97_write_cache(ac97, 0x26, 0x0300);
+	snd_ac97_write_cache(ac97, 0x26, 0x0000);
+	snd_ac97_write_cache(ac97, AC97_SURROUND_MASTER, 0x0000);
+	snd_ac97_write_cache(ac97, AC97_SPDIF, 0x0000);
+	return 0;
+}
+
+int patch_sigmatel_stac9708(ac97_t * ac97)
+{
+	unsigned int codec72, codec6c;
+
+	codec72 = snd_ac97_read(ac97, AC97_SIGMATEL_BIAS2) & 0x8000;
+	codec6c = snd_ac97_read(ac97, AC97_SIGMATEL_ANALOG);
+
+	if ((codec72==0) && (codec6c==0)) {
+		snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba);
+		snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC2, 0x1000);
+		snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS1, 0xabba);
+		snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS2, 0x0007);
+	} else if ((codec72==0x8000) && (codec6c==0)) {
+		snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba);
+		snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC2, 0x1001);
+		snd_ac97_write_cache(ac97, AC97_SIGMATEL_DAC2INVERT, 0x0008);
+	} else if ((codec72==0x8000) && (codec6c==0x0080)) {
+		/* nothing */
+	}
+	snd_ac97_write_cache(ac97, AC97_SIGMATEL_MULTICHN, 0x0000);
+	return 0;
+}
+
+int patch_sigmatel_stac9721(ac97_t * ac97)
+{
+	if (snd_ac97_read(ac97, AC97_SIGMATEL_ANALOG) == 0) {
+		// patch for SigmaTel
+		snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba);
+		snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC2, 0x4000);
+		snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS1, 0xabba);
+		snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS2, 0x0002);
+	}
+	snd_ac97_write_cache(ac97, AC97_SIGMATEL_MULTICHN, 0x0000);
+	return 0;
+}
+
+int patch_sigmatel_stac9744(ac97_t * ac97)
+{
+	// patch for SigmaTel
+	snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba);
+	snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC2, 0x0000);	/* is this correct? --jk */
+	snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS1, 0xabba);
+	snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS2, 0x0002);
+	snd_ac97_write_cache(ac97, AC97_SIGMATEL_MULTICHN, 0x0000);
+	return 0;
+}
+
+int patch_sigmatel_stac9756(ac97_t * ac97)
+{
+	// patch for SigmaTel
+	snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba);
+	snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC2, 0x0000);	/* is this correct? --jk */
+	snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS1, 0xabba);
+	snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS2, 0x0002);
+	snd_ac97_write_cache(ac97, AC97_SIGMATEL_MULTICHN, 0x0000);
+	return 0;
+}
+
+int patch_cirrus_spdif(ac97_t * ac97)
+{
+	/* Basically, the cs4201/cs4205/cs4297a has non-standard sp/dif registers.
+	   WHY CAN'T ANYONE FOLLOW THE BLOODY SPEC?  *sigh*
+	   - sp/dif EA ID is not set, but sp/dif is always present.
+	   - enable/disable is spdif register bit 15.
+	   - sp/dif control register is 0x68.  differs from AC97:
+	   - valid is bit 14 (vs 15)
+	   - no DRS
+	   - only 44.1/48k [00 = 48, 01=44,1] (AC97 is 00=44.1, 10=48)
+	   - sp/dif ssource select is in 0x5e bits 0,1.
+	*/
+
+	ac97->flags |= AC97_CS_SPDIF; 
+        ac97->ext_id |= AC97_EA_SPDIF;	/* force the detection of spdif */
+	snd_ac97_write_cache(ac97, AC97_CSR_ACMODE, 0x0080);
+	return 0;
+}
+
+int patch_cirrus_cs4299(ac97_t * ac97)
+{
+	/* force the detection of PC Beep */
+	ac97->flags |= AC97_HAS_PC_BEEP;
+	
+	return patch_cirrus_spdif(ac97);
+}
+
+int patch_conexant(ac97_t * ac97)
+{
+	ac97->flags |= AC97_CX_SPDIF;
+        ac97->ext_id |= AC97_EA_SPDIF;	/* force the detection of spdif */
+	return 0;
+}
+
+int patch_ad1819(ac97_t * ac97)
+{
+	// patch for Analog Devices
+	snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, 0x7000); /* select all codecs */
+	return 0;
+}
+
+static unsigned short patch_ad1881_unchained(ac97_t * ac97, int idx, unsigned short mask)
+{
+	unsigned short val;
+
+	// test for unchained codec
+	snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, mask);
+	snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0000);	/* ID0C, ID1C, SDIE = off */
+	val = snd_ac97_read(ac97, AC97_VENDOR_ID2);
+	if ((val & 0xff40) != 0x5340)
+		return 0;
+	ac97->spec.ad18xx.unchained[idx] = mask;
+	ac97->spec.ad18xx.id[idx] = val;
+	return mask;
+}
+
+static int patch_ad1881_chained1(ac97_t * ac97, int idx, unsigned short codec_bits)
+{
+	static int cfg_bits[3] = { 1<<12, 1<<14, 1<<13 };
+	unsigned short val;
+	
+	snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, cfg_bits[idx]);
+	snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0004);	// SDIE
+	val = snd_ac97_read(ac97, AC97_VENDOR_ID2);
+	if ((val & 0xff40) != 0x5340)
+		return 0;
+	if (codec_bits)
+		snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, codec_bits);
+	ac97->spec.ad18xx.chained[idx] = cfg_bits[idx];
+	ac97->spec.ad18xx.id[idx] = val;
+	return 1;
+}
+
+static void patch_ad1881_chained(ac97_t * ac97, int unchained_idx, int cidx1, int cidx2)
+{
+	// already detected?
+	if (ac97->spec.ad18xx.unchained[cidx1] || ac97->spec.ad18xx.chained[cidx1])
+		cidx1 = -1;
+	if (ac97->spec.ad18xx.unchained[cidx2] || ac97->spec.ad18xx.chained[cidx2])
+		cidx2 = -1;
+	if (cidx1 < 0 && cidx2 < 0)
+		return;
+	// test for chained codecs
+	snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[unchained_idx]);
+	snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0002);		// ID1C
+	if (cidx1 >= 0) {
+		if (patch_ad1881_chained1(ac97, cidx1, 0x0006))		// SDIE | ID1C
+			patch_ad1881_chained1(ac97, cidx2, 0);
+		else if (patch_ad1881_chained1(ac97, cidx2, 0x0006))	// SDIE | ID1C
+			patch_ad1881_chained1(ac97, cidx1, 0);
+	} else if (cidx2 >= 0) {
+		patch_ad1881_chained1(ac97, cidx2, 0);
+	}
+}
+
+int patch_ad1881(ac97_t * ac97)
+{
+	static const char cfg_idxs[3][2] = {
+		{2, 1},
+		{0, 2},
+		{0, 1}
+	};
+	
+	// patch for Analog Devices
+	unsigned short codecs[3];
+	int idx, num;
+
+	init_MUTEX(&ac97->spec.ad18xx.mutex);
+
+	codecs[0] = patch_ad1881_unchained(ac97, 0, (1<<12));
+	codecs[1] = patch_ad1881_unchained(ac97, 1, (1<<14));
+	codecs[2] = patch_ad1881_unchained(ac97, 2, (1<<13));
+
+	snd_runtime_check(codecs[0] | codecs[1] | codecs[2], goto __end);
+
+	for (idx = 0; idx < 3; idx++)
+		if (ac97->spec.ad18xx.unchained[idx])
+			patch_ad1881_chained(ac97, idx, cfg_idxs[idx][0], cfg_idxs[idx][1]);
+
+	if (ac97->spec.ad18xx.id[1]) {
+		ac97->flags |= AC97_AD_MULTI;
+		ac97->scaps |= AC97_SCAP_SURROUND_DAC;
+	}
+	if (ac97->spec.ad18xx.id[2]) {
+		ac97->flags |= AC97_AD_MULTI;
+		ac97->scaps |= AC97_SCAP_CENTER_LFE_DAC;
+	}
+
+      __end:
+	/* select all codecs */
+	snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, 0x7000);
+	/* check if only one codec is present */
+	for (idx = num = 0; idx < 3; idx++)
+		if (ac97->spec.ad18xx.id[idx])
+			num++;
+	if (num == 1) {
+		/* ok, deselect all ID bits */
+		snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0000);
+	}
+	/* required for AD1886/AD1885 combination */
+	ac97->ext_id = snd_ac97_read(ac97, AC97_EXTENDED_ID);
+	if (ac97->spec.ad18xx.id[0]) {
+		ac97->id &= 0xffff0000;
+		ac97->id |= ac97->spec.ad18xx.id[0];
+	}
+	return 0;
+}
+
+int patch_ad1885(ac97_t * ac97)
+{
+	unsigned short jack;
+
+	patch_ad1881(ac97);
+	/* This is required to deal with the Intel D815EEAL2 */
+	/* i.e. Line out is actually headphone out from codec */
+
+	/* turn off jack sense bits D8 & D9 */
+	jack = snd_ac97_read(ac97, AC97_AD_JACK_SPDIF);
+	snd_ac97_write_cache(ac97, AC97_AD_JACK_SPDIF, jack | 0x0300);
+	return 0;
+}
+
+int patch_ad1886(ac97_t * ac97)
+{
+	patch_ad1881(ac97);
+	/* Presario700 workaround */
+	/* for Jack Sense/SPDIF Register misetting causing */
+	snd_ac97_write_cache(ac97, AC97_AD_JACK_SPDIF, 0x0010);
+	return 0;
+}
diff -Nru a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/ac97/ac97_patch.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,39 @@
+/*
+ *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *  Universal interface for Audio Codec '97
+ *
+ *  For more details look to AC '97 component specification revision 2.2
+ *  by Intel Corporation (http://developer.intel.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
+ *
+ */
+
+int patch_wolfson00(ac97_t * ac97);
+int patch_wolfson03(ac97_t * ac97);
+int patch_wolfson04(ac97_t * ac97);
+int patch_tritech_tr28028(ac97_t * ac97);
+int patch_sigmatel_stac9708(ac97_t * ac97);
+int patch_sigmatel_stac9721(ac97_t * ac97);
+int patch_sigmatel_stac9744(ac97_t * ac97);
+int patch_sigmatel_stac9756(ac97_t * ac97);
+int patch_cirrus_cs4299(ac97_t * ac97);
+int patch_cirrus_spdif(ac97_t * ac97);
+int patch_conexant(ac97_t * ac97);
+int patch_ad1819(ac97_t * ac97);
+int patch_ad1881(ac97_t * ac97);
+int patch_ad1885(ac97_t * ac97);
+int patch_ad1886(ac97_t * ac97);
diff -Nru a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
--- a/sound/pci/ali5451/ali5451.c	Tue Oct  1 00:08:20 2002
+++ b/sound/pci/ali5451/ali5451.c	Tue Oct  1 00:08:20 2002
@@ -1440,8 +1440,10 @@
 
 		unsigned int rate;
 		
-		if (codec->revision != ALI_5451_V02)
+		if (codec->revision != ALI_5451_V02) {
+			spin_unlock_irqrestore(&codec->reg_lock, flags);			
 			return -1;
+		}
 		rate = snd_ali_get_spdif_in_rate(codec);
 		if (rate == 0) {
 			snd_printk("ali_capture_preapre: spdif rate detect err!\n");
@@ -1968,9 +1970,10 @@
 static int snd_ali_free(ali_t * codec)
 {
 	snd_ali_disable_address_interrupt(codec);
-	synchronize_irq(codec->irq);
-	if (codec->irq >=0)
+	if (codec->irq >= 0) {
+		synchronize_irq(codec->irq);
 		free_irq(codec->irq, (void *)codec);
+	}
 	if (codec->res_port) {
 		release_resource(codec->res_port);
 		kfree_nocheck(codec->res_port);
diff -Nru a/sound/pci/cs4281.c b/sound/pci/cs4281.c
--- a/sound/pci/cs4281.c	Tue Oct  1 00:08:20 2002
+++ b/sound/pci/cs4281.c	Tue Oct  1 00:08:20 2002
@@ -1300,7 +1300,7 @@
 	}
 #endif
 	snd_cs4281_proc_done(chip);
-	if(chip->irq >= 0)
+	if (chip->irq >= 0)
 		synchronize_irq(chip->irq);
 
 	/* Mask interrupts */
diff -Nru a/sound/pci/cs46xx/Makefile b/sound/pci/cs46xx/Makefile
--- a/sound/pci/cs46xx/Makefile	Tue Oct  1 00:08:18 2002
+++ b/sound/pci/cs46xx/Makefile	Tue Oct  1 00:08:18 2002
@@ -4,6 +4,9 @@
 #
 
 snd-cs46xx-objs := cs46xx.o cs46xx_lib.o
+ifeq ($(CONFIG_SND_CS46XX_NEW_DSP),y)
+  snd-cs46xx-objs += dsp_spos.o dsp_spos_scb_lib.o
+endif
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_CS46XX) += snd-cs46xx.o
diff -Nru a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c
--- a/sound/pci/cs46xx/cs46xx.c	Tue Oct  1 00:08:21 2002
+++ b/sound/pci/cs46xx/cs46xx.c	Tue Oct  1 00:08:21 2002
@@ -51,9 +51,7 @@
 static int snd_enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
 static int snd_external_amp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
 static int snd_thinkpad[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
-#ifndef CONFIG_SND_CS46XX_ACCEPT_VALID
 static int snd_mmap_valid[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
-#endif
 
 MODULE_PARM(snd_index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
 MODULE_PARM_DESC(snd_index, "Index value for the CS46xx soundcard.");
@@ -70,11 +68,9 @@
 MODULE_PARM(snd_thinkpad, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
 MODULE_PARM_DESC(snd_thinkpad, "Force to enable Thinkpad's CLKRUN control.");
 MODULE_PARM_SYNTAX(snd_thinkpad, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC);
-#ifndef CONFIG_SND_CS46XX_ACCEPT_VALID
 MODULE_PARM(snd_mmap_valid, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
 MODULE_PARM_DESC(snd_mmap_valid, "Support OSS mmap.");
 MODULE_PARM_SYNTAX(snd_mmap_valid, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC);
-#endif
 
 static struct pci_device_id snd_cs46xx_ids[] __devinitdata = {
         { 0x1013, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* CS4280 */
@@ -109,11 +105,7 @@
 		snd_card_free(card);
 		return err;
 	}
-#ifdef CONFIG_SND_CS46XX_ACCEPT_VALID
-	chip->accept_valid = 1;
-#else
 	chip->accept_valid = snd_mmap_valid[dev];
-#endif
 	if ((err = snd_cs46xx_pcm(chip, 0, NULL)) < 0) {
 		snd_card_free(card);
 		return err;
diff -Nru a/sound/pci/cs46xx/cs46xx_image.h b/sound/pci/cs46xx/cs46xx_image.h
--- a/sound/pci/cs46xx/cs46xx_image.h	Tue Oct  1 00:08:17 2002
+++ b/sound/pci/cs46xx/cs46xx_image.h	Tue Oct  1 00:08:17 2002
@@ -1,4 +1,13 @@
-struct BA1struct BA1Struct = {
+struct BA1struct {
+	struct {
+		unsigned long offset;
+		unsigned long size;
+	} memory[BA1_MEMORY_COUNT];
+	u32 map[BA1_DWORD_SIZE];
+};
+
+
+static struct BA1struct BA1Struct = {
 {{ 0x00000000, 0x00003000 },{ 0x00010000, 0x00003800 },{ 0x00020000, 0x00007000 }},
 {0x00000000,0x00000000,0x00000000,0x00000000,
 0x00000000,0x00000000,0x00000000,0x00000000,
diff -Nru a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
--- a/sound/pci/cs46xx/cs46xx_lib.c	Tue Oct  1 00:08:15 2002
+++ b/sound/pci/cs46xx/cs46xx_lib.c	Tue Oct  1 00:08:15 2002
@@ -8,11 +8,12 @@
  *    --
  *
  *  TODO:
- *    We need a DSP code to support multichannel outputs and S/PDIF.
- *    Unfortunately, it seems that Cirrus Logic, Inc. is not willing
- *    to provide us sufficient information about the DSP processor,
- *    so we can't update the driver.
+ *    SPDIF input.
+ *    Secondary CODEC on some soundcards
  *
+ *  NOTE: with CONFIG_SND_CS46XX_NEW_DSP unset uses old DSP image (which
+ *        is default configuration), no SPDIF, no secondary codec, no
+ *        multi channel PCM.  But known to work.
  *
  *   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
@@ -45,75 +46,42 @@
 #ifndef LINUX_2_2
 #include <linux/gameport.h>
 #endif
-
-#define chip_t cs46xx_t
-
-/*
- *  constants
- */
-
-#define CS46XX_BA0_SIZE		0x1000
-#define CS46XX_BA1_DATA0_SIZE	0x3000
-#define CS46XX_BA1_DATA1_SIZE	0x3800
-#define CS46XX_BA1_PRG_SIZE	0x7000
-#define CS46XX_BA1_REG_SIZE	0x0100
-
-
-#define CS46XX_PERIOD_SIZE 2048
-#define CS46XX_FRAGS 2
-#define CS46XX_BUFFER_SIZE CS46XX_PERIOD_SIZE * CS46XX_FRAGS
-
-extern snd_pcm_ops_t snd_cs46xx_playback_ops;
-extern snd_pcm_ops_t snd_cs46xx_playback_indirect_ops;
-extern snd_pcm_ops_t snd_cs46xx_capture_ops;
-extern snd_pcm_ops_t snd_cs46xx_capture_indirect_ops;
-
-
-/*
- *  common I/O routines
- */
-
-static inline void snd_cs46xx_poke(cs46xx_t *chip, unsigned long reg, unsigned int val)
-{
-	unsigned int bank = reg >> 16;
-	unsigned int offset = reg & 0xffff;
-	writel(val, chip->region.idx[bank+1].remap_addr + offset);
-}
-
-static inline unsigned int snd_cs46xx_peek(cs46xx_t *chip, unsigned long reg)
-{
-	unsigned int bank = reg >> 16;
-	unsigned int offset = reg & 0xffff;
-	return readl(chip->region.idx[bank+1].remap_addr + offset);
-}
-
-static inline void snd_cs46xx_pokeBA0(cs46xx_t *chip, unsigned long offset, unsigned int val)
-{
-	writel(val, chip->region.name.ba0.remap_addr + offset);
-}
-
-static inline unsigned int snd_cs46xx_peekBA0(cs46xx_t *chip, unsigned long offset)
-{
-	return readl(chip->region.name.ba0.remap_addr + offset);
-}
-
+#include "cs46xx_lib.h"
 
 static unsigned short snd_cs46xx_codec_read(cs46xx_t *chip,
-					    unsigned short reg)
+					    unsigned short reg,
+					    int codec_index)
 {
 	int count;
-	unsigned short result;
+	unsigned short result,tmp;
+	u32 offset = 0;
+	snd_assert ( (codec_index == CS46XX_PRIMARY_CODEC_INDEX) ||
+		     (codec_index == CS46XX_SECONDARY_CODEC_INDEX),
+		     return -EINVAL);
+
+	if (codec_index == CS46XX_SECONDARY_CODEC_INDEX)
+		offset = CS46XX_SECONDARY_CODEC_OFFSET;
 
 	/*
 	 *  1. Write ACCAD = Command Address Register = 46Ch for AC97 register address
 	 *  2. Write ACCDA = Command Data Register = 470h    for data to write to AC97 
-	 *  3. Write ACCTL = Control Register = 460h for initiating the write
+	 *  3. Write ACCTL = Control Register = 460h for initiating the write7---55
 	 *  4. Read ACCTL = 460h, DCV should be reset by now and 460h = 17h
 	 *  5. if DCV not cleared, break and return error
 	 *  6. Read ACSTS = Status Register = 464h, check VSTS bit
 	 */
 
-	snd_cs46xx_peekBA0(chip, BA0_ACSDA);
+	snd_cs46xx_peekBA0(chip, BA0_ACSDA + offset);
+
+	tmp = snd_cs46xx_peekBA0(chip, BA0_ACCTL);
+	if ((tmp & ACCTL_VFRM) == 0) {
+		snd_printk(KERN_WARNING  "cs46xx: ACCTL_VFRM not set 0x%x\n",tmp);
+		snd_cs46xx_pokeBA0(chip, BA0_ACCTL, (tmp & (~ACCTL_ESYN)) | ACCTL_VFRM );
+		mdelay(50);
+		tmp = snd_cs46xx_peekBA0(chip, BA0_ACCTL + offset);
+		snd_cs46xx_pokeBA0(chip, BA0_ACCTL, tmp | ACCTL_ESYN | ACCTL_VFRM );
+
+	}
 
 	/*
 	 *  Setup the AC97 control registers on the CS461x to send the
@@ -130,10 +98,18 @@
 
 	snd_cs46xx_pokeBA0(chip, BA0_ACCAD, reg);
 	snd_cs46xx_pokeBA0(chip, BA0_ACCDA, 0);
-	snd_cs46xx_pokeBA0(chip, BA0_ACCTL, ACCTL_DCV | ACCTL_CRW |
-					     ACCTL_VFRM | ACCTL_ESYN |
-					     ACCTL_RSTN);
-
+	if (codec_index == CS46XX_PRIMARY_CODEC_INDEX) {
+		snd_cs46xx_pokeBA0(chip, BA0_ACCTL,/* clear ACCTL_DCV */ ACCTL_CRW | 
+				   ACCTL_VFRM | ACCTL_ESYN |
+				   ACCTL_RSTN);
+		snd_cs46xx_pokeBA0(chip, BA0_ACCTL, ACCTL_DCV | ACCTL_CRW |
+				   ACCTL_VFRM | ACCTL_ESYN |
+				   ACCTL_RSTN);
+	} else {
+		snd_cs46xx_pokeBA0(chip, BA0_ACCTL, ACCTL_DCV | ACCTL_TC |
+				   ACCTL_CRW | ACCTL_VFRM | ACCTL_ESYN |
+				   ACCTL_RSTN);
+	}
 
 	/*
 	 *  Wait for the read to occur.
@@ -165,12 +141,12 @@
 		 *  ACSTS = Status Register = 464h
 		 *  VSTS - Valid Status
 		 */
-		if (snd_cs46xx_peekBA0(chip, BA0_ACSTS) & ACSTS_VSTS)
+		if (snd_cs46xx_peekBA0(chip, BA0_ACSTS + offset) & ACSTS_VSTS)
 			goto ok2;
 		udelay(10);
 	}
 	
-	snd_printk("AC'97 read problem (ACSTS_VSTS), reg = 0x%x\n", reg);
+	snd_printk("AC'97 read problem (ACSTS_VSTS), codec_index %d, reg = 0x%x\n", codec_index, reg);
 	result = 0xffff;
 	goto end;
 
@@ -184,7 +160,9 @@
 			snd_cs46xx_peekBA0(chip, BA0_ACSDA),
 			snd_cs46xx_peekBA0(chip, BA0_ACCAD));
 #endif
-	result = snd_cs46xx_peekBA0(chip, BA0_ACSDA);
+
+	//snd_cs46xx_peekBA0(chip, BA0_ACCAD);
+	result = snd_cs46xx_peekBA0(chip, BA0_ACSDA + offset);
  end:
 	return result;
 }
@@ -194,8 +172,18 @@
 {
 	cs46xx_t *chip = snd_magic_cast(cs46xx_t, ac97->private_data, return -ENXIO);
 	unsigned short val;
+	int codec_index = -1;
+
+	/* UGGLY: nr_ac97_codecs == 0 primery codec detection is in progress */
+	if (ac97 == chip->ac97[CS46XX_PRIMARY_CODEC_INDEX] || chip->nr_ac97_codecs == 0)
+		codec_index = CS46XX_PRIMARY_CODEC_INDEX;
+	/* UGGLY: nr_ac97_codecs == 1 secondary codec detection is in progress */
+	else if (ac97 == chip->ac97[CS46XX_SECONDARY_CODEC_INDEX] || chip->nr_ac97_codecs == 1)
+		codec_index = CS46XX_SECONDARY_CODEC_INDEX;
+	else
+		snd_assert(0, return 0xffff);
 	chip->active_ctrl(chip, 1);
-	val = snd_cs46xx_codec_read(chip, reg);
+	val = snd_cs46xx_codec_read(chip, reg, codec_index);
 	chip->active_ctrl(chip, -1);
 	return val;
 }
@@ -203,8 +191,15 @@
 
 static void snd_cs46xx_codec_write(cs46xx_t *chip,
 				   unsigned short reg,
-				   unsigned short val)
+				   unsigned short val,
+				   int codec_index)
 {
+	int count;
+
+	snd_assert ((codec_index == CS46XX_PRIMARY_CODEC_INDEX) ||
+		    (codec_index == CS46XX_SECONDARY_CODEC_INDEX),
+		    return);
+
 	/*
 	 *  1. Write ACCAD = Command Address Register = 46Ch for AC97 register address
 	 *  2. Write ACCDA = Command Data Register = 470h    for data to write to AC97
@@ -212,7 +207,6 @@
 	 *  4. Read ACCTL = 460h, DCV should be reset by now and 460h = 07h
 	 *  5. if DCV not cleared, break and return error
 	 */
-	int count;
 
 	/*
 	 *  Setup the AC97 control registers on the CS461x to send the
@@ -226,10 +220,20 @@
 	 *  set ESYN - ASYNC generation enabled
 	 *  set RSTN - ARST# inactive, AC97 codec not reset
          */
-	snd_cs46xx_pokeBA0(chip, BA0_ACCAD, reg);
-	snd_cs46xx_pokeBA0(chip, BA0_ACCDA, val);
-	snd_cs46xx_pokeBA0(chip, BA0_ACCTL, ACCTL_DCV | ACCTL_VFRM |
-				             ACCTL_ESYN | ACCTL_RSTN);
+	snd_cs46xx_pokeBA0(chip, BA0_ACCAD , reg);
+	snd_cs46xx_pokeBA0(chip, BA0_ACCDA , val);
+	snd_cs46xx_peekBA0(chip, BA0_ACCTL);
+
+	if (codec_index == CS46XX_PRIMARY_CODEC_INDEX) {
+		snd_cs46xx_pokeBA0(chip, BA0_ACCTL, /* clear ACCTL_DCV */ ACCTL_VFRM |
+				   ACCTL_ESYN | ACCTL_RSTN);
+		snd_cs46xx_pokeBA0(chip, BA0_ACCTL, ACCTL_DCV | ACCTL_VFRM |
+				   ACCTL_ESYN | ACCTL_RSTN);
+	} else {
+		snd_cs46xx_pokeBA0(chip, BA0_ACCTL, ACCTL_DCV | ACCTL_TC |
+				   ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN);
+	}
+
 	for (count = 0; count < 4000; count++) {
 		/*
 		 *  First, we want to wait for a short time.
@@ -243,7 +247,7 @@
 			return;
 		}
 	}
-	snd_printk("AC'97 write problem, reg = 0x%x, val = 0x%x\n", reg, val);
+	snd_printk("AC'97 write problem, codec_index = %d, reg = 0x%x, val = 0x%x\n", codec_index, reg, val);
 }
 
 static void snd_cs46xx_ac97_write(ac97_t *ac97,
@@ -252,12 +256,21 @@
 {
 	cs46xx_t *chip = snd_magic_cast(cs46xx_t, ac97->private_data, return);
 	int val2 = 0;
+	int codec_index = -1;
 
+	/* UGGLY: nr_ac97_codecs == 0 primery codec detection is in progress */
+	if (ac97 == chip->ac97[CS46XX_PRIMARY_CODEC_INDEX] || chip->nr_ac97_codecs == 0)
+		codec_index = CS46XX_PRIMARY_CODEC_INDEX;
+	/* UGGLY: nr_ac97_codecs == 0 secondary codec detection is in progress */
+	else  if (ac97 == chip->ac97[CS46XX_SECONDARY_CODEC_INDEX] || chip->nr_ac97_codecs == 1)
+		codec_index = CS46XX_SECONDARY_CODEC_INDEX;
+	else
+		snd_assert(0,return);
 	chip->active_ctrl(chip, 1);
 	if (reg == AC97_CD)
-		val2 = snd_cs46xx_codec_read(chip, AC97_CD);
+		val2 = snd_cs46xx_codec_read(chip, AC97_CD, codec_index);
 
-	snd_cs46xx_codec_write(chip, reg, val);
+	snd_cs46xx_codec_write(chip, reg, val, codec_index);
 
 	
 	/*
@@ -320,19 +333,35 @@
 	return 0;
 }
 
-/* 3*1024 parameter, 3.5*1024 sample, 2*3.5*1024 code */
-#define BA1_DWORD_SIZE		(13 * 1024 + 512)
-#define BA1_MEMORY_COUNT	3
-
-struct BA1struct {
-	struct {
-		unsigned long offset;
-		unsigned long size;
-	} memory[BA1_MEMORY_COUNT];
-	u32 map[BA1_DWORD_SIZE];
-};
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+
+#include "imgs/cwc4630.h"
+#include "imgs/cwcasync.h"
+#include "imgs/cwcsnoop.h"
+#include "imgs/cwcbinhack.h"
+
+int snd_cs46xx_clear_BA1(cs46xx_t *chip,
+                         unsigned long offset,
+                         unsigned long len) 
+{
+	unsigned long dst;
+	unsigned int bank = offset >> 16;
+	offset = offset & 0xffff;
+
+	snd_assert(!(offset & 3) && !(len & 3), return -EINVAL);
+	dst = chip->region.idx[bank+1].remap_addr + offset;
+	len /= sizeof(u32);
+
+	/* writel already converts 32-bit value to right endianess */
+	while (len-- > 0) {
+		writel(0, dst);
+		dst += sizeof(u32);
+	}
+	return 0;
+}
+
+#else /* old DSP image */
 
-static
 #include "cs46xx_image.h"
 
 int snd_cs46xx_download_image(cs46xx_t *chip)
@@ -350,6 +379,7 @@
 	}	
 	return 0;
 }
+#endif /* CONFIG_SND_CS46XX_NEW_DSP */
 
 /*
  *  Chip reset
@@ -640,38 +670,42 @@
 static int snd_cs46xx_playback_transfer(snd_pcm_substream_t *substream, 
 					snd_pcm_uframes_t frames)
 {
-	cs46xx_t *chip = snd_pcm_substream_chip(substream);
+	/* cs46xx_t *chip = snd_pcm_substream_chip(substream); */
 	snd_pcm_runtime_t *runtime = substream->runtime;
-	snd_pcm_sframes_t diff = runtime->control->appl_ptr - chip->play.appl_ptr;
+	snd_pcm_sframes_t diff;
+	cs46xx_pcm_t * cpcm;
+	cpcm = snd_magic_cast(cs46xx_pcm_t, substream->runtime->private_data, return -ENXIO);
+
+	diff = runtime->control->appl_ptr - cpcm->appl_ptr;
 	if (diff) {
 		if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
 			diff += runtime->boundary;
-		chip->play.sw_ready += diff << chip->play.shift;
+		cpcm->sw_ready += diff << cpcm->shift;
 	}
-	chip->play.sw_ready += frames << chip->play.shift;
-	chip->play.appl_ptr = runtime->control->appl_ptr + frames;
-	while (chip->play.hw_ready < CS46XX_BUFFER_SIZE && 
-	       chip->play.sw_ready > 0) {
-		size_t hw_to_end = CS46XX_BUFFER_SIZE - chip->play.hw_data;
-		size_t sw_to_end = chip->play.sw_bufsize - chip->play.sw_data;
-		size_t bytes = CS46XX_BUFFER_SIZE - chip->play.hw_ready;
-		if (chip->play.sw_ready < bytes)
-			bytes = chip->play.sw_ready;
+	cpcm->sw_ready += frames << cpcm->shift;
+	cpcm->appl_ptr = runtime->control->appl_ptr + frames;
+	while (cpcm->hw_ready < CS46XX_BUFFER_SIZE && 
+	       cpcm->sw_ready > 0) {
+		size_t hw_to_end = CS46XX_BUFFER_SIZE - cpcm->hw_data;
+		size_t sw_to_end = cpcm->sw_bufsize - cpcm->sw_data;
+		size_t bytes = CS46XX_BUFFER_SIZE - cpcm->hw_ready;
+		if (cpcm->sw_ready < bytes)
+			bytes = cpcm->sw_ready;
 		if (hw_to_end < bytes)
 			bytes = hw_to_end;
 		if (sw_to_end < bytes)
 			bytes = sw_to_end;
-		memcpy(chip->play.hw_area + chip->play.hw_data,
-		       runtime->dma_area + chip->play.sw_data,
+		memcpy(cpcm->hw_area + cpcm->hw_data,
+		       runtime->dma_area + cpcm->sw_data,
 		       bytes);
-		chip->play.hw_data += bytes;
-		if (chip->play.hw_data == CS46XX_BUFFER_SIZE)
-			chip->play.hw_data = 0;
-		chip->play.sw_data += bytes;
-		if (chip->play.sw_data == chip->play.sw_bufsize)
-			chip->play.sw_data = 0;
-		chip->play.hw_ready += bytes;
-		chip->play.sw_ready -= bytes;
+		cpcm->hw_data += bytes;
+		if (cpcm->hw_data == CS46XX_BUFFER_SIZE)
+			cpcm->hw_data = 0;
+		cpcm->sw_data += bytes;
+		if (cpcm->sw_data == cpcm->sw_bufsize)
+			cpcm->sw_data = 0;
+		cpcm->hw_ready += bytes;
+		cpcm->sw_ready -= bytes;
 	}
 	return 0;
 }
@@ -718,24 +752,45 @@
 static snd_pcm_uframes_t snd_cs46xx_playback_direct_pointer(snd_pcm_substream_t * substream)
 {
 	cs46xx_t *chip = snd_pcm_substream_chip(substream);
-	size_t ptr = snd_cs46xx_peek(chip, BA1_PBA) - chip->play.hw_addr;
-	return ptr >> chip->play.shift;
+	size_t ptr;
+	cs46xx_pcm_t *cpcm = snd_magic_cast(cs46xx_pcm_t, substream->runtime->private_data, return -ENXIO);
+	snd_assert (cpcm->pcm_channel,return -ENXIO);
+
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	ptr = snd_cs46xx_peek(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 2) << 2);
+#else
+	ptr = snd_cs46xx_peek(chip, BA1_PBA);
+#endif
+	ptr -= cpcm->hw_addr;
+	return ptr >> cpcm->shift;
 }
 
 static snd_pcm_uframes_t snd_cs46xx_playback_indirect_pointer(snd_pcm_substream_t * substream)
 {
 	cs46xx_t *chip = snd_pcm_substream_chip(substream);
-	size_t ptr = snd_cs46xx_peek(chip, BA1_PBA) - chip->play.hw_addr;
-	ssize_t bytes = ptr - chip->play.hw_io;
+	size_t ptr;
+	cs46xx_pcm_t *cpcm = snd_magic_cast(cs46xx_pcm_t, substream->runtime->private_data, return -ENXIO);
+	ssize_t bytes;
+
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	snd_assert (cpcm->pcm_channel,return -ENXIO);
+	ptr = snd_cs46xx_peek(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 2) << 2);
+#else
+	ptr = snd_cs46xx_peek(chip, BA1_PBA);
+#endif
+	ptr -= cpcm->hw_addr;
+
+	bytes = ptr - cpcm->hw_io;
+
 	if (bytes < 0)
 		bytes += CS46XX_BUFFER_SIZE;
-	chip->play.hw_io = ptr;
-	chip->play.hw_ready -= bytes;
-	chip->play.sw_io += bytes;
-	if (chip->play.sw_io > chip->play.sw_bufsize)
-		chip->play.sw_io -= chip->play.sw_bufsize;
+	cpcm->hw_io = ptr;
+	cpcm->hw_ready -= bytes;
+	cpcm->sw_io += bytes;
+	if (cpcm->sw_io > cpcm->sw_bufsize)
+		cpcm->sw_io -= cpcm->sw_bufsize;
 	snd_cs46xx_playback_transfer(substream, 0);
-	return chip->play.sw_io >> chip->play.shift;
+	return cpcm->sw_io >> cpcm->shift;
 }
 
 static snd_pcm_uframes_t snd_cs46xx_capture_direct_pointer(snd_pcm_substream_t * substream)
@@ -768,10 +823,16 @@
 				    snd_pcm_uframes_t frames)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
-	cs46xx_t *chip = snd_pcm_substream_chip(substream);
-	size_t hwoffb = hwoff << chip->play.shift;
-	size_t bytes = frames << chip->play.shift;
-	char *hwbuf = runtime->dma_area + hwoffb;
+	/*cs46xx_t *chip = snd_pcm_substream_chip(substream); */
+	size_t hwoffb;
+	size_t bytes;
+	char *hwbuf;
+	cs46xx_pcm_t *cpcm = snd_magic_cast(cs46xx_pcm_t, substream->runtime->private_data, return -ENXIO);
+
+	hwoffb = hwoff << cpcm->shift;
+	bytes = frames << cpcm->shift;
+	hwbuf = runtime->dma_area + hwoffb;
+
 	if (copy_from_user(hwbuf, src, bytes))
 		return -EFAULT;
 	spin_lock_irq(&runtime->lock);
@@ -803,24 +864,49 @@
 				       int cmd)
 {
 	cs46xx_t *chip = snd_pcm_substream_chip(substream);
-	unsigned int tmp;
+	/*snd_pcm_runtime_t *runtime = substream->runtime;*/
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	cs46xx_pcm_t *cpcm = snd_magic_cast(cs46xx_pcm_t, substream->runtime->private_data, return -ENXIO);
+#endif
 	int result = 0;
 
 	spin_lock(&chip->reg_lock);
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	if (! cpcm->pcm_channel) {
+		spin_unlock(&chip->reg_lock);
+		return -ENXIO;
+	}
+#endif
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_RESUME:
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+		if (cpcm->pcm_channel->unlinked)
+			cs46xx_dsp_pcm_link(chip,cpcm->pcm_channel);
 		if (substream->runtime->periods != CS46XX_FRAGS)
 			snd_cs46xx_playback_transfer(substream, 0);
+#else
+		if (substream->runtime->periods != CS46XX_FRAGS)
+			snd_cs46xx_playback_transfer(substream, 0);
+		{ unsigned int tmp;
 		tmp = snd_cs46xx_peek(chip, BA1_PCTL);
 		tmp &= 0x0000ffff;
-		snd_cs46xx_poke(chip, BA1_PCTL, chip->play.ctl | tmp);
+		snd_cs46xx_poke(chip, BA1_PCTL, chip->play_ctl | tmp);
+		}
+#endif
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+		if (!cpcm->pcm_channel->unlinked)
+			cs46xx_dsp_pcm_unlink(chip,cpcm->pcm_channel);
+#else
+		{ unsigned int tmp;
 		tmp = snd_cs46xx_peek(chip, BA1_PCTL);
 		tmp &= 0x0000ffff;
 		snd_cs46xx_poke(chip, BA1_PCTL, tmp);
+		}
+#endif
 		break;
 	default:
 		result = -EINVAL;
@@ -862,19 +948,22 @@
 static int snd_cs46xx_playback_hw_params(snd_pcm_substream_t * substream,
 					 snd_pcm_hw_params_t * hw_params)
 {
-	cs46xx_t *chip = snd_pcm_substream_chip(substream);
+	/*cs46xx_t *chip = snd_pcm_substream_chip(substream);*/
 	snd_pcm_runtime_t *runtime = substream->runtime;
+	cs46xx_pcm_t *cpcm;
 	int err;
 
+	cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO);
+
 	if (params_periods(hw_params) == CS46XX_FRAGS) {
-		if (runtime->dma_area != chip->play.hw_area)
+		if (runtime->dma_area != cpcm->hw_area)
 			snd_pcm_lib_free_pages(substream);
-		runtime->dma_area = chip->play.hw_area;
-		runtime->dma_addr = chip->play.hw_addr;
-		runtime->dma_bytes = chip->play.hw_size;
+		runtime->dma_area = cpcm->hw_area;
+		runtime->dma_addr = cpcm->hw_addr;
+		runtime->dma_bytes = cpcm->hw_size;
 		substream->ops = &snd_cs46xx_playback_ops;
 	} else {
-		if (runtime->dma_area == chip->play.hw_area) {
+		if (runtime->dma_area == cpcm->hw_area) {
 			runtime->dma_area = NULL;
 			runtime->dma_addr = 0;
 			runtime->dma_bytes = 0;
@@ -888,11 +977,15 @@
 
 static int snd_cs46xx_playback_hw_free(snd_pcm_substream_t * substream)
 {
-	cs46xx_t *chip = snd_pcm_substream_chip(substream);
+	/*cs46xx_t *chip = snd_pcm_substream_chip(substream);*/
 	snd_pcm_runtime_t *runtime = substream->runtime;
+	cs46xx_pcm_t *cpcm;
+
+	cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO);
 
-	if (runtime->dma_area != chip->play.hw_area)
+	if (runtime->dma_area != cpcm->hw_area)
 		snd_pcm_lib_free_pages(substream);
+    
 	runtime->dma_area = NULL;
 	runtime->dma_addr = 0;
 	runtime->dma_bytes = 0;
@@ -905,39 +998,92 @@
 	unsigned int pfie;
 	cs46xx_t *chip = snd_pcm_substream_chip(substream);
 	snd_pcm_runtime_t *runtime = substream->runtime;
+	cs46xx_pcm_t *cpcm;
 
-	pfie = snd_cs46xx_peek(chip, BA1_PFIE);
+	cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO);
+
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	down (&chip->dsp_spos_instance->pcm_mutex);
+	if ( cpcm->pcm_channel->src_scb->ref_count == 1 &&
+	     cpcm->pcm_channel->sample_rate != runtime->rate) {
+		/* sample rate not set or we can reuse
+		   the same SRC*/
+
+		cs46xx_dsp_set_src_sample_rate (chip,cpcm->pcm_channel->src_scb,runtime->rate);
+		cpcm->pcm_channel->sample_rate = runtime->rate;
+	} 
+	up (&chip->dsp_spos_instance->pcm_mutex);
+
+	if (cpcm->pcm_channel->sample_rate != runtime->rate &&
+	    cpcm->pcm_channel->src_scb->ref_count != 1) {
+		cs46xx_dsp_destroy_pcm_channel (chip,cpcm->pcm_channel);
+
+		if ( (cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip,runtime->rate,cpcm)) == NULL) {
+			snd_printk(KERN_ERR "cs46xx: failed to re-create virtual PCM channel\n");
+			return -ENXIO;
+		}
+
+		cs46xx_dsp_pcm_unlink (chip,cpcm->pcm_channel);
+		cpcm->pcm_channel->sample_rate = runtime->rate;
+	}
+
+	pfie = snd_cs46xx_peek(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 1) << 2 );
 	pfie &= ~0x0000f03f;
+#else
+	/* old dsp */
+	pfie = snd_cs46xx_peek(chip, BA1_PFIE);
+ 	pfie &= ~0x0000f03f;
+#endif
 
-	chip->play.shift = 2;
+	cpcm->shift = 2;
+	/* if to convert from stereo to mono */
 	if (runtime->channels == 1) {
-		chip->play.shift--;
+		cpcm->shift--;
 		pfie |= 0x00002000;
 	}
+	/* if to convert from 8 bit to 16 bit */
 	if (snd_pcm_format_width(runtime->format) == 8) {
-		chip->play.shift--;
+		cpcm->shift--;
 		pfie |= 0x00001000;
 	}
+	/* if to convert to unsigned */
 	if (snd_pcm_format_unsigned(runtime->format))
 		pfie |= 0x00008000;
-	if (snd_pcm_format_big_endian(runtime->format))
-		pfie |= 0x00004000;
 
+	/* Never convert byte order when sample stream is 8 bit */
+	if (snd_pcm_format_width(runtime->format) != 8) {
+		/* convert from big endian to little endian */
+		if (snd_pcm_format_big_endian(runtime->format))
+			pfie |= 0x00004000;
+	}
 	
-	chip->play.sw_bufsize = snd_pcm_lib_buffer_bytes(substream);
-	chip->play.sw_data = chip->play.sw_io = chip->play.sw_ready = 0;
-	chip->play.hw_data = chip->play.hw_io = chip->play.hw_ready = 0;
-	chip->play.appl_ptr = 0;
-	snd_cs46xx_poke(chip, BA1_PBA, chip->play.hw_addr);
+	cpcm->sw_bufsize = snd_pcm_lib_buffer_bytes(substream);
+	cpcm->sw_data = cpcm->sw_io = cpcm->sw_ready = 0;
+	cpcm->hw_data = cpcm->hw_io = cpcm->hw_ready = 0;
+	cpcm->appl_ptr = 0;
+
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	/* playback address */
+	snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 2) << 2, cpcm->hw_addr);
 
+	tmp = snd_cs46xx_peek(chip, (cpcm->pcm_channel->pcm_reader_scb->address) << 2);
+	tmp &= ~0x000003ff;
+	tmp |= (4 << cpcm->shift) - 1;
+	/* playback transaction count register */
+	snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address) << 2, tmp);
+
+	/* playback format && interrupt enable */
+	snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 1) << 2, pfie | cpcm->pcm_channel->pcm_slot);
+#else
+	snd_cs46xx_poke(chip, BA1_PBA, cpcm->hw_addr);
 	tmp = snd_cs46xx_peek(chip, BA1_PDTC);
 	tmp &= ~0x000003ff;
-	tmp |= (4 << chip->play.shift) - 1;
+	tmp |= (4 << cpcm->shift) - 1;
 	snd_cs46xx_poke(chip, BA1_PDTC, tmp);
-
 	snd_cs46xx_poke(chip, BA1_PFIE, pfie);
-
 	snd_cs46xx_set_play_sample_rate(chip, runtime->rate);
+#endif
+
 	return 0;
 }
 
@@ -999,26 +1145,68 @@
 static void snd_cs46xx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	cs46xx_t *chip = snd_magic_cast(cs46xx_t, dev_id, return);
-	unsigned int status;
+	u32 status1;
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+	u32 status2;
+	int i;
+	cs46xx_pcm_t *cpcm = NULL;
+#endif
 
 	/*
 	 *  Read the Interrupt Status Register to clear the interrupt
 	 */
-	status = snd_cs46xx_peekBA0(chip, BA0_HISR);
-	if ((status & 0x7fffffff) == 0) {
+	status1 = snd_cs46xx_peekBA0(chip, BA0_HISR);
+	if ((status1 & 0x7fffffff) == 0) {
 		snd_cs46xx_pokeBA0(chip, BA0_HICR, HICR_CHGM | HICR_IEV);
 		return;
 	}
 
-	if ((status & HISR_VC0) && chip->pcm) {
-		if (chip->play.substream)
-			snd_pcm_period_elapsed(chip->play.substream);
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	status2 = snd_cs46xx_peekBA0(chip, BA0_HSR0);
+	for (i = 0; i < DSP_MAX_PCM_CHANNELS; ++i) {
+		if (i <= 15) {
+			if ( status1 & (1 << i) ) {
+				if (i == CS46XX_DSP_CAPTURE_CHANNEL) {
+					if (chip->capt.substream)
+						snd_pcm_period_elapsed(chip->capt.substream);
+				} else {
+					if (ins->pcm_channels[i].active &&
+					    ins->pcm_channels[i].private_data &&
+					    !ins->pcm_channels[i].unlinked) {
+						cpcm = snd_magic_cast(cs46xx_pcm_t, ins->pcm_channels[i].private_data, goto _invalid_pointer);
+						snd_pcm_period_elapsed(cpcm->substream);
+					}
+				}
+			}
+		} else {
+			if ( status2 & (1 << (i - 16))) {
+				if (ins->pcm_channels[i].active && 
+				    ins->pcm_channels[i].private_data &&
+				    !ins->pcm_channels[i].unlinked) {
+					cpcm = snd_magic_cast(cs46xx_pcm_t, ins->pcm_channels[i].private_data, goto _invalid_pointer);
+					snd_pcm_period_elapsed(cpcm->substream);
+				}
+			}
+		}
+
+		continue;
+	_invalid_pointer:
+		printk (KERN_ERR "cs46xx: (interrupt) invalid pointer at pcm_channel[%d]\n",i);
+	}
+#else
+	/* old dsp */
+	if ((status1 & HISR_VC0) && chip->playback_pcm) {
+		if (chip->playback_pcm->substream)
+			snd_pcm_period_elapsed(chip->playback_pcm->substream);
 	}
-	if ((status & HISR_VC1) && chip->pcm) {
+	if ((status1 & HISR_VC1) && chip->pcm) {
 		if (chip->capt.substream)
 			snd_pcm_period_elapsed(chip->capt.substream);
 	}
-	if ((status & HISR_MIDI) && chip->rmidi) {
+#endif
+
+	if ((status1 & HISR_MIDI) && chip->rmidi) {
 		unsigned char c;
 		
 		spin_lock(&chip->reg_lock);
@@ -1088,14 +1276,49 @@
 	.fifo_size		= 0,
 };
 
+static void snd_cs46xx_pcm_free_substream(snd_pcm_runtime_t *runtime)
+{
+	cs46xx_pcm_t * cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return);
+	
+	if (cpcm)
+		snd_magic_kfree(cpcm);
+}
+
 static int snd_cs46xx_playback_open(snd_pcm_substream_t * substream)
 {
 	cs46xx_t *chip = snd_pcm_substream_chip(substream);
+	cs46xx_pcm_t * cpcm;
+	snd_pcm_runtime_t *runtime = substream->runtime;
 
-	if ((chip->play.hw_area = snd_malloc_pci_pages(chip->pci, chip->play.hw_size, &chip->play.hw_addr)) == NULL)
+	cpcm = snd_magic_kcalloc(cs46xx_pcm_t, 0, GFP_KERNEL);
+	if (cpcm == NULL)
 		return -ENOMEM;
-	chip->play.substream = substream;
-	substream->runtime->hw = snd_cs46xx_playback;
+	cpcm->hw_size = PAGE_SIZE;
+	if ((cpcm->hw_area = snd_malloc_pci_pages(chip->pci, cpcm->hw_size, &cpcm->hw_addr)) == NULL) {
+		snd_magic_kfree(cpcm);
+		return -ENOMEM;
+	}
+
+	runtime->hw = snd_cs46xx_playback;
+	runtime->private_data = cpcm;
+	runtime->private_free = snd_cs46xx_pcm_free_substream;
+
+	cpcm->substream = substream;
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip,runtime->rate,cpcm);
+
+	if (cpcm->pcm_channel == NULL) {
+		snd_printk(KERN_ERR "cs46xx: failed to create virtual PCM channel\n");
+		snd_free_pci_pages(chip->pci, cpcm->hw_size, cpcm->hw_area, cpcm->hw_addr);
+		snd_magic_kfree(cpcm);
+		return -ENOMEM;
+	}
+
+	cs46xx_dsp_pcm_unlink (chip,cpcm->pcm_channel);
+#else
+	chip->playback_pcm = cpcm; /* HACK */
+#endif
+
 	if (chip->accept_valid)
 		substream->runtime->hw.info |= SNDRV_PCM_INFO_MMAP_VALID;
 	chip->active_ctrl(chip, 1);
@@ -1121,9 +1344,22 @@
 static int snd_cs46xx_playback_close(snd_pcm_substream_t * substream)
 {
 	cs46xx_t *chip = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	cs46xx_pcm_t * cpcm;
+
+	cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO);
+
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	if (cpcm->pcm_channel) {
+		cs46xx_dsp_destroy_pcm_channel(chip,cpcm->pcm_channel);
+		cpcm->pcm_channel = NULL;
+	}
+#else
+	chip->playback_pcm = NULL;
+#endif
 
-	chip->play.substream = NULL;
-	snd_free_pci_pages(chip->pci, chip->play.hw_size, chip->play.hw_area, chip->play.hw_addr);
+	cpcm->substream = NULL;
+	snd_free_pci_pages(chip->pci, cpcm->hw_size, cpcm->hw_area, cpcm->hw_addr);
 	chip->active_ctrl(chip, -1);
 	chip->amplifier_ctrl(chip, -1);
 	return 0;
@@ -1193,6 +1429,12 @@
 	snd_pcm_lib_preallocate_free_for_all(pcm);
 }
 
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+#define MAX_PLAYBACK_CHANNELS	(DSP_MAX_PCM_CHANNELS - 1)
+#else
+#define MAX_PLAYBACK_CHANNELS	1
+#endif
+
 int __devinit snd_cs46xx_pcm(cs46xx_t *chip, int device, snd_pcm_t ** rpcm)
 {
 	snd_pcm_t *pcm;
@@ -1200,7 +1442,7 @@
 
 	if (rpcm)
 		*rpcm = NULL;
-	if ((err = snd_pcm_new(chip->card, "CS46xx", device, 1, 1, &pcm)) < 0)
+	if ((err = snd_pcm_new(chip->card, "CS46xx", device, MAX_PLAYBACK_CHANNELS, 1, &pcm)) < 0)
 		return err;
 	pcm->private_data = chip;
 	pcm->private_free = snd_cs46xx_pcm_free;
@@ -1227,8 +1469,17 @@
 static void snd_cs46xx_mixer_free_ac97(ac97_t *ac97)
 {
 	cs46xx_t *chip = snd_magic_cast(cs46xx_t, ac97->private_data, return);
-	chip->ac97 = NULL;
-	chip->eapd_switch = NULL;
+
+	snd_assert ((ac97 == chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]) ||
+		    (ac97 == chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]),
+		    return);
+
+	if (ac97 == chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]) {
+		chip->ac97[CS46XX_PRIMARY_CODEC_INDEX] = NULL;
+		chip->eapd_switch = NULL;
+	}
+	else
+		chip->ac97[CS46XX_SECONDARY_CODEC_INDEX] = NULL;
 }
 
 static int snd_cs46xx_vol_info(snd_kcontrol_t *kcontrol, 
@@ -1264,6 +1515,41 @@
 	return change;
 }
 
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+
+static int snd_cs46xx_iec958_info(snd_kcontrol_t *kcontrol, 
+				  snd_ctl_elem_info_t *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int snd_cs46xx_iec958_get(snd_kcontrol_t *kcontrol, 
+                                 snd_ctl_elem_value_t *ucontrol)
+{
+	cs46xx_t *chip = snd_kcontrol_chip(kcontrol);
+	ucontrol->value.integer.value[0] = chip->dsp_spos_instance->spdif_status_out;
+	return 0;
+}
+
+static int snd_cs46xx_iec958_put(snd_kcontrol_t *kcontrol, 
+                                  snd_ctl_elem_value_t *ucontrol)
+{
+	cs46xx_t *chip = snd_kcontrol_chip(kcontrol);
+	int change = chip->dsp_spos_instance->spdif_status_out;
+
+	if (ucontrol->value.integer.value[0] && !change) 
+		cs46xx_dsp_enable_spdif_out(chip);
+	else if (change)
+		cs46xx_dsp_disable_spdif_out(chip);
+	return (change != chip->dsp_spos_instance->spdif_status_out);
+}
+
+#endif /* CONFIG_SND_CS46XX_NEW_DSP */
+
 static snd_kcontrol_new_t snd_cs46xx_controls[] __devinitdata = {
 {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -1280,7 +1566,17 @@
 	.get = snd_cs46xx_vol_get,
 	.put = snd_cs46xx_vol_put,
 	.private_value = BA1_CVOL,
-}};
+},
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "IEC 958 output",
+	.info = snd_cs46xx_iec958_info,
+	.get = snd_cs46xx_iec958_get,
+	.put = snd_cs46xx_iec958_put,
+},
+#endif
+	};
 
 int __devinit snd_cs46xx_mixer(cs46xx_t *chip)
 {
@@ -1290,12 +1586,17 @@
 	int err;
 	int idx;
 
+	/* detect primary codec */
+	chip->nr_ac97_codecs = 0;
+	snd_printdd("snd_cs46xx: detecting primary codec\n");
 	memset(&ac97, 0, sizeof(ac97));
 	ac97.write = snd_cs46xx_ac97_write;
 	ac97.read = snd_cs46xx_ac97_read;
 	ac97.private_data = chip;
 	ac97.private_free = snd_cs46xx_mixer_free_ac97;
 
+	chip->ac97[CS46XX_PRIMARY_CODEC_INDEX] = &ac97;
+
 	snd_cs46xx_ac97_write(&ac97, AC97_MASTER, 0x8000);
 	for (idx = 0; idx < 100; ++idx) {
 		if (snd_cs46xx_ac97_read(&ac97, AC97_MASTER) == 0x8000)
@@ -1303,11 +1604,60 @@
 		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(HZ/100);
 	}
+	chip->ac97[CS46XX_PRIMARY_CODEC_INDEX] = NULL;
 	return -ENXIO;
 
  _ok:
-	if ((err = snd_ac97_mixer(card, &ac97, &chip->ac97)) < 0)
+	if ((err = snd_ac97_mixer(card, &ac97, &chip->ac97[CS46XX_PRIMARY_CODEC_INDEX])) < 0)
+		return err;
+	snd_printdd("snd_cs46xx: primary codec phase one\n");
+	chip->nr_ac97_codecs = 1;
+
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	snd_printdd("snd_cs46xx: detecting seconadry codec\n");
+	/* try detect a secondary codec */
+	memset(&ac97, 0, sizeof(ac97));    
+	ac97.write = snd_cs46xx_ac97_write;
+	ac97.read = snd_cs46xx_ac97_read;
+	ac97.private_data = chip;
+	ac97.private_free = snd_cs46xx_mixer_free_ac97;
+	ac97.num = CS46XX_SECONDARY_CODEC_INDEX;
+
+	snd_cs46xx_ac97_write(&ac97, AC97_RESET, 0);
+	udelay(10);
+
+	if (snd_cs46xx_ac97_read(&ac97, AC97_RESET) & 0x8000) {
+		snd_printdd("snd_cs46xx: seconadry codec not present\n");
+		goto _no_sec_codec;
+	}
+
+	chip->ac97[CS46XX_SECONDARY_CODEC_INDEX] = &ac97;
+	snd_cs46xx_ac97_write(&ac97, AC97_MASTER, 0x8000);
+	for (idx = 0; idx < 100; ++idx) {
+		if (snd_cs46xx_ac97_read(&ac97, AC97_MASTER) == 0x8000) {
+			goto _ok2;
+		}
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(HZ/100);
+	}
+
+ _no_sec_codec:
+	snd_printdd("snd_cs46xx: secondary codec did not respond ...\n");
+
+	chip->ac97[CS46XX_SECONDARY_CODEC_INDEX] = NULL;
+	chip->nr_ac97_codecs = 1;
+    
+	/* well, one codec only ... */
+	goto _end;
+ _ok2:
+	if ((err = snd_ac97_mixer(card, &ac97, &chip->ac97[CS46XX_SECONDARY_CODEC_INDEX])) < 0)
 		return err;
+	chip->nr_ac97_codecs = 2;
+    
+	/* add cs4630 mixer controls */
+ _end:
+#endif /* CONFIG_SND_CS46XX_NEW_DSP */
+
 	for (idx = 0; idx < sizeof(snd_cs46xx_controls) / 
 		     sizeof(snd_cs46xx_controls[0]); idx++) {
 		snd_kcontrol_t *kctl;
@@ -1652,6 +2002,9 @@
 		}
 		region->proc_entry = entry;
 	}
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	cs46xx_dsp_proc_init(card, chip);
+#endif
 	return 0;
 }
 
@@ -1666,6 +2019,9 @@
 			region->proc_entry = NULL;
 		}
 	}
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	cs46xx_dsp_proc_done(chip);
+#endif
 	return 0;
 }
 
@@ -1761,6 +2117,9 @@
 	if (chip->active_ctrl)
 		chip->active_ctrl(chip, -chip->amplifier);
 
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	cs46xx_dsp_spos_destroy(chip->dsp_spos_instance);
+#endif
 	snd_magic_kfree(chip);
 	return 0;
 }
@@ -1792,8 +2151,13 @@
 	 *  If we are in AC97 mode, then we must set the part to a host controlled
          *  AC-link.  Otherwise, we won't be able to bring up the link.
          */        
-        snd_cs46xx_pokeBA0(chip, BA0_SERACC, SERACC_HSP | SERACC_CHIP_TYPE_1_03);	/* 1.03 codec */
-        /* snd_cs46xx_pokeBA0(chip, BA0_SERACC, SERACC_HSP | SERACC_CHIP_TYPE_2_0); */ /* 2.00 codec */
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	snd_cs46xx_pokeBA0(chip, BA0_SERACC, SERACC_HSP | SERACC_CHIP_TYPE_2_0 | 
+			   SERACC_TWO_CODECS);	/* 2.00 dual codecs */
+	/* snd_cs46xx_pokeBA0(chip, BA0_SERACC, SERACC_HSP | SERACC_CHIP_TYPE_2_0); */ /* 2.00 codec */
+#else
+	snd_cs46xx_pokeBA0(chip, BA0_SERACC, SERACC_HSP | SERACC_CHIP_TYPE_1_03); /* 1.03 codec */
+#endif
 
         /*
          *  Drive the ARST# pin low for a minimum of 1uS (as defined in the AC97
@@ -1801,23 +2165,32 @@
          *  there might be logic external to the CS461x that uses the ARST# line
          *  for a reset.
          */
-        snd_cs46xx_pokeBA0(chip, BA0_ACCTL, 0);
-        udelay(50);
-        snd_cs46xx_pokeBA0(chip, BA0_ACCTL, ACCTL_RSTN);
-
+	snd_cs46xx_pokeBA0(chip, BA0_ACCTL, 0);
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	snd_cs46xx_pokeBA0(chip, BA0_ACCTL2, 0);
+#endif
+	udelay(50);
+	snd_cs46xx_pokeBA0(chip, BA0_ACCTL, ACCTL_RSTN);
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	snd_cs46xx_pokeBA0(chip, BA0_ACCTL2, ACCTL_RSTN);
+#endif
+    
 	/*
 	 *  The first thing we do here is to enable sync generation.  As soon
 	 *  as we start receiving bit clock, we'll start producing the SYNC
 	 *  signal.
 	 */
 	snd_cs46xx_pokeBA0(chip, BA0_ACCTL, ACCTL_ESYN | ACCTL_RSTN);
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	snd_cs46xx_pokeBA0(chip, BA0_ACCTL2, ACCTL_ESYN | ACCTL_RSTN);
+#endif
 
 	/*
 	 *  Now wait for a short while to allow the AC97 part to start
 	 *  generating bit clock (so we don't try to start the PLL without an
 	 *  input clock).
 	 */
-	mdelay(1);
+	mdelay(10);
 
 	/*
 	 *  Set the serial port timing configuration, so that
@@ -1842,7 +2215,7 @@
 	/*
          *  Wait until the PLL has stabilized.
 	 */
-	mdelay(1);
+	mdelay(100); /* FIXME: schedule? */
 
 	/*
 	 *  Turn on clocking of the core so that we can setup the serial ports.
@@ -1867,6 +2240,16 @@
 	snd_cs46xx_pokeBA0(chip, BA0_SERC2, SERC2_SI1F_AC97 | SERC1_SO1EN);
 	snd_cs46xx_pokeBA0(chip, BA0_SERMC1, SERMC1_PTC_AC97 | SERMC1_MSPE);
 
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	snd_cs46xx_pokeBA0(chip, BA0_SERC7, SERC7_ASDI2EN);
+	snd_cs46xx_pokeBA0(chip, BA0_SERC3, 0);
+	snd_cs46xx_pokeBA0(chip, BA0_SERC4, 0);
+	snd_cs46xx_pokeBA0(chip, BA0_SERC5, 0);
+	snd_cs46xx_pokeBA0(chip, BA0_SERC6, 1);
+#endif
+
+	mdelay(5);
+
 	/*
 	 * Wait for the codec ready signal from the AC97 codec.
 	 */
@@ -1889,14 +2272,35 @@
 
 	snd_printk("create - never read codec ready from AC'97\n");
 	snd_printk("it is not probably bug, try to use CS4236 driver\n");
-	snd_cs46xx_free(chip);
 	return -EIO;
  ok1:
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	{
+		int count;
+		for (count = 0; count < 150; count++) {
+			/* First, we want to wait for a short time. */
+			udelay(25);
+        
+			if (snd_cs46xx_peekBA0(chip, BA0_ACSTS2) & ACSTS_CRDY)
+				break;
+		}
+
+		/*
+		 *  Make sure CODEC is READY.
+		 */
+		if (!(snd_cs46xx_peekBA0(chip, BA0_ACSTS2) & ACSTS_CRDY))
+			snd_printdd("cs46xx: never read card ready from secondary AC'97\n");
+	}
+#endif
+
 	/*
 	 *  Assert the vaid frame signal so that we can start sending commands
 	 *  to the AC97 codec.
 	 */
 	snd_cs46xx_pokeBA0(chip, BA0_ACCTL, ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN);
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	snd_cs46xx_pokeBA0(chip, BA0_ACCTL2, ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN);
+#endif
 
 	/*
 	 *  Wait until we've sampled input slots 3 and 4 as valid, meaning that
@@ -1919,7 +2323,6 @@
 	}
 
 	snd_printk("create - never read ISV3 & ISV4 from AC'97\n");
-	snd_cs46xx_free(chip);
 	return -EIO;
  ok2:
 
@@ -1927,7 +2330,7 @@
 	 *  Now, assert valid frame and the slot 3 and 4 valid bits.  This will
 	 *  commense the transfer of digital audio data to the AC97 codec.
 	 */
-	snd_cs46xx_pokeBA0(chip, BA0_ACOSV, ACOSV_SLV3 | ACOSV_SLV4);
+	snd_cs46xx_pokeBA0(chip, BA0_ACOSV, ACOSV_SLV3 | ACOSV_SLV4 | ACOSV_SLV7 | ACOSV_SLV8);
 
 	/*
 	 *  Power down the DAC and ADC.  We will power them up (if) when we need
@@ -1950,9 +2353,41 @@
 	/*
          *  Download the image to the processor.
 	 */
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+#if 0
+	if (cs46xx_dsp_load_module(chip, &cwcemb80_module) < 0) {
+		snd_printk(KERN_ERR "image download error\n");
+		return -EIO;
+	}
+#endif
+
+	if (cs46xx_dsp_load_module(chip, &cwc4630_module) < 0) {
+		snd_printk(KERN_ERR "image download error [cwc4630]\n");
+		return -EIO;
+	}
+
+	if (cs46xx_dsp_load_module(chip, &cwcasync_module) < 0) {
+		snd_printk(KERN_ERR "image download error [cwcasync]\n");
+		return -EIO;
+	}
+
+	if (cs46xx_dsp_load_module(chip, &cwcsnoop_module) < 0) {
+		snd_printk(KERN_ERR "image download error [cwcsnoop]\n");
+		return -EIO;
+	}
+
+	if (cs46xx_dsp_load_module(chip, &cwcbinhack_module) < 0) {
+		snd_printk(KERN_ERR "image download error [cwcbinhack]\n");
+		return -EIO;
+	}
+
+	if (cs46xx_dsp_scb_and_task_init(chip) < 0)
+		return -EIO;
+	snd_printdd("[get here]\n");
+#else
+	/* old image */
 	if (snd_cs46xx_download_image(chip) < 0) {
 		snd_printk("image download error\n");
-		snd_cs46xx_free(chip);
 		return -EIO;
 	}
 
@@ -1960,8 +2395,9 @@
          *  Stop playback DMA.
 	 */
 	tmp = snd_cs46xx_peek(chip, BA1_PCTL);
-	chip->play.ctl = tmp & 0xffff0000;
+	chip->play_ctl = tmp & 0xffff0000;
 	snd_cs46xx_poke(chip, BA1_PCTL, tmp & 0x0000ffff);
+#endif
 
 	/*
          *  Stop capture DMA.
@@ -1970,6 +2406,8 @@
 	chip->capt.ctl = tmp & 0x0000ffff;
 	snd_cs46xx_poke(chip, BA1_CCTL, tmp & 0xffff0000);
 
+	mdelay(5);
+
 	snd_cs46xx_set_play_sample_rate(chip, 8000);
 	snd_cs46xx_set_capture_sample_rate(chip, 8000);
 
@@ -1993,6 +2431,12 @@
 	snd_cs46xx_poke(chip, BA1_PVOL, 0x80008000);
 	snd_cs46xx_poke(chip, BA1_CVOL, 0x80008000);
 
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	/* mute spdif out */
+	cs46xx_dsp_disable_spdif_out(chip);
+	cs46xx_dsp_disable_spdif_in(chip);
+#endif
+
 	return 0;
 }
 
@@ -2005,6 +2449,106 @@
 {	
 }
 
+
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+static int voyetra_setup_eapd_slot(cs46xx_t *chip)
+{
+	int i;
+    u32 idx;
+    u16 modem_power,pin_config,logic_type,valid_slots,status;
+
+	snd_printd ("cs46xx: cs46xx_setup_eapd_slot()+\n");
+	/*
+	* Clear PRA.  The Bonzo chip will be used for GPIO not for modem
+	* stuff.
+	*/
+	if(chip->nr_ac97_codecs != 2)
+	{
+      snd_printk (KERN_ERR "cs46xx: cs46xx_setup_eapd_slot() - no secondary codec configured\n");
+      return -EINVAL;
+	}
+
+	modem_power = snd_cs46xx_codec_read (chip, 
+                                         BA0_AC97_EXT_MODEM_POWER,
+                                         CS46XX_SECONDARY_CODEC_INDEX);
+	modem_power &=0xFEFF;
+
+	snd_cs46xx_codec_write(chip, 
+                           BA0_AC97_EXT_MODEM_POWER, modem_power,
+                           CS46XX_SECONDARY_CODEC_INDEX);
+
+    /*
+     * Set GPIO pin's 7 and 8 so that they are configured for output.
+     */
+	pin_config = snd_cs46xx_codec_read (chip, 
+                                        BA0_AC97_GPIO_PIN_CONFIG,
+                                        CS46XX_SECONDARY_CODEC_INDEX);
+	pin_config &=0x27F;
+
+	snd_cs46xx_codec_write(chip, 
+                           BA0_AC97_GPIO_PIN_CONFIG, pin_config,
+                           CS46XX_SECONDARY_CODEC_INDEX);
+    
+    /*
+     * Set GPIO pin's 7 and 8 so that they are compatible with CMOS logic.
+     */
+
+	logic_type = snd_cs46xx_codec_read(chip, BA0_AC97_GPIO_PIN_TYPE,
+                                       CS46XX_SECONDARY_CODEC_INDEX);
+	logic_type &=0x27F;
+	snd_cs46xx_codec_write (chip, BA0_AC97_GPIO_PIN_TYPE, logic_type,
+                            CS46XX_SECONDARY_CODEC_INDEX);
+
+	valid_slots = snd_cs46xx_peekBA0(chip, BA0_ACOSV);
+	valid_slots |= 0x200;
+	snd_cs46xx_pokeBA0(chip, BA0_ACOSV, valid_slots);
+
+    /*
+     * Fill slots 12 with the correct value for the GPIO pins. 
+     */
+	for(idx = 0x90; idx <= 0x9F; idx++) {
+
+      /*
+       * Initialize the fifo so that bits 7 and 8 are on.
+       *
+       * Remember that the GPIO pins in bonzo are shifted by 4 bits to
+       * the left.  0x1800 corresponds to bits 7 and 8.
+       */
+      snd_cs46xx_pokeBA0(chip, BA0_SERBWP, 0x1800);
+      
+      /*
+       * Make sure the previous FIFO write operation has completed.
+       */
+      for(i = 0; i < 5; i++){
+        status = snd_cs46xx_peekBA0(chip, BA0_SERBST);
+
+        if( !(status & SERBST_WBSY) ) {
+          break;
+        }
+        mdelay(100);
+      }
+
+      if(status & SERBST_WBSY) {
+        snd_printk( KERN_ERR "cs46xx: cs46xx_setup_eapd_slot() " \
+                             "Failure to write the GPIO pins for slot 12.\n");
+         return -EINVAL;
+      }
+      
+      /*
+       * Write the serial port FIFO index.
+       */
+      snd_cs46xx_pokeBA0(chip, BA0_SERBAD, idx);
+      
+      /*
+       * Tell the serial port to load the new value into the FIFO location.
+       */
+      snd_cs46xx_pokeBA0(chip, BA0_SERBCM, SERBCM_WRC);
+	}
+
+	return 0;
+}
+#endif
+
 /*
  *	Crystal EAPD mode
  */
@@ -2018,7 +2562,8 @@
 	int oval, val;
 	
 	chip->amplifier += change;
-	oval = snd_cs46xx_codec_read(chip, AC97_POWERDOWN);
+	oval = snd_cs46xx_codec_read(chip, AC97_POWERDOWN,
+				     CS46XX_PRIMARY_CODEC_INDEX);
 	val = oval;
 	if (chip->amplifier && !old) {
 		/* Turn the EAPD amp on */
@@ -2028,11 +2573,18 @@
 		val &= ~0x8000;
 	}
 	if (val != oval) {
-		snd_cs46xx_codec_write(chip, AC97_POWERDOWN, val);
+		snd_cs46xx_codec_write(chip, AC97_POWERDOWN, val,
+				       CS46XX_PRIMARY_CODEC_INDEX);
 		if (chip->eapd_switch)
 			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
 				       &chip->eapd_switch->id);
 	}
+
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+    if (chip->amplifier && !old) {
+      voyetra_setup_eapd_slot(chip);
+    }
+#endif
 }
 
 
@@ -2222,7 +2774,7 @@
 	mdelay(5);
 #endif
 
-	snd_ac97_resume(chip->ac97);
+	snd_ac97_resume(chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]);
 
 	if (amp_saved)
 		chip->amplifier_ctrl(chip, 1); /* try to turn on */
@@ -2286,7 +2838,6 @@
 	spin_lock_init(&chip->reg_lock);
 	chip->card = card;
 	chip->pci = pci;
-	chip->play.hw_size = PAGE_SIZE;
 	chip->capt.hw_size = PAGE_SIZE;
 	chip->irq = -1;
 	chip->ba0_addr = pci_resource_start(pci, 0);
@@ -2378,6 +2929,14 @@
 		return -EBUSY;
 	}
 	chip->irq = pci->irq;
+
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	chip->dsp_spos_instance = cs46xx_dsp_spos_create(chip);
+	if (chip->dsp_spos_instance == NULL) {
+		snd_cs46xx_free(chip);
+		return -ENOMEM;
+	}
+#endif
 
 	err = snd_cs46xx_chip_init(chip, 0);
 	if (err < 0) {
diff -Nru a/sound/pci/cs46xx/cs46xx_lib.h b/sound/pci/cs46xx/cs46xx_lib.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/cs46xx/cs46xx_lib.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,191 @@
+/*
+ *  The driver for the Cirrus Logic's Sound Fusion CS46XX based soundcards
+ *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *
+ *
+ *   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
+ *
+ */
+
+#ifndef __CS46XX_LIB_H__
+#define __CS46XX_LIB_H__
+
+#define chip_t cs46xx_t
+
+/*
+ *  constants
+ */
+
+#define CS46XX_BA0_SIZE		0x1000
+#define CS46XX_BA1_DATA0_SIZE	0x3000
+#define CS46XX_BA1_DATA1_SIZE	0x3800
+#define CS46XX_BA1_PRG_SIZE	0x7000
+#define CS46XX_BA1_REG_SIZE	0x0100
+
+
+#define CS46XX_PERIOD_SIZE 2048
+#define CS46XX_FRAGS 2
+#define CS46XX_BUFFER_SIZE CS46XX_PERIOD_SIZE * CS46XX_FRAGS
+
+#define SCB_NO_PARENT             0
+#define SCB_ON_PARENT_NEXT_SCB    1
+#define SCB_ON_PARENT_SUBLIST_SCB 2
+
+/* 3*1024 parameter, 3.5*1024 sample, 2*3.5*1024 code */
+#define BA1_DWORD_SIZE		(13 * 1024 + 512)
+#define BA1_MEMORY_COUNT	3
+
+extern snd_pcm_ops_t snd_cs46xx_playback_ops;
+extern snd_pcm_ops_t snd_cs46xx_playback_indirect_ops;
+extern snd_pcm_ops_t snd_cs46xx_capture_ops;
+extern snd_pcm_ops_t snd_cs46xx_capture_indirect_ops;
+
+
+/*
+ *  common I/O routines
+ */
+
+static inline void snd_cs46xx_poke(cs46xx_t *chip, unsigned long reg, unsigned int val)
+{
+	unsigned int bank = reg >> 16;
+	unsigned int offset = reg & 0xffff;
+
+	/*if (bank == 0) printk("snd_cs46xx_poke: %04X - %08X\n",reg >> 2,val); */
+	writel(val, chip->region.idx[bank+1].remap_addr + offset);
+}
+
+static inline unsigned int snd_cs46xx_peek(cs46xx_t *chip, unsigned long reg)
+{
+	unsigned int bank = reg >> 16;
+	unsigned int offset = reg & 0xffff;
+	return readl(chip->region.idx[bank+1].remap_addr + offset);
+}
+
+static inline void snd_cs46xx_pokeBA0(cs46xx_t *chip, unsigned long offset, unsigned int val)
+{
+	writel(val, chip->region.name.ba0.remap_addr + offset);
+}
+
+static inline unsigned int snd_cs46xx_peekBA0(cs46xx_t *chip, unsigned long offset)
+{
+	return readl(chip->region.name.ba0.remap_addr + offset);
+}
+
+dsp_spos_instance_t *  cs46xx_dsp_spos_create (cs46xx_t * chip);
+void                   cs46xx_dsp_spos_destroy (dsp_spos_instance_t * instance);
+int                    cs46xx_dsp_load_module (cs46xx_t * chip,dsp_module_desc_t * module);
+symbol_entry_t *       cs46xx_dsp_lookup_symbol (cs46xx_t * chip,char * symbol_name,int symbol_type);
+symbol_entry_t *       cs46xx_dsp_lookup_symbol_addr (cs46xx_t * chip,u32 address,int symbol_type);
+int                    cs46xx_dsp_proc_init (snd_card_t * card, cs46xx_t *chip);
+int                    cs46xx_dsp_proc_done (cs46xx_t *chip);
+int                    cs46xx_dsp_scb_and_task_init (cs46xx_t *chip);
+int                    cs46xx_dsp_async_init (cs46xx_t *chip,dsp_scb_descriptor_t * fg_entry);
+int                    snd_cs46xx_download (cs46xx_t *chip,u32 *src,unsigned long offset,
+                                            unsigned long len);
+int                    snd_cs46xx_clear_BA1(cs46xx_t *chip,unsigned long offset,unsigned long len);
+int                    cs46xx_dsp_enable_spdif_out (cs46xx_t *chip);
+int                    cs46xx_dsp_disable_spdif_out (cs46xx_t *chip);
+int                    cs46xx_dsp_enable_spdif_in (cs46xx_t *chip);
+int                    cs46xx_dsp_disable_spdif_in (cs46xx_t *chip);
+int                    cs46xx_poke_via_dsp (cs46xx_t *chip,u32 address,u32 data);
+dsp_scb_descriptor_t * cs46xx_dsp_create_scb (cs46xx_t *chip,char * name, u32 * scb_data,u32 dest);
+void                   cs46xx_dsp_proc_free_scb_desc (dsp_scb_descriptor_t * scb);
+void                   cs46xx_dsp_proc_register_scb_desc (cs46xx_t *chip,dsp_scb_descriptor_t * scb);
+dsp_task_descriptor_t * cs46xx_dsp_create_task_tree (cs46xx_t *chip,char * name, 
+                                                     u32 * task_data,u32 dest,int size);
+dsp_scb_descriptor_t * cs46xx_dsp_create_timing_master_scb (cs46xx_t *chip);
+dsp_scb_descriptor_t * cs46xx_dsp_create_codec_out_scb(cs46xx_t * chip,char * codec_name,
+                                                       u16 channel_disp,u16 fifo_addr,
+                                                       u16 child_scb_addr,
+                                                       u32 dest,
+                                                       dsp_scb_descriptor_t * parent_scb,
+                                                       int scb_child_type);
+dsp_scb_descriptor_t * cs46xx_dsp_create_codec_in_scb(cs46xx_t * chip,char * codec_name,
+                                                      u16 channel_disp,u16 fifo_addr,
+                                                      u16 sample_buffer_addr,
+                                                      u32 dest,
+                                                      dsp_scb_descriptor_t * parent_scb,
+                                                      int scb_child_type);
+void                   cs46xx_dsp_remove_scb (cs46xx_t *chip,dsp_scb_descriptor_t * scb);
+dsp_scb_descriptor_t * cs46xx_dsp_create_generic_scb (cs46xx_t *chip,char * name, 
+                                                      u32 * scb_data,u32 dest,
+                                                      char * task_entry_name,
+                                                      dsp_scb_descriptor_t * parent_scb,
+                                                      int scb_child_type);
+dsp_scb_descriptor_t *  cs46xx_dsp_create_codec_in_scb(cs46xx_t * chip,char * codec_name,
+                                                       u16 channel_disp,u16 fifo_addr,
+                                                       u16 sample_buffer_addr,
+                                                       u32 dest,dsp_scb_descriptor_t * parent_scb,
+                                                       int scb_child_type);
+dsp_scb_descriptor_t * cs46xx_dsp_create_pcm_reader_scb(cs46xx_t * chip,char * scb_name,
+                                                        u16 sample_buffer_addr,u32 dest,
+                                                        int virtual_channel,u32 playback_hw_addr,
+                                                        dsp_scb_descriptor_t * parent_scb,
+                                                        int scb_child_type);
+dsp_scb_descriptor_t *  cs46xx_dsp_create_src_task_scb(cs46xx_t * chip,char * scb_name,
+                                                       u16 src_buffer_addr,
+                                                       u16 src_delay_buffer_addr,u32 dest,
+                                                       dsp_scb_descriptor_t * parent_scb,
+                                                       int scb_child_type);
+dsp_scb_descriptor_t *  cs46xx_dsp_create_mix_only_scb(cs46xx_t * chip,char * scb_name,
+                                                       u16 mix_buffer_addr,u32 dest,
+                                                       dsp_scb_descriptor_t * parent_scb,
+                                                       int scb_child_type);
+
+dsp_scb_descriptor_t *  cs46xx_dsp_create_vari_decimate_scb(cs46xx_t * chip,char * scb_name,
+                                                            u16 vari_buffer_addr0,
+                                                            u16 vari_buffer_addr1,
+                                                            u32 dest,
+                                                            dsp_scb_descriptor_t * parent_scb,
+                                                            int scb_child_type);
+dsp_scb_descriptor_t *  cs46xx_dsp_create_pcm_serial_input_scb(cs46xx_t * chip,char * scb_name,u32 dest,
+                                                               dsp_scb_descriptor_t * input_scb,
+                                                               dsp_scb_descriptor_t * parent_scb,
+                                                               int scb_child_type);
+dsp_scb_descriptor_t * cs46xx_dsp_create_asynch_fg_tx_scb(cs46xx_t * chip,char * scb_name,u32 dest,
+                                                          u16 hfg_scb_address,
+                                                          u16 asynch_buffer_address,
+                                                          dsp_scb_descriptor_t * parent_scb,
+                                                          int scb_child_type);
+dsp_scb_descriptor_t * cs46xx_dsp_create_asynch_fg_rx_scb(cs46xx_t * chip,char * scb_name,u32 dest,
+                                                          u16 hfg_scb_address,
+                                                          u16 asynch_buffer_address,
+                                                          dsp_scb_descriptor_t * parent_scb,
+                                                          int scb_child_type);
+dsp_scb_descriptor_t *  cs46xx_dsp_create_spio_write_scb(cs46xx_t * chip,char * scb_name,u32 dest,
+                                                         dsp_scb_descriptor_t * parent_scb,
+                                                         int scb_child_type);
+dsp_scb_descriptor_t *  cs46xx_dsp_create_mix_to_ostream_scb(cs46xx_t * chip,char * scb_name,
+                                                             u16 mix_buffer_addr,u16 writeback_spb,u32 dest,
+                                                             dsp_scb_descriptor_t * parent_scb,
+                                                             int scb_child_type);
+dsp_scb_descriptor_t *  cs46xx_dsp_create_output_snoop_scb(cs46xx_t * chip,char * scb_name,u32 dest,
+                                                           u16 snoop_buffer_address,
+                                                           dsp_scb_descriptor_t * snoop_scb,
+                                                           dsp_scb_descriptor_t * parent_scb,
+                                                           int scb_child_type);
+dsp_scb_descriptor_t *  cs46xx_dsp_create_magic_snoop_scb(cs46xx_t * chip,char * scb_name,u32 dest,
+                                                          u16 snoop_buffer_address,
+                                                          dsp_scb_descriptor_t * snoop_scb,
+                                                          dsp_scb_descriptor_t * parent_scb,
+                                                          int scb_child_type);
+pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,u32 sample_rate, void * private_data);
+void                       cs46xx_dsp_destroy_pcm_channel (cs46xx_t * chip,
+                                                           pcm_channel_descriptor_t * pcm_channel);
+void                       cs46xx_dsp_set_src_sample_rate(cs46xx_t * chip,dsp_scb_descriptor_t * src, 
+                                                          u32 rate);
+int                        cs46xx_dsp_pcm_unlink (cs46xx_t * chip,pcm_channel_descriptor_t * pcm_channel);
+int                        cs46xx_dsp_pcm_link (cs46xx_t * chip,pcm_channel_descriptor_t * pcm_channel);
+#endif /* __CS46XX_LIB_H__ */
diff -Nru a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/cs46xx/dsp_spos.c	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,1744 @@
+/*
+ *   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
+ *
+ */
+
+/*
+ * 2002-07 Benny Sjostrand benny@hostmobility.com
+ */
+
+
+#define __NO_VERSION__
+#include <sound/driver.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/pm.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/info.h>
+#include <sound/cs46xx.h>
+
+#include "cs46xx_lib.h"
+#include "dsp_spos.h"
+
+#if 0
+/* OBSOLETE NOW */
+
+static void handle_goto (cs46xx_t * chip,u32  * hival,u32 * loval,char * format, u32 overlay_begin_address);
+
+typedef struct _dsp_opcode_desc_t {
+	u32 hival,loval;
+	u32 himask,lomask;
+	void (*handler_func)(cs46xx_t * chip,u32 * hival,u32 * loval,char * format, u32 overlay_begin_address);
+	char * format;
+} dsp_opcode_desc_t;
+
+/* NOTE: theese opcodes are known needed to be reallocated,
+   there may be more. */
+dsp_opcode_desc_t dsp_opcodes[] = {
+	{ 0x01000,0x02730, 0xFF000,0x07FFF,handle_goto,"goto %s" },
+	{ 0x01000,0x00730, 0xFF000,0x07FFF,handle_goto,"goto %s after" },
+	{ 0x01000,0x02630, 0xFF000,0x07FFF,handle_goto,"if (tb) goto %s" },
+	{ 0x01000,0x00630, 0xFF000,0x07FFF,handle_goto,"if (tb) goto %s after" },
+	{ 0x01000,0x00530, 0xFF000,0x07FFF,handle_goto,"if (lt) goto %s after" },
+	{ 0x01000,0x02530, 0xFF000,0x07FFF,handle_goto,"if (lt) goto %s" },
+	{ 0x01000,0x006B0, 0xFF000,0x07FFF,handle_goto,"if (!tb) goto %s after" },
+	{ 0x01000,0x026B0, 0xFF000,0x07FFF,handle_goto,"if (!tb) goto %s" },
+	{ 0x01000,0x00FB0, 0xFF000,0x07FFF,handle_goto,"if (gt) goto %s after" },
+	{ 0x01000,0x02FB0, 0xFF000,0x07FFF,handle_goto,"if (gt) goto %s" },
+	{ 0x01000,0x02734, 0xFF000,0x07FFF,NULL,"goto *ind" },
+	{ 0x01000,0x00734, 0xFF000,0x07FFF,NULL,"goto *ind after" },
+	{ 0x01000,0x02130, 0xFF000,0x07FFF,handle_goto,"if (N) goto %s" },
+	{ 0x01000,0x00130, 0xFF000,0x07FFF,handle_goto,"if (N) goto %s after" },
+	{ 0x01000,0x020F2, 0xFF000,0x07FFF,handle_goto,"tb = Z, if(!Z) goto %s" },
+	{ 0x01000,0x000F2, 0xFF000,0x07FFF,handle_goto,"tb = Z, if(!Z) goto %s after" },
+	{ 0x01000,0x04030, 0xFF000,0x07FFF,handle_goto,"if(Z) goto %s" },
+	{ 0x01000,0x00030, 0xFF000,0x07FFF,handle_goto,"if(Z) goto %s after" },
+	{ 0x01000,0x020B0, 0xFF000,0x07FFF,handle_goto,"if(!Z) goto %s" },
+	{ 0x01000,0x000B0, 0xFF000,0x07FFF,handle_goto,"if(!Z) goto %s after" },
+	{ 0x01000,0x02731, 0xFF000,0x07FFF,handle_goto,"%s();" },
+};
+
+static void handle_goto (cs46xx_t * chip,u32  * hival,u32 * loval,
+			 char * format, u32 overlay_begin_address)
+{
+	u32 address ;
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+
+	address  = (*hival & 0x00FFF) << 5;
+	address |=  *loval >> 15;
+ 
+	snd_printdd("handle_goto[1]: %05x:%05x addr %04x\n",*hival,*loval,address);
+
+	if ( !(address & 0x8000) ) {
+		address += (ins->code.offset / 2) - overlay_begin_address;
+	} else {
+		snd_printdd("handle_goto[1]: ROM symbol not reallocated\n");
+	}
+
+	*hival &= 0xFF000;
+	*loval &= 0x07FFF;
+
+	*hival |= ( (address >> 5)  & 0x00FFF);
+	*loval |= ( (address << 15) & 0xF8000);
+
+	address  = (*hival & 0x00FFF) << 5;
+	address |=  *loval >> 15;
+
+	snd_printdd("handle_goto:[2] %05x:%05x addr %04x\n",*hival,*loval,address);
+}
+#endif /* #if 0 */
+
+static wide_opcode_t wide_opcodes[] = { 
+	WIDE_FOR_BEGIN_LOOP,
+	WIDE_FOR_BEGIN_LOOP2,
+	WIDE_COND_GOTO_ADDR,
+	WIDE_COND_GOTO_CALL,
+	WIDE_TBEQ_COND_GOTO_ADDR,
+	WIDE_TBEQ_COND_CALL_ADDR,
+	WIDE_TBEQ_NCOND_GOTO_ADDR,
+	WIDE_TBEQ_NCOND_CALL_ADDR,
+	WIDE_TBEQ_COND_GOTO1_ADDR,
+	WIDE_TBEQ_COND_CALL1_ADDR,
+	WIDE_TBEQ_NCOND_GOTOI_ADDR,
+	WIDE_TBEQ_NCOND_CALL1_ADDR
+};
+
+static int shadow_and_reallocate_code (cs46xx_t * chip,u32 * data,u32 size, u32 overlay_begin_address)
+{
+	int i = 0,j, nreallocated = 0;
+	u32 hival,loval,address;
+	u32 mop_operands,mop_type,wide_op;
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+
+	snd_assert( ((size % 2) == 0), return -EINVAL);
+  
+	while (i < size) {
+		loval = data[i++];
+		hival = data[i++];
+
+		if (ins->code.offset > 0) {
+#if 0
+			/* OBSOLETE NOW */
+			for (j = 0;j < sizeof(dsp_opcodes) / sizeof(dsp_opcode_desc_t); ++j) {
+				if ( (hival & dsp_opcodes[j].himask) == dsp_opcodes[j].hival &&
+				     (loval & dsp_opcodes[j].lomask) == dsp_opcodes[j].loval &&
+				     dsp_opcodes[j].handler_func != NULL) {
+					dsp_opcodes[j].handler_func (chip,&hival,&loval,dsp_opcodes[j].format, overlay_begin_address);
+					nreallocated ++;
+				}
+			}
+#endif
+
+			mop_operands = (hival >> 6) & 0x03fff;
+			mop_type = mop_operands >> 10;
+      
+			/* check for wide type instruction */
+			if (mop_type == 0 &&
+			    (mop_operands & WIDE_LADD_INSTR_MASK) == 0 &&
+			    (mop_operands & WIDE_INSTR_MASK) != 0) {
+				wide_op = loval & 0x7f;
+				for (j = 0;j < sizeof(wide_opcodes) / sizeof(wide_opcode_t); ++j) {
+					if (wide_opcodes[j] == wide_op) {
+						/* need to reallocate instruction */
+						address  = (hival & 0x00FFF) << 5;
+						address |=  loval >> 15;
+            
+						snd_printdd("handle_wideop[1]: %05x:%05x addr %04x\n",hival,loval,address);
+            
+						if ( !(address & 0x8000) ) {
+							address += (ins->code.offset / 2) - overlay_begin_address;
+						} else {
+							snd_printdd("handle_wideop[1]: ROM symbol not reallocated\n");
+						}
+            
+						hival &= 0xFF000;
+						loval &= 0x07FFF;
+            
+						hival |= ( (address >> 5)  & 0x00FFF);
+						loval |= ( (address << 15) & 0xF8000);
+            
+						address  = (hival & 0x00FFF) << 5;
+						address |=  loval >> 15;
+            
+						snd_printdd("handle_wideop:[2] %05x:%05x addr %04x\n",hival,loval,address);            
+						nreallocated ++;
+					} /* wide_opcodes[j] == wide_op */
+				} /* for */
+			} /* mod_type == 0 ... */
+		} /* ins->code.offset > 0 */
+
+		ins->code.data[ins->code.size++] = loval;
+		ins->code.data[ins->code.size++] = hival;
+	}
+
+	snd_printdd("dsp_spos: %d instructions reallocated\n",nreallocated);
+	return nreallocated;
+}
+
+static segment_desc_t * get_segment_desc (dsp_module_desc_t * module, int seg_type)
+{
+	int i;
+	for (i = 0;i < module->nsegments; ++i) {
+		if (module->segments[i].segment_type == seg_type) {
+			return (module->segments + i);
+		}
+	}
+
+	return NULL;
+};
+
+static int find_free_symbol_index (dsp_spos_instance_t * ins)
+{
+	int index = ins->symbol_table.nsymbols,i;
+
+	for (i = ins->symbol_table.highest_frag_index; i < ins->symbol_table.nsymbols; ++i) {
+		if (ins->symbol_table.symbols[i].deleted) {
+			index = i;
+			break;
+		}
+	}
+
+	return index;
+}
+
+static int add_symbols (cs46xx_t * chip, dsp_module_desc_t * module)
+{
+	int i;
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+
+	if (module->symbol_table.nsymbols > 0) {
+		if (!strcmp(module->symbol_table.symbols[0].symbol_name, "OVERLAYBEGINADDRESS") &&
+		    module->symbol_table.symbols[0].symbol_type == SYMBOL_CONSTANT ) {
+			module->overlay_begin_address = module->symbol_table.symbols[0].address;
+		}
+	}
+
+	for (i = 0;i < module->symbol_table.nsymbols; ++i) {
+		if (ins->symbol_table.nsymbols == (DSP_MAX_SYMBOLS - 1)) {
+			snd_printk(KERN_ERR "dsp_spos: symbol table is full\n");
+			return -ENOMEM;
+		}
+
+
+		if (cs46xx_dsp_lookup_symbol(chip,
+					     module->symbol_table.symbols[i].symbol_name,
+					     module->symbol_table.symbols[i].symbol_type) == NULL) {
+
+			ins->symbol_table.symbols[ins->symbol_table.nsymbols] = module->symbol_table.symbols[i];
+			ins->symbol_table.symbols[ins->symbol_table.nsymbols].address += ((ins->code.offset / 2) - module->overlay_begin_address);
+			ins->symbol_table.symbols[ins->symbol_table.nsymbols].module = module;
+			ins->symbol_table.symbols[ins->symbol_table.nsymbols].deleted = 0;
+
+			if (ins->symbol_table.nsymbols > ins->symbol_table.highest_frag_index) 
+				ins->symbol_table.highest_frag_index = ins->symbol_table.nsymbols;
+
+			ins->symbol_table.nsymbols++;
+		} else {
+			// if (0) printk ("dsp_spos: symbol <%s> duplicated, probably nothing wrong with that (Cirrus?)\n",
+			//                module->symbol_table.symbols[i].symbol_name);
+		}
+	}
+
+	return 0;
+}
+
+static symbol_entry_t * add_symbol (cs46xx_t * chip, char * symbol_name, u32 address, int type)
+{
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+	symbol_entry_t * symbol = NULL;
+	int index;
+
+	if (ins->symbol_table.nsymbols == (DSP_MAX_SYMBOLS - 1)) {
+		snd_printk(KERN_ERR "dsp_spos: symbol table is full\n");
+		return NULL;
+	}
+  
+	if (cs46xx_dsp_lookup_symbol(chip,
+				     symbol_name,
+				     type) != NULL) {
+		snd_printk(KERN_ERR "dsp_spos: symbol <%s> duplicated\n", symbol_name);
+		return NULL;
+	}
+
+	index = find_free_symbol_index (ins);
+
+	strcpy (ins->symbol_table.symbols[index].symbol_name, symbol_name);
+	ins->symbol_table.symbols[index].address = address;
+	ins->symbol_table.symbols[index].symbol_type = type;
+	ins->symbol_table.symbols[index].module = NULL;
+	ins->symbol_table.symbols[index].deleted = 0;
+	symbol = (ins->symbol_table.symbols + index);
+
+	if (index > ins->symbol_table.highest_frag_index) 
+		ins->symbol_table.highest_frag_index = index;
+
+	if (index == ins->symbol_table.nsymbols)
+		ins->symbol_table.nsymbols++; /* no frag. in list */
+
+	return symbol;
+}
+
+dsp_spos_instance_t *  cs46xx_dsp_spos_create (cs46xx_t * chip)
+{
+	dsp_spos_instance_t * ins = kmalloc(sizeof(dsp_spos_instance_t), GFP_KERNEL);
+
+	if (ins == NULL) 
+		return NULL;
+	memset(ins, 0, sizeof(*ins));
+
+	init_MUTEX(&ins->scb_mutex);
+	init_MUTEX(&ins->pcm_mutex);
+
+	/* better to use vmalloc for this big table */
+	ins->symbol_table.nsymbols = 0;
+	ins->symbol_table.symbols = vmalloc(sizeof(symbol_entry_t) * DSP_MAX_SYMBOLS);
+	ins->symbol_table.highest_frag_index = 0;
+
+	if (ins->symbol_table.symbols == NULL) {
+		cs46xx_dsp_spos_destroy(ins);
+		return NULL;
+	}
+
+	ins->code.offset = 0;
+	ins->code.size = 0;
+	ins->code.data = kmalloc(DSP_CODE_BYTE_SIZE, GFP_KERNEL);
+
+	if (ins->code.data == NULL) {
+		cs46xx_dsp_spos_destroy(ins);
+		return NULL;
+	}
+
+	ins->nscb = 0;
+	ins->ntask = 0;
+
+	ins->nmodules = 0;
+	ins->modules = kmalloc(sizeof(dsp_module_desc_t) * DSP_MAX_MODULES, GFP_KERNEL);
+
+	if (ins->modules == NULL) {
+		cs46xx_dsp_spos_destroy(ins);
+		return NULL;
+	}
+
+	return ins;
+}
+
+void  cs46xx_dsp_spos_destroy (dsp_spos_instance_t * ins)
+{
+	int i;
+
+	snd_assert(ins != NULL, return);
+
+	down(&ins->scb_mutex);
+	for (i = 0; i < ins->nscb; ++i) {
+		if (ins->scbs[i].deleted) continue;
+
+		cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) );
+	}
+	up(&ins->scb_mutex);
+
+	if (ins->code.data)
+		kfree(ins->code.data);
+	if (ins->symbol_table.symbols)
+		vfree(ins->symbol_table.symbols);
+	if (ins->modules)
+		kfree(ins->modules);
+	kfree(ins);  
+}
+
+int cs46xx_dsp_load_module (cs46xx_t * chip, dsp_module_desc_t * module)
+{
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+	segment_desc_t * code = get_segment_desc (module,SEGTYPE_SP_PROGRAM);
+	segment_desc_t * parameter = get_segment_desc (module,SEGTYPE_SP_PARAMETER);
+	segment_desc_t * sample = get_segment_desc (module,SEGTYPE_SP_SAMPLE);
+	u32 doffset, dsize;
+
+	if (ins->nmodules == DSP_MAX_MODULES - 1) {
+		snd_printk(KERN_ERR "dsp_spos: to many modules loaded into DSP\n");
+		return -ENOMEM;
+	}
+
+	snd_printdd("dsp_spos: loading module %s into DSP\n", module->module_name);
+  
+	if (ins->nmodules == 0) {
+		snd_printdd("dsp_spos: clearing parameter area\n");
+		snd_cs46xx_clear_BA1(chip, DSP_PARAMETER_BYTE_OFFSET, DSP_PARAMETER_BYTE_SIZE);
+	}
+  
+	if (parameter == NULL) {
+		snd_printdd("dsp_spos: module got no parameter segment\n");
+	} else {
+		if (ins->nmodules > 0) {
+			snd_printk(KERN_WARNING "dsp_spos: WARNING current parameter data may be overwriten!\n");
+		}
+
+		doffset = (parameter->offset * 4 + DSP_PARAMETER_BYTE_OFFSET);
+		dsize   = parameter->size * 4;
+
+		snd_printdd("dsp_spos: downloading parameter data to chip (%08x-%08x)\n",
+			    doffset,doffset + dsize);
+
+		if (snd_cs46xx_download (chip, parameter->data, doffset, dsize)) {
+			snd_printk(KERN_ERR "dsp_spos: failed to download parameter data to DSP\n");
+			return -EINVAL;
+		}
+	}
+
+	if (ins->nmodules == 0) {
+		snd_printdd("dsp_spos: clearing sample area\n");
+		snd_cs46xx_clear_BA1(chip, DSP_SAMPLE_BYTE_OFFSET, DSP_SAMPLE_BYTE_SIZE);
+	}
+
+	if (sample == NULL) {
+		snd_printdd("dsp_spos: module got no sample segment\n");
+	} else {
+		if (ins->nmodules > 0) {
+			snd_printk(KERN_WARNING "dsp_spos: WARNING current sample data may be overwriten\n");
+		}
+
+		doffset = (sample->offset * 4  + DSP_SAMPLE_BYTE_OFFSET);
+		dsize   =  sample->size * 4;
+
+		snd_printdd("dsp_spos: downloading sample data to chip (%08x-%08x)\n",
+			    doffset,doffset + dsize);
+
+		if (snd_cs46xx_download (chip,sample->data,doffset,dsize)) {
+			snd_printk(KERN_ERR "dsp_spos: failed to sample data to DSP\n");
+			return -EINVAL;
+		}
+	}
+
+
+	if (ins->nmodules == 0) {
+		snd_printdd("dsp_spos: clearing code area\n");
+		snd_cs46xx_clear_BA1(chip, DSP_CODE_BYTE_OFFSET, DSP_CODE_BYTE_SIZE);
+	}
+
+	if (code == NULL) {
+		snd_printdd("dsp_spos: module got no code segment\n");
+	} else {
+		if (ins->code.offset + code->size > DSP_CODE_BYTE_SIZE) {
+			snd_printk(KERN_ERR "dsp_spos: no space available in DSP\n");
+			return -ENOMEM;
+		}
+
+		module->load_address = ins->code.offset;
+		module->overlay_begin_address = 0x000;
+
+		/* if module has a code segment it must have
+		   symbol table */
+		snd_assert(module->symbol_table.symbols != NULL ,return -ENOMEM);
+		if (add_symbols(chip,module)) {
+			snd_printk(KERN_ERR "dsp_spos: failed to load symbol table\n");
+			return -ENOMEM;
+		}
+    
+		doffset = (code->offset * 4 + ins->code.offset * 4 + DSP_CODE_BYTE_OFFSET);
+		dsize   = code->size * 4;
+		snd_printdd("dsp_spos: downloading code to chip (%08x-%08x)\n",
+			    doffset,doffset + dsize);   
+
+		module->nfixups = shadow_and_reallocate_code(chip,code->data,code->size,module->overlay_begin_address);
+
+		if (snd_cs46xx_download (chip,(ins->code.data + ins->code.offset),doffset,dsize)) {
+			snd_printk(KERN_ERR "dsp_spos: failed to download code to DSP\n");
+			return -EINVAL;
+		}
+
+		ins->code.offset += code->size;
+	}
+
+	/* NOTE: module segments and symbol table must be
+	   statically allocated. Case that module data is
+	   not generated by the ospparser */
+	ins->modules[ins->nmodules] = *module;
+	ins->nmodules++;
+
+	return 0;
+}
+
+symbol_entry_t * cs46xx_dsp_lookup_symbol (cs46xx_t * chip, char * symbol_name, int symbol_type)
+{
+	int i;
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+
+	for ( i = 0; i < ins->symbol_table.nsymbols; ++i ) {
+
+		if (ins->symbol_table.symbols[i].deleted)
+			continue;
+
+		if (!strcmp(ins->symbol_table.symbols[i].symbol_name,symbol_name) &&
+		    ins->symbol_table.symbols[i].symbol_type == symbol_type) {
+			return (ins->symbol_table.symbols + i);
+		}
+	}
+
+#if 0
+	printk ("dsp_spos: symbol <%s> type %02x not found\n",
+		symbol_name,symbol_type);
+#endif
+
+	return NULL;
+}
+
+
+symbol_entry_t * cs46xx_dsp_lookup_symbol_addr (cs46xx_t * chip, u32 address, int symbol_type)
+{
+	int i;
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+
+	for ( i = 0; i < ins->symbol_table.nsymbols; ++i ) {
+
+		if (ins->symbol_table.symbols[i].deleted)
+			continue;
+
+		if (ins->symbol_table.symbols[i].address == address &&
+		    ins->symbol_table.symbols[i].symbol_type == symbol_type) {
+			return (ins->symbol_table.symbols + i);
+		}
+	}
+
+
+	return NULL;
+}
+
+
+static void cs46xx_dsp_proc_symbol_table_read (snd_info_entry_t *entry, snd_info_buffer_t * buffer)
+{
+	cs46xx_t *chip = snd_magic_cast(cs46xx_t, entry->private_data, return);
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+	int i;
+
+	snd_iprintf(buffer, "SYMBOLS:\n");
+	for ( i = 0; i < ins->symbol_table.nsymbols; ++i ) {
+		char *module_str = "system";
+
+		if (ins->symbol_table.symbols[i].deleted)
+			continue;
+
+		if (ins->symbol_table.symbols[i].module != NULL) {
+			module_str = ins->symbol_table.symbols[i].module->module_name;
+		}
+
+    
+		snd_iprintf(buffer, "%04X <%02X> %s [%s]\n",
+			    ins->symbol_table.symbols[i].address,
+			    ins->symbol_table.symbols[i].symbol_type,
+			    ins->symbol_table.symbols[i].symbol_name,
+			    module_str);    
+	}
+}
+
+
+static void cs46xx_dsp_proc_modules_read (snd_info_entry_t *entry, snd_info_buffer_t * buffer)
+{
+	cs46xx_t *chip = snd_magic_cast(cs46xx_t, entry->private_data, return);
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+	int i,j;
+
+	snd_iprintf(buffer, "MODULES:\n");
+	for ( i = 0; i < ins->nmodules; ++i ) {
+		snd_iprintf(buffer, "\n%s:\n", ins->modules[i].module_name);
+		snd_iprintf(buffer, "   %d symbols\n", ins->modules[i].symbol_table.nsymbols);
+		snd_iprintf(buffer, "   %d fixups\n", ins->modules[i].nfixups);
+
+		for (j = 0; j < ins->modules[i].nsegments; ++ j) {
+			segment_desc_t * desc = (ins->modules[i].segments + j);
+			snd_iprintf(buffer, "   segment %02x offset %08x size %08x\n",
+				    desc->segment_type,desc->offset, desc->size);
+		}
+	}
+}
+
+static void cs46xx_dsp_proc_task_tree_read (snd_info_entry_t *entry, snd_info_buffer_t * buffer)
+{
+	cs46xx_t *chip = snd_magic_cast(cs46xx_t, entry->private_data, return);
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+	int i,j,col;
+	unsigned long dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
+
+	snd_iprintf(buffer, "TASK TREES:\n");
+	for ( i = 0; i < ins->ntask; ++i) {
+		snd_iprintf(buffer,"\n%04x %s:\n",ins->tasks[i].address,ins->tasks[i].task_name);
+
+		for (col = 0,j = 0;j < ins->tasks[i].size; j++,col++) {
+			u32 val;
+			if (col == 4) {
+				snd_iprintf(buffer,"\n");
+				col = 0;
+			}
+			val = readl(dst + (ins->tasks[i].address + j) * sizeof(u32));
+			snd_iprintf(buffer,"%08x ",val);
+		}
+	}
+
+	snd_iprintf(buffer,"\n");  
+}
+
+static void cs46xx_dsp_proc_scb_read (snd_info_entry_t *entry, snd_info_buffer_t * buffer)
+{
+	cs46xx_t *chip = snd_magic_cast(cs46xx_t, entry->private_data, return);
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+	int i;
+
+	snd_iprintf(buffer, "SCB's:\n");
+	for ( i = 0; i < ins->nscb; ++i) {
+		if (ins->scbs[i].deleted)
+			continue;
+		snd_iprintf(buffer,"\n%04x %s:\n\n",ins->scbs[i].address,ins->scbs[i].scb_name);
+
+		if (ins->scbs[i].parent_scb_ptr != NULL) {
+			snd_iprintf(buffer,"parent [%s:%04x] ", 
+				    ins->scbs[i].parent_scb_ptr->scb_name,
+				    ins->scbs[i].parent_scb_ptr->address);
+		} else snd_iprintf(buffer,"parent [none] ");
+
+		snd_iprintf(buffer,"sub_list_ptr [%s:%04x]\nnext_scb_ptr [%s:%04x]  task_entry [%s:%04x]\n",
+			    ins->scbs[i].sub_list_ptr->scb_name,
+			    ins->scbs[i].sub_list_ptr->address,
+			    ins->scbs[i].next_scb_ptr->scb_name,
+			    ins->scbs[i].next_scb_ptr->address,
+			    ins->scbs[i].task_entry->symbol_name,
+			    ins->scbs[i].task_entry->address);
+	}
+
+	snd_iprintf(buffer,"\n");
+}
+
+static void cs46xx_dsp_proc_parameter_dump_read (snd_info_entry_t *entry, snd_info_buffer_t * buffer)
+{
+	cs46xx_t *chip = snd_magic_cast(cs46xx_t, entry->private_data, return);
+	/*dsp_spos_instance_t * ins = chip->dsp_spos_instance; */
+	int i,col = 0;
+	unsigned long dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
+	symbol_entry_t * symbol; 
+
+	for (i = 0;i < DSP_PARAMETER_BYTE_SIZE; i += sizeof(u32),col ++) {
+		if (col == 4) {
+			snd_iprintf(buffer,"\n");
+			col = 0;
+		}
+
+		if ( (symbol = cs46xx_dsp_lookup_symbol_addr (chip,i / sizeof(u32), SYMBOL_PARAMETER)) != NULL) {
+			col = 0;
+			snd_iprintf (buffer,"\n%s:\n",symbol->symbol_name);
+		}
+
+		if (col == 0) {
+			snd_iprintf(buffer, "%04X ",i / sizeof(u32));
+		}
+
+		snd_iprintf(buffer,"%08X ",readl(dst + i));
+	}
+}
+
+static void cs46xx_dsp_proc_sample_dump_read (snd_info_entry_t *entry, snd_info_buffer_t * buffer)
+{
+	cs46xx_t *chip = snd_magic_cast(cs46xx_t, entry->private_data, return);
+	/*dsp_spos_instance_t * ins = chip->dsp_spos_instance; */
+	int i,col = 0;
+	unsigned long dst = chip->region.idx[2].remap_addr;
+
+	snd_iprintf(buffer,"PCMREADER:\n");
+	for (i = PCM_READER_BUF1;i < PCM_READER_BUF1 + 0x30; i += sizeof(u32),col ++) {
+		if (col == 4) {
+			snd_iprintf(buffer,"\n");
+			col = 0;
+		}
+
+		if (col == 0) {
+			snd_iprintf(buffer, "%04X ",i);
+		}
+
+		snd_iprintf(buffer,"%08X ",readl(dst + i));
+	}
+
+	snd_iprintf(buffer,"\nMIX_SAMPLE_BUF1:\n");
+
+	col = 0;
+	for (i = MIX_SAMPLE_BUF1;i < MIX_SAMPLE_BUF1 + 0x30; i += sizeof(u32),col ++) {
+		if (col == 4) {
+			snd_iprintf(buffer,"\n");
+			col = 0;
+		}
+
+		if (col == 0) {
+			snd_iprintf(buffer, "%04X ",i);
+		}
+
+		snd_iprintf(buffer,"%08X ",readl(dst + i));
+	}
+
+	snd_iprintf(buffer,"\n\n");
+	col = 0;
+	for (i = SPDIFO_IP_OUTPUT_BUFFER1 - 0x80;i < SPDIFO_IP_OUTPUT_BUFFER1; i += sizeof(u32),col ++) {
+		if (col == 4) {
+			snd_iprintf(buffer,"\n");
+			col = 0;
+		}
+
+		if (col == 0) {
+			snd_iprintf(buffer, "%04X ",i);
+		}
+
+		snd_iprintf(buffer,"%08X ",readl(dst + i));
+	}
+
+
+	snd_iprintf(buffer,"\nSPDIFO_BUFFER:\n");
+	col = 0;
+	for (i = SPDIFO_IP_OUTPUT_BUFFER1;i < SPDIFO_IP_OUTPUT_BUFFER1 + 0x40; i += sizeof(u32),col ++) {
+		if (col == 4) {
+			snd_iprintf(buffer,"\n");
+			col = 0;
+		}
+
+		if (col == 0) {
+			snd_iprintf(buffer, "%04X ",i);
+		}
+
+		snd_iprintf(buffer,"%08X ",readl(dst + i));
+	}
+
+	snd_iprintf(buffer,"\n...\n");
+	col = 0;
+
+	for (i = SPDIFO_IP_OUTPUT_BUFFER1+0xD0;i < SPDIFO_IP_OUTPUT_BUFFER1 + 0x110; i += sizeof(u32),col ++) {
+		if (col == 4) {
+			snd_iprintf(buffer,"\n");
+			col = 0;
+		}
+
+		if (col == 0) {
+			snd_iprintf(buffer, "%04X ",i);
+		}
+
+		snd_iprintf(buffer,"%08X ",readl(dst + i));
+	}
+
+
+	snd_iprintf(buffer,"\nOUTPUT_SNOOP:\n");
+	col = 0;
+	for (i = OUTPUT_SNOOP_BUFFER;i < OUTPUT_SNOOP_BUFFER + 0x40; i += sizeof(u32),col ++) {
+		if (col == 4) {
+			snd_iprintf(buffer,"\n");
+			col = 0;
+		}
+
+		if (col == 0) {
+			snd_iprintf(buffer, "%04X ",i);
+		}
+
+		snd_iprintf(buffer,"%08X ",readl(dst + i));
+	}
+
+	snd_iprintf(buffer,"\nCODEC_INPUT_BUF1: \n");
+	col = 0;
+	for (i = CODEC_INPUT_BUF1;i < CODEC_INPUT_BUF1 + 0x40; i += sizeof(u32),col ++) {
+		if (col == 4) {
+			snd_iprintf(buffer,"\n");
+			col = 0;
+		}
+
+		if (col == 0) {
+			snd_iprintf(buffer, "%04X ",i);
+		}
+
+		snd_iprintf(buffer,"%08X ",readl(dst + i));
+	}
+
+	snd_iprintf(buffer,"\nWRITE_BACK_BUF1: \n");
+	col = 0;
+	for (i = WRITE_BACK_BUF1;i < WRITE_BACK_BUF1 + 0x40; i += sizeof(u32),col ++) {
+		if (col == 4) {
+			snd_iprintf(buffer,"\n");
+			col = 0;
+		}
+
+		if (col == 0) {
+			snd_iprintf(buffer, "%04X ",i);
+		}
+
+		snd_iprintf(buffer,"%08X ",readl(dst + i));
+	}
+
+	snd_iprintf(buffer,"\n");
+}
+
+int cs46xx_dsp_proc_init (snd_card_t * card, cs46xx_t *chip)
+{
+	snd_info_entry_t *entry;
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+	int i;
+
+	ins->snd_card = card;
+
+	if ((entry = snd_info_create_card_entry(card, "dsp", card->proc_root)) != NULL) {
+		entry->content = SNDRV_INFO_CONTENT_TEXT;
+		entry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
+		entry->c.text.read_size = 512;
+      
+		if (snd_info_register(entry) < 0) {
+			snd_info_free_entry(entry);
+			entry = NULL;
+		}
+	}
+
+	ins->proc_dsp_dir = entry;
+
+	if (!ins->proc_dsp_dir)
+		return -ENOMEM;
+
+	if ((entry = snd_info_create_card_entry(card, "spos_symbols", ins->proc_dsp_dir)) != NULL) {
+		entry->content = SNDRV_INFO_CONTENT_TEXT;
+		entry->private_data = chip;
+		entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
+		entry->c.text.read_size = 512;
+		entry->c.text.read = cs46xx_dsp_proc_symbol_table_read;
+		if (snd_info_register(entry) < 0) {
+			snd_info_free_entry(entry);
+			entry = NULL;
+		}
+	}
+	ins->proc_sym_info_entry = entry;
+    
+	if ((entry = snd_info_create_card_entry(card, "spos_modules", ins->proc_dsp_dir)) != NULL) {
+		entry->content = SNDRV_INFO_CONTENT_TEXT;
+		entry->private_data = chip;
+		entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
+		entry->c.text.read_size = 512;
+		entry->c.text.read = cs46xx_dsp_proc_modules_read;
+		if (snd_info_register(entry) < 0) {
+			snd_info_free_entry(entry);
+			entry = NULL;
+		}
+	}
+	ins->proc_modules_info_entry = entry;
+
+	if ((entry = snd_info_create_card_entry(card, "parameter", ins->proc_dsp_dir)) != NULL) {
+		entry->content = SNDRV_INFO_CONTENT_TEXT;
+		entry->private_data = chip;
+		entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
+		entry->c.text.read_size = 512;
+		entry->c.text.read = cs46xx_dsp_proc_parameter_dump_read;
+		if (snd_info_register(entry) < 0) {
+			snd_info_free_entry(entry);
+			entry = NULL;
+		}
+	}
+	ins->proc_parameter_dump_info_entry = entry;
+
+	if ((entry = snd_info_create_card_entry(card, "sample", ins->proc_dsp_dir)) != NULL) {
+		entry->content = SNDRV_INFO_CONTENT_TEXT;
+		entry->private_data = chip;
+		entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
+		entry->c.text.read_size = 512;
+		entry->c.text.read = cs46xx_dsp_proc_sample_dump_read;
+		if (snd_info_register(entry) < 0) {
+			snd_info_free_entry(entry);
+			entry = NULL;
+		}
+	}
+	ins->proc_sample_dump_info_entry = entry;
+
+	if ((entry = snd_info_create_card_entry(card, "task_tree", ins->proc_dsp_dir)) != NULL) {
+		entry->content = SNDRV_INFO_CONTENT_TEXT;
+		entry->private_data = chip;
+		entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
+		entry->c.text.read_size = 512;
+		entry->c.text.read = cs46xx_dsp_proc_task_tree_read;;
+		if (snd_info_register(entry) < 0) {
+			snd_info_free_entry(entry);
+			entry = NULL;
+		}
+	}
+	ins->proc_task_info_entry = entry;
+
+	if ((entry = snd_info_create_card_entry(card, "scb_info", ins->proc_dsp_dir)) != NULL) {
+		entry->content = SNDRV_INFO_CONTENT_TEXT;
+		entry->private_data = chip;
+		entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
+		entry->c.text.read_size = 1024;
+		entry->c.text.read = cs46xx_dsp_proc_scb_read;;
+		if (snd_info_register(entry) < 0) {
+			snd_info_free_entry(entry);
+			entry = NULL;
+		}
+	}
+	ins->proc_scb_info_entry = entry;
+
+	/* register/update SCB's entries on proc */
+	for (i = 0; i < ins->nscb; ++i) {
+		if (ins->scbs[i].deleted) continue;
+
+		cs46xx_dsp_proc_register_scb_desc (chip, (ins->scbs + i));
+	}
+
+	return 0;
+}
+
+int cs46xx_dsp_proc_done (cs46xx_t *chip)
+{
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+	int i;
+
+	if (ins->proc_sym_info_entry) {
+		snd_info_unregister(ins->proc_sym_info_entry);
+		ins->proc_sym_info_entry = NULL;
+	}
+  
+	if (ins->proc_modules_info_entry) {
+		snd_info_unregister(ins->proc_modules_info_entry);
+		ins->proc_modules_info_entry = NULL;
+	}
+ 
+	if (ins->proc_parameter_dump_info_entry) {
+		snd_info_unregister(ins->proc_parameter_dump_info_entry);
+		ins->proc_parameter_dump_info_entry = NULL;
+	}
+  
+	if (ins->proc_sample_dump_info_entry) {
+		snd_info_unregister(ins->proc_sample_dump_info_entry);
+		ins->proc_sample_dump_info_entry = NULL;
+	}
+  
+	if (ins->proc_scb_info_entry) {
+		snd_info_unregister(ins->proc_scb_info_entry);
+		ins->proc_scb_info_entry = NULL;
+	}
+  
+	if (ins->proc_task_info_entry) {
+		snd_info_unregister(ins->proc_task_info_entry);
+		ins->proc_task_info_entry = NULL;
+	}
+
+	down(&ins->scb_mutex);
+	for (i = 0; i < ins->nscb; ++i) {
+		if (ins->scbs[i].deleted) continue;
+		cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) );
+	}
+	up(&ins->scb_mutex);
+
+	if (ins->proc_dsp_dir) {
+		snd_info_unregister (ins->proc_dsp_dir);
+		ins->proc_dsp_dir = NULL;
+	}
+
+	return 0;
+}
+
+static int debug_tree = 0;
+static void _dsp_create_task_tree (cs46xx_t *chip,u32 * task_data, u32  dest, int size)
+{
+	unsigned long spdst = chip->region.idx[1].remap_addr + 
+		DSP_PARAMETER_BYTE_OFFSET + dest * sizeof(u32);
+	int i;
+
+	for (i = 0; i < size; ++i) {
+		if (debug_tree) printk ("addr %08x, val %08x\n",(int)spdst,task_data[i]);
+		writel(task_data[i],spdst);
+		spdst += sizeof(u32);
+	}
+}
+
+static int debug_scb = 0;
+static void _dsp_create_scb (cs46xx_t *chip,u32 * scb_data, u32  dest)
+{
+	unsigned long spdst = chip->region.idx[1].remap_addr + 
+		DSP_PARAMETER_BYTE_OFFSET + dest * sizeof(u32);
+	int i;
+
+	for (i = 0; i < 0x10; ++i) {
+		if (debug_scb) printk ("addr %08x, val %08x\n",(int)spdst,scb_data[i]);
+		writel(scb_data[i],spdst);
+		spdst += sizeof(u32);
+	}
+}
+
+static int find_free_scb_index (dsp_spos_instance_t * ins)
+{
+	int index = ins->nscb, i;
+
+	for (i = ins->scb_highest_frag_index; i < ins->nscb; ++i) {
+		if (ins->scbs[i].deleted) {
+			index = i;
+			break;
+		}
+	}
+
+	return index;
+}
+
+static dsp_scb_descriptor_t * _map_scb (cs46xx_t *chip,char * name,u32 dest)
+{
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+	dsp_scb_descriptor_t * desc = NULL;
+	int index;
+
+	if (ins->nscb == DSP_MAX_SCB_DESC - 1) {
+		snd_printk(KERN_ERR "dsp_spos: got no place for other SCB\n");
+		return NULL;
+	}
+
+	index = find_free_scb_index (ins);
+
+	strcpy(ins->scbs[index].scb_name, name);
+	ins->scbs[index].address = dest;
+	ins->scbs[index].index = index;
+	ins->scbs[index].proc_info = NULL;
+	ins->scbs[index].ref_count = 1;
+	ins->scbs[index].deleted = 0;
+
+	desc = (ins->scbs + index);
+	ins->scbs[index].scb_symbol = add_symbol (chip, name, dest, SYMBOL_PARAMETER);
+
+	if (index > ins->scb_highest_frag_index)
+		ins->scb_highest_frag_index = index;
+
+	if (index == ins->nscb)
+		ins->nscb++;
+
+	return desc;
+}
+
+static dsp_task_descriptor_t * _map_task_tree (cs46xx_t *chip,char * name,u32 dest,u32 size)
+{
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+	dsp_task_descriptor_t * desc = NULL;
+
+	if (ins->ntask == DSP_MAX_TASK_DESC - 1) {
+		snd_printk(KERN_ERR "dsp_spos: got no place for other TASK\n");
+		return NULL;
+	}
+
+	strcpy(ins->tasks[ins->ntask].task_name,name);
+	ins->tasks[ins->ntask].address = dest;
+	ins->tasks[ins->ntask].size = size;
+
+	/* quick find in list */
+	ins->tasks[ins->ntask].index = ins->ntask;
+	desc = (ins->tasks + ins->ntask);
+	ins->ntask++;
+
+	add_symbol (chip,name,dest,SYMBOL_PARAMETER);
+	return desc;
+}
+
+dsp_scb_descriptor_t * cs46xx_dsp_create_scb (cs46xx_t *chip,char * name, u32 * scb_data,u32 dest)
+{
+	dsp_scb_descriptor_t * desc;
+
+	desc = _map_scb (chip,name,dest);
+	if (desc) {
+		_dsp_create_scb(chip,scb_data,dest);
+	} else {
+		snd_printk(KERN_ERR "dsp_spos: failed to map SCB\n");
+	}
+
+	return desc;
+}
+
+
+dsp_task_descriptor_t *  cs46xx_dsp_create_task_tree (cs46xx_t *chip,char * name, u32 * task_data,u32 dest,int size)
+{
+	dsp_task_descriptor_t * desc;
+
+	desc = _map_task_tree (chip,name,dest,size);
+	if (desc) {
+		_dsp_create_task_tree(chip,task_data,dest,size);
+	} else {
+		snd_printk(KERN_ERR "dsp_spos: failed to map TASK\n");
+	}
+
+	return desc;
+}
+
+
+int cs46xx_dsp_scb_and_task_init (cs46xx_t *chip)
+{
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+	symbol_entry_t * fg_task_tree_header_code;
+	symbol_entry_t * task_tree_header_code;
+	symbol_entry_t * task_tree_thread;
+	symbol_entry_t * null_algorithm;
+	symbol_entry_t * magic_snoop_task;
+
+	dsp_scb_descriptor_t * timing_master_scb;
+	dsp_scb_descriptor_t * codec_out_scb;
+	dsp_scb_descriptor_t * codec_in_scb;
+	dsp_scb_descriptor_t * pcm_reader_scb;
+	dsp_scb_descriptor_t * src_task_scb;
+	dsp_scb_descriptor_t * master_mix_scb;
+	dsp_scb_descriptor_t * write_back_scb;
+	dsp_scb_descriptor_t * vari_decimate_scb;
+	dsp_scb_descriptor_t * pcm_serial_input_task;
+	dsp_scb_descriptor_t * asynch_tx_scb;
+	dsp_scb_descriptor_t * asynch_rx_scb;
+	dsp_scb_descriptor_t * sec_codec_out_scb;
+	dsp_scb_descriptor_t * magic_snoop_scb;
+	dsp_scb_descriptor_t * sec_magic_snoop_scb;
+
+	spos_control_block_t sposcb = {
+		/* 0 */ HFG_TREE_SCB,HFG_STACK,
+		/* 1 */ SPOSCB_ADDR,BG_TREE_SCB_ADDR,
+		/* 2 */ DSP_SPOS_DC,0,
+		/* 3 */ DSP_SPOS_DC,DSP_SPOS_DC,
+		/* 4 */ 0,0,
+		/* 5 */ DSP_SPOS_UU,0,
+		/* 6 */ FG_TASK_HEADER_ADDR,0,
+		/* 7 */ 0,0,
+		/* 8 */ DSP_SPOS_UU,DSP_SPOS_DC,
+		/* 9 */ 0,
+		/* A */ 0,HFG_FIRST_EXECUTE_MODE,
+		/* B */ DSP_SPOS_UU,DSP_SPOS_UU,
+		/* C */ DSP_SPOS_DC_DC,
+		/* D */ DSP_SPOS_DC_DC,
+		/* E */ DSP_SPOS_DC_DC,
+		/* F */ DSP_SPOS_DC_DC
+	};
+
+	cs46xx_dsp_create_task_tree(chip, "sposCB", (u32 *)&sposcb, SPOSCB_ADDR, 0x10);
+
+	null_algorithm  = cs46xx_dsp_lookup_symbol(chip, "NULLALGORITHM", SYMBOL_CODE);
+	if (null_algorithm == NULL) {
+		snd_printk(KERN_ERR "dsp_spos: symbol NULLALGORITHM not found\n");
+		return -EIO;
+	}
+
+	fg_task_tree_header_code = cs46xx_dsp_lookup_symbol(chip, "FGTASKTREEHEADERCODE", SYMBOL_CODE);  
+	if (fg_task_tree_header_code == NULL) {
+		snd_printk(KERN_ERR "dsp_spos: symbol FGTASKTREEHEADERCODE not found\n");
+		return -EIO;
+	}
+
+	task_tree_header_code = cs46xx_dsp_lookup_symbol(chip, "TASKTREEHEADERCODE", SYMBOL_CODE);  
+	if (task_tree_header_code == NULL) {
+		snd_printk(KERN_ERR "dsp_spos: symbol TASKTREEHEADERCODE not found\n");
+		return -EIO;
+	}
+  
+	task_tree_thread = cs46xx_dsp_lookup_symbol(chip, "TASKTREETHREAD", SYMBOL_CODE);
+	if (task_tree_thread == NULL) {
+		snd_printk(KERN_ERR "dsp_spos: symbol TASKTREETHREAD not found\n");
+		return -EIO;
+	}
+
+	magic_snoop_task = cs46xx_dsp_lookup_symbol(chip, "MAGICSNOOPTASK", SYMBOL_CODE);
+	if (magic_snoop_task == NULL) {
+		snd_printk(KERN_ERR "dsp_spos: symbol MAGICSNOOPTASK not found\n");
+		return -EIO;
+	}
+  
+	{
+		/* create the null SCB */
+		generic_scb_t null_scb = {
+			{ 0, 0, 0, 0 },
+			{ 0, 0, 0, 0, 0 },
+			NULL_SCB_ADDR, NULL_SCB_ADDR,
+			null_algorithm->address, 0,
+			0,0,0,
+			{
+				0,0,
+				0,0,
+			}
+		};
+
+		ins->the_null_scb = cs46xx_dsp_create_scb(chip, "nullSCB", (u32 *)&null_scb, NULL_SCB_ADDR);
+		ins->the_null_scb->task_entry = null_algorithm;
+		ins->the_null_scb->sub_list_ptr = ins->the_null_scb;
+		ins->the_null_scb->next_scb_ptr = ins->the_null_scb;
+		ins->the_null_scb->parent_scb_ptr = NULL;
+	}
+
+	{
+		/* setup foreground task tree */
+		task_tree_control_block_t fg_task_tree_hdr =  {
+			{ FG_TASK_HEADER_ADDR | (DSP_SPOS_DC << 0x10),
+			  DSP_SPOS_DC_DC,
+			  DSP_SPOS_DC_DC,
+			  0x0000,DSP_SPOS_DC,
+			  DSP_SPOS_DC, DSP_SPOS_DC,
+			  DSP_SPOS_DC_DC,
+			  DSP_SPOS_DC_DC,
+			  DSP_SPOS_DC_DC,
+			  DSP_SPOS_DC,DSP_SPOS_DC },
+    
+			{
+				BG_TREE_SCB_ADDR,TIMINGMASTER_SCB_ADDR, 
+				fg_task_tree_header_code->address,
+				FG_TASK_HEADER_ADDR + TCBData,                  
+			},
+
+			{    
+				4,0,
+				1,0,
+				2,SPOSCB_ADDR + HFGFlags,
+				0,0,
+				FG_TASK_HEADER_ADDR + TCBContextBlk,FG_STACK
+			},
+
+			{
+				DSP_SPOS_DC,task_tree_thread->address,
+				DSP_SPOS_DC,DSP_SPOS_DC,
+				DSP_SPOS_DC,DSP_SPOS_DC,
+				DSP_SPOS_DC,DSP_SPOS_DC,
+				DSP_SPOS_DC,DSP_SPOS_DC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_UU,1,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC 
+			},                                               
+			{ 
+				FG_INTERVAL_TIMER_PERIOD,DSP_SPOS_UU,
+				0,0
+			}
+		};
+
+		cs46xx_dsp_create_task_tree(chip,"FGtaskTreeHdr",(u32 *)&fg_task_tree_hdr,FG_TASK_HEADER_ADDR,0x35);
+	}
+
+
+	{
+		/* setup foreground task tree */
+		task_tree_control_block_t bg_task_tree_hdr =  {
+			{ DSP_SPOS_DC_DC,
+			  DSP_SPOS_DC_DC,
+			  DSP_SPOS_DC_DC,
+			  DSP_SPOS_DC, DSP_SPOS_DC,
+			  DSP_SPOS_DC, DSP_SPOS_DC,
+			  DSP_SPOS_DC_DC,
+			  DSP_SPOS_DC_DC,
+			  DSP_SPOS_DC_DC,
+			  DSP_SPOS_DC,DSP_SPOS_DC },
+    
+			{
+				NULL_SCB_ADDR,NULL_SCB_ADDR,  /* Set up the background to do nothing */
+				task_tree_header_code->address,
+				BG_TREE_SCB_ADDR + TCBData,
+			},
+
+			{    
+				9999,0,
+				0,1,
+				0,SPOSCB_ADDR + HFGFlags,
+				0,0,
+				BG_TREE_SCB_ADDR + TCBContextBlk,BG_STACK
+			},
+
+			{
+				DSP_SPOS_DC,task_tree_thread->address,
+				DSP_SPOS_DC,DSP_SPOS_DC,
+				DSP_SPOS_DC,DSP_SPOS_DC,
+				DSP_SPOS_DC,DSP_SPOS_DC,
+				DSP_SPOS_DC,DSP_SPOS_DC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_UU,1,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC,
+				DSP_SPOS_DCDC 
+			},                                               
+			{ 
+				BG_INTERVAL_TIMER_PERIOD,DSP_SPOS_UU,
+				0,0
+			}
+		};
+		// debug_tree = 1;
+		cs46xx_dsp_create_task_tree(chip,"BGtaskTreeHdr",(u32 *)&bg_task_tree_hdr,BG_TREE_SCB_ADDR,0x35);
+		// debug_tree = 0;
+    
+	}
+
+	//debug_scb = 1;
+	/* create timing master SCB */
+	timing_master_scb = cs46xx_dsp_create_timing_master_scb(chip);
+
+	/* create the CODEC output task */
+	codec_out_scb = cs46xx_dsp_create_codec_out_scb(chip,"CodecOutSCB_I",0x0010,0x0000,
+							MASTERMIX_SCB_ADDR,
+							CODECOUT_SCB_ADDR,timing_master_scb,
+							SCB_ON_PARENT_SUBLIST_SCB);
+
+	if (!codec_out_scb) goto _fail_end;
+	/* create the master mix SCB */
+	master_mix_scb = cs46xx_dsp_create_mix_only_scb(chip,"MasterMixSCB",
+							MIX_SAMPLE_BUF1,MASTERMIX_SCB_ADDR,
+							codec_out_scb,
+							SCB_ON_PARENT_SUBLIST_SCB);
+	ins->master_mix_scb = master_mix_scb;
+
+	if (!master_mix_scb) goto _fail_end;
+#if 0
+	/* the sample rate converter SCB */
+	src_task_scb = cs46xx_dsp_create_src_task_scb(chip,"SrcTaskSCB_I",
+						      SRC_OUTPUT_BUF1,
+						      SRC_DELAY_BUF1,SRCTASK_SCB_ADDR,
+						      asynch_tx_scb,
+
+						      SCB_ON_PARENT_SUBLIST_SCB);
+	/* create the PCM reader SCB */
+	pcm_reader_scb = cs46xx_dsp_create_pcm_reader_scb(chip,"PCMReaderSCB_I",
+							  PCM_READER_BUF1,PCMREADER_SCB_ADDR,
+							  0, /* playback how hw addr */
+							  src_task_scb,
+							  SCB_ON_PARENT_SUBLIST_SCB);
+#endif
+
+	/* create codec in */
+	codec_in_scb = cs46xx_dsp_create_codec_in_scb(chip,"CodecInSCB",0x0010,0x00A0,
+                                                  CODEC_INPUT_BUF1,
+                                                  CODECIN_SCB_ADDR,codec_out_scb,
+                                                  SCB_ON_PARENT_NEXT_SCB);
+	if (!codec_in_scb) goto _fail_end;
+  
+	/* create write back scb */
+	write_back_scb = cs46xx_dsp_create_mix_to_ostream_scb(chip,"WriteBackSCB",
+							      WRITE_BACK_BUF1,WRITE_BACK_SPB,
+							      WRITEBACK_SCB_ADDR,
+							      timing_master_scb,
+							      SCB_ON_PARENT_NEXT_SCB);
+	if (!write_back_scb) goto _fail_end;
+
+	{
+		mix2_ostream_spb_t mix2_ostream_spb = {
+			0x00020000,
+			0x0000ffff
+		};
+    
+		/* dirty hack ... */
+		_dsp_create_task_tree (chip,(u32 *)&mix2_ostream_spb,WRITE_BACK_SPB,2);
+	}
+
+	/* input sample converter */
+	vari_decimate_scb = cs46xx_dsp_create_vari_decimate_scb(chip,"VariDecimateSCB",
+								VARI_DECIMATE_BUF0,
+								VARI_DECIMATE_BUF1,
+								VARIDECIMATE_SCB_ADDR,
+								write_back_scb,
+								SCB_ON_PARENT_SUBLIST_SCB);
+	if (!vari_decimate_scb) goto _fail_end;
+
+
+	/* pcm input */
+	pcm_serial_input_task = cs46xx_dsp_create_pcm_serial_input_scb(chip,"PCMSerialInput",
+								       PCMSERIALIN_SCB_ADDR,
+								       codec_in_scb, vari_decimate_scb,
+								       SCB_ON_PARENT_SUBLIST_SCB);
+	if (!pcm_serial_input_task) goto _fail_end;
+  
+
+#if 0  /* asynch. receive task */
+	asynch_rx_scb = cs46xx_dsp_create_asynch_fg_rx_scb(chip,"AsynchFGRxSCB",
+							   ASYNCRX_SCB_ADDR,
+							   SPDIFI_SCB_INST,
+							   SPDIFI_IP_OUTPUT_BUFFER1,
+							   master_mix_scb,
+							   SCB_ON_PARENT_NEXT_SCB);
+	if (!asynch_rx_scb) goto _fail_end;
+#endif
+
+
+	/* create secondary CODEC output */
+	sec_codec_out_scb = cs46xx_dsp_create_codec_out_scb(chip,"CodecOutSCB_II",0x0010,0x0040,
+							    OUTPUTSNOOP_SCB_ADDR,
+							    SEC_CODECOUT_SCB_ADDR,codec_in_scb,
+							    SCB_ON_PARENT_NEXT_SCB);
+	if (!sec_codec_out_scb) goto _fail_end;
+
+	/* the magic snooper */
+	magic_snoop_scb = cs46xx_dsp_create_magic_snoop_scb (chip,"MagicSnoopSCB_I",OUTPUTSNOOP_SCB_ADDR,
+							     OUTPUT_SNOOP_BUFFER,
+							     codec_out_scb,
+							     sec_codec_out_scb,
+							     SCB_ON_PARENT_SUBLIST_SCB);
+	if (!magic_snoop_scb) goto _fail_end;
+
+	/* The asynch. transfer task */
+	asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
+							   SPDIFO_SCB_INST,
+							   SPDIFO_IP_OUTPUT_BUFFER1,
+							   magic_snoop_scb,
+							   SCB_ON_PARENT_NEXT_SCB);
+
+	if (!asynch_tx_scb) goto _fail_end;
+
+	/* pcm input */
+	pcm_serial_input_task = cs46xx_dsp_create_pcm_serial_input_scb(chip,"PCMSerialInput_II",
+								       PCMSERIALINII_SCB_ADDR,
+								       magic_snoop_scb,asynch_tx_scb,
+								       SCB_ON_PARENT_SUBLIST_SCB);
+  
+	if (!pcm_serial_input_task) goto _fail_end;
+
+	/* SP IO access */
+	if (!cs46xx_dsp_create_spio_write_scb(chip,"SPIOWriteSCB",SPIOWRITE_SCB_ADDR,
+					      asynch_tx_scb,
+					      SCB_ON_PARENT_NEXT_SCB))
+		goto _fail_end;
+
+
+	/* the magic snooper */
+#if 0
+	sec_magic_snoop_scb = cs46xx_dsp_create_magic_snoop_scb (chip,"MagicSnoopSCB_II",OUTPUTSNOOPII_SCB_ADDR,
+								 MIX_SAMPLE_BUF1,
+								 master_mix_scb,
+								 asynch_tx_scb,
+								 SCB_ON_PARENT_SUBLIST_SCB);
+	if (!sec_magic_scb) goto _fail_end;
+#endif
+
+	//debug_scb = 0;
+	cs46xx_dsp_async_init(chip,timing_master_scb);
+	return 0;
+
+ _fail_end:
+	snd_printk(KERN_ERR "dsp_spos: failed to setup SCB's in DSP\n");
+	return -EINVAL;
+}
+
+int cs46xx_dsp_async_init (cs46xx_t *chip, dsp_scb_descriptor_t * fg_entry)
+{
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+	symbol_entry_t * s16_async_codec_input_task;
+	symbol_entry_t * spdifo_task;
+	symbol_entry_t * spdifi_task;
+	dsp_scb_descriptor_t * spdifi_scb_desc,* spdifo_scb_desc,* async_codec_scb_desc;
+
+	s16_async_codec_input_task = cs46xx_dsp_lookup_symbol(chip, "S16_ASYNCCODECINPUTTASK", SYMBOL_CODE);
+	if (s16_async_codec_input_task == NULL) {
+		snd_printk(KERN_ERR "dsp_spos: symbol S16_ASYNCCODECINPUTTASK not found\n");
+		return -EIO;
+	}
+	spdifo_task = cs46xx_dsp_lookup_symbol(chip, "SPDIFOTASK", SYMBOL_CODE);
+	if (spdifo_task == NULL) {
+		snd_printk(KERN_ERR "dsp_spos: symbol SPDIFOTASK not found\n");
+		return -EIO;
+	}
+
+	spdifi_task = cs46xx_dsp_lookup_symbol(chip, "SPDIFITASK", SYMBOL_CODE);
+	if (spdifi_task == NULL) {
+		snd_printk(KERN_ERR "dsp_spos: symbol SPDIFITASK not found\n");
+		return -EIO;
+	}
+
+	{
+		/* 0xBC0 */
+		spdifoscb_t spdifo_scb = {
+			/* 0 */ DSP_SPOS_UUUU,
+			{
+				/* 1 */ 0xb0, //DSP_SPOS_UUUU,
+				/* 2 */ 0, //DSP_SPOS_UUUU,
+				/* 3 */ 0, //DSP_SPOS_UUUU, 
+				/* 4 */ 0, //DSP_SPOS_UUUU,
+			},
+			/* 5 */ 0x00000085,
+			/* 6 */ ( SPDIFO_IP_OUTPUT_BUFFER1 << 0x10 )  |  0xFFFC,
+			/* 7 */ 0,0, // DSP_SPOS_UU,1, //DSP_SPOS_DC,DSP_SPOS_UU, 
+			/* 8 */ 0, //DSP_SPOS_UUUU,      
+			/* 9 */ FG_TASK_HEADER_ADDR, NULL_SCB_ADDR, 
+			/* A */ spdifo_task->address,
+			SPDIFO_SCB_INST + SPDIFOFIFOPointer,
+			{
+				/* B */ 0x0040, /*DSP_SPOS_UUUU,*/
+				/* C */ 0x20ff, /*DSP_SPOS_UUUU,*/
+			},
+			/* D */ 0x804c,0,							  /* SPDIFOFIFOPointer:SPDIFOStatRegAddr; */
+			/* E */ 0x0108,0x0001,					  /* SPDIFOStMoFormat:SPDIFOFIFOBaseAddr; */
+			/* F */ DSP_SPOS_UUUU	  			          /* SPDIFOFree; */
+		};
+
+		/* 0xBB0 */
+		spdifiscb_t spdifi_scb = {
+			/* 0 */ DSP_SPOS_UULO,DSP_SPOS_UUHI,
+			/* 1 */ 0,
+			/* 2 */ 0,
+			/* 3 */ 1,4000,         
+			/* 4 */ DSP_SPOS_UUUU, 
+			/* 5 */ DSP_SPOS_UULO,DSP_SPOS_UUHI,
+			/* 6 */ DSP_SPOS_UUUU, 
+			/* 7 */ DSP_SPOS_UU,DSP_SPOS_DC, 
+			/* 8 */ DSP_SPOS_UUUU,			
+			/* 9 */ SPDIFO_SCB_INST, NULL_SCB_ADDR,
+			/* A */ spdifi_task->address,
+			SPDIFI_SCB_INST + SPDIFIFIFOPointer,
+              
+			/* B */ 0x00000083,				
+			/* C */ (SPDIFI_IP_OUTPUT_BUFFER1 << 0x10) | 0xFFFC,
+			/* D */ 0x8048,0,
+			/* E */ 0x01f0,0x0001,
+			/* F */ DSP_SPOS_UUUU
+		};
+
+		/* 0xBA0 */
+		async_codec_input_scb_t async_codec_input_scb = {
+			/* 0 */ DSP_SPOS_UUUU,
+			/* 1 */ 0,
+			/* 2 */ 0,
+			/* 3 */ 1,4000,
+			/* 4 */ 0x0118,0x0001,
+			/* 5 */ 0x00000083,
+			/* 6 */ (ASYNC_IP_OUTPUT_BUFFER1 << 0x10) | 0xFFFC,
+			/* 7 */ DSP_SPOS_UU,0x3,
+			/* 8 */ DSP_SPOS_UUUU,
+			/* 9 */ SPDIFI_SCB_INST,NULL_SCB_ADDR,
+			/* A */ s16_async_codec_input_task->address,
+			HFG_TREE_SCB + AsyncCIOFIFOPointer,
+              
+			/* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
+			/* C */ (ASYNC_IP_OUTPUT_BUFFER1 << 0x10),  /*(ASYNC_IP_OUTPUT_BUFFER1 << 0x10) | 0xFFFC,*/
+      
+#ifdef UseASER1Input
+			/* short AsyncCIFIFOPointer:AsyncCIStatRegAddr;	       
+			   Init. 0000:8042: for ASER1
+			   0000:8044: for ASER2 */
+			/* D */ 0x8042,0,
+      
+			/* short AsyncCIStMoFormat:AsyncCIFIFOBaseAddr;
+			   Init 1 stero:8050 ASER1
+			   Init 0  mono:8070 ASER2
+			   Init 1 Stereo : 0100 ASER1 (Set by script) */
+			/* E */ 0x0100,0x0001,
+      
+#endif
+      
+#ifdef UseASER2Input
+			/* short AsyncCIFIFOPointer:AsyncCIStatRegAddr;
+			   Init. 0000:8042: for ASER1
+			   0000:8044: for ASER2 */
+			/* D */ 0x8044,0,
+      
+			/* short AsyncCIStMoFormat:AsyncCIFIFOBaseAddr;
+			   Init 1 stero:8050 ASER1
+			   Init 0  mono:8070 ASER2
+			   Init 1 Stereo : 0100 ASER1 (Set by script) */
+			/* E */ 0x0110,0x0001,
+      
+#endif
+      
+			/* short AsyncCIOutputBufModulo:AsyncCIFree;
+			   AsyncCIOutputBufModulo: The modulo size for   
+			   the output buffer of this task */
+			/* F */ 0, /* DSP_SPOS_UUUU */
+		};
+
+		spdifo_scb_desc = cs46xx_dsp_create_scb(chip,"SPDIFOSCB",(u32 *)&spdifo_scb,SPDIFO_SCB_INST);
+		snd_assert(spdifo_scb_desc, return -EIO);
+		spdifi_scb_desc = cs46xx_dsp_create_scb(chip,"SPDIFISCB",(u32 *)&spdifi_scb,SPDIFI_SCB_INST);
+		snd_assert(spdifi_scb_desc, return -EIO);
+		async_codec_scb_desc = cs46xx_dsp_create_scb(chip,"AsynCodecInputSCB",(u32 *)&async_codec_input_scb, HFG_TREE_SCB);
+		snd_assert(async_codec_scb_desc, return -EIO);
+
+		async_codec_scb_desc->parent_scb_ptr = NULL;
+		async_codec_scb_desc->next_scb_ptr = spdifi_scb_desc;
+		async_codec_scb_desc->sub_list_ptr = ins->the_null_scb;
+		async_codec_scb_desc->task_entry = s16_async_codec_input_task;
+
+		spdifi_scb_desc->parent_scb_ptr = async_codec_scb_desc;
+		spdifi_scb_desc->next_scb_ptr = spdifo_scb_desc;
+		spdifi_scb_desc->sub_list_ptr = ins->the_null_scb;
+		spdifi_scb_desc->task_entry = spdifi_task;
+
+		spdifo_scb_desc->parent_scb_ptr = spdifi_scb_desc;
+		spdifo_scb_desc->next_scb_ptr = fg_entry;
+		spdifo_scb_desc->sub_list_ptr = ins->the_null_scb;
+		spdifo_scb_desc->task_entry = spdifo_task;
+
+		/* this one is faked, as the parnet of SPDIFO task
+		   is the FG task tree */
+		fg_entry->parent_scb_ptr = spdifo_scb_desc;
+
+		/* dirty hack to start forground task ... */
+		//snd_cs46xx_poke(chip,DSP_PARAMETER_BYTE_OFFSET  + 0x070 * sizeof(u32),0x066a0ba0);
+	}
+
+	return 0;
+}
+
+int cs46xx_dsp_enable_spdif_out (cs46xx_t *chip)
+{
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+
+	/* set SPDIF output FIFO slot */
+	snd_cs46xx_pokeBA0(chip, BA0_ASER_FADDR, ( 0x8100 | ((SP_SPDOUT_FIFO >> 4) << 4) ));
+
+	/* Async MASTER ENABLE */
+	snd_cs46xx_pokeBA0(chip, BA0_ASER_MASTER, 0x1 );
+
+#if 0
+	/* reset buffers */
+	snd_cs46xx_poke (chip, (SPDIFO_SCB_INST + 6) << 2,(SPDIFO_IP_OUTPUT_BUFFER1 << 0x10)  |  0xFFFC);
+	snd_cs46xx_poke (chip, (ASYNCTX_SCB_ADDR + 12) << 2, (SPDIFO_IP_OUTPUT_BUFFER1) << 0x10);
+
+	/* insert the foreground asynch tranfer task */
+	snd_cs46xx_poke (chip, (MASTERMIX_SCB_ADDR + 9) << 2, ASYNCTX_SCB_ADDR << 0x10 /*| ASYNCRX_SCB_ADDR*/);
+#endif
+
+	/* SPDIF output MASTER ENABLE */
+	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CONTROL, 0x80000000);
+
+	/* right and left validate bit 
+	   NOTE: 0x80000000 and enables the SCMC protection on stream 
+	*/
+	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, 0x00000000 | (1 << 13) | (1 << 12));
+
+	/* monitor state */
+	ins->spdif_status_out = 1;
+
+	return 0;
+}
+
+int  cs46xx_dsp_disable_spdif_out (cs46xx_t *chip)
+{
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+
+#if 0
+	/* unlink the foreground asynch tranfer task */
+	snd_cs46xx_poke (chip, (MASTERMIX_SCB_ADDR + 9) << 2, SRCTASK_SCB_ADDR << 0x10 /* | ASYNCRX_SCB_ADDR*/);
+#endif
+
+	/* Async MASTER DISABLE */
+	snd_cs46xx_pokeBA0(chip, BA0_ASER_MASTER, 0x0 );
+
+	/* SPDIF output MASTER DISABLE */
+	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CONTROL, 0x0);
+
+	/* monitor state */
+	ins->spdif_status_out = 0;
+
+	return 0;
+}
+
+int cs46xx_dsp_enable_spdif_in (cs46xx_t *chip)
+{
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+
+	/* Async MASTER ENABLE */
+	snd_cs46xx_pokeBA0(chip, BA0_ASER_MASTER, 0x1 );
+
+	/* Time countdown enable */
+	cs46xx_poke_via_dsp (chip,SP_ASER_COUNTDOWN, 0x80000000);
+
+	/* SPDIF input MASTER ENABLE */
+	cs46xx_poke_via_dsp (chip,SP_SPDIN_CONTROL, 0x800003ff);
+
+	/* monitor state */
+	ins->spdif_status_in = 1;
+
+	return 0;
+}
+
+int cs46xx_dsp_disable_spdif_in (cs46xx_t *chip)
+{
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+
+	/* SPDIF input MASTER DISABLE */
+	cs46xx_poke_via_dsp (chip,SP_SPDIN_CONTROL, 0x000003ff);
+
+	/* monitor state */
+	ins->spdif_status_in = 0;
+	return 0;
+}
+
+int  cs46xx_poke_via_dsp (cs46xx_t *chip,u32 address,u32 data)
+{
+	u32 temp;
+	int  i;
+
+	/* santiy check the parameters.  (These numbers are not 100% correct.  They are
+	   a rough guess from looking at the controller spec.) */
+	if (address < 0x8000 || address >= 0x9000)
+		return -EINVAL;
+        
+	/* initialize the SP_IO_WRITE SCB with the data. */
+	temp = ( address << 16 ) | ( address & 0x0000FFFF);   /* offset 0 <-- address2 : address1 */
+
+	snd_cs46xx_poke(chip,( SPIOWRITE_SCB_ADDR      << 2), temp);
+	snd_cs46xx_poke(chip,((SPIOWRITE_SCB_ADDR + 1) << 2), data); /* offset 1 <-- data1 */
+	snd_cs46xx_poke(chip,((SPIOWRITE_SCB_ADDR + 2) << 2), data); /* offset 1 <-- data2*/
+    
+	/* Poke this location to tell the task to start */
+	snd_cs46xx_poke(chip,((SPIOWRITE_SCB_ADDR + 6) << 2), SPIOWRITE_SCB_ADDR << 0x10);
+
+	/* Verify that the task ran */
+	for (i=0; i<25; i++) {
+		udelay(125);
+
+		temp =  snd_cs46xx_peek(chip,((SPIOWRITE_SCB_ADDR + 6) << 2));
+		if (temp == 0x00000000)
+			break;
+	}
+
+	if (i == 25) {
+		snd_printk(KERN_ERR "dsp_spos: SPIOWriteTask not responding\n");
+		return -EBUSY;
+	}
+
+	return 0;
+}
diff -Nru a/sound/pci/cs46xx/dsp_spos.h b/sound/pci/cs46xx/dsp_spos.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/cs46xx/dsp_spos.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,150 @@
+/*
+ *  The driver for the Cirrus Logic's Sound Fusion CS46XX based soundcards
+ *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *
+ *
+ *   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
+ *
+ */
+
+/*
+ * 2002-07 Benny Sjostrand benny@hostmobility.com
+ */
+
+#define DSP_MAX_SYMBOLS 1024
+#define DSP_MAX_MODULES 64
+
+#define DSP_CODE_BYTE_SIZE             0x00007000UL
+#define DSP_PARAMETER_BYTE_SIZE        0x00003000UL
+#define DSP_SAMPLE_BYTE_SIZE           0x00003800UL
+#define DSP_PARAMETER_BYTE_OFFSET      0x00000000UL
+#define DSP_SAMPLE_BYTE_OFFSET         0x00010000UL
+#define DSP_CODE_BYTE_OFFSET           0x00020000UL
+
+#define WIDE_INSTR_MASK       0x0040
+#define WIDE_LADD_INSTR_MASK  0x0380
+
+/* this instruction types
+   needs to be reallocated when load
+   code into DSP */
+typedef enum  {
+  WIDE_FOR_BEGIN_LOOP = 0x20,
+  WIDE_FOR_BEGIN_LOOP2,
+
+  WIDE_COND_GOTO_ADDR = 0x30,
+  WIDE_COND_GOTO_CALL,
+
+  WIDE_TBEQ_COND_GOTO_ADDR = 0x70,
+  WIDE_TBEQ_COND_CALL_ADDR,
+  WIDE_TBEQ_NCOND_GOTO_ADDR,
+  WIDE_TBEQ_NCOND_CALL_ADDR,
+  WIDE_TBEQ_COND_GOTO1_ADDR,
+  WIDE_TBEQ_COND_CALL1_ADDR,
+  WIDE_TBEQ_NCOND_GOTOI_ADDR,
+  WIDE_TBEQ_NCOND_CALL1_ADDR,
+} wide_opcode_t;
+
+/* SAMPLE segment */
+#define VARI_DECIMATE_BUF1       0x0000
+#define WRITE_BACK_BUF1          0x0400
+#define CODEC_INPUT_BUF1         0x0500
+#define PCM_READER_BUF1          0x0600
+#define SRC_DELAY_BUF1           0x0680
+#define VARI_DECIMATE_BUF0       0x0780
+#define SRC_OUTPUT_BUF1          0x07A0
+#define ASYNC_IP_OUTPUT_BUFFER1  0x0A00
+#define OUTPUT_SNOOP_BUFFER      0x0B00
+#define SPDIFI_IP_OUTPUT_BUFFER1 0x0E00
+#define SPDIFO_IP_OUTPUT_BUFFER1 0x1000
+#define MIX_SAMPLE_BUF1          0x1400
+
+// #define SRC_OUTPUT_BUF2          0x1280
+// #define SRC_DELAY_BUF2           0x1288
+
+/* Task stack address */
+#define HFG_STACK                0x066A
+#define FG_STACK                 0x066E
+#define BG_STACK                 0x068E
+
+/* SCB's addresses */
+#define SPOSCB_ADDR              0x070
+#define BG_TREE_SCB_ADDR         0x635
+#define NULL_SCB_ADDR            0x000
+#define TIMINGMASTER_SCB_ADDR    0x010
+#define CODECOUT_SCB_ADDR        0x020
+#define PCMREADER_SCB_ADDR       0x030
+#define WRITEBACK_SCB_ADDR       0x040
+#define CODECIN_SCB_ADDR         0x080
+#define MASTERMIX_SCB_ADDR       0x090
+#define SRCTASK_SCB_ADDR         0x0A0
+#define VARIDECIMATE_SCB_ADDR    0x0B0
+#define PCMSERIALIN_SCB_ADDR     0x0C0
+#define FG_TASK_HEADER_ADDR      0x600
+#define ASYNCTX_SCB_ADDR         0x0E0
+#define ASYNCRX_SCB_ADDR         0x0F0
+#define SRCTASKII_SCB_ADDR       0x100
+#define OUTPUTSNOOP_SCB_ADDR     0x110
+#define PCMSERIALINII_SCB_ADDR   0x120
+#define SPIOWRITE_SCB_ADDR       0x130
+#define SEC_CODECOUT_SCB_ADDR    0x140
+#define OUTPUTSNOOPII_SCB_ADDR   0x150
+
+/* hyperforground SCB's*/
+#define HFG_TREE_SCB             0xBA0
+#define SPDIFI_SCB_INST          0xBB0
+#define SPDIFO_SCB_INST          0xBC0
+#define WRITE_BACK_SPB           0x0D0
+
+/* offsets */
+#define AsyncCIOFIFOPointer  0xd
+#define SPDIFOFIFOPointer    0xd
+#define SPDIFIFIFOPointer    0xd
+#define TCBData              0xb
+#define HFGFlags             0xa
+#define TCBContextBlk        0x10
+#define AFGTxAccumPhi        0x4
+#define SCBsubListPtr        0x9
+#define SCBfuncEntryPtr      0xA
+#define SRCCorPerGof         0x2
+#define SRCPhiIncr6Int26Frac 0xd
+
+/* conf */
+#define UseASER1Input 1
+
+/* constants */
+#define FG_INTERVAL_TIMER_PERIOD                0x0051
+#define BG_INTERVAL_TIMER_PERIOD                0x0100
+#define RSCONFIG_MODULO_32                      0x00000002
+#define RSCONFIG_MODULO_64                      0x00000003
+#define RSCONFIG_MODULO_256                     0x00000005
+#define RSCONFIG_MODULO_8                       0x00000009
+#define RSCONFIG_SAMPLE_16STEREO                0x000000C0
+#define RSCONFIG_SAMPLE_16MONO                  0x00000080
+#define RSCONFIG_DMA_TO_HOST                    0x00008000
+#define RSCONFIG_DMA_ENABLE                     0x20000000
+#define RSCONFIG_STREAM_NUM_SHIFT               16
+#define RSCONFIG_MAX_DMA_SIZE_SHIFT             24
+
+/* Only SP accesible registers */
+#define SP_ASER_COUNTDOWN 0x8040
+#define SP_SPDOUT_FIFO    0x0108
+#define SP_SPDIN_MI_FIFO  0x01E0
+#define SP_SPDIN_D_FIFO   0x01F0
+#define SP_SPDIN_STATUS   0x8048
+#define SP_SPDIN_CONTROL  0x8049
+#define SP_SPDIN_FIFOPTR  0x804A
+#define SP_SPDOUT_STATUS  0x804C
+#define SP_SPDOUT_CONTROL 0x804D
+#define SP_SPDOUT_CSUV    0x808E
diff -Nru a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,1383 @@
+/*
+ *
+ *   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
+ *
+ */
+
+/*
+ * 2002-07 Benny Sjostrand benny@hostmobility.com
+ */
+
+
+#define __NO_VERSION__
+#include <sound/driver.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/pm.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/info.h>
+#include <sound/cs46xx.h>
+
+#include "cs46xx_lib.h"
+#include "dsp_spos.h"
+
+typedef struct _proc_scb_info_t {
+	dsp_scb_descriptor_t * scb_desc;
+	cs46xx_t *chip;
+} proc_scb_info_t;
+
+static void remove_symbol (cs46xx_t * chip,symbol_entry_t * symbol)
+{
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+	int symbol_index = (int)(symbol - ins->symbol_table.symbols);
+
+	snd_assert(ins->symbol_table.nsymbols > 0,return);
+	snd_assert(symbol_index >= 0 && symbol_index < ins->symbol_table.nsymbols, return);
+
+	ins->symbol_table.symbols[symbol_index].deleted = 1;
+
+	if (symbol_index < ins->symbol_table.highest_frag_index) {
+		ins->symbol_table.highest_frag_index = symbol_index;
+	}
+  
+	if (symbol_index == ins->symbol_table.nsymbols - 1)
+		ins->symbol_table.nsymbols --;
+
+	if (ins->symbol_table.highest_frag_index > ins->symbol_table.nsymbols) {
+		ins->symbol_table.highest_frag_index = ins->symbol_table.nsymbols;
+	}
+
+}
+
+static void cs46xx_dsp_proc_scb_info_read (snd_info_entry_t *entry, snd_info_buffer_t * buffer)
+{
+	proc_scb_info_t * scb_info  = (proc_scb_info_t *)entry->private_data;
+	dsp_scb_descriptor_t * scb = scb_info->scb_desc;
+	dsp_spos_instance_t * ins;
+	cs46xx_t *chip = snd_magic_cast(cs46xx_t, scb_info->chip, return);
+	int j,col;
+	unsigned long dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
+
+	ins = chip->dsp_spos_instance;
+
+	down(&ins->scb_mutex);
+	snd_iprintf(buffer,"%04x %s:\n",scb->address,scb->scb_name);
+
+	for (col = 0,j = 0;j < 0x10; j++,col++) {
+		if (col == 4) {
+			snd_iprintf(buffer,"\n");
+			col = 0;
+		}
+		snd_iprintf(buffer,"%08x ",readl(dst + (scb->address + j) * sizeof(u32)));
+	}
+  
+	snd_iprintf(buffer,"\n");
+
+	if (scb->parent_scb_ptr != NULL) {
+		snd_iprintf(buffer,"parent [%s:%04x] ", 
+			    scb->parent_scb_ptr->scb_name,
+			    scb->parent_scb_ptr->address);
+	} else snd_iprintf(buffer,"parent [none] ");
+  
+	snd_iprintf(buffer,"sub_list_ptr [%s:%04x]\nnext_scb_ptr [%s:%04x]  task_entry [%s:%04x]\n",
+		    scb->sub_list_ptr->scb_name,
+		    scb->sub_list_ptr->address,
+		    scb->next_scb_ptr->scb_name,
+		    scb->next_scb_ptr->address,
+		    scb->task_entry->symbol_name,
+		    scb->task_entry->address);
+
+	snd_iprintf(buffer,"index [%d] ref_count [%d]\n",scb->index,scb->ref_count);  
+	up(&ins->scb_mutex);
+}
+
+static void _dsp_unlink_scb (cs46xx_t *chip,dsp_scb_descriptor_t * scb)
+{
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+	unsigned long flags;
+
+	if ( scb->parent_scb_ptr ) {
+		/* unlink parent SCB */
+		snd_assert ((scb->parent_scb_ptr->sub_list_ptr == scb ||
+			     scb->parent_scb_ptr->next_scb_ptr == scb),return);
+  
+		if (scb->parent_scb_ptr->sub_list_ptr == scb) {
+
+			if (scb->next_scb_ptr == ins->the_null_scb) {
+				/* last and only node in parent sublist */
+				scb->parent_scb_ptr->sub_list_ptr = scb->sub_list_ptr;
+
+				if (scb->sub_list_ptr != ins->the_null_scb) {
+					scb->sub_list_ptr->parent_scb_ptr = scb->parent_scb_ptr;
+				}
+				scb->sub_list_ptr = ins->the_null_scb;
+			} else {
+				/* first node in parent sublist */
+				scb->parent_scb_ptr->sub_list_ptr = scb->next_scb_ptr;
+
+				if (scb->next_scb_ptr != ins->the_null_scb) {
+					/* update next node parent ptr. */
+					scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
+				}
+				scb->next_scb_ptr = ins->the_null_scb;
+			}
+		} else {
+			snd_assert ( (scb->sub_list_ptr == ins->the_null_scb), return);
+			scb->parent_scb_ptr->next_scb_ptr = scb->next_scb_ptr;
+
+			if (scb->next_scb_ptr != ins->the_null_scb) {
+				/* update next node parent ptr. */
+				scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
+			}
+			scb->next_scb_ptr = ins->the_null_scb;
+		}
+
+		spin_lock_irqsave(&chip->reg_lock, flags);    
+		/* update entry in DSP RAM */
+		snd_cs46xx_poke(chip,
+				(scb->address + SCBsubListPtr) << 2,
+				(scb->sub_list_ptr->address << 0x10) |
+				(scb->next_scb_ptr->address));
+		/* update parent entry in DSP RAM */
+		snd_cs46xx_poke(chip,
+				(scb->parent_scb_ptr->address + SCBsubListPtr) << 2,
+				(scb->parent_scb_ptr->sub_list_ptr->address << 0x10) |
+				(scb->parent_scb_ptr->next_scb_ptr->address));
+    
+		scb->parent_scb_ptr = NULL;
+		spin_unlock_irqrestore(&chip->reg_lock, flags);
+	}
+}
+
+void cs46xx_dsp_remove_scb (cs46xx_t *chip, dsp_scb_descriptor_t * scb)
+{
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+
+	down(&ins->scb_mutex);
+	/* check integrety */
+	snd_assert ( (scb->index >= 0 && 
+		      scb->index < ins->nscb && 
+		      (ins->scbs + scb->index) == scb), goto _end );
+
+#if 0
+	/* cant remove a SCB with childs before 
+	   removing childs first  */
+	snd_assert ( (scb->sub_list_ptr == ins->the_null_scb &&
+		      scb->next_scb_ptr == ins->the_null_scb),
+		     goto _end);
+#endif
+
+	_dsp_unlink_scb (chip,scb);
+  
+	cs46xx_dsp_proc_free_scb_desc(scb);
+	snd_assert (scb->scb_symbol != NULL, goto _end);
+	remove_symbol (chip,scb->scb_symbol);
+
+	ins->scbs[scb->index].deleted = 1;
+
+	if (scb->index < ins->scb_highest_frag_index)
+		ins->scb_highest_frag_index = scb->index;
+
+	if (scb->index == ins->nscb - 1) {
+		ins->nscb --;
+	}
+
+	if (ins->scb_highest_frag_index > ins->nscb) {
+		ins->scb_highest_frag_index = ins->nscb;
+	}
+
+#if 0
+	/* !!!! THIS IS A PIECE OF SHIT MADE BY ME !!! */
+	for(i = scb->index + 1;i < ins->nscb; ++i) {
+		ins->scbs[i - 1].index = i - 1;
+	}
+#endif
+
+#ifdef CONFIG_SND_DEBUG
+ _end:
+#endif
+	up(&ins->scb_mutex);
+}
+
+
+void cs46xx_dsp_proc_free_scb_desc (dsp_scb_descriptor_t * scb)
+{
+	if (scb->proc_info) {
+		proc_scb_info_t * scb_info  = (proc_scb_info_t *)scb->proc_info->private_data;
+
+		snd_printdd("cs46xx_dsp_proc_free_scb_desc: freeing %s\n",scb->scb_name);
+
+		snd_info_unregister(scb->proc_info);
+		scb->proc_info = NULL;
+
+		snd_assert (scb_info != NULL, return);
+		kfree (scb_info);
+	}
+}
+
+void cs46xx_dsp_proc_register_scb_desc (cs46xx_t *chip,dsp_scb_descriptor_t * scb)
+{
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+	snd_info_entry_t * entry;
+	proc_scb_info_t * scb_info;
+
+	down(&ins->scb_mutex);
+	/* register to proc */
+	if (ins->snd_card != NULL && ins->proc_dsp_dir != NULL &&
+	    scb->proc_info == NULL) {
+  
+		if ((entry = snd_info_create_card_entry(ins->snd_card, scb->scb_name, 
+							ins->proc_dsp_dir)) != NULL) {
+			scb_info = kmalloc(sizeof(proc_scb_info_t), GFP_KERNEL);
+			scb_info->chip = chip;
+			scb_info->scb_desc = scb;
+      
+			entry->content = SNDRV_INFO_CONTENT_TEXT;
+			entry->private_data = scb_info;
+			entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
+      
+			entry->c.text.read_size = 512;
+			entry->c.text.read = cs46xx_dsp_proc_scb_info_read;
+      
+			if (snd_info_register(entry) < 0) {
+				snd_info_free_entry(entry);
+				kfree (scb_info);
+				entry = NULL;
+			}
+		}
+
+		scb->proc_info = entry;
+	}
+	up(&ins->scb_mutex);
+}
+
+static dsp_scb_descriptor_t * 
+_dsp_create_generic_scb (cs46xx_t *chip,char * name, u32 * scb_data,u32 dest,
+                         symbol_entry_t * task_entry,
+                         dsp_scb_descriptor_t * parent_scb,
+                         int scb_child_type)
+{
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+	dsp_scb_descriptor_t * scb;
+  
+	unsigned long flags;
+
+	down(&ins->scb_mutex);
+	snd_assert (ins->the_null_scb != NULL,goto _fail_end);
+
+	/* fill the data that will be wroten to DSP */
+	scb_data[SCBsubListPtr] = 
+		(ins->the_null_scb->address << 0x10) | ins->the_null_scb->address;
+
+	scb_data[SCBfuncEntryPtr] &= 0xFFFF0000;
+	scb_data[SCBfuncEntryPtr] |= task_entry->address;
+
+	snd_printdd("dsp_spos: creating SCB <%s>\n",name);
+
+	scb = cs46xx_dsp_create_scb(chip,name,scb_data,dest);
+
+
+	scb->sub_list_ptr = ins->the_null_scb;
+	scb->next_scb_ptr = ins->the_null_scb;
+
+	scb->parent_scb_ptr = parent_scb;
+	scb->task_entry = task_entry;
+
+  
+	/* update parent SCB */
+	if (scb->parent_scb_ptr) {
+#if 0
+		printk ("scb->parent_scb_ptr = %s\n",scb->parent_scb_ptr->scb_name);
+		printk ("scb->parent_scb_ptr->next_scb_ptr = %s\n",scb->parent_scb_ptr->next_scb_ptr->scb_name);
+		printk ("scb->parent_scb_ptr->sub_list_ptr = %s\n",scb->parent_scb_ptr->sub_list_ptr->scb_name);
+#endif
+		/* link to  parent SCB */
+		if (scb_child_type == SCB_ON_PARENT_NEXT_SCB) {
+			snd_assert ( (scb->parent_scb_ptr->next_scb_ptr == ins->the_null_scb),
+				     goto _fail_end);
+
+			scb->parent_scb_ptr->next_scb_ptr = scb;
+
+		} else if (scb_child_type == SCB_ON_PARENT_SUBLIST_SCB) {
+			snd_assert ( (scb->parent_scb_ptr->sub_list_ptr == ins->the_null_scb),
+				     goto _fail_end);
+
+			scb->parent_scb_ptr->sub_list_ptr = scb;
+		} else {
+			snd_assert (0,goto _fail_end);
+		}
+
+		spin_lock_irqsave(&chip->reg_lock, flags);
+		/* update entry in DSP RAM */
+		snd_cs46xx_poke(chip,
+				(scb->parent_scb_ptr->address + SCBsubListPtr) << 2,
+				(scb->parent_scb_ptr->sub_list_ptr->address << 0x10) |
+				(scb->parent_scb_ptr->next_scb_ptr->address));
+
+		spin_unlock_irqrestore(&chip->reg_lock, flags);
+	}
+
+
+	up(&ins->scb_mutex);
+
+	cs46xx_dsp_proc_register_scb_desc (chip,scb);
+
+	return scb;
+#ifdef CONFIG_SND_DEBUG
+ _fail_end:
+
+	up(&ins->scb_mutex);
+	return NULL;
+#endif
+}
+
+dsp_scb_descriptor_t * 
+cs46xx_dsp_create_generic_scb (cs46xx_t *chip,char * name, u32 * scb_data,u32 dest,
+                               char * task_entry_name,
+                               dsp_scb_descriptor_t * parent_scb,
+                               int scb_child_type)
+{
+	symbol_entry_t * task_entry;
+
+	task_entry = cs46xx_dsp_lookup_symbol (chip,task_entry_name,
+					       SYMBOL_CODE);
+  
+	if (task_entry == NULL) {
+		snd_printk (KERN_ERR "dsp_spos: symbol %s not found\n",task_entry_name);
+		return NULL;
+	}
+  
+	return _dsp_create_generic_scb (chip,name,scb_data,dest,task_entry,
+					parent_scb,scb_child_type);
+}
+
+dsp_scb_descriptor_t * 
+cs46xx_dsp_create_timing_master_scb (cs46xx_t *chip)
+{
+	dsp_scb_descriptor_t * scb;
+  
+	timing_master_scb_t timing_master_scb = {
+		{ 0,
+		  0,
+		  0,
+		  0
+		},
+		{ 0,
+		  0,
+		  0,
+		  0,
+		  0
+		},
+		0,0,
+		0,NULL_SCB_ADDR,
+		0,0,             /* extraSampleAccum:TMreserved */
+		0,0,             /* codecFIFOptr:codecFIFOsyncd */
+		0x0001,0x8000,   /* fracSampAccumQm1:TMfrmsLeftInGroup */
+		0x0001,0x0000,   /* fracSampCorrectionQm1:TMfrmGroupLength */
+		0x00060000       /* nSampPerFrmQ15 */
+	};    
+  
+	scb = cs46xx_dsp_create_generic_scb(chip,"TimingMasterSCBInst",(u32 *)&timing_master_scb,
+					    TIMINGMASTER_SCB_ADDR,
+					    "TIMINGMASTER",NULL,SCB_NO_PARENT);
+
+	return scb;
+}
+
+
+dsp_scb_descriptor_t * 
+cs46xx_dsp_create_codec_out_scb(cs46xx_t * chip,char * codec_name,
+                                u16 channel_disp,u16 fifo_addr,
+                                u16 child_scb_addr,
+                                u32 dest,dsp_scb_descriptor_t * parent_scb,
+                                int scb_child_type)
+{
+	dsp_scb_descriptor_t * scb;
+  
+	codec_output_scb_t codec_out_scb = {
+		{ 0,
+		  0,
+		  0,
+		  0
+		},
+		{
+			0,
+			0,
+			0,
+			0,
+			0
+		},
+		0,0,
+		0,NULL_SCB_ADDR,
+		0,                      /* COstrmRsConfig */
+		0,                      /* COstrmBufPtr */
+		channel_disp,fifo_addr, /* leftChanBaseIOaddr:rightChanIOdisp */
+		0x0000,0x0080,          /* (!AC97!) COexpVolChangeRate:COscaleShiftCount */
+		0,child_scb_addr        /* COreserved - need child scb to work with rom code */
+	};
+  
+  
+	scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_out_scb,
+					    dest,"S16_CODECOUTPUTTASK",parent_scb,
+					    scb_child_type);
+  
+	return scb;
+}
+
+dsp_scb_descriptor_t * 
+cs46xx_dsp_create_codec_in_scb(cs46xx_t * chip,char * codec_name,
+                                u16 channel_disp,u16 fifo_addr,
+                                u16 sample_buffer_addr,
+                                u32 dest,dsp_scb_descriptor_t * parent_scb,
+                                int scb_child_type)
+{
+
+	dsp_scb_descriptor_t * scb;
+	codec_input_scb_t codec_input_scb = {
+		{ 0,
+		  0,
+		  0,
+		  0
+		},
+		{
+			0,
+			0,
+			0,
+			0,
+			0
+		},
+    
+#if 0  /* cs4620 */
+		SyncIOSCB,NULL_SCB_ADDR
+#else
+		0 , 0,
+#endif
+		0,0,
+
+		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,  /* strmRsConfig */
+		sample_buffer_addr << 0x10,       /* strmBufPtr; defined as a dword ptr, used as a byte ptr */
+		channel_disp,fifo_addr,           /* (!AC97!) leftChanBaseINaddr=AC97primary 
+						     link input slot 3 :rightChanINdisp=""slot 4 */
+		0x0000,0x0000,                    /* (!AC97!) ????:scaleShiftCount; no shift needed 
+						     because AC97 is already 20 bits */
+		0x80008000                        /* ??clw cwcgame.scb has 0 */
+	};
+  
+	scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_input_scb,
+					    dest,"S16_CODECINPUTTASK",parent_scb,
+					    scb_child_type);
+	return scb;
+}
+
+
+dsp_scb_descriptor_t * 
+cs46xx_dsp_create_pcm_reader_scb(cs46xx_t * chip,char * scb_name,
+                                 u16 sample_buffer_addr,u32 dest,
+                                 int virtual_channel, u32 playback_hw_addr,
+                                 dsp_scb_descriptor_t * parent_scb,
+                                 int scb_child_type)
+{
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+	dsp_scb_descriptor_t * scb;
+  
+	generic_scb_t pcm_reader_scb = {
+    
+		/*
+		  Play DMA Task xfers data from host buffer to SP buffer
+		  init/runtime variables:
+		  PlayAC: Play Audio Data Conversion - SCB loc: 2nd dword, mask: 0x0000F000L
+		  DATA_FMT_16BIT_ST_LTLEND(0x00000000L)   from 16-bit stereo, little-endian
+		  DATA_FMT_8_BIT_ST_SIGNED(0x00001000L)   from 8-bit stereo, signed
+		  DATA_FMT_16BIT_MN_LTLEND(0x00002000L)   from 16-bit mono, little-endian
+		  DATA_FMT_8_BIT_MN_SIGNED(0x00003000L)   from 8-bit mono, signed
+		  DATA_FMT_16BIT_ST_BIGEND(0x00004000L)   from 16-bit stereo, big-endian
+		  DATA_FMT_16BIT_MN_BIGEND(0x00006000L)   from 16-bit mono, big-endian
+		  DATA_FMT_8_BIT_ST_UNSIGNED(0x00009000L) from 8-bit stereo, unsigned
+		  DATA_FMT_8_BIT_MN_UNSIGNED(0x0000b000L) from 8-bit mono, unsigned
+		  ? Other combinations possible from:
+		  DMA_RQ_C2_AUDIO_CONVERT_MASK    0x0000F000L
+		  DMA_RQ_C2_AC_NONE               0x00000000L
+		  DMA_RQ_C2_AC_8_TO_16_BIT        0x00001000L
+		  DMA_RQ_C2_AC_MONO_TO_STEREO     0x00002000L
+		  DMA_RQ_C2_AC_ENDIAN_CONVERT     0x00004000L
+		  DMA_RQ_C2_AC_SIGNED_CONVERT     0x00008000L
+        
+		  HostBuffAddr: Host Buffer Physical Byte Address - SCB loc:3rd dword, Mask: 0xFFFFFFFFL
+		  aligned to dword boundary
+		*/
+		/* Basic (non scatter/gather) DMA requestor (4 ints) */
+		{ DMA_RQ_C1_SOURCE_ON_HOST +        /* source buffer is on the host */
+		  DMA_RQ_C1_SOURCE_MOD1024 +        /* source buffer is 1024 dwords (4096 bytes) */
+		  DMA_RQ_C1_DEST_MOD32 +            /* dest buffer(PCMreaderBuf) is 32 dwords*/
+		  DMA_RQ_C1_WRITEBACK_SRC_FLAG +    /* ?? */
+		  DMA_RQ_C1_WRITEBACK_DEST_FLAG +   /* ?? */
+		  15,                             /* DwordCount-1: picked 16 for DwordCount because Jim */
+		  /*        Barnette said that is what we should use since */
+		  /*        we are not running in optimized mode? */
+		  DMA_RQ_C2_AC_NONE +
+		  DMA_RQ_C2_SIGNAL_SOURCE_PINGPONG + /* set play interrupt (bit0) in HISR when source */
+		  /*   buffer (on host) crosses half-way point */
+		  virtual_channel,                   /* Play DMA channel arbitrarily set to 0 */
+		  playback_hw_addr,                  /* HostBuffAddr (source) */
+		  DMA_RQ_SD_SP_SAMPLE_ADDR +         /* destination buffer is in SP Sample Memory */
+		  sample_buffer_addr                 /* SP Buffer Address (destination) */
+		},
+		/* Scatter/gather DMA requestor extension   (5 ints) */
+		{
+			0,
+			0,
+			0,
+			0,
+			0 
+		},
+		/* Sublist pointer & next stream control block (SCB) link. */
+		NULL_SCB_ADDR,NULL_SCB_ADDR,
+		/* Pointer to this tasks parameter block & stream function pointer */
+		0,NULL_SCB_ADDR,
+		/* rsConfig register for stream buffer (rsDMA reg. is loaded from basicReq.daw */
+		/*   for incoming streams, or basicReq.saw, for outgoing streams) */
+		RSCONFIG_DMA_ENABLE +                 /* enable DMA */
+		(19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) + /* MAX_DMA_SIZE picked to be 19 since SPUD  */
+		/*  uses it for some reason */
+		((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) + /* stream number = SCBaddr/16 */
+		RSCONFIG_SAMPLE_16STEREO +
+		RSCONFIG_MODULO_32,             /* dest buffer(PCMreaderBuf) is 32 dwords (256 bytes) */
+		/* Stream sample pointer & MAC-unit mode for this stream */
+		(sample_buffer_addr << 0x10),
+		/* Fractional increment per output sample in the input sample buffer */
+		0, 
+		{
+			/* Standard stereo volume control */
+			0x8000,0x8000,
+			0x8000,0x8000
+		}
+	};
+
+	if (ins->null_algorithm == NULL) {
+		ins->null_algorithm =  cs46xx_dsp_lookup_symbol (chip,"NULLALGORITHM",
+								 SYMBOL_CODE);
+    
+		if (ins->null_algorithm == NULL) {
+			snd_printk (KERN_ERR "dsp_spos: symbol NULLALGORITHM not found\n");
+			return NULL;
+		}    
+	}
+
+	scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_reader_scb,
+				      dest,ins->null_algorithm,parent_scb,
+				      scb_child_type);
+  
+	return scb;
+}
+
+dsp_scb_descriptor_t * 
+cs46xx_dsp_create_src_task_scb(cs46xx_t * chip,char * scb_name,
+                               u16 src_buffer_addr,
+                               u16 src_delay_buffer_addr,u32 dest,
+                               dsp_scb_descriptor_t * parent_scb,
+                               int scb_child_type)
+{
+
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+	dsp_scb_descriptor_t * scb;
+    
+	src_task_scb_t src_task_scb = {
+		0x0028,0x00c8,
+		0x5555,0x0000,
+		0x0000,0x0000,
+		src_buffer_addr,1,
+		0x0028,0x00c8,
+		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,  
+		0x0000,src_delay_buffer_addr,                  
+		0x0,                                            
+		0x80,(src_delay_buffer_addr + (24 * 4)),
+		0,0, /* next_scb, sub_list_ptr */
+		0,0, /* entry, this_spb */
+		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
+		src_buffer_addr << 0x10,
+		0x04000000,
+		{ 
+			0x8000,0x8000,
+			0xFFFF,0xFFFF
+		}
+	};
+
+	if (ins->s16_up == NULL) {
+		ins->s16_up =  cs46xx_dsp_lookup_symbol (chip,"S16_UPSRC",
+							 SYMBOL_CODE);
+    
+		if (ins->s16_up == NULL) {
+			snd_printk (KERN_ERR "dsp_spos: symbol S16_UPSRC not found\n");
+			return NULL;
+		}    
+	}
+
+	scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
+				      dest,ins->s16_up,parent_scb,
+				      scb_child_type);
+
+	return scb;
+}
+
+
+dsp_scb_descriptor_t * 
+cs46xx_dsp_create_mix_only_scb(cs46xx_t * chip,char * scb_name,
+                               u16 mix_buffer_addr,u32 dest,
+                               dsp_scb_descriptor_t * parent_scb,
+                               int scb_child_type)
+{
+  dsp_scb_descriptor_t * scb;
+  
+  mix_only_scb_t master_mix_scb = {
+    /* 0 */ { 0,
+    /* 1 */   0,
+    /* 2 */  mix_buffer_addr,
+    /* 3 */  0
+    /*   */ },
+    {
+    /* 4 */  0,
+    /* 5 */  0,
+    /* 6 */  0,
+    /* 7 */  0,
+    /* 8 */  0x00000080
+    },
+    /* 9 */ 0,0,
+    /* A */ 0,0,
+    /* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
+    /* C */ (mix_buffer_addr  + (32 * 4)) << 0x10, 
+    /* D */ 0,
+    {
+    /* E */ 0x8000,0x8000,
+    /* F */ 0xFFFF,0xFFFF
+    }
+  };
+
+
+  scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&master_mix_scb,
+                                      dest,"S16_MIX",parent_scb,
+                                      scb_child_type);
+  return scb;
+}
+
+
+dsp_scb_descriptor_t * 
+cs46xx_dsp_create_mix_to_ostream_scb(cs46xx_t * chip,char * scb_name,
+                                     u16 mix_buffer_addr,u16 writeback_spb,u32 dest,
+                                     dsp_scb_descriptor_t * parent_scb,
+                                     int scb_child_type)
+{
+	dsp_scb_descriptor_t * scb;
+
+	mix2_ostream_scb_t mix2_ostream_scb = {
+		/* Basic (non scatter/gather) DMA requestor (4 ints) */
+		{ 
+			DMA_RQ_C1_SOURCE_MOD64 +
+			DMA_RQ_C1_DEST_ON_HOST +
+			DMA_RQ_C1_DEST_MOD1024 +
+			DMA_RQ_C1_WRITEBACK_SRC_FLAG + 
+			DMA_RQ_C1_WRITEBACK_DEST_FLAG +
+			15,                            
+      
+			DMA_RQ_C2_AC_NONE +
+			DMA_RQ_C2_SIGNAL_DEST_PINGPONG + 
+      
+			CS46XX_DSP_CAPTURE_CHANNEL,                                 
+			DMA_RQ_SD_SP_SAMPLE_ADDR + 
+			mix_buffer_addr, 
+			0x0                   
+		},
+    
+		{ 0, 0, 0, 0, 0, },
+		0,0,
+		0,writeback_spb,
+    
+		RSCONFIG_DMA_ENABLE + 
+		(19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) + 
+    
+		((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) +
+		RSCONFIG_DMA_TO_HOST + 
+		RSCONFIG_SAMPLE_16STEREO +
+		RSCONFIG_MODULO_64,    
+		(mix_buffer_addr + (32 * 4)) << 0x10,
+		1,0,            
+		0x0001,0x0080,
+		0xFFFF,0
+	};
+
+
+	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&mix2_ostream_scb,
+					    dest,"S16_MIX_TO_OSTREAM",parent_scb,
+					    scb_child_type);
+  
+	return scb;
+}
+
+
+dsp_scb_descriptor_t * 
+cs46xx_dsp_create_vari_decimate_scb(cs46xx_t * chip,char * scb_name,
+                                    u16 vari_buffer_addr0,
+                                    u16 vari_buffer_addr1,
+                                    u32 dest,
+                                    dsp_scb_descriptor_t * parent_scb,
+                                    int scb_child_type)
+{
+
+	dsp_scb_descriptor_t * scb;
+  
+	vari_decimate_scb_t vari_decimate_scb = {
+		0x0028,0x00c8,
+		0x5555,0x0000,
+		0x0000,0x0000,
+		vari_buffer_addr0,vari_buffer_addr1,
+    
+		0x0028,0x00c8,
+		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256, 
+    
+		0xFF800000,   
+		0,
+		0x0080,vari_buffer_addr1 + (25 * 4), 
+    
+		0,0, 
+		0,0,
+
+		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
+		vari_buffer_addr0 << 0x10,   
+		0x04000000,                   
+		{
+			0x8000,0x8000, 
+			0xFFFF,0xFFFF
+		}
+	};
+
+	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&vari_decimate_scb,
+					    dest,"VARIDECIMATE",parent_scb,
+					    scb_child_type);
+  
+	return scb;
+}
+
+
+dsp_scb_descriptor_t * 
+cs46xx_dsp_create_pcm_serial_input_scb(cs46xx_t * chip,char * scb_name,u32 dest,
+                                       dsp_scb_descriptor_t * input_scb,
+                                       dsp_scb_descriptor_t * parent_scb,
+                                       int scb_child_type)
+{
+
+	dsp_scb_descriptor_t * scb;
+
+
+	pcm_serial_input_scb_t pcm_serial_input_scb = {
+		{ 0,
+		  0,
+		  0,
+		  0
+		},
+		{
+			0,
+			0,
+			0,
+			0,
+			0
+		},
+
+		0,0,
+		0,0,
+
+		0x000000c1,
+		0,
+		0,input_scb->address, 
+		{
+			0x8000,0x8000,
+			0x8000,0x8000
+		}
+	};
+
+	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_serial_input_scb,
+					    dest,"PCMSERIALINPUTTASK",parent_scb,
+					    scb_child_type);
+	return scb;
+}
+
+
+dsp_scb_descriptor_t * 
+cs46xx_dsp_create_asynch_fg_tx_scb(cs46xx_t * chip,char * scb_name,u32 dest,
+                                   u16 hfg_scb_address,
+                                   u16 asynch_buffer_address,
+                                   dsp_scb_descriptor_t * parent_scb,
+                                   int scb_child_type)
+{
+
+	dsp_scb_descriptor_t * scb;
+
+	asynch_fg_tx_scb_t asynch_fg_tx_scb = {
+		0xfc00,0x03ff,      /*  Prototype sample buffer size of 256 dwords */
+		0x0058,0x0028,      /* Min Delta 7 dwords == 28 bytes */
+		/* : Max delta 25 dwords == 100 bytes */
+		0,hfg_scb_address,  /* Point to HFG task SCB */
+		0,0,				/* Initialize current Delta and Consumer ptr adjustment count */
+		0,                  /* Initialize accumulated Phi to 0 */
+		0,0x2aab,           /* Const 1/3 */
+    
+		{
+			0,                /* Define the unused elements */
+			0,
+			0
+		},
+    
+		0,0,
+		0,dest + AFGTxAccumPhi,
+    
+		0x000000c5,                       /* Stereo, 256 dword */
+		(asynch_buffer_address) << 0x10,  /* This should be automagically synchronized
+						     to the producer pointer */
+    
+		/* There is no correct initial value, it will depend upon the detected
+		   rate etc  */
+		0x18000000,                     /* Phi increment for approx 32k operation */
+		0x8000,0x8000,                  /* Volume controls are unused at this time */
+		0x8000,0x8000
+	};
+  
+	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_tx_scb,
+					    dest,"ASYNCHFGTXCODE",parent_scb,
+					    scb_child_type);
+
+	return scb;
+}
+
+
+dsp_scb_descriptor_t * 
+cs46xx_dsp_create_asynch_fg_rx_scb(cs46xx_t * chip,char * scb_name,u32 dest,
+                                   u16 hfg_scb_address,
+                                   u16 asynch_buffer_address,
+                                   dsp_scb_descriptor_t * parent_scb,
+                                   int scb_child_type)
+{
+
+	dsp_scb_descriptor_t * scb;
+
+	asynch_fg_rx_scb_t asynch_fg_rx_scb = {
+		0xff00,0x00ff,      /* Prototype sample buffer size of 512 dwords */
+		0x0064,0x001c,      /* Min Delta 7 dwords == 28 bytes */
+		/* : Max delta 25 dwords == 100 bytes */
+		0,hfg_scb_address,  /* Point to HFG task SCB */
+		0,0,				/* Initialize current Delta and Consumer ptr adjustment count */
+		{
+			0,                /* Define the unused elements */
+			0,
+			0,
+			0,
+			0
+		},
+      
+		0,0,
+		0,dest,
+    
+		0x000000c3,                            /* Stereo, 512 dword */
+		(asynch_buffer_address  << 0x10),      /* This should be automagically 
+							  synchrinized to the producer pointer */
+    
+		/* There is no correct initial value, it will depend upon the detected
+		   rate etc  */
+		0,         
+		0x8000,0x8000,       
+		0xFFFF,0xFFFF
+	};
+
+	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_rx_scb,
+					    dest,"ASYNCHFGRXCODE",parent_scb,
+					    scb_child_type);
+
+	return scb;
+}
+
+
+dsp_scb_descriptor_t * 
+cs46xx_dsp_create_output_snoop_scb(cs46xx_t * chip,char * scb_name,u32 dest,
+                                   u16 snoop_buffer_address,
+                                   dsp_scb_descriptor_t * snoop_scb,
+                                   dsp_scb_descriptor_t * parent_scb,
+                                   int scb_child_type)
+{
+
+	dsp_scb_descriptor_t * scb;
+  
+	output_snoop_scb_t output_snoop_scb = {
+		{ 0,	/*  not used.  Zero */
+		  0,
+		  0,
+		  0,
+		},
+		{
+			0, /* not used.  Zero */
+			0,
+			0,
+			0,
+			0
+		},
+    
+		0,0,
+		0,0,
+    
+		0x000000c3,
+		snoop_buffer_address << 0x10,  
+		0,0,
+		0,
+		0,snoop_scb->address
+	};
+  
+	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&output_snoop_scb,
+					    dest,"OUTPUTSNOOP",parent_scb,
+					    scb_child_type);
+	return scb;
+}
+
+
+dsp_scb_descriptor_t * 
+cs46xx_dsp_create_spio_write_scb(cs46xx_t * chip,char * scb_name,u32 dest,
+                                 dsp_scb_descriptor_t * parent_scb,
+                                 int scb_child_type)
+{
+	dsp_scb_descriptor_t * scb;
+  
+	spio_write_scb_t spio_write_scb = {
+		0,0,         /*   SPIOWAddress2:SPIOWAddress1; */
+		0,           /*   SPIOWData1; */
+		0,           /*   SPIOWData2; */
+		0,0,         /*   SPIOWAddress4:SPIOWAddress3; */
+		0,           /*   SPIOWData3; */
+		0,           /*   SPIOWData4; */
+		0,0,         /*   SPIOWDataPtr:Unused1; */
+		{ 0,0 },     /*   Unused2[2]; */
+    
+		0,0,	     /*   SPIOWChildPtr:SPIOWSiblingPtr; */
+		0,0,         /*   SPIOWThisPtr:SPIOWEntryPoint; */
+    
+		{ 
+			0,
+			0,
+			0,
+			0,
+			0          /*   Unused3[5];  */
+		}
+	};
+
+	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&spio_write_scb,
+					    dest,"SPIOWRITE",parent_scb,
+					    scb_child_type);
+
+	return scb;
+}
+
+dsp_scb_descriptor_t *  cs46xx_dsp_create_magic_snoop_scb(cs46xx_t * chip,char * scb_name,u32 dest,
+                                                          u16 snoop_buffer_address,
+                                                          dsp_scb_descriptor_t * snoop_scb,
+                                                          dsp_scb_descriptor_t * parent_scb,
+                                                          int scb_child_type)
+{
+	dsp_scb_descriptor_t * scb;
+  
+	magic_snoop_task_t magic_snoop_scb = {
+		/* 0 */ 0, /* i0 */
+		/* 1 */ 0, /* i1 */
+		/* 2 */ snoop_buffer_address << 0x10,
+		/* 3 */ 0,snoop_scb->address,
+		/* 4 */ 0, /* i3 */
+		/* 5 */ 0, /* i4 */
+		/* 6 */ 0, /* i5 */
+		/* 7 */ 0, /* i6 */
+		/* 8 */ 0, /* i7 */
+		/* 9 */ 0,0, /* next_scb, sub_list_ptr */
+		/* A */ 0,0, /* entry_point, this_ptr */
+		/* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
+		/* C */ snoop_buffer_address  << 0x10,
+		/* D */ 0,
+		/* E */ { 0x8000,0x8000,
+			  /* F */   0xffff,0xffff
+		}
+	};
+
+	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&magic_snoop_scb,
+					    dest,"MAGICSNOOPTASK",parent_scb,
+					    scb_child_type);
+
+	return scb;
+}
+
+static dsp_scb_descriptor_t * find_next_free_scb (cs46xx_t * chip,dsp_scb_descriptor_t * from)
+{
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+	dsp_scb_descriptor_t * scb = from;
+
+	while (scb->next_scb_ptr != ins->the_null_scb) {
+		snd_assert (scb->next_scb_ptr != NULL, return NULL);
+
+		scb = scb->next_scb_ptr;
+	}
+
+	return scb;
+}
+
+static u32 pcm_reader_buffer_addr[DSP_MAX_PCM_CHANNELS] = {
+	0x0600, /* 1 */
+	0x1500, /* 2 */
+	0x1580, /* 3 */
+	0x1600, /* 4 */
+	0x1680, /* 5 */
+	0x1700, /* 6 */
+	0x1780, /* 7 */
+	0x1800, /* 8 */
+	0x1880, /* 9 */
+	0x1900, /* 10 */
+	0x1980, /* 11 */
+	0x1A00, /* 12 */
+	0x1A80, /* 13 */
+	0x1B00, /* 14 */
+	0x1B80, /* 15 */
+	0x1C00, /* 16 */
+	0x1C80, /* 17 */
+	0x1D00, /* 18 */
+	0x1D80, /* 19 */
+	0x1E00, /* 20 */
+	0x1E80, /* 21 */
+	0x1F00, /* 22 */
+	0x1F80, /* 23 */
+	0x2000, /* 24 */
+	0x2080, /* 25 */
+	0x2100, /* 26 */
+	0x2180, /* 27 */
+	0x2200, /* 28 */
+	0x2280, /* 29 */
+	0x2300, /* 30 */
+	0x2380, /* 31 */
+	0x2400, /* 32 */
+};
+
+static u32 src_output_buffer_addr[DSP_MAX_SRC_NR] = {
+	0x2580,
+	0x2680,
+	0x2780,
+	0x2980,  
+	0x2A80,  
+	0x2B80,  
+};
+
+static u32 src_delay_buffer_addr[DSP_MAX_SRC_NR] = {
+	0x2600,
+	0x2700,
+	0x2800,
+	0x2900,
+	0x2A00,
+	0x2B00,
+};
+
+pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,u32 sample_rate, void * private_data)
+{
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+	dsp_scb_descriptor_t * src_scb = NULL,* pcm_scb;
+	dsp_scb_descriptor_t * pcm_parent_scb;
+	char scb_name[DSP_MAX_SCB_NAME];
+	int i,pcm_index = -1, insert_point, src_index = -1;
+	unsigned long flags;
+
+	down(&ins->pcm_mutex); 
+
+	/* default sample rate is 44100 */
+	if (!sample_rate) sample_rate = 44100;
+
+	/* search for a already created SRC SCB with the same sample rate */
+	for (i = 0; i < DSP_MAX_PCM_CHANNELS && 
+		     (pcm_index == -1 || src_scb == NULL); ++i) {
+
+		/* virtual channel reserved 
+		   for capture */
+		if (i == CS46XX_DSP_CAPTURE_CHANNEL) continue;
+
+		if (ins->pcm_channels[i].active) {
+			if (!src_scb && ins->pcm_channels[i].sample_rate == sample_rate) {
+				src_scb = ins->pcm_channels[i].src_scb;
+				ins->pcm_channels[i].src_scb->ref_count ++;
+				src_index = ins->pcm_channels[i].src_slot;
+			}
+		} else if (pcm_index == -1) {
+			pcm_index = i;
+		}
+	}
+
+	if (pcm_index == -1) {
+		snd_printk (KERN_ERR "dsp_spos: no free PCM channel\n");
+		goto _end;
+	}
+
+	if (src_scb == NULL) {
+		dsp_scb_descriptor_t * src_parent_scb;
+
+		if (ins->nsrc_scb >= DSP_MAX_SRC_NR) {
+			snd_printk(KERN_ERR "dsp_spos: to many SRC instances\n!");
+			goto _end;
+		}
+
+		/* find a free slot */
+		for (i = 0; i < DSP_MAX_SRC_NR; ++i) {
+			if (ins->src_scb_slots[i] == 0) {
+				src_index = i;
+				ins->src_scb_slots[i] = 1;
+				break;
+			}
+		}
+		snd_assert (src_index != -1,goto _end);
+
+		/* we need to create a new SRC SCB */
+		if (ins->master_mix_scb->sub_list_ptr == ins->the_null_scb) {
+			src_parent_scb = ins->master_mix_scb;
+			insert_point = SCB_ON_PARENT_SUBLIST_SCB;
+		} else {
+			src_parent_scb = find_next_free_scb(chip,ins->master_mix_scb->sub_list_ptr);
+			insert_point = SCB_ON_PARENT_NEXT_SCB;
+		}
+
+		snprintf (scb_name,DSP_MAX_SCB_NAME,"SrcTask_SCB%d",src_index);
+
+		snd_printdd( "dsp_spos: creating SRC \"%s\"\n",scb_name);
+		src_scb = cs46xx_dsp_create_src_task_scb(chip,scb_name,
+							 src_output_buffer_addr[src_index],
+							 src_delay_buffer_addr[src_index],
+							 /* 0x400 - 0x600 source SCBs */
+							 0x400 + (src_index * 0x10) ,
+							 src_parent_scb,
+							 insert_point);
+
+		if (!src_scb) {
+			snd_printk (KERN_ERR "dsp_spos: failed to create SRCtaskSCB\n");
+			goto _end;
+		}
+
+		cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate);
+
+		ins->nsrc_scb ++;
+
+		/* insert point for the PCMreader task */
+		pcm_parent_scb = src_scb;
+		insert_point = SCB_ON_PARENT_SUBLIST_SCB;
+	} else {
+		snd_assert (src_scb->sub_list_ptr != ins->the_null_scb, goto _end);
+		pcm_parent_scb = find_next_free_scb(chip,src_scb->sub_list_ptr);
+    
+		insert_point = SCB_ON_PARENT_NEXT_SCB;
+	}
+  
+  
+  
+	snprintf (scb_name,DSP_MAX_SCB_NAME,"PCMReader_SCB%d",pcm_index);
+
+	snd_printdd( "dsp_spos: creating PCM \"%s\"\n",scb_name);
+
+	pcm_scb = cs46xx_dsp_create_pcm_reader_scb(chip,scb_name,
+						   pcm_reader_buffer_addr[pcm_index],
+						   /* 0x200 - 400 PCMreader SCBs */
+						   (pcm_index * 0x10) + 0x200,
+						   pcm_index, /* virtual channel 0-31 */
+						   0, /* pcm hw addr */
+						   pcm_parent_scb,
+						   insert_point);
+
+	if (!pcm_scb) {
+		snd_printk (KERN_ERR "dsp_spos: failed to create PCMreaderSCB\n");
+		goto _end;
+	}
+
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	ins->pcm_channels[pcm_index].sample_rate = sample_rate;
+	ins->pcm_channels[pcm_index].pcm_reader_scb = pcm_scb;
+	ins->pcm_channels[pcm_index].src_scb = src_scb;
+	ins->pcm_channels[pcm_index].unlinked = 0;  
+	ins->pcm_channels[pcm_index].private_data = private_data;
+	ins->pcm_channels[pcm_index].src_slot = src_index;
+	ins->pcm_channels[pcm_index].active = 1;
+	ins->pcm_channels[pcm_index].pcm_slot = pcm_index;
+	ins->npcm_channels ++;
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+
+	up(&ins->pcm_mutex);  
+	return (ins->pcm_channels + pcm_index);
+ _end:
+
+	up(&ins->pcm_mutex);
+	return NULL;
+}
+
+void cs46xx_dsp_destroy_pcm_channel (cs46xx_t * chip,pcm_channel_descriptor_t * pcm_channel)
+{
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+	unsigned long flags;
+
+	down(&ins->pcm_mutex);
+  
+	snd_assert(pcm_channel->active,goto _end);
+	snd_assert(ins->npcm_channels > 0,goto _end);
+	snd_assert(pcm_channel->src_scb->ref_count > 0,goto _end);
+
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	pcm_channel->unlinked = 1;
+	pcm_channel->active = 0;
+	pcm_channel->private_data = NULL;
+	pcm_channel->src_scb->ref_count --;
+	ins->npcm_channels --;
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+
+	cs46xx_dsp_remove_scb(chip,pcm_channel->pcm_reader_scb);
+
+	if (!pcm_channel->src_scb->ref_count) {
+		cs46xx_dsp_remove_scb(chip,pcm_channel->src_scb);
+
+		snd_assert (pcm_channel->src_slot >= 0 && pcm_channel->src_slot <= DSP_MAX_SRC_NR,
+			    goto _end);
+
+		ins->src_scb_slots[pcm_channel->src_slot] = 0;
+		ins->nsrc_scb --;
+	}
+
+
+#ifdef CONFIG_SND_DEBUG
+ _end:
+#endif
+
+	up(&ins->pcm_mutex);
+}
+
+int cs46xx_dsp_pcm_unlink (cs46xx_t * chip,pcm_channel_descriptor_t * pcm_channel)
+{
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+	unsigned long flags;
+
+	down(&ins->pcm_mutex);
+	down(&ins->scb_mutex);
+
+	snd_assert(pcm_channel->active,goto _end);
+	snd_assert(ins->npcm_channels > 0,goto _end);
+
+	if (pcm_channel->unlinked)
+		goto _end;
+
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	pcm_channel->unlinked = 1;
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+
+	_dsp_unlink_scb (chip,pcm_channel->pcm_reader_scb);
+
+ _end:
+	up(&ins->scb_mutex);
+	up(&ins->pcm_mutex);
+
+	return 0;
+}
+
+int cs46xx_dsp_pcm_link (cs46xx_t * chip,pcm_channel_descriptor_t * pcm_channel)
+{
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+	dsp_scb_descriptor_t * parent_scb;
+	dsp_scb_descriptor_t * src_scb = pcm_channel->src_scb;
+	unsigned long flags;
+
+	down(&ins->pcm_mutex);
+	down(&ins->scb_mutex);
+
+	if (pcm_channel->unlinked == 0)
+		goto _end;
+
+	if (src_scb->sub_list_ptr == ins->the_null_scb) {
+		parent_scb = src_scb;
+		parent_scb->sub_list_ptr = pcm_channel->pcm_reader_scb;
+	} else {
+		parent_scb = find_next_free_scb(chip,src_scb->sub_list_ptr);
+		parent_scb->next_scb_ptr = pcm_channel->pcm_reader_scb;
+	}
+  
+	snd_assert (pcm_channel->pcm_reader_scb->parent_scb_ptr == NULL, ; );
+	pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb;
+
+	/* update entry in DSP RAM */
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	snd_cs46xx_poke(chip,
+			(parent_scb->address + SCBsubListPtr) << 2,
+			(parent_scb->sub_list_ptr->address << 0x10) |
+			(parent_scb->next_scb_ptr->address));
+
+	pcm_channel->unlinked = 0;
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+
+ _end:
+	up(&ins->scb_mutex);
+	up(&ins->pcm_mutex);
+
+	return 0;
+}
+
+#define GOF_PER_SEC 200
+  
+void cs46xx_dsp_set_src_sample_rate(cs46xx_t *chip,dsp_scb_descriptor_t * src, u32 rate)
+{
+	unsigned long flags;
+	unsigned int tmp1, tmp2;
+	unsigned int phiIncr;
+	unsigned int correctionPerGOF, correctionPerSec;
+
+	snd_printdd( "dsp_spos: setting SRC rate to %u\n",rate);
+	/*
+	 *  Compute the values used to drive the actual sample rate conversion.
+	 *  The following formulas are being computed, using inline assembly
+	 *  since we need to use 64 bit arithmetic to compute the values:
+	 *
+	 *  phiIncr = floor((Fs,in * 2^26) / Fs,out)
+	 *  correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) /
+	 *                                   GOF_PER_SEC)
+	 *  ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -M
+	 *                       GOF_PER_SEC * correctionPerGOF
+	 *
+	 *  i.e.
+	 *
+	 *  phiIncr:other = dividend:remainder((Fs,in * 2^26) / Fs,out)
+	 *  correctionPerGOF:correctionPerSec =
+	 *      dividend:remainder(ulOther / GOF_PER_SEC)
+	 */
+	tmp1 = rate << 16;
+	phiIncr = tmp1 / 48000;
+	tmp1 -= phiIncr * 48000;
+	tmp1 <<= 10;
+	phiIncr <<= 10;
+	tmp2 = tmp1 / 48000;
+	phiIncr += tmp2;
+	tmp1 -= tmp2 * 48000;
+	correctionPerGOF = tmp1 / GOF_PER_SEC;
+	tmp1 -= correctionPerGOF * GOF_PER_SEC;
+	correctionPerSec = tmp1;
+
+	/*
+	 *  Fill in the SampleRateConverter control block.
+	 */
+	spin_lock_irqsave(&chip->reg_lock, flags);
+
+	snd_cs46xx_poke(chip, (src->address + SRCCorPerGof) << 2,
+	  ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF));
+
+	snd_cs46xx_poke(chip, (src->address + SRCPhiIncr6Int26Frac) << 2, phiIncr);
+
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+}
diff -Nru a/sound/pci/cs46xx/imgs/cwc4630.h b/sound/pci/cs46xx/imgs/cwc4630.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/cs46xx/imgs/cwc4630.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,320 @@
+/* generated from cwc4630.osp DO NOT MODIFY */
+
+#ifndef __HEADER_cwc4630_H__
+#define __HEADER_cwc4630_H__
+
+static symbol_entry_t cwc4630_symbols[] = {
+  { 0x0000, "BEGINADDRESS",0x00 },
+  { 0x8000, "EXECCHILD",0x03 },
+  { 0x8001, "EXECCHILD_98",0x03 },
+  { 0x8003, "EXECCHILD_PUSH1IND",0x03 },
+  { 0x8008, "EXECSIBLING",0x03 },
+  { 0x800a, "EXECSIBLING_298",0x03 },
+  { 0x800b, "EXECSIBLING_2IND1",0x03 },
+  { 0x8010, "TIMINGMASTER",0x03 },
+  { 0x804f, "S16_CODECINPUTTASK",0x03 },
+  { 0x805e, "PCMSERIALINPUTTASK",0x03 },
+  { 0x806d, "S16_MIX_TO_OSTREAM",0x03 },
+  { 0x809a, "S16_MIX",0x03 },
+  { 0x80bb, "S16_UPSRC",0x03 },
+  { 0x813b, "MIX3_EXP",0x03 },
+  { 0x8164, "DECIMATEBYPOW2",0x03 },
+  { 0x8197, "VARIDECIMATE",0x03 },
+  { 0x81f2, "_3DINPUTTASK",0x03 },
+  { 0x820a, "_3DPRLGCINPTASK",0x03 },
+  { 0x8227, "_3DSTEREOINPUTTASK",0x03 },
+  { 0x8242, "_3DOUTPUTTASK",0x03 },
+  { 0x82c4, "HRTF_MORPH_TASK",0x03 },
+  { 0x82c6, "WAIT4DATA",0x03 },
+  { 0x82fa, "PROLOGIC",0x03 },
+  { 0x8496, "DECORRELATOR",0x03 },
+  { 0x84a4, "STEREO2MONO",0x03 },
+  { 0x0070, "SPOSCB",0x02 },
+  { 0x0107, "TASKTREETHREAD",0x03 },
+  { 0x013c, "TASKTREEHEADERCODE",0x03 },
+  { 0x0145, "FGTASKTREEHEADERCODE",0x03 },
+  { 0x0169, "NULLALGORITHM",0x03 },
+  { 0x016d, "HFGEXECCHILD",0x03 },
+  { 0x016e, "HFGEXECCHILD_98",0x03 },
+  { 0x0170, "HFGEXECCHILD_PUSH1IND",0x03 },
+  { 0x0173, "HFGEXECSIBLING",0x03 },
+  { 0x0175, "HFGEXECSIBLING_298",0x03 },
+  { 0x0176, "HFGEXECSIBLING_2IND1",0x03 },
+  { 0x0179, "S16_CODECOUTPUTTASK",0x03 },
+  { 0x0194, "#CODE_END",0x00 },
+}; /* cwc4630 symbols */
+
+static u32 cwc4630_code[] = {
+/* BEGINADDRESS */
+/* 0000 */ 0x00040730,0x00001002,0x000f619e,0x00001003,
+/* 0002 */ 0x00001705,0x00001400,0x000a411e,0x00001003,
+/* 0004 */ 0x00040730,0x00001002,0x000f619e,0x00001003,
+/* 0006 */ 0x00009705,0x00001400,0x000a411e,0x00001003,
+/* 0008 */ 0x00040730,0x00001002,0x000f619e,0x00001003,
+/* 000A */ 0x00011705,0x00001400,0x000a411e,0x00001003,
+/* 000C */ 0x00040730,0x00001002,0x000f619e,0x00001003,
+/* 000E */ 0x00019705,0x00001400,0x000a411e,0x00001003,
+/* 0010 */ 0x00040730,0x00001002,0x000f619e,0x00001003,
+/* 0012 */ 0x00021705,0x00001400,0x000a411e,0x00001003,
+/* 0014 */ 0x00040730,0x00001002,0x000f619e,0x00001003,
+/* 0016 */ 0x00029705,0x00001400,0x000a411e,0x00001003,
+/* 0018 */ 0x00040730,0x00001002,0x000f619e,0x00001003,
+/* 001A */ 0x00031705,0x00001400,0x000a411e,0x00001003,
+/* 001C */ 0x00040730,0x00001002,0x000f619e,0x00001003,
+/* 001E */ 0x00039705,0x00001400,0x000a411e,0x00001003,
+/* 0020 */ 0x000fe19e,0x00001003,0x0009c730,0x00001003,
+/* 0022 */ 0x0008e19c,0x00001003,0x000083c1,0x00093040,
+/* 0024 */ 0x00098730,0x00001002,0x000ee19e,0x00001003,
+/* 0026 */ 0x00009705,0x00001400,0x000a211e,0x00001003,
+/* 0028 */ 0x00098730,0x00001002,0x000ee19e,0x00001003,
+/* 002A */ 0x00011705,0x00001400,0x000a211e,0x00001003,
+/* 002C */ 0x00098730,0x00001002,0x000ee19e,0x00001003,
+/* 002E */ 0x00019705,0x00001400,0x000a211e,0x00001003,
+/* 0030 */ 0x00098730,0x00001002,0x000ee19e,0x00001003,
+/* 0032 */ 0x00021705,0x00001400,0x000a211e,0x00001003,
+/* 0034 */ 0x00098730,0x00001002,0x000ee19e,0x00001003,
+/* 0036 */ 0x00029705,0x00001400,0x000a211e,0x00001003,
+/* 0038 */ 0x00098730,0x00001002,0x000ee19e,0x00001003,
+/* 003A */ 0x00031705,0x00001400,0x000a211e,0x00001003,
+/* 003C */ 0x00098730,0x00001002,0x000ee19e,0x00001003,
+/* 003E */ 0x00039705,0x00001400,0x000a211e,0x00001003,
+/* 0040 */ 0x0001a730,0x00001008,0x000e2730,0x00001002,
+/* 0042 */ 0x0000a731,0x00001002,0x0000a731,0x00001002,
+/* 0044 */ 0x0000a731,0x00001002,0x0000a731,0x00001002,
+/* 0046 */ 0x0000a731,0x00001002,0x0000a731,0x00001002,
+/* 0048 */ 0x00000000,0x00000000,0x000f619c,0x00001003,
+/* 004A */ 0x0007f801,0x000c0000,0x00000037,0x00001000,
+/* 004C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 004E */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0050 */ 0x00000000,0x000c0000,0x00000000,0x00000000,
+/* 0052 */ 0x0000373c,0x00001000,0x00000000,0x00000000,
+/* 0054 */ 0x000ee19c,0x00001003,0x0007f801,0x000c0000,
+/* 0056 */ 0x00000037,0x00001000,0x00000000,0x00000000,
+/* 0058 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 005A */ 0x00000000,0x00000000,0x0000273c,0x00001000,
+/* 005C */ 0x00000033,0x00001000,0x000e679e,0x00001003,
+/* 005E */ 0x00007705,0x00001400,0x000ac71e,0x00001003,
+/* 0060 */ 0x00087fc1,0x000c3be0,0x0007f801,0x000c0000,
+/* 0062 */ 0x00000037,0x00001000,0x00000000,0x00000000,
+/* 0064 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0066 */ 0x00000000,0x00000000,0x0000a730,0x00001003,
+/* 0068 */ 0x00000033,0x00001000,0x0007f801,0x000c0000,
+/* 006A */ 0x00000037,0x00001000,0x00000000,0x00000000,
+/* 006C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 006E */ 0x00000000,0x00000000,0x00000000,0x000c0000,
+/* 0070 */ 0x00000032,0x00001000,0x0000273d,0x00001000,
+/* 0072 */ 0x0004a730,0x00001003,0x00000f41,0x00097140,
+/* 0074 */ 0x0000a841,0x0009b240,0x0000a0c1,0x0009f040,
+/* 0076 */ 0x0001c641,0x00093540,0x0001cec1,0x0009b5c0,
+/* 0078 */ 0x00000000,0x00000000,0x0001bf05,0x0003fc40,
+/* 007A */ 0x00002725,0x000aa400,0x00013705,0x00093a00,
+/* 007C */ 0x0000002e,0x0009d6c0,0x0002ef8a,0x00000000,
+/* 007E */ 0x00040630,0x00001004,0x0004ef0a,0x000eb785,
+/* 0080 */ 0x0003fc8a,0x00000000,0x00000000,0x000c70e0,
+/* 0082 */ 0x0007d182,0x0002c640,0x00008630,0x00001004,
+/* 0084 */ 0x000799b8,0x0002c6c0,0x00031705,0x00092240,
+/* 0086 */ 0x00039f05,0x000932c0,0x0003520a,0x00000000,
+/* 0088 */ 0x00070731,0x0000100b,0x00010705,0x000b20c0,
+/* 008A */ 0x00000000,0x000eba44,0x00032108,0x000c60c4,
+/* 008C */ 0x00065208,0x000c2917,0x000486b0,0x00001007,
+/* 008E */ 0x00012f05,0x00036880,0x0002818e,0x000c0000,
+/* 0090 */ 0x0004410a,0x00000000,0x00048630,0x00001007,
+/* 0092 */ 0x00029705,0x000c0000,0x00000000,0x00000000,
+/* 0094 */ 0x00003fc1,0x0003fc40,0x000037c1,0x00091b40,
+/* 0096 */ 0x00003fc1,0x000911c0,0x000037c1,0x000957c0,
+/* 0098 */ 0x00003fc1,0x000951c0,0x000037c1,0x00000000,
+/* 009A */ 0x00003fc1,0x000991c0,0x000037c1,0x00000000,
+/* 009C */ 0x00003fc1,0x0009d1c0,0x000037c1,0x00000000,
+/* 009E */ 0x0001ccc1,0x000915c0,0x0001c441,0x0009d800,
+/* 00A0 */ 0x0009cdc1,0x00091240,0x0001c541,0x00091d00,
+/* 00A2 */ 0x0009cfc1,0x00095240,0x0001c741,0x00095c80,
+/* 00A4 */ 0x000e8ca9,0x00099240,0x000e85ad,0x00095640,
+/* 00A6 */ 0x00069ca9,0x00099d80,0x000e952d,0x00099640,
+/* 00A8 */ 0x000eaca9,0x0009d6c0,0x000ea5ad,0x00091a40,
+/* 00AA */ 0x0006bca9,0x0009de80,0x000eb52d,0x00095a40,
+/* 00AC */ 0x000ecca9,0x00099ac0,0x000ec5ad,0x0009da40,
+/* 00AE */ 0x000edca9,0x0009d300,0x000a6e0a,0x00001000,
+/* 00B0 */ 0x000ed52d,0x00091e40,0x000eeca9,0x00095ec0,
+/* 00B2 */ 0x000ee5ad,0x00099e40,0x0006fca9,0x00002500,
+/* 00B4 */ 0x000fb208,0x000c59a0,0x000ef52d,0x0009de40,
+/* 00B6 */ 0x00068ca9,0x000912c1,0x000683ad,0x00095241,
+/* 00B8 */ 0x00020f05,0x000991c1,0x00000000,0x00000000,
+/* 00BA */ 0x00086f88,0x00001000,0x0009cf81,0x000b5340,
+/* 00BC */ 0x0009c701,0x000b92c0,0x0009de81,0x000bd300,
+/* 00BE */ 0x0009d601,0x000b1700,0x0001fd81,0x000b9d80,
+/* 00C0 */ 0x0009f501,0x000b57c0,0x000a0f81,0x000bd740,
+/* 00C2 */ 0x00020701,0x000b5c80,0x000a1681,0x000b97c0,
+/* 00C4 */ 0x00021601,0x00002500,0x000a0701,0x000b9b40,
+/* 00C6 */ 0x000a0f81,0x000b1bc0,0x00021681,0x00002d00,
+/* 00C8 */ 0x00020f81,0x000bd800,0x000a0701,0x000b5bc0,
+/* 00CA */ 0x00021601,0x00003500,0x000a0f81,0x000b5f40,
+/* 00CC */ 0x000a0701,0x000bdbc0,0x00021681,0x00003d00,
+/* 00CE */ 0x00020f81,0x000b1d00,0x000a0701,0x000b1fc0,
+/* 00D0 */ 0x00021601,0x00020500,0x00020f81,0x000b1341,
+/* 00D2 */ 0x000a0701,0x000b9fc0,0x00021681,0x00020d00,
+/* 00D4 */ 0x00020f81,0x000bde80,0x000a0701,0x000bdfc0,
+/* 00D6 */ 0x00021601,0x00021500,0x00020f81,0x000b9341,
+/* 00D8 */ 0x00020701,0x000b53c1,0x00021681,0x00021d00,
+/* 00DA */ 0x000a0f81,0x000d0380,0x0000b601,0x000b15c0,
+/* 00DC */ 0x00007b01,0x00000000,0x00007b81,0x000bd1c0,
+/* 00DE */ 0x00007b01,0x00000000,0x00007b81,0x000b91c0,
+/* 00E0 */ 0x00007b01,0x000b57c0,0x00007b81,0x000b51c0,
+/* 00E2 */ 0x00007b01,0x000b1b40,0x00007b81,0x000b11c0,
+/* 00E4 */ 0x00087b01,0x000c3dc0,0x0007e488,0x000d7e45,
+/* 00E6 */ 0x00000000,0x000d7a44,0x0007e48a,0x00000000,
+/* 00E8 */ 0x00011f05,0x00084080,0x00000000,0x00000000,
+/* 00EA */ 0x00001705,0x000b3540,0x00008a01,0x000bf040,
+/* 00EC */ 0x00007081,0x000bb5c0,0x00055488,0x00000000,
+/* 00EE */ 0x0000d482,0x0003fc40,0x0003fc88,0x00000000,
+/* 00F0 */ 0x0001e401,0x000b3a00,0x0001ec81,0x000bd6c0,
+/* 00F2 */ 0x0002ef88,0x000e7784,0x00056f08,0x00000000,
+/* 00F4 */ 0x000d86b0,0x00001007,0x00008281,0x000bb240,
+/* 00F6 */ 0x0000b801,0x000b7140,0x00007888,0x00000000,
+/* 00F8 */ 0x0000073c,0x00001000,0x0007f188,0x000c0000,
+/* 00FA */ 0x00000000,0x00000000,0x00055288,0x000c555c,
+/* 00FC */ 0x0005528a,0x000c0000,0x0009fa88,0x000c5d00,
+/* 00FE */ 0x0000fa88,0x00000000,0x00000032,0x00001000,
+/* 0100 */ 0x0000073d,0x00001000,0x0007f188,0x000c0000,
+/* 0102 */ 0x00000000,0x00000000,0x0008c01c,0x00001003,
+/* 0104 */ 0x00002705,0x00001008,0x0008b201,0x000c1392,
+/* 0106 */ 0x0000ba01,0x00000000,
+/* TASKTREETHREAD */
+/* 0107 */ 0x00008731,0x00001400,0x0004c108,0x000fe0c4,
+/* 0109 */ 0x00057488,0x00000000,0x000a6388,0x00001001,
+/* 010B */ 0x0008b334,0x000bc141,0x0003020e,0x00000000,
+/* 010D */ 0x000986b0,0x00001008,0x00003625,0x000c5dfa,
+/* 010F */ 0x000a638a,0x00001001,0x0008020e,0x00001002,
+/* 0111 */ 0x0009a6b0,0x00001008,0x0007f301,0x00000000,
+/* 0113 */ 0x00000000,0x00000000,0x00002725,0x000a8c40,
+/* 0115 */ 0x000000ae,0x00000000,0x000e8630,0x00001008,
+/* 0117 */ 0x00000000,0x000c74e0,0x0007d182,0x0002d640,
+/* 0119 */ 0x000b8630,0x00001008,0x000799b8,0x0002d6c0,
+/* 011B */ 0x0000748a,0x000c3ec5,0x0007420a,0x000c0000,
+/* 011D */ 0x00062208,0x000c4117,0x000a0630,0x00001009,
+/* 011F */ 0x00000000,0x000c0000,0x0001022e,0x00000000,
+/* 0121 */ 0x0006a630,0x00001009,0x00000032,0x00001000,
+/* 0123 */ 0x000ca21c,0x00001003,0x00005a02,0x00000000,
+/* 0125 */ 0x0001a630,0x00001009,0x00000000,0x000c0000,
+/* 0127 */ 0x00000036,0x00001000,0x00000000,0x00000000,
+/* 0129 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 012B */ 0x00000000,0x00000000,0x0003a730,0x00001008,
+/* 012D */ 0x0007f801,0x000c0000,0x00000037,0x00001000,
+/* 012F */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0131 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0133 */ 0x0003a730,0x00001008,0x00000033,0x00001000,
+/* 0135 */ 0x0003a705,0x00001008,0x00007a01,0x000c0000,
+/* 0137 */ 0x000e6288,0x000d550a,0x0006428a,0x00000000,
+/* 0139 */ 0x00090730,0x0000100a,0x00000000,0x000c0000,
+/* 013B */ 0x00000000,0x00000000,
+/* TASKTREEHEADERCODE */
+/* 013C */ 0x0007aab0,0x00034880,0x000a8fb0,0x0000100b,
+/* 013E */ 0x00057488,0x00000000,0x00033b94,0x00081140,
+/* 0140 */ 0x000183ae,0x00000000,0x000a86b0,0x0000100b,
+/* 0142 */ 0x00022f05,0x000c3545,0x0000eb8a,0x00000000,
+/* 0144 */ 0x00042731,0x00001003,
+/* FGTASKTREEHEADERCODE */
+/* 0145 */ 0x0007aab0,0x00034880,0x00078fb0,0x0000100a,
+/* 0147 */ 0x00057488,0x00000000,0x00033b94,0x00081140,
+/* 0149 */ 0x000183ae,0x00000000,0x000b06b0,0x0000100b,
+/* 014B */ 0x00022f05,0x00000000,0x00007401,0x00091140,
+/* 014D */ 0x00048f05,0x000951c0,0x00042731,0x00001003,
+/* 014F */ 0x0000473d,0x00001000,0x000f19b0,0x000bbc47,
+/* 0151 */ 0x00080000,0x000bffc7,0x000fe19e,0x00001003,
+/* 0153 */ 0x00000000,0x00000000,0x0008e19c,0x00001003,
+/* 0155 */ 0x000083c1,0x00093040,0x00000f41,0x00097140,
+/* 0157 */ 0x0000a841,0x0009b240,0x0000a0c1,0x0009f040,
+/* 0159 */ 0x0001c641,0x00093540,0x0001cec1,0x0009b5c0,
+/* 015B */ 0x00000000,0x000fdc44,0x00055208,0x00000000,
+/* 015D */ 0x00010705,0x000a2880,0x0000a23a,0x00093a00,
+/* 015F */ 0x0003fc8a,0x000df6c5,0x0004ef0a,0x000c0000,
+/* 0161 */ 0x00012f05,0x00036880,0x00065308,0x000c2997,
+/* 0163 */ 0x000086b0,0x0000100b,0x0004410a,0x000d40c7,
+/* 0165 */ 0x00000000,0x00000000,0x00088730,0x00001004,
+/* 0167 */ 0x00056f0a,0x000ea105,0x00000000,0x00000000,
+/* NULLALGORITHM */
+/* 0169 */ 0x0000473d,0x00001000,0x000f19b0,0x000bbc47,
+/* 016B */ 0x00080000,0x000bffc7,0x0000273d,0x00001000,
+/* HFGEXECCHILD */
+/* 016D */ 0x00000000,0x000eba44,
+/* HFGEXECCHILD_98 */
+/* 016E */ 0x00048f05,0x0000f440,0x00007401,0x0000f7c0,
+/* HFGEXECCHILD_PUSH1IND */
+/* 0170 */ 0x00000734,0x00001000,0x00010705,0x000a6880,
+/* 0172 */ 0x00006a88,0x000c75c4,
+/* HFGEXECSIBLING */
+/* 0173 */ 0x00000000,0x000e5084,0x00000000,0x000eba44,
+/* HFGEXECSIBLING_298 */
+/* 0175 */ 0x00087401,0x000e4782,
+/* HFGEXECSIBLING_2IND1 */
+/* 0176 */ 0x00000734,0x00001000,0x00010705,0x000a6880,
+/* 0178 */ 0x00006a88,0x000c75c4,
+/* S16_CODECOUTPUTTASK */
+/* 0179 */ 0x0007c108,0x000c0000,0x0007e721,0x000bed40,
+/* 017B */ 0x00005f25,0x000badc0,0x0003ba97,0x000beb80,
+/* 017D */ 0x00065590,0x000b2e00,0x00033217,0x00003ec0,
+/* 017F */ 0x00065590,0x000b8e40,0x0003ed80,0x000491c0,
+/* 0181 */ 0x00073fb0,0x00074c80,0x000583a0,0x0000100c,
+/* 0183 */ 0x000ee388,0x00042970,0x00008301,0x00021ef2,
+/* 0185 */ 0x000b8f14,0x0000000f,0x000c4d8d,0x0000001b,
+/* 0187 */ 0x000d6dc2,0x000e06c6,0x000032ac,0x000c3916,
+/* 0189 */ 0x0004edc2,0x00074c80,0x00078898,0x00001000,
+/* 018B */ 0x00038894,0x00000032,0x000c4d8d,0x00092e1b,
+/* 018D */ 0x000d6dc2,0x000e06c6,0x0004edc2,0x000c1956,
+/* 018F */ 0x0000722c,0x00034a00,0x00041705,0x0009ed40,
+/* 0191 */ 0x00058730,0x00001400,0x000d7488,0x000c3a00,
+/* 0193 */ 0x00048f05,0x00000000
+};
+/* #CODE_END */
+
+static u32 cwc4630_parameter[] = {
+/* 0000 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0004 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0008 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 000C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0010 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0014 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0018 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 001C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0020 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0024 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0028 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 002C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0030 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0034 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0038 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 003C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0040 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0044 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0048 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 004C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0050 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0054 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0058 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 005C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0060 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0064 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0068 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 006C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0070 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0074 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0078 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 007C */ 0x00000000,0x00000000,0x00000000,0x00000000
+}; /* #PARAMETER_END */
+
+
+static segment_desc_t cwc4630_segments[] = {
+  { SEGTYPE_SP_PROGRAM, 0x00000000, 0x00000328, cwc4630_code },
+  { SEGTYPE_SP_PARAMETER, 0x00000000, 0x00000080, cwc4630_parameter },
+};
+
+static dsp_module_desc_t cwc4630_module = {
+  "cwc4630",
+  {
+    38,
+    cwc4630_symbols
+  },
+  2,
+  cwc4630_segments,
+};
+
+#endif /* __HEADER_cwc4630_H__ */
diff -Nru a/sound/pci/cs46xx/imgs/cwcasync.h b/sound/pci/cs46xx/imgs/cwcasync.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/cs46xx/imgs/cwcasync.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,176 @@
+/* generated from cwcasync.osp DO NOT MODIFY */
+
+#ifndef __HEADER_cwcasync_H__
+#define __HEADER_cwcasync_H__
+
+static symbol_entry_t cwcasync_symbols[] = {
+  { 0x8000, "EXECCHILD",0x03 },
+  { 0x8001, "EXECCHILD_98",0x03 },
+  { 0x8003, "EXECCHILD_PUSH1IND",0x03 },
+  { 0x8008, "EXECSIBLING",0x03 },
+  { 0x800a, "EXECSIBLING_298",0x03 },
+  { 0x800b, "EXECSIBLING_2IND1",0x03 },
+  { 0x8010, "TIMINGMASTER",0x03 },
+  { 0x804f, "S16_CODECINPUTTASK",0x03 },
+  { 0x805e, "PCMSERIALINPUTTASK",0x03 },
+  { 0x806d, "S16_MIX_TO_OSTREAM",0x03 },
+  { 0x809a, "S16_MIX",0x03 },
+  { 0x80bb, "S16_UPSRC",0x03 },
+  { 0x813b, "MIX3_EXP",0x03 },
+  { 0x8164, "DECIMATEBYPOW2",0x03 },
+  { 0x8197, "VARIDECIMATE",0x03 },
+  { 0x81f2, "_3DINPUTTASK",0x03 },
+  { 0x820a, "_3DPRLGCINPTASK",0x03 },
+  { 0x8227, "_3DSTEREOINPUTTASK",0x03 },
+  { 0x8242, "_3DOUTPUTTASK",0x03 },
+  { 0x82c4, "HRTF_MORPH_TASK",0x03 },
+  { 0x82c6, "WAIT4DATA",0x03 },
+  { 0x82fa, "PROLOGIC",0x03 },
+  { 0x8496, "DECORRELATOR",0x03 },
+  { 0x84a4, "STEREO2MONO",0x03 },
+  { 0x0000, "OVERLAYBEGINADDRESS",0x00 },
+  { 0x0000, "SPIOWRITE",0x03 },
+  { 0x000d, "S16_ASYNCCODECINPUTTASK",0x03 },
+  { 0x0043, "SPDIFITASK",0x03 },
+  { 0x007b, "SPDIFOTASK",0x03 },
+  { 0x0097, "ASYNCHFGTXCODE",0x03 },
+  { 0x00be, "ASYNCHFGRXCODE",0x03 },
+  { 0x00db, "#CODE_END",0x00 },
+}; /* cwcasync symbols */
+
+static u32 cwcasync_code[] = {
+/* OVERLAYBEGINADDRESS */
+/* 0000 */ 0x00002731,0x00001400,0x00003725,0x000a8440,
+/* 0002 */ 0x000000ae,0x00000000,0x00060630,0x00001000,
+/* 0004 */ 0x00000000,0x000c7560,0x00075282,0x0002d640,
+/* 0006 */ 0x00021705,0x00000000,0x00072ab8,0x0002d6c0,
+/* 0008 */ 0x00020630,0x00001000,0x000c74c2,0x000d4b82,
+/* 000A */ 0x000475c2,0x00000000,0x0003430a,0x000c0000,
+/* 000C */ 0x00042730,0x00001400,
+/* S16_ASYNCCODECINPUTTASK */
+/* 000D */ 0x0006a108,0x000cf2c4,0x0004f4c0,0x00000000,
+/* 000F */ 0x000fa418,0x0000101f,0x0005d402,0x0001c500,
+/* 0011 */ 0x000f0630,0x00001000,0x00004418,0x00001380,
+/* 0013 */ 0x000e243d,0x000d394a,0x00049705,0x00000000,
+/* 0015 */ 0x0007d530,0x000b4240,0x000e00f2,0x00001000,
+/* 0017 */ 0x00009134,0x000ca20a,0x00004c90,0x00001000,
+/* 0019 */ 0x0005d705,0x00000000,0x00004f25,0x00098240,
+/* 001B */ 0x00004725,0x00000000,0x0000e48a,0x00000000,
+/* 001D */ 0x00027295,0x0009c2c0,0x0003df25,0x00000000,
+/* 001F */ 0x000e8030,0x00001001,0x0005f718,0x000ac600,
+/* 0021 */ 0x0007cf30,0x000c2a01,0x00082630,0x00001001,
+/* 0023 */ 0x000504a0,0x00001001,0x00029314,0x000bcb80,
+/* 0025 */ 0x0003cf25,0x000b0e00,0x0004f5c0,0x00000000,
+/* 0027 */ 0x00049118,0x000d888a,0x0007dd02,0x000c6efa,
+/* 0029 */ 0x00000000,0x00000000,0x0004f5c0,0x00069c80,
+/* 002B */ 0x0000d402,0x00000000,0x000e8630,0x00001001,
+/* 002D */ 0x00079130,0x00000000,0x00049118,0x00090e00,
+/* 002F */ 0x0006c10a,0x00000000,0x00000000,0x000c0000,
+/* 0031 */ 0x0007cf30,0x00030580,0x00005725,0x00000000,
+/* 0033 */ 0x000d84a0,0x00001001,0x00029314,0x000b4780,
+/* 0035 */ 0x0003cf25,0x000b8600,0x00000000,0x00000000,
+/* 0037 */ 0x00000000,0x000c0000,0x00000000,0x00042c80,
+/* 0039 */ 0x0001dec1,0x000e488c,0x00031114,0x00000000,
+/* 003B */ 0x0004f5c2,0x00000000,0x0003640a,0x00000000,
+/* 003D */ 0x00000000,0x000e5084,0x00000000,0x000eb844,
+/* 003F */ 0x00007001,0x00000000,0x00000734,0x00001000,
+/* 0041 */ 0x00010705,0x000a6880,0x00006a88,0x000c75c4,
+/* SPDIFITASK */
+/* 0043 */ 0x0006a108,0x000cf2c4,0x0004f4c0,0x000d5384,
+/* 0045 */ 0x0007e48a,0x00000000,0x00067718,0x00001000,
+/* 0047 */ 0x0007a418,0x00001000,0x0007221a,0x00000000,
+/* 0049 */ 0x0005d402,0x00014500,0x000b8630,0x00001002,
+/* 004B */ 0x00004418,0x00001780,0x000e243d,0x000d394a,
+/* 004D */ 0x00049705,0x00000000,0x0007d530,0x000b4240,
+/* 004F */ 0x000ac0f2,0x00001002,0x00014414,0x00000000,
+/* 0051 */ 0x00004c90,0x00001000,0x0005d705,0x00000000,
+/* 0053 */ 0x00004f25,0x00098240,0x00004725,0x00000000,
+/* 0055 */ 0x0000e48a,0x00000000,0x00027295,0x0009c2c0,
+/* 0057 */ 0x0007df25,0x00000000,0x000ac030,0x00001003,
+/* 0059 */ 0x0005f718,0x000fe798,0x00029314,0x000bcb80,
+/* 005B */ 0x00000930,0x000b0e00,0x0004f5c0,0x000de204,
+/* 005D */ 0x000884a0,0x00001003,0x0007cf25,0x000e3560,
+/* 005F */ 0x00049118,0x00000000,0x00049118,0x000d888a,
+/* 0061 */ 0x0007dd02,0x000c6efa,0x0000c434,0x00030040,
+/* 0063 */ 0x000fda82,0x000c2312,0x000fdc0e,0x00001001,
+/* 0065 */ 0x00083402,0x000c2b92,0x000706b0,0x00001003,
+/* 0067 */ 0x00075a82,0x00000000,0x0000d625,0x000b0940,
+/* 0069 */ 0x0000840e,0x00001002,0x0000aabc,0x000c511e,
+/* 006B */ 0x00078730,0x00001003,0x0000aaf4,0x000e910a,
+/* 006D */ 0x0004628a,0x00000000,0x00006aca,0x00000000,
+/* 006F */ 0x00000930,0x00000000,0x0004f5c0,0x00069c80,
+/* 0071 */ 0x00046ac0,0x00000000,0x0003c40a,0x000fc898,
+/* 0073 */ 0x00049118,0x00090e00,0x0006c10a,0x00000000,
+/* 0075 */ 0x00000000,0x000e5084,0x00000000,0x000eb844,
+/* 0077 */ 0x00007001,0x00000000,0x00000734,0x00001000,
+/* 0079 */ 0x00010705,0x000a6880,0x00006a88,0x000c75c4,
+/* SPDIFOTASK */
+/* 007B */ 0x0006a108,0x000c0000,0x0004f4c0,0x000c3245,
+/* 007D */ 0x0000a418,0x00001000,0x0003a20a,0x00000000,
+/* 007F */ 0x00004418,0x00001380,0x000e243d,0x000d394a,
+/* 0081 */ 0x000c9705,0x000def92,0x0008c030,0x00001004,
+/* 0083 */ 0x0005f718,0x000fe798,0x00000000,0x000c0000,
+/* 0085 */ 0x00005725,0x00000000,0x000704a0,0x00001004,
+/* 0087 */ 0x00029314,0x000b4780,0x0003cf25,0x000b8600,
+/* 0089 */ 0x00000000,0x00000000,0x00000000,0x000c0000,
+/* 008B */ 0x00000000,0x00042c80,0x0001dec1,0x000e488c,
+/* 008D */ 0x00031114,0x00000000,0x0004f5c2,0x00000000,
+/* 008F */ 0x0004a918,0x00098600,0x0006c28a,0x00000000,
+/* 0091 */ 0x00000000,0x000e5084,0x00000000,0x000eb844,
+/* 0093 */ 0x00007001,0x00000000,0x00000734,0x00001000,
+/* 0095 */ 0x00010705,0x000a6880,0x00006a88,0x000c75c4,
+/* ASYNCHFGTXCODE */
+/* 0097 */ 0x0002a880,0x000b4e40,0x00042214,0x000e5548,
+/* 0099 */ 0x000542bf,0x00000000,0x00000000,0x000481c0,
+/* 009B */ 0x00000000,0x00000000,0x00000000,0x00000030,
+/* 009D */ 0x0000072d,0x000fbf8a,0x00077f94,0x000ea7df,
+/* 009F */ 0x0002ac95,0x000d3145,0x00002731,0x00001400,
+/* 00A1 */ 0x00006288,0x000c71c4,0x00014108,0x000e6044,
+/* 00A3 */ 0x00035408,0x00000000,0x00025418,0x000a0ec0,
+/* 00A5 */ 0x0001443d,0x000ca21e,0x00046595,0x000d730c,
+/* 00A7 */ 0x0006538e,0x00000000,0x00064630,0x00001005,
+/* 00A9 */ 0x000e7b0e,0x000df782,0x000746b0,0x00001005,
+/* 00AB */ 0x00036f05,0x000c0000,0x00043695,0x000d598c,
+/* 00AD */ 0x0005331a,0x000f2185,0x00000000,0x00000000,
+/* 00AF */ 0x000007ae,0x000bdb00,0x00040630,0x00001400,
+/* 00B1 */ 0x0005e708,0x000c0000,0x0007ef30,0x000b1c00,
+/* 00B3 */ 0x000d86a0,0x00001005,0x00066408,0x000c0000,
+/* 00B5 */ 0x00000000,0x00000000,0x00021843,0x00000000,
+/* 00B7 */ 0x00000cac,0x00062c00,0x00001dac,0x00063400,
+/* 00B9 */ 0x00002cac,0x0006cc80,0x000db943,0x000e5ca1,
+/* 00BB */ 0x00000000,0x00000000,0x0006680a,0x000f3205,
+/* 00BD */ 0x00042730,0x00001400,
+/* ASYNCHFGRXCODE */
+/* 00BE */ 0x00014108,0x000f2204,0x00025418,0x000a2ec0,
+/* 00C0 */ 0x00015dbd,0x00038100,0x00015dbc,0x00000000,
+/* 00C2 */ 0x0005e415,0x00034880,0x0001258a,0x000d730c,
+/* 00C4 */ 0x0006538e,0x000baa40,0x00060630,0x00001006,
+/* 00C6 */ 0x00067b0e,0x000ac380,0x0003ef05,0x00000000,
+/* 00C8 */ 0x0000f734,0x0001c300,0x000586b0,0x00001400,
+/* 00CA */ 0x000b6f05,0x000c3a00,0x00048f05,0x00000000,
+/* 00CC */ 0x0005b695,0x0008c380,0x0002058e,0x00000000,
+/* 00CE */ 0x000500b0,0x00001400,0x0002b318,0x000e998d,
+/* 00D0 */ 0x0006430a,0x00000000,0x00000000,0x000ef384,
+/* 00D2 */ 0x00004725,0x000c0000,0x00000000,0x000f3204,
+/* 00D4 */ 0x00004f25,0x000c0000,0x00080000,0x000e5ca1,
+/* 00D6 */ 0x000cb943,0x000e5ca1,0x0004b943,0x00000000,
+/* 00D8 */ 0x00040730,0x00001400,0x000cb943,0x000e5ca1,
+/* 00DA */ 0x0004b943,0x00000000
+};
+/* #CODE_END */
+
+static segment_desc_t cwcasync_segments[] = {
+  { SEGTYPE_SP_PROGRAM, 0x00000000, 0x000001b6, cwcasync_code },
+};
+
+static dsp_module_desc_t cwcasync_module = {
+  "cwcasync",
+  {
+    32,
+    cwcasync_symbols
+  },
+  1,
+  cwcasync_segments,
+};
+
+#endif /* __HEADER_cwcasync_H__ */
diff -Nru a/sound/pci/cs46xx/imgs/cwcbinhack.h b/sound/pci/cs46xx/imgs/cwcbinhack.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/cs46xx/imgs/cwcbinhack.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,48 @@
+/* generated by Benny 
+   MODIFY ON YOUR OWN RISK */
+
+#ifndef __HEADER_cwcbinhack_H__
+#define __HEADER_cwcbinhack_H__
+
+static symbol_entry_t cwcbinhack_symbols[] = {
+  { 0x02c8, "OVERLAYBEGINADDRESS",0x00 },
+  { 0x02c8, "MAGICSNOOPTASK",0x03 },
+  { 0x0308, "#CODE_END",0x00 },
+}; /* cwcbinhack symbols */
+
+static u32 cwcbinhack_code[] = {
+  /* 0x02c8 */
+  0x0007bfb0,0x000bc240,0x00000c2e,0x000c6084, /* 1 */
+  0x000b8630,0x00001016,0x00006408,0x000efb84, /* 2 */
+  0x00016008,0x00000000,0x0001c088,0x000c0000, /* 3 */
+  0x000fc908,0x000e3392,0x0005f488,0x000efb84, /* 4 */
+  0x0001d402,0x000b2e00,0x0003d418,0x00001000, /* 5 */
+  0x0008d574,0x000c4293,0x00065625,0x000ea30e, /* 6 */
+  0x00096c01,0x000c6f92,0x0001a58a,0x000c6085, /* 7 */
+  0x00002f43,0x00000000,0x000e03a0,0x00001016, /* 8 */
+  0x0005e608,0x000c0000,0x00000000,0x00000000, /* 9 */
+  0x000ca108,0x000dcca1,0x00003bac,0x000c3205, /* 10 */
+  0x00073843,0x00000000,0x00010730,0x00001017, /* 11 */
+  0x0001600a,0x000c0000,0x00057488,0x00000000, /* 12 */
+  0x00000000,0x000e5084,0x00000000,0x000eba44, /* 13 */
+  0x00087401,0x000e4782,0x00000734,0x00001000, /* 14 */
+  0x00010705,0x000a6880,0x00006a88,0x000c75c4, /* 15 */
+  0x00000000,0x00000000,0x00000000,0x00000000, /* 16 */
+};
+/* #CODE_END */
+
+static segment_desc_t cwcbinhack_segments[] = {
+  { SEGTYPE_SP_PROGRAM, 0x00000000, 64, cwcbinhack_code },
+};
+
+static dsp_module_desc_t cwcbinhack_module = {
+  "cwcbinhack",
+  {
+    3,
+    cwcbinhack_symbols
+  },
+  1,
+  cwcbinhack_segments,
+};
+
+#endif /* __HEADER_cwcbinhack_H__ */
diff -Nru a/sound/pci/cs46xx/imgs/cwcemb80.h b/sound/pci/cs46xx/imgs/cwcemb80.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/cs46xx/imgs/cwcemb80.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,1607 @@
+/* generated from cwcemb80.osp DO NOT MODIFY */
+
+#ifndef __HEADER_cwcemb80_H__
+#define __HEADER_cwcemb80_H__
+
+static symbol_entry_t cwcemb80_symbols[] = {
+  { 0x0000, "BEGINADDRESS",0x00 },
+  { 0x8000, "EXECCHILD",0x03 },
+  { 0x8001, "EXECCHILD_98",0x03 },
+  { 0x8003, "EXECCHILD_PUSH1IND",0x03 },
+  { 0x8008, "EXECSIBLING",0x03 },
+  { 0x800a, "EXECSIBLING_298",0x03 },
+  { 0x800b, "EXECSIBLING_2IND1",0x03 },
+  { 0x8010, "TIMINGMASTER",0x03 },
+  { 0x804f, "S16_CODECINPUTTASK",0x03 },
+  { 0x805e, "PCMSERIALINPUTTASK",0x03 },
+  { 0x806d, "S16_MIX_TO_OSTREAM",0x03 },
+  { 0x809a, "S16_MIX",0x03 },
+  { 0x80bb, "S16_UPSRC",0x03 },
+  { 0x813b, "MIX3_EXP",0x03 },
+  { 0x8164, "DECIMATEBYPOW2",0x03 },
+  { 0x8197, "VARIDECIMATE",0x03 },
+  { 0x81f2, "_3DINPUTTASK",0x03 },
+  { 0x820a, "_3DPRLGCINPTASK",0x03 },
+  { 0x8227, "_3DSTEREOINPUTTASK",0x03 },
+  { 0x8242, "_3DOUTPUTTASK",0x03 },
+  { 0x82c4, "HRTF_MORPH_TASK",0x03 },
+  { 0x82c6, "WAIT4DATA",0x03 },
+  { 0x82fa, "PROLOGIC",0x03 },
+  { 0x8496, "DECORRELATOR",0x03 },
+  { 0x84a4, "STEREO2MONO",0x03 },
+  { 0x0070, "SPOSCB",0x02 },
+  { 0x0105, "TASKTREETHREAD",0x03 },
+  { 0x0136, "TASKTREEHEADERCODE",0x03 },
+  { 0x013f, "FGTASKTREEHEADERCODE",0x03 },
+  { 0x0163, "NULLALGORITHM",0x03 },
+  { 0x0167, "HFGEXECCHILD",0x03 },
+  { 0x0168, "HFGEXECCHILD_98",0x03 },
+  { 0x016a, "HFGEXECCHILD_PUSH1IND",0x03 },
+  { 0x016d, "HFGEXECSIBLING",0x03 },
+  { 0x016f, "HFGEXECSIBLING_298",0x03 },
+  { 0x0170, "HFGEXECSIBLING_2IND1",0x03 },
+  { 0x0173, "S16_CODECOUTPUTTASK",0x03 },
+  { 0x018e, "#CODE_END",0x00 },
+}; /* cwcemb80 symbols */
+
+static u32 cwcemb80_code[] = {
+/* BEGINADDRESS */
+/* 0000 */ 0x00040730,0x00001002,0x000f619e,0x00001003,
+/* 0002 */ 0x00001705,0x00001400,0x000a411e,0x00001003,
+/* 0004 */ 0x00040730,0x00001002,0x000f619e,0x00001003,
+/* 0006 */ 0x00009705,0x00001400,0x000a411e,0x00001003,
+/* 0008 */ 0x00040730,0x00001002,0x000f619e,0x00001003,
+/* 000A */ 0x00011705,0x00001400,0x000a411e,0x00001003,
+/* 000C */ 0x00040730,0x00001002,0x000f619e,0x00001003,
+/* 000E */ 0x00019705,0x00001400,0x000a411e,0x00001003,
+/* 0010 */ 0x00040730,0x00001002,0x000f619e,0x00001003,
+/* 0012 */ 0x00021705,0x00001400,0x000a411e,0x00001003,
+/* 0014 */ 0x00040730,0x00001002,0x000f619e,0x00001003,
+/* 0016 */ 0x00029705,0x00001400,0x000a411e,0x00001003,
+/* 0018 */ 0x00040730,0x00001002,0x000f619e,0x00001003,
+/* 001A */ 0x00031705,0x00001400,0x000a411e,0x00001003,
+/* 001C */ 0x00040730,0x00001002,0x000f619e,0x00001003,
+/* 001E */ 0x00039705,0x00001400,0x000a411e,0x00001003,
+/* 0020 */ 0x000fe19e,0x00001003,0x0009c730,0x00001003,
+/* 0022 */ 0x0008e19c,0x00001003,0x000083c1,0x00093040,
+/* 0024 */ 0x00098730,0x00001002,0x000ee19e,0x00001003,
+/* 0026 */ 0x00009705,0x00001400,0x000a211e,0x00001003,
+/* 0028 */ 0x00098730,0x00001002,0x000ee19e,0x00001003,
+/* 002A */ 0x00011705,0x00001400,0x000a211e,0x00001003,
+/* 002C */ 0x00098730,0x00001002,0x000ee19e,0x00001003,
+/* 002E */ 0x00019705,0x00001400,0x000a211e,0x00001003,
+/* 0030 */ 0x00098730,0x00001002,0x000ee19e,0x00001003,
+/* 0032 */ 0x00021705,0x00001400,0x000a211e,0x00001003,
+/* 0034 */ 0x00098730,0x00001002,0x000ee19e,0x00001003,
+/* 0036 */ 0x00029705,0x00001400,0x000a211e,0x00001003,
+/* 0038 */ 0x00098730,0x00001002,0x000ee19e,0x00001003,
+/* 003A */ 0x00031705,0x00001400,0x000a211e,0x00001003,
+/* 003C */ 0x00098730,0x00001002,0x000ee19e,0x00001003,
+/* 003E */ 0x00039705,0x00001400,0x000a211e,0x00001003,
+/* 0040 */ 0x0000a730,0x00001008,0x000e2730,0x00001002,
+/* 0042 */ 0x0000a731,0x00001002,0x0000a731,0x00001002,
+/* 0044 */ 0x0000a731,0x00001002,0x0000a731,0x00001002,
+/* 0046 */ 0x0000a731,0x00001002,0x0000a731,0x00001002,
+/* 0048 */ 0x00000000,0x00000000,0x000f619c,0x00001003,
+/* 004A */ 0x0007f801,0x000c0000,0x00000037,0x00001000,
+/* 004C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 004E */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0050 */ 0x00000000,0x000c0000,0x00000000,0x00000000,
+/* 0052 */ 0x0000373c,0x00001000,0x00000000,0x00000000,
+/* 0054 */ 0x000ee19c,0x00001003,0x0007f801,0x000c0000,
+/* 0056 */ 0x00000037,0x00001000,0x00000000,0x00000000,
+/* 0058 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 005A */ 0x00000000,0x00000000,0x0000273c,0x00001000,
+/* 005C */ 0x00000033,0x00001000,0x000e679e,0x00001003,
+/* 005E */ 0x00007705,0x00001400,0x000ac71e,0x00001003,
+/* 0060 */ 0x00087fc1,0x000c3be0,0x0007f801,0x000c0000,
+/* 0062 */ 0x00000037,0x00001000,0x00000000,0x00000000,
+/* 0064 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0066 */ 0x00000000,0x00000000,0x0000a730,0x00001003,
+/* 0068 */ 0x00000033,0x00001000,0x0007f801,0x000c0000,
+/* 006A */ 0x00000037,0x00001000,0x00000000,0x00000000,
+/* 006C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 006E */ 0x00000000,0x00000000,0x00000000,0x000c0000,
+/* 0070 */ 0x00000032,0x00001000,0x0000273d,0x00001000,
+/* 0072 */ 0x0004a730,0x00001003,0x00000f41,0x00097140,
+/* 0074 */ 0x0000a841,0x0009b240,0x0000a0c1,0x0009f040,
+/* 0076 */ 0x0001c641,0x00093540,0x0001cec1,0x0009b5c0,
+/* 0078 */ 0x00000000,0x00000000,0x0001bf05,0x0003fc40,
+/* 007A */ 0x00002725,0x000aa400,0x00013705,0x00093a00,
+/* 007C */ 0x0000002e,0x0009d6c0,0x00038630,0x00001004,
+/* 007E */ 0x0004ef0a,0x000eb785,0x0003fc8a,0x00000000,
+/* 0080 */ 0x00000000,0x000c70e0,0x0007d182,0x0002c640,
+/* 0082 */ 0x00000630,0x00001004,0x000799b8,0x0002c6c0,
+/* 0084 */ 0x00031705,0x00092240,0x00039f05,0x000932c0,
+/* 0086 */ 0x0003520a,0x00000000,0x00040731,0x0000100b,
+/* 0088 */ 0x00010705,0x000b20c0,0x00000000,0x000eba44,
+/* 008A */ 0x00032108,0x000c60c4,0x00065208,0x000c2917,
+/* 008C */ 0x000406b0,0x00001007,0x00012f05,0x00036880,
+/* 008E */ 0x0002818e,0x000c0000,0x0004410a,0x00000000,
+/* 0090 */ 0x00040630,0x00001007,0x00029705,0x000c0000,
+/* 0092 */ 0x00000000,0x00000000,0x00003fc1,0x0003fc40,
+/* 0094 */ 0x000037c1,0x00091b40,0x00003fc1,0x000911c0,
+/* 0096 */ 0x000037c1,0x000957c0,0x00003fc1,0x000951c0,
+/* 0098 */ 0x000037c1,0x00000000,0x00003fc1,0x000991c0,
+/* 009A */ 0x000037c1,0x00000000,0x00003fc1,0x0009d1c0,
+/* 009C */ 0x000037c1,0x00000000,0x0001ccc1,0x000915c0,
+/* 009E */ 0x0001c441,0x0009d800,0x0009cdc1,0x00091240,
+/* 00A0 */ 0x0001c541,0x00091d00,0x0009cfc1,0x00095240,
+/* 00A2 */ 0x0001c741,0x00095c80,0x000e8ca9,0x00099240,
+/* 00A4 */ 0x000e85ad,0x00095640,0x00069ca9,0x00099d80,
+/* 00A6 */ 0x000e952d,0x00099640,0x000eaca9,0x0009d6c0,
+/* 00A8 */ 0x000ea5ad,0x00091a40,0x0006bca9,0x0009de80,
+/* 00AA */ 0x000eb52d,0x00095a40,0x000ecca9,0x00099ac0,
+/* 00AC */ 0x000ec5ad,0x0009da40,0x000edca9,0x0009d300,
+/* 00AE */ 0x000a6e0a,0x00001000,0x000ed52d,0x00091e40,
+/* 00B0 */ 0x000eeca9,0x00095ec0,0x000ee5ad,0x00099e40,
+/* 00B2 */ 0x0006fca9,0x00002500,0x000fb208,0x000c59a0,
+/* 00B4 */ 0x000ef52d,0x0009de40,0x00068ca9,0x000912c1,
+/* 00B6 */ 0x000683ad,0x00095241,0x00020f05,0x000991c1,
+/* 00B8 */ 0x00000000,0x00000000,0x00086f88,0x00001000,
+/* 00BA */ 0x0009cf81,0x000b5340,0x0009c701,0x000b92c0,
+/* 00BC */ 0x0009de81,0x000bd300,0x0009d601,0x000b1700,
+/* 00BE */ 0x0001fd81,0x000b9d80,0x0009f501,0x000b57c0,
+/* 00C0 */ 0x000a0f81,0x000bd740,0x00020701,0x000b5c80,
+/* 00C2 */ 0x000a1681,0x000b97c0,0x00021601,0x00002500,
+/* 00C4 */ 0x000a0701,0x000b9b40,0x000a0f81,0x000b1bc0,
+/* 00C6 */ 0x00021681,0x00002d00,0x00020f81,0x000bd800,
+/* 00C8 */ 0x000a0701,0x000b5bc0,0x00021601,0x00003500,
+/* 00CA */ 0x000a0f81,0x000b5f40,0x000a0701,0x000bdbc0,
+/* 00CC */ 0x00021681,0x00003d00,0x00020f81,0x000b1d00,
+/* 00CE */ 0x000a0701,0x000b1fc0,0x00021601,0x00020500,
+/* 00D0 */ 0x00020f81,0x000b1341,0x000a0701,0x000b9fc0,
+/* 00D2 */ 0x00021681,0x00020d00,0x00020f81,0x000bde80,
+/* 00D4 */ 0x000a0701,0x000bdfc0,0x00021601,0x00021500,
+/* 00D6 */ 0x00020f81,0x000b9341,0x00020701,0x000b53c1,
+/* 00D8 */ 0x00021681,0x00021d00,0x000a0f81,0x000d0380,
+/* 00DA */ 0x0000b601,0x000b15c0,0x00007b01,0x00000000,
+/* 00DC */ 0x00007b81,0x000bd1c0,0x00007b01,0x00000000,
+/* 00DE */ 0x00007b81,0x000b91c0,0x00007b01,0x000b57c0,
+/* 00E0 */ 0x00007b81,0x000b51c0,0x00007b01,0x000b1b40,
+/* 00E2 */ 0x00007b81,0x000b11c0,0x00087b01,0x000c3dc0,
+/* 00E4 */ 0x0007e488,0x000d7e45,0x00000000,0x000d7a44,
+/* 00E6 */ 0x0007e48a,0x00000000,0x00011f05,0x00084080,
+/* 00E8 */ 0x00000000,0x00000000,0x00001705,0x000b3540,
+/* 00EA */ 0x00008a01,0x000bf040,0x00007081,0x000bb5c0,
+/* 00EC */ 0x00055488,0x00000000,0x0000d482,0x0003fc40,
+/* 00EE */ 0x0003fc88,0x00000000,0x0001e401,0x000b3a00,
+/* 00F0 */ 0x0001ec81,0x000bd6c0,0x0004ef08,0x000eb784,
+/* 00F2 */ 0x000c86b0,0x00001007,0x00008281,0x000bb240,
+/* 00F4 */ 0x0000b801,0x000b7140,0x00007888,0x00000000,
+/* 00F6 */ 0x0000073c,0x00001000,0x0007f188,0x000c0000,
+/* 00F8 */ 0x00000000,0x00000000,0x00055288,0x000c555c,
+/* 00FA */ 0x0005528a,0x000c0000,0x0009fa88,0x000c5d00,
+/* 00FC */ 0x0000fa88,0x00000000,0x00000032,0x00001000,
+/* 00FE */ 0x0000073d,0x00001000,0x0007f188,0x000c0000,
+/* 0100 */ 0x00000000,0x00000000,0x0008c01c,0x00001003,
+/* 0102 */ 0x00002705,0x00001008,0x0008b201,0x000c1392,
+/* 0104 */ 0x0000ba01,0x00000000,
+/* TASKTREETHREAD */
+/* 0105 */ 0x00008731,0x00001400,0x0004c108,0x000fe0c4,
+/* 0107 */ 0x00057488,0x00000000,0x000a6388,0x00001001,
+/* 0109 */ 0x0008b334,0x000bc141,0x0003020e,0x00000000,
+/* 010B */ 0x000886b0,0x00001008,0x00003625,0x000c5dfa,
+/* 010D */ 0x000a638a,0x00001001,0x0008020e,0x00001002,
+/* 010F */ 0x0008a6b0,0x00001008,0x0007f301,0x00000000,
+/* 0111 */ 0x00000000,0x00000000,0x00002725,0x000a8c40,
+/* 0113 */ 0x000000ae,0x00000000,0x000d8630,0x00001008,
+/* 0115 */ 0x00000000,0x000c74e0,0x0007d182,0x0002d640,
+/* 0117 */ 0x000a8630,0x00001008,0x000799b8,0x0002d6c0,
+/* 0119 */ 0x0000748a,0x000c3ec5,0x0007420a,0x000c0000,
+/* 011B */ 0x00062208,0x000c4117,0x00070630,0x00001009,
+/* 011D */ 0x00000000,0x000c0000,0x0001022e,0x00000000,
+/* 011F */ 0x0003a630,0x00001009,0x00000000,0x000c0000,
+/* 0121 */ 0x00000036,0x00001000,0x00000000,0x00000000,
+/* 0123 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0125 */ 0x00000000,0x00000000,0x0002a730,0x00001008,
+/* 0127 */ 0x0007f801,0x000c0000,0x00000037,0x00001000,
+/* 0129 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 012B */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 012D */ 0x0002a730,0x00001008,0x00000033,0x00001000,
+/* 012F */ 0x0002a705,0x00001008,0x00007a01,0x000c0000,
+/* 0131 */ 0x000e6288,0x000d550a,0x0006428a,0x00000000,
+/* 0133 */ 0x00060730,0x0000100a,0x00000000,0x000c0000,
+/* 0135 */ 0x00000000,0x00000000,
+/* TASKTREEHEADERCODE */
+/* 0136 */ 0x0007aab0,0x00034880,0x00078fb0,0x0000100b,
+/* 0138 */ 0x00057488,0x00000000,0x00033b94,0x00081140,
+/* 013A */ 0x000183ae,0x00000000,0x000786b0,0x0000100b,
+/* 013C */ 0x00022f05,0x000c3545,0x0000eb8a,0x00000000,
+/* 013E */ 0x00042731,0x00001003,
+/* FGTASKTREEHEADERCODE */
+/* 013F */ 0x0007aab0,0x00034880,0x00048fb0,0x0000100a,
+/* 0141 */ 0x00057488,0x00000000,0x00033b94,0x00081140,
+/* 0143 */ 0x000183ae,0x00000000,0x000806b0,0x0000100b,
+/* 0145 */ 0x00022f05,0x00000000,0x00007401,0x00091140,
+/* 0147 */ 0x00048f05,0x000951c0,0x00042731,0x00001003,
+/* 0149 */ 0x0000473d,0x00001000,0x000f19b0,0x000bbc47,
+/* 014B */ 0x00080000,0x000bffc7,0x000fe19e,0x00001003,
+/* 014D */ 0x00000000,0x00000000,0x0008e19c,0x00001003,
+/* 014F */ 0x000083c1,0x00093040,0x00000f41,0x00097140,
+/* 0151 */ 0x0000a841,0x0009b240,0x0000a0c1,0x0009f040,
+/* 0153 */ 0x0001c641,0x00093540,0x0001cec1,0x0009b5c0,
+/* 0155 */ 0x00000000,0x000fdc44,0x00055208,0x00000000,
+/* 0157 */ 0x00010705,0x000a2880,0x0000a23a,0x00093a00,
+/* 0159 */ 0x0003fc8a,0x000df6c5,0x0004ef0a,0x000c0000,
+/* 015B */ 0x00012f05,0x00036880,0x00065308,0x000c2997,
+/* 015D */ 0x000d86b0,0x0000100a,0x0004410a,0x000d40c7,
+/* 015F */ 0x00000000,0x00000000,0x00080730,0x00001004,
+/* 0161 */ 0x00056f0a,0x000ea105,0x00000000,0x00000000,
+/* NULLALGORITHM */
+/* 0163 */ 0x0000473d,0x00001000,0x000f19b0,0x000bbc47,
+/* 0165 */ 0x00080000,0x000bffc7,0x0000273d,0x00001000,
+/* HFGEXECCHILD */
+/* 0167 */ 0x00000000,0x000eba44,
+/* HFGEXECCHILD_98 */
+/* 0168 */ 0x00048f05,0x0000f440,0x00007401,0x0000f7c0,
+/* HFGEXECCHILD_PUSH1IND */
+/* 016A */ 0x00000734,0x00001000,0x00010705,0x000a6880,
+/* 016C */ 0x00006a88,0x000c75c4,
+/* HFGEXECSIBLING */
+/* 016D */ 0x00000000,0x000e5084,0x00000000,0x000eba44,
+/* HFGEXECSIBLING_298 */
+/* 016F */ 0x00087401,0x000e4782,
+/* HFGEXECSIBLING_2IND1 */
+/* 0170 */ 0x00000734,0x00001000,0x00010705,0x000a6880,
+/* 0172 */ 0x00006a88,0x000c75c4,
+/* S16_CODECOUTPUTTASK */
+/* 0173 */ 0x0007c108,0x000c0000,0x0007e721,0x000bed40,
+/* 0175 */ 0x00005f25,0x000badc0,0x0003ba97,0x000beb80,
+/* 0177 */ 0x00065590,0x000b2e00,0x00033217,0x00003ec0,
+/* 0179 */ 0x00065590,0x000b8e40,0x0003ed80,0x000491c0,
+/* 017B */ 0x00073fb0,0x00074c80,0x000283a0,0x0000100c,
+/* 017D */ 0x000ee388,0x00042970,0x00008301,0x00021ef2,
+/* 017F */ 0x000b8f14,0x0000000f,0x000c4d8d,0x0000001b,
+/* 0181 */ 0x000d6dc2,0x000e06c6,0x000032ac,0x000c3916,
+/* 0183 */ 0x0004edc2,0x00074c80,0x00078898,0x00001000,
+/* 0185 */ 0x00038894,0x00000032,0x000c4d8d,0x00092e1b,
+/* 0187 */ 0x000d6dc2,0x000e06c6,0x0004edc2,0x000c1956,
+/* 0189 */ 0x0000722c,0x00034a00,0x00041705,0x0009ed40,
+/* 018B */ 0x00058730,0x00001400,0x000d7488,0x000c3a00,
+/* 018D */ 0x00048f05,0x00000000
+};
+/* #CODE_END */
+
+static u32 cwcemb80_parameter[] = {
+/* 0000 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0004 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0008 */ 0x00000000,0x00000000,0x00000163,0x00000000,
+/* 000C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0010 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0014 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0018 */ 0x00000000,0x00200040,0x00008010,0x00000000,
+/* 001C */ 0x00000000,0x80000001,0x00000001,0x00060000,
+/* 0020 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0024 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0028 */ 0x00000000,0x00900080,0x00000173,0x00000000,
+/* 002C */ 0x00000000,0x00000010,0x00800000,0x00900000,
+/* 0030 */ 0xf2c0000f,0x00000200,0x00000000,0x00010600,
+/* 0034 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0038 */ 0x00000000,0x00000000,0x00000163,0x330300c2,
+/* 003C */ 0x06000000,0x00000000,0x80008000,0x80008000,
+/* 0040 */ 0x3fc0000f,0x00000301,0x00010400,0x00000000,
+/* 0044 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0048 */ 0x00000000,0x00b00000,0x00d0806d,0x330480c3,
+/* 004C */ 0x04800000,0x00000001,0x00800001,0x0000ffff,
+/* 0050 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0054 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0058 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 005C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0060 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0064 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0068 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 006C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0070 */ 0x066a0600,0x06350070,0x0000929d,0x929d929d,
+/* 0074 */ 0x00000000,0x0000735a,0x00000600,0x00000000,
+/* 0078 */ 0x929d735a,0x00000000,0x00010000,0x735a735a,
+/* 007C */ 0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
+/* 0080 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0084 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0088 */ 0x00000000,0x00000000,0x0000804f,0x000000c3,
+/* 008C */ 0x05000000,0x00a00010,0x00000000,0x80008000,
+/* 0090 */ 0x00000000,0x00000000,0x00000700,0x00000000,
+/* 0094 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0098 */ 0x00000080,0x00a00000,0x0000809a,0x000000c2,
+/* 009C */ 0x07400000,0x00000000,0x80008000,0xffffffff,
+/* 00A0 */ 0x00c80028,0x00005555,0x00000000,0x000107a0,
+/* 00A4 */ 0x00c80028,0x000000c2,0x06800000,0x00000000,
+/* 00A8 */ 0x06e00080,0x00300000,0x000080bb,0x000000c9,
+/* 00AC */ 0x07a00000,0x04000000,0x80008000,0xffffffff,
+/* 00B0 */ 0x00c80028,0x00005555,0x00000000,0x00000780,
+/* 00B4 */ 0x00c80028,0x000000c5,0xff800000,0x00000000,
+/* 00B8 */ 0x00640080,0x00c00000,0x00008197,0x000000c9,
+/* 00BC */ 0x07800000,0x04000000,0x80008000,0xffffffff,
+/* 00C0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00C4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00C8 */ 0x00000000,0x00000000,0x0000805e,0x000000c1,
+/* 00CC */ 0x00000000,0x00800000,0x80008000,0x80008000,
+/* 00D0 */ 0x00020000,0x0000ffff,0x00000000,0x00000000,
+/* 00D4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00D8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00DC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00E0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00E4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00E8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00EC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00F0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00F4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00F8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00FC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0100 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0104 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0108 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 010C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0110 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0114 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0118 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 011C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0120 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0124 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0128 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 012C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0130 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0134 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0138 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 013C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0140 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0144 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0148 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 014C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0150 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0154 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0158 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 015C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0160 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0164 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0168 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 016C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0170 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0174 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0178 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 017C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0180 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0184 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0188 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 018C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0190 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0194 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0198 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 019C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01A0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01A4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01A8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01AC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01B0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01B4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01B8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01BC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01C0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01C4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01C8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01CC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01D0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01D4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01D8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01DC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01E0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01E4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01E8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01EC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01F0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01F4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01F8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01FC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0200 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0204 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0208 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 020C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0210 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0214 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0218 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 021C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0220 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0224 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0228 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 022C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0230 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0234 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0238 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 023C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0240 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0244 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0248 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 024C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0250 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0254 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0258 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 025C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0260 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0264 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0268 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 026C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0270 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0274 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0278 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 027C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0280 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0284 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0288 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 028C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0290 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0294 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0298 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 029C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02A0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02A4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02A8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02AC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02B0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02B4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02B8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02BC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02C0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02C4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02C8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02CC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02D0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02D4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02D8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02DC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02E0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02E4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02E8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02EC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02F0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02F4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02F8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02FC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0300 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0304 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0308 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 030C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0310 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0314 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0318 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 031C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0320 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0324 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0328 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 032C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0330 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0334 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0338 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 033C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0340 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0344 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0348 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 034C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0350 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0354 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0358 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 035C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0360 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0364 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0368 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 036C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0370 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0374 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0378 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 037C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0380 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0384 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0388 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 038C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0390 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0394 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0398 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 039C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03A0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03A4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03A8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03AC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03B0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03B4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03B8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03BC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03C0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03C4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03C8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03CC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03D0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03D4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03D8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03DC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03E0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03E4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03E8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03EC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03F0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03F4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03F8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03FC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0400 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0404 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0408 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 040C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0410 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0414 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0418 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 041C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0420 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0424 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0428 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 042C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0430 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0434 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0438 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 043C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0440 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0444 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0448 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 044C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0450 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0454 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0458 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 045C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0460 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0464 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0468 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 046C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0470 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0474 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0478 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 047C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0480 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0484 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0488 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 048C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0490 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0494 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0498 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 049C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04A0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04A4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04A8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04AC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04B0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04B4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04B8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04BC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04C0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04C4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04C8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04CC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04D0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04D4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04D8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04DC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04E0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04E4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04E8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04EC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04F0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04F4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04F8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04FC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0500 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0504 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0508 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 050C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0510 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0514 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0518 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 051C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0520 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0524 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0528 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 052C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0530 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0534 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0538 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 053C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0540 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0544 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0548 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 054C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0550 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0554 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0558 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 055C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0560 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0564 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0568 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 056C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0570 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0574 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0578 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 057C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0580 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0584 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0588 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 058C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0590 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0594 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0598 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 059C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05A0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05A4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05A8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05AC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05B0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05B4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05B8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05BC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05C0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05C4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05C8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05CC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05D0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05D4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05D8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05DC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05E0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05E4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05E8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05EC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05F0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05F4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05F8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05FC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0600 */ 0x929d0600,0x929d929d,0x929d929d,0x929d0000,
+/* 0604 */ 0x929d929d,0x929d929d,0x929d929d,0x929d929d,
+/* 0608 */ 0x929d929d,0x00100635,0x060b013f,0x00000004,
+/* 060C */ 0x00000001,0x007a0002,0x00000000,0x066e0610,
+/* 0610 */ 0x0105929d,0x929d929d,0x929d929d,0x929d929d,
+/* 0614 */ 0x929d929d,0xa431ac75,0x0001735a,0xa431ac75,
+/* 0618 */ 0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
+/* 061C */ 0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
+/* 0620 */ 0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
+/* 0624 */ 0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
+/* 0628 */ 0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
+/* 062C */ 0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
+/* 0630 */ 0xa431ac75,0xa431ac75,0xa431ac75,0x735a0051,
+/* 0634 */ 0x00000000,0x929d929d,0x929d929d,0x929d929d,
+/* 0638 */ 0x929d929d,0x929d929d,0x929d929d,0x929d929d,
+/* 063C */ 0x929d929d,0x929d929d,0x00000000,0x06400136,
+/* 0640 */ 0x0000270f,0x00010000,0x007a0000,0x00000000,
+/* 0644 */ 0x068e0645,0x0105929d,0x929d929d,0x929d929d,
+/* 0648 */ 0x929d929d,0x929d929d,0xa431ac75,0x0001735a,
+/* 064C */ 0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
+/* 0650 */ 0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
+/* 0654 */ 0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
+/* 0658 */ 0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
+/* 065C */ 0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
+/* 0660 */ 0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
+/* 0664 */ 0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
+/* 0668 */ 0x735a0100,0x00000000,0x00000000,0x00000000,
+/* 066C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0670 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0674 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0678 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 067C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0680 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0684 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0688 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 068C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0690 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0694 */ 0x00000000,0x00000000,0x00000000
+}; /* #PARAMETER_END */
+
+static u32 cwcemb80_sample[] = {
+/* 0000 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0004 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0008 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 000C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0010 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0014 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0018 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 001C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0020 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0024 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0028 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 002C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0030 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0034 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0038 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 003C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0040 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0044 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0048 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 004C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0050 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0054 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0058 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 005C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0060 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0064 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0068 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 006C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0070 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0074 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0078 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 007C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0080 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0084 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0088 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 008C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0090 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0094 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0098 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 009C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00A0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00A4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00A8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00AC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00B0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00B4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00B8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00BC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00C0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00C4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00C8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00CC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00D0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00D4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00D8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00DC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00E0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00E4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00E8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00EC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00F0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00F4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00F8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 00FC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0100 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0104 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0108 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 010C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0110 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0114 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0118 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 011C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0120 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0124 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0128 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 012C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0130 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0134 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0138 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 013C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0140 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0144 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0148 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 014C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0150 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0154 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0158 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 015C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0160 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0164 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0168 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 016C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0170 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0174 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0178 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 017C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0180 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0184 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0188 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 018C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0190 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0194 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0198 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 019C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01A0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01A4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01A8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01AC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01B0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01B4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01B8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01BC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01C0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01C4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01C8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01CC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01D0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01D4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01D8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01DC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01E0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01E4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01E8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01EC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01F0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01F4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01F8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 01FC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0200 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0204 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0208 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 020C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0210 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0214 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0218 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 021C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0220 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0224 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0228 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 022C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0230 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0234 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0238 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 023C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0240 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0244 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0248 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 024C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0250 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0254 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0258 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 025C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0260 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0264 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0268 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 026C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0270 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0274 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0278 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 027C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0280 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0284 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0288 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 028C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0290 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0294 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0298 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 029C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02A0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02A4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02A8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02AC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02B0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02B4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02B8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02BC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02C0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02C4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02C8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02CC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02D0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02D4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02D8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02DC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02E0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02E4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02E8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02EC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02F0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02F4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02F8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 02FC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0300 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0304 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0308 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 030C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0310 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0314 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0318 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 031C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0320 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0324 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0328 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 032C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0330 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0334 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0338 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 033C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0340 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0344 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0348 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 034C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0350 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0354 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0358 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 035C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0360 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0364 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0368 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 036C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0370 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0374 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0378 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 037C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0380 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0384 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0388 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 038C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0390 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0394 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0398 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 039C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03A0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03A4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03A8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03AC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03B0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03B4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03B8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03BC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03C0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03C4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03C8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03CC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03D0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03D4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03D8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03DC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03E0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03E4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03E8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03EC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03F0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03F4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03F8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 03FC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0400 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0404 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0408 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 040C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0410 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0414 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0418 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 041C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0420 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0424 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0428 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 042C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0430 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0434 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0438 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 043C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0440 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0444 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0448 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 044C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0450 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0454 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0458 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 045C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0460 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0464 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0468 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 046C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0470 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0474 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0478 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 047C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0480 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0484 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0488 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 048C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0490 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0494 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0498 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 049C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04A0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04A4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04A8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04AC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04B0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04B4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04B8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04BC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04C0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04C4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04C8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04CC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04D0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04D4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04D8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04DC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04E0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04E4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04E8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04EC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04F0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04F4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04F8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 04FC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0500 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0504 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0508 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 050C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0510 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0514 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0518 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 051C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0520 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0524 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0528 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 052C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0530 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0534 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0538 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 053C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0540 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0544 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0548 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 054C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0550 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0554 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0558 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 055C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0560 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0564 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0568 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 056C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0570 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0574 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0578 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 057C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0580 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0584 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0588 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 058C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0590 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0594 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0598 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 059C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05A0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05A4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05A8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05AC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05B0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05B4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05B8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05BC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05C0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05C4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05C8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05CC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05D0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05D4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05D8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05DC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05E0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05E4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05E8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05EC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05F0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05F4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05F8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 05FC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0600 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0604 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0608 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 060C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0610 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0614 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0618 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 061C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0620 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0624 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0628 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 062C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0630 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0634 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0638 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 063C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0640 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0644 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0648 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 064C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0650 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0654 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0658 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 065C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0660 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0664 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0668 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 066C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0670 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0674 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0678 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 067C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0680 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0684 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0688 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 068C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0690 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0694 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0698 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 069C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 06A0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 06A4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 06A8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 06AC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 06B0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 06B4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 06B8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 06BC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 06C0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 06C4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 06C8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 06CC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 06D0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 06D4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 06D8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 06DC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 06E0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 06E4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 06E8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 06EC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 06F0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 06F4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 06F8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 06FC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0700 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0704 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0708 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 070C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0710 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0714 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0718 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 071C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0720 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0724 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0728 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 072C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0730 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0734 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0738 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 073C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0740 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0744 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0748 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 074C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0750 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0754 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0758 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 075C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0760 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0764 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0768 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 076C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0770 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0774 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0778 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 077C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0780 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0784 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0788 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 078C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0790 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0794 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0798 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 079C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 07A0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 07A4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 07A8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 07AC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 07B0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 07B4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 07B8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 07BC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 07C0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 07C4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 07C8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 07CC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 07D0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 07D4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 07D8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 07DC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 07E0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 07E4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 07E8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 07EC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 07F0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 07F4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 07F8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 07FC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0800 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0804 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0808 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 080C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0810 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0814 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0818 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 081C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0820 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0824 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0828 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 082C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0830 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0834 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0838 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 083C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0840 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0844 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0848 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 084C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0850 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0854 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0858 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 085C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0860 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0864 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0868 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 086C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0870 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0874 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0878 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 087C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0880 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0884 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0888 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 088C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0890 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0894 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0898 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 089C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 08A0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 08A4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 08A8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 08AC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 08B0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 08B4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 08B8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 08BC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 08C0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 08C4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 08C8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 08CC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 08D0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 08D4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 08D8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 08DC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 08E0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 08E4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 08E8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 08EC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 08F0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 08F4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 08F8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 08FC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0900 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0904 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0908 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 090C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0910 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0914 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0918 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 091C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0920 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0924 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0928 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 092C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0930 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0934 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0938 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 093C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0940 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0944 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0948 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 094C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0950 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0954 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0958 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 095C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0960 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0964 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0968 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 096C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0970 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0974 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0978 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 097C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0980 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0984 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0988 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 098C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0990 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0994 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0998 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 099C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 09A0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 09A4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 09A8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 09AC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 09B0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 09B4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 09B8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 09BC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 09C0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 09C4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 09C8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 09CC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 09D0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 09D4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 09D8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 09DC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 09E0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 09E4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 09E8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 09EC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 09F0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 09F4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 09F8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 09FC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A00 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A04 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A08 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A0C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A10 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A14 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A18 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A1C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A20 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A24 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A28 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A2C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A30 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A34 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A38 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A3C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A40 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A44 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A48 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A4C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A50 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A54 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A58 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A5C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A60 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A64 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A68 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A6C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A70 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A74 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A78 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A7C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A80 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A84 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A88 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A8C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A90 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A94 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A98 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0A9C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0AA0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0AA4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0AA8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0AAC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0AB0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0AB4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0AB8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0ABC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0AC0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0AC4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0AC8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0ACC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0AD0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0AD4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0AD8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0ADC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0AE0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0AE4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0AE8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0AEC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0AF0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0AF4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0AF8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0AFC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B00 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B04 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B08 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B0C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B10 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B14 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B18 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B1C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B20 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B24 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B28 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B2C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B30 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B34 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B38 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B3C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B40 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B44 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B48 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B4C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B50 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B54 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B58 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B5C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B60 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B64 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B68 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B6C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B70 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B74 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B78 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B7C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B80 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B84 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B88 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B8C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B90 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B94 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B98 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0B9C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0BA0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0BA4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0BA8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0BAC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0BB0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0BB4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0BB8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0BBC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0BC0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0BC4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0BC8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0BCC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0BD0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0BD4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0BD8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0BDC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0BE0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0BE4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0BE8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0BEC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0BF0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0BF4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0BF8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0BFC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C00 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C04 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C08 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C0C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C10 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C14 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C18 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C1C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C20 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C24 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C28 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C2C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C30 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C34 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C38 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C3C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C40 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C44 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C48 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C4C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C50 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C54 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C58 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C5C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C60 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C64 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C68 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C6C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C70 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C74 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C78 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C7C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C80 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C84 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C88 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C8C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C90 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C94 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C98 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0C9C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0CA0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0CA4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0CA8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0CAC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0CB0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0CB4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0CB8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0CBC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0CC0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0CC4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0CC8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0CCC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0CD0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0CD4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0CD8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0CDC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0CE0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0CE4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0CE8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0CEC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0CF0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0CF4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0CF8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0CFC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D00 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D04 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D08 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D0C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D10 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D14 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D18 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D1C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D20 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D24 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D28 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D2C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D30 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D34 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D38 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D3C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D40 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D44 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D48 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D4C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D50 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D54 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D58 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D5C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D60 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D64 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D68 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D6C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D70 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D74 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D78 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D7C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D80 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D84 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D88 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D8C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D90 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D94 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D98 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0D9C */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0DA0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0DA4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0DA8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0DAC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0DB0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0DB4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0DB8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0DBC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0DC0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0DC4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0DC8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0DCC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0DD0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0DD4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0DD8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0DDC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0DE0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0DE4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0DE8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0DEC */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0DF0 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0DF4 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0DF8 */ 0x00000000,0x00000000,0x00000000,0x00000000,
+/* 0DFC */ 0x00000000,0x00000000,0x00000000,0x00010004
+}; /* #SAMPLE_END */
+
+
+static segment_desc_t cwcemb80_segments[] = {
+  { SEGTYPE_SP_PROGRAM, 0x00000000, 0x0000031c, cwcemb80_code },
+  { SEGTYPE_SP_PARAMETER, 0x00000000, 0x00000697, cwcemb80_parameter },
+  { SEGTYPE_SP_SAMPLE, 0x00000000, 0x00000e00, cwcemb80_sample },
+};
+
+static dsp_module_desc_t cwcemb80_module = {
+  "cwcemb80",
+  {
+    38,
+    cwcemb80_symbols
+  },
+  3,
+  cwcemb80_segments,
+};
+
+#endif /* __HEADER_cwcemb80_H__ */
diff -Nru a/sound/pci/cs46xx/imgs/cwcsnoop.h b/sound/pci/cs46xx/imgs/cwcsnoop.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/cs46xx/imgs/cwcsnoop.h	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,46 @@
+/* generated from cwcsnoop.osp DO NOT MODIFY */
+
+#ifndef __HEADER_cwcsnoop_H__
+#define __HEADER_cwcsnoop_H__
+
+static symbol_entry_t cwcsnoop_symbols[] = {
+  { 0x0500, "OVERLAYBEGINADDRESS",0x00 },
+  { 0x0500, "OUTPUTSNOOP",0x03 },
+  { 0x051f, "#CODE_END",0x00 },
+}; /* cwcsnoop symbols */
+
+static u32 cwcsnoop_code[] = {
+/* 0000 */ 0x0007bfb0,0x000b4e40,0x0007c088,0x000c0617,
+/* 0002 */ 0x00049705,0x00000000,0x00080630,0x00001028,
+/* 0004 */ 0x00076408,0x000efb84,0x00066008,0x00000000,
+/* 0006 */ 0x0007c908,0x000c0000,0x00046725,0x000efa44,
+/* 0008 */ 0x0005f708,0x00000000,0x0001d402,0x000b2e00,
+/* 000A */ 0x0003d418,0x00001000,0x0008d574,0x000c4293,
+/* 000C */ 0x00065625,0x000ea30e,0x00096c01,0x000c6f92,
+/* 000E */ 0x0006a58a,0x000f6085,0x00002f43,0x00000000,
+/* 0010 */ 0x000a83a0,0x00001028,0x0005e608,0x000c0000,
+/* 0012 */ 0x00000000,0x00000000,0x000ca108,0x000dcca1,
+/* 0014 */ 0x00003bac,0x000fb205,0x00073843,0x00000000,
+/* 0016 */ 0x000d8730,0x00001028,0x0006600a,0x000c0000,
+/* 0018 */ 0x00057488,0x00000000,0x00000000,0x000e5084,
+/* 001A */ 0x00000000,0x000eba44,0x00087401,0x000e4782,
+/* 001C */ 0x00000734,0x00001000,0x00010705,0x000a6880,
+/* 001E */ 0x00006a88,0x000c75c4
+};
+/* #CODE_END */
+
+static segment_desc_t cwcsnoop_segments[] = {
+  { SEGTYPE_SP_PROGRAM, 0x00000000, 0x0000003e, cwcsnoop_code },
+};
+
+static dsp_module_desc_t cwcsnoop_module = {
+  "cwcsnoop",
+  {
+    3,
+    cwcsnoop_symbols
+  },
+  1,
+  cwcsnoop_segments,
+};
+
+#endif /* __HEADER_cwcsnoop_H__ */
diff -Nru a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
--- a/sound/pci/emu10k1/emufx.c	Tue Oct  1 00:08:17 2002
+++ b/sound/pci/emu10k1/emufx.c	Tue Oct  1 00:08:17 2002
@@ -794,7 +794,7 @@
 				 u32 op, u32 r, u32 a, u32 x, u32 y)
 {
 	snd_assert(*ptr < 512, return);
-	set_bit(*ptr, &icode->code_valid);
+	set_bit(*ptr, icode->code_valid);
 	icode->code[*ptr    ][0] = ((x & 0x3ff) << 10) | (y & 0x3ff);
 	icode->code[(*ptr)++][1] = ((op & 0x0f) << 20) | ((r & 0x3ff) << 10) | (a & 0x3ff);
 }
@@ -806,7 +806,7 @@
 					u32 op, u32 r, u32 a, u32 x, u32 y)
 {
 	snd_assert(*ptr < 512, return);
-	set_bit(*ptr, &icode->code_valid);
+	set_bit(*ptr, icode->code_valid);
 	icode->code[*ptr    ][0] = ((x & 0x7ff) << 12) | (y & 0x7ff);
 	icode->code[(*ptr)++][1] = ((op & 0x0f) << 24) | ((r & 0x7ff) << 12) | (a & 0x7ff);
 }
@@ -831,7 +831,7 @@
 	int gpr;
 
 	for (gpr = 0; gpr < 0x100; gpr++) {
-		if (!test_bit(gpr, &icode->gpr_valid))
+		if (!test_bit(gpr, icode->gpr_valid))
 			continue;
 		snd_emu10k1_ptr_write(emu, emu->gpr_base + gpr, 0, icode->gpr_map[gpr]);
 	}
@@ -842,7 +842,7 @@
 	int gpr;
 
 	for (gpr = 0; gpr < 0x100; gpr++) {
-		set_bit(gpr, &icode->gpr_valid);
+		set_bit(gpr, icode->gpr_valid);
 		icode->gpr_map[gpr] = snd_emu10k1_ptr_read(emu, emu->gpr_base + gpr, 0);
 	}
 }
@@ -852,7 +852,7 @@
 	int tram;
 
 	for (tram = 0; tram < 0xa0; tram++) {
-		if (!test_bit(tram, &icode->tram_valid))
+		if (!test_bit(tram, icode->tram_valid))
 			continue;
 		snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + tram, 0, icode->tram_data_map[tram]);
 		snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, icode->tram_addr_map[tram]);
@@ -864,7 +864,7 @@
 	int tram;
 
 	for (tram = 0; tram < 0xa0; tram++) {
-		set_bit(tram, &icode->tram_valid);
+		set_bit(tram, icode->tram_valid);
 		icode->tram_data_map[tram] = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + tram, 0);
 		icode->tram_addr_map[tram] = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0);
 	}
@@ -875,7 +875,7 @@
 	u32 pc;
 
 	for (pc = 0; pc < 512; pc++) {
-		if (!test_bit(pc, &icode->code_valid))
+		if (!test_bit(pc, icode->code_valid))
 			continue;
 		snd_emu10k1_efx_write(emu, pc * 2, icode->code[pc][0]);
 		snd_emu10k1_efx_write(emu, pc * 2 + 1, icode->code[pc][1]);
@@ -887,7 +887,7 @@
 	u32 pc;
 
 	for (pc = 0; pc < 512; pc++) {
-		set_bit(pc, &icode->code_valid);
+		set_bit(pc, icode->code_valid);
 		icode->code[pc][0] = snd_emu10k1_efx_read(emu, pc * 2);
 		icode->code[pc][1] = snd_emu10k1_efx_read(emu, pc * 2 + 1);
 	}
@@ -1215,7 +1215,7 @@
 	
 	/* clear free GPRs */
 	for (i = 0; i < 256; i++)
-		set_bit(i, &icode->gpr_valid);
+		set_bit(i, icode->gpr_valid);
 
 	strcpy(icode->name, "Audigy DSP code for ALSA");
 	ptr = 0;
@@ -1467,11 +1467,11 @@
 	
 	/* clear free GPRs */
 	for (i = 0; i < 256; i++)
-		set_bit(i, &icode->gpr_valid);
+		set_bit(i, icode->gpr_valid);
 
 	/* clear TRAM data & address lines */
 	for (i = 0; i < 160; i++)
-		set_bit(i, &icode->tram_valid);
+		set_bit(i, icode->tram_valid);
 
 	strcpy(icode->name, "SB Live! FX8010 code for ALSA v1.2 by Jaroslav Kysela");
 	ptr = 0; i = 0;
diff -Nru a/sound/pci/emu10k1/emumpu401.c b/sound/pci/emu10k1/emumpu401.c
--- a/sound/pci/emu10k1/emumpu401.c	Tue Oct  1 00:08:15 2002
+++ b/sound/pci/emu10k1/emumpu401.c	Tue Oct  1 00:08:15 2002
@@ -64,7 +64,7 @@
 		mpu401_read_data(emu, mpu);
 #ifdef CONFIG_SND_DEBUG
 	if (timeout <= 0)
-		snd_printk("cmd: clear rx timeout (status = 0x%x)\n", mpu401_read_stat(emu, mpu));
+		snd_printk(KERN_ERR "cmd: clear rx timeout (status = 0x%x)\n", mpu401_read_stat(emu, mpu));
 #endif
 }
 
@@ -143,7 +143,7 @@
 	}
 	spin_unlock_irqrestore(&midi->input_lock, flags);
 	if (!ok)
-		snd_printk("midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n",
+		snd_printk(KERN_ERR "midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n",
 			   cmd, emu->port,
 			   mpu401_read_stat(emu, midi),
 			   mpu401_read_data(emu, midi));
diff -Nru a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c
--- a/sound/pci/emu10k1/emupcm.c	Tue Oct  1 00:08:14 2002
+++ b/sound/pci/emu10k1/emupcm.c	Tue Oct  1 00:08:14 2002
@@ -32,6 +32,7 @@
 #include <linux/init.h>
 #include <sound/core.h>
 #include <sound/emu10k1.h>
+#include <sound/pcm_sgbuf.h>
 
 #define chip_t emu10k1_t
 
@@ -358,13 +359,13 @@
 
 	if ((err = snd_emu10k1_pcm_channel_alloc(epcm, params_channels(hw_params))) < 0)
 		return err;
-	if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
+	if ((err = snd_pcm_sgbuf_alloc(substream, params_buffer_bytes(hw_params))) < 0)
 		return err;
 	if (err > 0) {	/* change */
 		snd_util_memblk_t *memblk;
 		if (epcm->memblk != NULL)
 			snd_emu10k1_free_pages(emu, epcm->memblk);
-		memblk = snd_emu10k1_alloc_pages(emu, runtime->dma_addr, runtime->dma_bytes);
+		memblk = snd_emu10k1_alloc_pages(emu, (struct snd_sg_buf *)substream->dma_private);
 		if ((epcm->memblk = memblk) == NULL || ((emu10k1_memblk_t *)memblk)->mapped_page < 0) {
 			epcm->start_addr = 0;
 			return -ENOMEM;
@@ -400,7 +401,7 @@
 		epcm->memblk = NULL;
 		epcm->start_addr = 0;
 	}
-	snd_pcm_lib_free_pages(substream);
+	snd_pcm_sgbuf_free(substream);
 	return 0;
 }
 
@@ -778,6 +779,10 @@
 	runtime->private_data = epcm;
 	runtime->private_free = snd_emu10k1_pcm_free_substream;
 	runtime->hw = snd_emu10k1_playback;
+	if ((err = snd_pcm_sgbuf_init(substream, emu->pci, 32)) < 0) {
+		snd_magic_kfree(epcm);
+		return err;
+	}
 	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) {
 		snd_magic_kfree(epcm);
 		return err;
@@ -804,6 +809,7 @@
 	emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[substream->number];
 
 	mix->epcm = NULL;
+	snd_pcm_sgbuf_delete(substream);
 	snd_emu10k1_pcm_mixer_notify(emu->card, mix, 0);
 	return 0;
 }
@@ -942,6 +948,9 @@
 	prepare:		snd_emu10k1_playback_prepare,
 	trigger:		snd_emu10k1_playback_trigger,
 	pointer:		snd_emu10k1_playback_pointer,
+	copy:			snd_pcm_sgbuf_ops_copy_playback,
+	silence:		snd_pcm_sgbuf_ops_silence,
+	page:			snd_pcm_sgbuf_ops_page,
 };
 
 static snd_pcm_ops_t snd_emu10k1_capture_ops = {
@@ -965,6 +974,7 @@
 int __devinit snd_emu10k1_pcm(emu10k1_t * emu, int device, snd_pcm_t ** rpcm)
 {
 	snd_pcm_t *pcm;
+	snd_pcm_substream_t *substream;
 	int err;
 
 	if (rpcm)
@@ -984,7 +994,9 @@
 	strcpy(pcm->name, "EMU10K1");
 	emu->pcm = pcm;
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(emu->pci, pcm, 64*1024, 128*1024);
+	for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next)
+		snd_pcm_lib_preallocate_pci_pages(emu->pci, substream, 64*1024, 64*1024);
+			return err;
 
 	if (rpcm)
 		*rpcm = pcm;
diff -Nru a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c
--- a/sound/pci/emu10k1/memory.c	Tue Oct  1 00:08:19 2002
+++ b/sound/pci/emu10k1/memory.c	Tue Oct  1 00:08:19 2002
@@ -289,22 +289,19 @@
  * page allocation for DMA
  */
 snd_util_memblk_t *
-snd_emu10k1_alloc_pages(emu10k1_t *emu, dma_addr_t addr, unsigned long size)
+snd_emu10k1_alloc_pages(emu10k1_t *emu, struct snd_sg_buf *sgbuf)
 {
 	snd_util_memhdr_t *hdr;
 	emu10k1_memblk_t *blk;
-	int page, err;
+	int page, err, idx;
 
 	snd_assert(emu, return NULL);
-	snd_assert(size > 0 && size < MAXPAGES * EMUPAGESIZE, return NULL);
+	snd_assert(sgbuf->size > 0 && sgbuf->size < MAXPAGES * EMUPAGESIZE, return NULL);
 	hdr = emu->memhdr;
 	snd_assert(hdr, return NULL);
 
-	if (!is_valid_page(addr))
-		return NULL;
-
 	down(&hdr->block_mutex);
-	blk = search_empty(emu, size);
+	blk = search_empty(emu, sgbuf->size);
 	if (blk == NULL) {
 		up(&hdr->block_mutex);
 		return NULL;
@@ -312,10 +309,15 @@
 	/* fill buffer addresses but pointers are not stored so that
 	 * snd_free_pci_pages() is not called in in synth_free()
 	 */
-	for (page = blk->first_page; page <= blk->last_page; page++) {
+	idx = 0;
+	for (page = blk->first_page; page <= blk->last_page; page++, idx++) {
+		dma_addr_t addr = sgbuf->table[idx].addr;
+		if (! is_valid_page(addr)) {
+			up(&hdr->block_mutex);
+			return NULL;
+		}
 		emu->page_addr_table[page] = addr;
 		emu->page_ptr_table[page] = NULL;
-		addr += PAGE_SIZE;
 	}
 
 	/* set PTB entries */
diff -Nru a/sound/pci/ens1370.c b/sound/pci/ens1370.c
--- a/sound/pci/ens1370.c	Tue Oct  1 00:08:16 2002
+++ b/sound/pci/ens1370.c	Tue Oct  1 00:08:16 2002
@@ -1532,8 +1532,7 @@
 	outl(0, ES_REG(ensoniq, CONTROL));	/* switch everything off */
 	outl(0, ES_REG(ensoniq, SERIAL));	/* clear serial interface */
 #endif
-	if(ensoniq->irq >= 0)
-		synchronize_irq(ensoniq->irq);
+	synchronize_irq(ensoniq->irq);
 	pci_set_power_state(ensoniq->pci, 3);
       __hw_end:
 #ifdef CHIP1370
diff -Nru a/sound/pci/es1968.c b/sound/pci/es1968.c
--- a/sound/pci/es1968.c	Tue Oct  1 00:08:18 2002
+++ b/sound/pci/es1968.c	Tue Oct  1 00:08:18 2002
@@ -1129,7 +1129,7 @@
 	/* clear WP interupts */
 	outw(1, chip->io_port + 0x04);
 	/* enable WP ints */
-	outw(inw(chip->io_port + 0x18) | 4, chip->io_port + 0x18);
+	outw(inw(chip->io_port + ESM_PORT_HOST_IRQ) | ESM_HIRQ_DSIE, chip->io_port + ESM_PORT_HOST_IRQ);
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 
 	freq = runtime->rate;
@@ -1260,7 +1260,7 @@
 	/* clear WP interupts */
 	outw(1, chip->io_port + 0x04);
 	/* enable WP ints */
-	outw(inw(chip->io_port + 0x18) | 4, chip->io_port + 0x18);
+	outw(inw(chip->io_port + ESM_PORT_HOST_IRQ) | ESM_HIRQ_DSIE, chip->io_port + ESM_PORT_HOST_IRQ);
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 
 	freq = runtime->rate;
@@ -1446,8 +1446,10 @@
 __found:
 	if (buf->size > size) {
 		esm_memory_t *chunk = kmalloc(sizeof(*chunk), GFP_KERNEL);
-		if (chunk == NULL)
+		if (chunk == NULL) {
+			up(&chip->memory_mutex);
 			return NULL;
+		}
 		chunk->size = buf->size - size;
 		chunk->buf = buf->buf + size;
 		chunk->addr = buf->addr + size;
@@ -1821,7 +1823,7 @@
 	apu_set_register(chip, apu, 11, 0x0000);
 	spin_lock_irqsave(&chip->reg_lock, flags);
 	outw(1, chip->io_port + 0x04); /* clear WP interupts */
-	outw(inw(chip->io_port + 0x18) | 4, chip->io_port + 0x18); /* enable WP ints */
+	outw(inw(chip->io_port + ESM_PORT_HOST_IRQ) | ESM_HIRQ_DSIE, chip->io_port + ESM_PORT_HOST_IRQ); /* enable WP ints */
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 
 	snd_es1968_apu_set_freq(chip, apu, ((unsigned int)48000 << 16) / chip->clock); /* 48000 Hz */
@@ -2328,9 +2330,10 @@
 	outb(0, iobase + ASSP_CONTROL_C);	/* M: Disable ASSP, ASSP IRQ's and FM Port */
 
 	/* Enable IRQ's */
-	w = ESM_HIRQ_DSIE | ESM_HIRQ_MPU401;
+	w = ESM_HIRQ_DSIE | ESM_HIRQ_MPU401 | ESM_HIRQ_HW_VOLUME;
 	outw(w, iobase + ESM_PORT_HOST_IRQ);
 
+
 	/*
 	 * set up wavecache
 	 */
@@ -2502,6 +2505,7 @@
 	chip->master_switch = NULL;
 	chip->master_volume = NULL;
 	if (chip->res_io_port) {
+		snd_es1968_reset(chip);
 		release_resource(chip->res_io_port);
 		kfree_nocheck(chip->res_io_port);
 	}
diff -Nru a/sound/pci/ice1712.c b/sound/pci/ice1712.c
--- a/sound/pci/ice1712.c	Tue Oct  1 00:08:18 2002
+++ b/sound/pci/ice1712.c	Tue Oct  1 00:08:18 2002
@@ -1142,6 +1142,8 @@
 {
 	unsigned char reg[2] = { 0x80 | 4, 0 };   /* CS8427 auto increment | register number 4 + data */
 	unsigned char val, nval;
+	int res = 0;
+	
 	snd_i2c_lock(ice->i2c);
 	if (snd_i2c_sendbytes(ice->cs8427, reg, 1) != 1) {
 		snd_i2c_unlock(ice->i2c);
@@ -1159,13 +1161,13 @@
 	if (val != nval) {
 		reg[1] = nval;
 		if (snd_i2c_sendbytes(ice->cs8427, reg, 2) != 2) {
-			snd_i2c_unlock(ice->i2c);
-			return -EREMOTE;
+			res = -EREMOTE;
+		} else {
+			res++;
 		}
-		return 1;
 	}
 	snd_i2c_unlock(ice->i2c);
-	return 0;
+	return res;
 }
 
 /*
@@ -4070,7 +4072,7 @@
 	/* --- */
       __hw_end:
 	snd_ice1712_proc_done(ice);
-	if (ice->irq) {
+	if (ice->irq >= 0) {
 		synchronize_irq(ice->irq);
 		free_irq(ice->irq, (void *) ice);
 	}
@@ -4144,7 +4146,7 @@
 	pci_write_config_word(ice->pci, 0x40, 0x807f);
 	pci_write_config_word(ice->pci, 0x42, 0x0006);
 	snd_ice1712_proc_init(ice);
-	synchronize_irq(ice->irq);
+	synchronize_irq(pci->irq);
 
 	if ((ice->res_port = request_region(ice->port, 32, "ICE1712 - Controller")) == NULL) {
 		snd_ice1712_free(ice);
diff -Nru a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
--- a/sound/pci/intel8x0.c	Tue Oct  1 00:08:17 2002
+++ b/sound/pci/intel8x0.c	Tue Oct  1 00:08:17 2002
@@ -293,7 +293,7 @@
 	{ 0x8086, 0x7195, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL },	/* 440MX */
 	{ 0x1039, 0x7012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_SIS },	/* SI7012 */
 	{ 0x10de, 0x01b1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL },	/* NFORCE */
-	{ 0x1022, 0x764d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL },	/* AMD8111 */
+	{ 0x1022, 0x746d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL },	/* AMD8111 */
 	{ 0x1022, 0x7445, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL },	/* AMD768 */
 	{ 0, }
 };
@@ -1104,8 +1104,7 @@
 	outb(ICH_RESETREGS, ICHREG(chip, PO_CR));
 	outb(ICH_RESETREGS, ICHREG(chip, MC_CR));
 	/* --- */
-	if(chip->irq >= 0)
-		synchronize_irq(chip->irq);
+	synchronize_irq(chip->irq);
       __hw_end:
 	if (chip->bdbars)
 		snd_free_pci_pages(chip->pci, 3 * sizeof(u32) * ICH_MAX_FRAGS * 2, chip->bdbars, chip->bdbars_addr);
@@ -1233,7 +1232,10 @@
 	chip->playback.substream = NULL; /* don't process interrupts */
 
 	/* set rate */
-	snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, 48000);
+	if (snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, 48000) < 0) {
+		snd_printk(KERN_ERR "cannot set ac97 rate: clock = %d\n", chip->ac97->clock);
+		return;
+	}
 	snd_intel8x0_setup_periods(chip, &chip->playback);
 	port = chip->bmport + chip->playback.reg_offset;
 	spin_lock_irqsave(&chip->reg_lock, flags);
@@ -1412,7 +1414,7 @@
 	{ PCI_DEVICE_ID_INTEL_ICH4, "Intel 82801DB-ICH4" },
 	{ PCI_DEVICE_ID_SI_7012, "SiS SI7012" },
 	{ PCI_DEVICE_ID_NVIDIA_MCP_AUDIO, "NVidia NForce" },
-	{ 0x764d, "AMD AMD8111" },
+	{ 0x746d, "AMD AMD8111" },
 	{ 0x7445, "AMD AMD768" },
 	{ 0, 0 },
 };
diff -Nru a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
--- a/sound/pci/korg1212/korg1212.c	Tue Oct  1 00:08:14 2002
+++ b/sound/pci/korg1212/korg1212.c	Tue Oct  1 00:08:14 2002
@@ -29,6 +29,7 @@
 #include <sound/info.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
+#include <sound/pcm_params.h>
 #define SNDRV_GET_ID
 #include <sound/initval.h>
 
diff -Nru a/sound/pci/maestro3.c b/sound/pci/maestro3.c
--- a/sound/pci/maestro3.c	Tue Oct  1 00:08:17 2002
+++ b/sound/pci/maestro3.c	Tue Oct  1 00:08:17 2002
@@ -2310,7 +2310,7 @@
 		vfree(chip->suspend_mem);
 #endif
 
-	if(chip->irq >= 0)
+	if (chip->irq >= 0)
 		synchronize_irq(chip->irq);
 
 	if (chip->iobase_res) {
diff -Nru a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
--- a/sound/pci/nm256/nm256.c	Tue Oct  1 00:08:19 2002
+++ b/sound/pci/nm256/nm256.c	Tue Oct  1 00:08:19 2002
@@ -892,7 +892,7 @@
 #endif
 };
 
-static int __init
+static int __devinit
 snd_nm256_pcm(nm256_t *chip, int device)
 {
 	snd_pcm_t *pcm;
@@ -1188,21 +1188,31 @@
 }
 
 /* create an ac97 mixer interface */
-static int __init
+static int __devinit
 snd_nm256_mixer(nm256_t *chip)
 {
 	ac97_t ac97;
-	int err;
+	int i;
+	/* looks like nm256 hangs up when unexpected registers are touched... */
+	static int mixer_regs[] = {
+		AC97_MASTER, AC97_HEADPHONE, AC97_MASTER_MONO,
+		AC97_PC_BEEP, AC97_PHONE, AC97_MIC, AC97_LINE,
+		AC97_VIDEO, AC97_AUX, AC97_PCM, AC97_REC_SEL,
+		AC97_REC_GAIN, AC97_GENERAL_PURPOSE, AC97_3D_CONTROL,
+		AC97_EXTENDED_ID, AC97_EXTENDED_STATUS,
+		AC97_VENDOR_ID1, AC97_VENDOR_ID2,
+		-1
+	};
 
 	memset(&ac97, 0, sizeof(ac97));
-	ac97.init = snd_nm256_ac97_reset;
+	ac97.reset = snd_nm256_ac97_reset;
 	ac97.write = snd_nm256_ac97_write;
 	ac97.read = snd_nm256_ac97_read;
+	ac97.limited_regs = 1;
+	for (i = 0; mixer_regs[i] >= 0; i++)
+		set_bit(mixer_regs[i], ac97.reg_accessed);
 	ac97.private_data = chip;
-	if ((err = snd_ac97_mixer(chip->card, &ac97, &chip->ac97)) < 0)
-		return err;
-
-	return 0;
+	return snd_ac97_mixer(chip->card, &ac97, &chip->ac97);
 }
 
 /* 
@@ -1211,7 +1221,7 @@
  * RAM.
  */
 
-static int __init
+static int __devinit
 snd_nm256_peek_for_sig(nm256_t *chip)
 {
 	/* The signature is located 1K below the end of video RAM.  */
@@ -1346,7 +1356,7 @@
 	if (chip->streams[SNDRV_PCM_STREAM_CAPTURE].running)
 		snd_nm256_capture_stop(chip);
 
-	if(chip->irq >= 0)
+	if (chip->irq >= 0)
 		synchronize_irq(chip->irq);
 
 	if (chip->cport)
@@ -1374,7 +1384,7 @@
 	return snd_nm256_free(chip);
 }
 
-static int __init
+static int __devinit
 snd_nm256_create(snd_card_t *card, struct pci_dev *pci,
 		 int play_bufsize, int capt_bufsize,
 		 int force_load,
diff -Nru a/sound/pci/rme32.c b/sound/pci/rme32.c
--- a/sound/pci/rme32.c	Tue Oct  1 00:08:21 2002
+++ b/sound/pci/rme32.c	Tue Oct  1 00:08:21 2002
@@ -23,8 +23,7 @@
  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  * 
  * 
- *   ToDo: - ADAT (32/8)
- *         - full duplex (32, 32/8, 32Pro)
+ *   ToDo: full duplex (32, 32/8, 32Pro)
  */
 
 #include <sound/driver.h>
@@ -37,6 +36,7 @@
 #include <sound/info.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
+#include <sound/pcm_params.h>
 #include <sound/asoundef.h>
 #define SNDRV_GET_ID
 #include <sound/initval.h>
@@ -327,6 +327,54 @@
 	fifo_size:	0,
 };
 
+/*
+ * Digital output capabilites (ADAT)
+ */
+static snd_pcm_hardware_t snd_rme32_playback_adat_info =
+{
+	info:		     (SNDRV_PCM_INFO_MMAP |
+			      SNDRV_PCM_INFO_MMAP_VALID |
+			      SNDRV_PCM_INFO_INTERLEAVED |
+			      SNDRV_PCM_INFO_PAUSE),
+	formats:             SNDRV_PCM_FMTBIT_S16_LE,
+	rates:	             (SNDRV_PCM_RATE_44100 | 
+			      SNDRV_PCM_RATE_48000),
+	rate_min:            44100,
+	rate_max:            48000,
+	channels_min:        8,
+	channels_max:	     8,
+	buffer_bytes_max:   RME32_BUFFER_SIZE,
+	period_bytes_min:   RME32_BLOCK_SIZE,
+	period_bytes_max:   RME32_BLOCK_SIZE,
+	periods_min:	     RME32_BUFFER_SIZE / RME32_BLOCK_SIZE,
+	periods_max:	     RME32_BUFFER_SIZE / RME32_BLOCK_SIZE,
+	fifo_size:	     0,
+};
+
+/*
+ * Digital input capabilites (ADAT)
+ */
+static snd_pcm_hardware_t snd_rme32_capture_adat_info =
+{
+	info:		     (SNDRV_PCM_INFO_MMAP |
+			      SNDRV_PCM_INFO_MMAP_VALID |
+			      SNDRV_PCM_INFO_INTERLEAVED |
+			      SNDRV_PCM_INFO_PAUSE),
+	formats:             SNDRV_PCM_FMTBIT_S16_LE,
+	rates:	             (SNDRV_PCM_RATE_44100 | 
+			      SNDRV_PCM_RATE_48000),
+	rate_min:            44100,
+	rate_max:            48000,
+	channels_min:        8,
+	channels_max:	     8,
+	buffer_bytes_max:   RME32_BUFFER_SIZE,
+	period_bytes_min:   RME32_BLOCK_SIZE,
+	period_bytes_max:   RME32_BLOCK_SIZE,
+	periods_min:	     RME32_BUFFER_SIZE / RME32_BLOCK_SIZE,
+	periods_max:	     RME32_BUFFER_SIZE / RME32_BLOCK_SIZE,
+	fifo_size:           0,
+};
+
 static void snd_rme32_reset_dac(rme32_t *rme32)
 {
         writel(rme32->wcreg | RME32_WCR_PD,
@@ -359,15 +407,20 @@
 static int snd_rme32_capture_getrate(rme32_t * rme32, int *is_adat)
 {
 	int n;
-	*is_adat = 0;
 
+	*is_adat = 0;
+	if (rme32->rcreg & RME32_RCR_LOCK) { 
+                /* ADAT rate */
+                *is_adat = 1;
+	}
 	if (rme32->rcreg & RME32_RCR_ERF) {
 		return -1;
 	}
 
+        /* S/PDIF rate */
 	n = ((rme32->rcreg >> RME32_RCR_BITPOS_F0) & 1) +
-	    (((rme32->rcreg >> RME32_RCR_BITPOS_F1) & 1) << 1) +
-	    (((rme32->rcreg >> RME32_RCR_BITPOS_F2) & 1) << 2);
+		(((rme32->rcreg >> RME32_RCR_BITPOS_F1) & 1) << 1) +
+		(((rme32->rcreg >> RME32_RCR_BITPOS_F2) & 1) << 2);
 
 	if (RME32_PRO_WITH_8414(rme32))
 		switch (n) {	/* supporting the CS8414 */
@@ -388,7 +441,8 @@
 		default:
 			return -1;
 			break;
-	} else
+		} 
+	else
 		switch (n) {	/* supporting the CS8412 */
 		case 0:
 			return -1;
@@ -816,6 +870,62 @@
 	return 0;
 }
 
+static int
+snd_rme32_playback_adat_open(snd_pcm_substream_t *substream)
+{
+	unsigned long flags;
+	rme32_t *rme32 = _snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	
+	snd_pcm_set_sync(substream);
+
+	spin_lock_irqsave(&rme32->lock, flags);	
+	rme32->wcreg |= RME32_WCR_ADAT;
+	writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);
+	rme32->playback_substream = substream;
+	rme32->playback_last_appl_ptr = 0;
+	rme32->playback_ptr = 0;
+	spin_unlock_irqrestore(&rme32->lock, flags);
+	
+	runtime->hw = snd_rme32_playback_adat_info;
+	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+				     RME32_BUFFER_SIZE, RME32_BUFFER_SIZE);
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+				   &hw_constraints_period_bytes);
+	return 0;
+}
+
+static int
+snd_rme32_capture_adat_open(snd_pcm_substream_t *substream)
+{
+	unsigned long flags;
+	int isadat;
+	rme32_t *rme32 = _snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+
+	rme32->rcreg = readl(rme32->iobase + RME32_IO_CONTROL_REGISTER);
+	if (snd_rme32_capture_getrate(rme32, &isadat) < 0) {
+		/* no input */
+		return -EIO;
+	}
+	if (!isadat) {
+		/* S/PDIF input */
+		return -EBUSY;
+	}
+	snd_pcm_set_sync(substream);
+
+	spin_lock_irqsave(&rme32->lock, flags);	
+	rme32->capture_substream = substream;
+	rme32->capture_ptr = 0;
+	spin_unlock_irqrestore(&rme32->lock, flags);
+
+	runtime->hw = snd_rme32_capture_adat_info;
+	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+				     RME32_BUFFER_SIZE, RME32_BUFFER_SIZE);
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+				   &hw_constraints_period_bytes);
+	return 0;
+}
 
 static int snd_rme32_playback_close(snd_pcm_substream_t * substream)
 {
@@ -1004,7 +1114,31 @@
 snd_rme32_capture_pointer(snd_pcm_substream_t * substream)
 {
 	rme32_t *rme32 = _snd_pcm_substream_chip(substream);
-	return snd_rme32_capture_ptr(rme32);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	snd_pcm_uframes_t frameptr;
+	size_t ptr;
+
+	frameptr = snd_rme32_capture_ptr(rme32);
+	if (runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) {
+		ptr = frameptr << rme32->capture_frlog;
+		if (ptr > rme32->capture_ptr) {
+			memcpy_fromio(runtime->dma_area + rme32->capture_ptr,
+				      rme32->iobase + RME32_IO_DATA_BUFFER +
+				      rme32->capture_ptr,
+				      ptr - rme32->capture_ptr);
+			rme32->capture_ptr += ptr - rme32->capture_ptr;
+		} else if (ptr < rme32->capture_ptr) {
+			memcpy_fromio(runtime->dma_area + rme32->capture_ptr,
+				      rme32->iobase + RME32_IO_DATA_BUFFER +
+				      rme32->capture_ptr,
+				      RME32_BUFFER_SIZE - rme32->capture_ptr);
+			memcpy_fromio(runtime->dma_area,
+				      rme32->iobase + RME32_IO_DATA_BUFFER,
+				      ptr);
+			rme32->capture_ptr = ptr;
+		}
+	}
+	return frameptr;
 }
 
 static snd_pcm_ops_t snd_rme32_playback_spdif_ops = {
@@ -1032,6 +1166,31 @@
 	copy:		snd_rme32_capture_copy,
 };
 
+static snd_pcm_ops_t snd_rme32_playback_adat_ops = {
+	open:		snd_rme32_playback_adat_open,
+	close:		snd_rme32_playback_close,
+	ioctl:		snd_pcm_lib_ioctl,
+	hw_params:	snd_rme32_playback_hw_params,
+	hw_free:	snd_rme32_playback_hw_free,
+	prepare:	snd_rme32_playback_prepare,
+	trigger:	snd_rme32_playback_trigger,
+	pointer:	snd_rme32_playback_pointer,
+	copy:		snd_rme32_playback_copy,
+	silence:	snd_rme32_playback_silence,
+};
+
+static snd_pcm_ops_t snd_rme32_capture_adat_ops = {
+	open:		snd_rme32_capture_adat_open,
+	close:		snd_rme32_capture_close,
+	ioctl:		snd_pcm_lib_ioctl,
+	hw_params:	snd_rme32_capture_hw_params,
+	hw_free:	snd_rme32_capture_hw_free,
+	prepare:	snd_rme32_capture_prepare,
+	trigger:	snd_rme32_capture_trigger,
+	pointer:	snd_rme32_capture_pointer,
+	copy:		snd_rme32_capture_copy,
+};
+
 static void snd_rme32_free(void *private_data)
 {
 	rme32_t *rme32 = (rme32_t *) private_data;
@@ -1063,6 +1222,14 @@
 	snd_pcm_lib_preallocate_free_for_all(pcm);
 }
 
+static void
+snd_rme32_free_adat_pcm(snd_pcm_t *pcm)
+{
+	rme32_t *rme32 = (rme32_t *) pcm->private_data;
+	rme32->adat_pcm = NULL;
+	snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
 static int __devinit snd_rme32_create(rme32_t * rme32)
 {
 	struct pci_dev *pci = rme32->pci;
@@ -1117,10 +1284,33 @@
 					      GFP_KERNEL);
 
 	/* set up ALSA pcm device for ADAT */
-	if (pci->device == PCI_DEVICE_ID_DIGI32) {
-		/* ADAT is not available on the base model */
+	if ((pci->device == PCI_DEVICE_ID_DIGI32) ||
+	    (pci->device == PCI_DEVICE_ID_DIGI32_PRO)) {
+		/* ADAT is not available on DIGI32 and DIGI32 Pro */
 		rme32->adat_pcm = NULL;
 	}
+	else {
+		if ((err = snd_pcm_new(rme32->card, "Digi32 ADAT", 1,
+				       1, 1, &rme32->adat_pcm)) < 0)
+		{
+			return err;
+		}		
+		rme32->adat_pcm->private_data = rme32;
+		rme32->adat_pcm->private_free = snd_rme32_free_adat_pcm;
+		strcpy(rme32->adat_pcm->name, "Digi32 ADAT");
+		snd_pcm_set_ops(rme32->adat_pcm, SNDRV_PCM_STREAM_PLAYBACK, 
+				&snd_rme32_playback_adat_ops);
+		snd_pcm_set_ops(rme32->adat_pcm, SNDRV_PCM_STREAM_CAPTURE, 
+				&snd_rme32_capture_adat_ops);
+		
+		rme32->adat_pcm->info_flags = 0;
+
+		snd_pcm_lib_preallocate_pages_for_all(rme32->adat_pcm, 
+						      RME32_BUFFER_SIZE, 
+						      RME32_BUFFER_SIZE, 
+						      GFP_KERNEL);
+	}
+
 
 	rme32->playback_periodsize = 0;
 	rme32->capture_periodsize = 0;
@@ -1137,8 +1327,8 @@
 
 	/* set default values in registers */
 	rme32->wcreg = RME32_WCR_SEL |	 /* normal playback */
-		       RME32_WCR_INP_0 | /* input select */
-		       RME32_WCR_MUTE;	 /* setting muting on */
+		RME32_WCR_INP_0 | /* input select */
+		RME32_WCR_MUTE;	 /* muting on */
 	writel(rme32->wcreg, rme32->iobase + RME32_IO_CONTROL_REGISTER);
 
 
diff -Nru a/sound/pci/rme96.c b/sound/pci/rme96.c
--- a/sound/pci/rme96.c	Tue Oct  1 00:08:16 2002
+++ b/sound/pci/rme96.c	Tue Oct  1 00:08:16 2002
@@ -33,6 +33,7 @@
 #include <sound/info.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
+#include <sound/pcm_params.h>
 #include <sound/asoundef.h>
 #define SNDRV_GET_ID
 #include <sound/initval.h>
@@ -436,7 +437,8 @@
 			      SNDRV_PCM_INFO_MMAP_VALID |
 			      SNDRV_PCM_INFO_INTERLEAVED |
 			      SNDRV_PCM_INFO_PAUSE),
-	formats:             SNDRV_PCM_FMTBIT_S16_LE,
+	formats:	     (SNDRV_PCM_FMTBIT_S16_LE |
+			      SNDRV_PCM_FMTBIT_S32_LE),
 	rates:	             (SNDRV_PCM_RATE_44100 | 
 			      SNDRV_PCM_RATE_48000),
 	rate_min:            44100,
@@ -460,7 +462,8 @@
 			      SNDRV_PCM_INFO_MMAP_VALID |
 			      SNDRV_PCM_INFO_INTERLEAVED |
 			      SNDRV_PCM_INFO_PAUSE),
-	formats:             SNDRV_PCM_FMTBIT_S16_LE,
+	formats:	     (SNDRV_PCM_FMTBIT_S16_LE |
+			      SNDRV_PCM_FMTBIT_S32_LE),
 	rates:	             (SNDRV_PCM_RATE_44100 | 
 			      SNDRV_PCM_RATE_48000),
 	rate_min:            44100,
diff -Nru a/sound/pci/rme9652/digiface_firmware.dat b/sound/pci/rme9652/digiface_firmware.dat
--- a/sound/pci/rme9652/digiface_firmware.dat	Tue Oct  1 00:08:17 2002
+++ b/sound/pci/rme9652/digiface_firmware.dat	Tue Oct  1 00:08:17 2002
@@ -1,5 +1,5 @@
 /* stored in little-endian */
-static u32 digiface_firmware[97652] __devinitdata = {
+static u32 digiface_firmware[24413] __devinitdata = {
 0xffffffff, 0x66aa9955, 0x8001000c, 0xe0000000, 0x8006800c, 0xb0000000,
 0x8004800c, 0xb4fc0100, 0x8003000c, 0x00000000, 0x8001000c, 0x90000000,
 0x8004000c, 0x00000000, 0x8001000c, 0x80000000, 0x0002000c, 0x581a000a,
diff -Nru a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
--- a/sound/pci/rme9652/hdsp.c	Tue Oct  1 00:08:16 2002
+++ b/sound/pci/rme9652/hdsp.c	Tue Oct  1 00:08:16 2002
@@ -25,6 +25,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/pci.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
@@ -41,6 +42,8 @@
 static char *snd_id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
 static int snd_enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
 static int snd_precise_ptr[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 0 }; /* Enable precise pointer */
+static int snd_line_outs_monitor[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 0}; /* Send all inputs/playback to line outs */
+static int snd_force_firmware[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 0}; /* Force firmware reload */
 
 MODULE_PARM(snd_index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
 MODULE_PARM_DESC(snd_index, "Index value for RME Hammerfall DSP interface.");
@@ -54,8 +57,14 @@
 MODULE_PARM(snd_precise_ptr, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
 MODULE_PARM_DESC(snd_precise_ptr, "Enable precise pointer (doesn't work reliably).");
 MODULE_PARM_SYNTAX(snd_precise_ptr, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC);
+MODULE_PARM(snd_line_outs_monitor,"1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(snd_line_outs_monitor, "Send all input and playback streams to line outs by default.");
+MODULE_PARM_SYNTAX(snd_line_outs_monitor, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC);
+MODULE_PARM(snd_force_firmware,"1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(snd_force_firmware, "Force a reload of the I/O box firmware");
+MODULE_PARM_SYNTAX(snd_force_firmware, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC);
 MODULE_AUTHOR("Paul Davis <pbd@op.net>");
-MODULE_DESCRIPTION("RME Hammerfall DDSP");
+MODULE_DESCRIPTION("RME Hammerfall DSP");
 MODULE_LICENSE("GPL");
 MODULE_CLASSES("{sound}");
 MODULE_DEVICES("{{RME,Hammerfall-DSP},");
@@ -473,7 +482,6 @@
 	if (hdsp_fifo_wait(hdsp, 127, HDSP_LONG_WAIT)) {
 		return -1;
 	}
-	
 	hdsp_write (hdsp, HDSP_fifoData, ad);
 	hdsp->mixer_matrix[addr] = data;
 
@@ -845,10 +853,7 @@
 		}
 
 		if (clear_timer && hmidi->istimer && --hmidi->istimer <= 0) {
-			printk ("removing timer because there is nothing to do\n");
-			if (del_timer(&hmidi->timer)) {
-				printk ("not removed\n");
-			}
+			del_timer(&hmidi->timer);
 		} 
 	}
 
@@ -947,16 +952,12 @@
 			hmidi->timer.function = snd_hdsp_midi_output_timer;
 			hmidi->timer.data = (unsigned long) hmidi;
 			hmidi->timer.expires = 1 + jiffies;
-			printk ("add timer from output trigger\n");
 			add_timer(&hmidi->timer);
 			hmidi->istimer++;
 		}
 	} else {
 		if (hmidi->istimer && --hmidi->istimer <= 0) {
-			printk ("remove timer in trigger off\n");
-			if (del_timer (&hmidi->timer)) {
-				printk ("not removed\n");
-			}
+			del_timer (&hmidi->timer);
 		}
 	}
 	spin_unlock_irqrestore (&hmidi->lock, flags);
@@ -2189,6 +2190,25 @@
 	for (i = 0; i < 2048; i++)
 		hdsp_write_gain (hdsp, i, MINUS_INFINITY_GAIN);
 
+	if (snd_line_outs_monitor[hdsp->dev]) {
+		
+		snd_printk ("sending all inputs and playback streams to line outs.\n");
+
+		/* route all inputs to the line outs for easy monitoring. send
+		   odd numbered channels to right, even to left.
+		*/
+		
+		for (i = 0; i < HDSP_MAX_CHANNELS; i++) {
+			if (i & 1) { 
+				hdsp_write_gain (hdsp, INPUT_TO_OUTPUT_KEY (i, 26), UNITY_GAIN);
+				hdsp_write_gain (hdsp, PLAYBACK_TO_OUTPUT_KEY (i, 26), UNITY_GAIN);
+			} else {
+				hdsp_write_gain (hdsp, INPUT_TO_OUTPUT_KEY (i, 27), UNITY_GAIN);
+				hdsp_write_gain (hdsp, PLAYBACK_TO_OUTPUT_KEY (i, 27), UNITY_GAIN);
+			}
+		}
+	}
+
 	hdsp->passthru = 0;
 
 	/* set a default rate so that the channel map is set up.
@@ -2532,7 +2552,7 @@
 				 SNDRV_PCM_INFO_SYNC_START |
 				 SNDRV_PCM_INFO_DOUBLE),
 	formats:		SNDRV_PCM_FMTBIT_S32_LE,
-	rates:			(SNDRV_PCM_RATE_32000 | 
+	rates:			(SNDRV_PCM_RATE_32000 |
 				 SNDRV_PCM_RATE_44100 | 
 				 SNDRV_PCM_RATE_48000 | 
 				 SNDRV_PCM_RATE_64000 | 
@@ -2607,7 +2627,7 @@
 			integer: 1,
 		};
 		return snd_interval_refine(c, &t);
-	} else if (r->max < 88200) {
+	} else if (r->max < 64000) {
 		snd_interval_t t = {
 			min: hdsp->ss_channels,
 			max: hdsp->ss_channels,
@@ -2626,14 +2646,14 @@
 	snd_interval_t *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
 	if (c->min >= hdsp->ss_channels) {
 		snd_interval_t t = {
-			min: 44100,
+			min: 32000,
 			max: 48000,
 			integer: 1,
 		};
 		return snd_interval_refine(r, &t);
 	} else if (c->max <= hdsp->ds_channels) {
 		snd_interval_t t = {
-			min: 88200,
+			min: 64000,
 			max: 96000,
 			integer: 1,
 		};
@@ -2811,7 +2831,6 @@
 static int __devinit snd_hdsp_initialize_firmware (hdsp_t *hdsp)
 {
 	int i;
-	int status_reg;
 	u32 *firmware_ptr;
 
 	if (hdsp_check_for_iobox (hdsp)) {
@@ -2829,52 +2848,33 @@
 		hdsp_write (hdsp, HDSP_outputEnable + (4 * i), 1);
 	}
 
-	status_reg = hdsp_read (hdsp, HDSP_statusRegister);
-
-	if ((status_reg & HDSP_DllError) == 0) {
-
-		/* i/o box is connected, firmware already loaded */
+	if (snd_force_firmware[hdsp->dev] || (hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) {
 
-		if (hdsp_read (hdsp, HDSP_status2Register) & HDSP_version1) {
-			hdsp->type = Multiface;
-			hdsp->card_name = "RME Hammerfall DSP (Multiface)";
-			hdsp->ss_channels = MULTIFACE_SS_CHANNELS;
-			hdsp->ds_channels = MULTIFACE_DS_CHANNELS;
-		} else {
-			hdsp->type = Digiface;
-			hdsp->card_name = "RME Hammerfall DSP (Digiface)";
-			hdsp->ss_channels = DIGIFACE_SS_CHANNELS;
-			hdsp->ds_channels = DIGIFACE_DS_CHANNELS;
-		}
+		snd_printk ("loading firmware\n");
 
-	} else {
-
-		/* firmware not loaded, but i/o box is connected */
-		
 		hdsp_write (hdsp, HDSP_jtagReg, HDSP_PROGRAM);
 		hdsp_write (hdsp, HDSP_fifoData, 0);
-		hdsp_fifo_wait (hdsp, 0, HDSP_SHORT_WAIT);
+		if (hdsp_fifo_wait (hdsp, 0, HDSP_SHORT_WAIT) < 0) {
+			snd_printk ("timeout waiting for firmware setup\n");
+			return -EIO;
+		}
 
 		hdsp_write (hdsp, HDSP_jtagReg, HDSP_S_LOAD);
 		hdsp_write (hdsp, HDSP_fifoData, 0);
 
-		if (hdsp_fifo_wait (hdsp, 0, HDSP_SHORT_WAIT) < 0) {
-			printk ("looks like a multiface\n");
+		if (hdsp_fifo_wait (hdsp, 0, HDSP_SHORT_WAIT)) {
 			hdsp->type = Multiface;
-			hdsp->card_name = "RME Hammerfall DSP (Multiface)";
 			hdsp_write (hdsp, HDSP_jtagReg, HDSP_VERSION_BIT);
 			hdsp_write (hdsp, HDSP_jtagReg, HDSP_S_LOAD);
 			hdsp_fifo_wait (hdsp, 0, HDSP_SHORT_WAIT);
 		} else {
-			printk ("looks like a digiface\n");
 			hdsp->type = Digiface;
-			hdsp->card_name = "RME Hammerfall DSP (Digiface)";
 		} 
 
 		hdsp_write (hdsp, HDSP_jtagReg, HDSP_S_PROGRAM);
 		hdsp_write (hdsp, HDSP_fifoData, 0);
 		
-		if (hdsp_fifo_wait (hdsp, 0, HDSP_LONG_WAIT) < 0) {
+		if (hdsp_fifo_wait (hdsp, 0, HDSP_LONG_WAIT)) {
 			snd_printk ("timeout waiting for download preparation\n");
 			return -EIO;
 		}
@@ -2882,9 +2882,9 @@
 		hdsp_write (hdsp, HDSP_jtagReg, HDSP_S_LOAD);
 		
 		if (hdsp->type == Digiface) {
-			firmware_ptr = digiface_firmware;
+			firmware_ptr = (u32 *) digiface_firmware;
 		} else {
-			firmware_ptr = multiface_firmware;
+			firmware_ptr = (u32 *) multiface_firmware;
 		}
 		
 		for (i = 0; i < 24413; ++i) {
@@ -2900,8 +2900,30 @@
 			return -EIO;
 		}
 
+	} else {
+
+		/* firmware already loaded, but we need to know what type
+		   of I/O box is connected.
+		*/
+
+		if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1) {
+			hdsp->type = Multiface;
+		} else {
+			hdsp->type = Digiface;
+		}
 	}
 
+	if (hdsp->type == Digiface) {
+		snd_printk ("I/O Box is a Digiface\n");
+		hdsp->card_name = "RME Hammerfall DSP (Digiface)";
+		hdsp->ss_channels = DIGIFACE_SS_CHANNELS;
+		hdsp->ds_channels = DIGIFACE_DS_CHANNELS;
+	} else {
+		snd_printk ("I/O Box is a Multiface\n");
+		hdsp->card_name = "RME Hammerfall DSP (Multiface)";
+		hdsp->ss_channels = MULTIFACE_SS_CHANNELS;
+		hdsp->ds_channels = MULTIFACE_DS_CHANNELS;
+	}
 	
 	snd_hdsp_flush_midi_input (hdsp, 0);
 	snd_hdsp_flush_midi_input (hdsp, 1);
diff -Nru a/sound/pci/rme9652/multiface_firmware.dat b/sound/pci/rme9652/multiface_firmware.dat
--- a/sound/pci/rme9652/multiface_firmware.dat	Tue Oct  1 00:08:16 2002
+++ b/sound/pci/rme9652/multiface_firmware.dat	Tue Oct  1 00:08:16 2002
@@ -1,5 +1,5 @@
 /* stored in little-endian */
-static u32 multiface_firmware[97652] __devinitdata = {
+static u32 multiface_firmware[24413] __devinitdata = {
 0xffffffff, 0x66aa9955, 0x8001000c, 0xe0000000, 0x8006800c, 0xb0000000,
 0x8004800c, 0xb4fc0100, 0x8003000c, 0x00000000, 0x8001000c, 0x90000000,
 0x8004000c, 0x00000000, 0x8001000c, 0x80000000, 0x0002000c, 0x581a000a,
diff -Nru a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c
--- a/sound/pci/rme9652/rme9652.c	Tue Oct  1 00:08:17 2002
+++ b/sound/pci/rme9652/rme9652.c	Tue Oct  1 00:08:17 2002
@@ -523,6 +523,7 @@
 		rate = RME9652_DS | RME9652_freq;
 		break;
 	default:
+		spin_unlock_irq(&rme9652->lock);
 		return -EINVAL;
 	}
 
diff -Nru a/sound/pci/via686.c b/sound/pci/via686.c
--- a/sound/pci/via686.c	Tue Oct  1 00:08:16 2002
+++ b/sound/pci/via686.c	Tue Oct  1 00:08:16 2002
@@ -28,6 +28,8 @@
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
+#include <sound/pcm_sgbuf.h>
+#include <sound/pcm_params.h>
 #include <sound/info.h>
 #include <sound/ac97_codec.h>
 #include <sound/mpu401.h>
@@ -135,29 +137,90 @@
 #define   VIA_REG_AC97_DATA_MASK	0xffff
 #define VIA_REG_SGD_SHADOW		0x84	/* dword */
 
-/*
- *
- */
-
-#define VIA_MAX_FRAGS			32
+#define VIA_TBL_BIT_FLAG	0x40000000
+#define VIA_TBL_BIT_EOL		0x80000000
 
 /*
- *  
+ * pcm stream
  */
 
 typedef struct {
 	unsigned long reg_offset;
-	unsigned int *table;
-	dma_addr_t table_addr;
         snd_pcm_substream_t *substream;
-	dma_addr_t physbuf;
+	int running;
         unsigned int size;
         unsigned int fragsize;
 	unsigned int frags;
 	unsigned int lastptr;
 	unsigned int lastcount;
+	unsigned int page_per_frag;
+	unsigned int curidx;
+	unsigned int tbl_entries;	/* number of descriptor table entries */
+	unsigned int tbl_size;		/* size of a table entry */
+	u32 *table; /* physical address + flag */
+	dma_addr_t table_addr;
 } viadev_t;
 
+
+static int build_via_table(viadev_t *dev, snd_pcm_substream_t *substream,
+			   struct pci_dev *pci)
+{
+	int i, size;
+	struct snd_sg_buf *sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL);
+
+	if (dev->table) {
+		snd_free_pci_pages(pci, PAGE_ALIGN(dev->tbl_entries * 8), dev->table, dev->table_addr);
+		dev->table = NULL;
+	}
+
+	/* allocate buffer descriptor lists */
+	if (dev->fragsize < PAGE_SIZE) {
+		dev->tbl_size = dev->fragsize;
+		dev->tbl_entries = dev->frags;
+		dev->page_per_frag = 1;
+	} else {
+		dev->tbl_size = PAGE_SIZE;
+		dev->tbl_entries = sgbuf->pages;
+		dev->page_per_frag = dev->fragsize >> PAGE_SHIFT;
+	}
+	/* the start of each lists must be aligned to 8 bytes,
+	 * but the kernel pages are much bigger, so we don't care
+	 */
+	dev->table = (u32*)snd_malloc_pci_pages(pci, PAGE_ALIGN(dev->tbl_entries * 8), &dev->table_addr);
+	if (! dev->table)
+		return -ENOMEM;
+
+	if (dev->tbl_size < PAGE_SIZE) {
+		for (i = 0; i < dev->tbl_entries; i++)
+			dev->table[i << 1] = cpu_to_le32((u32)sgbuf->table[0].addr + dev->fragsize * i);
+	} else {
+		for (i = 0; i < dev->tbl_entries; i++)
+			dev->table[i << 1] = cpu_to_le32((u32)sgbuf->table[i].addr);
+	}
+	size = dev->size;
+	for (i = 0; i < dev->tbl_entries - 1; i++) {
+		dev->table[(i << 1) + 1] = cpu_to_le32(VIA_TBL_BIT_FLAG | dev->tbl_size);
+		size -= dev->tbl_size;
+	}
+	dev->table[(dev->tbl_entries << 1) - 1] = cpu_to_le32(VIA_TBL_BIT_EOL | size);
+
+	return 0;
+}
+
+
+static void clean_via_table(viadev_t *dev, snd_pcm_substream_t *substream,
+			    struct pci_dev *pci)
+{
+	if (dev->table) {
+		snd_free_pci_pages(pci, PAGE_ALIGN(dev->tbl_entries * 8), dev->table, dev->table_addr);
+		dev->table = NULL;
+	}
+}
+
+
+/*
+ */
+
 typedef struct _snd_via686a via686a_t;
 #define chip_t via686a_t
 
@@ -175,10 +238,10 @@
 	snd_card_t *card;
 
 	snd_pcm_t *pcm;
-	snd_pcm_t *pcm_fm;
+	/*snd_pcm_t *pcm_fm;*/
 	viadev_t playback;
 	viadev_t capture;
-	viadev_t playback_fm;
+	/*viadev_t playback_fm;*/
 
 	snd_rawmidi_t *rmidi;
 
@@ -188,9 +251,6 @@
 
 	spinlock_t reg_lock;
 	snd_info_entry_t *proc_entry;
-
-	void *tables;
-	dma_addr_t tables_addr;
 };
 
 static struct pci_device_id snd_via686a_ids[] __devinitdata = {
@@ -336,15 +396,19 @@
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 		val = VIA_REG_CTRL_START;
+		viadev->running = 1;
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 		val = VIA_REG_CTRL_TERMINATE | VIA_REG_CTRL_RESET;
+		viadev->running = 0;
 		break;
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		val = VIA_REG_CTRL_PAUSE;
+		viadev->running = 1;
 		break;
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		val = 0;
+		viadev->running = 0;
 		break;
 	default:
 		return -EINVAL;
@@ -355,44 +419,43 @@
 	return 0;
 }
 
-static void snd_via686a_setup_periods(via686a_t *chip, viadev_t *viadev,
+
+static int snd_via686a_setup_periods(via686a_t *chip, viadev_t *viadev,
 				      snd_pcm_substream_t *substream)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
-	int idx, frags;
-	unsigned int *table = viadev->table;
 	unsigned long port = chip->port + viadev->reg_offset;
+	int v, err;
 
-	viadev->physbuf = runtime->dma_addr;
 	viadev->size = snd_pcm_lib_buffer_bytes(substream);
 	viadev->fragsize = snd_pcm_lib_period_bytes(substream);
 	viadev->frags = runtime->periods;
 	viadev->lastptr = ~0;
 	viadev->lastcount = ~0;
+	viadev->curidx = 0;
+
+	/* the period size must be in power of 2 */
+	v = ld2(viadev->fragsize);
+	if (viadev->fragsize != (1 << v)) {
+		snd_printd(KERN_ERR "invalid fragment size %d\n", viadev->fragsize);
+		return -EINVAL;
+	}
 
 	snd_via686a_channel_reset(chip, viadev);
-	outl(viadev->table_addr, port + VIA_REG_OFFSET_TABLE_PTR);
+
+	err = build_via_table(viadev, substream, chip->pci);
+	if (err < 0)
+		return err;
+
+	runtime->dma_bytes = viadev->size;
+	outl((u32)viadev->table_addr, port + VIA_REG_OFFSET_TABLE_PTR);
 	outb(VIA_REG_TYPE_AUTOSTART |
 	     (runtime->format == SNDRV_PCM_FORMAT_S16_LE ? VIA_REG_TYPE_16BIT : 0) |
 	     (runtime->channels > 1 ? VIA_REG_TYPE_STEREO : 0) |
 	     ((viadev->reg_offset & 0x10) == 0 ? VIA_REG_TYPE_INT_LSAMPLE : 0) |
 	     VIA_REG_TYPE_INT_EOL |
 	     VIA_REG_TYPE_INT_FLAG, port + VIA_REG_OFFSET_TYPE);
-	if (viadev->size == viadev->fragsize) {
-		table[0] = cpu_to_le32(viadev->physbuf);
-		table[1] = cpu_to_le32(0xc0000000 | /* EOL + flag */
-				       viadev->fragsize);
-	} else {
-		frags = viadev->size / viadev->fragsize;
-		for (idx = 0; idx < frags - 1; idx++) {
-			table[(idx << 1) + 0] = cpu_to_le32(viadev->physbuf + (idx * viadev->fragsize));
-			table[(idx << 1) + 1] = cpu_to_le32(0x40000000 |	/* flag */
-							    viadev->fragsize);
-		}
-		table[((frags-1) << 1) + 0] = cpu_to_le32(viadev->physbuf + ((frags-1) * viadev->fragsize));
-		table[((frags-1) << 1) + 1] = cpu_to_le32(0x80000000 |	/* EOL */
-							  viadev->fragsize);
-	}
+	return 0;
 }
 
 /*
@@ -401,8 +464,16 @@
 
 static inline void snd_via686a_update(via686a_t *chip, viadev_t *viadev)
 {
-	snd_pcm_period_elapsed(viadev->substream);
 	outb(VIA_REG_STAT_FLAG | VIA_REG_STAT_EOL, VIAREG(chip, OFFSET_STATUS) + viadev->reg_offset);
+	if (viadev->substream && viadev->running) {
+		viadev->curidx++;
+		if (viadev->curidx >= viadev->page_per_frag) {
+			viadev->curidx = 0;
+			spin_unlock(&chip->reg_lock);
+			snd_pcm_period_elapsed(viadev->substream);
+			spin_lock(&chip->reg_lock);
+		}
+	}
 }
 
 static void snd_via686a_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -410,8 +481,10 @@
 	via686a_t *chip = snd_magic_cast(via686a_t, dev_id, return);
 	unsigned int status;
 
+	spin_lock(&chip->reg_lock);
 	status = inl(VIAREG(chip, SGD_SHADOW));
 	if ((status & 0x00000077) == 0) {
+		spin_unlock(&chip->reg_lock);
 		if (chip->rmidi != NULL) {
 			snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
 		}
@@ -419,10 +492,11 @@
 	}
 	if (inb(VIAREG(chip, PLAYBACK_STATUS)) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
 		snd_via686a_update(chip, &chip->playback);
-	if (inb(VIAREG(chip, FM_STATUS)) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
-		snd_via686a_update(chip, &chip->playback_fm);
 	if (inb(VIAREG(chip, CAPTURE_STATUS)) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
 		snd_via686a_update(chip, &chip->capture);
+	/*if (inb(VIAREG(chip, FM_STATUS)) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
+	  snd_via686a_update(chip, &chip->playback_fm);*/
+	spin_unlock(&chip->reg_lock);
 }
 
 /*
@@ -448,12 +522,12 @@
 static int snd_via686a_hw_params(snd_pcm_substream_t * substream,
 				 snd_pcm_hw_params_t * hw_params)
 {
-	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
+	return snd_pcm_sgbuf_alloc(substream, params_buffer_bytes(hw_params));
 }
 
 static int snd_via686a_hw_free(snd_pcm_substream_t * substream)
 {
-	return snd_pcm_lib_free_pages(substream);
+	return 0;
 }
 
 static int snd_via686a_playback_prepare(snd_pcm_substream_t * substream)
@@ -462,8 +536,7 @@
 	snd_pcm_runtime_t *runtime = substream->runtime;
 
 	snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate);
-	snd_via686a_setup_periods(chip, &chip->playback, substream);
-	return 0;
+	return snd_via686a_setup_periods(chip, &chip->playback, substream);
 }
 
 static int snd_via686a_capture_prepare(snd_pcm_substream_t * substream)
@@ -472,8 +545,7 @@
 	snd_pcm_runtime_t *runtime = substream->runtime;
 
 	snd_ac97_set_rate(chip->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate);
-	snd_via686a_setup_periods(chip, &chip->capture, substream);
-	return 0;
+	return snd_via686a_setup_periods(chip, &chip->capture, substream);
 }
 
 static inline unsigned int snd_via686a_cur_ptr(via686a_t *chip, viadev_t *viadev)
@@ -486,9 +558,19 @@
 		ptr += 8;
 	if (!(inb(VIAREG(chip, OFFSET_STATUS) + viadev->reg_offset) & VIA_REG_STAT_ACTIVE))
 		return 0;
-	val = (((unsigned int)(ptr - viadev->table_addr) / 8) - 1) % viadev->frags;
-	val *= viadev->fragsize;
-	val += viadev->fragsize - count;
+	snd_assert(viadev->tbl_entries, return 0);
+	/* get index */
+	if (ptr <= (unsigned int)viadev->table_addr)
+		val = 0;
+	else
+		val = ((ptr - (unsigned int)viadev->table_addr) / 8 - 1) % viadev->tbl_entries;
+	if (val < viadev->tbl_entries - 1) {
+		val *= viadev->tbl_size;
+		val += viadev->tbl_size - count;
+	} else {
+		val *= viadev->tbl_size;
+		val += (viadev->size % viadev->tbl_size) + 1 - count;
+	}
 	viadev->lastptr = ptr;
 	viadev->lastcount = count;
 	// printk("pointer: ptr = 0x%x (%i), count = 0x%x, val = 0x%x\n", ptr, count, val);
@@ -522,8 +604,8 @@
 	buffer_bytes_max:	128 * 1024,
 	period_bytes_min:	32,
 	period_bytes_max:	128 * 1024,
-	periods_min:		1,
-	periods_max:		VIA_MAX_FRAGS,
+	periods_min:		2,
+	periods_max:		1024,
 	fifo_size:		0,
 };
 
@@ -541,8 +623,8 @@
 	buffer_bytes_max:	128 * 1024,
 	period_bytes_min:	32,
 	period_bytes_max:	128 * 1024,
-	periods_min:		1,
-	periods_max:		VIA_MAX_FRAGS,
+	periods_min:		2,
+	periods_max:		1024,
 	fifo_size:		0,
 };
 
@@ -557,8 +639,18 @@
 	runtime->hw.rates = chip->ac97->rates_front_dac;
 	if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
 		runtime->hw.rate_min = 48000;
+	if ((err = snd_pcm_sgbuf_init(substream, chip->pci, 32)) < 0)
+		return err;
+	if ((err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
+		return err;
+#if 0
+	/* applying the following constraint together with the power-of-2 rule
+	 * above may result in too narrow space.
+	 * this one is not strictly necessary, so let's disable it.
+	 */
 	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
 		return err;
+#endif
 	return 0;
 }
 
@@ -573,8 +665,14 @@
 	runtime->hw.rates = chip->ac97->rates_adc;
 	if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
 		runtime->hw.rate_min = 48000;
+	if ((err = snd_pcm_sgbuf_init(substream, chip->pci, 32)) < 0)
+		return err;
+	if ((err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
+		return err;
+#if 0
 	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
 		return err;
+#endif
 	return 0;
 }
 
@@ -582,6 +680,8 @@
 {
 	via686a_t *chip = snd_pcm_substream_chip(substream);
 
+	clean_via_table(&chip->playback, substream, chip->pci);
+	snd_pcm_sgbuf_delete(substream);
 	chip->playback.substream = NULL;
 	/* disable DAC power */
 	snd_ac97_update_bits(chip->ac97, AC97_POWERDOWN, 0x0200, 0x0200);
@@ -592,6 +692,8 @@
 {
 	via686a_t *chip = snd_pcm_substream_chip(substream);
 
+	clean_via_table(&chip->capture, substream, chip->pci);
+	snd_pcm_sgbuf_delete(substream);
 	chip->capture.substream = NULL;
 	/* disable ADC power */
 	snd_ac97_update_bits(chip->ac97, AC97_POWERDOWN, 0x0100, 0x0100);
@@ -607,6 +709,9 @@
 	prepare:	snd_via686a_playback_prepare,
 	trigger:	snd_via686a_playback_trigger,
 	pointer:	snd_via686a_playback_pointer,
+	copy:           snd_pcm_sgbuf_ops_copy_playback,
+	silence:        snd_pcm_sgbuf_ops_silence,
+	page:           snd_pcm_sgbuf_ops_page,
 };
 
 static snd_pcm_ops_t snd_via686a_capture_ops = {
@@ -618,13 +723,15 @@
 	prepare:	snd_via686a_capture_prepare,
 	trigger:	snd_via686a_capture_trigger,
 	pointer:	snd_via686a_capture_pointer,
+	copy:           snd_pcm_sgbuf_ops_copy_capture,
+	silence:        snd_pcm_sgbuf_ops_silence,
+	page:           snd_pcm_sgbuf_ops_page,
 };
 
 static void snd_via686a_pcm_free(snd_pcm_t *pcm)
 {
 	via686a_t *chip = snd_magic_cast(via686a_t, pcm->private_data, return);
 	chip->pcm = NULL;
-	snd_pcm_lib_preallocate_free_for_all(pcm);
 }
 
 static int __devinit snd_via686a_pcm(via686a_t *chip, int device, snd_pcm_t ** rpcm)
@@ -647,146 +754,11 @@
 	strcpy(pcm->name, "VIA 82C686A");
 	chip->pcm = pcm;
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 128*1024);
-
 	if (rpcm)
 		*rpcm = NULL;
 	return 0;
 }
 
-#if 0
-
-/*
- *  PCM code - FM channel
- */
-
-static int snd_via686a_playback_fm_ioctl(snd_pcm_substream_t * substream,
-					 unsigned int cmd,
-					 void *arg)
-{
-	return snd_pcm_lib_ioctl(substream, cmd, arg);
-}
-
-static int snd_via686a_playback_fm_trigger(snd_pcm_substream_t * substream,
-					   int cmd)
-{
-	via686a_t *chip = snd_pcm_substream_chip(substream);
-
-	return snd_via686a_trigger(chip, &chip->playback_fm, cmd);
-}
-
-static int snd_via686a_playback_fm_prepare(snd_pcm_substream_t * substream)
-{
-	via686a_t *chip = snd_pcm_substream_chip(substream);
-	snd_pcm_runtime_t *runtime = substream->runtime;
-
-	snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate);
-	snd_via686a_setup_periods(chip, &chip->playback_fm, substream);
-	return 0;
-}
-
-static snd_pcm_uframes_t snd_via686a_playback_fm_pointer(snd_pcm_substream_t * substream)
-{
-	via686a_t *chip = snd_pcm_substream_chip(substream);
-	return bytes_to_frames(substream->runtime, snd_via686a_cur_ptr(chip, &chip->playback_fm));
-}
-
-static snd_pcm_hardware_t snd_via686a_playback_fm =
-{
-	info:			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
-				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
-				 SNDRV_PCM_INFO_MMAP_VALID |
-				 SNDRV_PCM_INFO_PAUSE),
-	formats:		SNDRV_PCM_FMTBIT_S16_LE,
-	rates:			SNDRV_PCM_RATE_KNOT,
-	rate_min:		24000,
-	rate_max:		24000,
-	channels_min:		2,
-	channels_max:		2,
-	buffer_bytes_max:	128 * 1024,
-	period_bytes_min:	32,
-	period_bytes_max:	128 * 1024,
-	periods_min:		1,
-	periods_max:		VIA_MAX_FRAGS,
-	fifo_size:		0,
-};
-
-static int snd_via686a_playback_fm_open(snd_pcm_substream_t * substream)
-{
-	via686a_t *chip = snd_pcm_substream_chip(substream);
-	snd_pcm_runtime_t *runtime = substream->runtime;
-	int err;
-
-	if ((runtime->dma_area = snd_malloc_pci_pages_fallback(chip->pci, chip->dma_fm_size, &runtime->dma_addr, &runtime->dma_bytes)) == NULL)
-		return -ENOMEM;
-	chip->playback_fm.substream = substream;
-	runtime->hw = snd_via686a_playback_fm;
-#if 0
-	runtime->hw.rates = chip->ac97->rates_front_dac;
-	if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
-		runtime->hw.min_rate = 48000;
-#endif
-	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
-		return err;
-	return 0;
-}
-
-static int snd_via686a_playback_fm_close(snd_pcm_substream_t * substream)
-{
-	via686a_t *chip = snd_pcm_substream_chip(substream);
-	snd_pcm_runtime_t *runtime = substream->runtime;
-
-	chip->playback_fm.substream = NULL;
-	snd_free_pci_pages(chip->pci, runtime->dma_bytes, runtime->dma_area, runtime->dma_addr);
-	/* disable DAC power */
-	snd_ac97_update_bits(chip->ac97, AC97_POWERDOWN, 0x0200, 0x0200);
-	return 0;
-}
-
-static snd_pcm_ops_t snd_via686a_playback_fm_ops = {
-	open:		snd_via686a_playback_fm_open,
-	close:		snd_via686a_playback_fm_close,
-	ioctl:		snd_pcm_lib_ioctl,
-	prepare:	snd_via686a_playback_fm_prepare,
-	trigger:	snd_via686a_playback_fm_trigger,
-	pointer:	snd_via686a_playback_fm_pointer,
-};
-
-static void snd_via686a_pcm_fm_free(void *private_data)
-{
-	via686a_t *chip = snd_magic_cast(via686a_t, private_data, return);
-	chip->pcm_fm = NULL;
-	snd_pcm_lib_preallocate_pci_free_for_all(ensoniq->pci, pcm);
-}
-
-static int __devinit snd_via686a_pcm_fm(via686a_t *chip, int device, snd_pcm_t ** rpcm)
-{
-	snd_pcm_t *pcm;
-	int err;
-
-	if (rpcm)
-		*rpcm = NULL;
-	err = snd_pcm_new(chip->card, "VIA 82C686A - FM DAC", device, 1, 0, &pcm);
-	if (err < 0)
-		return err;
-
-	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_via686a_playback_fm_ops);
-
-	pcm->private_data = chip;
-	pcm->private_free = snd_via686a_pcm_fm_free;
-	pcm->info_flags = 0;
-	strcpy(pcm->name, "VIA 82C686A - FM DAC");
-
-	snd_pcm_add_buffer_bytes_controls(pcm);
-	snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024);
-
-	chip->pcm_fm = pcm;
-	if (rpcm)
-		*rpcm = NULL;
-	return 0;
-}
-
-#endif
 
 /*
  *  Mixer part
@@ -979,7 +951,7 @@
 	/* disable interrupts */
 	snd_via686a_channel_reset(chip, &chip->playback);
 	snd_via686a_channel_reset(chip, &chip->capture);
-	snd_via686a_channel_reset(chip, &chip->playback_fm);
+	/*snd_via686a_channel_reset(chip, &chip->playback_fm);*/
 	return 0;
 }
 
@@ -990,13 +962,10 @@
 	/* disable interrupts */
 	snd_via686a_channel_reset(chip, &chip->playback);
 	snd_via686a_channel_reset(chip, &chip->capture);
-	snd_via686a_channel_reset(chip, &chip->playback_fm);
+	/*snd_via686a_channel_reset(chip, &chip->playback_fm);*/
 	/* --- */
+	synchronize_irq(chip->irq);
       __end_hw:
-	if(chip->irq >= 0)
-		synchronize_irq(chip->irq);
-	if (chip->tables)
-		snd_free_pci_pages(chip->pci, 3 * sizeof(unsigned int) * VIA_MAX_FRAGS * 2, chip->tables, chip->tables_addr);
 	if (chip->res_port) {
 		release_resource(chip->res_port);
 		kfree_nocheck(chip->res_port);
@@ -1056,28 +1025,12 @@
 	if (ac97_clock >= 8000 && ac97_clock <= 48000)
 		chip->ac97_clock = ac97_clock;
 	pci_read_config_byte(pci, PCI_REVISION_ID, &chip->revision);
-	synchronize_irq(pci->irq);
+	synchronize_irq(chip->irq);
 
 	/* initialize offsets */
 	chip->playback.reg_offset = VIA_REG_PLAYBACK_STATUS;
 	chip->capture.reg_offset = VIA_REG_CAPTURE_STATUS;
-	chip->playback_fm.reg_offset = VIA_REG_FM_STATUS;
-
-	/* allocate buffer descriptor lists */
-	/* the start of each lists must be aligned to 8 bytes */
-	chip->tables = (unsigned int *)snd_malloc_pci_pages(pci, 3 * sizeof(unsigned int) * VIA_MAX_FRAGS * 2, &chip->tables_addr);
-	if (chip->tables == NULL) {
-		snd_via686a_free(chip);
-		return -ENOMEM;
-	}
-	/* tables must be aligned to 8 bytes, but the kernel pages
-	   are much bigger, so we don't care */
-	chip->playback.table = chip->tables;
-	chip->playback.table_addr = chip->tables_addr;
-	chip->capture.table = chip->playback.table + VIA_MAX_FRAGS * 2;
-	chip->capture.table_addr = chip->playback.table_addr + sizeof(unsigned int) * VIA_MAX_FRAGS * 2;
-	chip->playback_fm.table = chip->capture.table + VIA_MAX_FRAGS * 2;
-	chip->playback_fm.table_addr = chip->capture.table_addr + sizeof(unsigned int) * VIA_MAX_FRAGS * 2;
+	/*chip->playback_fm.reg_offset = VIA_REG_FM_STATUS;*/
 
 	if ((err = snd_via686a_chip_init(chip)) < 0) {
 		snd_via686a_free(chip);
diff -Nru a/sound/pci/via8233.c b/sound/pci/via8233.c
--- a/sound/pci/via8233.c	Tue Oct  1 00:08:16 2002
+++ b/sound/pci/via8233.c	Tue Oct  1 00:08:16 2002
@@ -29,6 +29,8 @@
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
+#include <sound/pcm_sgbuf.h>
+#include <sound/pcm_params.h>
 #include <sound/info.h>
 #include <sound/ac97_codec.h>
 #include <sound/mpu401.h>
@@ -157,11 +159,8 @@
 #define   VIA_REG_AC97_DATA_MASK	0xffff
 #define VIA_REG_SGD_SHADOW		0x84	/* dword */
 
-/*
- *
- */
-
-#define VIA_MAX_FRAGS			32
+#define VIA_TBL_BIT_FLAG	0x40000000
+#define VIA_TBL_BIT_EOL		0x80000000
 
 /*
  *  
@@ -169,15 +168,78 @@
 
 typedef struct {
 	unsigned long reg_offset;
-	unsigned int *table;
-	dma_addr_t table_addr;
         snd_pcm_substream_t *substream;
-	dma_addr_t physbuf;
+	int running;
         unsigned int size;
         unsigned int fragsize;
 	unsigned int frags;
+	unsigned int page_per_frag;
+	unsigned int curidx;
+	unsigned int tbl_entries;	/* number of descriptor table entries */
+	unsigned int tbl_size;		/* size of a table entry */
+	u32 *table; /* physical address + flag */
+	dma_addr_t table_addr;
 } viadev_t;
 
+static int build_via_table(viadev_t *dev, snd_pcm_substream_t *substream,
+			   struct pci_dev *pci)
+{
+	int i, size;
+	struct snd_sg_buf *sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL);
+
+	if (dev->table) {
+		snd_free_pci_pages(pci, PAGE_ALIGN(dev->tbl_entries * 8), dev->table, dev->table_addr);
+		dev->table = NULL;
+	}
+
+	/* allocate buffer descriptor lists */
+	if (dev->fragsize < PAGE_SIZE) {
+		dev->tbl_size = dev->fragsize;
+		dev->tbl_entries = dev->frags;
+		dev->page_per_frag = 1;
+	} else {
+		dev->tbl_size = PAGE_SIZE;
+		dev->tbl_entries = sgbuf->pages;
+		dev->page_per_frag = dev->fragsize >> PAGE_SHIFT;
+	}
+	/* the start of each lists must be aligned to 8 bytes,
+	 * but the kernel pages are much bigger, so we don't care
+	 */
+	dev->table = (u32*)snd_malloc_pci_pages(pci, PAGE_ALIGN(dev->tbl_entries * 8), &dev->table_addr);
+	if (! dev->table)
+		return -ENOMEM;
+
+	if (dev->tbl_size < PAGE_SIZE) {
+		for (i = 0; i < dev->tbl_entries; i++)
+			dev->table[i << 1] = cpu_to_le32((u32)sgbuf->table[0].addr + dev->fragsize * i);
+	} else {
+		for (i = 0; i < dev->tbl_entries; i++)
+			dev->table[i << 1] = cpu_to_le32((u32)sgbuf->table[i].addr);
+	}
+	size = dev->size;
+	for (i = 0; i < dev->tbl_entries - 1; i++) {
+		dev->table[(i << 1) + 1] = cpu_to_le32(VIA_TBL_BIT_FLAG | dev->tbl_size);
+		size -= dev->tbl_size;
+	}
+	dev->table[(dev->tbl_entries << 1) - 1] = cpu_to_le32(VIA_TBL_BIT_EOL | size);
+
+	return 0;
+}
+
+
+static void clean_via_table(viadev_t *dev, snd_pcm_substream_t *substream,
+			    struct pci_dev *pci)
+{
+	if (dev->table) {
+		snd_free_pci_pages(pci, PAGE_ALIGN(dev->tbl_entries * 8), dev->table, dev->table_addr);
+		dev->table = NULL;
+	}
+}
+
+
+/*
+ */
+
 typedef struct _snd_via8233 via8233_t;
 #define chip_t via8233_t
 
@@ -200,9 +262,6 @@
 
 	spinlock_t reg_lock;
 	snd_info_entry_t *proc_entry;
-
-	void *tables;
-	dma_addr_t tables_addr;
 };
 
 static struct pci_device_id snd_via8233_ids[] __devinitdata = {
@@ -323,15 +382,19 @@
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 		val = VIA_REG_CTRL_INT | VIA_REG_CTRL_START;
+		viadev->running = 1;
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 		val = VIA_REG_CTRL_TERMINATE;
+		viadev->running = 0;
 		break;
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		val = VIA_REG_CTRL_INT | VIA_REG_CTRL_PAUSE;
+		viadev->running = 1;
 		break;
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		val = VIA_REG_CTRL_INT;
+		viadev->running = 0;
 		break;
 	default:
 		return -EINVAL;
@@ -342,21 +405,33 @@
 	return 0;
 }
 
-static void snd_via8233_setup_periods(via8233_t *chip, viadev_t *viadev,
-					snd_pcm_substream_t *substream)
+static int snd_via8233_setup_periods(via8233_t *chip, viadev_t *viadev,
+				     snd_pcm_substream_t *substream)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
-	int idx, frags;
-	unsigned int *table = viadev->table;
 	unsigned long port = chip->port + viadev->reg_offset;
+	int v, err;
 
-	viadev->physbuf = runtime->dma_addr;
 	viadev->size = snd_pcm_lib_buffer_bytes(substream);
 	viadev->fragsize = snd_pcm_lib_period_bytes(substream);
 	viadev->frags = runtime->periods;
+	viadev->curidx = 0;
+
+	/* the period size must be in power of 2 */
+	v = ld2(viadev->fragsize);
+	if (viadev->fragsize != (1 << v)) {
+		snd_printd(KERN_ERR "invalid fragment size %d\n", viadev->fragsize);
+		return -EINVAL;
+	}
 
 	snd_via8233_channel_reset(chip, viadev);
-	outl(viadev->table_addr, port + VIA_REG_OFFSET_TABLE_PTR);
+
+	err = build_via_table(viadev, substream, chip->pci);
+	if (err < 0)
+		return err;
+
+	runtime->dma_bytes = viadev->size;
+	outl((u32)viadev->table_addr, port + VIA_REG_OFFSET_TABLE_PTR);
 	if (viadev->reg_offset == VIA_REG_MULTPLAY_STATUS) {
 		unsigned int slots;
 		int fmt = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? VIA_REG_MULTPLAY_FMT_16BIT : VIA_REG_MULTPLAY_FMT_8BIT;
@@ -364,11 +439,11 @@
 		outb(fmt, chip->port + VIA_REG_MULTPLAY_FORMAT);
 		/* set sample number to slot 3, 4, 7, 8, 6, 9 */
 		switch (runtime->channels) {
-		case 1: slots = (1<<0); break;
+		case 1: slots = (1<<0) | (1<<4); break;
 		case 2: slots = (1<<0) | (2<<4); break;
-		case 4: slots = (1<<0) | (2<<4) | (3<<8) | (4<<12);
+		case 4: slots = (1<<0) | (2<<4) | (3<<8) | (4<<12); break;
 		case 6: slots = (1<<0) | (2<<4) | (5<<8) | (6<<12) | (3<<16) | (4<<20); break;
-		default: slots = 0;
+		default: slots = 0; break;
 		}
 		/* STOP index is never reached */
 		outl(0xff000000 | slots, chip->port + VIA_REG_MULTPLAY_STOP_IDX);
@@ -378,27 +453,7 @@
 		     0xff000000,    /* STOP index is never reached */
 		     port + VIA_REG_OFFSET_STOP_IDX);
 	}
-
-	if (viadev->size == viadev->fragsize) {
-		table[0] = cpu_to_le32(viadev->physbuf);
-		table[1] = cpu_to_le32(0xc0000000 | /* EOL + flag */
-				       viadev->fragsize);
-	} else {
-		frags = viadev->size / viadev->fragsize;
-		for (idx = 0; idx < frags - 1; idx++) {
-			table[(idx << 1) + 0] = cpu_to_le32(viadev->physbuf + (idx * viadev->fragsize));
-			table[(idx << 1) + 1] = cpu_to_le32(0x40000000 |	/* flag */
-							    viadev->fragsize);
-		}
-		table[((frags-1) << 1) + 0] = cpu_to_le32(viadev->physbuf + ((frags-1) * viadev->fragsize));
-		table[((frags-1) << 1) + 1] = cpu_to_le32(0x80000000 |	/* EOL */
-							  viadev->fragsize);
-	}
-#if 0
-	printk("%s: size = %d  frags = %d  fragsize = %d\n",  __FUNCTION__, viadev->size, frags, viadev->fragsize);
-	for (idx=0; idx < frags; idx++)
-		printk("    address %x,  count %x\n", table[idx*2], table[idx*2+1]);
-#endif
+	return 0;
 }
 
 /*
@@ -407,18 +462,28 @@
 
 static inline void snd_via8233_update(via8233_t *chip, viadev_t *viadev)
 {
-	snd_pcm_period_elapsed(viadev->substream);
 	outb(VIA_REG_STAT_FLAG | VIA_REG_STAT_EOL, VIAREG(chip, OFFSET_STATUS) + viadev->reg_offset);
+	if (viadev->substream && viadev->running) {
+		viadev->curidx++;
+		if (viadev->curidx >= viadev->page_per_frag) {
+			viadev->curidx = 0;
+			spin_unlock(&chip->reg_lock);
+			snd_pcm_period_elapsed(viadev->substream);
+			spin_lock(&chip->reg_lock);
+		}
+	}
 }
 
 static void snd_via8233_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	via8233_t *chip = snd_magic_cast(via8233_t, dev_id, return);
 
+	spin_lock(&chip->reg_lock);
 	if (inb(chip->port + chip->playback.reg_offset) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
 		snd_via8233_update(chip, &chip->playback);
 	if (inb(chip->port + chip->capture.reg_offset) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
 		snd_via8233_update(chip, &chip->capture);
+	spin_unlock(&chip->reg_lock);
 }
 
 /*
@@ -443,12 +508,12 @@
 static int snd_via8233_hw_params(snd_pcm_substream_t * substream,
 					  snd_pcm_hw_params_t * hw_params)
 {
-	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
+	return snd_pcm_sgbuf_alloc(substream, params_buffer_bytes(hw_params));
 }
 
 static int snd_via8233_hw_free(snd_pcm_substream_t * substream)
 {
-	return snd_pcm_lib_free_pages(substream);
+	return 0;
 }
 
 static int snd_via8233_playback_prepare(snd_pcm_substream_t * substream)
@@ -457,7 +522,6 @@
 	snd_pcm_runtime_t *runtime = substream->runtime;
 
 	snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate);
-	snd_via8233_setup_periods(chip, &chip->playback, substream);
 	if (chip->playback.reg_offset != VIA_REG_MULTPLAY_STATUS) {
 		unsigned int tmp;
 		/* I don't understand this stuff but its from the documentation and this way it works */
@@ -466,7 +530,7 @@
 		tmp = inl(VIAREG(chip, PLAYBACK_STOP_IDX)) & ~0xfffff;
 		outl(tmp | (0xffff * runtime->rate)/(48000/16), VIAREG(chip, PLAYBACK_STOP_IDX));
 	}
-	return 0;
+	return snd_via8233_setup_periods(chip, &chip->playback, substream);
 }
 
 static int snd_via8233_capture_prepare(snd_pcm_substream_t * substream)
@@ -475,10 +539,9 @@
 	snd_pcm_runtime_t *runtime = substream->runtime;
 
 	snd_ac97_set_rate(chip->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate);
-	snd_via8233_setup_periods(chip, &chip->capture, substream);
 	outb(VIA_REG_CAPTURE_CHANNEL_LINE, VIAREG(chip, CAPTURE_CHANNEL));
 	outb(VIA_REG_CAPTURE_FIFO_ENABLE, VIAREG(chip, CAPTURE_FIFO));
-	return 0;
+	return snd_via8233_setup_periods(chip, &chip->capture, substream);
 }
 
 static inline unsigned int snd_via8233_cur_ptr(via8233_t *chip, viadev_t *viadev)
@@ -488,9 +551,14 @@
 	count = inl(VIAREG(chip, OFFSET_CURR_COUNT) + viadev->reg_offset) & 0xffffff;
 	/* The via686a does not have this current index register,
 	 * this register makes life easier for us here. */
-	val = inb(VIAREG(chip, OFFSET_CURR_INDEX) + viadev->reg_offset) % viadev->frags;
-	val *= viadev->fragsize;
-	val += viadev->fragsize - count;
+	val = inb(VIAREG(chip, OFFSET_CURR_INDEX) + viadev->reg_offset) % viadev->tbl_entries;
+	if (val < viadev->tbl_entries - 1) {
+		val *= viadev->tbl_size;
+		val += viadev->tbl_size - count;
+	} else {
+		val *= viadev->tbl_size;
+		val += (viadev->size % viadev->tbl_size) + 1 - count;
+	}
 	// printk("pointer: ptr = 0x%x, count = 0x%x, val = 0x%x\n", ptr, count, val);
 	return val;
 }
@@ -522,8 +590,8 @@
 	buffer_bytes_max:	128 * 1024,
 	period_bytes_min:	32,
 	period_bytes_max:	128 * 1024,
-	periods_min:		1,
-	periods_max:		VIA_MAX_FRAGS,
+	periods_min:		2,
+	periods_max:		1024,
 	fifo_size:		0,
 };
 
@@ -541,8 +609,8 @@
 	buffer_bytes_max:	128 * 1024,
 	period_bytes_min:	32,
 	period_bytes_max:	128 * 1024,
-	periods_min:		1,
-	periods_max:		VIA_MAX_FRAGS,
+	periods_min:		2,
+	periods_max:		1024,
 	fifo_size:		0,
 };
 
@@ -569,8 +637,14 @@
 	runtime->hw.rates = chip->ac97->rates_front_dac;
 	if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
 		runtime->hw.rate_min = 48000;
+	if ((err = snd_pcm_sgbuf_init(substream, chip->pci, 32)) < 0)
+		return err;
+	if ((err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
+		return err;
+#if 0
 	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
 		return err;
+#endif
 	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels);
 	return 0;
 }
@@ -586,8 +660,14 @@
 	runtime->hw.rates = chip->ac97->rates_adc;
 	if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
 		runtime->hw.rate_min = 48000;
+	if ((err = snd_pcm_sgbuf_init(substream, chip->pci, 32)) < 0)
+		return err;
+	if ((err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
+		return err;
+#if 0
 	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
 		return err;
+#endif
 	return 0;
 }
 
@@ -596,6 +676,8 @@
 	via8233_t *chip = snd_pcm_substream_chip(substream);
 
 	snd_via8233_channel_reset(chip, &chip->playback);
+	clean_via_table(&chip->playback, substream, chip->pci);
+	snd_pcm_sgbuf_delete(substream);
 	chip->playback.substream = NULL;
 	/* disable DAC power */
 	snd_ac97_update_bits(chip->ac97, AC97_POWERDOWN, 0x0200, 0x0200);
@@ -607,6 +689,8 @@
 	via8233_t *chip = snd_pcm_substream_chip(substream);
 
 	snd_via8233_channel_reset(chip, &chip->capture);
+	clean_via_table(&chip->capture, substream, chip->pci);
+	snd_pcm_sgbuf_delete(substream);
 	chip->capture.substream = NULL;
 	/* disable ADC power */
 	snd_ac97_update_bits(chip->ac97, AC97_POWERDOWN, 0x0100, 0x0100);
@@ -622,6 +706,9 @@
 	prepare:	snd_via8233_playback_prepare,
 	trigger:	snd_via8233_playback_trigger,
 	pointer:	snd_via8233_playback_pointer,
+	copy:           snd_pcm_sgbuf_ops_copy_playback,
+	silence:        snd_pcm_sgbuf_ops_silence,
+	page:           snd_pcm_sgbuf_ops_page,
 };
 
 static snd_pcm_ops_t snd_via8233_capture_ops = {
@@ -633,13 +720,15 @@
 	prepare:	snd_via8233_capture_prepare,
 	trigger:	snd_via8233_capture_trigger,
 	pointer:	snd_via8233_capture_pointer,
+	copy:           snd_pcm_sgbuf_ops_copy_capture,
+	silence:        snd_pcm_sgbuf_ops_silence,
+	page:           snd_pcm_sgbuf_ops_page,
 };
 
 static void snd_via8233_pcm_free(snd_pcm_t *pcm)
 {
 	via8233_t *chip = snd_magic_cast(via8233_t, pcm->private_data, return);
 	chip->pcm = NULL;
-	snd_pcm_lib_preallocate_free_for_all(pcm);
 }
 
 static int __devinit snd_via8233_pcm(via8233_t *chip, int device, snd_pcm_t ** rpcm)
@@ -662,8 +751,6 @@
 	strcpy(pcm->name, "VIA 8233");
 	chip->pcm = pcm;
 
-	snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 128*1024);
-
 	if (rpcm)
 		*rpcm = NULL;
 	return 0;
@@ -758,14 +845,8 @@
 	snd_via8233_channel_reset(chip, &chip->playback);
 	snd_via8233_channel_reset(chip, &chip->capture);
 	/* --- */
+	synchronize_irq(chip->irq);
       __end_hw:
-	if (chip->irq)
-		synchronize_irq(chip->irq);
-	if (chip->tables)
-		snd_free_pci_pages(chip->pci,
-				   VIA_NUM_OF_DMA_CHANNELS * sizeof(unsigned int) * VIA_MAX_FRAGS * 2,
-				   chip->tables,
-				   chip->tables_addr);
 	if (chip->res_port) {
 		release_resource(chip->res_port);
 		kfree_nocheck(chip->res_port);
@@ -831,21 +912,6 @@
 
 	chip->capture.reg_offset = VIA_REG_CAPTURE_STATUS;
 
-	/* allocate buffer descriptor lists */
-	/* the start of each lists must be aligned to 8 bytes */
-	chip->tables = (unsigned int *)snd_malloc_pci_pages(pci,
-				VIA_NUM_OF_DMA_CHANNELS * sizeof(unsigned int) * VIA_MAX_FRAGS * 2,
-				&chip->tables_addr);
-	if (chip->tables == NULL) {
-		snd_via8233_free(chip);
-		return -ENOMEM;
-	}
-	/* tables must be aligned to 8 bytes, but the kernel pages
-	   are much bigger, so we don't care */
-	chip->playback.table = chip->tables;
-	chip->playback.table_addr = chip->tables_addr;
-	chip->capture.table = chip->playback.table + VIA_MAX_FRAGS * 2;
-	chip->capture.table_addr = chip->playback.table_addr + sizeof(unsigned int) * VIA_MAX_FRAGS * 2;
 	if ((err = snd_via8233_chip_init(chip)) < 0) {
 		snd_via8233_free(chip);
 		return err;
diff -Nru a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c
--- a/sound/pci/ymfpci/ymfpci.c	Tue Oct  1 00:08:17 2002
+++ b/sound/pci/ymfpci/ymfpci.c	Tue Oct  1 00:08:17 2002
@@ -46,6 +46,7 @@
 static int snd_enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
 static long snd_fm_port[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1};
 static long snd_mpu_port[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1};
+static int snd_rear_switch[SNDRV_CARDS];
 
 MODULE_PARM(snd_index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
 MODULE_PARM_DESC(snd_index, "Index value for the Yamaha DS-XG PCI soundcard.");
@@ -62,6 +63,9 @@
 MODULE_PARM(snd_fm_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
 MODULE_PARM_DESC(snd_fm_port, "FM OPL-3 Port.");
 MODULE_PARM_SYNTAX(snd_fm_port, SNDRV_ENABLED);
+MODULE_PARM(snd_rear_switch, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(snd_rear_switch, "Enable shared rear/line-in switch");
+MODULE_PARM_SYNTAX(snd_rear_switch, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC);
 
 static struct pci_device_id snd_ymfpci_ids[] __devinitdata = {
         { 0x1073, 0x0004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* YMF724 */
@@ -189,7 +193,7 @@
 		snd_card_free(card);
 		return err;
 	}
-	if ((err = snd_ymfpci_mixer(chip)) < 0) {
+	if ((err = snd_ymfpci_mixer(chip, snd_rear_switch[dev])) < 0) {
 		snd_card_free(card);
 		return err;
 	}
diff -Nru a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
--- a/sound/pci/ymfpci/ymfpci_main.c	Tue Oct  1 00:08:19 2002
+++ b/sound/pci/ymfpci/ymfpci_main.c	Tue Oct  1 00:08:19 2002
@@ -31,6 +31,7 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
+#include <linux/vmalloc.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/info.h>
@@ -1560,30 +1561,36 @@
 
 static int snd_ymfpci_get_gpio_out(ymfpci_t *chip, int pin)
 {
-	u16 reg, ctrl;
+	u16 reg, mode;
 	unsigned long flags;
 
-	reg = ~(1 << pin) & 0xff;
-	ctrl = 0xff00 | reg;
 	spin_lock_irqsave(&chip->reg_lock, flags);
-	snd_ymfpci_writew(chip, YDSXGR_GPIOFUNCENABLE, ctrl);
-	ctrl = snd_ymfpci_readw(chip, YDSXGR_GPIOINSTATUS);
+	reg = snd_ymfpci_readw(chip, YDSXGR_GPIOFUNCENABLE);
+	reg &= ~(1 << (pin + 8));
+	reg |= (1 << pin);
+	snd_ymfpci_writew(chip, YDSXGR_GPIOFUNCENABLE, reg);
+	/* set the level mode for input line */
+	mode = snd_ymfpci_readw(chip, YDSXGR_GPIOTYPECONFIG);
+	mode &= ~(3 << (pin * 2));
+	snd_ymfpci_writew(chip, YDSXGR_GPIOTYPECONFIG, mode);
+	snd_ymfpci_writew(chip, YDSXGR_GPIOFUNCENABLE, reg | (1 << (pin + 8)));
+	mode = snd_ymfpci_readw(chip, YDSXGR_GPIOINSTATUS);
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
-	return (ctrl >> pin) & 1;
+	return (mode >> pin) & 1;
 }
 
 static int snd_ymfpci_set_gpio_out(ymfpci_t *chip, int pin, int enable)
 {
-	u16 reg, ctrl;
+	u16 reg;
 	unsigned long flags;
 
-	reg = ~(1 << pin) & 0xff;
-	ctrl = (reg << 8) | reg;
 	spin_lock_irqsave(&chip->reg_lock, flags);
-	snd_ymfpci_writew(chip, YDSXGR_GPIOFUNCENABLE, ctrl);
+	reg = snd_ymfpci_readw(chip, YDSXGR_GPIOFUNCENABLE);
+	reg &= ~(1 << pin);
+	reg &= ~(1 << (pin + 8));
+	snd_ymfpci_writew(chip, YDSXGR_GPIOFUNCENABLE, reg);
 	snd_ymfpci_writew(chip, YDSXGR_GPIOOUTCTRL, enable << pin);
-	ctrl = 0xff00 | reg;
-	snd_ymfpci_writew(chip, YDSXGR_GPIOFUNCENABLE, ctrl);
+	snd_ymfpci_writew(chip, YDSXGR_GPIOFUNCENABLE, reg | (1 << (pin + 8)));
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 
 	return 0;
@@ -1639,7 +1646,7 @@
 	chip->ac97 = NULL;
 }
 
-int __devinit snd_ymfpci_mixer(ymfpci_t *chip)
+int __devinit snd_ymfpci_mixer(ymfpci_t *chip, int rear_switch)
 {
 	ac97_t ac97;
 	snd_kcontrol_t *kctl;
@@ -1673,10 +1680,11 @@
 
 	/*
 	 * shared rear/line-in
-	 * FIXME: should be only on supported models - checking subdevice
 	 */
-	if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_ymfpci_rear_shared, chip))) < 0)
-		return err;
+	if (rear_switch) {
+		if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_ymfpci_rear_shared, chip))) < 0)
+			return err;
+	}
 
 	return 0;
 }
diff -Nru a/sound/sparc/Config.in b/sound/sparc/Config.in
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/sparc/Config.in	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,13 @@
+# ALSA Sparc drivers
+
+mainmenu_option next_comment
+comment 'ALSA Sparc devices'
+
+if [ "$CONFIG_SBUS" != "n" ]; then
+  dep_tristate 'Sun AMD7930' CONFIG_SND_SUN_AMD7930 $CONFIG_SND
+#  dep_tristate 'Sun DBRI' CONFIG_SND_SUN_DBRI $CONFIG_SND
+fi
+
+dep_tristate 'Sun CS4231' CONFIG_SND_SUN_CS4231 $CONFIG_SND
+
+endmenu
diff -Nru a/sound/sparc/Makefile b/sound/sparc/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/sparc/Makefile	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,14 @@
+#
+# Makefile for ALSA
+# Copyright (c) 2002 by David S. Miller <davem@redhat.com>
+#
+
+snd-sun-amd7930-objs := amd7930.o
+#snd-sun-dbri-objs := dbri.o
+snd-sun-cs4231-objs := cs4231.o
+
+obj-$(CONFIG_SND_SUN_AMD7930) += snd-sun-amd7930.o
+#obj-$(CONFIG_SND_SUN_DBRI) += snd-sun-dbri.o
+obj-$(CONFIG_SND_SUN_CS4231) += snd-sun-cs4231.o
+
+include $(TOPDIR)/Rules.make
diff -Nru a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/sparc/amd7930.c	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,1171 @@
+/*
+ * Driver for AMD7930 sound chips found on Sparcs.
+ * Copyright (C) 2002 David S. Miller <davem@redhat.com>
+ *
+ * Based entirely upon drivers/sbus/audio/amd7930.c which is:
+ * Copyright (C) 1996,1997 Thomas K. Dyas (tdyas@eden.rutgers.edu)
+ *
+ * --- Notes from Thomas's original driver ---
+ * This is the lowlevel driver for the AMD7930 audio chip found on all
+ * sun4c machines and some sun4m machines.
+ *
+ * The amd7930 is actually an ISDN chip which has a very simple
+ * integrated audio encoder/decoder. When Sun decided on what chip to
+ * use for audio, they had the brilliant idea of using the amd7930 and
+ * only connecting the audio encoder/decoder pins.
+ *
+ * Thanks to the AMD engineer who was able to get us the AMD79C30
+ * databook which has all the programming information and gain tables.
+ *
+ * Advanced Micro Devices' Am79C30A is an ISDN/audio chip used in the
+ * SparcStation 1+.  The chip provides microphone and speaker interfaces
+ * which provide mono-channel audio at 8K samples per second via either
+ * 8-bit A-law or 8-bit mu-law encoding.  Also, the chip features an
+ * ISDN BRI Line Interface Unit (LIU), I.430 S/T physical interface,
+ * which performs basic D channel LAPD processing and provides raw
+ * B channel data.  The digital audio channel, the two ISDN B channels,
+ * and two 64 Kbps channels to the microprocessor are all interconnected
+ * via a multiplexer.
+ * --- End of notes from Thoamas's original driver ---
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/info.h>
+#include <sound/control.h>
+#define SNDRV_GET_ID
+#include <sound/initval.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/sbus.h>
+
+static int snd_index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
+static char *snd_id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
+static int snd_enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
+
+MODULE_PARM(snd_index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(snd_index, "Index value for Sun AMD7930 soundcard.");
+MODULE_PARM_SYNTAX(snd_index, SNDRV_INDEX_DESC);
+MODULE_PARM(snd_id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+MODULE_PARM_DESC(snd_id, "ID string for Sun AMD7930 soundcard.");
+MODULE_PARM_SYNTAX(snd_id, SNDRV_ID_DESC);
+MODULE_PARM(snd_enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(snd_enable, "Enable Sun AMD7930 soundcard.");
+MODULE_PARM_SYNTAX(snd_enable, SNDRV_ENABLE_DESC);
+MODULE_AUTHOR("Thomas K. Dyas and David S. Miller");
+MODULE_DESCRIPTION("Sun AMD7930");
+MODULE_LICENSE("GPL");
+MODULE_CLASSES("{sound}");
+MODULE_DEVICES("{{Sun,AMD7930}}");
+
+/* Device register layout.  */
+
+/* Register interface presented to the CPU by the amd7930. */
+#define AMD7930_CR	0x00UL		/* Command Register (W) */
+#define AMD7930_IR	AMD7930_CR	/* Interrupt Register (R) */
+#define AMD7930_DR	0x01UL		/* Data Register (R/W) */
+#define AMD7930_DSR1	0x02UL		/* D-channel Status Register 1 (R) */
+#define AMD7930_DER	0x03UL		/* D-channel Error Register (R) */
+#define AMD7930_DCTB	0x04UL		/* D-channel Transmit Buffer (W) */
+#define AMD7930_DCRB	AMD7930_DCTB	/* D-channel Receive Buffer (R) */
+#define AMD7930_BBTB	0x05UL		/* Bb-channel Transmit Buffer (W) */
+#define AMD7930_BBRB	AMD7930_BBTB	/* Bb-channel Receive Buffer (R) */
+#define AMD7930_BCTB	0x06UL		/* Bc-channel Transmit Buffer (W) */
+#define AMD7930_BCRB	AMD7930_BCTB	/* Bc-channel Receive Buffer (R) */
+#define AMD7930_DSR2	0x07UL		/* D-channel Status Register 2 (R) */
+
+/* Indirect registers in the Main Audio Processor. */
+struct amd7930_map {
+	__u16	x[8];
+	__u16	r[8];
+	__u16	gx;
+	__u16	gr;
+	__u16	ger;
+	__u16	stgr;
+	__u16	ftgr;
+	__u16	atgr;
+	__u8	mmr1;
+	__u8	mmr2;
+};
+
+/* After an amd7930 interrupt, reading the Interrupt Register (ir)
+ * clears the interrupt and returns a bitmask indicating which
+ * interrupt source(s) require service.
+ */
+
+#define AMR_IR_DTTHRSH			0x01 /* D-channel xmit threshold */
+#define AMR_IR_DRTHRSH			0x02 /* D-channel recv threshold */
+#define AMR_IR_DSRI			0x04 /* D-channel packet status */
+#define AMR_IR_DERI			0x08 /* D-channel error */
+#define AMR_IR_BBUF			0x10 /* B-channel data xfer */
+#define AMR_IR_LSRI			0x20 /* LIU status */
+#define AMR_IR_DSR2I			0x40 /* D-channel buffer status */
+#define AMR_IR_MLTFRMI			0x80 /* multiframe or PP */
+
+/* The amd7930 has "indirect registers" which are accessed by writing
+ * the register number into the Command Register and then reading or
+ * writing values from the Data Register as appropriate. We define the
+ * AMR_* macros to be the indirect register numbers and AM_* macros to
+ * be bits in whatever register is referred to.
+ */
+
+/* Initialization */
+#define	AMR_INIT			0x21
+#define		AM_INIT_ACTIVE			0x01
+#define		AM_INIT_DATAONLY		0x02
+#define		AM_INIT_POWERDOWN		0x03
+#define		AM_INIT_DISABLE_INTS		0x04
+#define AMR_INIT2			0x20
+#define		AM_INIT2_ENABLE_POWERDOWN	0x20
+#define		AM_INIT2_ENABLE_MULTIFRAME	0x10
+
+/* Line Interface Unit */
+#define	AMR_LIU_LSR			0xA1
+#define		AM_LIU_LSR_STATE		0x07
+#define		AM_LIU_LSR_F3			0x08
+#define		AM_LIU_LSR_F7			0x10
+#define		AM_LIU_LSR_F8			0x20
+#define		AM_LIU_LSR_HSW			0x40
+#define		AM_LIU_LSR_HSW_CHG		0x80
+#define	AMR_LIU_LPR			0xA2
+#define	AMR_LIU_LMR1			0xA3
+#define		AM_LIU_LMR1_B1_ENABL		0x01
+#define		AM_LIU_LMR1_B2_ENABL		0x02
+#define		AM_LIU_LMR1_F_DISABL		0x04
+#define		AM_LIU_LMR1_FA_DISABL		0x08
+#define		AM_LIU_LMR1_REQ_ACTIV		0x10
+#define		AM_LIU_LMR1_F8_F3		0x20
+#define		AM_LIU_LMR1_LIU_ENABL		0x40
+#define	AMR_LIU_LMR2			0xA4
+#define		AM_LIU_LMR2_DECHO		0x01
+#define		AM_LIU_LMR2_DLOOP		0x02
+#define		AM_LIU_LMR2_DBACKOFF		0x04
+#define		AM_LIU_LMR2_EN_F3_INT		0x08
+#define		AM_LIU_LMR2_EN_F8_INT		0x10
+#define		AM_LIU_LMR2_EN_HSW_INT		0x20
+#define		AM_LIU_LMR2_EN_F7_INT		0x40
+#define	AMR_LIU_2_4			0xA5
+#define	AMR_LIU_MF			0xA6
+#define	AMR_LIU_MFSB			0xA7
+#define	AMR_LIU_MFQB			0xA8
+
+/* Multiplexor */
+#define	AMR_MUX_MCR1			0x41
+#define	AMR_MUX_MCR2			0x42
+#define	AMR_MUX_MCR3			0x43
+#define		AM_MUX_CHANNEL_B1		0x01
+#define		AM_MUX_CHANNEL_B2		0x02
+#define		AM_MUX_CHANNEL_Ba		0x03
+#define		AM_MUX_CHANNEL_Bb		0x04
+#define		AM_MUX_CHANNEL_Bc		0x05
+#define		AM_MUX_CHANNEL_Bd		0x06
+#define		AM_MUX_CHANNEL_Be		0x07
+#define		AM_MUX_CHANNEL_Bf		0x08
+#define	AMR_MUX_MCR4			0x44
+#define		AM_MUX_MCR4_ENABLE_INTS		0x08
+#define		AM_MUX_MCR4_REVERSE_Bb		0x10
+#define		AM_MUX_MCR4_REVERSE_Bc		0x20
+#define	AMR_MUX_1_4			0x45
+
+/* Main Audio Processor */
+#define	AMR_MAP_X			0x61
+#define	AMR_MAP_R			0x62
+#define	AMR_MAP_GX			0x63
+#define	AMR_MAP_GR			0x64
+#define	AMR_MAP_GER			0x65
+#define	AMR_MAP_STGR			0x66
+#define	AMR_MAP_FTGR_1_2		0x67
+#define	AMR_MAP_ATGR_1_2		0x68
+#define	AMR_MAP_MMR1			0x69
+#define		AM_MAP_MMR1_ALAW		0x01
+#define		AM_MAP_MMR1_GX			0x02
+#define		AM_MAP_MMR1_GR			0x04
+#define		AM_MAP_MMR1_GER			0x08
+#define		AM_MAP_MMR1_X			0x10
+#define		AM_MAP_MMR1_R			0x20
+#define		AM_MAP_MMR1_STG			0x40
+#define		AM_MAP_MMR1_LOOPBACK		0x80
+#define	AMR_MAP_MMR2			0x6A
+#define		AM_MAP_MMR2_AINB		0x01
+#define		AM_MAP_MMR2_LS			0x02
+#define		AM_MAP_MMR2_ENABLE_DTMF		0x04
+#define		AM_MAP_MMR2_ENABLE_TONEGEN	0x08
+#define		AM_MAP_MMR2_ENABLE_TONERING	0x10
+#define		AM_MAP_MMR2_DISABLE_HIGHPASS	0x20
+#define		AM_MAP_MMR2_DISABLE_AUTOZERO	0x40
+#define	AMR_MAP_1_10			0x6B
+#define	AMR_MAP_MMR3			0x6C
+#define	AMR_MAP_STRA			0x6D
+#define	AMR_MAP_STRF			0x6E
+#define	AMR_MAP_PEAKX			0x70
+#define	AMR_MAP_PEAKR			0x71
+#define	AMR_MAP_15_16			0x72
+
+/* Data Link Controller */
+#define	AMR_DLC_FRAR_1_2_3		0x81
+#define	AMR_DLC_SRAR_1_2_3		0x82
+#define	AMR_DLC_TAR			0x83
+#define	AMR_DLC_DRLR			0x84
+#define	AMR_DLC_DTCR			0x85
+#define	AMR_DLC_DMR1			0x86
+#define		AMR_DLC_DMR1_DTTHRSH_INT	0x01
+#define		AMR_DLC_DMR1_DRTHRSH_INT	0x02
+#define		AMR_DLC_DMR1_TAR_ENABL		0x04
+#define		AMR_DLC_DMR1_EORP_INT		0x08
+#define		AMR_DLC_DMR1_EN_ADDR1		0x10
+#define		AMR_DLC_DMR1_EN_ADDR2		0x20
+#define		AMR_DLC_DMR1_EN_ADDR3		0x40
+#define		AMR_DLC_DMR1_EN_ADDR4		0x80
+#define		AMR_DLC_DMR1_EN_ADDRS		0xf0
+#define	AMR_DLC_DMR2			0x87
+#define		AMR_DLC_DMR2_RABRT_INT		0x01
+#define		AMR_DLC_DMR2_RESID_INT		0x02
+#define		AMR_DLC_DMR2_COLL_INT		0x04
+#define		AMR_DLC_DMR2_FCS_INT		0x08
+#define		AMR_DLC_DMR2_OVFL_INT		0x10
+#define		AMR_DLC_DMR2_UNFL_INT		0x20
+#define		AMR_DLC_DMR2_OVRN_INT		0x40
+#define		AMR_DLC_DMR2_UNRN_INT		0x80
+#define	AMR_DLC_1_7			0x88
+#define	AMR_DLC_DRCR			0x89
+#define	AMR_DLC_RNGR1			0x8A
+#define	AMR_DLC_RNGR2			0x8B
+#define	AMR_DLC_FRAR4			0x8C
+#define	AMR_DLC_SRAR4			0x8D
+#define	AMR_DLC_DMR3			0x8E
+#define		AMR_DLC_DMR3_VA_INT		0x01
+#define		AMR_DLC_DMR3_EOTP_INT		0x02
+#define		AMR_DLC_DMR3_LBRP_INT		0x04
+#define		AMR_DLC_DMR3_RBA_INT		0x08
+#define		AMR_DLC_DMR3_LBT_INT		0x10
+#define		AMR_DLC_DMR3_TBE_INT		0x20
+#define		AMR_DLC_DMR3_RPLOST_INT		0x40
+#define		AMR_DLC_DMR3_KEEP_FCS		0x80
+#define	AMR_DLC_DMR4			0x8F
+#define		AMR_DLC_DMR4_RCV_1		0x00
+#define		AMR_DLC_DMR4_RCV_2		0x01
+#define		AMR_DLC_DMR4_RCV_4		0x02
+#define		AMR_DLC_DMR4_RCV_8		0x03
+#define		AMR_DLC_DMR4_RCV_16		0x01
+#define		AMR_DLC_DMR4_RCV_24		0x02
+#define		AMR_DLC_DMR4_RCV_30		0x03
+#define		AMR_DLC_DMR4_XMT_1		0x00
+#define		AMR_DLC_DMR4_XMT_2		0x04
+#define		AMR_DLC_DMR4_XMT_4		0x08
+#define		AMR_DLC_DMR4_XMT_8		0x0c
+#define		AMR_DLC_DMR4_XMT_10		0x08
+#define		AMR_DLC_DMR4_XMT_14		0x0c
+#define		AMR_DLC_DMR4_IDLE_MARK		0x00
+#define		AMR_DLC_DMR4_IDLE_FLAG		0x10
+#define		AMR_DLC_DMR4_ADDR_BOTH		0x00
+#define		AMR_DLC_DMR4_ADDR_1ST		0x20
+#define		AMR_DLC_DMR4_ADDR_2ND		0xa0
+#define		AMR_DLC_DMR4_CR_ENABLE		0x40
+#define	AMR_DLC_12_15			0x90
+#define	AMR_DLC_ASR			0x91
+#define	AMR_DLC_EFCR			0x92
+#define		AMR_DLC_EFCR_EXTEND_FIFO	0x01
+#define		AMR_DLC_EFCR_SEC_PKT_INT	0x02
+
+#define AMR_DSR1_VADDR			0x01
+#define AMR_DSR1_EORP			0x02
+#define AMR_DSR1_PKT_IP			0x04
+#define AMR_DSR1_DECHO_ON		0x08
+#define AMR_DSR1_DLOOP_ON		0x10
+#define AMR_DSR1_DBACK_OFF		0x20
+#define AMR_DSR1_EOTP			0x40
+#define AMR_DSR1_CXMT_ABRT		0x80
+
+#define AMR_DSR2_LBRP			0x01
+#define AMR_DSR2_RBA			0x02
+#define AMR_DSR2_RPLOST			0x04
+#define AMR_DSR2_LAST_BYTE		0x08
+#define AMR_DSR2_TBE			0x10
+#define AMR_DSR2_MARK_IDLE		0x20
+#define AMR_DSR2_FLAG_IDLE		0x40
+#define AMR_DSR2_SECOND_PKT		0x80
+
+#define AMR_DER_RABRT			0x01
+#define AMR_DER_RFRAME			0x02
+#define AMR_DER_COLLISION		0x04
+#define AMR_DER_FCS			0x08
+#define AMR_DER_OVFL			0x10
+#define AMR_DER_UNFL			0x20
+#define AMR_DER_OVRN			0x40
+#define AMR_DER_UNRN			0x80
+
+/* Peripheral Port */
+#define	AMR_PP_PPCR1			0xC0
+#define	AMR_PP_PPSR			0xC1
+#define	AMR_PP_PPIER			0xC2
+#define	AMR_PP_MTDR			0xC3
+#define	AMR_PP_MRDR			0xC3
+#define	AMR_PP_CITDR0			0xC4
+#define	AMR_PP_CIRDR0			0xC4
+#define	AMR_PP_CITDR1			0xC5
+#define	AMR_PP_CIRDR1			0xC5
+#define	AMR_PP_PPCR2			0xC8
+#define	AMR_PP_PPCR3			0xC9
+
+typedef struct snd_amd7930 {
+	spinlock_t		lock;
+	unsigned long		regs;
+	u32			flags;
+#define AMD7930_FLAG_PLAYBACK	0x00000001
+#define AMD7930_FLAG_CAPTURE	0x00000002
+
+	struct amd7930_map	map;
+
+	snd_card_t		*card;
+	snd_pcm_t		*pcm;
+	snd_pcm_substream_t	*playback_substream;
+	snd_pcm_substream_t	*capture_substream;
+
+	/* Playback/Capture buffer state. */
+	unsigned char		*p_orig, *p_cur;
+	int			p_left;
+	unsigned char		*c_orig, *c_cur;
+	int			c_left;
+
+	int			rgain;
+	int			pgain;
+	int			mgain;
+
+	struct sbus_dev		*sdev;
+	unsigned int		irq;
+	unsigned int		regs_size;
+	struct snd_amd7930	*next;
+} amd7930_t;
+#define chip_t amd7930_t
+
+static amd7930_t *amd7930_list;
+
+/* Idle the AMD7930 chip.  The amd->lock is not held.  */
+static __inline__ void amd7930_idle(amd7930_t *amd)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&amd->lock, flags);
+	sbus_writeb(AMR_INIT, amd->regs + AMD7930_CR);
+	sbus_writeb(0, amd->regs + AMD7930_DR);
+	spin_unlock_irqrestore(&amd->lock, flags);
+}
+
+/* Enable chip interrupts.  The amd->lock is not held.  */
+static __inline__ void amd7930_enable_ints(amd7930_t *amd)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&amd->lock, flags);
+	sbus_writeb(AMR_INIT, amd->regs + AMD7930_CR);
+	sbus_writeb(AM_INIT_ACTIVE, amd->regs + AMD7930_DR);
+	spin_unlock_irqrestore(&amd->lock, flags);
+}
+
+/* Disable chip interrupts.  The amd->lock is not held.  */
+static __inline__ void amd7930_disable_ints(amd7930_t *amd)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&amd->lock, flags);
+	sbus_writeb(AMR_INIT, amd->regs + AMD7930_CR);
+	sbus_writeb(AM_INIT_ACTIVE | AM_INIT_DISABLE_INTS, amd->regs + AMD7930_DR);
+	spin_unlock_irqrestore(&amd->lock, flags);
+}
+
+/* Commit amd7930_map settings to the hardware.
+ * The amd->lock is held and local interrupts are disabled.
+ */
+static void __amd7930_write_map(amd7930_t *amd)
+{
+	struct amd7930_map *map = &amd->map;
+
+	sbus_writeb(AMR_MAP_GX, amd->regs + AMD7930_CR);
+	sbus_writeb(((map->gx >> 0) & 0xff), amd->regs + AMD7930_DR);
+	sbus_writeb(((map->gx >> 8) & 0xff), amd->regs + AMD7930_DR);
+
+	sbus_writeb(AMR_MAP_GR, amd->regs + AMD7930_CR);
+	sbus_writeb(((map->gr >> 0) & 0xff), amd->regs + AMD7930_DR);
+	sbus_writeb(((map->gr >> 8) & 0xff), amd->regs + AMD7930_DR);
+
+	sbus_writeb(AMR_MAP_STGR, amd->regs + AMD7930_CR);
+	sbus_writeb(((map->stgr >> 0) & 0xff), amd->regs + AMD7930_DR);
+	sbus_writeb(((map->stgr >> 8) & 0xff), amd->regs + AMD7930_DR);
+
+	sbus_writeb(AMR_MAP_GER, amd->regs + AMD7930_CR);
+	sbus_writeb(((map->ger >> 0) & 0xff), amd->regs + AMD7930_DR);
+	sbus_writeb(((map->ger >> 8) & 0xff), amd->regs + AMD7930_DR);
+
+	sbus_writeb(AMR_MAP_MMR1, amd->regs + AMD7930_CR);
+	sbus_writeb(map->mmr1, amd->regs + AMD7930_DR);
+
+	sbus_writeb(AMR_MAP_MMR2, amd->regs + AMD7930_CR);
+	sbus_writeb(map->mmr2, amd->regs + AMD7930_DR);
+}
+
+/* gx, gr & stg gains.  this table must contain 256 elements with
+ * the 0th being "infinity" (the magic value 9008).  The remaining
+ * elements match sun's gain curve (but with higher resolution):
+ * -18 to 0dB in .16dB steps then 0 to 12dB in .08dB steps.
+ */
+static __const__ __u16 gx_coeff[256] = {
+	0x9008, 0x8b7c, 0x8b51, 0x8b45, 0x8b42, 0x8b3b, 0x8b36, 0x8b33,
+	0x8b32, 0x8b2a, 0x8b2b, 0x8b2c, 0x8b25, 0x8b23, 0x8b22, 0x8b22,
+	0x9122, 0x8b1a, 0x8aa3, 0x8aa3, 0x8b1c, 0x8aa6, 0x912d, 0x912b,
+	0x8aab, 0x8b12, 0x8aaa, 0x8ab2, 0x9132, 0x8ab4, 0x913c, 0x8abb,
+	0x9142, 0x9144, 0x9151, 0x8ad5, 0x8aeb, 0x8a79, 0x8a5a, 0x8a4a,
+	0x8b03, 0x91c2, 0x91bb, 0x8a3f, 0x8a33, 0x91b2, 0x9212, 0x9213,
+	0x8a2c, 0x921d, 0x8a23, 0x921a, 0x9222, 0x9223, 0x922d, 0x9231,
+	0x9234, 0x9242, 0x925b, 0x92dd, 0x92c1, 0x92b3, 0x92ab, 0x92a4,
+	0x92a2, 0x932b, 0x9341, 0x93d3, 0x93b2, 0x93a2, 0x943c, 0x94b2,
+	0x953a, 0x9653, 0x9782, 0x9e21, 0x9d23, 0x9cd2, 0x9c23, 0x9baa,
+	0x9bde, 0x9b33, 0x9b22, 0x9b1d, 0x9ab2, 0xa142, 0xa1e5, 0x9a3b,
+	0xa213, 0xa1a2, 0xa231, 0xa2eb, 0xa313, 0xa334, 0xa421, 0xa54b,
+	0xada4, 0xac23, 0xab3b, 0xaaab, 0xaa5c, 0xb1a3, 0xb2ca, 0xb3bd,
+	0xbe24, 0xbb2b, 0xba33, 0xc32b, 0xcb5a, 0xd2a2, 0xe31d, 0x0808,
+	0x72ba, 0x62c2, 0x5c32, 0x52db, 0x513e, 0x4cce, 0x43b2, 0x4243,
+	0x41b4, 0x3b12, 0x3bc3, 0x3df2, 0x34bd, 0x3334, 0x32c2, 0x3224,
+	0x31aa, 0x2a7b, 0x2aaa, 0x2b23, 0x2bba, 0x2c42, 0x2e23, 0x25bb,
+	0x242b, 0x240f, 0x231a, 0x22bb, 0x2241, 0x2223, 0x221f, 0x1a33,
+	0x1a4a, 0x1acd, 0x2132, 0x1b1b, 0x1b2c, 0x1b62, 0x1c12, 0x1c32,
+	0x1d1b, 0x1e71, 0x16b1, 0x1522, 0x1434, 0x1412, 0x1352, 0x1323,
+	0x1315, 0x12bc, 0x127a, 0x1235, 0x1226, 0x11a2, 0x1216, 0x0a2a,
+	0x11bc, 0x11d1, 0x1163, 0x0ac2, 0x0ab2, 0x0aab, 0x0b1b, 0x0b23,
+	0x0b33, 0x0c0f, 0x0bb3, 0x0c1b, 0x0c3e, 0x0cb1, 0x0d4c, 0x0ec1,
+	0x079a, 0x0614, 0x0521, 0x047c, 0x0422, 0x03b1, 0x03e3, 0x0333,
+	0x0322, 0x031c, 0x02aa, 0x02ba, 0x02f2, 0x0242, 0x0232, 0x0227,
+	0x0222, 0x021b, 0x01ad, 0x0212, 0x01b2, 0x01bb, 0x01cb, 0x01f6,
+	0x0152, 0x013a, 0x0133, 0x0131, 0x012c, 0x0123, 0x0122, 0x00a2,
+	0x011b, 0x011e, 0x0114, 0x00b1, 0x00aa, 0x00b3, 0x00bd, 0x00ba,
+	0x00c5, 0x00d3, 0x00f3, 0x0062, 0x0051, 0x0042, 0x003b, 0x0033,
+	0x0032, 0x002a, 0x002c, 0x0025, 0x0023, 0x0022, 0x001a, 0x0021,
+	0x001b, 0x001b, 0x001d, 0x0015, 0x0013, 0x0013, 0x0012, 0x0012,
+	0x000a, 0x000a, 0x0011, 0x0011, 0x000b, 0x000b, 0x000c, 0x000e,
+};
+
+static __const__ __u16 ger_coeff[] = {
+	0x431f, /* 5. dB */
+	0x331f, /* 5.5 dB */
+	0x40dd, /* 6. dB */
+	0x11dd, /* 6.5 dB */
+	0x440f, /* 7. dB */
+	0x411f, /* 7.5 dB */
+	0x311f, /* 8. dB */
+	0x5520, /* 8.5 dB */
+	0x10dd, /* 9. dB */
+	0x4211, /* 9.5 dB */
+	0x410f, /* 10. dB */
+	0x111f, /* 10.5 dB */
+	0x600b, /* 11. dB */
+	0x00dd, /* 11.5 dB */
+	0x4210, /* 12. dB */
+	0x110f, /* 13. dB */
+	0x7200, /* 14. dB */
+	0x2110, /* 15. dB */
+	0x2200, /* 15.9 dB */
+	0x000b, /* 16.9 dB */
+	0x000f  /* 18. dB */
+};
+#define NR_GER_COEFFS (sizeof(ger_coeff) / sizeof(ger_coeff[0]))
+
+/* Update amd7930_map settings and program them into the hardware.
+ * The amd->lock is held and local interrupts are disabled.
+ */
+static void __amd7930_update_map(amd7930_t *amd)
+{
+	struct amd7930_map *map = &amd->map;
+	int level;
+
+	map->gx = gx_coeff[amd->rgain];
+	map->stgr = gx_coeff[amd->mgain];
+	level = (amd->pgain * (256 + NR_GER_COEFFS)) >> 8;
+	if (level >= 256) {
+		map->ger = ger_coeff[level - 256];
+		map->gr = gx_coeff[255];
+	} else {
+		map->ger = ger_coeff[0];
+		map->gr = gx_coeff[level];
+	}
+	__amd7930_write_map(amd);
+}
+
+static void snd_amd7930_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	amd7930_t *amd = dev_id;
+	unsigned int elapsed;
+	u8 ir;
+
+	spin_lock(&amd->lock);
+
+	elapsed = 0;
+
+	ir = sbus_readb(amd->regs + AMD7930_IR);
+	if (ir & AMR_IR_BBUF) {
+		u8 byte;
+
+		if (amd->flags & AMD7930_FLAG_PLAYBACK) {
+			if (amd->p_left > 0) {
+				byte = *(amd->p_cur++);
+				amd->p_left--;
+				sbus_writeb(byte, amd->regs + AMD7930_BBTB);
+				if (amd->p_left == 0)
+					elapsed |= AMD7930_FLAG_PLAYBACK;
+			} else
+				sbus_writeb(0, amd->regs + AMD7930_BBTB);
+		} else if (amd->flags & AMD7930_FLAG_CAPTURE) {
+			byte = sbus_readb(amd->regs + AMD7930_BBRB);
+			if (amd->c_left > 0) {
+				*(amd->c_cur++) = byte;
+				amd->c_left--;
+				if (amd->c_left == 0)
+					elapsed |= AMD7930_FLAG_CAPTURE;
+			}
+		}
+	}
+	spin_unlock(&amd->lock);
+
+	if (elapsed & AMD7930_FLAG_PLAYBACK)
+		snd_pcm_period_elapsed(amd->playback_substream);
+	else
+		snd_pcm_period_elapsed(amd->capture_substream);
+}
+
+static int snd_amd7930_trigger(amd7930_t *amd, unsigned int flag, int cmd)
+{
+	unsigned long flags;
+	int result = 0;
+
+	spin_lock_irqsave(&amd->lock, flags);
+	if (cmd == SNDRV_PCM_TRIGGER_START) {
+		if (!(amd->flags & flag)) {
+			amd->flags |= flag;
+
+			/* Enable B channel interrupts.  */
+			sbus_writeb(AMR_MUX_MCR4, amd->regs + AMD7930_CR);
+			sbus_writeb(AM_MUX_MCR4_ENABLE_INTS, amd->regs + AMD7930_DR);
+		}
+	} else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
+		if (amd->flags & flag) {
+			amd->flags &= ~flag;
+
+			/* Disable B channel interrupts.  */
+			sbus_writeb(AMR_MUX_MCR4, amd->regs + AMD7930_CR);
+			sbus_writeb(0, amd->regs + AMD7930_DR);
+		}
+	} else {
+		result = -EINVAL;
+	}
+	spin_unlock_irqrestore(&amd->lock, flags);
+
+	return result;
+}
+
+static int snd_amd7930_playback_trigger(snd_pcm_substream_t * substream,
+					int cmd)
+{
+	amd7930_t *amd = snd_pcm_substream_chip(substream);
+	return snd_amd7930_trigger(amd, AMD7930_FLAG_PLAYBACK, cmd);
+}
+
+static int snd_amd7930_capture_trigger(snd_pcm_substream_t * substream,
+				       int cmd)
+{
+	amd7930_t *amd = snd_pcm_substream_chip(substream);
+	return snd_amd7930_trigger(amd, AMD7930_FLAG_CAPTURE, cmd);
+}
+
+static int snd_amd7930_playback_prepare(snd_pcm_substream_t * substream)
+{
+	amd7930_t *amd = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	unsigned int size = snd_pcm_lib_buffer_bytes(substream);
+	unsigned long flags;
+	u8 new_mmr1;
+
+	spin_lock_irqsave(&amd->lock, flags);
+
+	amd->flags |= AMD7930_FLAG_PLAYBACK;
+
+	/* Setup the pseudo-dma transfer pointers.  */
+	amd->p_orig = amd->p_cur = runtime->dma_area;
+	amd->p_left = size;
+
+	/* Put the chip into the correct encoding format.  */
+	new_mmr1 = amd->map.mmr1;
+	if (runtime->format == SNDRV_PCM_FORMAT_A_LAW)
+		new_mmr1 |= AM_MAP_MMR1_ALAW;
+	else
+		new_mmr1 &= ~AM_MAP_MMR1_ALAW;
+	if (new_mmr1 != amd->map.mmr1) {
+		amd->map.mmr1 = new_mmr1;
+		__amd7930_update_map(amd);
+	}
+
+	spin_unlock_irqrestore(&amd->lock, flags);
+
+	return 0;
+}
+
+static int snd_amd7930_capture_prepare(snd_pcm_substream_t * substream)
+{
+	amd7930_t *amd = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	unsigned int size = snd_pcm_lib_buffer_bytes(substream);
+	unsigned long flags;
+	u8 new_mmr1;
+
+	spin_lock_irqsave(&amd->lock, flags);
+
+	amd->flags |= AMD7930_FLAG_CAPTURE;
+
+	/* Setup the pseudo-dma transfer pointers.  */
+	amd->c_orig = amd->c_cur = runtime->dma_area;
+	amd->c_left = size;
+
+	/* Put the chip into the correct encoding format.  */
+	new_mmr1 = amd->map.mmr1;
+	if (runtime->format == SNDRV_PCM_FORMAT_A_LAW)
+		new_mmr1 |= AM_MAP_MMR1_ALAW;
+	else
+		new_mmr1 &= ~AM_MAP_MMR1_ALAW;
+	if (new_mmr1 != amd->map.mmr1) {
+		amd->map.mmr1 = new_mmr1;
+		__amd7930_update_map(amd);
+	}
+
+	spin_unlock_irqrestore(&amd->lock, flags);
+
+	return 0;
+}
+
+static snd_pcm_uframes_t snd_amd7930_playback_pointer(snd_pcm_substream_t * substream)
+{
+	amd7930_t *amd = snd_pcm_substream_chip(substream);
+	size_t ptr;
+
+	if (!(amd->flags & AMD7930_FLAG_PLAYBACK))
+		return 0;
+	ptr = amd->p_cur - amd->p_orig;
+	return bytes_to_frames(substream->runtime, ptr);
+}
+
+static snd_pcm_uframes_t snd_amd7930_capture_pointer(snd_pcm_substream_t * substream)
+{
+	amd7930_t *amd = snd_pcm_substream_chip(substream);
+	size_t ptr;
+
+	if (!(amd->flags & AMD7930_FLAG_CAPTURE))
+		return 0;
+
+	ptr = amd->c_cur - amd->c_orig;
+	return bytes_to_frames(substream->runtime, ptr);
+}
+
+/* Playback and capture have identical properties.  */
+static snd_pcm_hardware_t snd_amd7930_pcm_hw =
+{
+	.info			= (SNDRV_PCM_INFO_MMAP |
+				   SNDRV_PCM_INFO_MMAP_VALID |
+				   SNDRV_PCM_INFO_INTERLEAVED |
+				   SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				   SNDRV_PCM_INFO_HALF_DUPLEX),
+	.formats		= SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW,
+	.rates			= SNDRV_PCM_RATE_8000,
+	.rate_min		= 8000,
+	.rate_max		= 8000,
+	.channels_min		= 1,
+	.channels_max		= 1,
+	.buffer_bytes_max	= (64*1024),
+	.period_bytes_min	= 1,
+	.period_bytes_max	= (64*1024),
+	.periods_min		= 1,
+	.periods_max		= 1024,
+};
+
+static int snd_amd7930_playback_open(snd_pcm_substream_t * substream)
+{
+	amd7930_t *amd = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+
+	amd->playback_substream = substream;
+	runtime->hw = snd_amd7930_pcm_hw;
+	return 0;
+}
+
+static int snd_amd7930_capture_open(snd_pcm_substream_t * substream)
+{
+	amd7930_t *amd = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+
+	amd->capture_substream = substream;
+	runtime->hw = snd_amd7930_pcm_hw;
+	return 0;
+}
+
+static int snd_amd7930_playback_close(snd_pcm_substream_t * substream)
+{
+	amd7930_t *amd = snd_pcm_substream_chip(substream);
+
+	amd->playback_substream = NULL;
+	return 0;
+}
+
+static int snd_amd7930_capture_close(snd_pcm_substream_t * substream)
+{
+	amd7930_t *amd = snd_pcm_substream_chip(substream);
+
+	amd->capture_substream = NULL;
+	return 0;
+}
+
+static int snd_amd7930_hw_params(snd_pcm_substream_t * substream,
+				    snd_pcm_hw_params_t * hw_params)
+{
+	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
+}
+
+static int snd_amd7930_hw_free(snd_pcm_substream_t * substream)
+{
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static snd_pcm_ops_t snd_amd7930_playback_ops = {
+	.open		=	snd_amd7930_playback_open,
+	.close		=	snd_amd7930_playback_close,
+	.ioctl		=	snd_pcm_lib_ioctl,
+	.hw_params	=	snd_amd7930_hw_params,
+	.hw_free	=	snd_amd7930_hw_free,
+	.prepare	=	snd_amd7930_playback_prepare,
+	.trigger	=	snd_amd7930_playback_trigger,
+	.pointer	=	snd_amd7930_playback_pointer,
+};
+
+static snd_pcm_ops_t snd_amd7930_capture_ops = {
+	.open		=	snd_amd7930_capture_open,
+	.close		=	snd_amd7930_capture_close,
+	.ioctl		=	snd_pcm_lib_ioctl,
+	.hw_params	=	snd_amd7930_hw_params,
+	.hw_free	=	snd_amd7930_hw_free,
+	.prepare	=	snd_amd7930_capture_prepare,
+	.trigger	=	snd_amd7930_capture_trigger,
+	.pointer	=	snd_amd7930_capture_pointer,
+};
+
+static void snd_amd7930_pcm_free(snd_pcm_t *pcm)
+{
+	amd7930_t *amd = snd_magic_cast(amd7930_t, pcm->private_data, return);
+
+	amd->pcm = NULL;
+	snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static int __init snd_amd7930_pcm(amd7930_t *amd)
+{
+	snd_pcm_t *pcm;
+	int err;
+
+	if ((err = snd_pcm_new(amd->card,
+			       /* ID */             "sun_amd7930",
+			       /* device */         0,
+			       /* playback count */ 1,
+			       /* capture count */  1, &pcm)) < 0)
+		return err;
+	snd_assert(pcm != NULL, return -EINVAL);
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_amd7930_playback_ops);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_amd7930_capture_ops);
+
+	pcm->private_data = amd;
+	pcm->private_free = snd_amd7930_pcm_free;
+	pcm->info_flags = 0;
+	strcpy(pcm->name, amd->card->shortname);
+	amd->pcm = pcm;
+
+	snd_pcm_lib_preallocate_pages_for_all(pcm, 64*1024, 64*1024, GFP_KERNEL);
+
+	return 0;
+}
+
+#define VOLUME_MONITOR	0
+#define VOLUME_CAPTURE	1
+#define VOLUME_PLAYBACK	2
+
+static int snd_amd7930_info_volume(snd_kcontrol_t *kctl, snd_ctl_elem_info_t *uinfo)
+{
+	int type = kctl->private_value;
+
+	snd_assert(type == VOLUME_MONITOR ||
+		   type == VOLUME_CAPTURE ||
+		   type == VOLUME_PLAYBACK, return -EINVAL);
+	(void) type;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 255;
+
+	return 0;
+}
+
+static int snd_amd7930_get_volume(snd_kcontrol_t *kctl, snd_ctl_elem_value_t *ucontrol)
+{
+	amd7930_t *amd = snd_kcontrol_chip(kctl);
+	int type = kctl->private_value;
+	int *swval;
+
+	snd_assert(type == VOLUME_MONITOR ||
+		   type == VOLUME_CAPTURE ||
+		   type == VOLUME_PLAYBACK, return -EINVAL);
+
+	switch (type) {
+	case VOLUME_MONITOR:
+		swval = &amd->mgain;
+		break;
+	case VOLUME_CAPTURE:
+		swval = &amd->rgain;
+		break;
+	case VOLUME_PLAYBACK:
+	default:
+		swval = &amd->pgain;
+		break;
+	};
+
+	ucontrol->value.integer.value[0] = *swval;
+
+	return 0;
+}
+
+static int snd_amd7930_put_volume(snd_kcontrol_t *kctl, snd_ctl_elem_value_t *ucontrol)
+{
+	amd7930_t *amd = snd_kcontrol_chip(kctl);
+	unsigned long flags;
+	int type = kctl->private_value;
+	int *swval, change;
+
+	snd_assert(type == VOLUME_MONITOR ||
+		   type == VOLUME_CAPTURE ||
+		   type == VOLUME_PLAYBACK, return -EINVAL);
+
+	switch (type) {
+	case VOLUME_MONITOR:
+		swval = &amd->mgain;
+		break;
+	case VOLUME_CAPTURE:
+		swval = &amd->rgain;
+		break;
+	case VOLUME_PLAYBACK:
+	default:
+		swval = &amd->pgain;
+		break;
+	};
+
+	spin_lock_irqsave(&amd->lock, flags);
+
+	if (*swval != ucontrol->value.integer.value[0]) {
+		*swval = ucontrol->value.integer.value[0];
+		__amd7930_update_map(amd);
+		change = 1;
+	} else
+		change = 0;
+
+	spin_unlock_irqrestore(&amd->lock, flags);
+
+	return change;
+}
+
+static snd_kcontrol_new_t amd7930_controls[] __initdata = {
+	{
+		.iface		=	SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name		=	"Monitor Volume",
+		.index		=	0,
+		.info		=	snd_amd7930_info_volume,
+		.get		=	snd_amd7930_get_volume,
+		.put		=	snd_amd7930_put_volume,
+		.private_value	=	VOLUME_MONITOR,
+	},
+	{
+		.iface		=	SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name		=	"Capture Volume",
+		.index		=	0,
+		.info		=	snd_amd7930_info_volume,
+		.get		=	snd_amd7930_get_volume,
+		.put		=	snd_amd7930_put_volume,
+		.private_value	=	VOLUME_CAPTURE,
+	},
+	{
+		.iface		=	SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name		=	"Playback Volume",
+		.index		=	0,
+		.info		=	snd_amd7930_info_volume,
+		.get		=	snd_amd7930_get_volume,
+		.put		=	snd_amd7930_put_volume,
+		.private_value	=	VOLUME_PLAYBACK,
+	},
+};
+
+#define NUM_AMD7930_CONTROLS (sizeof(amd7930_controls)/sizeof(snd_kcontrol_new_t))
+
+static int __init snd_amd7930_mixer(amd7930_t *amd)
+{
+	snd_card_t *card;
+	int idx, err;
+
+	snd_assert(amd != NULL && amd->card != NULL, return -EINVAL);
+
+	card = amd->card;
+	strcpy(card->mixername, card->shortname);
+
+	for (idx = 0; idx < NUM_AMD7930_CONTROLS; idx++) {
+		if ((err = snd_ctl_add(card,
+				       snd_ctl_new1(&amd7930_controls[idx], amd))) < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+static int snd_amd7930_free(amd7930_t *amd)
+{
+	amd7930_idle(amd);
+
+	if (amd->irq)
+		free_irq(amd->irq, amd);
+
+	if (amd->regs)
+		sbus_iounmap(amd->regs, amd->regs_size);
+
+	snd_magic_kfree(amd);
+
+	return 0;
+}
+
+static int snd_amd7930_dev_free(snd_device_t *device)
+{
+	amd7930_t *amd = snd_magic_cast(amd7930_t, device->device_data, return -ENXIO);
+
+	return snd_amd7930_free(amd);
+}
+
+static snd_device_ops_t snd_amd7930_dev_ops = {
+	.dev_free	=	snd_amd7930_dev_free,
+};
+
+static int __init snd_amd7930_create(snd_card_t *card,
+				     struct sbus_dev *sdev,
+				     struct resource *rp,
+				     unsigned int reg_size,
+				     struct linux_prom_irqs *irq_prop,
+				     int dev,
+				     amd7930_t **ramd)
+{
+	unsigned long flags;
+	amd7930_t *amd;
+	int err;
+
+	*ramd = NULL;
+	amd = snd_magic_kcalloc(amd7930_t, 0, GFP_KERNEL);
+	if (amd == NULL)
+		return -ENOMEM;
+
+	spin_lock_init(&amd->lock);
+	amd->card = card;
+	amd->sdev = sdev;
+	amd->regs_size = reg_size;
+
+	amd->regs = sbus_ioremap(rp, 0, amd->regs_size, "amd7930");
+	if (!amd->regs) {
+		snd_printk("amd7930-%d: Unable to map chip registers.\n", dev);
+		return -EIO;
+	}
+
+	amd7930_idle(amd);
+
+	if (request_irq(irq_prop->pri, snd_amd7930_interrupt,
+			SA_INTERRUPT | SA_SHIRQ, "amd7930", amd)) {
+		snd_amd7930_free(amd);
+		snd_printk("amd7930-%d: Unable to grab IRQ %s\n",
+			   dev,
+			   __irq_itoa(irq_prop->pri));
+		return -EBUSY;
+	}
+	amd->irq = irq_prop->pri;
+
+	amd7930_enable_ints(amd);
+
+	spin_lock_irqsave(&amd->lock, flags);
+
+	amd->rgain = 128;
+	amd->pgain = 200;
+	amd->mgain = 0;
+
+	memset(&amd->map, 0, sizeof(amd->map));
+	amd->map.mmr1 = (AM_MAP_MMR1_GX | AM_MAP_MMR1_GER |
+			 AM_MAP_MMR1_GR | AM_MAP_MMR1_STG);
+	amd->map.mmr2 = (AM_MAP_MMR2_LS | AM_MAP_MMR2_AINB);
+
+	__amd7930_update_map(amd);
+
+	/* Always MUX audio (Ba) to channel Bb. */
+	sbus_writeb(AMR_MUX_MCR1, amd->regs + AMD7930_CR);
+	sbus_writeb(AM_MUX_CHANNEL_Ba | (AM_MUX_CHANNEL_Bb << 4),
+		    amd->regs + AMD7930_DR);
+
+	spin_unlock_irqrestore(&amd->lock, flags);
+
+	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL,
+				  amd, &snd_amd7930_dev_ops)) < 0) {
+		snd_amd7930_free(amd);
+		return err;
+	}
+
+	*ramd = amd;
+	return 0;
+}
+
+static int __init amd7930_attach(int prom_node, struct sbus_dev *sdev)
+{
+	static int dev;
+	struct linux_prom_registers reg_prop;
+	struct linux_prom_irqs irq_prop;
+	struct resource res, *rp;
+	snd_card_t *card;
+	amd7930_t *amd;
+	int err;
+
+	if (dev >= SNDRV_CARDS)
+		return -ENODEV;
+	if (!snd_enable[dev]) {
+		dev++;
+		return -ENOENT;
+	}
+
+	err = prom_getproperty(prom_node, "intr",
+			       (char *) &irq_prop, sizeof(irq_prop));
+	if (err < 0) {
+		snd_printk("amd7930-%d: Firmware node lacks IRQ property.\n", dev);
+		return -ENODEV;
+	}
+
+	err = prom_getproperty(prom_node, "reg",
+			       (char *) &reg_prop, sizeof(reg_prop));
+	if (err < 0) {
+		snd_printk("amd7930-%d: Firmware node lacks register property.\n", dev);
+		return -ENODEV;
+	}
+
+	if (sdev) {
+		rp = &sdev->resource[0];
+	} else {
+		rp = &res;
+		rp->start = reg_prop.phys_addr;
+		rp->end = rp->start + reg_prop.reg_size - 1;
+		rp->flags = IORESOURCE_IO | (reg_prop.which_io & 0xff);
+	}
+
+	card = snd_card_new(snd_index[dev], snd_id[dev], THIS_MODULE, 0);
+	if (card == NULL)
+		return -ENOMEM;
+
+	strcpy(card->driver, "AMD7930");
+	strcpy(card->shortname, "Sun AMD7930");
+	sprintf(card->longname, "%s at 0x%02lx:0x%08lx, irq %s",
+		card->shortname,
+		rp->flags & 0xffL,
+		rp->start,
+		__irq_itoa(irq_prop.pri));
+
+	if ((err = snd_amd7930_create(card, sdev, rp, reg_prop.reg_size,
+					  &irq_prop, dev, &amd)) < 0)
+		goto out_err;
+
+	if ((err = snd_amd7930_pcm(amd)) < 0)
+		goto out_err;
+
+	if ((err = snd_amd7930_mixer(amd)) < 0)
+		goto out_err;
+
+	if ((err = snd_card_register(card)) < 0)
+		goto out_err;
+
+	amd->next = amd7930_list;
+	amd7930_list = amd;
+
+	dev++;
+	return 0;
+
+out_err:
+	snd_card_free(card);
+	return err;
+}
+
+static int __init amd7930_init(void)
+{
+	struct sbus_bus *sbus;
+	struct sbus_dev *sdev;
+	int node, found;
+
+	found = 0;
+
+	/* Try to find the sun4c "audio" node first. */
+	node = prom_getchild(prom_root_node);
+	node = prom_searchsiblings(node, "audio");
+	if (node && amd7930_attach(node, NULL) == 0)
+		found++;
+
+	/* Probe each SBUS for amd7930 chips. */
+	for_all_sbusdev(sdev, sbus) {
+		if (!strcmp(sdev->prom_name, "audio")) {
+			if (amd7930_attach(sdev->prom_node, sdev) == 0)
+				found++;
+		}
+	}
+
+	return (found > 0) ? 0 : -EIO;
+}
+
+static void __exit amd7930_exit(void)
+{
+	amd7930_t *p = amd7930_list;
+
+	while (p != NULL) {
+		amd7930_t *next = p->next;
+
+		snd_card_free(p->card);
+
+		p = next;
+	}
+
+	amd7930_list = NULL;
+}
+
+module_init(amd7930_init);
+module_exit(amd7930_exit);
+
+#ifndef MODULE
+
+/* format is: snd-sun-amd7930=snd_index,snd_id,snd_enable */
+
+static int __init alsa_card_sun_amd7930_setup(char *str)
+{
+	static unsigned __initdata nr_dev = 0;
+
+	if (nr_dev >= SNDRV_CARDS)
+		return 0;
+	(void)(get_option(&str,&snd_index[nr_dev]) == 2 &&
+	       get_option(&str,&snd_id[nr_dev]) == 2 &&
+	       get_id(&str,&snd_enable[nr_dev]) == 2);
+	nr_dev++;
+	return 1;
+}
+
+__setup("snd-sun-amd7930=", alsa_card_sun_amd7930_setup);
+
+#endif /* ifndef MODULE */
diff -Nru a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/sparc/cs4231.c	Tue Oct  1 00:08:22 2002
@@ -0,0 +1,2271 @@
+/*
+ * Driver for CS4231 sound chips found on Sparcs.
+ * Copyright (C) 2002 David S. Miller <davem@redhat.com>
+ *
+ * Based entirely upon drivers/sbus/audio/cs4231.c which is:
+ * Copyright (C) 1996, 1997, 1998, 1998 Derrick J Brashear (shadow@andrew.cmu.edu)
+ * and also sound/isa/cs423x/cs4231_lib.c which is:
+ * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/info.h>
+#include <sound/control.h>
+#include <sound/timer.h>
+#define SNDRV_GET_ID
+#include <sound/initval.h>
+#include <sound/pcm_params.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#ifdef CONFIG_SBUS
+#define SBUS_SUPPORT
+#endif
+
+#ifdef SBUS_SUPPORT
+#include <asm/sbus.h>
+#endif
+
+#if defined(CONFIG_PCI) && defined(CONFIG_SPARC64)
+#define EBUS_SUPPORT
+#endif
+
+#ifdef EBUS_SUPPORT
+#include <linux/pci.h>
+#include <asm/ebus.h>
+#endif
+
+static int snd_index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
+static char *snd_id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
+static int snd_enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
+
+MODULE_PARM(snd_index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(snd_index, "Index value for Sun CS4231 soundcard.");
+MODULE_PARM_SYNTAX(snd_index, SNDRV_INDEX_DESC);
+MODULE_PARM(snd_id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
+MODULE_PARM_DESC(snd_id, "ID string for Sun CS4231 soundcard.");
+MODULE_PARM_SYNTAX(snd_id, SNDRV_ID_DESC);
+MODULE_PARM(snd_enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(snd_enable, "Enable Sun CS4231 soundcard.");
+MODULE_PARM_SYNTAX(snd_enable, SNDRV_ENABLE_DESC);
+MODULE_AUTHOR("Jaroslav Kysela, Derrick J. Brashear and David S. Miller");
+MODULE_DESCRIPTION("Sun CS4231");
+MODULE_LICENSE("GPL");
+MODULE_CLASSES("{sound}");
+MODULE_DEVICES("{{Sun,CS4231}}");
+
+typedef struct snd_cs4231 {
+	spinlock_t		lock;
+	unsigned long		port;
+#ifdef EBUS_SUPPORT
+	struct ebus_dma_info	eb2c;
+	struct ebus_dma_info	eb2p;
+#endif
+
+	u32			flags;
+#define CS4231_FLAG_EBUS	0x00000001
+#define CS4231_FLAG_PLAYBACK	0x00000002
+#define CS4231_FLAG_CAPTURE	0x00000004
+
+	snd_card_t		*card;
+	snd_pcm_t		*pcm;
+	snd_pcm_substream_t	*playback_substream;
+	unsigned int		p_periods_sent;
+	snd_pcm_substream_t	*capture_substream;
+	unsigned int		c_periods_sent;
+	snd_timer_t		*timer;
+
+	unsigned short mode;
+#define CS4231_MODE_NONE	0x0000
+#define CS4231_MODE_PLAY	0x0001
+#define CS4231_MODE_RECORD	0x0002
+#define CS4231_MODE_TIMER	0x0004
+#define CS4231_MODE_OPEN	(CS4231_MODE_PLAY|CS4231_MODE_RECORD|CS4231_MODE_TIMER)
+
+	unsigned char		image[32];	/* registers image */
+	int			mce_bit;
+	int			calibrate_mute;
+	struct semaphore	mce_mutex;
+	struct semaphore	open_mutex;
+
+	union {
+#ifdef SBUS_SUPPORT
+		struct sbus_dev		*sdev;
+#endif
+#ifdef EBUS_SUPPORT
+		struct pci_dev		*pdev;
+#endif
+	} dev_u;
+	unsigned int		irq[2];
+	unsigned int		regs_size;
+	struct snd_cs4231	*next;
+} cs4231_t;
+#define chip_t cs4231_t
+
+static cs4231_t *cs4231_list;
+
+/* Eventually we can use sound/isa/cs423x/cs4231_lib.c directly, but for
+ * now....  -DaveM
+ */
+
+/* IO ports */
+
+#define CS4231P(chip, x)	((chip)->port + c_d_c_CS4231##x)
+
+/* XXX offsets are different than PC ISA chips... */
+#define c_d_c_CS4231REGSEL	0x0
+#define c_d_c_CS4231REG		0x4
+#define c_d_c_CS4231STATUS	0x8
+#define c_d_c_CS4231PIO		0xc
+
+/* codec registers */
+
+#define CS4231_LEFT_INPUT	0x00	/* left input control */
+#define CS4231_RIGHT_INPUT	0x01	/* right input control */
+#define CS4231_AUX1_LEFT_INPUT	0x02	/* left AUX1 input control */
+#define CS4231_AUX1_RIGHT_INPUT	0x03	/* right AUX1 input control */
+#define CS4231_AUX2_LEFT_INPUT	0x04	/* left AUX2 input control */
+#define CS4231_AUX2_RIGHT_INPUT	0x05	/* right AUX2 input control */
+#define CS4231_LEFT_OUTPUT	0x06	/* left output control register */
+#define CS4231_RIGHT_OUTPUT	0x07	/* right output control register */
+#define CS4231_PLAYBK_FORMAT	0x08	/* clock and data format - playback - bits 7-0 MCE */
+#define CS4231_IFACE_CTRL	0x09	/* interface control - bits 7-2 MCE */
+#define CS4231_PIN_CTRL		0x0a	/* pin control */
+#define CS4231_TEST_INIT	0x0b	/* test and initialization */
+#define CS4231_MISC_INFO	0x0c	/* miscellaneaous information */
+#define CS4231_LOOPBACK		0x0d	/* loopback control */
+#define CS4231_PLY_UPR_CNT	0x0e	/* playback upper base count */
+#define CS4231_PLY_LWR_CNT	0x0f	/* playback lower base count */
+#define CS4231_ALT_FEATURE_1	0x10	/* alternate #1 feature enable */
+#define CS4231_ALT_FEATURE_2	0x11	/* alternate #2 feature enable */
+#define CS4231_LEFT_LINE_IN	0x12	/* left line input control */
+#define CS4231_RIGHT_LINE_IN	0x13	/* right line input control */
+#define CS4231_TIMER_LOW	0x14	/* timer low byte */
+#define CS4231_TIMER_HIGH	0x15	/* timer high byte */
+#define CS4231_LEFT_MIC_INPUT	0x16	/* left MIC input control register (InterWave only) */
+#define CS4231_RIGHT_MIC_INPUT	0x17	/* right MIC input control register (InterWave only) */
+#define CS4236_EXT_REG		0x17	/* extended register access */
+#define CS4231_IRQ_STATUS	0x18	/* irq status register */
+#define CS4231_LINE_LEFT_OUTPUT	0x19	/* left line output control register (InterWave only) */
+#define CS4231_VERSION		0x19	/* CS4231(A) - version values */
+#define CS4231_MONO_CTRL	0x1a	/* mono input/output control */
+#define CS4231_LINE_RIGHT_OUTPUT 0x1b	/* right line output control register (InterWave only) */
+#define CS4235_LEFT_MASTER	0x1b	/* left master output control */
+#define CS4231_REC_FORMAT	0x1c	/* clock and data format - record - bits 7-0 MCE */
+#define CS4231_PLY_VAR_FREQ	0x1d	/* playback variable frequency */
+#define CS4235_RIGHT_MASTER	0x1d	/* right master output control */
+#define CS4231_REC_UPR_CNT	0x1e	/* record upper count */
+#define CS4231_REC_LWR_CNT	0x1f	/* record lower count */
+
+/* definitions for codec register select port - CODECP( REGSEL ) */
+
+#define CS4231_INIT		0x80	/* CODEC is initializing */
+#define CS4231_MCE		0x40	/* mode change enable */
+#define CS4231_TRD		0x20	/* transfer request disable */
+
+/* definitions for codec status register - CODECP( STATUS ) */
+
+#define CS4231_GLOBALIRQ	0x01	/* IRQ is active */
+
+/* definitions for codec irq status */
+
+#define CS4231_PLAYBACK_IRQ	0x10
+#define CS4231_RECORD_IRQ	0x20
+#define CS4231_TIMER_IRQ	0x40
+#define CS4231_ALL_IRQS		0x70
+#define CS4231_REC_UNDERRUN	0x08
+#define CS4231_REC_OVERRUN	0x04
+#define CS4231_PLY_OVERRUN	0x02
+#define CS4231_PLY_UNDERRUN	0x01
+
+/* definitions for CS4231_LEFT_INPUT and CS4231_RIGHT_INPUT registers */
+
+#define CS4231_ENABLE_MIC_GAIN	0x20
+
+#define CS4231_MIXS_LINE	0x00
+#define CS4231_MIXS_AUX1	0x40
+#define CS4231_MIXS_MIC		0x80
+#define CS4231_MIXS_ALL		0xc0
+
+/* definitions for clock and data format register - CS4231_PLAYBK_FORMAT */
+
+#define CS4231_LINEAR_8		0x00	/* 8-bit unsigned data */
+#define CS4231_ALAW_8		0x60	/* 8-bit A-law companded */
+#define CS4231_ULAW_8		0x20	/* 8-bit U-law companded */
+#define CS4231_LINEAR_16	0x40	/* 16-bit twos complement data - little endian */
+#define CS4231_LINEAR_16_BIG	0xc0	/* 16-bit twos complement data - big endian */
+#define CS4231_ADPCM_16		0xa0	/* 16-bit ADPCM */
+#define CS4231_STEREO		0x10	/* stereo mode */
+/* bits 3-1 define frequency divisor */
+#define CS4231_XTAL1		0x00	/* 24.576 crystal */
+#define CS4231_XTAL2		0x01	/* 16.9344 crystal */
+
+/* definitions for interface control register - CS4231_IFACE_CTRL */
+
+#define CS4231_RECORD_PIO	0x80	/* record PIO enable */
+#define CS4231_PLAYBACK_PIO	0x40	/* playback PIO enable */
+#define CS4231_CALIB_MODE	0x18	/* calibration mode bits */
+#define CS4231_AUTOCALIB	0x08	/* auto calibrate */
+#define CS4231_SINGLE_DMA	0x04	/* use single DMA channel */
+#define CS4231_RECORD_ENABLE	0x02	/* record enable */
+#define CS4231_PLAYBACK_ENABLE	0x01	/* playback enable */
+
+/* definitions for pin control register - CS4231_PIN_CTRL */
+
+#define CS4231_IRQ_ENABLE	0x02	/* enable IRQ */
+#define CS4231_XCTL1		0x40	/* external control #1 */
+#define CS4231_XCTL0		0x80	/* external control #0 */
+
+/* definitions for test and init register - CS4231_TEST_INIT */
+
+#define CS4231_CALIB_IN_PROGRESS 0x20	/* auto calibrate in progress */
+#define CS4231_DMA_REQUEST	0x10	/* DMA request in progress */
+
+/* definitions for misc control register - CS4231_MISC_INFO */
+
+#define CS4231_MODE2		0x40	/* MODE 2 */
+#define CS4231_IW_MODE3		0x6c	/* MODE 3 - InterWave enhanced mode */
+#define CS4231_4236_MODE3	0xe0	/* MODE 3 - CS4236+ enhanced mode */
+
+/* definitions for alternate feature 1 register - CS4231_ALT_FEATURE_1 */
+
+#define	CS4231_DACZ		0x01	/* zero DAC when underrun */
+#define CS4231_TIMER_ENABLE	0x40	/* codec timer enable */
+#define CS4231_OLB		0x80	/* output level bit */
+
+/* SBUS DMA register defines.  */
+
+#define APCCSR	0x10UL	/* APC DMA CSR */
+#define APCCVA	0x20UL	/* APC Capture DMA Address */
+#define APCCC	0x24UL	/* APC Capture Count */
+#define APCCNVA	0x28UL	/* APC Capture DMA Next Address */
+#define APCCNC	0x2cUL	/* APC Capture Next Count */
+#define APCPVA	0x30UL	/* APC Play DMA Address */
+#define APCPC	0x34UL	/* APC Play Count */
+#define APCPNVA	0x38UL	/* APC Play DMA Next Address */
+#define APCPNC	0x3cUL	/* APC Play Next Count */
+
+/* APCCSR bits */
+
+#define APC_INT_PENDING 0x800000 /* Interrupt Pending */
+#define APC_PLAY_INT    0x400000 /* Playback interrupt */
+#define APC_CAPT_INT    0x200000 /* Capture interrupt */
+#define APC_GENL_INT    0x100000 /* General interrupt */
+#define APC_XINT_ENA    0x80000  /* General ext int. enable */
+#define APC_XINT_PLAY   0x40000  /* Playback ext intr */
+#define APC_XINT_CAPT   0x20000  /* Capture ext intr */
+#define APC_XINT_GENL   0x10000  /* Error ext intr */
+#define APC_XINT_EMPT   0x8000   /* Pipe empty interrupt (0 write to pva) */
+#define APC_XINT_PEMP   0x4000   /* Play pipe empty (pva and pnva not set) */
+#define APC_XINT_PNVA   0x2000   /* Playback NVA dirty */
+#define APC_XINT_PENA   0x1000   /* play pipe empty Int enable */
+#define APC_XINT_COVF   0x800    /* Cap data dropped on floor */
+#define APC_XINT_CNVA   0x400    /* Capture NVA dirty */
+#define APC_XINT_CEMP   0x200    /* Capture pipe empty (cva and cnva not set) */
+#define APC_XINT_CENA   0x100    /* Cap. pipe empty int enable */
+#define APC_PPAUSE      0x80     /* Pause the play DMA */
+#define APC_CPAUSE      0x40     /* Pause the capture DMA */
+#define APC_CDC_RESET   0x20     /* CODEC RESET */
+#define APC_PDMA_READY  0x08     /* Play DMA Go */
+#define APC_CDMA_READY  0x04     /* Capture DMA Go */
+#define APC_CHIP_RESET  0x01     /* Reset the chip */
+
+/* EBUS DMA register offsets  */
+
+#define EBDMA_CSR	0x00UL	/* Control/Status */
+#define EBDMA_ADDR	0x04UL	/* DMA Address */
+#define EBDMA_COUNT	0x08UL	/* DMA Count */
+
+/*
+ *  Some variables
+ */
+
+static unsigned char freq_bits[14] = {
+	/* 5510 */	0x00 | CS4231_XTAL2,
+	/* 6620 */	0x0E | CS4231_XTAL2,
+	/* 8000 */	0x00 | CS4231_XTAL1,
+	/* 9600 */	0x0E | CS4231_XTAL1,
+	/* 11025 */	0x02 | CS4231_XTAL2,
+	/* 16000 */	0x02 | CS4231_XTAL1,
+	/* 18900 */	0x04 | CS4231_XTAL2,
+	/* 22050 */	0x06 | CS4231_XTAL2,
+	/* 27042 */	0x04 | CS4231_XTAL1,
+	/* 32000 */	0x06 | CS4231_XTAL1,
+	/* 33075 */	0x0C | CS4231_XTAL2,
+	/* 37800 */	0x08 | CS4231_XTAL2,
+	/* 44100 */	0x0A | CS4231_XTAL2,
+	/* 48000 */	0x0C | CS4231_XTAL1
+};
+
+static unsigned int rates[14] = {
+	5510, 6620, 8000, 9600, 11025, 16000, 18900, 22050,
+	27042, 32000, 33075, 37800, 44100, 48000
+};
+
+static snd_pcm_hw_constraint_list_t hw_constraints_rates = {
+	count: 14,
+	list: rates,
+	mask: 0,
+};
+
+static int snd_cs4231_xrate(snd_pcm_runtime_t *runtime)
+{
+	return snd_pcm_hw_constraint_list(runtime, 0,
+					  SNDRV_PCM_HW_PARAM_RATE,
+					  &hw_constraints_rates);
+}
+
+static unsigned char snd_cs4231_original_image[32] =
+{
+	0x00,			/* 00/00 - lic */
+	0x00,			/* 01/01 - ric */
+	0x9f,			/* 02/02 - la1ic */
+	0x9f,			/* 03/03 - ra1ic */
+	0x9f,			/* 04/04 - la2ic */
+	0x9f,			/* 05/05 - ra2ic */
+	0xbf,			/* 06/06 - loc */
+	0xbf,			/* 07/07 - roc */
+	0x20,			/* 08/08 - pdfr */
+	CS4231_AUTOCALIB,	/* 09/09 - ic */
+	0x00,			/* 0a/10 - pc */
+	0x00,			/* 0b/11 - ti */
+	CS4231_MODE2,		/* 0c/12 - mi */
+	0x00,			/* 0d/13 - lbc */
+	0x00,			/* 0e/14 - pbru */
+	0x00,			/* 0f/15 - pbrl */
+	0x80,			/* 10/16 - afei */
+	0x01,			/* 11/17 - afeii */
+	0x9f,			/* 12/18 - llic */
+	0x9f,			/* 13/19 - rlic */
+	0x00,			/* 14/20 - tlb */
+	0x00,			/* 15/21 - thb */
+	0x00,			/* 16/22 - la3mic/reserved */
+	0x00,			/* 17/23 - ra3mic/reserved */
+	0x00,			/* 18/24 - afs */
+	0x00,			/* 19/25 - lamoc/version */
+	0x00,			/* 1a/26 - mioc */
+	0x00,			/* 1b/27 - ramoc/reserved */
+	0x20,			/* 1c/28 - cdfr */
+	0x00,			/* 1d/29 - res4 */
+	0x00,			/* 1e/30 - cbru */
+	0x00,			/* 1f/31 - cbrl */
+};
+
+static u8 __cs4231_readb(cs4231_t *cp, unsigned long reg_addr)
+{
+#ifdef EBUS_SUPPORT
+	if (cp->flags & CS4231_FLAG_EBUS) {
+		return readb(reg_addr);
+	} else {
+#endif
+#ifdef SBUS_SUPPORT
+		return sbus_readb(reg_addr);
+#endif
+#ifdef EBUS_SUPPORT
+	}
+#endif
+}
+
+static void __cs4231_writeb(cs4231_t *cp, u8 val, unsigned long reg_addr)
+{
+#ifdef EBUS_SUPPORT
+	if (cp->flags & CS4231_FLAG_EBUS) {
+		return writeb(val, reg_addr);
+	} else {
+#endif
+#ifdef SBUS_SUPPORT
+		return sbus_writeb(val, reg_addr);
+#endif
+#ifdef EBUS_SUPPORT
+	}
+#endif
+}
+
+/*
+ *  Basic I/O functions
+ */
+
+void snd_cs4231_outm(cs4231_t *chip, unsigned char reg,
+		     unsigned char mask, unsigned char value)
+{
+	int timeout;
+	unsigned char tmp;
+
+	for (timeout = 250;
+	     timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT);
+	     timeout--)
+	     	udelay(100);
+#ifdef CONFIG_SND_DEBUG
+	if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)
+		snd_printk("outm: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
+#endif
+	if (chip->calibrate_mute) {
+		chip->image[reg] &= mask;
+		chip->image[reg] |= value;
+	} else {
+		__cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL));
+		mb();
+		tmp = (chip->image[reg] & mask) | value;
+		__cs4231_writeb(chip, tmp, CS4231P(chip, REG));
+		chip->image[reg] = tmp;
+		mb();
+	}
+}
+
+static void snd_cs4231_dout(cs4231_t *chip, unsigned char reg, unsigned char value)
+{
+	int timeout;
+
+	for (timeout = 250;
+	     timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT);
+	     timeout--)
+	     	udelay(100);
+	__cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL));
+	__cs4231_writeb(chip, value, CS4231P(chip, REG));
+	mb();
+}
+
+static void snd_cs4231_out(cs4231_t *chip, unsigned char reg, unsigned char value)
+{
+	int timeout;
+
+	for (timeout = 250;
+	     timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT);
+	     timeout--)
+	     	udelay(100);
+#ifdef CONFIG_SND_DEBUG
+	if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)
+		snd_printk("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
+#endif
+	__cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL));
+	__cs4231_writeb(chip, value, CS4231P(chip, REG));
+	chip->image[reg] = value;
+	mb();
+#if 0
+	printk("codec out - reg 0x%x = 0x%x\n", chip->mce_bit | reg, value);
+#endif
+}
+
+static unsigned char snd_cs4231_in(cs4231_t *chip, unsigned char reg)
+{
+	int timeout;
+	unsigned char ret;
+
+	for (timeout = 250;
+	     timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT);
+	     timeout--)
+	     	udelay(100);
+#ifdef CONFIG_SND_DEBUG
+	if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)
+		snd_printk("in: auto calibration time out - reg = 0x%x\n", reg);
+#endif
+	__cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL));
+	mb();
+	ret = __cs4231_readb(chip, CS4231P(chip, REG));
+#if 0
+	printk("codec in - reg 0x%x = 0x%x\n", chip->mce_bit | reg, ret);
+#endif
+	return ret;
+}
+
+#ifdef CONFIG_SND_DEBUG
+
+void snd_cs4231_debug(cs4231_t *chip)
+{
+	printk("CS4231 REGS:      INDEX = 0x%02x  ",
+	       __cs4231_readb(chip, CS4231P(chip, REGSEL)));
+	printk("                 STATUS = 0x%02x\n",
+	       __cs4231_readb(chip, CS4231P(chip, STATUS)));
+	printk("  0x00: left input      = 0x%02x  ", snd_cs4231_in(chip, 0x00));
+	printk("  0x10: alt 1 (CFIG 2)  = 0x%02x\n", snd_cs4231_in(chip, 0x10));
+	printk("  0x01: right input     = 0x%02x  ", snd_cs4231_in(chip, 0x01));
+	printk("  0x11: alt 2 (CFIG 3)  = 0x%02x\n", snd_cs4231_in(chip, 0x11));
+	printk("  0x02: GF1 left input  = 0x%02x  ", snd_cs4231_in(chip, 0x02));
+	printk("  0x12: left line in    = 0x%02x\n", snd_cs4231_in(chip, 0x12));
+	printk("  0x03: GF1 right input = 0x%02x  ", snd_cs4231_in(chip, 0x03));
+	printk("  0x13: right line in   = 0x%02x\n", snd_cs4231_in(chip, 0x13));
+	printk("  0x04: CD left input   = 0x%02x  ", snd_cs4231_in(chip, 0x04));
+	printk("  0x14: timer low       = 0x%02x\n", snd_cs4231_in(chip, 0x14));
+	printk("  0x05: CD right input  = 0x%02x  ", snd_cs4231_in(chip, 0x05));
+	printk("  0x15: timer high      = 0x%02x\n", snd_cs4231_in(chip, 0x15));
+	printk("  0x06: left output     = 0x%02x  ", snd_cs4231_in(chip, 0x06));
+	printk("  0x16: left MIC (PnP)  = 0x%02x\n", snd_cs4231_in(chip, 0x16));
+	printk("  0x07: right output    = 0x%02x  ", snd_cs4231_in(chip, 0x07));
+	printk("  0x17: right MIC (PnP) = 0x%02x\n", snd_cs4231_in(chip, 0x17));
+	printk("  0x08: playback format = 0x%02x  ", snd_cs4231_in(chip, 0x08));
+	printk("  0x18: IRQ status      = 0x%02x\n", snd_cs4231_in(chip, 0x18));
+	printk("  0x09: iface (CFIG 1)  = 0x%02x  ", snd_cs4231_in(chip, 0x09));
+	printk("  0x19: left line out   = 0x%02x\n", snd_cs4231_in(chip, 0x19));
+	printk("  0x0a: pin control     = 0x%02x  ", snd_cs4231_in(chip, 0x0a));
+	printk("  0x1a: mono control    = 0x%02x\n", snd_cs4231_in(chip, 0x1a));
+	printk("  0x0b: init & status   = 0x%02x  ", snd_cs4231_in(chip, 0x0b));
+	printk("  0x1b: right line out  = 0x%02x\n", snd_cs4231_in(chip, 0x1b));
+	printk("  0x0c: revision & mode = 0x%02x  ", snd_cs4231_in(chip, 0x0c));
+	printk("  0x1c: record format   = 0x%02x\n", snd_cs4231_in(chip, 0x1c));
+	printk("  0x0d: loopback        = 0x%02x  ", snd_cs4231_in(chip, 0x0d));
+	printk("  0x1d: var freq (PnP)  = 0x%02x\n", snd_cs4231_in(chip, 0x1d));
+	printk("  0x0e: ply upr count   = 0x%02x  ", snd_cs4231_in(chip, 0x0e));
+	printk("  0x1e: rec upr count   = 0x%02x\n", snd_cs4231_in(chip, 0x1e));
+	printk("  0x0f: ply lwr count   = 0x%02x  ", snd_cs4231_in(chip, 0x0f));
+	printk("  0x1f: rec lwr count   = 0x%02x\n", snd_cs4231_in(chip, 0x1f));
+}
+
+#endif
+
+/*
+ *  CS4231 detection / MCE routines
+ */
+
+static void snd_cs4231_busy_wait(cs4231_t *chip)
+{
+	int timeout;
+
+	/* huh.. looks like this sequence is proper for CS4231A chip (GUS MAX) */
+	for (timeout = 5; timeout > 0; timeout--)
+		__cs4231_readb(chip, CS4231P(chip, REGSEL));
+	/* end of cleanup sequence */
+	for (timeout = 250;
+	     timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT);
+	     timeout--)
+	     	udelay(100);
+}
+
+static void snd_cs4231_mce_up(cs4231_t *chip)
+{
+	unsigned long flags;
+	int timeout;
+
+	spin_lock_irqsave(&chip->lock, flags);
+	for (timeout = 250; timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT); timeout--)
+		udelay(100);
+#ifdef CONFIG_SND_DEBUG
+	if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)
+		snd_printk("mce_up - auto calibration time out (0)\n");
+#endif
+	chip->mce_bit |= CS4231_MCE;
+	timeout = __cs4231_readb(chip, CS4231P(chip, REGSEL));
+	if (timeout == 0x80)
+		snd_printk("mce_up [0x%lx]: serious init problem - codec still busy\n", chip->port);
+	if (!(timeout & CS4231_MCE))
+		__cs4231_writeb(chip, chip->mce_bit | (timeout & 0x1f), CS4231P(chip, REGSEL));
+	spin_unlock_irqrestore(&chip->lock, flags);
+}
+
+static void snd_cs4231_mce_down(cs4231_t *chip)
+{
+	unsigned long flags;
+	int timeout;
+	signed long time;
+
+	spin_lock_irqsave(&chip->lock, flags);
+	snd_cs4231_busy_wait(chip);
+#if 0
+	printk("(1) timeout = %i\n", timeout);
+#endif
+#ifdef CONFIG_SND_DEBUG
+	if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)
+		snd_printk("mce_down [0x%lx] - auto calibration time out (0)\n", CS4231P(chip, REGSEL));
+#endif
+	chip->mce_bit &= ~CS4231_MCE;
+	timeout = __cs4231_readb(chip, CS4231P(chip, REGSEL));
+	__cs4231_writeb(chip, chip->mce_bit | (timeout & 0x1f), CS4231P(chip, REGSEL));
+	if (timeout == 0x80)
+		snd_printk("mce_down [0x%lx]: serious init problem - codec still busy\n", chip->port);
+	if ((timeout & CS4231_MCE) == 0) {
+		spin_unlock_irqrestore(&chip->lock, flags);
+		return;
+	}
+	snd_cs4231_busy_wait(chip);
+
+	/* calibration process */
+
+	for (timeout = 500; timeout > 0 && (snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) == 0; timeout--)
+		udelay(100);
+	if ((snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) == 0) {
+		snd_printd("cs4231_mce_down - auto calibration time out (1)\n");
+		spin_unlock_irqrestore(&chip->lock, flags);
+		return;
+	}
+#if 0
+	printk("(2) timeout = %i, jiffies = %li\n", timeout, jiffies);
+#endif
+	time = HZ / 4;
+	while (snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) {
+		spin_unlock_irqrestore(&chip->lock, flags);
+		if (time <= 0) {
+			snd_printk("mce_down - auto calibration time out (2)\n");
+			return;
+		}
+		set_current_state(TASK_INTERRUPTIBLE);
+		time = schedule_timeout(time);
+		spin_lock_irqsave(&chip->lock, flags);
+	}
+#if 0
+	printk("(3) jiffies = %li\n", jiffies);
+#endif
+	time = HZ / 10;
+	while (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) {
+		spin_unlock_irqrestore(&chip->lock, flags);
+		if (time <= 0) {
+			snd_printk("mce_down - auto calibration time out (3)\n");
+			return;
+		}
+		set_current_state(TASK_INTERRUPTIBLE);		
+		time = schedule_timeout(time);
+		spin_lock_irqsave(&chip->lock, flags);
+	}
+	spin_unlock_irqrestore(&chip->lock, flags);
+#if 0
+	printk("(4) jiffies = %li\n", jiffies);
+	snd_printk("mce_down - exit = 0x%x\n", __cs4231_readb(chip, CS4231P(chip, REGSEL)));
+#endif
+}
+
+#if 0 /* Unused for now... */
+static unsigned int snd_cs4231_get_count(unsigned char format, unsigned int size)
+{
+	switch (format & 0xe0) {
+	case CS4231_LINEAR_16:
+	case CS4231_LINEAR_16_BIG:
+		size >>= 1;
+		break;
+	case CS4231_ADPCM_16:
+		return size >> 2;
+	}
+	if (format & CS4231_STEREO)
+		size >>= 1;
+	return size;
+}
+#endif
+
+#ifdef EBUS_SUPPORT
+static void snd_cs4231_ebus_advance_dma(struct ebus_dma_info *p, snd_pcm_substream_t *substream, unsigned int *periods_sent)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+
+	while (1) {
+		unsigned int dma_size = snd_pcm_lib_period_bytes(substream);
+		unsigned int offset = dma_size * (*periods_sent);
+
+		if (dma_size >= (1 << 24))
+			BUG();
+
+		if (ebus_dma_request(p, runtime->dma_addr + offset, dma_size))
+			return;
+#if 0
+		printk("ebus_advance: Sent period %u (size[%x] offset[%x])\n",
+		       (*periods_sent), dma_size, offset);
+#endif
+		(*periods_sent) = ((*periods_sent) + 1) % runtime->periods;
+	}
+}
+#endif
+
+static void cs4231_dma_trigger(cs4231_t *chip, unsigned int what, int on)
+{
+#ifdef EBUS_SUPPORT
+	if (chip->flags & CS4231_FLAG_EBUS) {
+		if (what & CS4231_PLAYBACK_ENABLE) {
+			if (on) {
+				ebus_dma_prepare(&chip->eb2p, 0);
+				ebus_dma_enable(&chip->eb2p, 1);
+				snd_cs4231_ebus_advance_dma(&chip->eb2p,
+					chip->playback_substream,
+					&chip->p_periods_sent);
+			} else {
+				ebus_dma_enable(&chip->eb2p, 0);
+			}
+		}
+		if (what & CS4231_RECORD_ENABLE) {
+			if (on) {
+				ebus_dma_prepare(&chip->eb2c, 1);
+				ebus_dma_enable(&chip->eb2c, 1);
+				snd_cs4231_ebus_advance_dma(&chip->eb2c,
+					chip->capture_substream,
+					&chip->c_periods_sent);
+			} else {
+				ebus_dma_enable(&chip->eb2c, 0);
+			}
+		}
+	} else {
+#endif
+#ifdef SBUS_SUPPORT
+#endif
+#ifdef EBUS_SUPPORT
+	}
+#endif
+}
+
+static int snd_cs4231_trigger(snd_pcm_substream_t *substream, int cmd)
+{
+	cs4231_t *chip = snd_pcm_substream_chip(substream);
+	int result = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_STOP:
+	{
+		unsigned int what = 0;
+		snd_pcm_substream_t *s = substream;
+		unsigned long flags;
+
+		do {
+			if (s == chip->playback_substream) {
+				what |= CS4231_PLAYBACK_ENABLE;
+				snd_pcm_trigger_done(s, substream);
+			} else if (s == chip->capture_substream) {
+				what |= CS4231_RECORD_ENABLE;
+				snd_pcm_trigger_done(s, substream);
+			}
+			s = s->link_next;
+		} while (s != substream);
+
+#if 0
+		printk("TRIGGER: what[%x] on(%d)\n",
+		       what, (cmd == SNDRV_PCM_TRIGGER_START));
+#endif
+
+		spin_lock_irqsave(&chip->lock, flags);
+		if (cmd == SNDRV_PCM_TRIGGER_START) {
+			cs4231_dma_trigger(chip, what, 1);
+			chip->image[CS4231_IFACE_CTRL] |= what;
+			if (what & CS4231_PLAYBACK_ENABLE) {
+				snd_cs4231_out(chip, CS4231_PLY_LWR_CNT, 0xff);
+				snd_cs4231_out(chip, CS4231_PLY_UPR_CNT, 0xff);
+			}
+			if (what & CS4231_RECORD_ENABLE) {
+				snd_cs4231_out(chip, CS4231_REC_LWR_CNT, 0xff);
+				snd_cs4231_out(chip, CS4231_REC_UPR_CNT, 0xff);
+			}
+		} else {
+			cs4231_dma_trigger(chip, what, 0);
+			chip->image[CS4231_IFACE_CTRL] &= ~what;
+		}
+		snd_cs4231_out(chip, CS4231_IFACE_CTRL,
+			       chip->image[CS4231_IFACE_CTRL]);
+		spin_unlock_irqrestore(&chip->lock, flags);
+		break;
+	}
+	default:
+		result = -EINVAL;
+		break;
+	}
+#if 0
+	snd_cs4231_debug(chip);
+#endif
+	return result;
+}
+
+/*
+ *  CODEC I/O
+ */
+
+static unsigned char snd_cs4231_get_rate(unsigned int rate)
+{
+	int i;
+
+	for (i = 0; i < 14; i++)
+		if (rate == rates[i])
+			return freq_bits[i];
+	// snd_BUG();
+	return freq_bits[13];
+}
+
+static unsigned char snd_cs4231_get_format(cs4231_t *chip, int format, int channels)
+{
+	unsigned char rformat;
+
+	rformat = CS4231_LINEAR_8;
+	switch (format) {
+	case SNDRV_PCM_FORMAT_MU_LAW:	rformat = CS4231_ULAW_8; break;
+	case SNDRV_PCM_FORMAT_A_LAW:	rformat = CS4231_ALAW_8; break;
+	case SNDRV_PCM_FORMAT_S16_LE:	rformat = CS4231_LINEAR_16; break;
+	case SNDRV_PCM_FORMAT_S16_BE:	rformat = CS4231_LINEAR_16_BIG; break;
+	case SNDRV_PCM_FORMAT_IMA_ADPCM:	rformat = CS4231_ADPCM_16; break;
+	}
+	if (channels > 1)
+		rformat |= CS4231_STEREO;
+#if 0
+	snd_printk("get_format: 0x%x (mode=0x%x)\n", format, mode);
+#endif
+	return rformat;
+}
+
+static void snd_cs4231_calibrate_mute(cs4231_t *chip, int mute)
+{
+	unsigned long flags;
+
+	mute = mute ? 1 : 0;
+	spin_lock_irqsave(&chip->lock, flags);
+	if (chip->calibrate_mute == mute) {
+		spin_unlock_irqrestore(&chip->lock, flags);
+		return;
+	}
+	if (!mute) {
+		snd_cs4231_dout(chip, CS4231_LEFT_INPUT,
+				chip->image[CS4231_LEFT_INPUT]);
+		snd_cs4231_dout(chip, CS4231_RIGHT_INPUT,
+				chip->image[CS4231_RIGHT_INPUT]);
+		snd_cs4231_dout(chip, CS4231_LOOPBACK,
+				chip->image[CS4231_LOOPBACK]);
+	}
+	snd_cs4231_dout(chip, CS4231_AUX1_LEFT_INPUT,
+			mute ? 0x80 : chip->image[CS4231_AUX1_LEFT_INPUT]);
+	snd_cs4231_dout(chip, CS4231_AUX1_RIGHT_INPUT,
+			mute ? 0x80 : chip->image[CS4231_AUX1_RIGHT_INPUT]);
+	snd_cs4231_dout(chip, CS4231_AUX2_LEFT_INPUT,
+			mute ? 0x80 : chip->image[CS4231_AUX2_LEFT_INPUT]);
+	snd_cs4231_dout(chip, CS4231_AUX2_RIGHT_INPUT,
+			mute ? 0x80 : chip->image[CS4231_AUX2_RIGHT_INPUT]);
+	snd_cs4231_dout(chip, CS4231_LEFT_OUTPUT,
+			mute ? 0x80 : chip->image[CS4231_LEFT_OUTPUT]);
+	snd_cs4231_dout(chip, CS4231_RIGHT_OUTPUT,
+			mute ? 0x80 : chip->image[CS4231_RIGHT_OUTPUT]);
+	snd_cs4231_dout(chip, CS4231_LEFT_LINE_IN,
+			mute ? 0x80 : chip->image[CS4231_LEFT_LINE_IN]);
+	snd_cs4231_dout(chip, CS4231_RIGHT_LINE_IN,
+			mute ? 0x80 : chip->image[CS4231_RIGHT_LINE_IN]);
+	snd_cs4231_dout(chip, CS4231_MONO_CTRL,
+			mute ? 0xc0 : chip->image[CS4231_MONO_CTRL]);
+	chip->calibrate_mute = mute;
+	spin_unlock_irqrestore(&chip->lock, flags);
+}
+
+static void snd_cs4231_playback_format(cs4231_t *chip, snd_pcm_hw_params_t *params,
+				       unsigned char pdfr)
+{
+	unsigned long flags;
+
+	down(&chip->mce_mutex);
+	snd_cs4231_calibrate_mute(chip, 1);
+
+	snd_cs4231_mce_up(chip);
+
+	spin_lock_irqsave(&chip->lock, flags);
+	snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT,
+		       (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) ?
+		       (pdfr & 0xf0) | (chip->image[CS4231_REC_FORMAT] & 0x0f) :
+		       pdfr);
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	snd_cs4231_mce_down(chip);
+
+	snd_cs4231_calibrate_mute(chip, 0);
+	up(&chip->mce_mutex);
+}
+
+static void snd_cs4231_capture_format(cs4231_t *chip, snd_pcm_hw_params_t *params,
+                                      unsigned char cdfr)
+{
+	unsigned long flags;
+
+	down(&chip->mce_mutex);
+	snd_cs4231_calibrate_mute(chip, 1);
+
+	snd_cs4231_mce_up(chip);
+
+	spin_lock_irqsave(&chip->lock, flags);
+	if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) {
+		snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT,
+			       ((chip->image[CS4231_PLAYBK_FORMAT]) & 0xf0) |
+			       (cdfr & 0x0f));
+		spin_unlock_irqrestore(&chip->lock, flags);
+		snd_cs4231_mce_down(chip);
+		snd_cs4231_mce_up(chip);
+		spin_lock_irqsave(&chip->lock, flags);
+	}
+	snd_cs4231_out(chip, CS4231_REC_FORMAT, cdfr);
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	snd_cs4231_mce_down(chip);
+
+	snd_cs4231_calibrate_mute(chip, 0);
+	up(&chip->mce_mutex);
+}
+
+/*
+ *  Timer interface
+ */
+
+static unsigned long snd_cs4231_timer_resolution(snd_timer_t *timer)
+{
+	cs4231_t *chip = snd_timer_chip(timer);
+
+	return chip->image[CS4231_PLAYBK_FORMAT] & 1 ? 9969 : 9920;
+}
+
+static int snd_cs4231_timer_start(snd_timer_t *timer)
+{
+	unsigned long flags;
+	unsigned int ticks;
+	cs4231_t *chip = snd_timer_chip(timer);
+
+	spin_lock_irqsave(&chip->lock, flags);
+	ticks = timer->sticks;
+	if ((chip->image[CS4231_ALT_FEATURE_1] & CS4231_TIMER_ENABLE) == 0 ||
+	    (unsigned char)(ticks >> 8) != chip->image[CS4231_TIMER_HIGH] ||
+	    (unsigned char)ticks != chip->image[CS4231_TIMER_LOW]) {
+		snd_cs4231_out(chip, CS4231_TIMER_HIGH,
+			       chip->image[CS4231_TIMER_HIGH] =
+			       (unsigned char) (ticks >> 8));
+		snd_cs4231_out(chip, CS4231_TIMER_LOW,
+			       chip->image[CS4231_TIMER_LOW] =
+			       (unsigned char) ticks);
+		snd_cs4231_out(chip, CS4231_ALT_FEATURE_1,
+			       chip->image[CS4231_ALT_FEATURE_1] | CS4231_TIMER_ENABLE);
+	}
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	return 0;
+}
+
+static int snd_cs4231_timer_stop(snd_timer_t *timer)
+{
+	unsigned long flags;
+	cs4231_t *chip = snd_timer_chip(timer);
+
+	spin_lock_irqsave(&chip->lock, flags);
+	snd_cs4231_out(chip, CS4231_ALT_FEATURE_1,
+		       chip->image[CS4231_ALT_FEATURE_1] &= ~CS4231_TIMER_ENABLE);
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	return 0;
+}
+
+static void snd_cs4231_init(cs4231_t *chip)
+{
+	unsigned long flags;
+
+	snd_cs4231_mce_down(chip);
+
+#ifdef SNDRV_DEBUG_MCE
+	snd_printk("init: (1)\n");
+#endif
+	snd_cs4231_mce_up(chip);
+	spin_lock_irqsave(&chip->lock, flags);
+	chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO |
+					    CS4231_RECORD_ENABLE | CS4231_RECORD_PIO |
+					    CS4231_CALIB_MODE);
+	chip->image[CS4231_IFACE_CTRL] |= CS4231_AUTOCALIB;
+	snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
+	spin_unlock_irqrestore(&chip->lock, flags);
+	snd_cs4231_mce_down(chip);
+
+#ifdef SNDRV_DEBUG_MCE
+	snd_printk("init: (2)\n");
+#endif
+
+	snd_cs4231_mce_up(chip);
+	spin_lock_irqsave(&chip->lock, flags);
+	snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1]);
+	spin_unlock_irqrestore(&chip->lock, flags);
+	snd_cs4231_mce_down(chip);
+
+#ifdef SNDRV_DEBUG_MCE
+	snd_printk("init: (3) - afei = 0x%x\n", chip->image[CS4231_ALT_FEATURE_1]);
+#endif
+
+	spin_lock_irqsave(&chip->lock, flags);
+	snd_cs4231_out(chip, CS4231_ALT_FEATURE_2, chip->image[CS4231_ALT_FEATURE_2]);
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	snd_cs4231_mce_up(chip);
+	spin_lock_irqsave(&chip->lock, flags);
+	snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, chip->image[CS4231_PLAYBK_FORMAT]);
+	spin_unlock_irqrestore(&chip->lock, flags);
+	snd_cs4231_mce_down(chip);
+
+#ifdef SNDRV_DEBUG_MCE
+	snd_printk("init: (4)\n");
+#endif
+
+	snd_cs4231_mce_up(chip);
+	spin_lock_irqsave(&chip->lock, flags);
+	snd_cs4231_out(chip, CS4231_REC_FORMAT, chip->image[CS4231_REC_FORMAT]);
+	spin_unlock_irqrestore(&chip->lock, flags);
+	snd_cs4231_mce_down(chip);
+
+#ifdef SNDRV_DEBUG_MCE
+	snd_printk("init: (5)\n");
+#endif
+}
+
+static int snd_cs4231_open(cs4231_t *chip, unsigned int mode)
+{
+	unsigned long flags;
+
+	down(&chip->open_mutex);
+	if ((chip->mode & mode)) {
+		up(&chip->open_mutex);
+		return -EAGAIN;
+	}
+	if (chip->mode & CS4231_MODE_OPEN) {
+		chip->mode |= mode;
+		up(&chip->open_mutex);
+		return 0;
+	}
+	/* ok. now enable and ack CODEC IRQ */
+	spin_lock_irqsave(&chip->lock, flags);
+	snd_cs4231_out(chip, CS4231_IRQ_STATUS, CS4231_PLAYBACK_IRQ |
+		       CS4231_RECORD_IRQ |
+		       CS4231_TIMER_IRQ);
+	snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
+	__cs4231_writeb(chip, 0, CS4231P(chip, STATUS));	/* clear IRQ */
+	__cs4231_writeb(chip, 0, CS4231P(chip, STATUS));	/* clear IRQ */
+
+	snd_cs4231_out(chip, CS4231_IRQ_STATUS, CS4231_PLAYBACK_IRQ |
+		       CS4231_RECORD_IRQ |
+		       CS4231_TIMER_IRQ);
+	snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	chip->mode = mode;
+	up(&chip->open_mutex);
+	return 0;
+}
+
+static void snd_cs4231_close(cs4231_t *chip, unsigned int mode)
+{
+	unsigned long flags;
+
+	down(&chip->open_mutex);
+	chip->mode &= ~mode;
+	if (chip->mode & CS4231_MODE_OPEN) {
+		up(&chip->open_mutex);
+		return;
+	}
+	snd_cs4231_calibrate_mute(chip, 1);
+
+	/* disable IRQ */
+	spin_lock_irqsave(&chip->lock, flags);
+	snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
+	__cs4231_writeb(chip, 0, CS4231P(chip, STATUS));	/* clear IRQ */
+	__cs4231_writeb(chip, 0, CS4231P(chip, STATUS));	/* clear IRQ */
+
+	/* now disable record & playback */
+
+	if (chip->image[CS4231_IFACE_CTRL] &
+	    (CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO |
+	     CS4231_RECORD_ENABLE | CS4231_RECORD_PIO)) {
+		spin_unlock_irqrestore(&chip->lock, flags);
+		snd_cs4231_mce_up(chip);
+		spin_lock_irqsave(&chip->lock, flags);
+		chip->image[CS4231_IFACE_CTRL] &=
+			~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO |
+			  CS4231_RECORD_ENABLE | CS4231_RECORD_PIO);
+		snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
+		spin_unlock_irqrestore(&chip->lock, flags);
+		snd_cs4231_mce_down(chip);
+		spin_lock_irqsave(&chip->lock, flags);
+	}
+
+	/* clear IRQ again */
+	snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
+	__cs4231_writeb(chip, 0, CS4231P(chip, STATUS));	/* clear IRQ */
+	__cs4231_writeb(chip, 0, CS4231P(chip, STATUS));	/* clear IRQ */
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	snd_cs4231_calibrate_mute(chip, 0);
+
+	chip->mode = 0;
+	up(&chip->open_mutex);
+}
+
+/*
+ *  timer open/close
+ */
+
+static int snd_cs4231_timer_open(snd_timer_t *timer)
+{
+	cs4231_t *chip = snd_timer_chip(timer);
+	snd_cs4231_open(chip, CS4231_MODE_TIMER);
+	return 0;
+}
+
+static int snd_cs4231_timer_close(snd_timer_t * timer)
+{
+	cs4231_t *chip = snd_timer_chip(timer);
+	snd_cs4231_close(chip, CS4231_MODE_TIMER);
+	return 0;
+}
+
+static struct _snd_timer_hardware snd_cs4231_timer_table =
+{
+	.flags		=	SNDRV_TIMER_HW_AUTO,
+	.resolution	=	9945,
+	.ticks		=	65535,
+	.open		=	snd_cs4231_timer_open,
+	.close		=	snd_cs4231_timer_close,
+	.c_resolution	=	snd_cs4231_timer_resolution,
+	.start		=	snd_cs4231_timer_start,
+	.stop		=	snd_cs4231_timer_stop,
+};
+
+/*
+ *  ok.. exported functions..
+ */
+
+static int snd_cs4231_playback_hw_params(snd_pcm_substream_t *substream,
+					 snd_pcm_hw_params_t *hw_params)
+{
+	cs4231_t *chip = snd_pcm_substream_chip(substream);
+	unsigned char new_pdfr;
+	int err;
+
+	if ((err = snd_pcm_lib_malloc_pages(substream,
+					    params_buffer_bytes(hw_params))) < 0)
+		return err;
+	new_pdfr = snd_cs4231_get_format(chip, params_format(hw_params),
+					 params_channels(hw_params)) |
+		snd_cs4231_get_rate(params_rate(hw_params));
+	snd_cs4231_playback_format(chip, hw_params, new_pdfr);
+
+	return 0;
+}
+
+static int snd_cs4231_playback_hw_free(snd_pcm_substream_t *substream)
+{
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static int snd_cs4231_playback_prepare(snd_pcm_substream_t *substream)
+{
+	cs4231_t *chip = snd_pcm_substream_chip(substream);
+	unsigned long flags;
+
+	spin_lock_irqsave(&chip->lock, flags);
+	chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE |
+					    CS4231_PLAYBACK_PIO);
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	return 0;
+}
+
+static int snd_cs4231_capture_hw_params(snd_pcm_substream_t *substream,
+					snd_pcm_hw_params_t *hw_params)
+{
+	cs4231_t *chip = snd_pcm_substream_chip(substream);
+	unsigned char new_cdfr;
+	int err;
+
+	if ((err = snd_pcm_lib_malloc_pages(substream,
+					    params_buffer_bytes(hw_params))) < 0)
+		return err;
+	new_cdfr = snd_cs4231_get_format(chip, params_format(hw_params),
+					 params_channels(hw_params)) |
+		snd_cs4231_get_rate(params_rate(hw_params));
+	snd_cs4231_capture_format(chip, hw_params, new_cdfr);
+
+	return 0;
+}
+
+static int snd_cs4231_capture_hw_free(snd_pcm_substream_t *substream)
+{
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static int snd_cs4231_capture_prepare(snd_pcm_substream_t *substream)
+{
+	cs4231_t *chip = snd_pcm_substream_chip(substream);
+	unsigned long flags;
+
+	spin_lock_irqsave(&chip->lock, flags);
+	chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE |
+					    CS4231_RECORD_PIO);
+
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	return 0;
+}
+
+static void snd_cs4231_overrange(cs4231_t *chip)
+{
+	unsigned long flags;
+	unsigned char res;
+
+	spin_lock_irqsave(&chip->lock, flags);
+	res = snd_cs4231_in(chip, CS4231_TEST_INIT);
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	if (res & (0x08 | 0x02))	/* detect overrange only above 0dB; may be user selectable? */
+		chip->capture_substream->runtime->overrange++;
+}
+
+static void snd_cs4231_generic_interrupt(cs4231_t *chip)
+{
+	unsigned long flags;
+	unsigned char status;
+
+	status = snd_cs4231_in(chip, CS4231_IRQ_STATUS);
+	if (!status)
+		return;
+
+	if (status & CS4231_TIMER_IRQ) {
+		if (chip->timer)
+			snd_timer_interrupt(chip->timer, chip->timer->sticks);
+	}		
+	if (status & CS4231_PLAYBACK_IRQ)
+		snd_pcm_period_elapsed(chip->playback_substream);
+	if (status & CS4231_RECORD_IRQ) {
+		snd_cs4231_overrange(chip);
+		snd_pcm_period_elapsed(chip->capture_substream);
+	}
+
+	/* ACK the CS4231 interrupt. */
+	spin_lock_irqsave(&chip->lock, flags);
+	snd_cs4231_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0);
+	spin_unlock_irqrestore(&chip->lock, flags);
+}
+
+#ifdef SBUS_SUPPORT
+static void snd_cs4231_sbus_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	cs4231_t *chip = snd_magic_cast(cs4231_t, dev_id, return);
+	u32 csr;
+
+	csr = sbus_readl(chip->port + APCCSR);
+	if (!(csr & (APC_INT_PENDING |
+		     APC_PLAY_INT |
+		     APC_CAPT_INT |
+		     APC_GENL_INT |
+		     APC_XINT_PEMP |
+		     APC_XINT_CEMP)))
+		return;
+
+	/* ACK the APC interrupt. */
+	sbus_writel(csr, chip->port + APCCSR);
+
+	snd_cs4231_generic_interrupt(chip);
+}
+#endif
+
+#ifdef EBUS_SUPPORT
+static void snd_cs4231_ebus_play_callback(struct ebus_dma_info *p, int event, void *cookie)
+{
+	cs4231_t *chip = snd_magic_cast(cs4231_t, cookie, return);
+
+	if (chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE) {
+		snd_pcm_period_elapsed(chip->playback_substream);
+		snd_cs4231_ebus_advance_dma(p, chip->playback_substream,
+					    &chip->p_periods_sent);
+	}
+}
+
+static void snd_cs4231_ebus_capture_callback(struct ebus_dma_info *p, int event, void *cookie)
+{
+	cs4231_t *chip = snd_magic_cast(cs4231_t, cookie, return);
+
+	if (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) {
+		snd_pcm_period_elapsed(chip->capture_substream);
+		snd_cs4231_ebus_advance_dma(p, chip->capture_substream,
+					    &chip->c_periods_sent);
+	}
+}
+#endif
+
+static snd_pcm_uframes_t snd_cs4231_playback_pointer(snd_pcm_substream_t *substream)
+{
+	cs4231_t *chip = snd_pcm_substream_chip(substream);
+	size_t ptr, residue, period_bytes;
+
+	if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE))
+		return 0;
+	period_bytes = snd_pcm_lib_period_bytes(substream);
+	ptr = period_bytes * chip->p_periods_sent;
+#ifdef EBUS_SUPPORT
+	if (chip->flags & CS4231_FLAG_EBUS) {
+		residue = ebus_dma_residue(&chip->eb2p);
+	} else {
+#endif
+#ifdef SBUS_SUPPORT
+		residue = sbus_readl(chip->port + APCPC);
+#endif
+#ifdef EBUS_SUPPORT
+	}
+#endif
+	ptr += (period_bytes - residue);
+	return bytes_to_frames(substream->runtime, ptr);
+}
+
+static snd_pcm_uframes_t snd_cs4231_capture_pointer(snd_pcm_substream_t * substream)
+{
+	cs4231_t *chip = snd_pcm_substream_chip(substream);
+	size_t ptr, residue, period_bytes;
+	
+	if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE))
+		return 0;
+	period_bytes = snd_pcm_lib_period_bytes(substream);
+	ptr = period_bytes * chip->c_periods_sent;
+#ifdef EBUS_SUPPORT
+	if (chip->flags & CS4231_FLAG_EBUS) {
+		residue = ebus_dma_residue(&chip->eb2c);
+	} else {
+#endif
+#ifdef SBUS_SUPPORT
+		residue = sbus_readl(chip->port + APCCC);
+#endif
+#ifdef EBUS_SUPPORT
+	}
+#endif
+	ptr += (period_bytes - residue);
+	return bytes_to_frames(substream->runtime, ptr);
+}
+
+/*
+
+ */
+
+static int snd_cs4231_probe(cs4231_t *chip)
+{
+	unsigned long flags;
+	int i, id, vers;
+	unsigned char *ptr;
+
+#if 0
+	snd_cs4231_debug(chip);
+#endif
+	id = vers = 0;
+	for (i = 0; i < 50; i++) {
+		mb();
+		if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)
+			udelay(2000);
+		else {
+			spin_lock_irqsave(&chip->lock, flags);
+			snd_cs4231_out(chip, CS4231_MISC_INFO, CS4231_MODE2);
+			id = snd_cs4231_in(chip, CS4231_MISC_INFO) & 0x0f;
+			vers = snd_cs4231_in(chip, CS4231_VERSION);
+			spin_unlock_irqrestore(&chip->lock, flags);
+			if (id == 0x0a)
+				break;	/* this is valid value */
+		}
+	}
+	snd_printdd("cs4231: port = 0x%lx, id = 0x%x\n", chip->port, id);
+	if (id != 0x0a)
+		return -ENODEV;	/* no valid device found */
+
+	spin_lock_irqsave(&chip->lock, flags);
+
+
+	/* Reset DMA engine.  */
+#ifdef EBUS_SUPPORT
+	if (chip->flags & CS4231_FLAG_EBUS) {
+		/* Done by ebus_dma_register */
+	} else {
+#endif
+#ifdef SBUS_SUPPORT
+                sbus_writel(APC_CHIP_RESET, chip->port + APCCSR);
+                sbus_writel(0x00, chip->port + APCCSR);
+                sbus_writel(sbus_readl(chip->port + APCCSR) | APC_CDC_RESET,
+			    chip->port + APCCSR);
+  
+                udelay(20);
+  
+                sbus_writel(sbus_readl(chip->port + APCCSR) & ~APC_CDC_RESET,
+			    chip->port + APCCSR);
+                sbus_writel(sbus_readl(chip->port + APCCSR) | (APC_XINT_ENA |
+							       APC_XINT_PENA |
+							       APC_XINT_CENA),
+			    chip->port + APCCSR);
+#endif
+#ifdef EBUS_SUPPORT
+	}
+#endif
+
+	__cs4231_readb(chip, CS4231P(chip, STATUS));	/* clear any pendings IRQ */
+	__cs4231_writeb(chip, 0, CS4231P(chip, STATUS));
+	mb();
+
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	chip->image[CS4231_MISC_INFO] = CS4231_MODE2;
+	chip->image[CS4231_IFACE_CTRL] =
+		chip->image[CS4231_IFACE_CTRL] & ~CS4231_SINGLE_DMA;
+	chip->image[CS4231_ALT_FEATURE_1] = 0x80;
+	chip->image[CS4231_ALT_FEATURE_2] = 0x01;
+	if (vers & 0x20)
+		chip->image[CS4231_ALT_FEATURE_2] |= 0x02;
+
+	ptr = (unsigned char *) &chip->image;
+
+	snd_cs4231_mce_down(chip);
+
+	spin_lock_irqsave(&chip->lock, flags);
+
+	for (i = 0; i < 32; i++)	/* ok.. fill all CS4231 registers */
+		snd_cs4231_out(chip, i, *ptr++);
+
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	snd_cs4231_mce_up(chip);
+
+	snd_cs4231_mce_down(chip);
+
+	mdelay(2);
+
+	return 0;		/* all things are ok.. */
+}
+
+static snd_pcm_hardware_t snd_cs4231_playback =
+{
+	info:			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+				 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START),
+	formats:		(SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW |
+				 SNDRV_PCM_FMTBIT_IMA_ADPCM |
+				 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |
+				 SNDRV_PCM_FMTBIT_S16_BE),
+	rates:			SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
+	rate_min:		5510,
+	rate_max:		48000,
+	channels_min:		1,
+	channels_max:		2,
+	buffer_bytes_max:	(32*1024),
+	period_bytes_min:	4096,
+	period_bytes_max:	(32*1024),
+	periods_min:		1,
+	periods_max:		1024,
+	fifo_size:		0,
+};
+
+static snd_pcm_hardware_t snd_cs4231_capture =
+{
+	info:			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
+				 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START),
+	formats:		(SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW |
+				 SNDRV_PCM_FMTBIT_IMA_ADPCM |
+				 SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |
+				 SNDRV_PCM_FMTBIT_S16_BE),
+	rates:			SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000,
+	rate_min:		5510,
+	rate_max:		48000,
+	channels_min:		1,
+	channels_max:		2,
+	buffer_bytes_max:	(32*1024),
+	period_bytes_min:	4096,
+	period_bytes_max:	(32*1024),
+	periods_min:		1,
+	periods_max:		1024,
+	fifo_size:		0,
+};
+
+static int snd_cs4231_playback_open(snd_pcm_substream_t *substream)
+{
+	cs4231_t *chip = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	int err;
+
+	runtime->hw = snd_cs4231_playback;
+
+	if ((err = snd_cs4231_open(chip, CS4231_MODE_PLAY)) < 0) {
+		snd_free_pages(runtime->dma_area, runtime->dma_bytes);
+		return err;
+	}
+	chip->playback_substream = substream;
+	chip->p_periods_sent = 0;
+	snd_pcm_set_sync(substream);
+	snd_cs4231_xrate(runtime);
+
+	return 0;
+}
+
+static int snd_cs4231_capture_open(snd_pcm_substream_t *substream)
+{
+	cs4231_t *chip = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	int err;
+
+	runtime->hw = snd_cs4231_capture;
+
+	if ((err = snd_cs4231_open(chip, CS4231_MODE_RECORD)) < 0) {
+		snd_free_pages(runtime->dma_area, runtime->dma_bytes);
+		return err;
+	}
+	chip->capture_substream = substream;
+	chip->c_periods_sent = 0;
+	snd_pcm_set_sync(substream);
+	snd_cs4231_xrate(runtime);
+
+	return 0;
+}
+
+static int snd_cs4231_playback_close(snd_pcm_substream_t *substream)
+{
+	cs4231_t *chip = snd_pcm_substream_chip(substream);
+
+	chip->playback_substream = NULL;
+	snd_cs4231_close(chip, CS4231_MODE_PLAY);
+
+	return 0;
+}
+
+static int snd_cs4231_capture_close(snd_pcm_substream_t *substream)
+{
+	cs4231_t *chip = snd_pcm_substream_chip(substream);
+
+	chip->capture_substream = NULL;
+	snd_cs4231_close(chip, CS4231_MODE_RECORD);
+
+	return 0;
+}
+
+/* XXX We can do some power-management, in particular on EBUS using
+ * XXX the audio AUXIO register...
+ */
+
+static snd_pcm_ops_t snd_cs4231_playback_ops = {
+	.open		=	snd_cs4231_playback_open,
+	.close		=	snd_cs4231_playback_close,
+	.ioctl		=	snd_pcm_lib_ioctl,
+	.hw_params	=	snd_cs4231_playback_hw_params,
+	.hw_free	=	snd_cs4231_playback_hw_free,
+	.prepare	=	snd_cs4231_playback_prepare,
+	.trigger	=	snd_cs4231_trigger,
+	.pointer	=	snd_cs4231_playback_pointer,
+};
+
+static snd_pcm_ops_t snd_cs4231_capture_ops = {
+	.open		=	snd_cs4231_capture_open,
+	.close		=	snd_cs4231_capture_close,
+	.ioctl		=	snd_pcm_lib_ioctl,
+	.hw_params	=	snd_cs4231_capture_hw_params,
+	.hw_free	=	snd_cs4231_capture_hw_free,
+	.prepare	=	snd_cs4231_capture_prepare,
+	.trigger	=	snd_cs4231_trigger,
+	.pointer	=	snd_cs4231_capture_pointer,
+};
+
+static void snd_cs4231_pcm_free(snd_pcm_t *pcm)
+{
+	cs4231_t *chip = snd_magic_cast(cs4231_t, pcm->private_data, return);
+	chip->pcm = NULL;
+	snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+int snd_cs4231_pcm(cs4231_t *chip)
+{
+	snd_pcm_t *pcm;
+	int err;
+
+	if ((err = snd_pcm_new(chip->card, "CS4231", 0, 1, 1, &pcm)) < 0)
+		return err;
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cs4231_playback_ops);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cs4231_capture_ops);
+	
+	/* global setup */
+	pcm->private_data = chip;
+	pcm->private_free = snd_cs4231_pcm_free;
+	pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
+	strcpy(pcm->name, "CS4231");
+
+#ifdef EBUS_SUPPORT
+	if (chip->flags & CS4231_FLAG_EBUS) {
+		snd_pcm_lib_preallocate_pci_pages_for_all(chip->dev_u.pdev, pcm,
+							  64*1024, 128*1024);
+	} else {
+#endif
+#ifdef SBUS_SUPPORT
+		snd_pcm_lib_preallocate_sbus_pages_for_all(chip->dev_u.sdev, pcm,
+							   64*1024, 128*1024);
+#endif
+#ifdef EBUS_SUPPORT
+	}
+#endif
+
+	chip->pcm = pcm;
+
+	return 0;
+}
+
+static void snd_cs4231_timer_free(snd_timer_t *timer)
+{
+	cs4231_t *chip = snd_magic_cast(cs4231_t, timer->private_data, return);
+	chip->timer = NULL;
+}
+
+int snd_cs4231_timer(cs4231_t *chip)
+{
+	snd_timer_t *timer;
+	snd_timer_id_t tid;
+	int err;
+
+	/* Timer initialization */
+	tid.dev_class = SNDRV_TIMER_CLASS_CARD;
+	tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
+	tid.card = chip->card->number;
+	tid.device = 0;
+	tid.subdevice = 0;
+	if ((err = snd_timer_new(chip->card, "CS4231", &tid, &timer)) < 0)
+		return err;
+	strcpy(timer->name, "CS4231");
+	timer->private_data = chip;
+	timer->private_free = snd_cs4231_timer_free;
+	timer->hw = snd_cs4231_timer_table;
+	chip->timer = timer;
+
+	return 0;
+}
+	
+/*
+ *  MIXER part
+ */
+
+static int snd_cs4231_info_mux(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	static char *texts[4] = {
+		"Line", "CD", "Mic", "Mix"
+	};
+	cs4231_t *chip = snd_kcontrol_chip(kcontrol);
+
+	snd_assert(chip->card != NULL, return -EINVAL);
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 2;
+	uinfo->value.enumerated.items = 4;
+	if (uinfo->value.enumerated.item > 3)
+		uinfo->value.enumerated.item = 3;
+	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+
+	return 0;
+}
+
+static int snd_cs4231_get_mux(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	cs4231_t *chip = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	
+	spin_lock_irqsave(&chip->lock, flags);
+	ucontrol->value.enumerated.item[0] =
+		(chip->image[CS4231_LEFT_INPUT] & CS4231_MIXS_ALL) >> 6;
+	ucontrol->value.enumerated.item[1] =
+		(chip->image[CS4231_RIGHT_INPUT] & CS4231_MIXS_ALL) >> 6;
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	return 0;
+}
+
+static int snd_cs4231_put_mux(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	cs4231_t *chip = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	unsigned short left, right;
+	int change;
+	
+	if (ucontrol->value.enumerated.item[0] > 3 ||
+	    ucontrol->value.enumerated.item[1] > 3)
+		return -EINVAL;
+	left = ucontrol->value.enumerated.item[0] << 6;
+	right = ucontrol->value.enumerated.item[1] << 6;
+
+	spin_lock_irqsave(&chip->lock, flags);
+
+	left = (chip->image[CS4231_LEFT_INPUT] & ~CS4231_MIXS_ALL) | left;
+	right = (chip->image[CS4231_RIGHT_INPUT] & ~CS4231_MIXS_ALL) | right;
+	change = left != chip->image[CS4231_LEFT_INPUT] ||
+	         right != chip->image[CS4231_RIGHT_INPUT];
+	snd_cs4231_out(chip, CS4231_LEFT_INPUT, left);
+	snd_cs4231_out(chip, CS4231_RIGHT_INPUT, right);
+
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	return change;
+}
+
+int snd_cs4231_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	int mask = (kcontrol->private_value >> 16) & 0xff;
+
+	uinfo->type = (mask == 1) ?
+		SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = mask;
+
+	return 0;
+}
+
+int snd_cs4231_get_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	cs4231_t *chip = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	int reg = kcontrol->private_value & 0xff;
+	int shift = (kcontrol->private_value >> 8) & 0xff;
+	int mask = (kcontrol->private_value >> 16) & 0xff;
+	int invert = (kcontrol->private_value >> 24) & 0xff;
+	
+	spin_lock_irqsave(&chip->lock, flags);
+
+	ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask;
+
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	if (invert)
+		ucontrol->value.integer.value[0] =
+			(mask - ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+int snd_cs4231_put_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	cs4231_t *chip = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	int reg = kcontrol->private_value & 0xff;
+	int shift = (kcontrol->private_value >> 8) & 0xff;
+	int mask = (kcontrol->private_value >> 16) & 0xff;
+	int invert = (kcontrol->private_value >> 24) & 0xff;
+	int change;
+	unsigned short val;
+	
+	val = (ucontrol->value.integer.value[0] & mask);
+	if (invert)
+		val = mask - val;
+	val <<= shift;
+
+	spin_lock_irqsave(&chip->lock, flags);
+
+	val = (chip->image[reg] & ~(mask << shift)) | val;
+	change = val != chip->image[reg];
+	snd_cs4231_out(chip, reg, val);
+
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	return change;
+}
+
+int snd_cs4231_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	int mask = (kcontrol->private_value >> 24) & 0xff;
+
+	uinfo->type = mask == 1 ?
+		SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = mask;
+
+	return 0;
+}
+
+int snd_cs4231_get_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	cs4231_t *chip = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	int left_reg = kcontrol->private_value & 0xff;
+	int right_reg = (kcontrol->private_value >> 8) & 0xff;
+	int shift_left = (kcontrol->private_value >> 16) & 0x07;
+	int shift_right = (kcontrol->private_value >> 19) & 0x07;
+	int mask = (kcontrol->private_value >> 24) & 0xff;
+	int invert = (kcontrol->private_value >> 22) & 1;
+	
+	spin_lock_irqsave(&chip->lock, flags);
+
+	ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask;
+	ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask;
+
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	if (invert) {
+		ucontrol->value.integer.value[0] =
+			(mask - ucontrol->value.integer.value[0]);
+		ucontrol->value.integer.value[1] =
+			(mask - ucontrol->value.integer.value[1]);
+	}
+
+	return 0;
+}
+
+int snd_cs4231_put_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	cs4231_t *chip = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	int left_reg = kcontrol->private_value & 0xff;
+	int right_reg = (kcontrol->private_value >> 8) & 0xff;
+	int shift_left = (kcontrol->private_value >> 16) & 0x07;
+	int shift_right = (kcontrol->private_value >> 19) & 0x07;
+	int mask = (kcontrol->private_value >> 24) & 0xff;
+	int invert = (kcontrol->private_value >> 22) & 1;
+	int change;
+	unsigned short val1, val2;
+	
+	val1 = ucontrol->value.integer.value[0] & mask;
+	val2 = ucontrol->value.integer.value[1] & mask;
+	if (invert) {
+		val1 = mask - val1;
+		val2 = mask - val2;
+	}
+	val1 <<= shift_left;
+	val2 <<= shift_right;
+
+	spin_lock_irqsave(&chip->lock, flags);
+
+	val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
+	val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2;
+	change = val1 != chip->image[left_reg] || val2 != chip->image[right_reg];
+	snd_cs4231_out(chip, left_reg, val1);
+	snd_cs4231_out(chip, right_reg, val2);
+
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	return change;
+}
+
+#define CS4231_CONTROLS (sizeof(snd_cs4231_controls)/sizeof(snd_kcontrol_new_t))
+
+#define CS4231_SINGLE(xname, xindex, reg, shift, mask, invert) \
+{ iface: SNDRV_CTL_ELEM_IFACE_MIXER, name: xname, index: xindex, \
+  info: snd_cs4231_info_single, \
+  get: snd_cs4231_get_single, put: snd_cs4231_put_single, \
+  private_value: reg | (shift << 8) | (mask << 16) | (invert << 24) }
+
+#define CS4231_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
+{ iface: SNDRV_CTL_ELEM_IFACE_MIXER, name: xname, index: xindex, \
+  info: snd_cs4231_info_double, \
+  get: snd_cs4231_get_double, put: snd_cs4231_put_double, \
+  private_value: left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
+
+static snd_kcontrol_new_t snd_cs4231_controls[] = {
+CS4231_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
+CS4231_DOUBLE("PCM Playback Volume", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),
+CS4231_DOUBLE("Line Playback Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),
+CS4231_DOUBLE("Line Playback Volume", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),
+CS4231_DOUBLE("Aux Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
+CS4231_DOUBLE("Aux Playback Volume", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),
+CS4231_DOUBLE("Aux Playback Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
+CS4231_DOUBLE("Aux Playback Volume", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),
+CS4231_SINGLE("Mono Playback Switch", 0, CS4231_MONO_CTRL, 7, 1, 1),
+CS4231_SINGLE("Mono Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),
+CS4231_SINGLE("Mono Output Playback Switch", 0, CS4231_MONO_CTRL, 6, 1, 1),
+CS4231_SINGLE("Mono Output Playback Bypass", 0, CS4231_MONO_CTRL, 5, 1, 0),
+CS4231_DOUBLE("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0),
+{
+	iface: SNDRV_CTL_ELEM_IFACE_MIXER,
+	name: "Capture Source",
+	info: snd_cs4231_info_mux,
+	get: snd_cs4231_get_mux,
+	put: snd_cs4231_put_mux,
+},
+CS4231_DOUBLE("Mic Boost", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0),
+CS4231_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
+CS4231_SINGLE("Loopback Capture Volume", 0, CS4231_LOOPBACK, 2, 63, 1),
+/* SPARC specific uses of XCTL{0,1} general purpose outputs.  */
+CS4231_SINGLE("Line Out Switch", 0, CS4231_PIN_CTRL, 6, 1, 1),
+CS4231_SINGLE("Headphone Out Switch", 0, CS4231_PIN_CTRL, 7, 1, 1)
+};
+                                        
+int snd_cs4231_mixer(cs4231_t *chip)
+{
+	snd_card_t *card;
+	int err, idx;
+
+	snd_assert(chip != NULL && chip->pcm != NULL, return -EINVAL);
+
+	card = chip->card;
+
+	strcpy(card->mixername, chip->pcm->name);
+
+	for (idx = 0; idx < CS4231_CONTROLS; idx++) {
+		if ((err = snd_ctl_add(card,
+				       snd_ctl_new1(&snd_cs4231_controls[idx],
+						    chip))) < 0)
+			return err;
+	}
+	return 0;
+}
+
+static int dev;
+
+static int cs4231_attach_begin(snd_card_t **rcard)
+{
+	snd_card_t *card;
+
+	*rcard = NULL;
+
+	if (dev >= SNDRV_CARDS)
+		return -ENODEV;
+
+	if (!snd_enable[dev]) {
+		dev++;
+		return -ENOENT;
+	}
+
+	card = snd_card_new(snd_index[dev], snd_id[dev], THIS_MODULE, 0);
+	if (card == NULL)
+		return -ENOMEM;
+
+	strcpy(card->driver, "CS4231");
+	strcpy(card->shortname, "Sun CS4231");
+
+	*rcard = card;
+	return 0;
+}
+
+static int cs4231_attach_finish(snd_card_t *card, cs4231_t *chip)
+{
+	int err;
+
+	if ((err = snd_cs4231_pcm(chip)) < 0)
+		goto out_err;
+
+	if ((err = snd_cs4231_mixer(chip)) < 0)
+		goto out_err;
+
+	if ((err = snd_cs4231_timer(chip)) < 0)
+		goto out_err;
+
+	if ((err = snd_card_register(card)) < 0)
+		goto out_err;
+
+	chip->next = cs4231_list;
+	cs4231_list = chip;
+
+	dev++;
+	return 0;
+
+out_err:
+	snd_card_free(card);
+	return err;
+}
+
+#ifdef SBUS_SUPPORT
+static int snd_cs4231_sbus_free(cs4231_t *chip)
+{
+	if (chip->irq[0])
+		free_irq(chip->irq[0], chip);
+
+	if (chip->port)
+		sbus_iounmap(chip->port, chip->regs_size);
+
+	if (chip->timer)
+		snd_device_free(chip->card, chip->timer);
+
+	snd_magic_kfree(chip);
+
+	return 0;
+}
+
+static int snd_cs4231_sbus_dev_free(snd_device_t *device)
+{
+	cs4231_t *cp = snd_magic_cast(cs4231_t, device->device_data, return -ENXIO);
+
+	return snd_cs4231_sbus_free(cp);
+}
+
+static snd_device_ops_t snd_cs4231_sbus_dev_ops = {
+	.dev_free	=	snd_cs4231_sbus_dev_free,
+};
+
+static int __init snd_cs4231_sbus_create(snd_card_t *card,
+					 struct sbus_dev *sdev,
+					 int dev,
+					 cs4231_t **rchip)
+{
+	cs4231_t *chip;
+	int err;
+
+	*rchip = NULL;
+	chip = snd_magic_kcalloc(cs4231_t, 0, GFP_KERNEL);
+	if (chip == NULL)
+		return -ENOMEM;
+
+	spin_lock_init(&chip->lock);
+	init_MUTEX(&chip->mce_mutex);
+	init_MUTEX(&chip->open_mutex);
+	chip->card = card;
+	chip->dev_u.sdev = sdev;
+	chip->regs_size = sdev->reg_addrs[0].reg_size;
+	memcpy(&chip->image, &snd_cs4231_original_image,
+	       sizeof(snd_cs4231_original_image));
+
+	chip->port = sbus_ioremap(&sdev->resource[0], 0,
+				  chip->regs_size, "cs4231");
+	if (!chip->port) {
+		snd_printk("cs4231-%d: Unable to map chip registers.\n", dev);
+		return -EIO;
+	}
+
+	if (request_irq(sdev->irqs[0], snd_cs4231_sbus_interrupt,
+			SA_SHIRQ, "cs4231", chip)) {
+		snd_cs4231_sbus_free(chip);
+		snd_printk("cs4231-%d: Unable to grab SBUS IRQ %s\n",
+			   dev,
+			   __irq_itoa(sdev->irqs[0]));
+		return -EBUSY;
+	}
+	chip->irq[0] = sdev->irqs[0];
+
+	if (snd_cs4231_probe(chip) < 0) {
+		snd_cs4231_sbus_free(chip);
+		return -ENODEV;
+	}
+	snd_cs4231_init(chip);
+
+	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL,
+				  chip, &snd_cs4231_sbus_dev_ops)) < 0) {
+		snd_cs4231_sbus_free(chip);
+		return err;
+	}
+
+	*rchip = chip;
+	return 0;
+}
+
+static int cs4231_sbus_attach(struct sbus_dev *sdev)
+{
+	struct resource *rp = &sdev->resource[0];
+	cs4231_t *cp;
+	snd_card_t *card;
+	int err;
+
+	err = cs4231_attach_begin(&card);
+	if (err)
+		return err;
+
+	sprintf(card->longname, "%s at 0x%02lx:0x%08lx, irq %s",
+		card->shortname,
+		rp->flags & 0xffL,
+		rp->start,
+		__irq_itoa(sdev->irqs[0]));
+
+	if ((err = snd_cs4231_sbus_create(card, sdev, dev, &cp)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+	return cs4231_attach_finish(card, cp);
+}
+#endif
+
+#ifdef EBUS_SUPPORT
+static int snd_cs4231_ebus_free(cs4231_t *chip)
+{
+	if (chip->eb2c.regs) {
+		ebus_dma_unregister(&chip->eb2c);
+		iounmap(chip->eb2c.regs);
+	}
+	if (chip->eb2p.regs) {
+		ebus_dma_unregister(&chip->eb2p);
+		iounmap(chip->eb2p.regs);
+	}
+
+	if (chip->port)
+		iounmap(chip->port);
+	if (chip->timer)
+		snd_device_free(chip->card, chip->timer);
+
+	snd_magic_kfree(chip);
+
+	return 0;
+}
+
+static int snd_cs4231_ebus_dev_free(snd_device_t *device)
+{
+	cs4231_t *cp = snd_magic_cast(cs4231_t, device->device_data, return -ENXIO);
+
+	return snd_cs4231_ebus_free(cp);
+}
+
+static snd_device_ops_t snd_cs4231_ebus_dev_ops = {
+	.dev_free	=	snd_cs4231_ebus_dev_free,
+};
+
+static int __init snd_cs4231_ebus_create(snd_card_t *card,
+					 struct linux_ebus_device *edev,
+					 int dev,
+					 cs4231_t **rchip)
+{
+	cs4231_t *chip;
+	int err;
+
+	*rchip = NULL;
+	chip = snd_magic_kcalloc(cs4231_t, 0, GFP_KERNEL);
+	if (chip == NULL)
+		return -ENOMEM;
+
+	spin_lock_init(&chip->lock);
+	spin_lock_init(&chip->eb2c.lock);
+	spin_lock_init(&chip->eb2p.lock);
+	init_MUTEX(&chip->mce_mutex);
+	init_MUTEX(&chip->open_mutex);
+	chip->flags |= CS4231_FLAG_EBUS;
+	chip->card = card;
+	chip->dev_u.pdev = edev->bus->self;
+	memcpy(&chip->image, &snd_cs4231_original_image,
+	       sizeof(snd_cs4231_original_image));
+	strcpy(chip->eb2c.name, "cs4231(capture)");
+	chip->eb2c.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER;
+	chip->eb2c.callback = snd_cs4231_ebus_capture_callback;
+	chip->eb2c.client_cookie = chip;
+	chip->eb2c.irq = edev->irqs[0];
+	strcpy(chip->eb2p.name, "cs4231(play)");
+	chip->eb2p.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER;
+	chip->eb2p.callback = snd_cs4231_ebus_play_callback;
+	chip->eb2p.client_cookie = chip;
+	chip->eb2p.irq = edev->irqs[1];
+
+	chip->port = (unsigned long) ioremap(edev->resource[0].start, 0x10);
+	chip->eb2p.regs = (unsigned long) ioremap(edev->resource[1].start, 0x10);
+	chip->eb2c.regs = (unsigned long) ioremap(edev->resource[2].start, 0x10);
+	if (!chip->port || !chip->eb2p.regs || !chip->eb2c.regs) {
+		snd_cs4231_ebus_free(chip);
+		snd_printk("cs4231-%d: Unable to map chip registers.\n", dev);
+		return -EIO;
+	}
+
+	if (ebus_dma_register(&chip->eb2c)) {
+		snd_cs4231_ebus_free(chip);
+		snd_printk("cs4231-%d: Unable to register EBUS capture DMA\n", dev);
+		return -EBUSY;
+	}
+	if (ebus_dma_irq_enable(&chip->eb2c, 1)) {
+		snd_cs4231_ebus_free(chip);
+		snd_printk("cs4231-%d: Unable to enable EBUS capture IRQ\n", dev);
+		return -EBUSY;
+	}
+
+	if (ebus_dma_register(&chip->eb2p)) {
+		snd_cs4231_ebus_free(chip);
+		snd_printk("cs4231-%d: Unable to register EBUS play DMA\n", dev);
+		return -EBUSY;
+	}
+	if (ebus_dma_irq_enable(&chip->eb2p, 1)) {
+		snd_cs4231_ebus_free(chip);
+		snd_printk("cs4231-%d: Unable to enable EBUS play IRQ\n", dev);
+		return -EBUSY;
+	}
+
+	if (snd_cs4231_probe(chip) < 0) {
+		snd_cs4231_ebus_free(chip);
+		return -ENODEV;
+	}
+	snd_cs4231_init(chip);
+
+	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL,
+				  chip, &snd_cs4231_ebus_dev_ops)) < 0) {
+		snd_cs4231_ebus_free(chip);
+		return err;
+	}
+
+	*rchip = chip;
+	return 0;
+}
+
+static int cs4231_ebus_attach(struct linux_ebus_device *edev)
+{
+	snd_card_t *card;
+	cs4231_t *chip;
+	int err;
+
+	err = cs4231_attach_begin(&card);
+	if (err)
+		return err;
+
+	sprintf(card->longname, "%s at 0x%lx, irq %s",
+		card->shortname,
+		edev->resource[0].start,
+		__irq_itoa(edev->irqs[0]));
+
+	if ((err = snd_cs4231_ebus_create(card, edev, dev, &chip)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+	return cs4231_attach_finish(card, chip);
+}
+#endif
+
+static int __init cs4231_init(void)
+{
+#ifdef SBUS_SUPPORT
+	struct sbus_bus *sbus;
+	struct sbus_dev *sdev;
+#endif
+#ifdef EBUS_SUPPORT
+	struct linux_ebus *ebus;
+	struct linux_ebus_device *edev;
+#endif
+	int found;
+
+	found = 0;
+
+#ifdef SBUS_SUPPORT
+	for_all_sbusdev(sdev, sbus) {
+		if (!strcmp(sdev->prom_name, "SUNW,CS4231")) {
+			if (cs4231_sbus_attach(sdev) == 0)
+				found++;
+		}
+	}
+#endif
+#ifdef EBUS_SUPPORT
+	for_each_ebus(ebus) {
+		for_each_ebusdev(edev, ebus) {
+			int match = 0;
+
+			if (!strcmp(edev->prom_name, "SUNW,CS4231")) {
+				match = 1;
+			} else if (!strcmp(edev->prom_name, "audio")) {
+				char compat[16];
+
+				prom_getstring(edev->prom_node, "compatible",
+					       compat, sizeof(compat));
+				compat[15] = '\0';
+				if (!strcmp(compat, "SUNW,CS4231"))
+					match = 1;
+			}
+
+			if (match &&
+			    cs4231_ebus_attach(edev) == 0)
+				found++;
+		}
+	}
+#endif
+
+
+	return (found > 0) ? 0 : -EIO;
+}
+
+static void __exit cs4231_exit(void)
+{
+	cs4231_t *p = cs4231_list;
+
+	while (p != NULL) {
+		cs4231_t *next = p->next;
+
+		snd_card_free(p->card);
+
+		p = next;
+	}
+
+	cs4231_list = NULL;
+}
+
+module_init(cs4231_init);
+module_exit(cs4231_exit);
+
+#ifndef MODULE
+
+/* format is: snd-sun-cs4231=snd_index,snd_id,snd_enable */
+
+static int __init alsa_card_sun_cs4231_setup(char *str)
+{
+	static unsigned __initdata nr_dev = 0;
+
+	if (nr_dev >= SNDRV_CARDS)
+		return 0;
+	(void)(get_option(&str,&snd_index[nr_dev]) == 2 &&
+	       get_option(&str,&snd_id[nr_dev]) == 2 &&
+	       get_id(&str,&snd_enable[nr_dev]) == 2);
+	nr_dev++;
+	return 1;
+}
+
+__setup("snd-sun-cs4231=", alsa_card_sun_cs4231_setup);
+
+#endif /* ifndef MODULE */
