merge 2.6.13-rc4 with ACPI's to-linus tree
diff --git a/Documentation/pcmcia/driver-changes.txt b/Documentation/pcmcia/driver-changes.txt
index 59ccc63..403e7b4 100644
--- a/Documentation/pcmcia/driver-changes.txt
+++ b/Documentation/pcmcia/driver-changes.txt
@@ -56,3 +56,12 @@
    memory regions in-use. The name argument should be a pointer to
    your driver name. Eg, for pcnet_cs, name should point to the
    string "pcnet_cs".
+
+* CardServices is gone
+  CardServices() in 2.4 is just a big switch statement to call various
+  services.  In 2.6, all of those entry points are exported and called
+  directly (except for pcmcia_report_error(), just use cs_error() instead).
+
+* struct pcmcia_driver
+  You need to use struct pcmcia_driver and pcmcia_{un,}register_driver
+  instead of {un,}register_pccard_driver
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index 104a994..a18ecb9 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -636,11 +636,16 @@
 	  3stack-digout	3-jack in back, a HP out and a SPDIF out
 	  5stack	5-jack in back, 2-jack in front
 	  5stack-digout	5-jack in back, 2-jack in front, a SPDIF out
+	  6stack	6-jack in back, 2-jack in front
+	  6stack-digout	6-jack with a SPDIF out
 	  w810		3-jack
 	  z71v		3-jack (HP shared SPDIF)
 	  asus		3-jack
 	  uniwill	3-jack
 	  F1734		2-jack
+	  test		for testing/debugging purpose, almost all controls can be
+			adjusted.  Appearing only when compiled with
+			$CONFIG_SND_DEBUG=y
 
 	CMI9880
 	  minimal	3-jack in back
@@ -1054,6 +1059,13 @@
 
     The power-management is supported.
 
+  Module snd-pxa2xx-ac97 (on arm only)
+  ------------------------------------
+
+    Module for AC97 driver for the Intel PXA2xx chip
+
+    For ARM architecture only.
+
   Module snd-rme32
   ----------------
 
@@ -1173,6 +1185,13 @@
 
     Module supports up to 8 cards.
 
+  Module snd-sun-dbri (on sparc only)
+  -----------------------------------
+
+    Module for DBRI sound chips found on Sparcs.
+
+    Module supports up to 8 cards.
+
   Module snd-wavefront
   --------------------
 
@@ -1371,7 +1390,7 @@
   Module snd-vxpocket
   -------------------
 
-    Module for Digigram VX-Pocket VX2 PCMCIA card.
+    Module for Digigram VX-Pocket VX2 and 440 PCMCIA cards.
 
     ibl      - Capture IBL size. (default = 0, minimum size)
 
@@ -1391,29 +1410,6 @@
 
     Note: the driver is build only when CONFIG_ISA is set.
     
-  Module snd-vxp440
-  -----------------
-
-    Module for Digigram VX-Pocket 440 PCMCIA card.
-
-    ibl      - Capture IBL size. (default = 0, minimum size)
-
-    Module supports up to 8 cards.  The module is compiled only when
-    PCMCIA is supported on kernel.
-
-    To activate the driver via the card manager, you'll need to set
-    up /etc/pcmcia/vxp440.conf.  See the sound/pcmcia/vx/vxp440.c.
-
-    When the driver is compiled as a module and the hotplug firmware
-    is supported, the firmware data is loaded via hotplug automatically.
-    Install the necessary firmware files in alsa-firmware package.
-    When no hotplug fw loader is available, you need to load the
-    firmware via vxloader utility in alsa-tools package.
-
-    About capture IBL, see the description of snd-vx222 module.
-
-    Note: the driver is build only when CONFIG_ISA is set.
-    
   Module snd-ymfpci
   -----------------
 
diff --git a/Documentation/stable_api_nonsense.txt b/Documentation/stable_api_nonsense.txt
index 3cea138..f39c9d7 100644
--- a/Documentation/stable_api_nonsense.txt
+++ b/Documentation/stable_api_nonsense.txt
@@ -132,7 +132,7 @@
 their work on their own time, asking programmers to do extra work for no
 gain, for free, is not a possibility.
 
-Security issues are also a very important for Linux.  When a
+Security issues are also very important for Linux.  When a
 security issue is found, it is fixed in a very short amount of time.  A
 number of times this has caused internal kernel interfaces to be
 reworked to prevent the security problem from occurring.  When this
diff --git a/Documentation/stable_kernel_rules.txt b/Documentation/stable_kernel_rules.txt
new file mode 100644
index 0000000..2c81305
--- /dev/null
+++ b/Documentation/stable_kernel_rules.txt
@@ -0,0 +1,58 @@
+Everything you ever wanted to know about Linux 2.6 -stable releases.
+
+Rules on what kind of patches are accepted, and what ones are not, into
+the "-stable" tree:
+
+ - It must be obviously correct and tested.
+ - It can not bigger than 100 lines, with context.
+ - It must fix only one thing.
+ - It must fix a real bug that bothers people (not a, "This could be a
+   problem..." type thing.)
+ - It must fix a problem that causes a build error (but not for things
+   marked CONFIG_BROKEN), an oops, a hang, data corruption, a real
+   security issue, or some "oh, that's not good" issue.  In short,
+   something critical.
+ - No "theoretical race condition" issues, unless an explanation of how
+   the race can be exploited.
+ - It can not contain any "trivial" fixes in it (spelling changes,
+   whitespace cleanups, etc.)
+ - It must be accepted by the relevant subsystem maintainer.
+ - It must follow Documentation/SubmittingPatches rules.
+
+
+Procedure for submitting patches to the -stable tree:
+
+ - Send the patch, after verifying that it follows the above rules, to
+   stable@kernel.org.
+ - The sender will receive an ack when the patch has been accepted into
+   the queue, or a nak if the patch is rejected.  This response might
+   take a few days, according to the developer's schedules.
+ - If accepted, the patch will be added to the -stable queue, for review
+   by other developers.
+ - Security patches should not be sent to this alias, but instead to the
+   documented security@kernel.org.
+
+
+Review cycle:
+
+ - When the -stable maintainers decide for a review cycle, the patches
+   will be sent to the review committee, and the maintainer of the
+   affected area of the patch (unless the submitter is the maintainer of
+   the area) and CC: to the linux-kernel mailing list.
+ - The review committee has 48 hours in which to ack or nak the patch.
+ - If the patch is rejected by a member of the committee, or linux-kernel
+   members object to the patch, bringing up issues that the maintainers
+   and members did not realize, the patch will be dropped from the
+   queue.
+ - At the end of the review cycle, the acked patches will be added to
+   the latest -stable release, and a new -stable release will happen.
+ - Security patches will be accepted into the -stable tree directly from
+   the security kernel team, and not go through the normal review cycle.
+   Contact the kernel security team for more details on this procedure.
+
+
+Review committe:
+
+ - This will be made up of a number of kernel developers who have
+   volunteered for this task, and a few that haven't.
+
diff --git a/Documentation/x86_64/boot-options.txt b/Documentation/x86_64/boot-options.txt
index b9e6be0..476c0c2 100644
--- a/Documentation/x86_64/boot-options.txt
+++ b/Documentation/x86_64/boot-options.txt
@@ -47,7 +47,7 @@
   notsc
   Don't use the CPU time stamp counter to read the wall time.
   This can be used to work around timing problems on multiprocessor systems
-  with not properly synchronized CPUs. Only useful with a SMP kernel
+  with not properly synchronized CPUs.
 
   report_lost_ticks
   Report when timer interrupts are lost because some code turned off
@@ -74,6 +74,9 @@
   event. This will make the CPUs eat a lot more power, but may be useful
   to get slightly better performance in multiprocessor benchmarks. It also
   makes some profiling using performance counters more accurate.
+  Please note that on systems with MONITOR/MWAIT support (like Intel EM64T
+  CPUs) this option has no performance advantage over the normal idle loop.
+  It may also interact badly with hyperthreading.
 
 Rebooting
 
@@ -178,6 +181,5 @@
 Misc
 
   noreplacement  Don't replace instructions with more appropiate ones
-  				 for the CPU. This may be useful on asymmetric MP systems
-				 where some CPU have less capabilities than the others.
-
+		 for the CPU. This may be useful on asymmetric MP systems
+		 where some CPU have less capabilities than the others.
diff --git a/Makefile b/Makefile
index cf34a6b..717b9b9 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 13
-EXTRAVERSION =-rc3
+EXTRAVERSION =-rc4
 NAME=Woozy Numbat
 
 # *DOCUMENTATION*
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 295e0a8..b208573 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -176,6 +176,7 @@
 	cpu_set(cpu, mm->cpu_vm_mask);
 	cpu_switch_mm(mm->pgd, mm);
 	enter_lazy_tlb(mm, current);
+	local_flush_tlb_all();
 
 	cpu_init();
 
diff --git a/arch/arm/lib/bitops.h b/arch/arm/lib/bitops.h
index 5382a30..2036ff1 100644
--- a/arch/arm/lib/bitops.h
+++ b/arch/arm/lib/bitops.h
@@ -7,7 +7,7 @@
 1:	ldrexb	r2, [r1]
 	\instr	r2, r2, r3
 	strexb	r0, r2, [r1]
-	cmpne	r0, #0
+	cmp	r0, #0
 	bne	1b
 	mov	pc, lr
 	.endm
diff --git a/arch/arm/mach-integrator/platsmp.c b/arch/arm/mach-integrator/platsmp.c
index aecf47b..ea10bd8 100644
--- a/arch/arm/mach-integrator/platsmp.c
+++ b/arch/arm/mach-integrator/platsmp.c
@@ -15,6 +15,7 @@
 #include <linux/mm.h>
 
 #include <asm/atomic.h>
+#include <asm/cacheflush.h>
 #include <asm/delay.h>
 #include <asm/mmu_context.h>
 #include <asm/procinfo.h>
@@ -80,6 +81,7 @@
 	 * "cpu" is Linux's internal ID.
 	 */
 	pen_release = cpu;
+	flush_cache_all();
 
 	/*
 	 * XXX
diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
index 31f65c8..ab6e061 100644
--- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
@@ -1,5 +1,5 @@
 /*
- *   (c) 2003, 2004 Advanced Micro Devices, Inc.
+ *   (c) 2003, 2004, 2005 Advanced Micro Devices, Inc.
  *  Your use of this code is subject to the terms and conditions of the
  *  GNU general public license version 2. See "COPYING" or
  *  http://www.gnu.org/licenses/gpl.html
@@ -44,7 +44,7 @@
 
 #define PFX "powernow-k8: "
 #define BFX PFX "BIOS error: "
-#define VERSION "version 1.40.2"
+#define VERSION "version 1.50.3"
 #include "powernow-k8.h"
 
 /* serialize freq changes  */
@@ -231,7 +231,7 @@
 /*
  * Reduce the vid by the max of step or reqvid.
  * Decreasing vid codes represent increasing voltages:
- * vid of 0 is 1.550V, vid of 0x1e is 0.800V, vid of 0x1f is off.
+ * vid of 0 is 1.550V, vid of 0x1e is 0.800V, vid of VID_OFF is off.
  */
 static int decrease_vid_code_by_step(struct powernow_k8_data *data, u32 reqvid, u32 step)
 {
@@ -466,7 +466,7 @@
 	eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
 	if (((eax & CPUID_USE_XFAM_XMOD) != CPUID_USE_XFAM_XMOD) ||
 	    ((eax & CPUID_XFAM) != CPUID_XFAM_K8) ||
-	    ((eax & CPUID_XMOD) > CPUID_XMOD_REV_E)) {
+	    ((eax & CPUID_XMOD) > CPUID_XMOD_REV_F)) {
 		printk(KERN_INFO PFX "Processor cpuid %x not supported\n", eax);
 		goto out;
 	}
@@ -695,6 +695,7 @@
 
 	data->irt = (data->acpi_data.states[index].control >> IRT_SHIFT) & IRT_MASK;
 	data->rvo = (data->acpi_data.states[index].control >> RVO_SHIFT) & RVO_MASK;
+	data->exttype = (data->acpi_data.states[index].control >> EXT_TYPE_SHIFT) & EXT_TYPE_MASK;
 	data->plllock = (data->acpi_data.states[index].control >> PLL_L_SHIFT) & PLL_L_MASK;
 	data->vidmvs = 1 << ((data->acpi_data.states[index].control >> MVS_SHIFT) & MVS_MASK);
 	data->vstable = (data->acpi_data.states[index].control >> VST_SHIFT) & VST_MASK;
@@ -734,8 +735,16 @@
 	}
 
 	for (i = 0; i < data->acpi_data.state_count; i++) {
-		u32 fid = data->acpi_data.states[i].control & FID_MASK;
-		u32 vid = (data->acpi_data.states[i].control >> VID_SHIFT) & VID_MASK;
+		u32 fid;
+		u32 vid;
+
+		if (data->exttype) {
+			fid = data->acpi_data.states[i].status & FID_MASK;
+			vid = (data->acpi_data.states[i].status >> VID_SHIFT) & VID_MASK;
+		} else {
+			fid = data->acpi_data.states[i].control & FID_MASK;
+			vid = (data->acpi_data.states[i].control >> VID_SHIFT) & VID_MASK;
+		}
 
 		dprintk("   %d : fid 0x%x, vid 0x%x\n", i, fid, vid);
 
@@ -752,7 +761,7 @@
 		}
 
 		/* verify voltage is OK - BIOSs are using "off" to indicate invalid */
-		if (vid == 0x1f) {
+		if (vid == VID_OFF) {
 			dprintk("invalid vid %u, ignoring\n", vid);
 			powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID;
 			continue;
@@ -929,15 +938,6 @@
 
 	down(&fidvid_sem);
 
-	for_each_cpu_mask(i, cpu_core_map[pol->cpu]) {
-		/* make sure the sibling is initialized */
-		if (!powernow_data[i]) {
-                        ret = 0;
-                        up(&fidvid_sem);
-                        goto err_out;
-                }
-	}
-
 	powernow_k8_acpi_pst_values(data, newstate);
 
 	if (transition_frequency(data, newstate)) {
@@ -977,7 +977,7 @@
 {
 	struct powernow_k8_data *data;
 	cpumask_t oldmask = CPU_MASK_ALL;
-	int rc;
+	int rc, i;
 
 	if (!check_supported_cpu(pol->cpu))
 		return -ENODEV;
@@ -1063,7 +1063,9 @@
 	printk("cpu_init done, current fid 0x%x, vid 0x%x\n",
 	       data->currfid, data->currvid);
 
-	powernow_data[pol->cpu] = data;
+	for_each_cpu_mask(i, cpu_core_map[pol->cpu]) {
+		powernow_data[i] = data;
+	}
 
 	return 0;
 
diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h
index 9ed5bf2..b1e85bb 100644
--- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h
@@ -1,5 +1,5 @@
 /*
- *  (c) 2003, 2004 Advanced Micro Devices, Inc.
+ *  (c) 2003, 2004, 2005 Advanced Micro Devices, Inc.
  *  Your use of this code is subject to the terms and conditions of the
  *  GNU general public license version 2. See "COPYING" or
  *  http://www.gnu.org/licenses/gpl.html
@@ -19,6 +19,7 @@
 	u32 vidmvs;  /* usable value calculated from mvs */
 	u32 vstable; /* voltage stabilization time, units 20 us */
 	u32 plllock; /* pll lock time, units 1 us */
+        u32 exttype; /* extended interface = 1 */
 
 	/* keep track of the current fid / vid */
 	u32 currvid, currfid;
@@ -41,7 +42,7 @@
 #define CPUID_XFAM			0x0ff00000	/* extended family */
 #define CPUID_XFAM_K8			0
 #define CPUID_XMOD			0x000f0000	/* extended model */
-#define CPUID_XMOD_REV_E		0x00020000
+#define CPUID_XMOD_REV_F		0x00040000
 #define CPUID_USE_XFAM_XMOD		0x00000f00
 #define CPUID_GET_MAX_CAPABILITIES	0x80000000
 #define CPUID_FREQ_VOLT_CAPABILITIES	0x80000007
@@ -57,25 +58,26 @@
 
 /* Field definitions within the FID VID Low Control MSR : */
 #define MSR_C_LO_INIT_FID_VID     0x00010000
-#define MSR_C_LO_NEW_VID          0x00001f00
-#define MSR_C_LO_NEW_FID          0x0000002f
+#define MSR_C_LO_NEW_VID          0x00003f00
+#define MSR_C_LO_NEW_FID          0x0000003f
 #define MSR_C_LO_VID_SHIFT        8
 
 /* Field definitions within the FID VID High Control MSR : */
-#define MSR_C_HI_STP_GNT_TO       0x000fffff
+#define MSR_C_HI_STP_GNT_TO 	  0x000fffff
 
 /* Field definitions within the FID VID Low Status MSR : */
-#define MSR_S_LO_CHANGE_PENDING   0x80000000	/* cleared when completed */
-#define MSR_S_LO_MAX_RAMP_VID     0x1f000000
+#define MSR_S_LO_CHANGE_PENDING   0x80000000   /* cleared when completed */
+#define MSR_S_LO_MAX_RAMP_VID     0x3f000000
 #define MSR_S_LO_MAX_FID          0x003f0000
 #define MSR_S_LO_START_FID        0x00003f00
 #define MSR_S_LO_CURRENT_FID      0x0000003f
 
 /* Field definitions within the FID VID High Status MSR : */
-#define MSR_S_HI_MAX_WORKING_VID  0x001f0000
-#define MSR_S_HI_START_VID        0x00001f00
-#define MSR_S_HI_CURRENT_VID      0x0000001f
-#define MSR_C_HI_STP_GNT_BENIGN   0x00000001
+#define MSR_S_HI_MIN_WORKING_VID  0x3f000000
+#define MSR_S_HI_MAX_WORKING_VID  0x003f0000
+#define MSR_S_HI_START_VID        0x00003f00
+#define MSR_S_HI_CURRENT_VID      0x0000003f
+#define MSR_C_HI_STP_GNT_BENIGN	  0x00000001
 
 /*
  * There are restrictions frequencies have to follow:
@@ -99,13 +101,15 @@
 #define MIN_FREQ_RESOLUTION  200 /* fids jump by 2 matching freq jumps by 200 */
 
 #define MAX_FID 0x2a	/* Spec only gives FID values as far as 5 GHz */
-#define LEAST_VID 0x1e	/* Lowest (numerically highest) useful vid value */
+#define LEAST_VID 0x3e	/* Lowest (numerically highest) useful vid value */
 
 #define MIN_FREQ 800	/* Min and max freqs, per spec */
 #define MAX_FREQ 5000
 
 #define INVALID_FID_MASK 0xffffffc1  /* not a valid fid if these bits are set */
-#define INVALID_VID_MASK 0xffffffe0  /* not a valid vid if these bits are set */
+#define INVALID_VID_MASK 0xffffffc0  /* not a valid vid if these bits are set */
+
+#define VID_OFF 0x3f
 
 #define STOP_GRANT_5NS 1 /* min poss memory access latency for voltage change */
 
@@ -121,12 +125,14 @@
                                                                                                     
 #define IRT_SHIFT      30
 #define RVO_SHIFT      28
+#define EXT_TYPE_SHIFT 27
 #define PLL_L_SHIFT    20
 #define MVS_SHIFT      18
 #define VST_SHIFT      11
 #define VID_SHIFT       6
 #define IRT_MASK        3
 #define RVO_MASK        3
+#define EXT_TYPE_MASK   1
 #define PLL_L_MASK   0x7f
 #define MVS_MASK        3
 #define VST_MASK     0x7f
diff --git a/arch/i386/kernel/cpu/intel_cacheinfo.c b/arch/i386/kernel/cpu/intel_cacheinfo.c
index 1d768b2..6c55b50 100644
--- a/arch/i386/kernel/cpu/intel_cacheinfo.c
+++ b/arch/i386/kernel/cpu/intel_cacheinfo.c
@@ -128,7 +128,7 @@
 	cpuid_count(4, index, &eax, &ebx, &ecx, &edx);
 	cache_eax.full = eax;
 	if (cache_eax.split.type == CACHE_TYPE_NULL)
-		return -1;
+		return -EIO; /* better error ? */
 
 	this_leaf->eax.full = eax;
 	this_leaf->ebx.full = ebx;
@@ -334,6 +334,7 @@
 	struct _cpuid4_info	*this_leaf;
 	unsigned long 		j;
 	int 			retval;
+	cpumask_t		oldmask;
 
 	if (num_cache_leaves == 0)
 		return -ENOENT;
@@ -345,19 +346,26 @@
 	memset(cpuid4_info[cpu], 0,
 	    sizeof(struct _cpuid4_info) * num_cache_leaves);
 
+	oldmask = current->cpus_allowed;
+	retval = set_cpus_allowed(current, cpumask_of_cpu(cpu));
+	if (retval)
+		goto out;
+
 	/* Do cpuid and store the results */
+	retval = 0;
 	for (j = 0; j < num_cache_leaves; j++) {
 		this_leaf = CPUID4_INFO_IDX(cpu, j);
 		retval = cpuid4_cache_lookup(j, this_leaf);
 		if (unlikely(retval < 0))
-			goto err_out;
+			break;
 		cache_shared_cpu_map_setup(cpu, j);
 	}
-	return 0;
+	set_cpus_allowed(current, oldmask);
 
-err_out:
-	free_cache_attributes(cpu);
-	return -ENOMEM;
+out:
+	if (retval)
+		free_cache_attributes(cpu);
+	return retval;
 }
 
 #ifdef CONFIG_SYSFS
diff --git a/arch/i386/kernel/machine_kexec.c b/arch/i386/kernel/machine_kexec.c
index 52ed18d..cb699a2 100644
--- a/arch/i386/kernel/machine_kexec.c
+++ b/arch/i386/kernel/machine_kexec.c
@@ -16,6 +16,7 @@
 #include <asm/io.h>
 #include <asm/apic.h>
 #include <asm/cpufeature.h>
+#include <asm/desc.h>
 
 static inline unsigned long read_cr3(void)
 {
@@ -90,33 +91,32 @@
 }
 #endif
 
-
 static void set_idt(void *newidt, __u16 limit)
 {
-	unsigned char curidt[6];
+	struct Xgt_desc_struct curidt;
 
 	/* ia32 supports unaliged loads & stores */
-	(*(__u16 *)(curidt)) = limit;
-	(*(__u32 *)(curidt +2)) = (unsigned long)(newidt);
+	curidt.size    = limit;
+	curidt.address = (unsigned long)newidt;
 
 	__asm__ __volatile__ (
-		"lidt %0\n"
-		: "=m" (curidt)
+		"lidtl %0\n"
+		: : "m" (curidt)
 		);
 };
 
 
 static void set_gdt(void *newgdt, __u16 limit)
 {
-	unsigned char curgdt[6];
+	struct Xgt_desc_struct curgdt;
 
 	/* ia32 supports unaligned loads & stores */
-	(*(__u16 *)(curgdt)) = limit;
-	(*(__u32 *)(curgdt +2)) = (unsigned long)(newgdt);
+	curgdt.size    = limit;
+	curgdt.address = (unsigned long)newgdt;
 
 	__asm__ __volatile__ (
-		"lgdt %0\n"
-		: "=m" (curgdt)
+		"lgdtl %0\n"
+		: : "m" (curgdt)
 		);
 };
 
diff --git a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c
index af917f6..ce838ab 100644
--- a/arch/i386/kernel/mpparse.c
+++ b/arch/i386/kernel/mpparse.c
@@ -1116,7 +1116,15 @@
 		 */
 		int irq = gsi;
 		if (gsi < MAX_GSI_NUM) {
-			gsi = pci_irq++;
+			if (gsi > 15)
+				gsi = pci_irq++;
+#ifdef CONFIG_ACPI_BUS
+			/*
+			 * Don't assign IRQ used by ACPI SCI
+			 */
+			if (gsi == acpi_fadt.sci_int)
+				gsi = pci_irq++;
+#endif
 			gsi_to_irq[irq] = gsi;
 		} else {
 			printk(KERN_ERR "GSI %u is too high\n", gsi);
diff --git a/arch/i386/kernel/numaq.c b/arch/i386/kernel/numaq.c
index e51edf0..5f5b075 100644
--- a/arch/i386/kernel/numaq.c
+++ b/arch/i386/kernel/numaq.c
@@ -31,6 +31,7 @@
 #include <linux/nodemask.h>
 #include <asm/numaq.h>
 #include <asm/topology.h>
+#include <asm/processor.h>
 
 #define	MB_TO_PAGES(addr) ((addr) << (20 - PAGE_SHIFT))
 
@@ -77,3 +78,11 @@
 	smp_dump_qct();
 	return 1;
 }
+
+static int __init numaq_dsc_disable(void)
+{
+	printk(KERN_DEBUG "NUMAQ: disabling TSC\n");
+	tsc_disable = 1;
+	return 0;
+}
+core_initcall(numaq_dsc_disable);
diff --git a/arch/i386/mm/discontig.c b/arch/i386/mm/discontig.c
index b358f07..c369a8b 100644
--- a/arch/i386/mm/discontig.c
+++ b/arch/i386/mm/discontig.c
@@ -243,6 +243,14 @@
 		/* now the roundup is correct, convert to PAGE_SIZE pages */
 		size = size * PTRS_PER_PTE;
 
+		if (node_end_pfn[nid] & (PTRS_PER_PTE-1)) {
+			/*
+			 * Adjust size if node_end_pfn is not on a proper
+			 * pmd boundary. remap_numa_kva will barf otherwise.
+			 */
+			size +=  node_end_pfn[nid] & (PTRS_PER_PTE-1);
+		}
+
 		/*
 		 * Validate the region we are allocating only contains valid
 		 * pages.
diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c
index 187350c..86348b6 100644
--- a/arch/i386/pci/irq.c
+++ b/arch/i386/pci/irq.c
@@ -551,6 +551,13 @@
 static __init int via_router_probe(struct irq_router *r, struct pci_dev *router, u16 device)
 {
 	/* FIXME: We should move some of the quirk fixup stuff here */
+
+	if (router->device == PCI_DEVICE_ID_VIA_82C686 &&
+			device == PCI_DEVICE_ID_VIA_82C586_0) {
+		/* Asus k7m bios wrongly reports 82C686A as 586-compatible */
+		device = PCI_DEVICE_ID_VIA_82C686;
+	}
+
 	switch(device)
 	{
 		case PCI_DEVICE_ID_VIA_82C586_0:
diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c
index c067435..c9f2f60 100644
--- a/arch/s390/appldata/appldata_base.c
+++ b/arch/s390/appldata/appldata_base.c
@@ -232,7 +232,11 @@
 	ry = -1;
 	asm volatile(
 			"diag %1,%0,0xDC\n\t"
-			: "=d" (ry) : "d" (&(appldata_parameter_list)) : "cc");
+			: "=d" (ry)
+			: "d" (&appldata_parameter_list),
+			  "m" (appldata_parameter_list),
+			  "m" (appldata_product_id)
+			: "cc");
 	return (int) ry;
 }
 /************************ timer, work, DIAG <END> ****************************/
diff --git a/arch/s390/defconfig b/arch/s390/defconfig
index 89850b2..0865251 100644
--- a/arch/s390/defconfig
+++ b/arch/s390/defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc3
-# Fri Apr 22 15:30:58 2005
+# Linux kernel version: 2.6.13-rc4
+# Fri Jul 29 14:49:30 2005
 #
 CONFIG_MMU=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
@@ -23,10 +23,11 @@
 CONFIG_LOCALVERSION=""
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
-# CONFIG_POSIX_MQUEUE is not set
+CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
-# CONFIG_AUDIT is not set
+CONFIG_AUDIT=y
+# CONFIG_AUDITSYSCALL is not set
 CONFIG_HOTPLUG=y
 CONFIG_KOBJECT_UEVENT=y
 CONFIG_IKCONFIG=y
@@ -36,6 +37,8 @@
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
@@ -51,9 +54,10 @@
 # Loadable module support
 #
 CONFIG_MODULES=y
-# CONFIG_MODULE_UNLOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
 CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
+CONFIG_MODVERSIONS=y
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 CONFIG_STOP_MACHINE=y
@@ -81,8 +85,15 @@
 # CONFIG_MARCH_Z990 is not set
 CONFIG_PACK_STACK=y
 # CONFIG_SMALL_STACK is not set
-# CONFIG_CHECK_STACK is not set
+CONFIG_CHECK_STACK=y
+CONFIG_STACK_GUARD=256
 # CONFIG_WARN_STACK is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
 
 #
 # I/O subsystem configuration
@@ -95,7 +106,7 @@
 #
 # Misc
 #
-# CONFIG_PREEMPT is not set
+CONFIG_PREEMPT=y
 CONFIG_IPL=y
 # CONFIG_IPL_TAPE is not set
 CONFIG_IPL_VM=y
@@ -105,9 +116,110 @@
 CONFIG_PFAULT=y
 # CONFIG_SHARED_KERNEL is not set
 # CONFIG_CMM is not set
-# CONFIG_VIRT_TIMER is not set
+CONFIG_VIRT_TIMER=y
+CONFIG_VIRT_CPU_ACCOUNTING=y
+# CONFIG_APPLDATA_BASE is not set
 CONFIG_NO_IDLE_HZ=y
 CONFIG_NO_IDLE_HZ_INIT=y
+# CONFIG_KEXEC is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+CONFIG_IP_TCPDIAG_IPV6=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+CONFIG_IPV6=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CLK_JIFFIES=y
+# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set
+# CONFIG_NET_SCH_CLK_CPU is not set
+CONFIG_NET_SCH_CBQ=m
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_HFSC is not set
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+# CONFIG_NET_SCH_NETEM is not set
+# CONFIG_NET_SCH_INGRESS is not set
+CONFIG_NET_QOS=y
+CONFIG_NET_ESTIMATOR=y
+CONFIG_NET_CLS=y
+# CONFIG_NET_CLS_BASIC is not set
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+# CONFIG_CLS_U32_PERF is not set
+# CONFIG_NET_CLS_IND is not set
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_CLS_ACT is not set
+CONFIG_NET_CLS_POLICE=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
 # CONFIG_PCMCIA is not set
 
 #
@@ -133,6 +245,7 @@
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
 
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
@@ -205,7 +318,13 @@
 # CONFIG_MD_RAID6 is not set
 CONFIG_MD_MULTIPATH=m
 # CONFIG_MD_FAULTY is not set
-# CONFIG_BLK_DEV_DM is not set
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_SNAPSHOT=y
+CONFIG_DM_MIRROR=y
+CONFIG_DM_ZERO=y
+CONFIG_DM_MULTIPATH=y
+# CONFIG_DM_MULTIPATH_EMC is not set
 
 #
 # Character device drivers
@@ -231,7 +350,8 @@
 CONFIG_SCLP=y
 CONFIG_SCLP_TTY=y
 CONFIG_SCLP_CONSOLE=y
-# CONFIG_SCLP_VT220_TTY is not set
+CONFIG_SCLP_VT220_TTY=y
+CONFIG_SCLP_VT220_CONSOLE=y
 CONFIG_SCLP_CPI=m
 CONFIG_S390_TAPE=m
 
@@ -255,105 +375,8 @@
 CONFIG_Z90CRYPT=m
 
 #
-# Networking support
+# Network device support
 #
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_UNIX=y
-CONFIG_NET_KEY=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-CONFIG_IP_TCPDIAG_IPV6=y
-CONFIG_IPV6=y
-# CONFIG_IPV6_PRIVACY is not set
-# CONFIG_INET6_AH is not set
-# CONFIG_INET6_ESP is not set
-# CONFIG_INET6_IPCOMP is not set
-# CONFIG_INET6_TUNNEL is not set
-# CONFIG_IPV6_TUNNEL is not set
-# CONFIG_NETFILTER is not set
-CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-CONFIG_NET_SCHED=y
-CONFIG_NET_SCH_CLK_JIFFIES=y
-# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set
-# CONFIG_NET_SCH_CLK_CPU is not set
-CONFIG_NET_SCH_CBQ=m
-# CONFIG_NET_SCH_HTB is not set
-# CONFIG_NET_SCH_HFSC is not set
-CONFIG_NET_SCH_PRIO=m
-CONFIG_NET_SCH_RED=m
-CONFIG_NET_SCH_SFQ=m
-CONFIG_NET_SCH_TEQL=m
-CONFIG_NET_SCH_TBF=m
-CONFIG_NET_SCH_GRED=m
-CONFIG_NET_SCH_DSMARK=m
-# CONFIG_NET_SCH_NETEM is not set
-# CONFIG_NET_SCH_INGRESS is not set
-CONFIG_NET_QOS=y
-CONFIG_NET_ESTIMATOR=y
-CONFIG_NET_CLS=y
-# CONFIG_NET_CLS_BASIC is not set
-CONFIG_NET_CLS_TCINDEX=m
-CONFIG_NET_CLS_ROUTE4=m
-CONFIG_NET_CLS_ROUTE=y
-CONFIG_NET_CLS_FW=m
-CONFIG_NET_CLS_U32=m
-# CONFIG_CLS_U32_PERF is not set
-# CONFIG_NET_CLS_IND is not set
-CONFIG_NET_CLS_RSVP=m
-CONFIG_NET_CLS_RSVP6=m
-# CONFIG_NET_EMATCH is not set
-# CONFIG_NET_CLS_ACT is not set
-CONFIG_NET_CLS_POLICE=y
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=m
 CONFIG_BONDING=m
@@ -411,12 +434,15 @@
 # CONFIG_SLIP is not set
 # CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
 
 #
 # File systems
 #
 CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
 CONFIG_EXT3_FS_XATTR=y
 # CONFIG_EXT3_FS_POSIX_ACL is not set
@@ -426,6 +452,7 @@
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
 
 #
 # XFS support
@@ -433,6 +460,7 @@
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
 # CONFIG_QUOTA is not set
 CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
@@ -457,7 +485,6 @@
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
 CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
 # CONFIG_TMPFS_XATTR is not set
@@ -486,15 +513,18 @@
 #
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
 # CONFIG_NFS_V4 is not set
 # CONFIG_NFS_DIRECTIO is not set
 CONFIG_NFSD=y
 CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
 # CONFIG_NFSD_V4 is not set
 CONFIG_NFSD_TCP=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
 CONFIG_EXPORTFS=y
+CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -544,11 +574,12 @@
 CONFIG_LOG_BUF_SHIFT=17
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_PREEMPT=y
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_INFO is not set
-# CONFIG_DEBUG_FS is not set
+CONFIG_DEBUG_FS=y
 
 #
 # Security options
diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S
index d12cff1..2710e66 100644
--- a/arch/s390/kernel/head.S
+++ b/arch/s390/kernel/head.S
@@ -346,6 +346,13 @@
         la    %r2,.Lreset              
         lhi   %r3,26
 	diag  %r2,%r3,8
+	la    %r5,.Lirb
+	stsch 0(%r5)			       # check if irq is pending
+	tm    30(%r5),0x0f		       # by verifying if any of the
+	bnz   .Lwaitforirq		       # activity or status control
+	tm    31(%r5),0xff		       # bits is set in the schib
+	bz    .Lnoreset
+.Lwaitforirq:
 	mvc   0x78(8),.Lrdrnewpsw              # set up IO interrupt psw
 .Lwaitrdrirq:
 	lpsw  .Lrdrwaitpsw
diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S
index 10bc592..9a8263a 100644
--- a/arch/s390/kernel/head64.S
+++ b/arch/s390/kernel/head64.S
@@ -345,6 +345,13 @@
         la    %r2,.Lreset              
         lhi   %r3,26
 	diag  %r2,%r3,8
+	la    %r5,.Lirb
+	stsch 0(%r5)			       # check if irq is pending
+	tm    30(%r5),0x0f		       # by verifying if any of the
+	bnz   .Lwaitforirq		       # activity or status control
+	tm    31(%r5),0xff		       # bits is set in the schib
+	bz    .Lnoreset
+.Lwaitforirq:
 	mvc   0x78(8),.Lrdrnewpsw	       # set up IO interrupt psw
 .Lwaitrdrirq:
 	lpsw  .Lrdrwaitpsw
diff --git a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile
index d6c31a9..de17d4c 100644
--- a/arch/um/drivers/Makefile
+++ b/arch/um/drivers/Makefile
@@ -19,6 +19,8 @@
 
 LDFLAGS_pcap.o := -r $(shell $(CC) $(CFLAGS) -print-file-name=libpcap.a)
 
+targets := pcap_kern.o pcap_user.o
+
 $(obj)/pcap.o: $(obj)/pcap_kern.o $(obj)/pcap_user.o
 	$(LD) -r -dp -o $@ $^ $(LDFLAGS) $(LDFLAGS_pcap.o)
 #XXX: The call below does not work because the flags are added before the
@@ -26,7 +28,7 @@
 #$(call if_changed,ld)
 
 # When the above is fixed, don't forget to add this too!
-#targets := $(obj)/pcap.o
+#targets += $(obj)/pcap.o
 
 obj-y := stdio_console.o fd.o chan_kern.o chan_user.o line.o
 obj-$(CONFIG_SSL) += ssl.o
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
index 404de41..c190c24 100644
--- a/arch/um/drivers/mconsole_kern.c
+++ b/arch/um/drivers/mconsole_kern.c
@@ -557,7 +557,7 @@
 
 	ent = create_proc_entry("mconsole", S_IFREG | 0200, NULL);
 	if(ent == NULL){
-		printk("create_proc_mconsole : create_proc_entry failed\n");
+		printk(KERN_INFO "create_proc_mconsole : create_proc_entry failed\n");
 		return(0);
 	}
 
diff --git a/arch/um/kernel/exitcode.c b/arch/um/kernel/exitcode.c
index 0ea87f2..d21ebad 100644
--- a/arch/um/kernel/exitcode.c
+++ b/arch/um/kernel/exitcode.c
@@ -48,7 +48,7 @@
 
 	ent = create_proc_entry("exitcode", 0600, &proc_root);
 	if(ent == NULL){
-		printk("make_proc_exitcode : Failed to register "
+		printk(KERN_WARNING "make_proc_exitcode : Failed to register "
 		       "/proc/exitcode\n");
 		return(0);
 	}
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index 8b01a55..67acd92 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -131,7 +131,7 @@
 	return(arg.pid);
 }
 
-static int ptrace_child(void)
+static int ptrace_child(void *arg)
 {
 	int ret;
 	int pid = os_getpid(), ppid = getppid();
@@ -160,16 +160,20 @@
 	_exit(ret);
 }
 
-static int start_ptraced_child(void)
+static int start_ptraced_child(void **stack_out)
 {
+	void *stack;
+	unsigned long sp;
 	int pid, n, status;
 	
-	pid = fork();
-	if(pid == 0)
-		ptrace_child();
-
+	stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
+		     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+	if(stack == MAP_FAILED)
+		panic("check_ptrace : mmap failed, errno = %d", errno);
+	sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
+	pid = clone(ptrace_child, (void *) sp, SIGCHLD, NULL);
 	if(pid < 0)
-		panic("check_ptrace : fork failed, errno = %d", errno);
+		panic("check_ptrace : clone failed, errno = %d", errno);
 	CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
 	if(n < 0)
 		panic("check_ptrace : wait failed, errno = %d", errno);
@@ -177,6 +181,7 @@
 		panic("check_ptrace : expected SIGSTOP, got status = %d",
 		      status);
 
+	*stack_out = stack;
 	return(pid);
 }
 
@@ -184,12 +189,12 @@
  * just avoid using sysemu, not panic, but only if SYSEMU features are broken.
  * So only for SYSEMU features we test mustpanic, while normal host features
  * must work anyway!*/
-static int stop_ptraced_child(int pid, int exitcode, int mustexit)
+static int stop_ptraced_child(int pid, void *stack, int exitcode, int mustpanic)
 {
 	int status, n, ret = 0;
 
 	if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
-		panic("stop_ptraced_child : ptrace failed, errno = %d", errno);
+		panic("check_ptrace : ptrace failed, errno = %d", errno);
 	CATCH_EINTR(n = waitpid(pid, &status, 0));
 	if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) {
 		int exit_with = WEXITSTATUS(status);
@@ -200,13 +205,15 @@
 		printk("check_ptrace : child exited with exitcode %d, while "
 		      "expecting %d; status 0x%x", exit_with,
 		      exitcode, status);
-		if (mustexit)
+		if (mustpanic)
 			panic("\n");
 		else
 			printk("\n");
 		ret = -1;
 	}
 
+	if(munmap(stack, PAGE_SIZE) < 0)
+		panic("check_ptrace : munmap failed, errno = %d", errno);
 	return ret;
 }
 
@@ -242,11 +249,12 @@
 
 static void __init check_sysemu(void)
 {
+	void *stack;
 	int pid, syscall, n, status, count=0;
 
 	printk("Checking syscall emulation patch for ptrace...");
 	sysemu_supported = 0;
-	pid = start_ptraced_child();
+	pid = start_ptraced_child(&stack);
 
 	if(ptrace(PTRACE_SYSEMU, pid, 0, 0) < 0)
 		goto fail;
@@ -264,7 +272,7 @@
 		panic("check_sysemu : failed to modify system "
 		      "call return, errno = %d", errno);
 
-	if (stop_ptraced_child(pid, 0, 0) < 0)
+	if (stop_ptraced_child(pid, stack, 0, 0) < 0)
 		goto fail_stopped;
 
 	sysemu_supported = 1;
@@ -272,7 +280,7 @@
 	set_using_sysemu(!force_sysemu_disabled);
 
 	printk("Checking advanced syscall emulation patch for ptrace...");
-	pid = start_ptraced_child();
+	pid = start_ptraced_child(&stack);
 	while(1){
 		count++;
 		if(ptrace(PTRACE_SYSEMU_SINGLESTEP, pid, 0, 0) < 0)
@@ -297,7 +305,7 @@
 			break;
 		}
 	}
-	if (stop_ptraced_child(pid, 0, 0) < 0)
+	if (stop_ptraced_child(pid, stack, 0, 0) < 0)
 		goto fail_stopped;
 
 	sysemu_supported = 2;
@@ -308,17 +316,18 @@
 	return;
 
 fail:
-	stop_ptraced_child(pid, 1, 0);
+	stop_ptraced_child(pid, stack, 1, 0);
 fail_stopped:
 	printk("missing\n");
 }
 
 void __init check_ptrace(void)
 {
+	void *stack;
 	int pid, syscall, n, status;
 
 	printk("Checking that ptrace can change system call numbers...");
-	pid = start_ptraced_child();
+	pid = start_ptraced_child(&stack);
 
 	if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
 		panic("check_ptrace: PTRACE_SETOPTIONS failed, errno = %d", errno);
@@ -345,7 +354,7 @@
 			break;
 		}
 	}
-	stop_ptraced_child(pid, 0, 1);
+	stop_ptraced_child(pid, stack, 0, 1);
 	printk("OK\n");
 	check_sysemu();
 }
@@ -380,10 +389,11 @@
 static inline void check_skas3_ptrace_support(void)
 {
 	struct ptrace_faultinfo fi;
+	void *stack;
 	int pid, n;
 
 	printf("Checking for the skas3 patch in the host...");
-	pid = start_ptraced_child();
+	pid = start_ptraced_child(&stack);
 
 	n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi);
 	if (n < 0) {
@@ -402,7 +412,7 @@
 	}
 
 	init_registers(pid);
-	stop_ptraced_child(pid, 1, 1);
+	stop_ptraced_child(pid, stack, 1, 1);
 }
 
 int can_do_skas(void)
diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c
index d4036ed..c23d8a0 100644
--- a/arch/um/kernel/process_kern.c
+++ b/arch/um/kernel/process_kern.c
@@ -412,7 +412,7 @@
 
 	if (ent == NULL)
 	{
-		printk("Failed to register /proc/sysemu\n");
+		printk(KERN_WARNING "Failed to register /proc/sysemu\n");
 		return(0);
 	}
 
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
index ba671da..6dd9e5b 100644
--- a/arch/um/kernel/skas/process.c
+++ b/arch/um/kernel/skas/process.c
@@ -64,7 +64,7 @@
                 (WSTOPSIG(status) == SIGVTALRM));
 
         if((n < 0) || !WIFSTOPPED(status) ||
-           (WSTOPSIG(status) != SIGUSR1 && WSTOPSIG(status != SIGTRAP))){
+           (WSTOPSIG(status) != SIGUSR1 && WSTOPSIG(status) != SIGTRAP)){
                 panic("%s : failed to wait for SIGUSR1/SIGTRAP, "
                       "pid = %d, n = %d, errno = %d, status = 0x%x\n",
                       fname, pid, n, errno, status);
diff --git a/arch/um/kernel/skas/trap_user.c b/arch/um/kernel/skas/trap_user.c
index 0dee1d9..9950a67 100644
--- a/arch/um/kernel/skas/trap_user.c
+++ b/arch/um/kernel/skas/trap_user.c
@@ -58,7 +58,6 @@
         int segv = ((sig == SIGFPE) || (sig == SIGSEGV) || (sig == SIGBUS) ||
                     (sig == SIGILL) || (sig == SIGTRAP));
 
-	regs->skas.is_user = 1;
 	if (segv)
 		get_skas_faultinfo(pid, &regs->skas.faultinfo);
 	info = &sig_info[sig];
diff --git a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c
index a8b4ef6..4e08f75 100644
--- a/arch/um/kernel/time_kern.c
+++ b/arch/um/kernel/time_kern.c
@@ -137,7 +137,10 @@
 void timer_handler(int sig, union uml_pt_regs *regs)
 {
 	local_irq_disable();
-	update_process_times(CHOOSE_MODE(user_context(UPT_SP(regs)), (regs)->skas.is_user));
+	irq_enter();
+	update_process_times(CHOOSE_MODE(user_context(UPT_SP(regs)),
+					 (regs)->skas.is_user));
+	irq_exit();
 	local_irq_enable();
 	if(current_thread->cpu == 0)
 		timer_irq(regs);
diff --git a/arch/um/os-Linux/elf_aux.c b/arch/um/os-Linux/elf_aux.c
index 5423b1c..9416e1c 100644
--- a/arch/um/os-Linux/elf_aux.c
+++ b/arch/um/os-Linux/elf_aux.c
@@ -9,9 +9,10 @@
  */
 #include <elf.h>
 #include <stddef.h>
+#include <asm/elf.h>
 #include "init.h"
 #include "elf_user.h"
-#include <asm/elf.h>
+#include "mem_user.h"
 
 #if ELF_CLASS == ELFCLASS32
 typedef Elf32_auxv_t elf_auxv_t;
@@ -41,6 +42,9 @@
 				break;
 			case AT_SYSINFO_EHDR:
 				vsyscall_ehdr = auxv->a_un.a_val;
+				/* See if the page is under TASK_SIZE */
+				if (vsyscall_ehdr < (unsigned long) envp)
+					vsyscall_ehdr = 0;
 				break;
 			case AT_HWCAP:
 				elf_aux_hwcap = auxv->a_un.a_val;
diff --git a/arch/um/os-Linux/user_syms.c b/arch/um/os-Linux/user_syms.c
index 75d7af9..56d3f87 100644
--- a/arch/um/os-Linux/user_syms.c
+++ b/arch/um/os-Linux/user_syms.c
@@ -83,6 +83,9 @@
 
 EXPORT_SYMBOL_PROTO(getuid);
 
+EXPORT_SYMBOL_PROTO(fsync);
+EXPORT_SYMBOL_PROTO(fdatasync);
+
 /*
  * 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 --git a/arch/um/sys-i386/stub_segv.c b/arch/um/sys-i386/stub_segv.c
index b251442..68aeabe 100644
--- a/arch/um/sys-i386/stub_segv.c
+++ b/arch/um/sys-i386/stub_segv.c
@@ -21,10 +21,10 @@
 	__asm__("movl %0, %%eax ; int $0x80": : "g" (__NR_getpid));
 	__asm__("movl %%eax, %%ebx ; movl %0, %%eax ; movl %1, %%ecx ;"
 		"int $0x80": : "g" (__NR_kill), "g" (SIGUSR1));
-	/* Pop the frame pointer and return address since we need to leave
+	/* Load pointer to sigcontext into esp, since we need to leave
 	 * the stack in its original form when we do the sigreturn here, by
 	 * hand.
 	 */
-	__asm__("popl %%eax ; popl %%eax ; popl %%eax ; movl %0, %%eax ; "
-		"int $0x80" : : "g" (__NR_sigreturn));
+	__asm__("mov %0,%%esp ; movl %1, %%eax ; "
+		"int $0x80" : : "a" (sc), "g" (__NR_sigreturn));
 }
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
index 4b83261..660a03a 100644
--- a/arch/x86_64/Kconfig
+++ b/arch/x86_64/Kconfig
@@ -329,12 +329,15 @@
 
 config GART_IOMMU
 	bool "IOMMU support"
+	default y
 	depends on PCI
 	help
-	  Support the K8 IOMMU. Needed to run systems with more than 4GB of memory
+	  Support the IOMMU. Needed to run systems with more than 3GB of memory
 	  properly with 32-bit PCI devices that do not support DAC (Double Address
 	  Cycle). The IOMMU can be turned off at runtime with the iommu=off parameter.
 	  Normally the kernel will take the right choice by itself.
+	  This option includes a driver for the AMD Opteron/Athlon64 IOMMU
+	  and a software emulation used on some other systems.
 	  If unsure, say Y.
 
 # need this always enabled with GART_IOMMU for the VIA workaround
diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile
index 4289156..4c6ed96 100644
--- a/arch/x86_64/Makefile
+++ b/arch/x86_64/Makefile
@@ -21,18 +21,6 @@
 #
 # $Id: Makefile,v 1.31 2002/03/22 15:56:07 ak Exp $
 
-#
-# early bootup linking needs 32bit. You can either use real 32bit tools
-# here or 64bit tools in 32bit mode.
-#
-IA32_CC := $(CC) $(CPPFLAGS) -m32 -O2 -fomit-frame-pointer
-IA32_LD := $(LD) -m elf_i386
-IA32_AS := $(CC) $(AFLAGS) -m32 -Wa,--32 -traditional -c
-IA32_OBJCOPY := $(CROSS_COMPILE)objcopy
-IA32_CPP := $(CROSS_COMPILE)gcc -m32 -E
-export IA32_CC IA32_LD IA32_AS IA32_OBJCOPY IA32_CPP
-
-
 LDFLAGS		:= -m elf_x86_64
 OBJCOPYFLAGS	:= -O binary -R .note -R .comment -S
 LDFLAGS_vmlinux :=
diff --git a/arch/x86_64/defconfig b/arch/x86_64/defconfig
index 569595b..776f3c8 100644
--- a/arch/x86_64/defconfig
+++ b/arch/x86_64/defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc4
-# Fri May 13 06:39:11 2005
+# Linux kernel version: 2.6.13-rc3
+# Fri Jul 22 16:47:31 2005
 #
 CONFIG_X86_64=y
 CONFIG_64BIT=y
@@ -84,14 +84,27 @@
 CONFIG_X86_LOCAL_APIC=y
 CONFIG_MTRR=y
 CONFIG_SMP=y
-# CONFIG_PREEMPT is not set
 CONFIG_SCHED_SMT=y
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_PREEMPT_BKL=y
 CONFIG_K8_NUMA=y
 # CONFIG_NUMA_EMU is not set
-CONFIG_DISCONTIGMEM=y
+CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
 CONFIG_NUMA=y
+CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_SELECT_MEMORY_MODEL=y
+# CONFIG_FLATMEM_MANUAL is not set
+CONFIG_DISCONTIGMEM_MANUAL=y
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_DISCONTIGMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_NEED_MULTIPLE_NODES=y
+CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y
 CONFIG_HAVE_DEC_LOCK=y
-CONFIG_NR_CPUS=8
+CONFIG_NR_CPUS=32
 CONFIG_HPET_TIMER=y
 CONFIG_X86_PM_TIMER=y
 CONFIG_HPET_EMULATE_RTC=y
@@ -99,7 +112,13 @@
 CONFIG_SWIOTLB=y
 CONFIG_X86_MCE=y
 CONFIG_X86_MCE_INTEL=y
+CONFIG_PHYSICAL_START=0x100000
+# CONFIG_KEXEC is not set
 CONFIG_SECCOMP=y
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_ISA_DMA_API=y
@@ -118,12 +137,11 @@
 CONFIG_ACPI=y
 CONFIG_ACPI_BOOT=y
 CONFIG_ACPI_INTERPRETER=y
-CONFIG_ACPI_SLEEP=y
-CONFIG_ACPI_SLEEP_PROC_FS=y
 CONFIG_ACPI_AC=y
 CONFIG_ACPI_BATTERY=y
 CONFIG_ACPI_BUTTON=y
 # CONFIG_ACPI_VIDEO is not set
+CONFIG_ACPI_HOTKEY=m
 CONFIG_ACPI_FAN=y
 CONFIG_ACPI_PROCESSOR=y
 CONFIG_ACPI_THERMAL=y
@@ -154,6 +172,7 @@
 # CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
 CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
 
 #
 # CPUFreq processor drivers
@@ -204,6 +223,76 @@
 CONFIG_UID16=y
 
 #
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+CONFIG_IP_TCPDIAG_IPV6=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+CONFIG_IPV6=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+
+#
 # Device Drivers
 #
 
@@ -308,6 +397,7 @@
 # CONFIG_BLK_DEV_HPT366 is not set
 # CONFIG_BLK_DEV_SC1200 is not set
 CONFIG_BLK_DEV_PIIX=y
+# CONFIG_BLK_DEV_IT821X is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_PDC202XX_OLD is not set
 CONFIG_BLK_DEV_PDC202XX_NEW=y
@@ -338,6 +428,7 @@
 # CONFIG_CHR_DEV_OSST is not set
 # CONFIG_BLK_DEV_SR is not set
 # CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
 
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
@@ -372,7 +463,6 @@
 # CONFIG_MEGARAID_NEWGEN is not set
 # CONFIG_MEGARAID_LEGACY is not set
 CONFIG_SCSI_SATA=y
-# CONFIG_SCSI_SATA_AHCI is not set
 # CONFIG_SCSI_SATA_SVW is not set
 CONFIG_SCSI_ATA_PIIX=y
 # CONFIG_SCSI_SATA_NV is not set
@@ -410,14 +500,21 @@
 #
 # Multi-device support (RAID and LVM)
 #
-# CONFIG_MD is not set
+CONFIG_MD=y
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_DM=y
+# CONFIG_DM_CRYPT is not set
+# CONFIG_DM_SNAPSHOT is not set
+# CONFIG_DM_MIRROR is not set
+# CONFIG_DM_ZERO is not set
+# CONFIG_DM_MULTIPATH is not set
 
 #
 # Fusion MPT device support
 #
-CONFIG_FUSION=y
-CONFIG_FUSION_MAX_SGE=40
-# CONFIG_FUSION_CTL is not set
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
 
 #
 # IEEE 1394 (FireWire) support
@@ -430,75 +527,8 @@
 # CONFIG_I2O is not set
 
 #
-# Networking support
+# Network device support
 #
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-CONFIG_IP_TCPDIAG_IPV6=y
-CONFIG_IPV6=y
-# CONFIG_IPV6_PRIVACY is not set
-# CONFIG_INET6_AH is not set
-# CONFIG_INET6_ESP is not set
-# CONFIG_INET6_IPCOMP is not set
-# CONFIG_INET6_TUNNEL is not set
-# CONFIG_IPV6_TUNNEL is not set
-# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-CONFIG_NETPOLL=y
-# CONFIG_NETPOLL_RX is not set
-# CONFIG_NETPOLL_TRAP is not set
-CONFIG_NET_POLL_CONTROLLER=y
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
 CONFIG_NETDEVICES=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
@@ -517,7 +547,9 @@
 CONFIG_MII=y
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_VORTEX=y
+# CONFIG_TYPHOON is not set
 
 #
 # Tulip family network device support
@@ -532,7 +564,7 @@
 CONFIG_FORCEDETH=y
 # CONFIG_DGRS is not set
 # CONFIG_EEPRO100 is not set
-# CONFIG_E100 is not set
+CONFIG_E100=y
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
 # CONFIG_NE2K_PCI is not set
@@ -553,14 +585,15 @@
 # CONFIG_ACENIC is not set
 # CONFIG_DL2K is not set
 CONFIG_E1000=y
-# CONFIG_E1000_NAPI is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
+# CONFIG_SKGE is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 CONFIG_TIGON3=y
+# CONFIG_BNX2 is not set
 
 #
 # Ethernet (10000 Mbit)
@@ -647,7 +680,6 @@
 CONFIG_SERIO_LIBPS2=y
 # CONFIG_SERIO_RAW is not set
 # CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
 
 #
 # Character devices
@@ -716,6 +748,7 @@
 # I2C support
 #
 # CONFIG_I2C is not set
+# CONFIG_I2C_SENSOR is not set
 
 #
 # Dallas's 1-wire bus
@@ -723,6 +756,12 @@
 # CONFIG_W1 is not set
 
 #
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
 # Misc devices
 #
 # CONFIG_IBM_ASM is not set
@@ -808,6 +847,7 @@
 CONFIG_USB_EHCI_HCD=y
 # CONFIG_USB_EHCI_SPLIT_ISO is not set
 # CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_ISP116X_HCD is not set
 CONFIG_USB_OHCI_HCD=y
 # CONFIG_USB_OHCI_BIG_ENDIAN is not set
 CONFIG_USB_OHCI_LITTLE_ENDIAN=y
@@ -846,12 +886,15 @@
 # CONFIG_USB_HIDDEV is not set
 # CONFIG_USB_AIPTEK is not set
 # CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
 # CONFIG_USB_KBTAB is not set
 # CONFIG_USB_POWERMATE is not set
 # CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_ITMTOUCH is not set
 # CONFIG_USB_EGALAX is not set
 # CONFIG_USB_XPAD is not set
 # CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
 
 #
 # USB Imaging devices
@@ -902,10 +945,11 @@
 # CONFIG_USB_PHIDGETSERVO is not set
 # CONFIG_USB_IDMOUSE is not set
 # CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
 # CONFIG_USB_TEST is not set
 
 #
-# USB ATM/DSL drivers
+# USB DSL modem support
 #
 
 #
@@ -924,6 +968,10 @@
 # CONFIG_INFINIBAND is not set
 
 #
+# SN Devices
+#
+
+#
 # Firmware Drivers
 #
 # CONFIG_EDD is not set
@@ -935,6 +983,7 @@
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT2_FS_POSIX_ACL=y
 # CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
 CONFIG_EXT3_FS_XATTR=y
 CONFIG_EXT3_FS_POSIX_ACL=y
@@ -957,6 +1006,7 @@
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
 # CONFIG_QUOTA is not set
 CONFIG_DNOTIFY=y
 CONFIG_AUTOFS_FS=y
@@ -986,7 +1036,6 @@
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
 CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
 # CONFIG_TMPFS_XATTR is not set
@@ -1016,15 +1065,18 @@
 #
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
 # CONFIG_NFS_V4 is not set
 # CONFIG_NFS_DIRECTIO is not set
 CONFIG_NFSD=y
 CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
 # CONFIG_NFSD_V4 is not set
 CONFIG_NFSD_TCP=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
 CONFIG_EXPORTFS=y
+CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
diff --git a/arch/x86_64/ia32/Makefile b/arch/x86_64/ia32/Makefile
index a12b19d..f76217d 100644
--- a/arch/x86_64/ia32/Makefile
+++ b/arch/x86_64/ia32/Makefile
@@ -4,14 +4,14 @@
 
 obj-$(CONFIG_IA32_EMULATION) := ia32entry.o sys_ia32.o ia32_ioctl.o \
 	ia32_signal.o tls32.o \
-	ia32_binfmt.o fpu32.o ptrace32.o syscall32.o
+	ia32_binfmt.o fpu32.o ptrace32.o syscall32.o syscall32_syscall.o
 
 sysv-$(CONFIG_SYSVIPC) := ipc32.o
 obj-$(CONFIG_IA32_EMULATION) += $(sysv-y)
 
 obj-$(CONFIG_IA32_AOUT) += ia32_aout.o
 
-$(obj)/syscall32.o: $(src)/syscall32.c \
+$(obj)/syscall32_syscall.o: \
 	$(foreach F,sysenter syscall,$(obj)/vsyscall-$F.so)
 
 # Teach kbuild about targets
diff --git a/arch/x86_64/ia32/syscall32.c b/arch/x86_64/ia32/syscall32.c
index 816a3b8..adbc5f8 100644
--- a/arch/x86_64/ia32/syscall32.c
+++ b/arch/x86_64/ia32/syscall32.c
@@ -14,16 +14,6 @@
 #include <asm/tlbflush.h>
 #include <asm/ia32_unistd.h>
 
-/* 32bit VDSOs mapped into user space. */ 
-asm(".section \".init.data\",\"aw\"\n"
-    "syscall32_syscall:\n"
-    ".incbin \"arch/x86_64/ia32/vsyscall-syscall.so\"\n"
-    "syscall32_syscall_end:\n"
-    "syscall32_sysenter:\n"
-    ".incbin \"arch/x86_64/ia32/vsyscall-sysenter.so\"\n"
-    "syscall32_sysenter_end:\n"
-    ".previous");
-
 extern unsigned char syscall32_syscall[], syscall32_syscall_end[];
 extern unsigned char syscall32_sysenter[], syscall32_sysenter_end[];
 extern int sysctl_vsyscall32;
diff --git a/arch/x86_64/ia32/syscall32_syscall.S b/arch/x86_64/ia32/syscall32_syscall.S
new file mode 100644
index 0000000..8f8271b
--- /dev/null
+++ b/arch/x86_64/ia32/syscall32_syscall.S
@@ -0,0 +1,17 @@
+/* 32bit VDSOs mapped into user space. */
+
+	.section ".init.data","aw"
+
+	.globl syscall32_syscall
+	.globl syscall32_syscall_end
+
+syscall32_syscall:
+	.incbin "arch/x86_64/ia32/vsyscall-syscall.so"
+syscall32_syscall_end:
+
+	.globl syscall32_sysenter
+	.globl syscall32_sysenter_end
+
+syscall32_sysenter:
+	.incbin "arch/x86_64/ia32/vsyscall-sysenter.so"
+syscall32_sysenter_end:
diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S
index 2881749..096d470 100644
--- a/arch/x86_64/kernel/entry.S
+++ b/arch/x86_64/kernel/entry.S
@@ -76,7 +76,7 @@
 
 	.macro FAKE_STACK_FRAME child_rip
 	/* push in order ss, rsp, eflags, cs, rip */
-	xorq %rax, %rax
+	xorl %eax, %eax
 	pushq %rax /* ss */
 	CFI_ADJUST_CFA_OFFSET	8
 	pushq %rax /* rsp */
@@ -423,7 +423,7 @@
 	testl $3,CS(%rdi)
 	je 1f
 	swapgs	
-1:	addl $1,%gs:pda_irqcount	# RED-PEN should check preempt count
+1:	incl	%gs:pda_irqcount	# RED-PEN should check preempt count
 	movq %gs:pda_irqstackptr,%rax
 	cmoveq %rax,%rsp							
 	pushq %rdi			# save old stack	
@@ -436,7 +436,7 @@
 ret_from_intr:		
 	popq  %rdi
 	cli	
-	subl $1,%gs:pda_irqcount
+	decl %gs:pda_irqcount
 #ifdef CONFIG_DEBUG_INFO
 	movq RBP(%rdi),%rbp
 #endif
@@ -494,7 +494,7 @@
 	sti
 	SAVE_REST
 	movq $-1,ORIG_RAX(%rsp) 			
-	xorq %rsi,%rsi		# oldset
+	xorl %esi,%esi		# oldset
 	movq %rsp,%rdi		# &pt_regs
 	call do_notify_resume
 	RESTORE_REST
@@ -752,7 +752,7 @@
 	movq %rsi, %rdi
 	call *%rax
 	# exit
-	xorq %rdi, %rdi
+	xorl %edi, %edi
 	call do_exit
 
 /*
@@ -918,3 +918,15 @@
 ENTRY(call_debug)
        zeroentry do_call_debug
 
+ENTRY(call_softirq)
+	movq %gs:pda_irqstackptr,%rax
+	pushq %r15
+	movq %rsp,%r15
+	incl %gs:pda_irqcount
+	cmove %rax,%rsp
+	call __do_softirq
+	movq %r15,%rsp
+	decl %gs:pda_irqcount
+	popq %r15
+	ret
+
diff --git a/arch/x86_64/kernel/genapic.c b/arch/x86_64/kernel/genapic.c
index 69b9c25..30c843a 100644
--- a/arch/x86_64/kernel/genapic.c
+++ b/arch/x86_64/kernel/genapic.c
@@ -31,6 +31,7 @@
 
 extern struct genapic apic_cluster;
 extern struct genapic apic_flat;
+extern struct genapic apic_physflat;
 
 struct genapic *genapic = &apic_flat;
 
@@ -44,12 +45,7 @@
 	u8 clusters, max_cluster;
 	u8 id;
 	u8 cluster_cnt[NUM_APIC_CLUSTERS];
-
-	if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
-		/* AMD always uses flat mode right now */
-		genapic = &apic_flat;
-		goto print;
-	}
+	int num_cpus = 0;
 
 #if defined(CONFIG_ACPI_BUS)
 	/*
@@ -64,15 +60,34 @@
 #endif
 
 	memset(cluster_cnt, 0, sizeof(cluster_cnt));
-
 	for (i = 0; i < NR_CPUS; i++) {
 		id = bios_cpu_apicid[i];
-		if (id != BAD_APICID)
-			cluster_cnt[APIC_CLUSTERID(id)]++;
+		if (id == BAD_APICID)
+			continue;
+		num_cpus++;
+		cluster_cnt[APIC_CLUSTERID(id)]++;
 	}
 
+	/* Don't use clustered mode on AMD platforms. */
+ 	if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
+		genapic = &apic_physflat;
+#ifndef CONFIG_CPU_HOTPLUG
+		/* In the CPU hotplug case we cannot use broadcast mode
+		   because that opens a race when a CPU is removed.
+		   Stay at physflat mode in this case.
+		   It is bad to do this unconditionally though. Once
+		   we have ACPI platform support for CPU hotplug
+		   we should detect hotplug capablity from ACPI tables and
+		   only do this when really needed. -AK */
+		if (num_cpus <= 8)
+			genapic = &apic_flat;
+#endif
+ 		goto print;
+ 	}
+
 	clusters = 0;
 	max_cluster = 0;
+
 	for (i = 0; i < NUM_APIC_CLUSTERS; i++) {
 		if (cluster_cnt[i] > 0) {
 			++clusters;
diff --git a/arch/x86_64/kernel/genapic_flat.c b/arch/x86_64/kernel/genapic_flat.c
index 2828469..adc9628 100644
--- a/arch/x86_64/kernel/genapic_flat.c
+++ b/arch/x86_64/kernel/genapic_flat.c
@@ -2,13 +2,11 @@
  * Copyright 2004 James Cleverdon, IBM.
  * Subject to the GNU Public License, v.2
  *
- * Flat APIC subarch code.  Maximum 8 CPUs, logical delivery.
+ * Flat APIC subarch code.
  *
  * Hacked for x86-64 by James Cleverdon from i386 architecture code by
  * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and
  * James Cleverdon.
- * Ashok Raj <ashok.raj@intel.com>
- * 	Removed IPI broadcast shortcut to support CPU hotplug
  */
 #include <linux/config.h>
 #include <linux/threads.h>
@@ -20,47 +18,6 @@
 #include <asm/smp.h>
 #include <asm/ipi.h>
 
-/*
- * The following permit choosing broadcast IPI shortcut v.s sending IPI only
- * to online cpus via the send_IPI_mask varient.
- * The mask version is my preferred option, since it eliminates a lot of
- * other extra code that would need to be written to cleanup intrs sent
- * to a CPU while offline.
- *
- * Sending broadcast introduces lots of trouble in CPU hotplug situations.
- * These IPI's are delivered to cpu's irrespective of their offline status
- * and could pickup stale intr data when these CPUS are turned online.
- *
- * Not using broadcast is a cleaner approach IMO, but Andi Kleen disagrees with
- * the idea of not using broadcast IPI's anymore. Hence the run time check
- * is introduced, on his request so we can choose an alternate mechanism.
- *
- * Initial wacky performance tests that collect cycle counts show
- * no increase in using mask v.s broadcast version. In fact they seem
- * identical in terms of cycle counts.
- *
- * if we need to use broadcast, we need to do the following.
- *
- * cli;
- * hold call_lock;
- * clear any pending IPI, just ack and clear all pending intr
- * set cpu_online_map;
- * release call_lock;
- * sti;
- *
- * The complicated dummy irq processing shown above is not required if
- * we didnt sent IPI's to wrong CPU's in the first place.
- *
- * - Ashok Raj <ashok.raj@intel.com>
- */
-#ifdef CONFIG_HOTPLUG_CPU
-#define DEFAULT_SEND_IPI	(1)
-#else
-#define DEFAULT_SEND_IPI	(0)
-#endif
-
-static int no_broadcast=DEFAULT_SEND_IPI;
-
 static cpumask_t flat_target_cpus(void)
 {
 	return cpu_online_map;
@@ -119,37 +76,15 @@
 	local_irq_restore(flags);
 }
 
-static inline void __local_flat_send_IPI_allbutself(int vector)
-{
-	if (no_broadcast) {
-		cpumask_t mask = cpu_online_map;
-		int this_cpu = get_cpu();
-
-		cpu_clear(this_cpu, mask);
-		flat_send_IPI_mask(mask, vector);
-		put_cpu();
-	}
-	else
-		__send_IPI_shortcut(APIC_DEST_ALLBUT, vector, APIC_DEST_LOGICAL);
-}
-
-static inline void __local_flat_send_IPI_all(int vector)
-{
-	if (no_broadcast)
-		flat_send_IPI_mask(cpu_online_map, vector);
-	else
-		__send_IPI_shortcut(APIC_DEST_ALLINC, vector, APIC_DEST_LOGICAL);
-}
-
 static void flat_send_IPI_allbutself(int vector)
 {
 	if (((num_online_cpus()) - 1) >= 1)
-		__local_flat_send_IPI_allbutself(vector);
+		__send_IPI_shortcut(APIC_DEST_ALLBUT, vector,APIC_DEST_LOGICAL);
 }
 
 static void flat_send_IPI_all(int vector)
 {
-	__local_flat_send_IPI_all(vector);
+	__send_IPI_shortcut(APIC_DEST_ALLINC, vector, APIC_DEST_LOGICAL);
 }
 
 static int flat_apic_id_registered(void)
@@ -170,16 +105,6 @@
 	return ((ebx >> 24) & 0xFF) >> index_msb;
 }
 
-static __init int no_ipi_broadcast(char *str)
-{
-	get_option(&str, &no_broadcast);
-	printk ("Using %s mode\n", no_broadcast ? "No IPI Broadcast" :
-											"IPI Broadcast");
-	return 1;
-}
-
-__setup("no_ipi_broadcast", no_ipi_broadcast);
-
 struct genapic apic_flat =  {
 	.name = "flat",
 	.int_delivery_mode = dest_LowestPrio,
@@ -195,11 +120,62 @@
 	.phys_pkg_id = phys_pkg_id,
 };
 
-static int __init print_ipi_mode(void)
+/*
+ * Physflat mode is used when there are more than 8 CPUs on a AMD system.
+ * We cannot use logical delivery in this case because the mask
+ * overflows, so use physical mode.
+ */
+
+static cpumask_t physflat_target_cpus(void)
 {
-	printk ("Using IPI %s mode\n", no_broadcast ? "No-Shortcut" :
-											"Shortcut");
-	return 0;
+	return cpumask_of_cpu(0);
 }
 
-late_initcall(print_ipi_mode);
+static void physflat_send_IPI_mask(cpumask_t cpumask, int vector)
+{
+	send_IPI_mask_sequence(cpumask, vector);
+}
+
+static void physflat_send_IPI_allbutself(int vector)
+{
+	cpumask_t allbutme = cpu_online_map;
+	int me = get_cpu();
+	cpu_clear(me, allbutme);
+	physflat_send_IPI_mask(allbutme, vector);
+	put_cpu();
+}
+
+static void physflat_send_IPI_all(int vector)
+{
+	physflat_send_IPI_mask(cpu_online_map, vector);
+}
+
+static unsigned int physflat_cpu_mask_to_apicid(cpumask_t cpumask)
+{
+	int cpu;
+
+	/*
+	 * We're using fixed IRQ delivery, can only return one phys APIC ID.
+	 * May as well be the first.
+	 */
+	cpu = first_cpu(cpumask);
+	if ((unsigned)cpu < NR_CPUS)
+		return x86_cpu_to_apicid[cpu];
+	else
+		return BAD_APICID;
+}
+
+struct genapic apic_physflat =  {
+	.name = "physical flat",
+	.int_delivery_mode = dest_LowestPrio,
+	.int_dest_mode = (APIC_DEST_PHYSICAL != 0),
+	.int_delivery_dest = APIC_DEST_PHYSICAL | APIC_DM_LOWEST,
+	.target_cpus = physflat_target_cpus,
+	.apic_id_registered = flat_apic_id_registered,
+	.init_apic_ldr = flat_init_apic_ldr,/*not needed, but shouldn't hurt*/
+	.send_IPI_all = physflat_send_IPI_all,
+	.send_IPI_allbutself = physflat_send_IPI_allbutself,
+	.send_IPI_mask = physflat_send_IPI_mask,
+	.cpu_mask_to_apicid = physflat_cpu_mask_to_apicid,
+	.phys_pkg_id = phys_pkg_id,
+};
diff --git a/arch/x86_64/kernel/head.S b/arch/x86_64/kernel/head.S
index 8d765aa..98ff5eb 100644
--- a/arch/x86_64/kernel/head.S
+++ b/arch/x86_64/kernel/head.S
@@ -137,14 +137,14 @@
 	wrmsr
 
 	/* Setup cr0 */
-	xorq	%rax, %rax
-	btsq	$31, %rax			/* Enable paging */
-	btsq	$0, %rax			/* Enable protected mode */
-	btsq	$1, %rax			/* Enable MP */
-	btsq	$4, %rax			/* Enable ET */
-	btsq	$5, %rax			/* Enable NE */
-	btsq	$16, %rax			/* Enable WP */
-	btsq	$18, %rax			/* Enable AM */
+#define CR0_PM				1		/* protected mode */
+#define CR0_MP				(1<<1)
+#define CR0_ET				(1<<4)
+#define CR0_NE				(1<<5)
+#define CR0_WP				(1<<16)
+#define CR0_AM				(1<<18)
+#define CR0_PAGING 			(1<<31)
+	movl $CR0_PM|CR0_MP|CR0_ET|CR0_NE|CR0_WP|CR0_AM|CR0_PAGING,%eax
 	/* Make changes effective */
 	movq	%rax, %cr0
 
diff --git a/arch/x86_64/kernel/irq.c b/arch/x86_64/kernel/irq.c
index cc3fb85..849a20a 100644
--- a/arch/x86_64/kernel/irq.c
+++ b/arch/x86_64/kernel/irq.c
@@ -135,3 +135,22 @@
 	local_irq_disable();
 }
 #endif
+
+extern void call_softirq(void);
+
+asmlinkage void do_softirq(void)
+{
+ 	__u32 pending;
+ 	unsigned long flags;
+
+ 	if (in_interrupt())
+ 		return;
+
+ 	local_irq_save(flags);
+ 	pending = local_softirq_pending();
+ 	/* Switch to interrupt stack */
+ 	if (pending)
+		call_softirq();
+ 	local_irq_restore(flags);
+}
+EXPORT_SYMBOL(do_softirq);
diff --git a/arch/x86_64/kernel/machine_kexec.c b/arch/x86_64/kernel/machine_kexec.c
index 60d1eff..89fab51 100644
--- a/arch/x86_64/kernel/machine_kexec.c
+++ b/arch/x86_64/kernel/machine_kexec.c
@@ -8,43 +8,26 @@
 
 #include <linux/mm.h>
 #include <linux/kexec.h>
-#include <linux/delay.h>
 #include <linux/string.h>
 #include <linux/reboot.h>
-#include <asm/pda.h>
 #include <asm/pgtable.h>
-#include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 #include <asm/mmu_context.h>
 #include <asm/io.h>
-#include <asm/apic.h>
-#include <asm/cpufeature.h>
-#include <asm/hw_irq.h>
 
-#define LEVEL0_SIZE (1UL << 12UL)
-#define LEVEL1_SIZE (1UL << 21UL)
-#define LEVEL2_SIZE (1UL << 30UL)
-#define LEVEL3_SIZE (1UL << 39UL)
-#define LEVEL4_SIZE (1UL << 48UL)
-
-#define L0_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
-#define L1_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_PSE)
-#define L2_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
-#define L3_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
-
-static void init_level2_page(u64 *level2p, unsigned long addr)
+static void init_level2_page(pmd_t *level2p, unsigned long addr)
 {
 	unsigned long end_addr;
 
 	addr &= PAGE_MASK;
-	end_addr = addr + LEVEL2_SIZE;
+	end_addr = addr + PUD_SIZE;
 	while (addr < end_addr) {
-		*(level2p++) = addr | L1_ATTR;
-		addr += LEVEL1_SIZE;
+		set_pmd(level2p++, __pmd(addr | __PAGE_KERNEL_LARGE_EXEC));
+		addr += PMD_SIZE;
 	}
 }
 
-static int init_level3_page(struct kimage *image, u64 *level3p,
+static int init_level3_page(struct kimage *image, pud_t *level3p,
 				unsigned long addr, unsigned long last_addr)
 {
 	unsigned long end_addr;
@@ -52,32 +35,32 @@
 
 	result = 0;
 	addr &= PAGE_MASK;
-	end_addr = addr + LEVEL3_SIZE;
+	end_addr = addr + PGDIR_SIZE;
 	while ((addr < last_addr) && (addr < end_addr)) {
 		struct page *page;
-		u64 *level2p;
+		pmd_t *level2p;
 
 		page = kimage_alloc_control_pages(image, 0);
 		if (!page) {
 			result = -ENOMEM;
 			goto out;
 		}
-		level2p = (u64 *)page_address(page);
+		level2p = (pmd_t *)page_address(page);
 		init_level2_page(level2p, addr);
-		*(level3p++) = __pa(level2p) | L2_ATTR;
-		addr += LEVEL2_SIZE;
+		set_pud(level3p++, __pud(__pa(level2p) | _KERNPG_TABLE));
+		addr += PUD_SIZE;
 	}
 	/* clear the unused entries */
 	while (addr < end_addr) {
-		*(level3p++) = 0;
-		addr += LEVEL2_SIZE;
+		pud_clear(level3p++);
+		addr += PUD_SIZE;
 	}
 out:
 	return result;
 }
 
 
-static int init_level4_page(struct kimage *image, u64 *level4p,
+static int init_level4_page(struct kimage *image, pgd_t *level4p,
 				unsigned long addr, unsigned long last_addr)
 {
 	unsigned long end_addr;
@@ -85,28 +68,28 @@
 
 	result = 0;
 	addr &= PAGE_MASK;
-	end_addr = addr + LEVEL4_SIZE;
+	end_addr = addr + (PTRS_PER_PGD * PGDIR_SIZE);
 	while ((addr < last_addr) && (addr < end_addr)) {
 		struct page *page;
-		u64 *level3p;
+		pud_t *level3p;
 
 		page = kimage_alloc_control_pages(image, 0);
 		if (!page) {
 			result = -ENOMEM;
 			goto out;
 		}
-		level3p = (u64 *)page_address(page);
+		level3p = (pud_t *)page_address(page);
 		result = init_level3_page(image, level3p, addr, last_addr);
 		if (result) {
 			goto out;
 		}
-		*(level4p++) = __pa(level3p) | L3_ATTR;
-		addr += LEVEL3_SIZE;
+		set_pgd(level4p++, __pgd(__pa(level3p) | _KERNPG_TABLE));
+		addr += PGDIR_SIZE;
 	}
 	/* clear the unused entries */
 	while (addr < end_addr) {
-		*(level4p++) = 0;
-		addr += LEVEL3_SIZE;
+		pgd_clear(level4p++);
+		addr += PGDIR_SIZE;
 	}
 out:
 	return result;
@@ -115,52 +98,50 @@
 
 static int init_pgtable(struct kimage *image, unsigned long start_pgtable)
 {
-	u64 *level4p;
-	level4p = (u64 *)__va(start_pgtable);
+	pgd_t *level4p;
+	level4p = (pgd_t *)__va(start_pgtable);
  	return init_level4_page(image, level4p, 0, end_pfn << PAGE_SHIFT);
 }
 
 static void set_idt(void *newidt, u16 limit)
 {
-	unsigned char curidt[10];
+	struct desc_ptr curidt;
 
 	/* x86-64 supports unaliged loads & stores */
-	(*(u16 *)(curidt)) = limit;
-	(*(u64 *)(curidt +2)) = (unsigned long)(newidt);
+	curidt.size    = limit;
+	curidt.address = (unsigned long)newidt;
 
 	__asm__ __volatile__ (
-		"lidt %0\n"
-		: "=m" (curidt)
+		"lidtq %0\n"
+		: : "m" (curidt)
 		);
 };
 
 
 static void set_gdt(void *newgdt, u16 limit)
 {
-	unsigned char curgdt[10];
+	struct desc_ptr curgdt;
 
 	/* x86-64 supports unaligned loads & stores */
-	(*(u16 *)(curgdt)) = limit;
-	(*(u64 *)(curgdt +2)) = (unsigned long)(newgdt);
+	curgdt.size    = limit;
+	curgdt.address = (unsigned long)newgdt;
 
 	__asm__ __volatile__ (
-		"lgdt %0\n"
-		: "=m" (curgdt)
+		"lgdtq %0\n"
+		: : "m" (curgdt)
 		);
 };
 
 static void load_segments(void)
 {
 	__asm__ __volatile__ (
-		"\tmovl $"STR(__KERNEL_DS)",%eax\n"
-		"\tmovl %eax,%ds\n"
-		"\tmovl %eax,%es\n"
-		"\tmovl %eax,%ss\n"
-		"\tmovl %eax,%fs\n"
-		"\tmovl %eax,%gs\n"
+		"\tmovl %0,%%ds\n"
+		"\tmovl %0,%%es\n"
+		"\tmovl %0,%%ss\n"
+		"\tmovl %0,%%fs\n"
+		"\tmovl %0,%%gs\n"
+		: : "a" (__KERNEL_DS)
 		);
-#undef STR
-#undef __STR
 }
 
 typedef NORET_TYPE void (*relocate_new_kernel_t)(unsigned long indirection_page,
@@ -178,7 +159,7 @@
 
 	/* Calculate the offsets */
 	start_pgtable = page_to_pfn(image->control_code_page) << PAGE_SHIFT;
-	control_code_buffer = start_pgtable + 4096UL;
+	control_code_buffer = start_pgtable + PAGE_SIZE;
 
 	/* Setup the identity mapped 64bit page table */
 	result = init_pgtable(image, start_pgtable);
@@ -214,7 +195,7 @@
 	/* Calculate the offsets */
 	page_list = image->head;
 	start_pgtable = page_to_pfn(image->control_code_page) << PAGE_SHIFT;
-	control_code_buffer = start_pgtable + 4096UL;
+	control_code_buffer = start_pgtable + PAGE_SIZE;
 
 	/* Set the low half of the page table to my identity mapped
 	 * page table for kexec.  Leave the high half pointing at the
diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c
index 21e7062..3b267c9 100644
--- a/arch/x86_64/kernel/mce.c
+++ b/arch/x86_64/kernel/mce.c
@@ -15,6 +15,8 @@
 #include <linux/sysdev.h>
 #include <linux/miscdevice.h>
 #include <linux/fs.h>
+#include <linux/cpu.h>
+#include <linux/percpu.h>
 #include <asm/processor.h> 
 #include <asm/msr.h>
 #include <asm/mce.h>
@@ -514,10 +516,7 @@
 	set_kset_name("machinecheck"),
 };
 
-static struct sys_device device_mce = {
-	.id	= 0,
-	.cls	= &mce_sysclass,
-};
+static DEFINE_PER_CPU(struct sys_device, device_mce);
 
 /* Why are there no generic functions for this? */
 #define ACCESSOR(name, var, start) \
@@ -542,27 +541,83 @@
 ACCESSOR(tolerant,tolerant,)
 ACCESSOR(check_interval,check_interval,mce_restart())
 
-static __cpuinit int mce_init_device(void)
+/* Per cpu sysdev init.  All of the cpus still share the same ctl bank */
+static __cpuinit int mce_create_device(unsigned int cpu)
 {
 	int err;
+	if (!mce_available(&cpu_data[cpu]))
+		return -EIO;
+
+	per_cpu(device_mce,cpu).id = cpu;
+	per_cpu(device_mce,cpu).cls = &mce_sysclass;
+
+	err = sysdev_register(&per_cpu(device_mce,cpu));
+
+	if (!err) {
+		sysdev_create_file(&per_cpu(device_mce,cpu), &attr_bank0ctl);
+		sysdev_create_file(&per_cpu(device_mce,cpu), &attr_bank1ctl);
+		sysdev_create_file(&per_cpu(device_mce,cpu), &attr_bank2ctl);
+		sysdev_create_file(&per_cpu(device_mce,cpu), &attr_bank3ctl);
+		sysdev_create_file(&per_cpu(device_mce,cpu), &attr_bank4ctl);
+		sysdev_create_file(&per_cpu(device_mce,cpu), &attr_tolerant);
+		sysdev_create_file(&per_cpu(device_mce,cpu), &attr_check_interval);
+	}
+	return err;
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+static __cpuinit void mce_remove_device(unsigned int cpu)
+{
+	sysdev_remove_file(&per_cpu(device_mce,cpu), &attr_bank0ctl);
+	sysdev_remove_file(&per_cpu(device_mce,cpu), &attr_bank1ctl);
+	sysdev_remove_file(&per_cpu(device_mce,cpu), &attr_bank2ctl);
+	sysdev_remove_file(&per_cpu(device_mce,cpu), &attr_bank3ctl);
+	sysdev_remove_file(&per_cpu(device_mce,cpu), &attr_bank4ctl);
+	sysdev_remove_file(&per_cpu(device_mce,cpu), &attr_tolerant);
+	sysdev_remove_file(&per_cpu(device_mce,cpu), &attr_check_interval);
+	sysdev_unregister(&per_cpu(device_mce,cpu));
+}
+#endif
+
+/* Get notified when a cpu comes on/off. Be hotplug friendly. */
+static __cpuinit int
+mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
+{
+	unsigned int cpu = (unsigned long)hcpu;
+
+	switch (action) {
+	case CPU_ONLINE:
+		mce_create_device(cpu);
+		break;
+#ifdef CONFIG_HOTPLUG_CPU
+	case CPU_DEAD:
+		mce_remove_device(cpu);
+		break;
+#endif
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block mce_cpu_notifier = {
+	.notifier_call = mce_cpu_callback,
+};
+
+static __init int mce_init_device(void)
+{
+	int err;
+	int i = 0;
+
 	if (!mce_available(&boot_cpu_data))
 		return -EIO;
 	err = sysdev_class_register(&mce_sysclass);
-	if (!err)
-		err = sysdev_register(&device_mce);
-	if (!err) { 
-		/* could create per CPU objects, but it is not worth it. */
-		sysdev_create_file(&device_mce, &attr_bank0ctl); 
-		sysdev_create_file(&device_mce, &attr_bank1ctl); 
-		sysdev_create_file(&device_mce, &attr_bank2ctl); 
-		sysdev_create_file(&device_mce, &attr_bank3ctl); 
-		sysdev_create_file(&device_mce, &attr_bank4ctl); 
-		sysdev_create_file(&device_mce, &attr_tolerant); 
-		sysdev_create_file(&device_mce, &attr_check_interval);
-	} 
-	
+
+	for_each_online_cpu(i) {
+		mce_create_device(i);
+	}
+
+	register_cpu_notifier(&mce_cpu_notifier);
 	misc_register(&mce_log_device);
 	return err;
-
 }
+
 device_initcall(mce_init_device);
diff --git a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c
index 9c5aa2a..08abf9f 100644
--- a/arch/x86_64/kernel/mpparse.c
+++ b/arch/x86_64/kernel/mpparse.c
@@ -109,7 +109,7 @@
 
 static void __init MP_processor_info (struct mpc_config_processor *m)
 {
-	int ver;
+	int ver, cpu;
 	static int found_bsp=0;
 
 	if (!(m->mpc_cpuflag & CPU_ENABLED))
@@ -131,7 +131,7 @@
 		return;
 	}
 
-	num_processors++;
+	cpu = num_processors++;
 
 	if (m->mpc_apicid > MAX_APICS) {
 		printk(KERN_ERR "Processor #%d INVALID. (Max ID: %d).\n",
@@ -155,13 +155,18 @@
  		 * in same order as logical cpu numbers. Hence the first
  		 * entry is BSP, and so on.
  		 */
+		cpu = 0;
+
  		bios_cpu_apicid[0] = m->mpc_apicid;
  		x86_cpu_to_apicid[0] = m->mpc_apicid;
  		found_bsp = 1;
- 	} else {
- 		bios_cpu_apicid[num_processors - found_bsp] = m->mpc_apicid;
- 		x86_cpu_to_apicid[num_processors - found_bsp] = m->mpc_apicid;
- 	}
+ 	} else
+		cpu = num_processors - found_bsp;
+	bios_cpu_apicid[cpu] = m->mpc_apicid;
+	x86_cpu_to_apicid[cpu] = m->mpc_apicid;
+
+	cpu_set(cpu, cpu_possible_map);
+	cpu_set(cpu, cpu_present_map);
 }
 
 static void __init MP_bus_info (struct mpc_config_bus *m)
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
index 5fd0322..0aa5262 100644
--- a/arch/x86_64/kernel/setup.c
+++ b/arch/x86_64/kernel/setup.c
@@ -765,8 +765,6 @@
 	int cpu = smp_processor_id();
 	int node = 0;
 	unsigned bits;
-	if (c->x86_num_cores == 1)
-		return;
 
 	bits = 0;
 	while ((1 << bits) < c->x86_num_cores)
@@ -1081,8 +1079,7 @@
 	else
 		mtrr_ap_init();
 #ifdef CONFIG_NUMA
-	if (c != &boot_cpu_data)
-		numa_add_cpu(c - cpu_data);
+	numa_add_cpu(smp_processor_id());
 #endif
 }
  
diff --git a/arch/x86_64/kernel/setup64.c b/arch/x86_64/kernel/setup64.c
index f2b9c6b..34082c1 100644
--- a/arch/x86_64/kernel/setup64.c
+++ b/arch/x86_64/kernel/setup64.c
@@ -12,6 +12,7 @@
 #include <linux/string.h>
 #include <linux/bootmem.h>
 #include <linux/bitops.h>
+#include <linux/module.h>
 #include <asm/bootsetup.h>
 #include <asm/pda.h>
 #include <asm/pgtable.h>
@@ -22,10 +23,8 @@
 #include <asm/smp.h>
 #include <asm/i387.h>
 #include <asm/percpu.h>
-#include <asm/mtrr.h>
 #include <asm/proto.h>
-#include <asm/mman.h>
-#include <asm/numa.h>
+#include <asm/sections.h>
 
 char x86_boot_params[BOOT_PARAM_SIZE] __initdata = {0,};
 
@@ -33,11 +32,6 @@
 
 struct x8664_pda cpu_pda[NR_CPUS] __cacheline_aligned; 
 
-extern struct task_struct init_task;
-
-extern unsigned char __per_cpu_start[], __per_cpu_end[]; 
-
-extern struct desc_ptr cpu_gdt_descr[];
 struct desc_ptr idt_descr = { 256 * 16, (unsigned long) idt_table }; 
 
 char boot_cpu_stack[IRQSTACKSIZE] __attribute__((section(".bss.page_aligned")));
@@ -101,7 +95,7 @@
 #endif
 
 	for (i = 0; i < NR_CPUS; i++) { 
-		unsigned char *ptr;
+		char *ptr;
 
 		if (!NODE_DATA(cpu_to_node(i))) {
 			printk("cpu with no node %d, num_online_nodes %d\n",
@@ -190,11 +184,7 @@
  */
 void __cpuinit cpu_init (void)
 {
-#ifdef CONFIG_SMP
 	int cpu = stack_smp_processor_id();
-#else
-	int cpu = smp_processor_id();
-#endif
 	struct tss_struct *t = &per_cpu(init_tss, cpu);
 	unsigned long v; 
 	char *estacks = NULL; 
@@ -214,7 +204,7 @@
 
 	printk("Initializing CPU#%d\n", cpu);
 
-		clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
+	clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
 
 	/*
 	 * Initialize the per-CPU GDT with the boot GDT,
diff --git a/arch/x86_64/kernel/smp.c b/arch/x86_64/kernel/smp.c
index ccae392..e595822 100644
--- a/arch/x86_64/kernel/smp.c
+++ b/arch/x86_64/kernel/smp.c
@@ -129,10 +129,9 @@
 		} else
 			leave_mm(cpu);
 	}
+out:
 	ack_APIC_irq();
 	cpu_clear(cpu, flush_cpumask);
-
-out:
 	put_cpu_no_resched();
 }
 
@@ -294,6 +293,69 @@
 }
 
 /*
+ * this function sends a 'generic call function' IPI to one other CPU
+ * in the system.
+ */
+static void __smp_call_function_single (int cpu, void (*func) (void *info), void *info,
+				int nonatomic, int wait)
+{
+	struct call_data_struct data;
+	int cpus = 1;
+
+	data.func = func;
+	data.info = info;
+	atomic_set(&data.started, 0);
+	data.wait = wait;
+	if (wait)
+		atomic_set(&data.finished, 0);
+
+	call_data = &data;
+	wmb();
+	/* Send a message to all other CPUs and wait for them to respond */
+	send_IPI_mask(cpumask_of_cpu(cpu), CALL_FUNCTION_VECTOR);
+
+	/* Wait for response */
+	while (atomic_read(&data.started) != cpus)
+		cpu_relax();
+
+	if (!wait)
+		return;
+
+	while (atomic_read(&data.finished) != cpus)
+		cpu_relax();
+}
+
+/*
+ * smp_call_function_single - Run a function on another CPU
+ * @func: The function to run. This must be fast and non-blocking.
+ * @info: An arbitrary pointer to pass to the function.
+ * @nonatomic: Currently unused.
+ * @wait: If true, wait until function has completed on other CPUs.
+ *
+ * Retrurns 0 on success, else a negative status code.
+ *
+ * Does not return until the remote CPU is nearly ready to execute <func>
+ * or is or has executed.
+ */
+
+int smp_call_function_single (int cpu, void (*func) (void *info), void *info,
+	int nonatomic, int wait)
+{
+	/* prevent preemption and reschedule on another processor */
+	int me = get_cpu();
+	if (cpu == me) {
+		WARN_ON(1);
+		put_cpu();
+		return -EBUSY;
+	}
+	spin_lock_bh(&call_lock);
+	__smp_call_function_single(cpu, func, info, nonatomic, wait);
+	spin_unlock_bh(&call_lock);
+	put_cpu();
+	return 0;
+}
+
+/*
  * this function sends a 'generic call function' IPI to all other CPUs
  * in the system.
  */
diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c
index e773a79..6e4807d 100644
--- a/arch/x86_64/kernel/smpboot.c
+++ b/arch/x86_64/kernel/smpboot.c
@@ -113,24 +113,6 @@
 #define set_idle_for_cpu(x,p)   (idle_thread_array[(x)] = (p))
 
 /*
- * cpu_possible_map should be static, it cannot change as cpu's
- * are onlined, or offlined. The reason is per-cpu data-structures
- * are allocated by some modules at init time, and dont expect to
- * do this dynamically on cpu arrival/departure.
- * cpu_present_map on the other hand can change dynamically.
- * In case when cpu_hotplug is not compiled, then we resort to current
- * behaviour, which is cpu_possible == cpu_present.
- * If cpu-hotplug is supported, then we need to preallocate for all
- * those NR_CPUS, hence cpu_possible_map represents entire NR_CPUS range.
- * - Ashok Raj
- */
-#ifdef CONFIG_HOTPLUG_CPU
-#define fixup_cpu_possible_map(x)	cpu_set((x), cpu_possible_map)
-#else
-#define fixup_cpu_possible_map(x)
-#endif
-
-/*
  * Currently trivial. Write the real->protected mode
  * bootstrap into the page concerned. The caller
  * has made sure it's suitably aligned.
@@ -229,9 +211,6 @@
 {
 	unsigned long flags, i;
 
-	if (smp_processor_id() != 0)
-		return;
-
 	go[MASTER] = 0;
 
 	local_irq_save(flags);
@@ -280,7 +259,7 @@
 	return tcenter - best_tm;
 }
 
-static __cpuinit void sync_tsc(void)
+static __cpuinit void sync_tsc(unsigned int master)
 {
 	int i, done = 0;
 	long delta, adj, adjust_latency = 0;
@@ -294,9 +273,17 @@
 	} t[NUM_ROUNDS] __cpuinitdata;
 #endif
 
+	printk(KERN_INFO "CPU %d: Syncing TSC to CPU %u.\n",
+		smp_processor_id(), master);
+
 	go[MASTER] = 1;
 
-	smp_call_function(sync_master, NULL, 1, 0);
+	/* It is dangerous to broadcast IPI as cpus are coming up,
+	 * as they may not be ready to accept them.  So since
+	 * we only need to send the ipi to the boot cpu direct
+	 * the message, and avoid the race.
+	 */
+	smp_call_function_single(master, sync_master, NULL, 1, 0);
 
 	while (go[MASTER])	/* wait for master to be ready */
 		no_cpu_relax();
@@ -340,16 +327,14 @@
 	printk(KERN_INFO
 	       "CPU %d: synchronized TSC with CPU %u (last diff %ld cycles, "
 	       "maxerr %lu cycles)\n",
-	       smp_processor_id(), boot_cpu_id, delta, rt);
+	       smp_processor_id(), master, delta, rt);
 }
 
 static void __cpuinit tsc_sync_wait(void)
 {
 	if (notscsync || !cpu_has_tsc)
 		return;
-	printk(KERN_INFO "CPU %d: Syncing TSC to CPU %u.\n", smp_processor_id(),
-			boot_cpu_id);
-	sync_tsc();
+	sync_tsc(boot_cpu_id);
 }
 
 static __init int notscsync_setup(char *s)
@@ -773,8 +758,9 @@
 	initial_code = start_secondary;
 	clear_ti_thread_flag(c_idle.idle->thread_info, TIF_FORK);
 
-	printk(KERN_INFO "Booting processor %d/%d rip %lx rsp %lx\n", cpu, apicid,
-	       start_rip, init_rsp);
+	printk(KERN_INFO "Booting processor %d/%d APIC 0x%x\n", cpu,
+		cpus_weight(cpu_present_map),
+		apicid);
 
 	/*
 	 * This grunge runs the startup process for
@@ -924,6 +910,27 @@
 	}
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+/*
+ * cpu_possible_map should be static, it cannot change as cpu's
+ * are onlined, or offlined. The reason is per-cpu data-structures
+ * are allocated by some modules at init time, and dont expect to
+ * do this dynamically on cpu arrival/departure.
+ * cpu_present_map on the other hand can change dynamically.
+ * In case when cpu_hotplug is not compiled, then we resort to current
+ * behaviour, which is cpu_possible == cpu_present.
+ * If cpu-hotplug is supported, then we need to preallocate for all
+ * those NR_CPUS, hence cpu_possible_map represents entire NR_CPUS range.
+ * - Ashok Raj
+ */
+static void prefill_possible_map(void)
+{
+	int i;
+	for (i = 0; i < NR_CPUS; i++)
+		cpu_set(i, cpu_possible_map);
+}
+#endif
+
 /*
  * Various sanity checks.
  */
@@ -987,25 +994,15 @@
  */
 void __init smp_prepare_cpus(unsigned int max_cpus)
 {
-	int i;
-
 	nmi_watchdog_default();
 	current_cpu_data = boot_cpu_data;
 	current_thread_info()->cpu = 0;  /* needed? */
 
 	enforce_max_cpus(max_cpus);
 
-	/*
-	 * Fill in cpu_present_mask
-	 */
-	for (i = 0; i < NR_CPUS; i++) {
-		int apicid = cpu_present_to_apicid(i);
-		if (physid_isset(apicid, phys_cpu_present_map)) {
-			cpu_set(i, cpu_present_map);
-			cpu_set(i, cpu_possible_map);
-		}
-		fixup_cpu_possible_map(i);
-	}
+#ifdef CONFIG_HOTPLUG_CPU
+	prefill_possible_map();
+#endif
 
 	if (smp_sanity_check(max_cpus) < 0) {
 		printk(KERN_INFO "SMP disabled\n");
@@ -1189,8 +1186,7 @@
 			printk ("CPU %d is now offline\n", cpu);
 			return;
 		}
-		current->state = TASK_UNINTERRUPTIBLE;
-		schedule_timeout(HZ/10);
+		msleep(100);
 	}
  	printk(KERN_ERR "CPU %u didn't die...\n", cpu);
 }
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index 1027366..6ead433 100644
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -594,9 +594,6 @@
 	if (!cpu)
 		reason = get_nmi_reason();
 
-	if (!cpu_online(cpu))
-		return;
-
 	if (!(reason & 0xc0)) {
 		if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 0, SIGINT)
 								== NOTIFY_STOP)
diff --git a/arch/x86_64/lib/delay.c b/arch/x86_64/lib/delay.c
index 33a873a..841bd73 100644
--- a/arch/x86_64/lib/delay.c
+++ b/arch/x86_64/lib/delay.c
@@ -18,8 +18,6 @@
 #include <asm/smp.h>
 #endif
 
-int x86_udelay_tsc = 0;		/* Delay via TSC */
-
 int read_current_timer(unsigned long *timer_value)
 {
 	rdtscll(*timer_value);
diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c
index 2f18798..1379272 100644
--- a/arch/x86_64/mm/fault.c
+++ b/arch/x86_64/mm/fault.c
@@ -23,7 +23,6 @@
 #include <linux/vt_kern.h>		/* For unblank_screen() */
 #include <linux/compiler.h>
 #include <linux/module.h>
-#include <linux/kprobes.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
diff --git a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c
index ac61c18..70cb290 100644
--- a/arch/x86_64/mm/numa.c
+++ b/arch/x86_64/mm/numa.c
@@ -36,34 +36,36 @@
 int __init compute_hash_shift(struct node *nodes, int numnodes)
 {
 	int i; 
-	int shift = 24;
-	u64 addr;
+	int shift = 20;
+	unsigned long addr,maxend=0;
 	
-	/* When in doubt use brute force. */
-	while (shift < 48) { 
-		memset(memnodemap,0xff,sizeof(*memnodemap) * NODEMAPSIZE); 
-		for (i = 0; i < numnodes; i++) {
-			if (nodes[i].start == nodes[i].end) 
-				continue;
-			for (addr = nodes[i].start; 
-			     addr < nodes[i].end; 
-			     addr += (1UL << shift)) {
-				if (memnodemap[addr >> shift] != 0xff && 
-				    memnodemap[addr >> shift] != i) { 
-					printk(KERN_INFO 
-					    "node %d shift %d addr %Lx conflict %d\n", 
-					       i, shift, addr, memnodemap[addr>>shift]);
-					goto next; 
-				} 
-				memnodemap[addr >> shift] = i; 
+	for (i = 0; i < numnodes; i++)
+		if ((nodes[i].start != nodes[i].end) && (nodes[i].end > maxend))
+				maxend = nodes[i].end;
+
+	while ((1UL << shift) <  (maxend / NODEMAPSIZE))
+		shift++;
+
+	printk (KERN_DEBUG"Using %d for the hash shift. Max adder is %lx \n",
+			shift,maxend);
+	memset(memnodemap,0xff,sizeof(*memnodemap) * NODEMAPSIZE);
+	for (i = 0; i < numnodes; i++) {
+		if (nodes[i].start == nodes[i].end)
+			continue;
+		for (addr = nodes[i].start;
+		     addr < nodes[i].end;
+		     addr += (1UL << shift)) {
+			if (memnodemap[addr >> shift] != 0xff) {
+				printk(KERN_INFO
+	"Your memory is not aligned you need to rebuild your kernel "
+	"with a bigger NODEMAPSIZE shift=%d adder=%lu\n",
+					shift,addr);
+				return -1;
 			} 
+			memnodemap[addr >> shift] = i;
 		} 
-		return shift; 
-	next:
-		shift++; 
 	} 
-	memset(memnodemap,0,sizeof(*memnodemap) * NODEMAPSIZE); 
-	return -1; 
+	return shift;
 }
 
 #ifdef CONFIG_SPARSEMEM
diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat.c
index 5d01b31..8e3d097 100644
--- a/arch/x86_64/mm/srat.c
+++ b/arch/x86_64/mm/srat.c
@@ -20,6 +20,9 @@
 
 static struct acpi_table_slit *acpi_slit;
 
+/* Internal processor count */
+static unsigned int __initdata num_processors = 0;
+
 static nodemask_t nodes_parsed __initdata;
 static nodemask_t nodes_found __initdata;
 static struct node nodes[MAX_NUMNODES] __initdata;
@@ -101,16 +104,18 @@
 		bad_srat();
 		return;
 	}
-	if (pa->apic_id >= NR_CPUS) {
-		printk(KERN_ERR "SRAT: lapic %u too large.\n",
-		       pa->apic_id);
+	if (num_processors >= NR_CPUS) {
+		printk(KERN_ERR "SRAT: Processor #%d (lapic %u) INVALID. (Max ID: %d).\n",
+			num_processors, pa->apic_id, NR_CPUS);
 		bad_srat();
 		return;
 	}
-	cpu_to_node[pa->apic_id] = node;
+	cpu_to_node[num_processors] = node;
 	acpi_numa = 1;
-	printk(KERN_INFO "SRAT: PXM %u -> APIC %u -> Node %u\n",
-	       pxm, pa->apic_id, node);
+	printk(KERN_INFO "SRAT: PXM %u -> APIC %u -> CPU %u -> Node %u\n",
+	       pxm, pa->apic_id, num_processors, node);
+
+	num_processors++;
 }
 
 /* Callback for parsing of the Proximity Domain <-> Memory Area mappings */
@@ -124,7 +129,6 @@
 
 	if (srat_disabled() || ma->flags.enabled == 0)
 		return;
-	/* hotplug bit is ignored for now */
 	pxm = ma->proximity_domain;
 	node = setup_node(pxm);
 	if (node < 0) {
@@ -134,6 +138,10 @@
 	}
 	start = ma->base_addr_lo | ((u64)ma->base_addr_hi << 32);
 	end = start + (ma->length_lo | ((u64)ma->length_hi << 32));
+	/* It is fine to add this area to the nodes data it will be used later*/
+	if (ma->flags.hot_pluggable == 1)
+		printk(KERN_INFO "SRAT: hot plug zone found %lx - %lx \n",
+				start, end);
 	i = conflicting_nodes(start, end);
 	if (i >= 0) {
 		printk(KERN_ERR
diff --git a/arch/x86_64/pci/k8-bus.c b/arch/x86_64/pci/k8-bus.c
index 7e7d0c2..c2c38b5 100644
--- a/arch/x86_64/pci/k8-bus.c
+++ b/arch/x86_64/pci/k8-bus.c
@@ -29,7 +29,7 @@
 fill_mp_bus_to_cpumask(void)
 {
 	struct pci_dev *nb_dev = NULL;
-	int i, j, printed;
+	int i, j;
 	u32 ldtbus, nid;
 	static int lbnr[3] = {
 		LDT_BUS_NUMBER_REGISTER_0,
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 3e9fb6e..418b146 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -1135,7 +1135,7 @@
 		/* this is for the online array utilities */
 		if (!drv->heads && i)
 			continue;
-		blk_queue_hardsect_size(host->queue, drv->block_size);
+		blk_queue_hardsect_size(drv->queue, drv->block_size);
 		set_capacity(disk, drv->nr_blocks);
 		add_disk(disk);
 	}
@@ -1691,7 +1691,7 @@
 	cciss_read_capacity(h->ctlr, logvol, size_buff, 1, &total_size, &block_size);
 	cciss_geometry_inquiry(h->ctlr, logvol, 1, total_size, block_size, inq_buff, drv);
 
-	blk_queue_hardsect_size(h->queue, drv->block_size);
+	blk_queue_hardsect_size(drv->queue, drv->block_size);
 	set_capacity(disk, drv->nr_blocks);
 
 	kfree(size_buff);
@@ -2248,12 +2248,12 @@
  	 * them up.  We will also keep track of the next queue to run so
  	 * that every queue gets a chance to be started first.
  	*/
- 	for (j=0; j < NWD; j++){
- 		int curr_queue = (start_queue + j) % NWD;
+	for (j=0; j < h->highest_lun + 1; j++){
+		int curr_queue = (start_queue + j) % (h->highest_lun + 1);
  		/* make sure the disk has been added and the drive is real
  		 * because this can be called from the middle of init_one.
  		*/
- 		if(!(h->gendisk[curr_queue]->queue) ||
+		if(!(h->drv[curr_queue].queue) ||
 		 		   !(h->drv[curr_queue].heads))
  			continue;
  		blk_start_queue(h->gendisk[curr_queue]->queue);
@@ -2264,14 +2264,14 @@
  		if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS)
  		{
  			if (curr_queue == start_queue){
- 				h->next_to_run = (start_queue + 1) % NWD;
+				h->next_to_run = (start_queue + 1) % (h->highest_lun + 1);
  				goto cleanup;
  			} else {
  				h->next_to_run = curr_queue;
  				goto cleanup;
  	}
  		} else {
- 			curr_queue = (curr_queue + 1) % NWD;
+			curr_queue = (curr_queue + 1) % (h->highest_lun + 1);
  		}
  	}
 
@@ -2279,7 +2279,6 @@
 	spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
 	return IRQ_HANDLED;
 }
-
 /* 
  *  We cannot read the structure directly, for portablity we must use 
  *   the io functions.
@@ -2789,13 +2788,6 @@
 	}
 
 	spin_lock_init(&hba[i]->lock);
-	q = blk_init_queue(do_cciss_request, &hba[i]->lock);
-	if (!q)
-		goto clean4;
-
-	q->backing_dev_info.ra_pages = READ_AHEAD;
-	hba[i]->queue = q;
-	q->queuedata = hba[i];
 
 	/* Initialize the pdev driver private data. 
 		have it point to hba[i].  */
@@ -2817,6 +2809,20 @@
 
 	cciss_procinit(i);
 
+	for(j=0; j < NWD; j++) { /* mfm */
+		drive_info_struct *drv = &(hba[i]->drv[j]);
+		struct gendisk *disk = hba[i]->gendisk[j];
+
+		q = blk_init_queue(do_cciss_request, &hba[i]->lock);
+		if (!q) {
+			printk(KERN_ERR
+			   "cciss:  unable to allocate queue for disk %d\n",
+			   j);
+			break;
+		}
+		drv->queue = q;
+
+		q->backing_dev_info.ra_pages = READ_AHEAD;
 	blk_queue_bounce_limit(q, hba[i]->pdev->dma_mask);
 
 	/* This is a hardware imposed limit. */
@@ -2827,26 +2833,23 @@
 
 	blk_queue_max_sectors(q, 512);
 
-
-	for(j=0; j<NWD; j++) {
-		drive_info_struct *drv = &(hba[i]->drv[j]);
-		struct gendisk *disk = hba[i]->gendisk[j];
-
+		q->queuedata = hba[i];
 		sprintf(disk->disk_name, "cciss/c%dd%d", i, j);
 		sprintf(disk->devfs_name, "cciss/host%d/target%d", i, j);
 		disk->major = hba[i]->major;
 		disk->first_minor = j << NWD_SHIFT;
 		disk->fops = &cciss_fops;
-		disk->queue = hba[i]->queue;
+		disk->queue = q;
 		disk->private_data = drv;
 		/* we must register the controller even if no disks exist */
 		/* this is for the online array utilities */
 		if(!drv->heads && j)
 			continue;
-		blk_queue_hardsect_size(hba[i]->queue, drv->block_size);
+		blk_queue_hardsect_size(q, drv->block_size);
 		set_capacity(disk, drv->nr_blocks);
 		add_disk(disk);
 	}
+
 	return(1);
 
 clean4:
@@ -2912,10 +2915,10 @@
 	for (j = 0; j < NWD; j++) {
 		struct gendisk *disk = hba[i]->gendisk[j];
 		if (disk->flags & GENHD_FL_UP)
+			blk_cleanup_queue(disk->queue);
 			del_gendisk(disk);
 	}
 
-	blk_cleanup_queue(hba[i]->queue);
 	pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof(CommandList_struct),
 			    hba[i]->cmd_pool, hba[i]->cmd_pool_dhandle);
 	pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof( ErrorInfo_struct),
diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h
index 8fb1920..566587d 100644
--- a/drivers/block/cciss.h
+++ b/drivers/block/cciss.h
@@ -29,6 +29,7 @@
 {
  	__u32   LunID;	
 	int 	usage_count;
+	struct request_queue *queue;
 	sector_t nr_blocks;
 	int	block_size;
 	int 	heads;
@@ -72,7 +73,6 @@
 	unsigned int maxQsinceinit;
 	unsigned int maxSG;
 	spinlock_t lock;
-	struct request_queue *queue;
 
 	//* pointers to command and error info pool */ 
 	CommandList_struct 	*cmd_pool;
@@ -260,7 +260,7 @@
 	struct access_method *access;
 };
 
-#define CCISS_LOCK(i)	(hba[i]->queue->queue_lock)
+#define CCISS_LOCK(i)	(&hba[i]->lock)
 
 #endif /* CCISS_H */
 
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index c1fe013..b4af87c 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -143,6 +143,7 @@
 	char major_version;
 	char minor_version;
 	struct list_head list;
+	u32 apbase_config;
 };
 
 #define KB(x)	((x) * 1024)
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index 51266d6..1f7d415 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -1047,9 +1047,15 @@
 	/* aperture size */
 	pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
 
-	/* address to map to */
-	pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
-	agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+	if (agp_bridge->apbase_config != 0) {
+		pci_write_config_dword(agp_bridge->dev, AGP_APBASE,
+				       agp_bridge->apbase_config);
+	} else {
+		/* address to map to */
+		pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
+		agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+		agp_bridge->apbase_config = temp;
+	}
 
 	/* attbase - aperture base */
 	pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index 7b19e02..523fd3c 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -198,10 +198,10 @@
 
 	if (scancode >= dev->keycodemax)
 		return -EINVAL;
-	if (keycode > KEY_MAX)
-		return -EINVAL;
 	if (keycode < 0 || keycode > KEY_MAX)
 		return -EINVAL;
+	if (keycode >> (dev->keycodesize * 8))
+		return -EINVAL;
 
 	oldkey = SET_INPUT_KEYCODE(dev, scancode, keycode);
 
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index fd04206..cefbe98 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -439,6 +439,11 @@
 	{ 0, 0 },
 };
 
+struct sonypi_keypress {
+	struct input_dev *dev;
+	int key;
+};
+
 static struct sonypi_device {
 	struct pci_dev *dev;
 	struct platform_device *pdev;
@@ -710,22 +715,61 @@
 
 static void input_keyrelease(void *data)
 {
-	struct input_dev *input_dev;
-	int key;
+	struct sonypi_keypress kp;
 
-	while (1) {
-		if (kfifo_get(sonypi_device.input_fifo,
-			      (unsigned char *)&input_dev,
-			      sizeof(input_dev)) != sizeof(input_dev))
-			return;
-		if (kfifo_get(sonypi_device.input_fifo,
-			      (unsigned char *)&key,
-			      sizeof(key)) != sizeof(key))
-			return;
-
+	while (kfifo_get(sonypi_device.input_fifo, (unsigned char *)&kp,
+			 sizeof(kp)) == sizeof(kp)) {
 		msleep(10);
-		input_report_key(input_dev, key, 0);
-		input_sync(input_dev);
+		input_report_key(kp.dev, kp.key, 0);
+		input_sync(kp.dev);
+	}
+}
+
+static void sonypi_report_input_event(u8 event)
+{
+	struct input_dev *jog_dev = &sonypi_device.input_jog_dev;
+	struct input_dev *key_dev = &sonypi_device.input_key_dev;
+	struct sonypi_keypress kp = { NULL };
+	int i;
+
+	switch (event) {
+	case SONYPI_EVENT_JOGDIAL_UP:
+	case SONYPI_EVENT_JOGDIAL_UP_PRESSED:
+		input_report_rel(jog_dev, REL_WHEEL, 1);
+		input_sync(jog_dev);
+		break;
+
+	case SONYPI_EVENT_JOGDIAL_DOWN:
+	case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED:
+		input_report_rel(jog_dev, REL_WHEEL, -1);
+		input_sync(jog_dev);
+		break;
+
+	case SONYPI_EVENT_JOGDIAL_PRESSED:
+		kp.key = BTN_MIDDLE;
+		kp.dev = jog_dev;
+		break;
+
+	case SONYPI_EVENT_FNKEY_RELEASED:
+		/* Nothing, not all VAIOs generate this event */
+		break;
+
+	default:
+		for (i = 0; sonypi_inputkeys[i].sonypiev; i++)
+			if (event == sonypi_inputkeys[i].sonypiev) {
+				kp.dev = key_dev;
+				kp.key = sonypi_inputkeys[i].inputev;
+				break;
+			}
+		break;
+	}
+
+	if (kp.dev) {
+		input_report_key(kp.dev, kp.key, 1);
+		input_sync(kp.dev);
+		kfifo_put(sonypi_device.input_fifo,
+			  (unsigned char *)&kp, sizeof(kp));
+		schedule_work(&sonypi_device.input_work);
 	}
 }
 
@@ -768,51 +812,8 @@
 		printk(KERN_INFO
 		       "sonypi: event port1=0x%02x,port2=0x%02x\n", v1, v2);
 
-	if (useinput) {
-		struct input_dev *input_jog_dev = &sonypi_device.input_jog_dev;
-		struct input_dev *input_key_dev = &sonypi_device.input_key_dev;
-		switch (event) {
-		case SONYPI_EVENT_JOGDIAL_UP:
-		case SONYPI_EVENT_JOGDIAL_UP_PRESSED:
-			input_report_rel(input_jog_dev, REL_WHEEL, 1);
-			break;
-		case SONYPI_EVENT_JOGDIAL_DOWN:
-		case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED:
-			input_report_rel(input_jog_dev, REL_WHEEL, -1);
-			break;
-		case SONYPI_EVENT_JOGDIAL_PRESSED: {
-			int key = BTN_MIDDLE;
-			input_report_key(input_jog_dev, key, 1);
-			kfifo_put(sonypi_device.input_fifo,
-				  (unsigned char *)&input_jog_dev,
-				  sizeof(input_jog_dev));
-			kfifo_put(sonypi_device.input_fifo,
-				  (unsigned char *)&key, sizeof(key));
-			break;
-		}
-		case SONYPI_EVENT_FNKEY_RELEASED:
-			/* Nothing, not all VAIOs generate this event */
-			break;
-		}
-		input_sync(input_jog_dev);
-
-		for (i = 0; sonypi_inputkeys[i].sonypiev; i++) {
-			int key;
-
-			if (event != sonypi_inputkeys[i].sonypiev)
-				continue;
-
-			key = sonypi_inputkeys[i].inputev;
-			input_report_key(input_key_dev, key, 1);
-			kfifo_put(sonypi_device.input_fifo,
-				  (unsigned char *)&input_key_dev,
-				  sizeof(input_key_dev));
-			kfifo_put(sonypi_device.input_fifo,
-				  (unsigned char *)&key, sizeof(key));
-		}
-		input_sync(input_key_dev);
-		schedule_work(&sonypi_device.input_work);
-	}
+	if (useinput)
+		sonypi_report_input_event(event);
 
 	kfifo_put(sonypi_device.fifo, (unsigned char *)&event, sizeof(event));
 	kill_fasync(&sonypi_device.fifo_async, SIGIO, POLL_IN);
@@ -1227,14 +1228,7 @@
 		sonypi_device.input_jog_dev.keybit[LONG(BTN_MOUSE)] =
 			BIT(BTN_MIDDLE);
 		sonypi_device.input_jog_dev.relbit[0] = BIT(REL_WHEEL);
-		sonypi_device.input_jog_dev.name =
-			kmalloc(sizeof(SONYPI_JOG_INPUTNAME), GFP_KERNEL);
-		if (!sonypi_device.input_jog_dev.name) {
-			printk(KERN_ERR "sonypi: kmalloc failed\n");
-			ret = -ENOMEM;
-			goto out_inkmallocinput1;
-		}
-		sprintf(sonypi_device.input_jog_dev.name, SONYPI_JOG_INPUTNAME);
+		sonypi_device.input_jog_dev.name = SONYPI_JOG_INPUTNAME;
 		sonypi_device.input_jog_dev.id.bustype = BUS_ISA;
 		sonypi_device.input_jog_dev.id.vendor = PCI_VENDOR_ID_SONY;
 
@@ -1248,14 +1242,7 @@
 			if (sonypi_inputkeys[i].inputev)
 				set_bit(sonypi_inputkeys[i].inputev,
 					sonypi_device.input_key_dev.keybit);
-		sonypi_device.input_key_dev.name =
-			kmalloc(sizeof(SONYPI_KEY_INPUTNAME), GFP_KERNEL);
-		if (!sonypi_device.input_key_dev.name) {
-			printk(KERN_ERR "sonypi: kmalloc failed\n");
-			ret = -ENOMEM;
-			goto out_inkmallocinput2;
-		}
-		sprintf(sonypi_device.input_key_dev.name, SONYPI_KEY_INPUTNAME);
+		sonypi_device.input_key_dev.name = SONYPI_KEY_INPUTNAME;
 		sonypi_device.input_key_dev.id.bustype = BUS_ISA;
 		sonypi_device.input_key_dev.id.vendor = PCI_VENDOR_ID_SONY;
 
@@ -1313,11 +1300,7 @@
 	kfifo_free(sonypi_device.input_fifo);
 out_infifo:
 	input_unregister_device(&sonypi_device.input_key_dev);
-	kfree(sonypi_device.input_key_dev.name);
-out_inkmallocinput2:
 	input_unregister_device(&sonypi_device.input_jog_dev);
-	kfree(sonypi_device.input_jog_dev.name);
-out_inkmallocinput1:
 	free_irq(sonypi_device.irq, sonypi_irq);
 out_reqirq:
 	release_region(sonypi_device.ioport1, sonypi_device.region_size);
@@ -1337,13 +1320,14 @@
 {
 	sonypi_disable();
 
+	synchronize_sched();  /* Allow sonypi interrupt to complete. */
+	flush_scheduled_work();
+
 	platform_device_unregister(sonypi_device.pdev);
 
 	if (useinput) {
 		input_unregister_device(&sonypi_device.input_key_dev);
-		kfree(sonypi_device.input_key_dev.name);
 		input_unregister_device(&sonypi_device.input_jog_dev);
-		kfree(sonypi_device.input_jog_dev.name);
 		kfifo_free(sonypi_device.input_fifo);
 	}
 
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 7a7859d..10b0149 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -1130,7 +1130,7 @@
 			  unsigned int target_freq,
 			  unsigned int relation)
 {
-	unsigned int ret;
+	int ret;
 
 	policy = cpufreq_cpu_get(policy->cpu);
 	if (!policy)
@@ -1151,7 +1151,7 @@
 
 static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event)
 {
-	int ret = -EINVAL;
+	int ret;
 
 	if (!try_module_get(policy->governor->owner))
 		return -EINVAL;
diff --git a/drivers/firmware/pcdp.c b/drivers/firmware/pcdp.c
index 53c95c0..ae1fb45 100644
--- a/drivers/firmware/pcdp.c
+++ b/drivers/firmware/pcdp.c
@@ -25,14 +25,22 @@
 #ifdef CONFIG_SERIAL_8250_CONSOLE
 	int mmio;
 	static char options[64], *p = options;
+	char parity;
 
 	mmio = (uart->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY);
 	p += sprintf(p, "console=uart,%s,0x%lx",
 		mmio ? "mmio" : "io", uart->addr.address);
-	if (uart->baud)
+	if (uart->baud) {
 		p += sprintf(p, ",%lu", uart->baud);
-	if (uart->bits)
-		p += sprintf(p, "n%d", uart->bits);
+		if (uart->bits) {
+			switch (uart->parity) {
+			    case 0x2: parity = 'e'; break;
+			    case 0x3: parity = 'o'; break;
+			    default:  parity = 'n';
+			}
+			p += sprintf(p, "%c%d", parity, uart->bits);
+		}
+	}
 
 	return early_serial_console_init(options);
 #else
diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c
index 3c85fe1..4fa17c7 100644
--- a/drivers/hwmon/adm1026.c
+++ b/drivers/hwmon/adm1026.c
@@ -393,7 +393,7 @@
 
 	value = data->config3;
 	if (data->config3 & CFG3_GPIO16_ENABLE) {
-		dev_dbg(&client->dev, "GPIO16 enabled.  THERM"
+		dev_dbg(&client->dev, "GPIO16 enabled.  THERM "
 			"pin disabled.\n");
 	} else {
 		dev_dbg(&client->dev, "THERM pin enabled.  "
diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c
index 0bcf82b..fca3fc1 100644
--- a/drivers/hwmon/atxp1.c
+++ b/drivers/hwmon/atxp1.c
@@ -21,6 +21,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 #include <linux/i2c-vid.h>
@@ -80,9 +81,7 @@
 
 	down(&data->update_lock);
 
-	if ((jiffies - data->last_updated > HZ) ||
-	    (jiffies < data->last_updated) ||
-	    !data->valid) {
+	if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
 
 		/* Update local register data */
 		data->reg.vid = i2c_smbus_read_byte_data(client, ATXP1_VID);
diff --git a/drivers/hwmon/fscpos.c b/drivers/hwmon/fscpos.c
index 3beaa61..270015b 100644
--- a/drivers/hwmon/fscpos.c
+++ b/drivers/hwmon/fscpos.c
@@ -32,6 +32,7 @@
 
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 #include <linux/init.h>
@@ -572,8 +573,7 @@
 
 	down(&data->update_lock);
 
-	if ((jiffies - data->last_updated > 2 * HZ) ||
-			(jiffies < data->last_updated) || !data->valid) {
+	if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
 		int i;
 
 		dev_dbg(&client->dev, "Starting fscpos update\n");
diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c
index a13a504..80ae8d3 100644
--- a/drivers/hwmon/gl520sm.c
+++ b/drivers/hwmon/gl520sm.c
@@ -24,6 +24,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/i2c-sensor.h>
 #include <linux/i2c-vid.h>
@@ -678,8 +679,7 @@
 
 	down(&data->update_lock);
 
-	if ((jiffies - data->last_updated > 2 * HZ) ||
-	    (jiffies < data->last_updated) || !data->valid) {
+	if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
 
 		dev_dbg(&client->dev, "Starting gl520sm update\n");
 
diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c
index bf553dc..3c159f1 100644
--- a/drivers/hwmon/max1619.c
+++ b/drivers/hwmon/max1619.c
@@ -363,7 +363,7 @@
 	i2c_del_driver(&max1619_driver);
 }
 
-MODULE_AUTHOR("Alexey Fisher <fishor@mail.ru> and"
+MODULE_AUTHOR("Alexey Fisher <fishor@mail.ru> and "
 	"Jean Delvare <khali@linux-fr.org>");
 MODULE_DESCRIPTION("MAX1619 sensor driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c
index 876c68f..fa4032d 100644
--- a/drivers/hwmon/pc87360.c
+++ b/drivers/hwmon/pc87360.c
@@ -1043,7 +1043,7 @@
 	if (init >= 2 && data->innr) {
 		reg = pc87360_read_value(data, LD_IN, NO_BANK,
 					 PC87365_REG_IN_CONVRATE);
-		dev_info(&client->dev, "VLM conversion set to"
+		dev_info(&client->dev, "VLM conversion set to "
 			 "1s period, 160us delay\n");
 		pc87360_write_value(data, LD_IN, NO_BANK,
 				    PC87365_REG_IN_CONVRATE,
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 0ab7e37..1ab4131 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -137,7 +137,7 @@
 		pci_read_config_word(I801_dev, SMBBA, &i801_smba);
 		i801_smba &= 0xfff0;
 		if(i801_smba == 0) {
-			dev_err(&dev->dev, "SMB base address uninitialized"
+			dev_err(&dev->dev, "SMB base address uninitialized "
 				"- upgrade BIOS or use force_addr=0xaddr\n");
 			return -ENODEV;
 		}
@@ -186,7 +186,7 @@
 	int result = 0;
 	int timeout = 0;
 
-	dev_dbg(&I801_dev->dev, "Transaction (pre): CNT=%02x, CMD=%02x,"
+	dev_dbg(&I801_dev->dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
 		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
 		inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
 		inb_p(SMBHSTDAT1));
@@ -240,7 +240,7 @@
 		outb_p(inb(SMBHSTSTS), SMBHSTSTS);
 
 	if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
-		dev_dbg(&I801_dev->dev, "Failed reset at end of transaction"
+		dev_dbg(&I801_dev->dev, "Failed reset at end of transaction "
 			"(%02x)\n", temp);
 	}
 	dev_dbg(&I801_dev->dev, "Transaction (post): CNT=%02x, CMD=%02x, "
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 9ad3e92..04adde6 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -382,6 +382,100 @@
 module_init(fsl_i2c_init);
 module_exit(fsl_i2c_exit);
 
+static int fsl_i2c_probe(struct device *device)
+{
+	int result = 0;
+	struct mpc_i2c *i2c;
+	struct platform_device *pdev = to_platform_device(device);
+	struct fsl_i2c_platform_data *pdata;
+	struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	pdata = (struct fsl_i2c_platform_data *) pdev->dev.platform_data;
+
+	if (!(i2c = kmalloc(sizeof(*i2c), GFP_KERNEL))) {
+		return -ENOMEM;
+	}
+	memset(i2c, 0, sizeof(*i2c));
+
+	i2c->irq = platform_get_irq(pdev, 0);
+	i2c->flags = pdata->device_flags;
+	init_waitqueue_head(&i2c->queue);
+
+	i2c->base = ioremap((phys_addr_t)r->start, MPC_I2C_REGION);
+
+	if (!i2c->base) {
+		printk(KERN_ERR "i2c-mpc - failed to map controller\n");
+		result = -ENOMEM;
+		goto fail_map;
+	}
+
+	if (i2c->irq != 0)
+		if ((result = request_irq(i2c->irq, mpc_i2c_isr,
+					  SA_SHIRQ, "i2c-mpc", i2c)) < 0) {
+			printk(KERN_ERR
+			       "i2c-mpc - failed to attach interrupt\n");
+			goto fail_irq;
+		}
+
+	mpc_i2c_setclock(i2c);
+	dev_set_drvdata(device, i2c);
+
+	i2c->adap = mpc_ops;
+	i2c_set_adapdata(&i2c->adap, i2c);
+	i2c->adap.dev.parent = &pdev->dev;
+	if ((result = i2c_add_adapter(&i2c->adap)) < 0) {
+		printk(KERN_ERR "i2c-mpc - failed to add adapter\n");
+		goto fail_add;
+	}
+
+	return result;
+
+      fail_add:
+	if (i2c->irq != 0)
+		free_irq(i2c->irq, NULL);
+      fail_irq:
+	iounmap(i2c->base);
+      fail_map:
+	kfree(i2c);
+	return result;
+};
+
+static int fsl_i2c_remove(struct device *device)
+{
+	struct mpc_i2c *i2c = dev_get_drvdata(device);
+
+	i2c_del_adapter(&i2c->adap);
+	dev_set_drvdata(device, NULL);
+
+	if (i2c->irq != 0)
+		free_irq(i2c->irq, i2c);
+
+	iounmap(i2c->base);
+	kfree(i2c);
+	return 0;
+};
+
+/* Structure for a device driver */
+static struct device_driver fsl_i2c_driver = {
+	.name = "fsl-i2c",
+	.bus = &platform_bus_type,
+	.probe = fsl_i2c_probe,
+	.remove = fsl_i2c_remove,
+};
+
+static int __init fsl_i2c_init(void)
+{
+	return driver_register(&fsl_i2c_driver);
+}
+
+static void __exit fsl_i2c_exit(void)
+{
+	driver_unregister(&fsl_i2c_driver);
+}
+
+module_init(fsl_i2c_init);
+module_exit(fsl_i2c_exit);
+
 MODULE_AUTHOR("Adrian Cox <adrian@humboldt.co.uk>");
 MODULE_DESCRIPTION
     ("I2C-Bus adapter for MPC107 bridge and MPC824x/85xx/52xx processors");
diff --git a/drivers/i2c/chips/ds1337.c b/drivers/i2c/chips/ds1337.c
index 74ece8a..82cf959 100644
--- a/drivers/i2c/chips/ds1337.c
+++ b/drivers/i2c/chips/ds1337.c
@@ -165,7 +165,7 @@
 	buf[0] = 0;		/* reg offset */
 	buf[1] = BIN2BCD(dt->tm_sec);
 	buf[2] = BIN2BCD(dt->tm_min);
-	buf[3] = BIN2BCD(dt->tm_hour) | (1 << 6);
+	buf[3] = BIN2BCD(dt->tm_hour);
 	buf[4] = BIN2BCD(dt->tm_wday) + 1;
 	buf[5] = BIN2BCD(dt->tm_mday);
 	buf[6] = BIN2BCD(dt->tm_mon) + 1;
@@ -344,9 +344,9 @@
 
 	/* Ensure that device is set in 24-hour mode */
 	val = i2c_smbus_read_byte_data(client, DS1337_REG_HOUR);
-	if ((val >= 0) && (val & (1 << 6)) == 0)
+	if ((val >= 0) && (val & (1 << 6)))
 		i2c_smbus_write_byte_data(client, DS1337_REG_HOUR,
-					  val | (1 << 6));
+					  val & 0x3f);
 }
 
 static int ds1337_detach_client(struct i2c_client *client)
diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c
index 6ea413f..a2da31b 100644
--- a/drivers/i2c/chips/eeprom.c
+++ b/drivers/i2c/chips/eeprom.c
@@ -163,6 +163,11 @@
 	struct eeprom_data *data;
 	int err = 0;
 
+	/* prevent 24RF08 corruption */
+	if (kind < 0)
+		i2c_smbus_xfer(adapter, address, 0, 0, 0,
+			       I2C_SMBUS_QUICK, NULL);
+
 	/* There are three ways we can read the EEPROM data:
 	   (1) I2C block reads (faster, but unsupported by most adapters)
 	   (2) Consecutive byte reads (100% overhead)
@@ -187,9 +192,6 @@
 	new_client->driver = &eeprom_driver;
 	new_client->flags = 0;
 
-	/* prevent 24RF08 corruption */
-	i2c_smbus_write_quick(new_client, 0);
-
 	/* Fill in the remaining client fields */
 	strlcpy(new_client->name, "eeprom", I2C_NAME_SIZE);
 	data->valid = 0;
diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c
index c4f14d9..0230375 100644
--- a/drivers/i2c/chips/max6875.c
+++ b/drivers/i2c/chips/max6875.c
@@ -343,6 +343,11 @@
 	struct max6875_data *data;
 	int err = 0;
 
+	/* Prevent 24RF08 corruption (in case of user error) */
+	if (kind < 0)
+		i2c_smbus_xfer(adapter, address, 0, 0, 0,
+			       I2C_SMBUS_QUICK, NULL);
+
 	/* There are three ways we can read the EEPROM data:
 	   (1) I2C block reads (faster, but unsupported by most adapters)
 	   (2) Consecutive byte reads (100% overhead)
@@ -370,9 +375,6 @@
 	new_client->driver = &max6875_driver;
 	new_client->flags = 0;
 
-	/* Prevent 24RF08 corruption */
-	i2c_smbus_write_quick(new_client, 0);
-
 	/* Setup the user section */
 	data->blocks[max6875_eeprom_user].type    = max6875_eeprom_user;
 	data->blocks[max6875_eeprom_user].slices  = USER_EEPROM_SLICES;
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 4fd4f52..4a9ead2 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -231,8 +231,8 @@
 		if (driver->detach_adapter)
 			if ((res = driver->detach_adapter(adap))) {
 				dev_warn(&adap->dev, "can't detach adapter "
-					 "while detaching driver %s: driver not "
-					 "detached!", driver->name);
+					 "while detaching driver %s: driver "
+					 "not detached!\n", driver->name);
 				goto out_unlock;
 			}
 	}
@@ -456,8 +456,8 @@
 		res = adapter->client_unregister(client);
 		if (res) {
 			dev_err(&client->dev,
-			       "client_unregister [%s] failed, "
-			       "client not detached", client->name);
+				"client_unregister [%s] failed, "
+				"client not detached\n", client->name);
 			goto out;
 		}
 	}
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
index aac5975..0374743 100644
--- a/drivers/ide/legacy/ide-cs.c
+++ b/drivers/ide/legacy/ide-cs.c
@@ -465,7 +465,7 @@
 	PCMCIA_DEVICE_PROD_ID12("CNF CD-M", "CD-ROM", 0x7d93b852, 0x66536591),
 	PCMCIA_DEVICE_PROD_ID12("Creative Technology Ltd.", "PCMCIA CD-ROM Interface Card", 0xff8c8a45, 0xfe8020c4),
 	PCMCIA_DEVICE_PROD_ID12("Digital Equipment Corporation.", "Digital Mobile Media CD-ROM", 0x17692a66, 0xef1dcbde),
-	PCMCIA_DEVICE_PROD_ID12("EXP", "CD", 0x6f58c983, 0xaae5994f),
+	PCMCIA_DEVICE_PROD_ID12("EXP", "CD+GAME", 0x6f58c983, 0x63c13aaf),
 	PCMCIA_DEVICE_PROD_ID12("EXP   ", "CD-ROM", 0x0a5c52fd, 0x66536591),
 	PCMCIA_DEVICE_PROD_ID12("EXP   ", "PnPIDE", 0x0a5c52fd, 0x0c694728),
 	PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e),
@@ -481,6 +481,7 @@
 	PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003),
 	PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852),
 	PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209),
+	PCMCIA_MFC_DEVICE_PROD_ID12(1, "SanDisk", "ConnectPlus", 0x7a954bd9, 0x74be00c6),
 	PCMCIA_DEVICE_NULL,
 };
 MODULE_DEVICE_TABLE(pcmcia, ide_ids);
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 374f404..20e3a16 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -320,6 +320,7 @@
 			if (t < 0 || t >= dev->keycodemax || !dev->keycodesize) return -EINVAL;
 			if (get_user(v, ip + 1)) return -EFAULT;
 			if (v < 0 || v > KEY_MAX) return -EINVAL;
+			if (v >> (dev->keycodesize * 8)) return -EINVAL;
 			u = SET_INPUT_KEYCODE(dev, t, v);
 			clear_bit(u, dev->keybit);
 			set_bit(v, dev->keybit);
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 7c4b4d3..a275211 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -48,12 +48,6 @@
 
 static struct input_handler *input_table[8];
 
-#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry *proc_bus_input_dir;
-static DECLARE_WAIT_QUEUE_HEAD(input_devices_poll_wait);
-static int input_devices_state;
-#endif
-
 void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
 	struct input_handle *handle;
@@ -312,6 +306,7 @@
 	return NULL;
 }
 
+
 /*
  * Input hotplugging interface - loading event handlers based on
  * device bitfields.
@@ -428,162 +423,27 @@
 
 #endif
 
-void input_register_device(struct input_dev *dev)
-{
-	struct input_handle *handle;
-	struct input_handler *handler;
-	struct input_device_id *id;
-
-	set_bit(EV_SYN, dev->evbit);
-
-	init_MUTEX(&dev->sem);
-
-	/*
-	 * If delay and period are pre-set by the driver, then autorepeating
-	 * is handled by the driver itself and we don't do it in input.c.
-	 */
-
-	init_timer(&dev->timer);
-	if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
-		dev->timer.data = (long) dev;
-		dev->timer.function = input_repeat_key;
-		dev->rep[REP_DELAY] = 250;
-		dev->rep[REP_PERIOD] = 33;
-	}
-
-	INIT_LIST_HEAD(&dev->h_list);
-	list_add_tail(&dev->node, &input_dev_list);
-
-	list_for_each_entry(handler, &input_handler_list, node)
-		if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
-			if ((id = input_match_device(handler->id_table, dev)))
-				if ((handle = handler->connect(handler, dev, id)))
-					input_link_handle(handle);
-
-#ifdef CONFIG_HOTPLUG
-	input_call_hotplug("add", dev);
-#endif
-
 #ifdef CONFIG_PROC_FS
+
+static struct proc_dir_entry *proc_bus_input_dir;
+static DECLARE_WAIT_QUEUE_HEAD(input_devices_poll_wait);
+static int input_devices_state;
+
+static inline void input_wakeup_procfs_readers(void)
+{
 	input_devices_state++;
 	wake_up(&input_devices_poll_wait);
-#endif
 }
 
-void input_unregister_device(struct input_dev *dev)
+static unsigned int input_devices_poll(struct file *file, poll_table *wait)
 {
-	struct list_head * node, * next;
-
-	if (!dev) return;
-
-	del_timer_sync(&dev->timer);
-
-	list_for_each_safe(node, next, &dev->h_list) {
-		struct input_handle * handle = to_handle(node);
-		list_del_init(&handle->d_node);
-		list_del_init(&handle->h_node);
-		handle->handler->disconnect(handle);
-	}
-
-#ifdef CONFIG_HOTPLUG
-	input_call_hotplug("remove", dev);
-#endif
-
-	list_del_init(&dev->node);
-
-#ifdef CONFIG_PROC_FS
-	input_devices_state++;
-	wake_up(&input_devices_poll_wait);
-#endif
+	int state = input_devices_state;
+	poll_wait(file, &input_devices_poll_wait, wait);
+	if (state != input_devices_state)
+		return POLLIN | POLLRDNORM;
+	return 0;
 }
 
-void input_register_handler(struct input_handler *handler)
-{
-	struct input_dev *dev;
-	struct input_handle *handle;
-	struct input_device_id *id;
-
-	if (!handler) return;
-
-	INIT_LIST_HEAD(&handler->h_list);
-
-	if (handler->fops != NULL)
-		input_table[handler->minor >> 5] = handler;
-
-	list_add_tail(&handler->node, &input_handler_list);
-
-	list_for_each_entry(dev, &input_dev_list, node)
-		if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
-			if ((id = input_match_device(handler->id_table, dev)))
-				if ((handle = handler->connect(handler, dev, id)))
-					input_link_handle(handle);
-
-#ifdef CONFIG_PROC_FS
-	input_devices_state++;
-	wake_up(&input_devices_poll_wait);
-#endif
-}
-
-void input_unregister_handler(struct input_handler *handler)
-{
-	struct list_head * node, * next;
-
-	list_for_each_safe(node, next, &handler->h_list) {
-		struct input_handle * handle = to_handle_h(node);
-		list_del_init(&handle->h_node);
-		list_del_init(&handle->d_node);
-		handler->disconnect(handle);
-	}
-
-	list_del_init(&handler->node);
-
-	if (handler->fops != NULL)
-		input_table[handler->minor >> 5] = NULL;
-
-#ifdef CONFIG_PROC_FS
-	input_devices_state++;
-	wake_up(&input_devices_poll_wait);
-#endif
-}
-
-static int input_open_file(struct inode *inode, struct file *file)
-{
-	struct input_handler *handler = input_table[iminor(inode) >> 5];
-	struct file_operations *old_fops, *new_fops = NULL;
-	int err;
-
-	/* No load-on-demand here? */
-	if (!handler || !(new_fops = fops_get(handler->fops)))
-		return -ENODEV;
-
-	/*
-	 * That's _really_ odd. Usually NULL ->open means "nothing special",
-	 * not "no device". Oh, well...
-	 */
-	if (!new_fops->open) {
-		fops_put(new_fops);
-		return -ENODEV;
-	}
-	old_fops = file->f_op;
-	file->f_op = new_fops;
-
-	err = new_fops->open(inode, file);
-
-	if (err) {
-		fops_put(file->f_op);
-		file->f_op = fops_get(old_fops);
-	}
-	fops_put(old_fops);
-	return err;
-}
-
-static struct file_operations input_fops = {
-	.owner = THIS_MODULE,
-	.open = input_open_file,
-};
-
-#ifdef CONFIG_PROC_FS
-
 #define SPRINTF_BIT_B(bit, name, max) \
 	do { \
 		len += sprintf(buf + len, "B: %s", name); \
@@ -600,16 +460,6 @@
 			SPRINTF_BIT_B(bit, name, max); \
 	} while (0)
 
-
-static unsigned int input_devices_poll(struct file *file, poll_table *wait)
-{
-	int state = input_devices_state;
-	poll_wait(file, &input_devices_poll_wait, wait);
-	if (state != input_devices_state)
-		return POLLIN | POLLRDNORM;
-	return 0;
-}
-
 static int input_devices_read(char *buf, char **start, off_t pos, int count, int *eof, void *data)
 {
 	struct input_dev *dev;
@@ -704,68 +554,225 @@
 	struct proc_dir_entry *entry;
 
 	proc_bus_input_dir = proc_mkdir("input", proc_bus);
-	if (proc_bus_input_dir == NULL)
+	if (!proc_bus_input_dir)
 		return -ENOMEM;
+
 	proc_bus_input_dir->owner = THIS_MODULE;
+
 	entry = create_proc_read_entry("devices", 0, proc_bus_input_dir, input_devices_read, NULL);
-	if (entry == NULL) {
-		remove_proc_entry("input", proc_bus);
-		return -ENOMEM;
-	}
+	if (!entry)
+		goto fail1;
+
 	entry->owner = THIS_MODULE;
 	input_fileops = *entry->proc_fops;
 	entry->proc_fops = &input_fileops;
 	entry->proc_fops->poll = input_devices_poll;
+
 	entry = create_proc_read_entry("handlers", 0, proc_bus_input_dir, input_handlers_read, NULL);
-	if (entry == NULL) {
-		remove_proc_entry("devices", proc_bus_input_dir);
-		remove_proc_entry("input", proc_bus);
-		return -ENOMEM;
-	}
+	if (!entry)
+		goto fail2;
+
 	entry->owner = THIS_MODULE;
+
 	return 0;
+
+ fail2:	remove_proc_entry("devices", proc_bus_input_dir);
+ fail1: remove_proc_entry("input", proc_bus);
+	return -ENOMEM;
 }
+
+static void input_proc_exit(void)
+{
+	remove_proc_entry("devices", proc_bus_input_dir);
+	remove_proc_entry("handlers", proc_bus_input_dir);
+	remove_proc_entry("input", proc_bus);
+}
+
 #else /* !CONFIG_PROC_FS */
+static inline void input_wakeup_procfs_readers(void) { }
 static inline int input_proc_init(void) { return 0; }
+static inline void input_proc_exit(void) { }
 #endif
 
+void input_register_device(struct input_dev *dev)
+{
+	struct input_handle *handle;
+	struct input_handler *handler;
+	struct input_device_id *id;
+
+	set_bit(EV_SYN, dev->evbit);
+
+	init_MUTEX(&dev->sem);
+
+	/*
+	 * If delay and period are pre-set by the driver, then autorepeating
+	 * is handled by the driver itself and we don't do it in input.c.
+	 */
+
+	init_timer(&dev->timer);
+	if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
+		dev->timer.data = (long) dev;
+		dev->timer.function = input_repeat_key;
+		dev->rep[REP_DELAY] = 250;
+		dev->rep[REP_PERIOD] = 33;
+	}
+
+	INIT_LIST_HEAD(&dev->h_list);
+	list_add_tail(&dev->node, &input_dev_list);
+
+	list_for_each_entry(handler, &input_handler_list, node)
+		if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
+			if ((id = input_match_device(handler->id_table, dev)))
+				if ((handle = handler->connect(handler, dev, id)))
+					input_link_handle(handle);
+
+#ifdef CONFIG_HOTPLUG
+	input_call_hotplug("add", dev);
+#endif
+
+	input_wakeup_procfs_readers();
+}
+
+void input_unregister_device(struct input_dev *dev)
+{
+	struct list_head * node, * next;
+
+	if (!dev) return;
+
+	del_timer_sync(&dev->timer);
+
+	list_for_each_safe(node, next, &dev->h_list) {
+		struct input_handle * handle = to_handle(node);
+		list_del_init(&handle->d_node);
+		list_del_init(&handle->h_node);
+		handle->handler->disconnect(handle);
+	}
+
+#ifdef CONFIG_HOTPLUG
+	input_call_hotplug("remove", dev);
+#endif
+
+	list_del_init(&dev->node);
+
+	input_wakeup_procfs_readers();
+}
+
+void input_register_handler(struct input_handler *handler)
+{
+	struct input_dev *dev;
+	struct input_handle *handle;
+	struct input_device_id *id;
+
+	if (!handler) return;
+
+	INIT_LIST_HEAD(&handler->h_list);
+
+	if (handler->fops != NULL)
+		input_table[handler->minor >> 5] = handler;
+
+	list_add_tail(&handler->node, &input_handler_list);
+
+	list_for_each_entry(dev, &input_dev_list, node)
+		if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
+			if ((id = input_match_device(handler->id_table, dev)))
+				if ((handle = handler->connect(handler, dev, id)))
+					input_link_handle(handle);
+
+	input_wakeup_procfs_readers();
+}
+
+void input_unregister_handler(struct input_handler *handler)
+{
+	struct list_head * node, * next;
+
+	list_for_each_safe(node, next, &handler->h_list) {
+		struct input_handle * handle = to_handle_h(node);
+		list_del_init(&handle->h_node);
+		list_del_init(&handle->d_node);
+		handler->disconnect(handle);
+	}
+
+	list_del_init(&handler->node);
+
+	if (handler->fops != NULL)
+		input_table[handler->minor >> 5] = NULL;
+
+	input_wakeup_procfs_readers();
+}
+
+static int input_open_file(struct inode *inode, struct file *file)
+{
+	struct input_handler *handler = input_table[iminor(inode) >> 5];
+	struct file_operations *old_fops, *new_fops = NULL;
+	int err;
+
+	/* No load-on-demand here? */
+	if (!handler || !(new_fops = fops_get(handler->fops)))
+		return -ENODEV;
+
+	/*
+	 * That's _really_ odd. Usually NULL ->open means "nothing special",
+	 * not "no device". Oh, well...
+	 */
+	if (!new_fops->open) {
+		fops_put(new_fops);
+		return -ENODEV;
+	}
+	old_fops = file->f_op;
+	file->f_op = new_fops;
+
+	err = new_fops->open(inode, file);
+
+	if (err) {
+		fops_put(file->f_op);
+		file->f_op = fops_get(old_fops);
+	}
+	fops_put(old_fops);
+	return err;
+}
+
+static struct file_operations input_fops = {
+	.owner = THIS_MODULE,
+	.open = input_open_file,
+};
+
 struct class *input_class;
 
 static int __init input_init(void)
 {
-	int retval = -ENOMEM;
+	int err;
 
 	input_class = class_create(THIS_MODULE, "input");
-	if (IS_ERR(input_class))
+	if (IS_ERR(input_class)) {
+		printk(KERN_ERR "input: unable to register input class\n");
 		return PTR_ERR(input_class);
-	input_proc_init();
-	retval = register_chrdev(INPUT_MAJOR, "input", &input_fops);
-	if (retval) {
-		printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
-		remove_proc_entry("devices", proc_bus_input_dir);
-		remove_proc_entry("handlers", proc_bus_input_dir);
-		remove_proc_entry("input", proc_bus);
-		class_destroy(input_class);
-		return retval;
 	}
 
-	retval = devfs_mk_dir("input");
-	if (retval) {
-		remove_proc_entry("devices", proc_bus_input_dir);
-		remove_proc_entry("handlers", proc_bus_input_dir);
-		remove_proc_entry("input", proc_bus);
-		unregister_chrdev(INPUT_MAJOR, "input");
-		class_destroy(input_class);
+	err = input_proc_init();
+	if (err)
+		goto fail1;
+
+	err = register_chrdev(INPUT_MAJOR, "input", &input_fops);
+	if (err) {
+		printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
+		goto fail2;
 	}
-	return retval;
+
+	err = devfs_mk_dir("input");
+	if (err)
+		goto fail3;
+
+	return 0;
+
+ fail3:	unregister_chrdev(INPUT_MAJOR, "input");
+ fail2:	input_proc_exit();
+ fail1:	class_destroy(input_class);
+	return err;
 }
 
 static void __exit input_exit(void)
 {
-	remove_proc_entry("devices", proc_bus_input_dir);
-	remove_proc_entry("handlers", proc_bus_input_dir);
-	remove_proc_entry("input", proc_bus);
-
+	input_proc_exit();
 	devfs_remove("input");
 	unregister_chrdev(INPUT_MAJOR, "input");
 	class_destroy(input_class);
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index ff8e1bb..e0938d1 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -37,8 +37,6 @@
 #define JOYDEV_MINORS		16
 #define JOYDEV_BUFFER_SIZE	64
 
-#define MSECS(t)	(1000 * ((t) / HZ) + 1000 * ((t) % HZ) / HZ)
-
 struct joydev {
 	int exist;
 	int open;
@@ -117,7 +115,7 @@
 			return;
 	}
 
-	event.time = MSECS(jiffies);
+	event.time = jiffies_to_msecs(jiffies);
 
 	list_for_each_entry(list, &joydev->list, node) {
 
@@ -245,7 +243,7 @@
 
 		struct js_event event;
 
-		event.time = MSECS(jiffies);
+		event.time = jiffies_to_msecs(jiffies);
 
 		if (list->startup < joydev->nkey) {
 			event.type = JS_EVENT_BUTTON | JS_EVENT_INIT;
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index 9871099..d5c5b32 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -36,16 +36,6 @@
 #include <linux/miscdevice.h>
 #include <linux/uinput.h>
 
-static int uinput_dev_open(struct input_dev *dev)
-{
-	return 0;
-}
-
-static void uinput_dev_close(struct input_dev *dev)
-{
-
-}
-
 static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
 	struct uinput_device	*udev;
@@ -63,22 +53,24 @@
 	return 0;
 }
 
-static int uinput_request_alloc_id(struct input_dev *dev, struct uinput_request *request)
+static int uinput_request_alloc_id(struct uinput_device *udev, struct uinput_request *request)
 {
 	/* Atomically allocate an ID for the given request. Returns 0 on success. */
-	struct uinput_device *udev = dev->private;
 	int id;
+	int err = -1;
 
-	down(&udev->requests_sem);
-	for (id=0; id<UINPUT_NUM_REQUESTS; id++)
+	spin_lock(&udev->requests_lock);
+
+	for (id = 0; id < UINPUT_NUM_REQUESTS; id++)
 		if (!udev->requests[id]) {
-			udev->requests[id] = request;
 			request->id = id;
-			up(&udev->requests_sem);
-			return 0;
+			udev->requests[id] = request;
+			err = 0;
+			break;
 		}
-	up(&udev->requests_sem);
-	return -1;
+
+	spin_unlock(&udev->requests_lock);
+	return err;
 }
 
 static struct uinput_request* uinput_request_find(struct uinput_device *udev, int id)
@@ -86,70 +78,78 @@
 	/* Find an input request, by ID. Returns NULL if the ID isn't valid. */
 	if (id >= UINPUT_NUM_REQUESTS || id < 0)
 		return NULL;
-	if (udev->requests[id]->completed)
-		return NULL;
 	return udev->requests[id];
 }
 
-static void uinput_request_init(struct input_dev *dev, struct uinput_request *request, int code)
+static inline int uinput_request_reserve_slot(struct uinput_device *udev, struct uinput_request *request)
 {
-	struct uinput_device *udev = dev->private;
-
-	memset(request, 0, sizeof(struct uinput_request));
-	request->code = code;
-	init_waitqueue_head(&request->waitq);
-
-	/* Allocate an ID. If none are available right away, wait. */
-	request->retval = wait_event_interruptible(udev->requests_waitq,
-				       !uinput_request_alloc_id(dev, request));
+	/* Allocate slot. If none are available right away, wait. */
+	return wait_event_interruptible(udev->requests_waitq,
+					!uinput_request_alloc_id(udev, request));
 }
 
-static void uinput_request_submit(struct input_dev *dev, struct uinput_request *request)
+static void uinput_request_done(struct uinput_device *udev, struct uinput_request *request)
 {
-	struct uinput_device *udev = dev->private;
+	complete(&request->done);
+
+	/* Mark slot as available */
+	udev->requests[request->id] = NULL;
+	wake_up_interruptible(&udev->requests_waitq);
+}
+
+static int uinput_request_submit(struct input_dev *dev, struct uinput_request *request)
+{
 	int retval;
 
 	/* Tell our userspace app about this new request by queueing an input event */
 	uinput_dev_event(dev, EV_UINPUT, request->code, request->id);
 
 	/* Wait for the request to complete */
-	retval = wait_event_interruptible(request->waitq, request->completed);
-	if (retval)
-		request->retval = retval;
+	retval = wait_for_completion_interruptible(&request->done);
+	if (!retval)
+		retval = request->retval;
 
-	/* Release this request's ID, let others know it's available */
-	udev->requests[request->id] = NULL;
-	wake_up_interruptible(&udev->requests_waitq);
+	return retval;
 }
 
 static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect)
 {
 	struct uinput_request request;
+	int retval;
 
 	if (!test_bit(EV_FF, dev->evbit))
 		return -ENOSYS;
 
-	uinput_request_init(dev, &request, UI_FF_UPLOAD);
-	if (request.retval)
-		return request.retval;
+	request.id = -1;
+	init_completion(&request.done);
+	request.code = UI_FF_UPLOAD;
 	request.u.effect = effect;
-	uinput_request_submit(dev, &request);
-	return request.retval;
+
+	retval = uinput_request_reserve_slot(dev->private, &request);
+	if (!retval)
+		retval = uinput_request_submit(dev, &request);
+
+	return retval;
 }
 
 static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
 {
 	struct uinput_request request;
+	int retval;
 
 	if (!test_bit(EV_FF, dev->evbit))
 		return -ENOSYS;
 
-	uinput_request_init(dev, &request, UI_FF_ERASE);
-	if (request.retval)
-		return request.retval;
+	request.id = -1;
+	init_completion(&request.done);
+	request.code = UI_FF_ERASE;
 	request.u.effect_id = effect_id;
-	uinput_request_submit(dev, &request);
-	return request.retval;
+
+	retval = uinput_request_reserve_slot(dev->private, &request);
+	if (!retval)
+		retval = uinput_request_submit(dev, &request);
+
+	return retval;
 }
 
 static int uinput_create_device(struct uinput_device *udev)
@@ -159,32 +159,30 @@
 		return -EINVAL;
 	}
 
-	udev->dev->open = uinput_dev_open;
-	udev->dev->close = uinput_dev_close;
 	udev->dev->event = uinput_dev_event;
 	udev->dev->upload_effect = uinput_dev_upload_effect;
 	udev->dev->erase_effect = uinput_dev_erase_effect;
 	udev->dev->private = udev;
 
-	init_waitqueue_head(&(udev->waitq));
+	init_waitqueue_head(&udev->waitq);
 
 	input_register_device(udev->dev);
 
-	set_bit(UIST_CREATED, &(udev->state));
+	set_bit(UIST_CREATED, &udev->state);
 
 	return 0;
 }
 
 static int uinput_destroy_device(struct uinput_device *udev)
 {
-	if (!test_bit(UIST_CREATED, &(udev->state))) {
+	if (!test_bit(UIST_CREATED, &udev->state)) {
 		printk(KERN_WARNING "%s: create the device first\n", UINPUT_NAME);
 		return -EINVAL;
 	}
 
 	input_unregister_device(udev->dev);
 
-	clear_bit(UIST_CREATED, &(udev->state));
+	clear_bit(UIST_CREATED, &udev->state);
 
 	return 0;
 }
@@ -198,7 +196,7 @@
 	if (!newdev)
 		goto error;
 	memset(newdev, 0, sizeof(struct uinput_device));
-	init_MUTEX(&newdev->requests_sem);
+	spin_lock_init(&newdev->requests_lock);
 	init_waitqueue_head(&newdev->requests_waitq);
 
 	newinput = kmalloc(sizeof(struct input_dev), GFP_KERNEL);
@@ -253,15 +251,16 @@
 	struct uinput_user_dev	*user_dev;
 	struct input_dev	*dev;
 	struct uinput_device	*udev;
-	int			size,
-				retval;
+	char			*name;
+	int			size;
+	int			retval;
 
 	retval = count;
 
 	udev = file->private_data;
 	dev = udev->dev;
 
-	user_dev = kmalloc(sizeof(*user_dev), GFP_KERNEL);
+	user_dev = kmalloc(sizeof(struct uinput_user_dev), GFP_KERNEL);
 	if (!user_dev) {
 		retval = -ENOMEM;
 		goto exit;
@@ -272,17 +271,17 @@
 		goto exit;
 	}
 
-	if (NULL != dev->name)
+	if (dev->name)
 		kfree(dev->name);
 
 	size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1;
-	dev->name = kmalloc(size, GFP_KERNEL);
-	if (!dev->name) {
+	dev->name = name = kmalloc(size, GFP_KERNEL);
+	if (!name) {
 		retval = -ENOMEM;
 		goto exit;
 	}
+	strlcpy(name, user_dev->name, size);
 
-	strlcpy(dev->name, user_dev->name, size);
 	dev->id.bustype	= user_dev->id.bustype;
 	dev->id.vendor	= user_dev->id.vendor;
 	dev->id.product	= user_dev->id.product;
@@ -314,14 +313,13 @@
 {
 	struct uinput_device *udev = file->private_data;
 
-	if (test_bit(UIST_CREATED, &(udev->state))) {
+	if (test_bit(UIST_CREATED, &udev->state)) {
 		struct input_event	ev;
 
 		if (copy_from_user(&ev, buffer, sizeof(struct input_event)))
 			return -EFAULT;
 		input_event(udev->dev, ev.type, ev.code, ev.value);
-	}
-	else
+	} else
 		count = uinput_alloc_device(file, buffer, count);
 
 	return count;
@@ -332,26 +330,24 @@
 	struct uinput_device *udev = file->private_data;
 	int retval = 0;
 
-	if (!test_bit(UIST_CREATED, &(udev->state)))
+	if (!test_bit(UIST_CREATED, &udev->state))
 		return -ENODEV;
 
-	if ((udev->head == udev->tail) && (file->f_flags & O_NONBLOCK))
+	if (udev->head == udev->tail && (file->f_flags & O_NONBLOCK))
 		return -EAGAIN;
 
 	retval = wait_event_interruptible(udev->waitq,
-			(udev->head != udev->tail) ||
-			!test_bit(UIST_CREATED, &(udev->state)));
-
+			udev->head != udev->tail || !test_bit(UIST_CREATED, &udev->state));
 	if (retval)
 		return retval;
 
-	if (!test_bit(UIST_CREATED, &(udev->state)))
+	if (!test_bit(UIST_CREATED, &udev->state))
 		return -ENODEV;
 
 	while ((udev->head != udev->tail) &&
 	    (retval + sizeof(struct input_event) <= count)) {
-		if (copy_to_user(buffer + retval, &(udev->buff[udev->tail]),
-		    sizeof(struct input_event))) return -EFAULT;
+		if (copy_to_user(buffer + retval, &udev->buff[udev->tail], sizeof(struct input_event)))
+			return -EFAULT;
 		udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE;
 		retval += sizeof(struct input_event);
 	}
@@ -373,12 +369,12 @@
 
 static int uinput_burn_device(struct uinput_device *udev)
 {
-	if (test_bit(UIST_CREATED, &(udev->state)))
+	if (test_bit(UIST_CREATED, &udev->state))
 		uinput_destroy_device(udev);
 
-	if (NULL != udev->dev->name)
+	if (udev->dev->name)
 		kfree(udev->dev->name);
-	if (NULL != udev->dev->phys)
+	if (udev->dev->phys)
 		kfree(udev->dev->phys);
 
 	kfree(udev->dev);
@@ -389,7 +385,8 @@
 
 static int uinput_close(struct inode *inode, struct file *file)
 {
-	return uinput_burn_device(file->private_data);
+	uinput_burn_device(file->private_data);
+	return 0;
 }
 
 static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
@@ -401,6 +398,7 @@
 	struct uinput_ff_erase  ff_erase;
 	struct uinput_request   *req;
 	int                     length;
+	char			*phys;
 
 	udev = file->private_data;
 
@@ -415,7 +413,7 @@
 		case UI_SET_SNDBIT:
 		case UI_SET_FFBIT:
 		case UI_SET_PHYS:
-			if (test_bit(UIST_CREATED, &(udev->state)))
+			if (test_bit(UIST_CREATED, &udev->state))
 				return -EINVAL;
 	}
 
@@ -498,20 +496,19 @@
 				retval = -EFAULT;
 				break;
 			}
-			if (NULL != udev->dev->phys)
-				kfree(udev->dev->phys);
-			udev->dev->phys = kmalloc(length, GFP_KERNEL);
-			if (!udev->dev->phys) {
+			kfree(udev->dev->phys);
+			udev->dev->phys = phys = kmalloc(length, GFP_KERNEL);
+			if (!phys) {
 				retval = -ENOMEM;
 				break;
 			}
-			if (copy_from_user(udev->dev->phys, p, length)) {
-				retval = -EFAULT;
-				kfree(udev->dev->phys);
+			if (copy_from_user(phys, p, length)) {
 				udev->dev->phys = NULL;
+				kfree(phys);
+				retval = -EFAULT;
 				break;
 			}
-			udev->dev->phys[length-1] = '\0';
+			phys[length - 1] = '\0';
 			break;
 
 		case UI_BEGIN_FF_UPLOAD:
@@ -520,7 +517,7 @@
 				break;
 			}
 			req = uinput_request_find(udev, ff_up.request_id);
-			if (!(req && req->code==UI_FF_UPLOAD && req->u.effect)) {
+			if (!(req && req->code == UI_FF_UPLOAD && req->u.effect)) {
 				retval = -EINVAL;
 				break;
 			}
@@ -538,7 +535,7 @@
 				break;
 			}
 			req = uinput_request_find(udev, ff_erase.request_id);
-			if (!(req && req->code==UI_FF_ERASE)) {
+			if (!(req && req->code == UI_FF_ERASE)) {
 				retval = -EINVAL;
 				break;
 			}
@@ -556,14 +553,13 @@
 				break;
 			}
 			req = uinput_request_find(udev, ff_up.request_id);
-			if (!(req && req->code==UI_FF_UPLOAD && req->u.effect)) {
+			if (!(req && req->code == UI_FF_UPLOAD && req->u.effect)) {
 				retval = -EINVAL;
 				break;
 			}
 			req->retval = ff_up.retval;
 			memcpy(req->u.effect, &ff_up.effect, sizeof(struct ff_effect));
-			req->completed = 1;
-			wake_up_interruptible(&req->waitq);
+			uinput_request_done(udev, req);
 			break;
 
 		case UI_END_FF_ERASE:
@@ -572,13 +568,12 @@
 				break;
 			}
 			req = uinput_request_find(udev, ff_erase.request_id);
-			if (!(req && req->code==UI_FF_ERASE)) {
+			if (!(req && req->code == UI_FF_ERASE)) {
 				retval = -EINVAL;
 				break;
 			}
 			req->retval = ff_erase.retval;
-			req->completed = 1;
-			wake_up_interruptible(&req->waitq);
+			uinput_request_done(udev, req);
 			break;
 
 		default:
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index a12e981..0d68e5e 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -2,7 +2,7 @@
  * ALPS touchpad PS/2 mouse driver
  *
  * Copyright (c) 2003 Neil Brown <neilb@cse.unsw.edu.au>
- * Copyright (c) 2003 Peter Osterlund <petero2@telia.com>
+ * Copyright (c) 2003-2005 Peter Osterlund <petero2@telia.com>
  * Copyright (c) 2004 Dmitry Torokhov <dtor@mail.ru>
  * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
  *
@@ -350,7 +350,6 @@
 static int alps_reconnect(struct psmouse *psmouse)
 {
 	struct alps_data *priv = psmouse->private;
-	unsigned char param[4];
 	int version;
 
 	psmouse_reset(psmouse);
@@ -358,21 +357,20 @@
 	if (!(priv->i = alps_get_model(psmouse, &version)))
 		return -1;
 
-	if (priv->i->flags & ALPS_PASS && alps_passthrough_mode(psmouse, 1))
+	if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 1))
 		return -1;
 
-	if (alps_get_status(psmouse, param))
-		return -1;
-
-	if (!(param[0] & 0x04))
-		alps_tap_mode(psmouse, 1);
-
-	if (alps_absolute_mode(psmouse)) {
-		printk(KERN_ERR "alps.c: Failed to enable absolute mode\n");
+	if (alps_tap_mode(psmouse, 1)) {
+		printk(KERN_WARNING "alps.c: Failed to reenable hardware tapping\n");
 		return -1;
 	}
 
-	if (priv->i->flags == ALPS_PASS && alps_passthrough_mode(psmouse, 0))
+	if (alps_absolute_mode(psmouse)) {
+		printk(KERN_ERR "alps.c: Failed to reenable absolute mode\n");
+		return -1;
+	}
+
+	if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 0))
 		return -1;
 
 	return 0;
@@ -389,7 +387,6 @@
 int alps_init(struct psmouse *psmouse)
 {
 	struct alps_data *priv;
-	unsigned char param[4];
 	int version;
 
 	psmouse->private = priv = kmalloc(sizeof(struct alps_data), GFP_KERNEL);
@@ -403,16 +400,8 @@
 	if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 1))
 		goto init_fail;
 
-	if (alps_get_status(psmouse, param)) {
-		printk(KERN_ERR "alps.c: touchpad status report request failed\n");
-		goto init_fail;
-	}
-
-	if (param[0] & 0x04) {
-		printk(KERN_INFO "alps.c: Enabling hardware tapping\n");
-		if (alps_tap_mode(psmouse, 1))
-			printk(KERN_WARNING "alps.c: Failed to enable hardware tapping\n");
-	}
+	if (alps_tap_mode(psmouse, 1))
+		printk(KERN_WARNING "alps.c: Failed to enable hardware tapping\n");
 
 	if (alps_absolute_mode(psmouse)) {
 		printk(KERN_ERR "alps.c: Failed to enable absolute mode\n");
diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c
index 5ab1bd7..48d2b20 100644
--- a/drivers/input/mouse/logips2pp.c
+++ b/drivers/input/mouse/logips2pp.c
@@ -385,8 +385,6 @@
 
 		if (buttons < 3)
 			clear_bit(BTN_MIDDLE, psmouse->dev.keybit);
-		if (buttons < 2)
-			clear_bit(BTN_RIGHT, psmouse->dev.keybit);
 
 		if (model_info)
 			ps2pp_set_model_properties(psmouse, model_info, use_ps2pp);
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 19785a6..2bb2fe7 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -344,6 +344,7 @@
 		return -1;
 
 	if (set_properties) {
+		set_bit(BTN_MIDDLE, psmouse->dev.keybit);
 		set_bit(REL_WHEEL, psmouse->dev.relbit);
 
 		if (!psmouse->vendor) psmouse->vendor = "Generic";
@@ -376,6 +377,7 @@
 		return -1;
 
 	if (set_properties) {
+		set_bit(BTN_MIDDLE, psmouse->dev.keybit);
 		set_bit(REL_WHEEL, psmouse->dev.relbit);
 		set_bit(BTN_SIDE, psmouse->dev.keybit);
 		set_bit(BTN_EXTRA, psmouse->dev.keybit);
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 36c7212..0293094 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -219,7 +219,7 @@
 		serio_interrupt(ptport, packet[1], 0, NULL);
 		serio_interrupt(ptport, packet[4], 0, NULL);
 		serio_interrupt(ptport, packet[5], 0, NULL);
-		if (child->type >= PSMOUSE_GENPS)
+		if (child->pktsize == 4)
 			serio_interrupt(ptport, packet[2], 0, NULL);
 	} else
 		serio_interrupt(ptport, packet[1], 0, NULL);
@@ -233,7 +233,7 @@
 
 	/* adjust the touchpad to child's choice of protocol */
 	if (child) {
-		if (child->type >= PSMOUSE_GENPS)
+		if (child->pktsize == 4)
 			priv->mode |= SYN_BIT_FOUR_BYTE_CLIENT;
 		else
 			priv->mode &= ~SYN_BIT_FOUR_BYTE_CLIENT;
@@ -608,6 +608,13 @@
 			DMI_MATCH(DMI_PRODUCT_NAME , "Satellite"),
 		},
 	},
+	{
+		.ident = "Toshiba Dynabook",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+			DMI_MATCH(DMI_PRODUCT_NAME , "dynabook"),
+		},
+	},
 	{ }
 };
 #endif
@@ -656,7 +663,8 @@
 	 * thye same as rate of standard PS/2 mouse.
 	 */
 	if (psmouse->rate >= 80 && dmi_check_system(toshiba_dmi_table)) {
-		printk(KERN_INFO "synaptics: Toshiba Satellite detected, limiting rate to 40pps.\n");
+		printk(KERN_INFO "synaptics: Toshiba %s detected, limiting rate to 40pps.\n",
+			dmi_get_system_info(DMI_PRODUCT_NAME));
 		psmouse->rate = 40;
 	}
 #endif
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index b371073..98acf17 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -175,7 +175,7 @@
 	  allocating minor 1 (that historically corresponds to /dev/psaux)
 	  first. To bind this driver to a serio port use sysfs interface:
 
-	      echo -n "serio_raw" > /sys/bus/serio/devices/serioX/driver
+	      echo -n "serio_raw" > /sys/bus/serio/devices/serioX/drvctl
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called serio_raw.
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 0487ecb..03877c8 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -131,12 +131,26 @@
 		},
 	},
 	{
+		.ident = "Fujitsu-Siemens Lifebook T3010",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T3010"),
+		},
+	},
+	{
 		.ident = "Toshiba P10",
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
 			DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P10"),
 		},
 	},
+	{
+		.ident = "Alienware Sentia",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "ALIENWARE"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Sentia"),
+		},
+	},
 	{ }
 };
 
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index a9bf549..708a1d3 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -100,7 +100,7 @@
 static struct i8042_port i8042_ports[I8042_NUM_PORTS] = {
 	{
 		.disable	= I8042_CTR_KBDDIS,
-		.irqen 		= I8042_CTR_KBDINT,
+		.irqen		= I8042_CTR_KBDINT,
 		.mux		= -1,
 		.name		= "KBD",
 	},
@@ -191,41 +191,45 @@
 static int i8042_command(unsigned char *param, int command)
 {
 	unsigned long flags;
-	int retval = 0, i = 0;
+	int i, retval, auxerr = 0;
 
 	if (i8042_noloop && command == I8042_CMD_AUX_LOOP)
 		return -1;
 
 	spin_lock_irqsave(&i8042_lock, flags);
 
-	retval = i8042_wait_write();
-	if (!retval) {
-		dbg("%02x -> i8042 (command)", command & 0xff);
-		i8042_write_command(command & 0xff);
+	if ((retval = i8042_wait_write()))
+		goto out;
+
+	dbg("%02x -> i8042 (command)", command & 0xff);
+	i8042_write_command(command & 0xff);
+
+	for (i = 0; i < ((command >> 12) & 0xf); i++) {
+		if ((retval = i8042_wait_write()))
+			goto out;
+		dbg("%02x -> i8042 (parameter)", param[i]);
+		i8042_write_data(param[i]);
 	}
 
-	if (!retval)
-		for (i = 0; i < ((command >> 12) & 0xf); i++) {
-			if ((retval = i8042_wait_write())) break;
-			dbg("%02x -> i8042 (parameter)", param[i]);
-			i8042_write_data(param[i]);
+	for (i = 0; i < ((command >> 8) & 0xf); i++) {
+		if ((retval = i8042_wait_read()))
+			goto out;
+
+		if (command == I8042_CMD_AUX_LOOP &&
+		    !(i8042_read_status() & I8042_STR_AUXDATA)) {
+			retval = auxerr = -1;
+			goto out;
 		}
 
-	if (!retval)
-		for (i = 0; i < ((command >> 8) & 0xf); i++) {
-			if ((retval = i8042_wait_read())) break;
-			if (i8042_read_status() & I8042_STR_AUXDATA)
-				param[i] = ~i8042_read_data();
-			else
-				param[i] = i8042_read_data();
-			dbg("%02x <- i8042 (return)", param[i]);
-		}
-
-	spin_unlock_irqrestore(&i8042_lock, flags);
+		param[i] = i8042_read_data();
+		dbg("%02x <- i8042 (return)", param[i]);
+	}
 
 	if (retval)
-		dbg("     -- i8042 (timeout)");
+		dbg("     -- i8042 (%s)", auxerr ? "auxerr" : "timeout");
 
+ out:
+	spin_unlock_irqrestore(&i8042_lock, flags);
 	return retval;
 }
 
@@ -507,17 +511,17 @@
  */
 
 	param = 0xf0;
-	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0x0f)
+	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0xf0)
 		return -1;
 	param = mode ? 0x56 : 0xf6;
-	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != (mode ? 0xa9 : 0x09))
+	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != (mode ? 0x56 : 0xf6))
 		return -1;
 	param = mode ? 0xa4 : 0xa5;
-	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param == (mode ? 0x5b : 0x5a))
+	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param == (mode ? 0xa4 : 0xa5))
 		return -1;
 
 	if (mux_version)
-		*mux_version = ~param;
+		*mux_version = param;
 
 	return 0;
 }
@@ -619,7 +623,7 @@
  */
 
 	param = 0x5a;
-	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0xa5) {
+	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0x5a) {
 
 /*
  * External connection test - filters out AT-soldered PS/2 i8042's
@@ -630,7 +634,7 @@
  */
 
 		if (i8042_command(&param, I8042_CMD_AUX_TEST)
-		    	|| (param && param != 0xfa && param != 0xff))
+			|| (param && param != 0xfa && param != 0xff))
 				return -1;
 	}
 
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index f367695..edd15db 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -389,6 +389,14 @@
 	return sprintf(buf, "%s\n", serio->name);
 }
 
+static ssize_t serio_show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct serio *serio = to_serio_port(dev);
+
+	return sprintf(buf, "serio:ty%02Xpr%02Xid%02Xex%02X\n",
+			serio->id.type, serio->id.proto, serio->id.id, serio->id.extra);
+}
+
 static ssize_t serio_show_id_type(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct serio *serio = to_serio_port(dev);
@@ -487,6 +495,7 @@
 
 static struct device_attribute serio_device_attrs[] = {
 	__ATTR(description, S_IRUGO, serio_show_description, NULL),
+	__ATTR(modalias, S_IRUGO, serio_show_modalias, NULL),
 	__ATTR(drvctl, S_IWUSR, NULL, serio_rebind_driver),
 	__ATTR(bind_mode, S_IWUSR | S_IRUGO, serio_show_bind_mode, serio_set_bind_mode),
 	__ATTR_NULL
@@ -785,36 +794,37 @@
 
 #ifdef CONFIG_HOTPLUG
 
-#define PUT_ENVP(fmt, val) 						\
-do {									\
-	envp[i++] = buffer;						\
-	length += snprintf(buffer, buffer_size - length, fmt, val);	\
-	if (buffer_size - length <= 0 || i >= num_envp)			\
-		return -ENOMEM;						\
-	length++;							\
-	buffer += length;						\
-} while (0)
+#define SERIO_ADD_HOTPLUG_VAR(fmt, val...)				\
+	do {								\
+		int err = add_hotplug_env_var(envp, num_envp, &i,	\
+					buffer, buffer_size, &len,	\
+					fmt, val);			\
+		if (err)						\
+			return err;					\
+	} while (0)
+
 static int serio_hotplug(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
 {
 	struct serio *serio;
 	int i = 0;
-	int length = 0;
+	int len = 0;
 
 	if (!dev)
 		return -ENODEV;
 
 	serio = to_serio_port(dev);
 
-	PUT_ENVP("SERIO_TYPE=%02x", serio->id.type);
-	PUT_ENVP("SERIO_PROTO=%02x", serio->id.proto);
-	PUT_ENVP("SERIO_ID=%02x", serio->id.id);
-	PUT_ENVP("SERIO_EXTRA=%02x", serio->id.extra);
-
+	SERIO_ADD_HOTPLUG_VAR("SERIO_TYPE=%02x", serio->id.type);
+	SERIO_ADD_HOTPLUG_VAR("SERIO_PROTO=%02x", serio->id.proto);
+	SERIO_ADD_HOTPLUG_VAR("SERIO_ID=%02x", serio->id.id);
+	SERIO_ADD_HOTPLUG_VAR("SERIO_EXTRA=%02x", serio->id.extra);
+	SERIO_ADD_HOTPLUG_VAR("MODALIAS=serio:ty%02Xpr%02Xid%02Xex%02X",
+				serio->id.type, serio->id.proto, serio->id.id, serio->id.extra);
 	envp[i] = NULL;
 
 	return 0;
 }
-#undef PUT_ENVP
+#undef SERIO_ADD_HOTPLUG_VAR
 
 #else
 
diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c
index d914e7e..47e08de 100644
--- a/drivers/input/serio/serio_raw.c
+++ b/drivers/input/serio/serio_raw.c
@@ -299,6 +299,7 @@
 
 	serio_raw->dev.minor = PSMOUSE_MINOR;
 	serio_raw->dev.name = serio_raw->name;
+	serio_raw->dev.dev = &serio->dev;
 	serio_raw->dev.fops = &serio_raw_fops;
 
 	err = misc_register(&serio_raw->dev);
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 7e99127..0489af5 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -58,7 +58,7 @@
 	  If unsure, say N.
 
 	  To compile this driver as a module, choose M here: the
-	  module will be called gunze.
+	  module will be called elo.
 
 config TOUCHSCREEN_MTOUCH
 	tristate "MicroTouch serial touchscreens"
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index a5a4c0e..a6d3baa 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -869,11 +869,17 @@
 
 void dm_table_presuspend_targets(struct dm_table *t)
 {
+	if (!t)
+		return;
+
 	return suspend_targets(t, 0);
 }
 
 void dm_table_postsuspend_targets(struct dm_table *t)
 {
+	if (!t)
+		return;
+
 	return suspend_targets(t, 1);
 }
 
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 54fabbf..d487d9d 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -55,10 +55,10 @@
  */
 #define DMF_BLOCK_IO 0
 #define DMF_SUSPENDED 1
-#define DMF_FS_LOCKED 2
 
 struct mapped_device {
-	struct rw_semaphore lock;
+	struct rw_semaphore io_lock;
+	struct semaphore suspend_lock;
 	rwlock_t map_lock;
 	atomic_t holders;
 
@@ -248,16 +248,16 @@
  */
 static int queue_io(struct mapped_device *md, struct bio *bio)
 {
-	down_write(&md->lock);
+	down_write(&md->io_lock);
 
 	if (!test_bit(DMF_BLOCK_IO, &md->flags)) {
-		up_write(&md->lock);
+		up_write(&md->io_lock);
 		return 1;
 	}
 
 	bio_list_add(&md->deferred, bio);
 
-	up_write(&md->lock);
+	up_write(&md->io_lock);
 	return 0;		/* deferred successfully */
 }
 
@@ -568,14 +568,14 @@
 	int r;
 	struct mapped_device *md = q->queuedata;
 
-	down_read(&md->lock);
+	down_read(&md->io_lock);
 
 	/*
 	 * If we're suspended we have to queue
 	 * this io for later.
 	 */
 	while (test_bit(DMF_BLOCK_IO, &md->flags)) {
-		up_read(&md->lock);
+		up_read(&md->io_lock);
 
 		if (bio_rw(bio) == READA) {
 			bio_io_error(bio, bio->bi_size);
@@ -594,11 +594,11 @@
 		 * We're in a while loop, because someone could suspend
 		 * before we get to the following read lock.
 		 */
-		down_read(&md->lock);
+		down_read(&md->io_lock);
 	}
 
 	__split_bio(md, bio);
-	up_read(&md->lock);
+	up_read(&md->io_lock);
 	return 0;
 }
 
@@ -610,7 +610,7 @@
 	int ret = -ENXIO;
 
 	if (map) {
-		ret = dm_table_flush_all(md->map);
+		ret = dm_table_flush_all(map);
 		dm_table_put(map);
 	}
 
@@ -747,7 +747,8 @@
 		goto bad1;
 
 	memset(md, 0, sizeof(*md));
-	init_rwsem(&md->lock);
+	init_rwsem(&md->io_lock);
+	init_MUTEX(&md->suspend_lock);
 	rwlock_init(&md->map_lock);
 	atomic_set(&md->holders, 1);
 	atomic_set(&md->event_nr, 0);
@@ -825,18 +826,13 @@
 	wake_up(&md->eventq);
 }
 
-static void __set_size(struct gendisk *disk, sector_t size)
+static void __set_size(struct mapped_device *md, sector_t size)
 {
-	struct block_device *bdev;
+	set_capacity(md->disk, size);
 
-	set_capacity(disk, size);
-	bdev = bdget_disk(disk, 0);
-	if (bdev) {
-		down(&bdev->bd_inode->i_sem);
-		i_size_write(bdev->bd_inode, (loff_t)size << SECTOR_SHIFT);
-		up(&bdev->bd_inode->i_sem);
-		bdput(bdev);
-	}
+	down(&md->frozen_bdev->bd_inode->i_sem);
+	i_size_write(md->frozen_bdev->bd_inode, (loff_t)size << SECTOR_SHIFT);
+	up(&md->frozen_bdev->bd_inode->i_sem);
 }
 
 static int __bind(struct mapped_device *md, struct dm_table *t)
@@ -845,17 +841,18 @@
 	sector_t size;
 
 	size = dm_table_get_size(t);
-	__set_size(md->disk, size);
+	__set_size(md, size);
 	if (size == 0)
 		return 0;
 
+	dm_table_get(t);
+	dm_table_event_callback(t, event_callback, md);
+
 	write_lock(&md->map_lock);
 	md->map = t;
+	dm_table_set_restrictions(t, q);
 	write_unlock(&md->map_lock);
 
-	dm_table_get(t);
-	dm_table_event_callback(md->map, event_callback, md);
-	dm_table_set_restrictions(t, q);
 	return 0;
 }
 
@@ -935,7 +932,7 @@
 	struct dm_table *map = dm_get_table(md);
 
 	if (atomic_dec_and_test(&md->holders)) {
-		if (!test_bit(DMF_SUSPENDED, &md->flags) && map) {
+		if (!dm_suspended(md)) {
 			dm_table_presuspend_targets(map);
 			dm_table_postsuspend_targets(map);
 		}
@@ -968,17 +965,17 @@
 {
 	int r = -EINVAL;
 
-	down_write(&md->lock);
+	down(&md->suspend_lock);
 
 	/* device must be suspended */
-	if (!test_bit(DMF_SUSPENDED, &md->flags))
+	if (!dm_suspended(md))
 		goto out;
 
 	__unbind(md);
 	r = __bind(md, table);
 
 out:
-	up_write(&md->lock);
+	up(&md->suspend_lock);
 	return r;
 }
 
@@ -986,16 +983,13 @@
  * Functions to lock and unlock any filesystem running on the
  * device.
  */
-static int __lock_fs(struct mapped_device *md)
+static int lock_fs(struct mapped_device *md)
 {
-	int error = -ENOMEM;
-
-	if (test_and_set_bit(DMF_FS_LOCKED, &md->flags))
-		return 0;
+	int r = -ENOMEM;
 
 	md->frozen_bdev = bdget_disk(md->disk, 0);
 	if (!md->frozen_bdev) {
-		DMWARN("bdget failed in __lock_fs");
+		DMWARN("bdget failed in lock_fs");
 		goto out;
 	}
 
@@ -1003,13 +997,13 @@
 
 	md->frozen_sb = freeze_bdev(md->frozen_bdev);
 	if (IS_ERR(md->frozen_sb)) {
-		error = PTR_ERR(md->frozen_sb);
+		r = PTR_ERR(md->frozen_sb);
 		goto out_bdput;
 	}
 
 	/* don't bdput right now, we don't want the bdev
 	 * to go away while it is locked.  We'll bdput
-	 * in __unlock_fs
+	 * in unlock_fs
 	 */
 	return 0;
 
@@ -1018,15 +1012,11 @@
 	md->frozen_sb = NULL;
 	md->frozen_bdev = NULL;
 out:
-	clear_bit(DMF_FS_LOCKED, &md->flags);
-	return error;
+	return r;
 }
 
-static void __unlock_fs(struct mapped_device *md)
+static void unlock_fs(struct mapped_device *md)
 {
-	if (!test_and_clear_bit(DMF_FS_LOCKED, &md->flags))
-		return;
-
 	thaw_bdev(md->frozen_bdev, md->frozen_sb);
 	bdput(md->frozen_bdev);
 
@@ -1043,50 +1033,37 @@
  */
 int dm_suspend(struct mapped_device *md)
 {
-	struct dm_table *map;
+	struct dm_table *map = NULL;
 	DECLARE_WAITQUEUE(wait, current);
-	int error = -EINVAL;
+	int r = -EINVAL;
 
-	/* Flush I/O to the device. */
-	down_read(&md->lock);
-	if (test_bit(DMF_BLOCK_IO, &md->flags))
-		goto out_read_unlock;
+	down(&md->suspend_lock);
+
+	if (dm_suspended(md))
+		goto out;
 
 	map = dm_get_table(md);
-	if (map)
-		/* This does not get reverted if there's an error later. */
-		dm_table_presuspend_targets(map);
 
-	error = __lock_fs(md);
-	if (error) {
-		dm_table_put(map);
-		goto out_read_unlock;
-	}
+	/* This does not get reverted if there's an error later. */
+	dm_table_presuspend_targets(map);
 
-	up_read(&md->lock);
+	/* Flush I/O to the device. */
+	r = lock_fs(md);
+	if (r)
+		goto out;
 
 	/*
 	 * First we set the BLOCK_IO flag so no more ios will be mapped.
-	 *
-	 * If the flag is already set we know another thread is trying to
-	 * suspend as well, so we leave the fs locked for this thread.
 	 */
-	error = -EINVAL;
-	down_write(&md->lock);
-	if (test_and_set_bit(DMF_BLOCK_IO, &md->flags)) {
-		if (map)
-			dm_table_put(map);
-		goto out_write_unlock;
-	}
+	down_write(&md->io_lock);
+	set_bit(DMF_BLOCK_IO, &md->flags);
 
 	add_wait_queue(&md->wait, &wait);
-	up_write(&md->lock);
+	up_write(&md->io_lock);
 
 	/* unplug */
-	if (map) {
+	if (map)
 		dm_table_unplug_all(map);
-		dm_table_put(map);
-	}
 
 	/*
 	 * Then we wait for the already mapped ios to
@@ -1102,62 +1079,67 @@
 	}
 	set_current_state(TASK_RUNNING);
 
-	down_write(&md->lock);
+	down_write(&md->io_lock);
 	remove_wait_queue(&md->wait, &wait);
 
 	/* were we interrupted ? */
-	error = -EINTR;
-	if (atomic_read(&md->pending))
-		goto out_unfreeze;
+	r = -EINTR;
+	if (atomic_read(&md->pending)) {
+		up_write(&md->io_lock);
+		unlock_fs(md);
+		clear_bit(DMF_BLOCK_IO, &md->flags);
+		goto out;
+	}
+	up_write(&md->io_lock);
+
+	dm_table_postsuspend_targets(map);
 
 	set_bit(DMF_SUSPENDED, &md->flags);
 
-	map = dm_get_table(md);
-	if (map)
-		dm_table_postsuspend_targets(map);
+	r = 0;
+
+out:
 	dm_table_put(map);
-	up_write(&md->lock);
-
-	return 0;
-
-out_unfreeze:
-	__unlock_fs(md);
-	clear_bit(DMF_BLOCK_IO, &md->flags);
-out_write_unlock:
-	up_write(&md->lock);
-	return error;
-
-out_read_unlock:
-	up_read(&md->lock);
-	return error;
+	up(&md->suspend_lock);
+	return r;
 }
 
 int dm_resume(struct mapped_device *md)
 {
+	int r = -EINVAL;
 	struct bio *def;
-	struct dm_table *map = dm_get_table(md);
+	struct dm_table *map = NULL;
 
-	down_write(&md->lock);
-	if (!map ||
-	    !test_bit(DMF_SUSPENDED, &md->flags) ||
-	    !dm_table_get_size(map)) {
-		up_write(&md->lock);
-		dm_table_put(map);
-		return -EINVAL;
-	}
+	down(&md->suspend_lock);
+	if (!dm_suspended(md))
+		goto out;
+
+	map = dm_get_table(md);
+	if (!map || !dm_table_get_size(map))
+		goto out;
 
 	dm_table_resume_targets(map);
-	clear_bit(DMF_SUSPENDED, &md->flags);
+
+	down_write(&md->io_lock);
 	clear_bit(DMF_BLOCK_IO, &md->flags);
 
 	def = bio_list_get(&md->deferred);
 	__flush_deferred_io(md, def);
-	up_write(&md->lock);
-	__unlock_fs(md);
-	dm_table_unplug_all(map);
-	dm_table_put(map);
+	up_write(&md->io_lock);
 
-	return 0;
+	unlock_fs(md);
+
+	clear_bit(DMF_SUSPENDED, &md->flags);
+
+	dm_table_unplug_all(map);
+
+	r = 0;
+
+out:
+	dm_table_put(map);
+	up(&md->suspend_lock);
+
+	return r;
 }
 
 /*-----------------------------------------------------------------
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index b96d6fb..2c6dc24 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -1450,6 +1450,7 @@
 	/* Write the contents of the packet */
 	outsw(dev->base_addr + TX_FRAME_PORT,skb->data,(skb->len+1) >>1);
 	spin_unlock_irq(&lp->lock);
+	lp->stats.tx_bytes += skb->len;
 	dev->trans_start = jiffies;
 	dev_kfree_skb (skb);
 
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index cb7f051..5e5d2c3 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -162,7 +162,6 @@
 static void e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
 static void e1000_restore_vlan(struct e1000_adapter *adapter);
 
-static int e1000_notify_reboot(struct notifier_block *, unsigned long event, void *ptr);
 static int e1000_suspend(struct pci_dev *pdev, uint32_t state);
 #ifdef CONFIG_PM
 static int e1000_resume(struct pci_dev *pdev);
@@ -173,12 +172,6 @@
 static void e1000_netpoll (struct net_device *netdev);
 #endif
 
-struct notifier_block e1000_notifier_reboot = {
-	.notifier_call	= e1000_notify_reboot,
-	.next		= NULL,
-	.priority	= 0
-};
-
 /* Exported from other modules */
 
 extern void e1000_check_options(struct e1000_adapter *adapter);
@@ -221,9 +214,7 @@
 	printk(KERN_INFO "%s\n", e1000_copyright);
 
 	ret = pci_module_init(&e1000_driver);
-	if(ret >= 0) {
-		register_reboot_notifier(&e1000_notifier_reboot);
-	}
+
 	return ret;
 }
 
@@ -239,7 +230,6 @@
 static void __exit
 e1000_exit_module(void)
 {
-	unregister_reboot_notifier(&e1000_notifier_reboot);
 	pci_unregister_driver(&e1000_driver);
 }
 
@@ -3652,23 +3642,6 @@
 }
 
 static int
-e1000_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
-{
-	struct pci_dev *pdev = NULL;
-
-	switch(event) {
-	case SYS_DOWN:
-	case SYS_HALT:
-	case SYS_POWER_OFF:
-		while((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev))) {
-			if(pci_dev_driver(pdev) == &e1000_driver)
-				e1000_suspend(pdev, 3);
-		}
-	}
-	return NOTIFY_DONE;
-}
-
-static int
 e1000_suspend(struct pci_dev *pdev, uint32_t state)
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
index dbb9410..980d7e5 100644
--- a/drivers/net/pcmcia/nmclan_cs.c
+++ b/drivers/net/pcmcia/nmclan_cs.c
@@ -1671,7 +1671,7 @@
 
 static struct pcmcia_device_id nmclan_ids[] = {
 	PCMCIA_DEVICE_PROD_ID12("New Media Corporation", "Ethernet", 0x085a850b, 0x00b2e941),
-	PCMCIA_DEVICE_PROD_ID12("Portable Add-ons", "Ethernet", 0x0ebf1d60, 0x00b2e941),
+	PCMCIA_DEVICE_PROD_ID12("Portable Add-ons", "Ethernet+", 0xebf1d60, 0xad673aaf),
 	PCMCIA_DEVICE_NULL,
 };
 MODULE_DEVICE_TABLE(pcmcia, nmclan_ids);
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index e1664ae..9f22d138 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -1639,7 +1639,7 @@
 	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0143, 0xc0ab),
 	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x021b, 0x0101),
 	PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x08a1, 0xc0ab),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "AnyCom", "Fast Ethernet ", 0x578ba6e7, 0x02d92d1e),
+	PCMCIA_PFC_DEVICE_PROD_ID12(0, "AnyCom", "Fast Ethernet + 56K COMBO", 0x578ba6e7, 0xb0ac62c4),
 	PCMCIA_PFC_DEVICE_PROD_ID12(0, "D-Link", "DME336T", 0x1a424a1c, 0xb23897ff),
 	PCMCIA_PFC_DEVICE_PROD_ID12(0, "Grey Cell", "GCS3000", 0x2a151fac, 0x48b932ae),
 	PCMCIA_PFC_DEVICE_PROD_ID12(0, "Linksys", "EtherFast 10&100 + 56K PC Card (PCMLM56)", 0x0733cc81, 0xb3765033),
@@ -1683,7 +1683,6 @@
 	PCMCIA_DEVICE_PROD_ID12("ACCTON", "EN2212", 0xdfc6b5b2, 0xcb112a11),
 	PCMCIA_DEVICE_PROD_ID12("ACCTON", "EN2216-PCMCIA-ETHERNET", 0xdfc6b5b2, 0x5542bfff),
 	PCMCIA_DEVICE_PROD_ID12("Allied Telesis, K.K.", "CentreCOM LA100-PCM-T V2 100/10M LAN PC Card", 0xbb7fbdd7, 0xcd91cc68),
-	PCMCIA_DEVICE_PROD_ID12("Allied Telesis, K.K.", "CentreCOM LA-PCM", 0xbb7fbdd7, 0x5ba10d49),
 	PCMCIA_DEVICE_PROD_ID12("Allied Telesis K.K.", "LA100-PCM V2", 0x36634a66, 0xc6d05997),
   	PCMCIA_DEVICE_PROD_ID12("Allied Telesis, K.K.", "CentreCOM LA-PCM_V2", 0xbb7fBdd7, 0x28e299f8),
 	PCMCIA_DEVICE_PROD_ID12("Allied Telesis K.K.", "LA-PCM V3", 0x36634a66, 0x62241d96),
@@ -1719,6 +1718,7 @@
 	PCMCIA_DEVICE_PROD_ID12("DIGITAL", "DEPCM-XX", 0x69616cb3, 0xe600e76e),
 	PCMCIA_DEVICE_PROD_ID12("D-Link", "DE-650", 0x1a424a1c, 0xf28c8398),
 	PCMCIA_DEVICE_PROD_ID12("D-Link", "DE-660", 0x1a424a1c, 0xd9a1d05b),
+	PCMCIA_DEVICE_PROD_ID12("D-Link", "DE-660+", 0x1a424a1c, 0x50dcd0ec),
 	PCMCIA_DEVICE_PROD_ID12("D-Link", "DFE-650", 0x1a424a1c, 0x0f0073f9),
 	PCMCIA_DEVICE_PROD_ID12("Dual Speed", "10/100 PC Card", 0x725b842d, 0xf1efee84),
 	PCMCIA_DEVICE_PROD_ID12("Dual Speed", "10/100 Port Attached PC Card", 0x725b842d, 0x2db1f8e9),
@@ -1737,6 +1737,7 @@
 	PCMCIA_DEVICE_PROD_ID12("GVC", "NIC-2000p", 0x76e171bd, 0x6eb1c947),
 	PCMCIA_DEVICE_PROD_ID12("IBM Corp.", "Ethernet", 0xe3736c88, 0x00b2e941),
 	PCMCIA_DEVICE_PROD_ID12("IC-CARD", "IC-CARD", 0x60cb09a6, 0x60cb09a6),
+	PCMCIA_DEVICE_PROD_ID12("IC-CARD+", "IC-CARD+", 0x93693494, 0x93693494),
 	PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCETTX", 0x547e66dc, 0x6fc5459b),
 	PCMCIA_DEVICE_PROD_ID12("iPort", "10/100 Ethernet Card", 0x56c538d2, 0x11b0ffc0),
 	PCMCIA_DEVICE_PROD_ID12("KANSAI ELECTRIC CO.,LTD", "KLA-PCM/T", 0xb18dc3b4, 0xcc51a956),
@@ -1753,7 +1754,7 @@
 	PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 Integrated PC Card (PCM100)", 0x0733cc81, 0x453c3f9d),
 	PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 PC Card (PCMPC100)", 0x0733cc81, 0x66c5a389),
 	PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 PC Card (PCMPC100 V2)", 0x0733cc81, 0x3a3b28e9),
-	PCMCIA_DEVICE_PROD_ID12("Linksys", "HomeLink Phoneline ", 0x0733cc81, 0x5e07cfa0),
+	PCMCIA_DEVICE_PROD_ID12("Linksys", "HomeLink Phoneline + 10/100 Network PC Card (PCM100H1)", 0x733cc81, 0x7a3e5c3a),
 	PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN100TX", 0x88fcdeda, 0x6d772737),
 	PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN20T", 0x88fcdeda, 0x81090922),
 	PCMCIA_DEVICE_PROD_ID12("LONGSHINE", "PCMCIA Ethernet Card", 0xf866b0b0, 0x6f6652e0),
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index 0d8bb4c..d652e1ed 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -2332,8 +2332,8 @@
 	PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "XJEM1144/CCEM1144", "PCMCIA MODEM", 0xf510db04, 0x52d21e1e, 0xbd6c43ef),
 	PCMCIA_PFC_DEVICE_PROD_ID12(0, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x662c394c),
 	PCMCIA_PFC_DEVICE_PROD_ID12(0, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard", 0x0c2f80cd, 0x0573c29f),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard", 0x0c2f80cd, 0x0573c29f),
+	PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard:Jack of Diamonds Modem+Ethernet", 0xc2f80cd, 0x656947b9),
+	PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard:Jack of Hearts Modem+Ethernet", 0xc2f80cd, 0xdc9ba5ed),
 	PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x016c, 0x0020),
 	PCMCIA_DEVICE_MANF_CARD(0x016c, 0x0023),
 	PCMCIA_DEVICE_PROD_ID123("BASICS by New Media Corporation", "Ethernet", "SMC91C94", 0x23c78a9d, 0x00b2e941, 0xcef397fb),
@@ -2343,8 +2343,8 @@
 	PCMCIA_DEVICE_PROD_ID12("Farallon", "Farallon Enet", 0x58d93fc4, 0x244734e9),
 	PCMCIA_DEVICE_PROD_ID12("Megahertz", "CC10BT/2", 0x33234748, 0x3c95b953),
 	PCMCIA_DEVICE_PROD_ID12("MELCO/SMC", "LPC-TX", 0xa2cd8e6d, 0x42da662a),
-	PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard", 0x0c2f80cd, 0x0573c29f),
-	PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard", 0x0c2f80cd, 0x0573c29f),
+	PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard:Four of Diamonds Ethernet", 0xc2f80cd, 0xb3466314),
+	PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard:Seven of Diamonds Ethernet", 0xc2f80cd, 0x194b650a),
 	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Fast Ethernet PCCard", 0x281f1c5d, 0xdcea68bc),
 	PCMCIA_DEVICE_PROD_ID12("Psion", "10Mb Ethernet", 0x4ef00b21, 0x844be9e9),
 	PCMCIA_DEVICE_PROD_ID12("SMC", "EtherEZ Ethernet 8020", 0xc4f8b18b, 0x4a0eeb2d),
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index 9f33bad..ce143f0 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -1985,7 +1985,7 @@
 	PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "CEM56", 0x2e3ee845, 0xa650c32a),
 	PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "REM10", 0x2e3ee845, 0x76df1d29),
 	PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "XEM5600", 0x2e3ee845, 0xf1403719),
-	PCMCIA_PFC_DEVICE_PROD_ID12(0, "Xircom", "CreditCard Ethernet", 0x2e3ee845, 0xc0e778c2),
+	PCMCIA_PFC_DEVICE_PROD_ID12(0, "Xircom", "CreditCard Ethernet+Modem II", 0x2e3ee845, 0xeca401bf),
 	PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x010a),
 	PCMCIA_DEVICE_PROD_ID13("Toshiba Information Systems", "TPCENET", 0x1b3b94fe, 0xf381c1a2),
 	PCMCIA_DEVICE_PROD_ID13("Xircom", "CE3-10/100", 0x2e3ee845, 0x0ec0ac37),
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c
index 368d2f9..1cc1492 100644
--- a/drivers/net/wireless/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco_cs.c
@@ -621,8 +621,6 @@
 	PCMCIA_DEVICE_MANF_CARD(0x9005, 0x0021),
 	PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002),
 	PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002),
-	PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002),
-	PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005),
 	PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005),
 	PCMCIA_DEVICE_PROD_ID12("3Com", "3CRWE737A AirConnect Wireless LAN PC Card", 0x41240e5b, 0x56010af3),
 	PCMCIA_DEVICE_PROD_ID123("Instant Wireless ", " Network PC CARD", "Version 01.02", 0x11d901af, 0x6e9bd926, 0x4b74baa0),
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index df3bdae..93e8a87 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -507,7 +507,7 @@
 		pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses);
 
 		if (!is_cardbus) {
-			child->bridge_ctl = PCI_BRIDGE_CTL_NO_ISA;
+			child->bridge_ctl = bctl | PCI_BRIDGE_CTL_NO_ISA;
 			/*
 			 * Adjust subordinate busnr in parent buses.
 			 * We do this before scanning for children because
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 1521fd5..8d0968b 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -820,6 +820,11 @@
 			case 0x0001: /* Toshiba Satellite A40 */
 				asus_hides_smbus = 1;
 			}
+		if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
+			switch(dev->subsystem_device) {
+			case 0x0001: /* Toshiba Tecra M2 */
+				asus_hides_smbus = 1;
+			}
        } else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG)) {
                if (dev->device ==  PCI_DEVICE_ID_INTEL_82855PM_HB)
                        switch(dev->subsystem_device) {
diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c
index 838575e..713c78f 100644
--- a/drivers/pci/rom.c
+++ b/drivers/pci/rom.c
@@ -125,7 +125,9 @@
 		image += readw(pds + 16) * 512;
 	} while (!last_image);
 
-	*size = image - rom;
+	/* never return a size larger than the PCI resource window */
+	/* there are known ROMs that get the size wrong */
+	*size = min((size_t)(image - rom), *size);
 
 	return rom;
 }
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 9fe48f7..a2eebc6 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -51,8 +51,6 @@
 	struct resource_list head, *list, *tmp;
 	int idx;
 
-	bus->bridge_ctl &= ~PCI_BRIDGE_CTL_VGA;
-
 	head.next = NULL;
 	list_for_each_entry(dev, &bus->devices, bus_list) {
 		u16 class = dev->class >> 8;
@@ -62,10 +60,6 @@
 		    class == PCI_CLASS_BRIDGE_HOST)
 			continue;
 
-		if (class == PCI_CLASS_DISPLAY_VGA ||
-		    class == PCI_CLASS_NOT_DEFINED_VGA)
-			bus->bridge_ctl |= PCI_BRIDGE_CTL_VGA;
-
 		pdev_sort_resources(dev, &head);
 	}
 
@@ -509,12 +503,6 @@
 
 	pbus_assign_resources_sorted(bus);
 
-	if (bus->bridge_ctl & PCI_BRIDGE_CTL_VGA) {
-		/* Propagate presence of the VGA to upstream bridges */
-		for (b = bus; b->parent; b = b->parent) {
-			b->bridge_ctl |= PCI_BRIDGE_CTL_VGA;
-		}
-	}
 	list_for_each_entry(dev, &bus->devices, bus_list) {
 		b = dev->subordinate;
 		if (!b)
diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c
index 0a5c958..470ef75 100644
--- a/drivers/pcmcia/au1000_generic.c
+++ b/drivers/pcmcia/au1000_generic.c
@@ -388,6 +388,7 @@
 		struct au1000_pcmcia_socket *skt = PCMCIA_SOCKET(i);
 		memset(skt, 0, sizeof(*skt));
 
+		skt->socket.resource_ops = &pccard_static_ops;
 		skt->socket.ops = &au1x00_pcmcia_operations;
 		skt->socket.owner = ops->owner;
 		skt->socket.dev.dev = dev;
diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c
index dd7651f..3afb682 100644
--- a/drivers/pcmcia/cistpl.c
+++ b/drivers/pcmcia/cistpl.c
@@ -88,31 +88,38 @@
 static void __iomem *
 set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flags)
 {
-    pccard_mem_map *mem = &s->cis_mem;
-    int ret;
+	pccard_mem_map *mem = &s->cis_mem;
+	int ret;
 
-    if (!(s->features & SS_CAP_STATIC_MAP) && mem->res == NULL) {
-	mem->res = pcmcia_find_mem_region(0, s->map_size, s->map_size, 0, s);
-	if (mem->res == NULL) {
-	    printk(KERN_NOTICE "cs: unable to map card memory!\n");
-	    return NULL;
+	if (!(s->features & SS_CAP_STATIC_MAP) && (mem->res == NULL)) {
+		mem->res = pcmcia_find_mem_region(0, s->map_size, s->map_size, 0, s);
+		if (mem->res == NULL) {
+			printk(KERN_NOTICE "cs: unable to map card memory!\n");
+			return NULL;
+		}
+		s->cis_virt = NULL;
 	}
-	s->cis_virt = ioremap(mem->res->start, s->map_size);
-    }
-    mem->card_start = card_offset;
-    mem->flags = flags;
-    ret = s->ops->set_mem_map(s, mem);
-    if (ret) {
-	iounmap(s->cis_virt);
-	return NULL;
-    }
 
-    if (s->features & SS_CAP_STATIC_MAP) {
-	if (s->cis_virt)
-	    iounmap(s->cis_virt);
-	s->cis_virt = ioremap(mem->static_start, s->map_size);
-    }
-    return s->cis_virt;
+	if (!(s->features & SS_CAP_STATIC_MAP) && (!s->cis_virt))
+		s->cis_virt = ioremap(mem->res->start, s->map_size);
+
+	mem->card_start = card_offset;
+	mem->flags = flags;
+
+	ret = s->ops->set_mem_map(s, mem);
+	if (ret) {
+		iounmap(s->cis_virt);
+		s->cis_virt = NULL;
+		return NULL;
+	}
+
+	if (s->features & SS_CAP_STATIC_MAP) {
+		if (s->cis_virt)
+			iounmap(s->cis_virt);
+		s->cis_virt = ioremap(mem->static_start, s->map_size);
+	}
+
+	return s->cis_virt;
 }
 
 /*======================================================================
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 3e3c6f1..d63f22a 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -206,8 +206,8 @@
 	u32 hash;
 
 	if (!p_drv->attach || !p_drv->event || !p_drv->detach)
-		printk(KERN_DEBUG "pcmcia: %s does misses a callback function",
-		       p_drv->drv.name);
+		printk(KERN_DEBUG "pcmcia: %s lacks a requisite callback "
+		       "function\n", p_drv->drv.name);
 
 	while (did && did->match_flags) {
 		for (i=0; i<4; i++) {
diff --git a/drivers/pcmcia/o2micro.h b/drivers/pcmcia/o2micro.h
index b1f6e3d..a234ce1 100644
--- a/drivers/pcmcia/o2micro.h
+++ b/drivers/pcmcia/o2micro.h
@@ -120,11 +120,16 @@
 #define  O2_MODE_E_LED_OUT	0x08
 #define  O2_MODE_E_SKTA_ACTV	0x10
 
+#define O2_RESERVED1		0x94
+#define O2_RESERVED2		0xD4
+#define O2_RES_READ_PREFETCH	0x02
+#define O2_RES_WRITE_BURST	0x08
+
 static int o2micro_override(struct yenta_socket *socket)
 {
 	/*
-	 * 'reserved' register at 0x94/D4. chaning it to 0xCA (8 bit) enables
-	 * read prefetching which for example makes the RME Hammerfall DSP
+	 * 'reserved' register at 0x94/D4. allows setting read prefetch and write
+	 * bursting. read prefetching for example makes the RME Hammerfall DSP
 	 * working. for some bridges it is at 0x94, for others at 0xD4. it's
 	 * ok to write to both registers on all O2 bridges.
 	 * from Eric Still, 02Micro.
@@ -132,20 +137,35 @@
 	u8 a, b;
 
 	if (PCI_FUNC(socket->dev->devfn) == 0) {
-		a = config_readb(socket, 0x94);
-		b = config_readb(socket, 0xD4);
+		a = config_readb(socket, O2_RESERVED1);
+		b = config_readb(socket, O2_RESERVED2);
 
 		printk(KERN_INFO "Yenta O2: res at 0x94/0xD4: %02x/%02x\n", a, b);
 
 		switch (socket->dev->device) {
+		/*
+		 * older bridges have problems with both read prefetch and write
+		 * bursting depending on the combination of the chipset, bridge
+		 * and the cardbus card. so disable them to be on the safe side.
+		 */
+		case PCI_DEVICE_ID_O2_6729:
+		case PCI_DEVICE_ID_O2_6730:
+		case PCI_DEVICE_ID_O2_6812:
 		case PCI_DEVICE_ID_O2_6832:
-			printk(KERN_INFO "Yenta O2: old bridge, not enabling read prefetch / write burst\n");
+		case PCI_DEVICE_ID_O2_6836:
+			printk(KERN_INFO "Yenta O2: old bridge, disabling read prefetch/write burst\n");
+			config_writeb(socket, O2_RESERVED1,
+			              a & ~(O2_RES_READ_PREFETCH | O2_RES_WRITE_BURST));
+			config_writeb(socket, O2_RESERVED2,
+			              b & ~(O2_RES_READ_PREFETCH | O2_RES_WRITE_BURST));
 			break;
 
 		default:
 			printk(KERN_INFO "Yenta O2: enabling read prefetch/write burst\n");
-			config_writeb(socket, 0x94, a | 0x0a);
-			config_writeb(socket, 0xD4, b | 0x0a);
+			config_writeb(socket, O2_RESERVED1,
+			              a | O2_RES_READ_PREFETCH | O2_RES_WRITE_BURST);
+			config_writeb(socket, O2_RESERVED2,
+			              b | O2_RES_READ_PREFETCH | O2_RES_WRITE_BURST);
 		}
 	}
 
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
index 184f4f8..6f9fdb2 100644
--- a/drivers/pcmcia/pcmcia_resource.c
+++ b/drivers/pcmcia/pcmcia_resource.c
@@ -800,7 +800,7 @@
 	} else {
 		int try;
 		u32 mask = s->irq_mask;
-		void *data = NULL;
+		void *data = &p_dev->dev.driver; /* something unique to this device */
 
 		for (try = 0; try < 64; try++) {
 			irq = try % 32;
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 9b7f6f5..ee7a05e 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -235,6 +235,9 @@
 		sch->schib.pmcw.pam &
 		sch->schib.pmcw.pom &
 		sch->opm;
+	/* Check since device may again have become not operational. */
+	if (!sch->schib.pmcw.dnv)
+		state = DEV_STATE_NOT_OPER;
 	if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID)
 		/* Force reprobe on all chpids. */
 		old_lpm = 0;
diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c
index 3be5464..a2cfade 100644
--- a/drivers/scsi/ata_piix.c
+++ b/drivers/scsi/ata_piix.c
@@ -38,6 +38,7 @@
 	PIIX_IOCFG		= 0x54, /* IDE I/O configuration register */
 	ICH5_PMR		= 0x90, /* port mapping register */
 	ICH5_PCS		= 0x92,	/* port control and status */
+	PIIX_SCC		= 0x0A, /* sub-class code register */
 
 	PIIX_FLAG_AHCI		= (1 << 28), /* AHCI possible */
 	PIIX_FLAG_CHECKINTR	= (1 << 29), /* make sure PCI INTx enabled */
@@ -62,6 +63,8 @@
 	ich6_sata_rm		= 4,
 	ich7_sata		= 5,
 	esb2_sata		= 6,
+
+	PIIX_AHCI_DEVICE	= 6,
 };
 
 static int piix_init_one (struct pci_dev *pdev,
@@ -574,11 +577,11 @@
 	addr = pci_resource_start(pdev, AHCI_PCI_BAR);
 	if (!addr || !pci_resource_len(pdev, AHCI_PCI_BAR))
 		return 0;
-	
+
 	mmio = ioremap(addr, 64);
 	if (!mmio)
 		return -ENOMEM;
-	
+
 	tmp = readl(mmio + AHCI_GLOBAL_CTL);
 	if (tmp & AHCI_ENABLE) {
 		tmp &= ~AHCI_ENABLE;
@@ -588,7 +591,7 @@
 		if (tmp & AHCI_ENABLE)
 			rc = -EIO;
 	}
-	
+
 	iounmap(mmio);
 	return rc;
 }
@@ -626,9 +629,13 @@
 	port_info[1] = NULL;
 
 	if (port_info[0]->host_flags & PIIX_FLAG_AHCI) {
-		int rc = piix_disable_ahci(pdev);
-		if (rc)
-			return rc;
+               u8 tmp;
+               pci_read_config_byte(pdev, PIIX_SCC, &tmp);
+               if (tmp == PIIX_AHCI_DEVICE) {
+                       int rc = piix_disable_ahci(pdev);
+                       if (rc)
+                           return rc;
+               }
 	}
 
 	if (port_info[0]->host_flags & PIIX_FLAG_COMBINED) {
diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c
index 18c58fb..6b321e8 100644
--- a/drivers/serial/8250_pnp.c
+++ b/drivers/serial/8250_pnp.c
@@ -394,7 +394,7 @@
 }
 
 static int __devinit
-serial_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id)
+serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
 {
 	struct uart_port port;
 	int ret, line, flags = dev_id->driver_data;
@@ -406,15 +406,23 @@
 	}
 
 	memset(&port, 0, sizeof(struct uart_port));
-	port.irq = pnp_irq(dev,0);
-	port.iobase = pnp_port_start(dev, 0);
+	port.irq = pnp_irq(dev, 0);
+	if (pnp_port_valid(dev, 0)) {
+		port.iobase = pnp_port_start(dev, 0);
+		port.iotype = UPIO_PORT;
+	} else if (pnp_mem_valid(dev, 0)) {
+		port.mapbase = pnp_mem_start(dev, 0);
+		port.iotype = UPIO_MEM;
+		port.flags = UPF_IOREMAP;
+	} else
+		return -ENODEV;
 
 #ifdef SERIAL_DEBUG_PNP
-	printk("Setup PNP port: port %x, irq %d, type %d\n",
-	       port.iobase, port.irq, port.iotype);
+	printk("Setup PNP port: port %x, mem 0x%lx, irq %d, type %d\n",
+	       port.iobase, port.mapbase, port.irq, port.iotype);
 #endif
 
-	port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
+	port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
 	port.uartclk = 1843200;
 	port.dev = &dev->dev;
 
@@ -426,7 +434,7 @@
 
 }
 
-static void __devexit serial_pnp_remove(struct pnp_dev * dev)
+static void __devexit serial_pnp_remove(struct pnp_dev *dev)
 {
 	long line = (long)pnp_get_drvdata(dev);
 	if (line)
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
index de0136c..1ae0b38 100644
--- a/drivers/serial/serial_cs.c
+++ b/drivers/serial/serial_cs.c
@@ -790,19 +790,19 @@
 	PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM56", 0x2e3ee845, 0xa650c32a),
 	PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "REM10", 0x2e3ee845, 0x76df1d29),
 	PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "XEM5600", 0x2e3ee845, 0xf1403719),
-	PCMCIA_PFC_DEVICE_PROD_ID12(1, "AnyCom", "Fast Ethernet ", 0x578ba6e7, 0x02d92d1e),
+	PCMCIA_PFC_DEVICE_PROD_ID12(1, "AnyCom", "Fast Ethernet + 56K COMBO", 0x578ba6e7, 0xb0ac62c4),
 	PCMCIA_PFC_DEVICE_PROD_ID12(1, "D-Link", "DME336T", 0x1a424a1c, 0xb23897ff),
 	PCMCIA_PFC_DEVICE_PROD_ID12(1, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x662c394c),
 	PCMCIA_PFC_DEVICE_PROD_ID12(1, "Grey Cell", "GCS3000", 0x2a151fac, 0x48b932ae),
 	PCMCIA_PFC_DEVICE_PROD_ID12(1, "Linksys", "EtherFast 10&100 + 56K PC Card (PCMLM56)", 0x0733cc81, 0xb3765033),
 	PCMCIA_PFC_DEVICE_PROD_ID12(1, "LINKSYS", "PCMLM336", 0xf7cb0b07, 0x7a821b58),
 	PCMCIA_PFC_DEVICE_PROD_ID12(1, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),
-	PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard", 0x0c2f80cd, 0x0573c29f),
-	PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard", 0x0c2f80cd, 0x0573c29f),
+	PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Diamonds Modem+Ethernet", 0xc2f80cd, 0x656947b9),
+	PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Hearts Modem+Ethernet", 0xc2f80cd, 0xdc9ba5ed),
 	PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
 	PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "LanModem", 0xdcfe12d3, 0xc67c648f),
 	PCMCIA_PFC_DEVICE_PROD_ID12(1, "TDK", "GlobalNetworker 3410/3412", 0x1eae9475, 0xd9a93bed),
-	PCMCIA_PFC_DEVICE_PROD_ID12(1, "Xircom", "CreditCard Ethernet", 0x2e3ee845, 0xc0e778c2),
+	PCMCIA_PFC_DEVICE_PROD_ID12(1, "Xircom", "CreditCard Ethernet+Modem II", 0x2e3ee845, 0xeca401bf),
 	PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0104, 0x0070),
 	PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0101, 0x0562),
 	PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0104, 0x0070),
@@ -840,7 +840,7 @@
 	PCMCIA_DEVICE_PROD_ID12("Computerboards, Inc.", "PCM-COM422", 0xd0b78f51, 0x7e2d49ed),
 	PCMCIA_DEVICE_PROD_ID12("Dr. Neuhaus", "FURY CARD 14K4", 0x76942813, 0x8b96ce65),
 	PCMCIA_DEVICE_PROD_ID12("Intelligent", "ANGIA FAX/MODEM", 0xb496e65e, 0xf31602a6),
-	PCMCIA_DEVICE_PROD_ID12("Intel", "MODEM 2400", 0x816cc815, 0x23539b80),
+	PCMCIA_DEVICE_PROD_ID12("Intel", "MODEM 2400+", 0x816cc815, 0x412729fb),
 	PCMCIA_DEVICE_PROD_ID12("IOTech Inc ", "PCMCIA Dual RS-232 Serial Port Card", 0x3bd2d898, 0x92abc92f),
 	PCMCIA_DEVICE_PROD_ID12("MACRONIX", "FAX/MODEM", 0x668388b3, 0x3f9bdf2f),
 	PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT1432LT", 0x5f73be51, 0x0b3e2383),
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index cd329dd..85dacc9 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -20,6 +20,7 @@
 	default y if SA1111
 	default y if ARCH_OMAP
 	default y if ARCH_LH7A404
+	default y if ARCH_S3C2410
 	default y if PXA27x
 	# PPC:
 	default y if STB03xxx
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index adff5a7..16ecad3 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -980,6 +980,9 @@
 	{ USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
 	.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
 	},
+	{ USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */
+	.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
+	},
 	/* control interfaces with various AT-command sets */
 	{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
 		USB_CDC_ACM_PROTO_AT_V25TER) },
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 787c27a..f86bf14 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -569,8 +569,11 @@
 			free_page((unsigned long)tbuf);
 			return -EINVAL;
 		}
-		snoop(&dev->dev, "control read: bRequest=%02x bRrequestType=%02x wValue=%04x wIndex=%04x\n", 
-			ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex);
+		snoop(&dev->dev, "control read: bRequest=%02x "
+				"bRrequestType=%02x wValue=%04x "
+				"wIndex=%04x wLength=%04x\n",
+			ctrl.bRequest, ctrl.bRequestType, ctrl.wValue,
+				ctrl.wIndex, ctrl.wLength);
 
 		usb_unlock_device(dev);
 		i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType,
@@ -579,11 +582,11 @@
 		if ((i > 0) && ctrl.wLength) {
 			if (usbfs_snoop) {
 				dev_info(&dev->dev, "control read: data ");
-				for (j = 0; j < ctrl.wLength; ++j)
+				for (j = 0; j < i; ++j)
 					printk ("%02x ", (unsigned char)(tbuf)[j]);
 				printk("\n");
 			}
-			if (copy_to_user(ctrl.data, tbuf, ctrl.wLength)) {
+			if (copy_to_user(ctrl.data, tbuf, i)) {
 				free_page((unsigned long)tbuf);
 				return -EFAULT;
 			}
@@ -595,8 +598,11 @@
 				return -EFAULT;
 			}
 		}
-		snoop(&dev->dev, "control write: bRequest=%02x bRrequestType=%02x wValue=%04x wIndex=%04x\n", 
-			ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex);
+		snoop(&dev->dev, "control write: bRequest=%02x "
+				"bRrequestType=%02x wValue=%04x "
+				"wIndex=%04x wLength=%04x\n",
+			ctrl.bRequest, ctrl.bRequestType, ctrl.wValue,
+				ctrl.wIndex, ctrl.wLength);
 		if (usbfs_snoop) {
 			dev_info(&dev->dev, "control write: data: ");
 			for (j = 0; j < ctrl.wLength; ++j)
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 8616356..79422a3 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -939,9 +939,9 @@
 	case USB_SPEED_HIGH:	/* ISOC or INTR */
 		// FIXME adjust for input vs output
 		if (isoc)
-			tmp = HS_USECS (bytecount);
+			tmp = HS_NSECS_ISO (bytecount);
 		else
-			tmp = HS_USECS_ISO (bytecount);
+			tmp = HS_NSECS (bytecount);
 		return tmp;
 	default:
 		pr_debug ("%s: bogus device speed!\n", usbcore_name);
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index 67db4a9..28055f9 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -334,17 +334,19 @@
 extern int usb_check_bandwidth (struct usb_device *dev, struct urb *urb);
 
 /*
- * Ceiling microseconds (typical) for that many bytes at high speed
+ * Ceiling [nano/micro]seconds (typical) for that many bytes at high speed
  * ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed
  * to preallocate bandwidth)
  */
 #define USB2_HOST_DELAY	5	/* nsec, guess */
-#define HS_USECS(bytes) NS_TO_US ( ((55 * 8 * 2083)/1000) \
+#define HS_NSECS(bytes) ( ((55 * 8 * 2083)/1000) \
 	+ ((2083UL * (3167 + BitTime (bytes)))/1000) \
 	+ USB2_HOST_DELAY)
-#define HS_USECS_ISO(bytes) NS_TO_US ( ((38 * 8 * 2083)/1000) \
+#define HS_NSECS_ISO(bytes) ( ((38 * 8 * 2083)/1000) \
 	+ ((2083UL * (3167 + BitTime (bytes)))/1000) \
 	+ USB2_HOST_DELAY)
+#define HS_USECS(bytes) NS_TO_US (HS_NSECS(bytes))
+#define HS_USECS_ISO(bytes) NS_TO_US (HS_NSECS_ISO(bytes))
 
 extern long usb_calc_bus_time (int speed, int is_input,
 			int isoc, int bytecount);
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index a428ef4..88d1b37 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -985,8 +985,10 @@
 		for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
 			struct usb_interface	*interface;
 
-			/* remove this interface */
+			/* remove this interface if it has been registered */
 			interface = dev->actconfig->interface[i];
+			if (!klist_node_attached(&interface->dev.knode_bus))
+				continue;
 			dev_dbg (&dev->dev, "unregistering interface %s\n",
 				interface->dev.bus_id);
 			usb_remove_sysfs_intf_files(interface);
@@ -1439,7 +1441,7 @@
 		}
 	}
 
-	return ret;
+	return 0;
 }
 
 // synchronous request completion model
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index d74b2d6..4f97a4a 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -657,8 +657,8 @@
 	 * For control/bulk requests, the HC or TT handles these.
 	 */
 	if (type == PIPE_INTERRUPT) {
-		qh->usecs = usb_calc_bus_time (USB_SPEED_HIGH, is_input, 0,
-				hb_mult (maxp) * max_packet (maxp));
+		qh->usecs = NS_TO_US (usb_calc_bus_time (USB_SPEED_HIGH, is_input, 0,
+				hb_mult (maxp) * max_packet (maxp)));
 		qh->start = NO_FRAME;
 
 		if (urb->dev->speed == USB_SPEED_HIGH) {
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 68decab..56b43f2 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -887,6 +887,10 @@
 #include "ohci-sa1111.c"
 #endif
 
+#ifdef CONFIG_ARCH_S3C2410
+#include "ohci-s3c2410.c"
+#endif
+
 #ifdef CONFIG_ARCH_OMAP
 #include "ohci-omap.c"
 #endif
@@ -909,6 +913,7 @@
 
 #if !(defined(CONFIG_PCI) \
       || defined(CONFIG_SA1111) \
+      || defined(CONFIG_ARCH_S3C2410) \
       || defined(CONFIG_ARCH_OMAP) \
       || defined (CONFIG_ARCH_LH7A404) \
       || defined (CONFIG_PXA27x) \
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
new file mode 100644
index 0000000..e940166
--- /dev/null
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -0,0 +1,496 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2002 Hewlett-Packard Company
+ *
+ * USB Bus Glue for Samsung S3C2410
+ *
+ * Written by Christopher Hoover <ch@hpl.hp.com>
+ * Based on fragments of previous driver by Rusell King et al.
+ *
+ * Modified for S3C2410 from ohci-sa1111.c, ohci-omap.c and ohci-lh7a40.c
+ *	by Ben Dooks, <ben@simtec.co.uk>
+ *	Copyright (C) 2004 Simtec Electronics
+ *
+ * Thanks to basprog@mail.ru for updates to newer kernels
+ *
+ * This file is licenced under the GPL.
+*/
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/hardware/clock.h>
+#include <asm/arch/usb-control.h>
+
+#define valid_port(idx) ((idx) == 1 || (idx) == 2)
+
+/* clock device associated with the hcd */
+
+static struct clk *clk;
+
+/* forward definitions */
+
+static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc);
+
+/* conversion functions */
+
+struct s3c2410_hcd_info *to_s3c2410_info(struct usb_hcd *hcd)
+{
+	return hcd->self.controller->platform_data;
+}
+
+static void s3c2410_start_hc(struct platform_device *dev, struct usb_hcd *hcd)
+{
+	struct s3c2410_hcd_info *info = dev->dev.platform_data;
+
+	dev_dbg(&dev->dev, "s3c2410_start_hc:\n");
+	clk_enable(clk);
+
+	if (info != NULL) {
+		info->hcd	= hcd;
+		info->report_oc = s3c2410_hcd_oc;
+
+		if (info->enable_oc != NULL) {
+			(info->enable_oc)(info, 1);
+		}
+	}
+}
+
+static void s3c2410_stop_hc(struct platform_device *dev)
+{
+	struct s3c2410_hcd_info *info = dev->dev.platform_data;
+
+	dev_dbg(&dev->dev, "s3c2410_stop_hc:\n");
+
+	if (info != NULL) {
+		info->report_oc = NULL;
+		info->hcd	= NULL;
+
+		if (info->enable_oc != NULL) {
+			(info->enable_oc)(info, 0);
+		}
+	}
+
+	clk_disable(clk);
+}
+
+/* ohci_s3c2410_hub_status_data
+ *
+ * update the status data from the hub with anything that
+ * has been detected by our system
+*/
+
+static int
+ohci_s3c2410_hub_status_data (struct usb_hcd *hcd, char *buf)
+{
+	struct s3c2410_hcd_info *info = to_s3c2410_info(hcd);
+	struct s3c2410_hcd_port *port;
+	int orig;
+	int portno;
+
+	orig  = ohci_hub_status_data (hcd, buf);
+
+	if (info == NULL)
+		return orig;
+
+	port = &info->port[0];
+
+	/* mark any changed port as changed */
+
+	for (portno = 0; portno < 2; port++, portno++) {
+		if (port->oc_changed == 1 &&
+		    port->flags & S3C_HCDFLG_USED) {
+			dev_dbg(hcd->self.controller,
+				"oc change on port %d\n", portno);
+
+			if (orig < 1)
+				orig = 1;
+
+			buf[0] |= 1<<(portno+1);
+		}
+	}
+
+	return orig;
+}
+
+/* s3c2410_usb_set_power
+ *
+ * configure the power on a port, by calling the platform device
+ * routine registered with the platform device
+*/
+
+static void s3c2410_usb_set_power(struct s3c2410_hcd_info *info,
+				  int port, int to)
+{
+	if (info == NULL)
+		return;
+
+	if (info->power_control != NULL) {
+		info->port[port-1].power = to;
+		(info->power_control)(port, to);
+	}
+}
+
+/* ohci_s3c2410_hub_control
+ *
+ * look at control requests to the hub, and see if we need
+ * to take any action or over-ride the results from the
+ * request.
+*/
+
+static int ohci_s3c2410_hub_control (
+	struct usb_hcd	*hcd,
+	u16		typeReq,
+	u16		wValue,
+	u16		wIndex,
+	char		*buf,
+	u16		wLength)
+{
+	struct s3c2410_hcd_info *info = to_s3c2410_info(hcd);
+	struct usb_hub_descriptor *desc;
+	int ret = -EINVAL;
+	u32 *data = (u32 *)buf;
+
+	dev_dbg(hcd->self.controller,
+		"s3c2410_hub_control(%p,0x%04x,0x%04x,0x%04x,%p,%04x)\n",
+		hcd, typeReq, wValue, wIndex, buf, wLength);
+
+	/* if we are only an humble host without any special capabilites
+	 * process the request straight away and exit */
+
+	if (info == NULL) {
+		ret = ohci_hub_control(hcd, typeReq, wValue,
+				       wIndex, buf, wLength);
+		goto out;
+	}
+
+	/* check the request to see if it needs handling */
+
+	switch (typeReq) {
+	case SetPortFeature:
+		if (wValue == USB_PORT_FEAT_POWER) {
+			dev_dbg(hcd->self.controller, "SetPortFeat: POWER\n");
+			s3c2410_usb_set_power(info, wIndex, 1);
+			goto out;
+		}
+		break;
+
+	case ClearPortFeature:
+		switch (wValue) {
+		case USB_PORT_FEAT_C_OVER_CURRENT:
+			dev_dbg(hcd->self.controller,
+				"ClearPortFeature: C_OVER_CURRENT\n");
+
+			if (valid_port(wIndex)) {
+				info->port[wIndex-1].oc_changed = 0;
+				info->port[wIndex-1].oc_status = 0;
+			}
+
+			goto out;
+
+		case USB_PORT_FEAT_OVER_CURRENT:
+			dev_dbg(hcd->self.controller,
+				"ClearPortFeature: OVER_CURRENT\n");
+
+			if (valid_port(wIndex)) {
+				info->port[wIndex-1].oc_status = 0;
+			}
+
+			goto out;
+
+		case USB_PORT_FEAT_POWER:
+			dev_dbg(hcd->self.controller,
+				"ClearPortFeature: POWER\n");
+
+			if (valid_port(wIndex)) {
+				s3c2410_usb_set_power(info, wIndex, 0);
+				return 0;
+			}
+		}
+		break;
+	}
+
+	ret = ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
+	if (ret)
+		goto out;
+
+	switch (typeReq) {
+	case GetHubDescriptor:
+
+		/* update the hub's descriptor */
+
+		desc = (struct usb_hub_descriptor *)buf;
+
+		if (info->power_control == NULL)
+			return ret;
+
+		dev_dbg(hcd->self.controller, "wHubCharacteristics 0x%04x\n",
+			desc->wHubCharacteristics);
+
+		/* remove the old configurations for power-switching, and
+		 * over-current protection, and insert our new configuration
+		 */
+
+		desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_LPSM);
+		desc->wHubCharacteristics |= cpu_to_le16(0x0001);
+
+		if (info->enable_oc) {
+			desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_OCPM);
+			desc->wHubCharacteristics |=  cpu_to_le16(0x0008|0x0001);
+		}
+
+		dev_dbg(hcd->self.controller, "wHubCharacteristics after 0x%04x\n",
+			desc->wHubCharacteristics);
+
+		return ret;
+
+	case GetPortStatus:
+		/* check port status */
+
+		dev_dbg(hcd->self.controller, "GetPortStatus(%d)\n", wIndex);
+
+		if (valid_port(wIndex)) {
+			if (info->port[wIndex-1].oc_changed) {
+				*data |= cpu_to_le32(RH_PS_OCIC);
+			}
+
+			if (info->port[wIndex-1].oc_status) {
+				*data |= cpu_to_le32(RH_PS_POCI);
+			}
+		}
+	}
+
+ out:
+	return ret;
+}
+
+/* s3c2410_hcd_oc
+ *
+ * handle an over-current report
+*/
+
+static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc)
+{
+	struct s3c2410_hcd_port *port;
+	struct usb_hcd *hcd;
+	unsigned long flags;
+	int portno;
+
+	if (info == NULL)
+		return;
+
+	port = &info->port[0];
+	hcd = info->hcd;
+
+	local_irq_save(flags);
+
+	for (portno = 0; portno < 2; port++, portno++) {
+		if (port_oc & (1<<portno) &&
+		    port->flags & S3C_HCDFLG_USED) {
+			port->oc_status = 1;
+			port->oc_changed = 1;
+
+			/* ok, once over-current is detected,
+			   the port needs to be powered down */
+			s3c2410_usb_set_power(info, portno+1, 0);
+		}
+	}
+
+	local_irq_restore(flags);
+}
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/*
+ * usb_hcd_s3c2410_remove - shutdown processing for HCD
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_3c2410_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+*/
+
+void usb_hcd_s3c2410_remove (struct usb_hcd *hcd, struct platform_device *dev)
+{
+	usb_remove_hcd(hcd);
+	s3c2410_stop_hc(dev);
+	iounmap(hcd->regs);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
+}
+
+/**
+ * usb_hcd_s3c2410_probe - initialize S3C2410-based HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ */
+int usb_hcd_s3c2410_probe (const struct hc_driver *driver,
+			   struct platform_device *dev)
+{
+	struct usb_hcd *hcd = NULL;
+	int retval;
+
+	s3c2410_usb_set_power(dev->dev.platform_data, 0, 1);
+	s3c2410_usb_set_power(dev->dev.platform_data, 1, 1);
+
+	hcd = usb_create_hcd(driver, &dev->dev, "s3c24xx");
+	if (hcd == NULL)
+		return -ENOMEM;
+
+	hcd->rsrc_start = dev->resource[0].start;
+	hcd->rsrc_len   = dev->resource[0].end - dev->resource[0].start + 1;
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+		dev_err(&dev->dev, "request_mem_region failed");
+		retval = -EBUSY;
+		goto err0;
+	}
+
+	clk = clk_get(NULL, "usb-host");
+	if (IS_ERR(clk)) {
+		dev_err(&dev->dev, "cannot get usb-host clock\n");
+		retval = -ENOENT;
+		goto err1;
+	}
+
+	clk_use(clk);
+	s3c2410_start_hc(dev, hcd);
+
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs) {
+		dev_err(&dev->dev, "ioremap failed\n");
+		retval = -ENOMEM;
+		goto err2;
+	}
+
+	ohci_hcd_init(hcd_to_ohci(hcd));
+
+	retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT);
+	if (retval != 0)
+		goto err2;
+
+	return 0;
+
+ err2:
+	s3c2410_stop_hc(dev);
+	iounmap(hcd->regs);
+	clk_unuse(clk);
+	clk_put(clk);
+
+ err1:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+
+ err0:
+	usb_put_hcd(hcd);
+	return retval;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+ohci_s3c2410_start (struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+	int ret;
+
+	if ((ret = ohci_init(ohci)) < 0)
+		return ret;
+
+	if ((ret = ohci_run (ohci)) < 0) {
+		err ("can't start %s", hcd->self.bus_name);
+		ohci_stop (hcd);
+		return ret;
+	}
+
+	return 0;
+}
+
+
+static const struct hc_driver ohci_s3c2410_hc_driver = {
+	.description =		hcd_name,
+	.product_desc =		"S3C24XX OHCI",
+	.hcd_priv_size =	sizeof(struct ohci_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq =			ohci_irq,
+	.flags =		HCD_USB11 | HCD_MEMORY,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.start =		ohci_s3c2410_start,
+	.stop =			ohci_stop,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue =		ohci_urb_enqueue,
+	.urb_dequeue =		ohci_urb_dequeue,
+	.endpoint_disable =	ohci_endpoint_disable,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number =	ohci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data =	ohci_s3c2410_hub_status_data,
+	.hub_control =		ohci_s3c2410_hub_control,
+
+#if defined(CONFIG_USB_SUSPEND) && 0
+	.hub_suspend =		ohci_hub_suspend,
+	.hub_resume =		ohci_hub_resume,
+#endif
+};
+
+/* device driver */
+
+static int ohci_hcd_s3c2410_drv_probe(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	return usb_hcd_s3c2410_probe(&ohci_s3c2410_hc_driver, pdev);
+}
+
+static int ohci_hcd_s3c2410_drv_remove(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+	usb_hcd_s3c2410_remove(hcd, pdev);
+	return 0;
+}
+
+static struct device_driver ohci_hcd_s3c2410_driver = {
+	.name		= "s3c2410-ohci",
+	.bus		= &platform_bus_type,
+	.probe		= ohci_hcd_s3c2410_drv_probe,
+	.remove		= ohci_hcd_s3c2410_drv_remove,
+	/*.suspend	= ohci_hcd_s3c2410_drv_suspend, */
+	/*.resume	= ohci_hcd_s3c2410_drv_resume, */
+};
+
+static int __init ohci_hcd_s3c2410_init (void)
+{
+	return driver_register(&ohci_hcd_s3c2410_driver);
+}
+
+static void __exit ohci_hcd_s3c2410_cleanup (void)
+{
+	driver_unregister(&ohci_hcd_s3c2410_driver);
+}
+
+module_init (ohci_hcd_s3c2410_init);
+module_exit (ohci_hcd_s3c2410_cleanup);
diff --git a/drivers/usb/input/acecad.c b/drivers/usb/input/acecad.c
index ebcf7c9..13532f3 100644
--- a/drivers/usb/input/acecad.c
+++ b/drivers/usb/input/acecad.c
@@ -31,6 +31,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/usb.h>
+#include <linux/usb_input.h>
 
 /*
  * Version Information
@@ -87,8 +88,8 @@
 	if (prox) {
 		int x = data[1] | (data[2] << 8);
 		int y = data[3] | (data[4] << 8);
-		/*Pressure should compute the same way for flair and 302*/
-		int pressure = data[5] | ((int)data[6] << 8);
+		/* Pressure should compute the same way for flair and 302 */
+		int pressure = data[5] | (data[6] << 8);
 		int touch = data[0] & 0x01;
 		int stylus = (data[0] & 0x10) >> 4;
 		int stylus2 = (data[0] & 0x20) >> 5;
@@ -104,9 +105,9 @@
 	input_sync(dev);
 
 resubmit:
-	status = usb_submit_urb (urb, GFP_ATOMIC);
+	status = usb_submit_urb(urb, GFP_ATOMIC);
 	if (status)
-		err ("can't resubmit intr, %s-%s/input0, status %d",
+		err("can't resubmit intr, %s-%s/input0, status %d",
 			acecad->usbdev->bus->bus_name, acecad->usbdev->devpath, status);
 }
 
@@ -212,10 +213,7 @@
 
 	acecad->dev.name = acecad->name;
 	acecad->dev.phys = acecad->phys;
-	acecad->dev.id.bustype = BUS_USB;
-	acecad->dev.id.vendor = le16_to_cpu(dev->descriptor.idVendor);
-	acecad->dev.id.product = le16_to_cpu(dev->descriptor.idProduct);
-	acecad->dev.id.version = le16_to_cpu(dev->descriptor.bcdDevice);
+	usb_to_input_id(dev, &acecad->dev.id);
 	acecad->dev.dev = &intf->dev;
 
 	usb_fill_int_urb(acecad->irq, dev, pipe,
diff --git a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c
index 6bb0f25..cd0cbfe 100644
--- a/drivers/usb/input/aiptek.c
+++ b/drivers/usb/input/aiptek.c
@@ -77,6 +77,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/usb.h>
+#include <linux/usb_input.h>
 #include <linux/sched.h>
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
@@ -2125,10 +2126,7 @@
 	aiptek->inputdev.absflat[ABS_WHEEL] = 0;
 	aiptek->inputdev.name = "Aiptek";
 	aiptek->inputdev.phys = aiptek->features.usbPath;
-	aiptek->inputdev.id.bustype = BUS_USB;
-	aiptek->inputdev.id.vendor = le16_to_cpu(usbdev->descriptor.idVendor);
-	aiptek->inputdev.id.product = le16_to_cpu(usbdev->descriptor.idProduct);
-	aiptek->inputdev.id.version = le16_to_cpu(usbdev->descriptor.bcdDevice);
+	usb_to_input_id(usbdev, &aiptek->inputdev.id);
 	aiptek->inputdev.dev = &intf->dev;
 
 	aiptek->usbdev = usbdev;
diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c
index 654ac45..fd99681 100644
--- a/drivers/usb/input/ati_remote.c
+++ b/drivers/usb/input/ati_remote.c
@@ -94,6 +94,7 @@
 #include <linux/moduleparam.h>
 #include <linux/input.h>
 #include <linux/usb.h>
+#include <linux/usb_input.h>
 #include <linux/wait.h>
 
 /*
@@ -635,11 +636,8 @@
 	idev->name = ati_remote->name;
 	idev->phys = ati_remote->phys;
 
-	idev->id.bustype = BUS_USB;
-	idev->id.vendor = le16_to_cpu(ati_remote->udev->descriptor.idVendor);
-	idev->id.product = le16_to_cpu(ati_remote->udev->descriptor.idProduct);
-	idev->id.version = le16_to_cpu(ati_remote->udev->descriptor.bcdDevice);
-	idev->dev = &(ati_remote->udev->dev);
+	usb_to_input_id(ati_remote->udev, &idev->id);
+	idev->dev = &ati_remote->udev->dev;
 }
 
 static int ati_remote_initialize(struct ati_remote *ati_remote)
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
index 2350e7a..b2cb2b3 100644
--- a/drivers/usb/input/hid-core.c
+++ b/drivers/usb/input/hid-core.c
@@ -789,12 +789,12 @@
 	return -1;
 }
 
-static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, struct pt_regs *regs)
+static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, int interrupt, struct pt_regs *regs)
 {
 	hid_dump_input(usage, value);
 	if (hid->claimed & HID_CLAIMED_INPUT)
 		hidinput_hid_event(hid, field, usage, value, regs);
-	if (hid->claimed & HID_CLAIMED_HIDDEV)
+	if (hid->claimed & HID_CLAIMED_HIDDEV && interrupt)
 		hiddev_hid_event(hid, field, usage, value, regs);
 }
 
@@ -804,7 +804,7 @@
  * reporting to the layer).
  */
 
-static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, struct pt_regs *regs)
+static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt, struct pt_regs *regs)
 {
 	unsigned n;
 	unsigned count = field->report_count;
@@ -831,19 +831,19 @@
 	for (n = 0; n < count; n++) {
 
 		if (HID_MAIN_ITEM_VARIABLE & field->flags) {
-			hid_process_event(hid, field, &field->usage[n], value[n], regs);
+			hid_process_event(hid, field, &field->usage[n], value[n], interrupt, regs);
 			continue;
 		}
 
 		if (field->value[n] >= min && field->value[n] <= max
 			&& field->usage[field->value[n] - min].hid
 			&& search(value, field->value[n], count))
-				hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, regs);
+				hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt, regs);
 
 		if (value[n] >= min && value[n] <= max
 			&& field->usage[value[n] - min].hid
 			&& search(field->value, value[n], count))
-				hid_process_event(hid, field, &field->usage[value[n] - min], 1, regs);
+				hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt, regs);
 	}
 
 	memcpy(field->value, value, count * sizeof(__s32));
@@ -851,7 +851,7 @@
 	kfree(value);
 }
 
-static int hid_input_report(int type, struct urb *urb, struct pt_regs *regs)
+static int hid_input_report(int type, struct urb *urb, int interrupt, struct pt_regs *regs)
 {
 	struct hid_device *hid = urb->context;
 	struct hid_report_enum *report_enum = hid->report_enum + type;
@@ -899,7 +899,7 @@
 		hiddev_report_event(hid, report);
 
 	for (n = 0; n < report->maxfield; n++)
-		hid_input_field(hid, report->field[n], data, regs);
+		hid_input_field(hid, report->field[n], data, interrupt, regs);
 
 	if (hid->claimed & HID_CLAIMED_INPUT)
 		hidinput_report_event(hid, report);
@@ -918,7 +918,7 @@
 
 	switch (urb->status) {
 		case 0:			/* success */
-			hid_input_report(HID_INPUT_REPORT, urb, regs);
+			hid_input_report(HID_INPUT_REPORT, urb, 1, regs);
 			break;
 		case -ECONNRESET:	/* unlink */
 		case -ENOENT:
@@ -1142,7 +1142,7 @@
 	switch (urb->status) {
 		case 0:			/* success */
 			if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN)
-				hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, regs);
+				hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, 0, regs);
 		case -ESHUTDOWN:	/* unplug */
 		case -EILSEQ:		/* unplug timectrl on uhci */
 			unplug = 1;
@@ -1372,6 +1372,9 @@
 #define USB_VENDOR_ID_A4TECH		0x09da
 #define USB_DEVICE_ID_A4TECH_WCP32PU	0x0006
 
+#define USB_VENDOR_ID_AASHIMA		0x06D6
+#define USB_DEVICE_ID_AASHIMA_GAMEPAD	0x0025
+
 #define USB_VENDOR_ID_CYPRESS		0x04b4
 #define USB_DEVICE_ID_CYPRESS_MOUSE	0x0001
 #define USB_DEVICE_ID_CYPRESS_HIDCOM	0x5500
@@ -1548,6 +1551,7 @@
 	{ USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 },
 	{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_5 },
 
+	{ USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_GAMEPAD, HID_QUIRK_BADPAD },
 	{ USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD },
 	{ USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD },
 	{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c
index 9ac1e90..63a4db7 100644
--- a/drivers/usb/input/hid-input.c
+++ b/drivers/usb/input/hid-input.c
@@ -31,6 +31,7 @@
 #include <linux/kernel.h>
 #include <linux/input.h>
 #include <linux/usb.h>
+#include <linux/usb_input.h>
 
 #undef DEBUG
 
@@ -397,11 +398,12 @@
 
 void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, struct pt_regs *regs)
 {
-	struct input_dev *input = &field->hidinput->input;
+	struct input_dev *input;
 	int *quirks = &hid->quirks;
 
-	if (!input)
+	if (!field->hidinput)
 		return;
+	input = &field->hidinput->input;
 
 	input_regs(input, regs);
 
@@ -581,10 +583,7 @@
 				hidinput->input.name = hid->name;
 				hidinput->input.phys = hid->phys;
 				hidinput->input.uniq = hid->uniq;
-				hidinput->input.id.bustype = BUS_USB;
-				hidinput->input.id.vendor = le16_to_cpu(dev->descriptor.idVendor);
-				hidinput->input.id.product = le16_to_cpu(dev->descriptor.idProduct);
-				hidinput->input.id.version = le16_to_cpu(dev->descriptor.bcdDevice);
+				usb_to_input_id(dev, &hidinput->input.id);
 				hidinput->input.dev = &hid->intf->dev;
 			}
 
diff --git a/drivers/usb/input/itmtouch.c b/drivers/usb/input/itmtouch.c
index 47dec6a..0dc439f 100644
--- a/drivers/usb/input/itmtouch.c
+++ b/drivers/usb/input/itmtouch.c
@@ -53,6 +53,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/usb.h>
+#include <linux/usb_input.h>
 
 /* only an 8 byte buffer necessary for a single packet */
 #define ITM_BUFSIZE			8
@@ -184,10 +185,7 @@
 
 	itmtouch->inputdev.name = itmtouch->name;
 	itmtouch->inputdev.phys = itmtouch->phys;
-	itmtouch->inputdev.id.bustype = BUS_USB;
-	itmtouch->inputdev.id.vendor = udev->descriptor.idVendor;
-	itmtouch->inputdev.id.product = udev->descriptor.idProduct;
-	itmtouch->inputdev.id.version = udev->descriptor.bcdDevice;
+	usb_to_input_id(udev, &itmtouch->inputdev.id);
 	itmtouch->inputdev.dev = &intf->dev;
 
 	if (!strlen(itmtouch->name))
diff --git a/drivers/usb/input/kbtab.c b/drivers/usb/input/kbtab.c
index d2f0f90..b6f6ac8 100644
--- a/drivers/usb/input/kbtab.c
+++ b/drivers/usb/input/kbtab.c
@@ -4,6 +4,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/usb.h>
+#include <linux/usb_input.h>
 #include <asm/unaligned.h>
 #include <asm/byteorder.h>
 
@@ -167,10 +168,7 @@
 
 	kbtab->dev.name = "KB Gear Tablet";
 	kbtab->dev.phys = kbtab->phys;
-	kbtab->dev.id.bustype = BUS_USB;
-	kbtab->dev.id.vendor = le16_to_cpu(dev->descriptor.idVendor);
-	kbtab->dev.id.product = le16_to_cpu(dev->descriptor.idProduct);
-	kbtab->dev.id.version = le16_to_cpu(dev->descriptor.bcdDevice);
+	usb_to_input_id(dev, &kbtab->dev.id);
 	kbtab->dev.dev = &intf->dev;
 	kbtab->usbdev = dev;
 
diff --git a/drivers/usb/input/mtouchusb.c b/drivers/usb/input/mtouchusb.c
index 09b5cc7..ff92750 100644
--- a/drivers/usb/input/mtouchusb.c
+++ b/drivers/usb/input/mtouchusb.c
@@ -53,6 +53,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/usb.h>
+#include <linux/usb_input.h>
 
 #define MTOUCHUSB_MIN_XC                0x0
 #define MTOUCHUSB_MAX_RAW_XC            0x4000
@@ -232,10 +233,7 @@
 
 	mtouch->input.name = mtouch->name;
 	mtouch->input.phys = mtouch->phys;
-	mtouch->input.id.bustype = BUS_USB;
-	mtouch->input.id.vendor = le16_to_cpu(udev->descriptor.idVendor);
-	mtouch->input.id.product = le16_to_cpu(udev->descriptor.idProduct);
-	mtouch->input.id.version = le16_to_cpu(udev->descriptor.bcdDevice);
+	usb_to_input_id(udev, &mtouch->input.id);
 	mtouch->input.dev = &intf->dev;
 
 	mtouch->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
diff --git a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c
index 3975b30..ad4afe7 100644
--- a/drivers/usb/input/powermate.c
+++ b/drivers/usb/input/powermate.c
@@ -35,6 +35,7 @@
 #include <linux/init.h>
 #include <linux/spinlock.h>
 #include <linux/usb.h>
+#include <linux/usb_input.h>
 
 #define POWERMATE_VENDOR	0x077d	/* Griffin Technology, Inc. */
 #define POWERMATE_PRODUCT_NEW	0x0410	/* Griffin PowerMate */
@@ -389,10 +390,7 @@
 	pm->input.keybit[LONG(BTN_0)] = BIT(BTN_0);
 	pm->input.relbit[LONG(REL_DIAL)] = BIT(REL_DIAL);
 	pm->input.mscbit[LONG(MSC_PULSELED)] = BIT(MSC_PULSELED);
-	pm->input.id.bustype = BUS_USB;
-	pm->input.id.vendor = le16_to_cpu(udev->descriptor.idVendor);
-	pm->input.id.product = le16_to_cpu(udev->descriptor.idProduct);
-	pm->input.id.version = le16_to_cpu(udev->descriptor.bcdDevice);
+	usb_to_input_id(udev, &pm->input.id);
 	pm->input.event = powermate_input_event;
 	pm->input.dev = &intf->dev;
 	pm->input.phys = pm->phys;
diff --git a/drivers/usb/input/touchkitusb.c b/drivers/usb/input/touchkitusb.c
index 386595e..4276c24 100644
--- a/drivers/usb/input/touchkitusb.c
+++ b/drivers/usb/input/touchkitusb.c
@@ -35,7 +35,7 @@
 #define DEBUG
 #endif
 #include <linux/usb.h>
-
+#include <linux/usb_input.h>
 
 #define TOUCHKIT_MIN_XC			0x0
 #define TOUCHKIT_MAX_XC			0x07ff
@@ -202,10 +202,7 @@
 
 	touchkit->input.name = touchkit->name;
 	touchkit->input.phys = touchkit->phys;
-	touchkit->input.id.bustype = BUS_USB;
-	touchkit->input.id.vendor = le16_to_cpu(udev->descriptor.idVendor);
-	touchkit->input.id.product = le16_to_cpu(udev->descriptor.idProduct);
-	touchkit->input.id.version = le16_to_cpu(udev->descriptor.bcdDevice);
+	usb_to_input_id(udev, &touchkit->input.id);
 	touchkit->input.dev = &intf->dev;
 
 	touchkit->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
diff --git a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c
index f35db19..28987f1 100644
--- a/drivers/usb/input/usbkbd.c
+++ b/drivers/usb/input/usbkbd.c
@@ -32,6 +32,7 @@
 #include <linux/input.h>
 #include <linux/init.h>
 #include <linux/usb.h>
+#include <linux/usb_input.h>
 
 /*
  * Version Information
@@ -288,10 +289,7 @@
 
 	kbd->dev.name = kbd->name;
 	kbd->dev.phys = kbd->phys;
-	kbd->dev.id.bustype = BUS_USB;
-	kbd->dev.id.vendor = le16_to_cpu(dev->descriptor.idVendor);
-	kbd->dev.id.product = le16_to_cpu(dev->descriptor.idProduct);
-	kbd->dev.id.version = le16_to_cpu(dev->descriptor.bcdDevice);
+	usb_to_input_id(dev, &kbd->dev.id);
 	kbd->dev.dev = &iface->dev;
 
 	if (dev->manufacturer)
diff --git a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c
index 1ec41b5..4104dec 100644
--- a/drivers/usb/input/usbmouse.c
+++ b/drivers/usb/input/usbmouse.c
@@ -32,6 +32,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/usb.h>
+#include <linux/usb_input.h>
 
 /*
  * Version Information
@@ -171,10 +172,7 @@
 
 	mouse->dev.name = mouse->name;
 	mouse->dev.phys = mouse->phys;
-	mouse->dev.id.bustype = BUS_USB;
-	mouse->dev.id.vendor = le16_to_cpu(dev->descriptor.idVendor);
-	mouse->dev.id.product = le16_to_cpu(dev->descriptor.idProduct);
-	mouse->dev.id.version = le16_to_cpu(dev->descriptor.bcdDevice);
+	usb_to_input_id(dev, &mouse->dev.id);
 	mouse->dev.dev = &intf->dev;
 
 	if (dev->manufacturer)
diff --git a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c
index f6b34af..02412e3 100644
--- a/drivers/usb/input/wacom.c
+++ b/drivers/usb/input/wacom.c
@@ -69,6 +69,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/usb.h>
+#include <linux/usb_input.h>
 #include <asm/unaligned.h>
 #include <asm/byteorder.h>
 
@@ -823,10 +824,7 @@
 
 	wacom->dev.name = wacom->features->name;
 	wacom->dev.phys = wacom->phys;
-	wacom->dev.id.bustype = BUS_USB;
-	wacom->dev.id.vendor = le16_to_cpu(dev->descriptor.idVendor);
-	wacom->dev.id.product = le16_to_cpu(dev->descriptor.idProduct);
-	wacom->dev.id.version = le16_to_cpu(dev->descriptor.bcdDevice);
+	usb_to_input_id(dev, &wacom->dev.id);
 	wacom->dev.dev = &intf->dev;
 	wacom->usbdev = dev;
 
diff --git a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c
index a7fa1b1..18125e0 100644
--- a/drivers/usb/input/xpad.c
+++ b/drivers/usb/input/xpad.c
@@ -62,6 +62,7 @@
 #include <linux/module.h>
 #include <linux/smp_lock.h>
 #include <linux/usb.h>
+#include <linux/usb_input.h>
 
 #define DRIVER_VERSION "v0.0.5"
 #define DRIVER_AUTHOR "Marko Friedemann <mfr@bmx-chemnitz.de>"
@@ -256,10 +257,7 @@
 
 	xpad->udev = udev;
 
-	xpad->dev.id.bustype = BUS_USB;
-	xpad->dev.id.vendor = le16_to_cpu(udev->descriptor.idVendor);
-	xpad->dev.id.product = le16_to_cpu(udev->descriptor.idProduct);
-	xpad->dev.id.version = le16_to_cpu(udev->descriptor.bcdDevice);
+	usb_to_input_id(udev, &xpad->dev.id);
 	xpad->dev.dev = &intf->dev;
 	xpad->dev.private = xpad;
 	xpad->dev.name = xpad_device[i].name;
diff --git a/drivers/usb/media/konicawc.c b/drivers/usb/media/konicawc.c
index 08521a2..20ac9e1 100644
--- a/drivers/usb/media/konicawc.c
+++ b/drivers/usb/media/konicawc.c
@@ -16,6 +16,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/input.h>
+#include <linux/usb_input.h>
 
 #include "usbvideo.h"
 
@@ -845,10 +846,7 @@
 		cam->input.private = cam;
 		cam->input.evbit[0] = BIT(EV_KEY);
 		cam->input.keybit[LONG(BTN_0)] = BIT(BTN_0);
-		cam->input.id.bustype = BUS_USB;
-		cam->input.id.vendor = le16_to_cpu(dev->descriptor.idVendor);
-		cam->input.id.product = le16_to_cpu(dev->descriptor.idProduct);
-		cam->input.id.version = le16_to_cpu(dev->descriptor.bcdDevice);
+		usb_to_input_id(dev, &cam->input.id);
 		input_register_device(&cam->input);
 		
 		usb_make_path(dev, cam->input_physname, 56);
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index 66ec883..ad17892 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -23,6 +23,7 @@
  *
  * V0.1  (mh) Initial version
  * V0.11 (mh) Added raw support for HID 1.0 devices (no interrupt out endpoint)
+ * V0.12 (mh) Added kmalloc check for string buffer
  */
 
 #include <linux/config.h>
@@ -84,7 +85,7 @@
 	{ }					/* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, ld_usb_table);
-MODULE_VERSION("V0.11");
+MODULE_VERSION("V0.12");
 MODULE_AUTHOR("Michael Hund <mhund@ld-didactic.de>");
 MODULE_DESCRIPTION("LD USB Driver");
 MODULE_LICENSE("GPL");
@@ -635,6 +636,10 @@
 	     (le16_to_cpu(udev->descriptor.idProduct) == USB_DEVICE_ID_COM3LAB)) &&
 	    (le16_to_cpu(udev->descriptor.bcdDevice) <= 0x103)) {
 		buffer = kmalloc(256, GFP_KERNEL);
+		if (buffer == NULL) {
+			dev_err(&intf->dev, "Couldn't allocate string buffer\n");
+			goto error;
+		}
 		/* usb_string makes SETUP+STALL to leave always ControlReadLoop */
 		usb_string(udev, 255, buffer, 256);
 		kfree(buffer);
diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c
index 5f4496d..fcd6d3c 100644
--- a/drivers/usb/net/pegasus.c
+++ b/drivers/usb/net/pegasus.c
@@ -59,7 +59,6 @@
 
 static int loopback = 0;
 static int mii_mode = 0;
-static int multicast_filter_limit = 32;
 
 static struct usb_eth_dev usb_dev_id[] = {
 #define	PEGASUS_DEV(pn, vid, pid, flags)	\
diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c
index 626b016..59ab40e 100644
--- a/drivers/usb/net/rtl8150.c
+++ b/drivers/usb/net/rtl8150.c
@@ -167,8 +167,6 @@
 
 typedef struct rtl8150 rtl8150_t;
 
-static unsigned long multicast_filter_limit = 32;
-
 static void fill_skb_pool(rtl8150_t *);
 static void free_skb_pool(rtl8150_t *);
 static inline struct sk_buff *pull_skb(rtl8150_t *);
diff --git a/drivers/usb/net/zd1201.c b/drivers/usb/net/zd1201.c
index 3b387b0..29cd801 100644
--- a/drivers/usb/net/zd1201.c
+++ b/drivers/usb/net/zd1201.c
@@ -29,6 +29,7 @@
 	{USB_DEVICE(0x0ace, 0x1201)}, /* ZyDAS ZD1201 Wireless USB Adapter */
 	{USB_DEVICE(0x050d, 0x6051)}, /* Belkin F5D6051 usb  adapter */
 	{USB_DEVICE(0x0db0, 0x6823)}, /* MSI UB11B usb  adapter */
+	{USB_DEVICE(0x1044, 0x8005)}, /* GIGABYTE GN-WLBZ201 usb adapter */
 	{}
 };
 
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 0b03dda..d1964a0 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -429,6 +429,9 @@
 	{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) },
 	{ USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_MHAM_Y6_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_MHAM_Y8_PID) },
+	{ USB_DEVICE(EVOLUTION_VID, EVOLUTION_ER1_PID) },
 	{ }						/* Terminating entry */
 };
 
@@ -545,6 +548,7 @@
 
 
 #define WDR_TIMEOUT 5000 /* default urb timeout */
+#define WDR_SHORT_TIMEOUT 1000	/* shorter urb timeout */
 
 /* High and low are for DTR, RTS etc etc */
 #define HIGH 1
@@ -593,62 +597,59 @@
 	 return(ftdi_232bm_baud_base_to_divisor(baud, 48000000));
 }
 
-static int set_rts(struct usb_serial_port *port, int high_or_low)
+#define set_mctrl(port, set)		update_mctrl((port), (set), 0)
+#define clear_mctrl(port, clear)	update_mctrl((port), 0, (clear))
+
+static int update_mctrl(struct usb_serial_port *port, unsigned int set, unsigned int clear)
 {
 	struct ftdi_private *priv = usb_get_serial_port_data(port);
 	char *buf;
-	unsigned ftdi_high_or_low;
+	unsigned urb_value;
 	int rv;
-	
-	buf = kmalloc(1, GFP_NOIO);
-	if (!buf)
-		return -ENOMEM;
-	
-	if (high_or_low) {
-		ftdi_high_or_low = FTDI_SIO_SET_RTS_HIGH;
-		priv->last_dtr_rts |= TIOCM_RTS;
-	} else {
-		ftdi_high_or_low = FTDI_SIO_SET_RTS_LOW;
-		priv->last_dtr_rts &= ~TIOCM_RTS;
+
+	if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) {
+		dbg("%s - DTR|RTS not being set|cleared", __FUNCTION__);
+		return 0;	/* no change */
 	}
+
+	buf = kmalloc(1, GFP_NOIO);
+	if (!buf) {
+		return -ENOMEM;
+	}
+
+	clear &= ~set;	/* 'set' takes precedence over 'clear' */
+	urb_value = 0;
+	if (clear & TIOCM_DTR)
+		urb_value |= FTDI_SIO_SET_DTR_LOW;
+	if (clear & TIOCM_RTS)
+		urb_value |= FTDI_SIO_SET_RTS_LOW;
+	if (set & TIOCM_DTR)
+		urb_value |= FTDI_SIO_SET_DTR_HIGH;
+	if (set & TIOCM_RTS)
+		urb_value |= FTDI_SIO_SET_RTS_HIGH;
 	rv = usb_control_msg(port->serial->dev,
 			       usb_sndctrlpipe(port->serial->dev, 0),
 			       FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
 			       FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-			       ftdi_high_or_low, priv->interface, 
+			       urb_value, priv->interface,
 			       buf, 0, WDR_TIMEOUT);
 
 	kfree(buf);
-	return rv;
-}
-
-
-static int set_dtr(struct usb_serial_port *port, int high_or_low)
-{
-	struct ftdi_private *priv = usb_get_serial_port_data(port);
-	char *buf;
-	unsigned ftdi_high_or_low;
-	int rv;
-	
-	buf = kmalloc(1, GFP_NOIO);
-	if (!buf)
-		return -ENOMEM;
-
-	if (high_or_low) {
-		ftdi_high_or_low = FTDI_SIO_SET_DTR_HIGH;
-		priv->last_dtr_rts |= TIOCM_DTR;
+	if (rv < 0) {
+		err("%s Error from MODEM_CTRL urb: DTR %s, RTS %s",
+				__FUNCTION__,
+				(set & TIOCM_DTR) ? "HIGH" :
+				(clear & TIOCM_DTR) ? "LOW" : "unchanged",
+				(set & TIOCM_RTS) ? "HIGH" :
+				(clear & TIOCM_RTS) ? "LOW" : "unchanged");
 	} else {
-		ftdi_high_or_low = FTDI_SIO_SET_DTR_LOW;
-		priv->last_dtr_rts &= ~TIOCM_DTR;
+		dbg("%s - DTR %s, RTS %s", __FUNCTION__,
+				(set & TIOCM_DTR) ? "HIGH" :
+				(clear & TIOCM_DTR) ? "LOW" : "unchanged",
+				(set & TIOCM_RTS) ? "HIGH" :
+				(clear & TIOCM_RTS) ? "LOW" : "unchanged");
+		priv->last_dtr_rts = (priv->last_dtr_rts & ~clear) | set;
 	}
-	rv = usb_control_msg(port->serial->dev,
-			       usb_sndctrlpipe(port->serial->dev, 0),
-			       FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-			       FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-			       ftdi_high_or_low, priv->interface, 
-			       buf, 0, WDR_TIMEOUT);
-
-	kfree(buf);
 	return rv;
 }
 
@@ -681,7 +682,7 @@
 			    FTDI_SIO_SET_BAUDRATE_REQUEST,
 			    FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
 			    urb_value, urb_index,
-			    buf, 0, 100);
+			    buf, 0, WDR_SHORT_TIMEOUT);
 
 	kfree(buf);
 	return rv;
@@ -1219,12 +1220,7 @@
 	/* FIXME: Flow control might be enabled, so it should be checked -
 	   we have no control of defaults! */
 	/* Turn on RTS and DTR since we are not flow controlling by default */
-	if (set_dtr(port, HIGH) < 0) {
-		err("%s Error from DTR HIGH urb", __FUNCTION__);
-	}
-	if (set_rts(port, HIGH) < 0){
-		err("%s Error from RTS HIGH urb", __FUNCTION__);
-	}
+	set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
 
 	/* Not throttled */
 	spin_lock_irqsave(&priv->rx_lock, flags);
@@ -1274,14 +1270,8 @@
 			err("error from flowcontrol urb");
 		}	    
 
-		/* drop DTR */
-		if (set_dtr(port, LOW) < 0){
-			err("Error from DTR LOW urb");
-		}
-		/* drop RTS */
-		if (set_rts(port, LOW) < 0) {
-			err("Error from RTS LOW urb");
-		}
+		/* drop RTS and DTR */
+		clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
 	} /* Note change no line if hupcl is off */
 
 	/* cancel any scheduled reading */
@@ -1797,7 +1787,7 @@
 			    FTDI_SIO_SET_DATA_REQUEST, 
 			    FTDI_SIO_SET_DATA_REQUEST_TYPE,
 			    urb_value , priv->interface,
-			    buf, 0, 100) < 0) {
+			    buf, 0, WDR_SHORT_TIMEOUT) < 0) {
 		err("%s FAILED to set databits/stopbits/parity", __FUNCTION__);
 	}	   
 
@@ -1812,25 +1802,14 @@
 			err("%s error from disable flowcontrol urb", __FUNCTION__);
 		}	    
 		/* Drop RTS and DTR */
-		if (set_dtr(port, LOW) < 0){
-			err("%s Error from DTR LOW urb", __FUNCTION__);
-		}
-		if (set_rts(port, LOW) < 0){
-			err("%s Error from RTS LOW urb", __FUNCTION__);
-		}	
-		
+		clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
 	} else {
 		/* set the baudrate determined before */
 		if (change_speed(port)) {
 			err("%s urb failed to set baurdrate", __FUNCTION__);
 		}
 		/* Ensure  RTS and DTR are raised */
-		else if (set_dtr(port, HIGH) < 0){
-			err("%s Error from DTR HIGH urb", __FUNCTION__);
-		}
-		else if (set_rts(port, HIGH) < 0){
-			err("%s Error from RTS HIGH urb", __FUNCTION__);
-		}	
+		set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
 	}
 
 	/* Set flow control */
@@ -1942,35 +1921,8 @@
 
 static int ftdi_tiocmset(struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear)
 {
-	int ret;
-	
 	dbg("%s TIOCMSET", __FUNCTION__);
-	if (set & TIOCM_DTR){
-		if ((ret = set_dtr(port, HIGH)) < 0) {
-			err("Urb to set DTR failed");
-			return(ret);
-		}
-	}
-	if (set & TIOCM_RTS) {
-		if ((ret = set_rts(port, HIGH)) < 0){
-			err("Urb to set RTS failed");
-			return(ret);
-		}
-	}
-	
-	if (clear & TIOCM_DTR){
-		if ((ret = set_dtr(port, LOW)) < 0){
-			err("Urb to unset DTR failed");
-			return(ret);
-		}
-	}	
-	if (clear & TIOCM_RTS) {
-		if ((ret = set_rts(port, LOW)) < 0){
-			err("Urb to unset RTS failed");
-			return(ret);
-		}
-	}
-	return(0);
+	return update_mctrl(port, set, clear);
 }
 
 
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 8866376..9f43420 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -265,10 +265,24 @@
 #define MOBILITY_USB_SERIAL_PID		0x0202	/* EasiDock USB 200 serial */
 
 /*
+ * microHAM product IDs (http://www.microham.com).
+ * Submitted by Justin Burket (KL1RL) <zorton@jtan.com>.
+ */
+#define FTDI_MHAM_Y6_PID 0xEEEA		/* USB-Y6 interface */
+#define FTDI_MHAM_Y8_PID 0xEEEB		/* USB-Y8 interface */
+
+/*
  * Active Robots product ids.
  */
 #define FTDI_ACTIVE_ROBOTS_PID	0xE548	/* USB comms board */
 
+/*
+ * Evolution Robotics products (http://www.evolution.com/).
+ * Submitted by Shawn M. Lavelle.
+ */
+#define EVOLUTION_VID		0xDEEE	/* Vendor ID */
+#define EVOLUTION_ER1_PID	0x0300	/* ER1 Control Module */
+
 /* Commands */
 #define FTDI_SIO_RESET 		0 /* Reset the port */
 #define FTDI_SIO_MODEM_CTRL 	1 /* Set the modem control register */
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index 6051a64..353f24d 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -257,7 +257,8 @@
 		endpoint = &iface_desc->endpoint[i].desc;
 
 		if (!dev->bulk_in_endpointAddr &&
-		    (endpoint->bEndpointAddress & USB_DIR_IN) &&
+		    ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+					== USB_DIR_IN) &&
 		    ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
 					== USB_ENDPOINT_XFER_BULK)) {
 			/* we found a bulk in endpoint */
@@ -272,7 +273,8 @@
 		}
 
 		if (!dev->bulk_out_endpointAddr &&
-		    !(endpoint->bEndpointAddress & USB_DIR_OUT) &&
+		    ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+					== USB_DIR_OUT) &&
 		    ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
 					== USB_ENDPOINT_XFER_BULK)) {
 			/* we found a bulk out endpoint */
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 40784a9..d2e19f6 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -80,10 +80,12 @@
  */
 void fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, u32 height)
 {
-	int i;
+	int i, j;
 
 	for (i = height; i--; ) {
-		memcpy(dst, src, s_pitch);
+		/* s_pitch is a few bytes at the most, memcpy is suboptimal */
+		for (j = 0; j < s_pitch; j++)
+			dst[j] = src[j];
 		src += s_pitch;
 		dst += d_pitch;
 	}
diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
index 63b505c..ed1d4d1 100644
--- a/drivers/video/fbsysfs.c
+++ b/drivers/video/fbsysfs.c
@@ -244,15 +244,15 @@
 
 /* Format for cmap is "%02x%c%4x%4x%4x\n" */
 /* %02x entry %c transp %4x red %4x blue %4x green \n */
-/* 255 rows at 16 chars equals 4096 */
-/* PAGE_SIZE can be 4096 or larger */
+/* 256 rows at 16 chars equals 4096, the normal page size */
+/* the code will automatically adjust for different page sizes */
 static ssize_t store_cmap(struct class_device *class_device, const char *buf,
 			  size_t count)
 {
 	struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device);
 	int rc, i, start, length, transp = 0;
 
-	if ((count > 4096) || ((count % 16) != 0) || (PAGE_SIZE < 4096))
+	if ((count > PAGE_SIZE) || ((count % 16) != 0))
 		return -EINVAL;
 
 	if (!fb_info->fbops->fb_setcolreg && !fb_info->fbops->fb_setcmap)
@@ -317,18 +317,18 @@
 	   !fb_info->cmap.green)
 		return -EINVAL;
 
-	if (PAGE_SIZE < 4096)
+	if (fb_info->cmap.len > PAGE_SIZE / 16)
 		return -EINVAL;
 
 	/* don't mess with the format, the buffer is PAGE_SIZE */
-	/* 255 entries at 16 chars per line equals 4096 = PAGE_SIZE */
+	/* 256 entries at 16 chars per line equals 4096 = PAGE_SIZE */
 	for (i = 0; i < fb_info->cmap.len; i++) {
-		sprintf(&buf[ i * 16], "%02x%c%4x%4x%4x\n", i + fb_info->cmap.start,
+		snprintf(&buf[ i * 16], PAGE_SIZE - i * 16, "%02x%c%4x%4x%4x\n", i + fb_info->cmap.start,
 			((fb_info->cmap.transp && fb_info->cmap.transp[i]) ? '*' : ' '),
 			fb_info->cmap.red[i], fb_info->cmap.blue[i],
 			fb_info->cmap.green[i]);
 	}
-	return 4096;
+	return 16 * fb_info->cmap.len;
 }
 
 static ssize_t store_blank(struct class_device *class_device, const char * buf,
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c
index 9ed1a93..a272592 100644
--- a/drivers/video/vesafb.c
+++ b/drivers/video/vesafb.c
@@ -45,7 +45,7 @@
 };
 
 static int             inverse   = 0;
-static int             mtrr      = 1;
+static int             mtrr      = 3; /* default to write-combining */
 static int	       vram_remap __initdata = 0; /* Set amount of memory to be used */
 static int	       vram_total __initdata = 0; /* Set total amount of memory */
 static int             pmi_setpal = 0;	/* pmi for palette changes ??? */
@@ -204,8 +204,8 @@
 			pmi_setpal=0;
 		else if (! strcmp(this_opt, "pmipal"))
 			pmi_setpal=1;
-		else if (! strcmp(this_opt, "mtrr"))
-			mtrr=1;
+		else if (! strncmp(this_opt, "mtrr:", 5))
+			mtrr = simple_strtoul(this_opt+5, NULL, 0);
 		else if (! strcmp(this_opt, "nomtrr"))
 			mtrr=0;
 		else if (! strncmp(this_opt, "vtotal:", 7))
@@ -387,14 +387,39 @@
 
 	if (mtrr) {
 		unsigned int temp_size = size_total;
-		/* Find the largest power-of-two */
-		while (temp_size & (temp_size - 1))
-			temp_size &= (temp_size - 1);
+		unsigned int type = 0;
 
-		/* Try and find a power of two to add */
-		while (temp_size > PAGE_SIZE &&
-			mtrr_add(vesafb_fix.smem_start, temp_size, MTRR_TYPE_WRCOMB, 1)==-EINVAL) {
-			temp_size >>= 1;
+		switch (mtrr) {
+		case 1:
+			type = MTRR_TYPE_UNCACHABLE;
+			break;
+		case 2:
+			type = MTRR_TYPE_WRBACK;
+			break;
+		case 3:
+			type = MTRR_TYPE_WRCOMB;
+			break;
+		case 4:
+			type = MTRR_TYPE_WRTHROUGH;
+			break;
+		default:
+			type = 0;
+			break;
+		}
+
+		if (type) {
+			int rc;
+
+			/* Find the largest power-of-two */
+			while (temp_size & (temp_size - 1))
+				temp_size &= (temp_size - 1);
+
+			/* Try and find a power of two to add */
+			do {
+				rc = mtrr_add(vesafb_fix.smem_start, temp_size,
+					      type, 1);
+				temp_size >>= 1;
+			} while (temp_size >= PAGE_SIZE && rc == -EINVAL);
 		}
 	}
 	
diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig
index 4f12079..711b909 100644
--- a/drivers/w1/Kconfig
+++ b/drivers/w1/Kconfig
@@ -30,7 +30,7 @@
 	  This support is also available as a module.  If so, the module
 	  will be called ds9490r.ko.
 
-config W1_DS9490R_BRIDGE
+config W1_DS9490_BRIDGE
 	tristate "DS9490R USB <-> W1 transport layer for 1-wire"
 	depends on W1_DS9490
 	help
diff --git a/fs/bio.c b/fs/bio.c
index ca8f7a8..249dd6b 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -261,6 +261,7 @@
 	 */
 	bio->bi_vcnt = bio_src->bi_vcnt;
 	bio->bi_size = bio_src->bi_size;
+	bio->bi_idx = bio_src->bi_idx;
 	bio_phys_segments(q, bio);
 	bio_hw_segments(q, bio);
 }
diff --git a/fs/hostfs/hostfs.h b/fs/hostfs/hostfs.h
index c1516d0..67bca0d 100644
--- a/fs/hostfs/hostfs.h
+++ b/fs/hostfs/hostfs.h
@@ -69,6 +69,7 @@
 extern int write_file(int fd, unsigned long long *offset, const char *buf,
 		      int len);
 extern int lseek_file(int fd, long long offset, int whence);
+extern int fsync_file(int fd, int datasync);
 extern int file_create(char *name, int ur, int uw, int ux, int gr,
 		       int gw, int gx, int or, int ow, int ox);
 extern int set_attr(const char *file, struct hostfs_iattr *attrs);
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index 88e68ca..b2d1820 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -382,7 +382,7 @@
 
 int hostfs_fsync(struct file *file, struct dentry *dentry, int datasync)
 {
-	return(0);
+	return fsync_file(HOSTFS_I(dentry->d_inode)->fd, datasync);
 }
 
 static struct file_operations hostfs_file_fops = {
diff --git a/fs/hostfs/hostfs_user.c b/fs/hostfs/hostfs_user.c
index 4796e84..b97809d 100644
--- a/fs/hostfs/hostfs_user.c
+++ b/fs/hostfs/hostfs_user.c
@@ -153,10 +153,24 @@
 	int ret;
 
 	ret = lseek64(fd, offset, whence);
-	if(ret < 0) return(-errno);
+	if(ret < 0)
+		return(-errno);
 	return(0);
 }
 
+int fsync_file(int fd, int datasync)
+{
+	int ret;
+	if (datasync)
+		ret = fdatasync(fd);
+	else
+		ret = fsync(fd);
+
+	if (ret < 0)
+		return -errno;
+	return 0;
+}
+
 void close_file(void *stream)
 {
 	close(*((int *) stream));
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 335288b9..4013d79 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -437,8 +437,8 @@
 {
 	struct dentry *dir = kobj->dentry;
 	struct dentry *victim;
-	struct sysfs_dirent *sd;
-	umode_t umode = (mode & S_IALLUGO) | S_IFREG;
+	struct inode * inode;
+	struct iattr newattrs;
 	int res = -ENOENT;
 
 	down(&dir->d_inode->i_sem);
@@ -446,13 +446,15 @@
 	if (!IS_ERR(victim)) {
 		if (victim->d_inode &&
 		    (victim->d_parent->d_inode == dir->d_inode)) {
-			sd = victim->d_fsdata;
-			attr->mode = mode;
-			sd->s_mode = umode;
-			victim->d_inode->i_mode = umode;
-			dput(victim);
-			res = 0;
+			inode = victim->d_inode;
+			down(&inode->i_sem);
+			newattrs.ia_mode = (mode & S_IALLUGO) |
+						(inode->i_mode & ~S_IALLUGO);
+			newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
+			res = notify_change(victim, &newattrs);
+			up(&inode->i_sem);
 		}
+		dput(victim);
 	}
 	up(&dir->d_inode->i_sem);
 
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index 8de13ba..d727dc9 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -85,7 +85,7 @@
 
 		if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
 			mode &= ~S_ISGID;
-		sd_iattr->ia_mode = mode;
+		sd_iattr->ia_mode = sd->s_mode = mode;
 	}
 
 	return error;
diff --git a/include/asm-arm/bitops.h b/include/asm-arm/bitops.h
index c1adc6b..aad7aad 100644
--- a/include/asm-arm/bitops.h
+++ b/include/asm-arm/bitops.h
@@ -229,6 +229,7 @@
 extern int _find_first_bit_be(const unsigned long *p, unsigned size);
 extern int _find_next_bit_be(const unsigned long *p, int size, int offset);
 
+#ifndef CONFIG_SMP
 /*
  * The __* form of bitops are non-atomic and may be reordered.
  */
@@ -241,6 +242,10 @@
 	(__builtin_constant_p(nr) ?		\
 	 ____atomic_##name(nr, p) :		\
 	 _##name##_be(nr,p))
+#else
+#define ATOMIC_BITOP_LE(name,nr,p)	_##name##_le(nr,p)
+#define ATOMIC_BITOP_BE(name,nr,p)	_##name##_be(nr,p)
+#endif
 
 #define NONATOMIC_BITOP(name,nr,p)		\
 	(____nonatomic_##name(nr, p))
diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h
index 195ccdc..450eae2 100644
--- a/include/asm-generic/sections.h
+++ b/include/asm-generic/sections.h
@@ -11,5 +11,6 @@
 extern char _sextratext[] __attribute__((weak));
 extern char _eextratext[] __attribute__((weak));
 extern char _end[];
+extern char __per_cpu_start[], __per_cpu_end[];
 
 #endif /* _ASM_GENERIC_SECTIONS_H_ */
diff --git a/include/asm-i386/bitops.h b/include/asm-i386/bitops.h
index 9db0b712..ddf1739 100644
--- a/include/asm-i386/bitops.h
+++ b/include/asm-i386/bitops.h
@@ -311,6 +311,20 @@
 int find_next_zero_bit(const unsigned long *addr, int size, int offset);
 
 /**
+ * __ffs - find first bit in word.
+ * @word: The word to search
+ *
+ * Undefined if no bit exists, so code should check against 0 first.
+ */
+static inline unsigned long __ffs(unsigned long word)
+{
+	__asm__("bsfl %1,%0"
+		:"=r" (word)
+		:"rm" (word));
+	return word;
+}
+
+/**
  * find_first_bit - find the first set bit in a memory region
  * @addr: The address to start the search at
  * @size: The maximum size to search
@@ -320,22 +334,15 @@
  */
 static inline int find_first_bit(const unsigned long *addr, unsigned size)
 {
-	int d0, d1;
-	int res;
+	int x = 0;
 
-	/* This looks at memory. Mark it volatile to tell gcc not to move it around */
-	__asm__ __volatile__(
-		"xorl %%eax,%%eax\n\t"
-		"repe; scasl\n\t"
-		"jz 1f\n\t"
-		"leal -4(%%edi),%%edi\n\t"
-		"bsfl (%%edi),%%eax\n"
-		"1:\tsubl %%ebx,%%edi\n\t"
-		"shll $3,%%edi\n\t"
-		"addl %%edi,%%eax"
-		:"=a" (res), "=&c" (d0), "=&D" (d1)
-		:"1" ((size + 31) >> 5), "2" (addr), "b" (addr) : "memory");
-	return res;
+	while (x < size) {
+		unsigned long val = *addr++;
+		if (val)
+			return __ffs(val) + x;
+		x += (sizeof(*addr)<<3);
+	}
+	return x;
 }
 
 /**
@@ -360,20 +367,6 @@
 	return word;
 }
 
-/**
- * __ffs - find first bit in word.
- * @word: The word to search
- *
- * Undefined if no bit exists, so code should check against 0 first.
- */
-static inline unsigned long __ffs(unsigned long word)
-{
-	__asm__("bsfl %1,%0"
-		:"=r" (word)
-		:"rm" (word));
-	return word;
-}
-
 /*
  * fls: find last bit set.
  */
diff --git a/include/asm-i386/smp.h b/include/asm-i386/smp.h
index edad9b4..a283738 100644
--- a/include/asm-i386/smp.h
+++ b/include/asm-i386/smp.h
@@ -37,9 +37,6 @@
 extern cpumask_t cpu_sibling_map[];
 extern cpumask_t cpu_core_map[];
 
-extern void smp_flush_tlb(void);
-extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs);
-extern void smp_invalidate_rcv(void);		/* Process an NMI */
 extern void (*mtrr_hook) (void);
 extern void zap_low_mappings (void);
 extern void lock_ipi_call_lock(void);
diff --git a/include/asm-um/vm86.h b/include/asm-um/vm86.h
new file mode 100644
index 0000000..7801f82
--- /dev/null
+++ b/include/asm-um/vm86.h
@@ -0,0 +1,6 @@
+#ifndef __UM_VM86_H
+#define __UM_VM86_H
+
+#include "asm/arch/vm86.h"
+
+#endif
diff --git a/include/asm-x86_64/bitops.h b/include/asm-x86_64/bitops.h
index a31bb99..05a0d37 100644
--- a/include/asm-x86_64/bitops.h
+++ b/include/asm-x86_64/bitops.h
@@ -348,8 +348,7 @@
 		return __ffs(b[0]);
 	if (b[1])
 		return __ffs(b[1]) + 64;
-	if (b[2])
-		return __ffs(b[2]) + 128;
+	return __ffs(b[2]) + 128;
 }
 
 /**
diff --git a/include/asm-x86_64/bug.h b/include/asm-x86_64/bug.h
index 3d2a666..eed7856 100644
--- a/include/asm-x86_64/bug.h
+++ b/include/asm-x86_64/bug.h
@@ -8,17 +8,24 @@
  * this frame.
  */
 struct bug_frame {
-       unsigned char ud2[2];
+	unsigned char ud2[2];
+	unsigned char mov;
 	/* should use 32bit offset instead, but the assembler doesn't 
 	   like it */
 	char *filename;
+	unsigned char ret;
 	unsigned short line;
 } __attribute__((packed));
 
 #ifdef CONFIG_BUG
 #define HAVE_ARCH_BUG
-#define BUG() \
-	asm volatile("ud2 ; .quad %c1 ; .short %c0" :: \
+/* We turn the bug frame into valid instructions to not confuse
+   the disassembler. Thanks to Jan Beulich & Suresh Siddha
+   for nice instruction selection.
+   The magic numbers generate mov $64bitimm,%eax ; ret $offset. */
+#define BUG() 								\
+	asm volatile(							\
+	"ud2 ; .byte 0xa3 ; .quad %c1 ; .byte 0xc2 ; .short %c0" :: 	\
 		     "i"(__LINE__), "i" (__stringify(__FILE__)))
 void out_of_line_bug(void);
 #else
diff --git a/include/asm-x86_64/desc.h b/include/asm-x86_64/desc.h
index 6aefb9c..c89b58b 100644
--- a/include/asm-x86_64/desc.h
+++ b/include/asm-x86_64/desc.h
@@ -75,6 +75,7 @@
  */
 extern struct desc_struct default_ldt[];
 extern struct gate_struct idt_table[]; 
+extern struct desc_ptr cpu_gdt_descr[];
 
 static inline void _set_gate(void *adr, unsigned type, unsigned long func, unsigned dpl, unsigned ist)  
 {
diff --git a/include/asm-x86_64/ipi.h b/include/asm-x86_64/ipi.h
index d184184..5e166b9 100644
--- a/include/asm-x86_64/ipi.h
+++ b/include/asm-x86_64/ipi.h
@@ -82,30 +82,27 @@
 	 */
 	local_irq_save(flags);
 
-	for (query_cpu = 0; query_cpu < NR_CPUS; ++query_cpu) {
-		if (cpu_isset(query_cpu, mask)) {
+	for_each_cpu_mask(query_cpu, mask) {
+		/*
+		 * Wait for idle.
+		 */
+		apic_wait_icr_idle();
 
-			/*
-			 * Wait for idle.
-			 */
-			apic_wait_icr_idle();
+		/*
+		 * prepare target chip field
+		 */
+		cfg = __prepare_ICR2(x86_cpu_to_apicid[query_cpu]);
+		apic_write_around(APIC_ICR2, cfg);
 
-			/*
-			 * prepare target chip field
-			 */
-			cfg = __prepare_ICR2(x86_cpu_to_apicid[query_cpu]);
-			apic_write_around(APIC_ICR2, cfg);
+		/*
+		 * program the ICR
+		 */
+		cfg = __prepare_ICR(0, vector, APIC_DEST_PHYSICAL);
 
-			/*
-			 * program the ICR
-			 */
-			cfg = __prepare_ICR(0, vector, APIC_DEST_PHYSICAL);
-
-			/*
-			 * Send the IPI. The write to APIC_ICR fires this off.
-			 */
-			apic_write_around(APIC_ICR, cfg);
-		}
+		/*
+		 * Send the IPI. The write to APIC_ICR fires this off.
+		 */
+		apic_write_around(APIC_ICR, cfg);
 	}
 	local_irq_restore(flags);
 }
diff --git a/include/asm-x86_64/irq.h b/include/asm-x86_64/irq.h
index eb3b7aa..4482657 100644
--- a/include/asm-x86_64/irq.h
+++ b/include/asm-x86_64/irq.h
@@ -57,4 +57,6 @@
 extern void fixup_irqs(cpumask_t map);
 #endif
 
+#define __ARCH_HAS_DO_SOFTIRQ 1
+
 #endif /* _ASM_IRQ_H */
diff --git a/include/asm-x86_64/msr.h b/include/asm-x86_64/msr.h
index bc70023..ba15279 100644
--- a/include/asm-x86_64/msr.h
+++ b/include/asm-x86_64/msr.h
@@ -218,7 +218,7 @@
 #define MSR_K7_PERFCTR3            0xC0010007
 #define MSR_K8_TOP_MEM1		   0xC001001A
 #define MSR_K8_TOP_MEM2		   0xC001001D
-#define MSR_K8_SYSCFG		   0xC0000010	
+#define MSR_K8_SYSCFG		   0xC0010010
 
 /* K6 MSRs */
 #define MSR_K6_EFER			0xC0000080
diff --git a/include/asm-x86_64/pgtable.h b/include/asm-x86_64/pgtable.h
index 4eec176..4e167b5 100644
--- a/include/asm-x86_64/pgtable.h
+++ b/include/asm-x86_64/pgtable.h
@@ -176,6 +176,8 @@
 	(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_PCD)
 #define __PAGE_KERNEL_LARGE \
 	(__PAGE_KERNEL | _PAGE_PSE)
+#define __PAGE_KERNEL_LARGE_EXEC \
+	(__PAGE_KERNEL_EXEC | _PAGE_PSE)
 
 #define MAKE_GLOBAL(x) __pgprot((x) | _PAGE_GLOBAL)
 
diff --git a/include/asm-x86_64/smp.h b/include/asm-x86_64/smp.h
index aeb1b73..de8b57b 100644
--- a/include/asm-x86_64/smp.h
+++ b/include/asm-x86_64/smp.h
@@ -46,12 +46,12 @@
 extern void lock_ipi_call_lock(void);
 extern void unlock_ipi_call_lock(void);
 extern int smp_num_siblings;
-extern void smp_flush_tlb(void);
-extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs);
 extern void smp_send_reschedule(int cpu);
-extern void smp_invalidate_rcv(void);		/* Process an NMI */
 extern void zap_low_mappings(void);
 void smp_stop_cpu(void);
+extern int smp_call_function_single(int cpuid, void (*func) (void *info),
+				void *info, int retry, int wait);
+
 extern cpumask_t cpu_sibling_map[NR_CPUS];
 extern cpumask_t cpu_core_map[NR_CPUS];
 extern u8 phys_proc_id[NR_CPUS];
diff --git a/include/asm-x86_64/system.h b/include/asm-x86_64/system.h
index 7616573..8606e17 100644
--- a/include/asm-x86_64/system.h
+++ b/include/asm-x86_64/system.h
@@ -116,12 +116,12 @@
 /*
  * Alternative inline assembly with input.
  * 
- * Pecularities:
+ * Peculiarities:
  * No memory clobber here. 
  * Argument numbers start with 1.
  * Best is to use constraints that are fixed size (like (%1) ... "r")
  * If you use variable sized constraints like "m" or "g" in the 
- * replacement maake sure to pad to the worst case length.
+ * replacement make sure to pad to the worst case length.
  */
 #define alternative_input(oldinstr, newinstr, feature, input...)	\
 	asm volatile ("661:\n\t" oldinstr "\n662:\n"			\
@@ -335,9 +335,6 @@
 void disable_hlt(void);
 void enable_hlt(void);
 
-#define HAVE_EAT_KEY
-void eat_key(void);
-
 extern unsigned long arch_align_stack(unsigned long sp);
 
 #endif
diff --git a/include/asm-x86_64/tlbflush.h b/include/asm-x86_64/tlbflush.h
index 0617423..505b0cf 100644
--- a/include/asm-x86_64/tlbflush.h
+++ b/include/asm-x86_64/tlbflush.h
@@ -56,8 +56,9 @@
  *  - flush_tlb_kernel_range(start, end) flushes a range of kernel pages
  *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
  *
- * ..but the x86_64 has somewhat limited tlb flushing capabilities,
- * and page-granular flushes are available only on i486 and up.
+ * x86-64 can only flush individual pages or full VMs. For a range flush
+ * we always do the full VM. Might be worth trying if for a small
+ * range a few INVLPGs in a row are a win.
  */
 
 #ifndef CONFIG_SMP
@@ -115,7 +116,9 @@
 static inline void flush_tlb_pgtables(struct mm_struct *mm,
 				      unsigned long start, unsigned long end)
 {
-	/* x86_64 does not keep any page table caches in TLB */
+	/* x86_64 does not keep any page table caches in a software TLB.
+	   The CPUs do in their hardware TLBs, but they are handled
+	   by the normal TLB flushing algorithms. */
 }
 
 #endif /* _X8664_TLBFLUSH_H */
diff --git a/include/linux/input.h b/include/linux/input.h
index b9cc0ac..bdc53c6 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -811,9 +811,9 @@
 
 	void *private;
 
-	char *name;
-	char *phys;
-	char *uniq;
+	const char *name;
+	const char *phys;
+	const char *uniq;
 	struct input_id id;
 
 	unsigned long evbit[NBITS(EV_MAX)];
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 7ac1496..8621cf4 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -971,6 +971,8 @@
 
 #define	isa_bridge	((struct pci_dev *)NULL)
 
+#define pci_dma_burst_advice(pdev, strat, strategy_parameter) do { } while (0)
+
 #else
 
 /*
@@ -985,9 +987,6 @@
 	return 0;
 }
 #endif
-
-#define pci_dma_burst_advice(pdev, strat, strategy_parameter) do { } while (0)
-
 #endif /* !CONFIG_PCI */
 
 /* these helpers provide future and backwards compatibility
diff --git a/include/linux/uinput.h b/include/linux/uinput.h
index 4c2c823..8487607 100644
--- a/include/linux/uinput.h
+++ b/include/linux/uinput.h
@@ -42,8 +42,7 @@
 	int			code;	/* UI_FF_UPLOAD, UI_FF_ERASE */
 
 	int			retval;
-	wait_queue_head_t	waitq;
-	int			completed;
+	struct completion	done;
 
 	union {
 		int		effect_id;
@@ -62,7 +61,7 @@
 
 	struct uinput_request	*requests[UINPUT_NUM_REQUESTS];
 	wait_queue_head_t	requests_waitq;
-	struct semaphore	requests_sem;
+	spinlock_t		requests_lock;
 };
 #endif	/* __KERNEL__ */
 
diff --git a/include/linux/usb_input.h b/include/linux/usb_input.h
new file mode 100644
index 0000000..716e0cc
--- /dev/null
+++ b/include/linux/usb_input.h
@@ -0,0 +1,25 @@
+#ifndef __USB_INPUT_H
+#define __USB_INPUT_H
+
+/*
+ * Copyright (C) 2005 Dmitry Torokhov
+ *
+ * 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/usb.h>
+#include <linux/input.h>
+#include <asm/byteorder.h>
+
+static inline void
+usb_to_input_id(const struct usb_device *dev, struct input_id *id)
+{
+	id->bustype = BUS_USB;
+	id->vendor = le16_to_cpu(dev->descriptor.idVendor);
+	id->product = le16_to_cpu(dev->descriptor.idProduct);
+	id->version = le16_to_cpu(dev->descriptor.bcdDevice);
+}
+
+#endif
diff --git a/include/sound/core.h b/include/sound/core.h
index f8c4ef0a..38b357f 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -126,25 +126,26 @@
 	struct snd_monitor_file *next;
 };
 
-struct snd_shutdown_f_ops;	/* define it later */
+struct snd_shutdown_f_ops;	/* define it later in init.c */
 
 /* main structure for soundcard */
 
 struct _snd_card {
-	int number;			/* number of soundcard (index to snd_cards) */
+	int number;			/* number of soundcard (index to
+								snd_cards) */
 
 	char id[16];			/* id string of this card */
 	char driver[16];		/* driver name */
 	char shortname[32];		/* short name of this soundcard */
 	char longname[80];		/* name of this soundcard */
 	char mixername[80];		/* mixer name */
-	char components[80];		/* card components delimited with space */
-
+	char components[80];		/* card components delimited with
+								space */
 	struct module *module;		/* top-level module */
 
 	void *private_data;		/* private data for soundcard */
-	void (*private_free) (snd_card_t *card); /* callback for freeing of private data */
-
+	void (*private_free) (snd_card_t *card); /* callback for freeing of
+								private data */
 	struct list_head devices;	/* devices */
 
 	unsigned int last_numid;	/* last used numeric ID */
@@ -160,7 +161,8 @@
 	struct proc_dir_entry *proc_root_link;	/* number link to real id */
 
 	struct snd_monitor_file *files; /* all files associated to this card */
-	struct snd_shutdown_f_ops *s_f_ops; /* file operations in the shutdown state */
+	struct snd_shutdown_f_ops *s_f_ops; /* file operations in the shutdown
+								state */
 	spinlock_t files_lock;		/* lock the files for this card */
 	int shutdown;			/* this card is going down */
 	wait_queue_head_t shutdown_sleep;
@@ -196,8 +198,6 @@
 	up(&card->power_lock);
 }
 
-int snd_power_wait(snd_card_t *card, unsigned int power_state, struct file *file);
-
 static inline unsigned int snd_power_get_state(snd_card_t *card)
 {
 	return card->power_state;
@@ -208,6 +208,10 @@
 	card->power_state = state;
 	wake_up(&card->power_sleep);
 }
+
+/* init.c */
+int snd_power_wait(snd_card_t *card, unsigned int power_state, struct file *file);
+
 int snd_card_set_pm_callback(snd_card_t *card,
 			     int (*suspend)(snd_card_t *, pm_message_t),
 			     int (*resume)(snd_card_t *),
@@ -238,15 +242,14 @@
 
 #endif /* CONFIG_PM */
 
-/* device.c */
-
 struct _snd_minor {
 	struct list_head list;		/* list of all minors per card */
 	int number;			/* minor number */
 	int device;			/* device number */
 	const char *comment;		/* for /proc/asound/devices */
 	struct file_operations *f_ops;	/* file operations */
-	char name[0];			/* device name (keep at the end of structure) */
+	char name[0];			/* device name (keep at the end of
+								structure) */
 };
 
 typedef struct _snd_minor snd_minor_t;
@@ -287,12 +290,12 @@
 void snd_memory_done(void);
 int snd_memory_info_init(void);
 int snd_memory_info_done(void);
-void *snd_hidden_kmalloc(size_t size, int flags);
-void *snd_hidden_kcalloc(size_t n, size_t size, int flags);
+void *snd_hidden_kmalloc(size_t size, unsigned int __nocast flags);
+void *snd_hidden_kcalloc(size_t n, size_t size, unsigned int __nocast flags);
 void snd_hidden_kfree(const void *obj);
 void *snd_hidden_vmalloc(unsigned long size);
 void snd_hidden_vfree(void *obj);
-char *snd_hidden_kstrdup(const char *s, int flags);
+char *snd_hidden_kstrdup(const char *s, unsigned int __nocast flags);
 #define kmalloc(size, flags) snd_hidden_kmalloc(size, flags)
 #define kcalloc(n, size, flags) snd_hidden_kcalloc(n, size, flags)
 #define kfree(obj) snd_hidden_kfree(obj)
@@ -411,7 +414,7 @@
 	printk(fmt ,##args)
 #endif
 /**
- * snd_assert - run-time assersion macro
+ * snd_assert - run-time assertion macro
  * @expr: expression
  * @args...: the action
  *
@@ -427,7 +430,7 @@
 	}\
 } while (0)
 /**
- * snd_runtime_check - run-time assersion macro
+ * snd_runtime_check - run-time assertion macro
  * @expr: expression
  * @args...: the action
  *
diff --git a/include/sound/driver.h b/include/sound/driver.h
index 948e9a1..0d12456 100644
--- a/include/sound/driver.h
+++ b/include/sound/driver.h
@@ -51,7 +51,7 @@
 #ifdef CONFIG_SND_DEBUG_MEMORY
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
-void *snd_wrapper_kmalloc(size_t, int);
+void *snd_wrapper_kmalloc(size_t, unsigned int __nocast);
 #undef kmalloc
 void snd_wrapper_kfree(const void *);
 #undef kfree
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
index c50b919..c2ef3f0 100644
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -1167,6 +1167,7 @@
 		       unsigned short extout_mask,
 		       long max_cache_bytes,
 		       int enable_ir,
+		       uint subsystem,
 		       emu10k1_t ** remu);
 
 int snd_emu10k1_pcm(emu10k1_t * emu, int device, snd_pcm_t ** rpcm);
diff --git a/include/sound/version.h b/include/sound/version.h
index 46acfa8..c085136 100644
--- a/include/sound/version.h
+++ b/include/sound/version.h
@@ -1,3 +1,3 @@
 /* include/version.h.  Generated by configure.  */
-#define CONFIG_SND_VERSION "1.0.9"
-#define CONFIG_SND_DATE " (Sun May 29 07:31:02 2005 UTC)"
+#define CONFIG_SND_VERSION "1.0.9b"
+#define CONFIG_SND_DATE " (Thu Jul 28 12:20:13 2005 UTC)"
diff --git a/init/main.c b/init/main.c
index b5e421e..c9c311c 100644
--- a/init/main.c
+++ b/init/main.c
@@ -51,6 +51,7 @@
 #include <asm/io.h>
 #include <asm/bugs.h>
 #include <asm/setup.h>
+#include <asm/sections.h>
 
 /*
  * This is one of the first .c files built. Error out early
@@ -323,8 +324,6 @@
 {
 	unsigned long size, i;
 	char *ptr;
-	/* Created by linker magic */
-	extern char __per_cpu_start[], __per_cpu_end[];
 
 	/* Copy section for each CPU (we discard the original) */
 	size = ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES);
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
index 5b7b473..10b2ad7 100644
--- a/kernel/posix-timers.c
+++ b/kernel/posix-timers.c
@@ -896,21 +896,10 @@
 			jiffies_64_f = get_jiffies_64();
 		}
 		/*
-		 * Take away now to get delta
+		 * Take away now to get delta and normalize
 		 */
-		oc.tv_sec -= now.tv_sec;
-		oc.tv_nsec -= now.tv_nsec;
-		/*
-		 * Normalize...
-		 */
-		while ((oc.tv_nsec - NSEC_PER_SEC) >= 0) {
-			oc.tv_nsec -= NSEC_PER_SEC;
-			oc.tv_sec++;
-		}
-		while ((oc.tv_nsec) < 0) {
-			oc.tv_nsec += NSEC_PER_SEC;
-			oc.tv_sec--;
-		}
+		set_normalized_timespec(&oc, oc.tv_sec - now.tv_sec,
+					oc.tv_nsec - now.tv_nsec);
 	}else{
 		jiffies_64_f = get_jiffies_64();
 	}
diff --git a/kernel/softirq.c b/kernel/softirq.c
index b4ab6af..31007d6 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -86,7 +86,7 @@
 	/* Reset the pending bitmask before enabling irqs */
 	local_softirq_pending() = 0;
 
-	local_irq_enable();
+	//local_irq_enable();
 
 	h = softirq_vec;
 
@@ -99,7 +99,7 @@
 		pending >>= 1;
 	} while (pending);
 
-	local_irq_disable();
+	//local_irq_disable();
 
 	pending = local_softirq_pending();
 	if (pending && --max_restart)
diff --git a/kernel/sys.c b/kernel/sys.c
index 8f25525..000e81a 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -392,7 +392,6 @@
 	}
 	notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
 	system_state = SYSTEM_RESTART;
-	device_suspend(PMSG_FREEZE);
 	device_shutdown();
 	printk(KERN_EMERG "Starting new kernel\n");
 	machine_shutdown();
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 0c42129..299f7f3 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -141,7 +141,7 @@
 
 config DEBUG_FS
 	bool "Debug Filesystem"
-	depends on DEBUG_KERNEL
+	depends on DEBUG_KERNEL && SYSFS
 	help
 	  debugfs is a virtual file system that kernel developers use to put
 	  debugging files into.  Enable this option to be able to read and
diff --git a/net/core/dev.c b/net/core/dev.c
index ff9dc02..52a3bf7a 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -901,8 +901,7 @@
 	smp_mb__after_clear_bit(); /* Commit netif_running(). */
 	while (test_bit(__LINK_STATE_RX_SCHED, &dev->state)) {
 		/* No hurry. */
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(1);
+		msleep(1);
 	}
 
 	/*
diff --git a/scripts/kconfig/gconf.c b/scripts/kconfig/gconf.c
index ad6b120..9f5aabd 100644
--- a/scripts/kconfig/gconf.c
+++ b/scripts/kconfig/gconf.c
@@ -178,17 +178,31 @@
 }
 
 
+void replace_button_icon(GladeXML * xml, GdkDrawable * window,
+			 GtkStyle * style, gchar * btn_name, gchar ** xpm)
+{
+	GdkPixmap *pixmap;
+	GdkBitmap *mask;
+	GtkToolButton *button;
+	GtkWidget *image;
+
+	pixmap = gdk_pixmap_create_from_xpm_d(window, &mask,
+					      &style->bg[GTK_STATE_NORMAL],
+					      xpm);
+
+	button = GTK_TOOL_BUTTON(glade_xml_get_widget(xml, btn_name));
+	image = gtk_image_new_from_pixmap(pixmap, mask);
+	gtk_widget_show(image);
+	gtk_tool_button_set_icon_widget(button, image);
+}
+
 /* Main Window Initialization */
-
-
 void init_main_window(const gchar * glade_file)
 {
 	GladeXML *xml;
 	GtkWidget *widget;
 	GtkTextBuffer *txtbuf;
 	char title[256];
-	GdkPixmap *pixmap;
-	GdkBitmap *mask;
 	GtkStyle *style;
 
 	xml = glade_xml_new(glade_file, "window1", NULL);
@@ -221,36 +235,22 @@
 	style = gtk_widget_get_style(main_wnd);
 	widget = glade_xml_get_widget(xml, "toolbar1");
 
-	pixmap = gdk_pixmap_create_from_xpm_d(main_wnd->window, &mask,
-					      &style->bg[GTK_STATE_NORMAL],
-					      (gchar **) xpm_single_view);
-	gtk_image_set_from_pixmap(GTK_IMAGE
-				  (((GtkToolbarChild
-				     *) (g_list_nth(GTK_TOOLBAR(widget)->
-						    children,
-						    5)->data))->icon),
-				  pixmap, mask);
-	pixmap =
-	    gdk_pixmap_create_from_xpm_d(main_wnd->window, &mask,
-					 &style->bg[GTK_STATE_NORMAL],
-					 (gchar **) xpm_split_view);
-	gtk_image_set_from_pixmap(GTK_IMAGE
-				  (((GtkToolbarChild
-				     *) (g_list_nth(GTK_TOOLBAR(widget)->
-						    children,
-						    6)->data))->icon),
-				  pixmap, mask);
-	pixmap =
-	    gdk_pixmap_create_from_xpm_d(main_wnd->window, &mask,
-					 &style->bg[GTK_STATE_NORMAL],
-					 (gchar **) xpm_tree_view);
-	gtk_image_set_from_pixmap(GTK_IMAGE
-				  (((GtkToolbarChild
-				     *) (g_list_nth(GTK_TOOLBAR(widget)->
-						    children,
-						    7)->data))->icon),
-				  pixmap, mask);
+#if 0	/* Use stock Gtk icons instead */
+	replace_button_icon(xml, main_wnd->window, style,
+			    "button1", (gchar **) xpm_back);
+	replace_button_icon(xml, main_wnd->window, style,
+			    "button2", (gchar **) xpm_load);
+	replace_button_icon(xml, main_wnd->window, style,
+			    "button3", (gchar **) xpm_save);
+#endif
+	replace_button_icon(xml, main_wnd->window, style,
+			    "button4", (gchar **) xpm_single_view);
+	replace_button_icon(xml, main_wnd->window, style,
+			    "button5", (gchar **) xpm_split_view);
+	replace_button_icon(xml, main_wnd->window, style,
+			    "button6", (gchar **) xpm_tree_view);
 
+#if 0
 	switch (view_mode) {
 	case SINGLE_VIEW:
 		widget = glade_xml_get_widget(xml, "button4");
@@ -265,7 +265,7 @@
 		g_signal_emit_by_name(widget, "clicked");
 		break;
 	}
-
+#endif
 	txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
 	tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1",
 					  "foreground", "red",
@@ -322,7 +322,7 @@
 	gtk_tree_view_set_model(view, model1);
 	gtk_tree_view_set_headers_visible(view, TRUE);
 	gtk_tree_view_set_rules_hint(view, FALSE);
-	
+
 	column = gtk_tree_view_column_new();
 	gtk_tree_view_append_column(view, column);
 	gtk_tree_view_column_set_title(column, _("Options"));
@@ -334,11 +334,11 @@
 					    renderer,
 					    "active", COL_BTNACT,
 					    "inconsistent", COL_BTNINC,
-					    "visible", COL_BTNVIS, 
+					    "visible", COL_BTNVIS,
 					    "radio", COL_BTNRAD, NULL);
 	renderer = gtk_cell_renderer_text_new();
 	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
-					renderer, FALSE);	
+					renderer, FALSE);
 	gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
 					    renderer,
 					    "text", COL_OPTION,
@@ -386,7 +386,7 @@
 					    renderer,
 					    "active", COL_BTNACT,
 					    "inconsistent", COL_BTNINC,
-					    "visible", COL_BTNVIS, 
+					    "visible", COL_BTNVIS,
 					    "radio", COL_BTNRAD, NULL);
 	/*g_signal_connect(G_OBJECT(renderer), "toggled",
 	   G_CALLBACK(renderer_toggled), NULL); */
@@ -806,7 +806,7 @@
 }
 
 
-void on_back_pressed(GtkButton * button, gpointer user_data)
+void on_back_clicked(GtkButton * button, gpointer user_data)
 {
 	enum prop_type ptype;
 
@@ -821,13 +821,13 @@
 }
 
 
-void on_load_pressed(GtkButton * button, gpointer user_data)
+void on_load_clicked(GtkButton * button, gpointer user_data)
 {
 	on_load1_activate(NULL, user_data);
 }
 
 
-void on_save_pressed(GtkButton * button, gpointer user_data)
+void on_save_clicked(GtkButton * button, gpointer user_data)
 {
 	on_save1_activate(NULL, user_data);
 }
@@ -850,9 +850,12 @@
 	gtk_widget_show(tree1_w);
 	gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
 	gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
-	if (tree2)	
+	if (tree2)
 		gtk_tree_store_clear(tree2);
 	display_list();
+
+	/* Disable back btn, like in full mode. */
+	gtk_widget_set_sensitive(back_btn, FALSE);
 }
 
 
@@ -868,13 +871,13 @@
 }
 
 
-void on_collapse_pressed(GtkButton * button, gpointer user_data)
+void on_collapse_clicked(GtkButton * button, gpointer user_data)
 {
 	gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w));
 }
 
 
-void on_expand_pressed(GtkButton * button, gpointer user_data)
+void on_expand_clicked(GtkButton * button, gpointer user_data)
 {
 	gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
 }
@@ -1242,13 +1245,13 @@
 			row[COL_VALUE] =
 			    g_strdup(menu_get_prompt(def_menu));
 	}
-	if(sym->flags & SYMBOL_CHOICEVAL)
+	if (sym->flags & SYMBOL_CHOICEVAL)
 		row[COL_BTNRAD] = GINT_TO_POINTER(TRUE);
 
 	stype = sym_get_type(sym);
 	switch (stype) {
 	case S_BOOLEAN:
-		if(GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE)
+		if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE)
 			row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
 		if (sym_is_choice(sym))
 			break;
@@ -1423,7 +1426,7 @@
 								 child2);
 				gtk_tree_store_remove(tree2, &tmp);
 				if (!valid)
-					return;	// next parent 
+					return;	// next parent
 				else
 					goto reparse;	// next child
 			} else
@@ -1448,7 +1451,7 @@
 								 child2);
 				gtk_tree_store_remove(tree2, &tmp);
 				if (!valid)
-					return;	// next parent 
+					return;	// next parent
 				else
 					goto reparse;	// next child
 			}
@@ -1486,12 +1489,12 @@
 		if (sym)
 			sym->flags &= ~SYMBOL_CHANGED;
 
-		if ((view_mode == SPLIT_VIEW) && !(child->flags & MENU_ROOT) &&
-		    (tree == tree1))
+		if ((view_mode == SPLIT_VIEW)
+		    && !(child->flags & MENU_ROOT) && (tree == tree1))
 			continue;
 
-		if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT) &&
-		    (tree == tree2))
+		if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT)
+		    && (tree == tree2))
 			continue;
 
 		if (menu_is_visible(child) || show_all)
@@ -1513,11 +1516,12 @@
 		    && (tree == tree2))
 			continue;
 /*
-		if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT)) ||
-		    (view_mode == FULL_VIEW)
+                if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
+		    || (view_mode == FULL_VIEW)
 		    || (view_mode == SPLIT_VIEW))*/
 		if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
-		    || (view_mode == FULL_VIEW) || (view_mode == SPLIT_VIEW)) {
+		    || (view_mode == FULL_VIEW)
+		    || (view_mode == SPLIT_VIEW)) {
 			indent++;
 			display_tree(child);
 			indent--;
@@ -1530,9 +1534,9 @@
 {
 	if (tree2)
 		gtk_tree_store_clear(tree2);
-	if(view_mode == SINGLE_VIEW)
+	if (view_mode == SINGLE_VIEW)
 		display_tree(current);
- 	else if(view_mode == SPLIT_VIEW)
+	else if (view_mode == SPLIT_VIEW)
 		display_tree(browsed);
 	gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
 }
@@ -1551,24 +1555,22 @@
 
 void fixup_rootmenu(struct menu *menu)
 {
-        struct menu *child;
-        static int menu_cnt = 0;
+	struct menu *child;
+	static int menu_cnt = 0;
 
-        menu->flags |= MENU_ROOT;
-        for (child = menu->list; child; child = child->next) {
-                if (child->prompt && child->prompt->type == P_MENU) {
-                        menu_cnt++;
-                        fixup_rootmenu(child);
-                        menu_cnt--;
-                } else if (!menu_cnt)
-                        fixup_rootmenu(child);
-        }
+	menu->flags |= MENU_ROOT;
+	for (child = menu->list; child; child = child->next) {
+		if (child->prompt && child->prompt->type == P_MENU) {
+			menu_cnt++;
+			fixup_rootmenu(child);
+			menu_cnt--;
+		} else if (!menu_cnt)
+			fixup_rootmenu(child);
+	}
 }
 
 
 /* Main */
-
-
 int main(int ac, char *av[])
 {
 	const char *name;
diff --git a/scripts/kconfig/gconf.glade b/scripts/kconfig/gconf.glade
index ace4706..f8744ed 100644
--- a/scripts/kconfig/gconf.glade
+++ b/scripts/kconfig/gconf.glade
@@ -13,6 +13,11 @@
   <property name="default_height">480</property>
   <property name="resizable">True</property>
   <property name="destroy_with_parent">False</property>
+  <property name="decorated">True</property>
+  <property name="skip_taskbar_hint">False</property>
+  <property name="skip_pager_hint">False</property>
+  <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
   <signal name="destroy" handler="on_window1_destroy" object="window1"/>
   <signal name="size_request" handler="on_window1_size_request" object="vpaned1" last_modification_time="Fri, 11 Jan 2002 16:17:11 GMT"/>
   <signal name="delete_event" handler="on_window1_delete_event" object="window1" last_modification_time="Sun, 09 Mar 2003 19:42:46 GMT"/>
@@ -46,7 +51,7 @@
 		      <accelerator key="L" modifiers="GDK_CONTROL_MASK" signal="activate"/>
 
 		      <child internal-child="image">
-			<widget class="GtkImage" id="image27">
+			<widget class="GtkImage" id="image39">
 			  <property name="visible">True</property>
 			  <property name="stock">gtk-open</property>
 			  <property name="icon_size">1</property>
@@ -69,7 +74,7 @@
 		      <accelerator key="S" modifiers="GDK_CONTROL_MASK" signal="activate"/>
 
 		      <child internal-child="image">
-			<widget class="GtkImage" id="image28">
+			<widget class="GtkImage" id="image40">
 			  <property name="visible">True</property>
 			  <property name="stock">gtk-save</property>
 			  <property name="icon_size">1</property>
@@ -91,7 +96,7 @@
 		      <signal name="activate" handler="on_save_as1_activate"/>
 
 		      <child internal-child="image">
-			<widget class="GtkImage" id="image29">
+			<widget class="GtkImage" id="image41">
 			  <property name="visible">True</property>
 			  <property name="stock">gtk-save-as</property>
 			  <property name="icon_size">1</property>
@@ -105,7 +110,7 @@
 		  </child>
 
 		  <child>
-		    <widget class="GtkMenuItem" id="separator1">
+		    <widget class="GtkSeparatorMenuItem" id="separator1">
 		      <property name="visible">True</property>
 		    </widget>
 		  </child>
@@ -119,7 +124,7 @@
 		      <accelerator key="Q" modifiers="GDK_CONTROL_MASK" signal="activate"/>
 
 		      <child internal-child="image">
-			<widget class="GtkImage" id="image30">
+			<widget class="GtkImage" id="image42">
 			  <property name="visible">True</property>
 			  <property name="stock">gtk-quit</property>
 			  <property name="icon_size">1</property>
@@ -179,7 +184,7 @@
 		  </child>
 
 		  <child>
-		    <widget class="GtkMenuItem" id="separator2">
+		    <widget class="GtkSeparatorMenuItem" id="separator2">
 		      <property name="visible">True</property>
 		    </widget>
 		  </child>
@@ -228,7 +233,7 @@
 		      <accelerator key="I" modifiers="GDK_CONTROL_MASK" signal="activate"/>
 
 		      <child internal-child="image">
-			<widget class="GtkImage" id="image31">
+			<widget class="GtkImage" id="image43">
 			  <property name="visible">True</property>
 			  <property name="stock">gtk-dialog-question</property>
 			  <property name="icon_size">1</property>
@@ -250,7 +255,7 @@
 		      <accelerator key="A" modifiers="GDK_CONTROL_MASK" signal="activate"/>
 
 		      <child internal-child="image">
-			<widget class="GtkImage" id="image32">
+			<widget class="GtkImage" id="image44">
 			  <property name="visible">True</property>
 			  <property name="stock">gtk-properties</property>
 			  <property name="icon_size">1</property>
@@ -271,7 +276,7 @@
 		      <signal name="activate" handler="on_license1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/>
 
 		      <child internal-child="image">
-			<widget class="GtkImage" id="image33">
+			<widget class="GtkImage" id="image45">
 			  <property name="visible">True</property>
 			  <property name="stock">gtk-justify-fill</property>
 			  <property name="icon_size">1</property>
@@ -308,109 +313,207 @@
 	      <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
 	      <property name="toolbar_style">GTK_TOOLBAR_BOTH</property>
 	      <property name="tooltips">True</property>
+	      <property name="show_arrow">True</property>
 
 	      <child>
-		<widget class="button" id="button1">
+		<widget class="GtkToolButton" id="button1">
 		  <property name="visible">True</property>
 		  <property name="tooltip" translatable="yes">Goes up of one level (single view)</property>
 		  <property name="label" translatable="yes">Back</property>
 		  <property name="use_underline">True</property>
-		  <property name="stock_pixmap">gtk-undo</property>
-		  <signal name="pressed" handler="on_back_pressed"/>
+		  <property name="stock_id">gtk-undo</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
+		  <signal name="clicked" handler="on_back_clicked"/>
 		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">True</property>
+		</packing>
 	      </child>
 
 	      <child>
-		<widget class="GtkVSeparator" id="vseparator1">
+		<widget class="GtkToolItem" id="toolitem1">
 		  <property name="visible">True</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
+
+		  <child>
+		    <widget class="GtkVSeparator" id="vseparator1">
+		      <property name="visible">True</property>
+		    </widget>
+		  </child>
 		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">False</property>
+		</packing>
 	      </child>
 
 	      <child>
-		<widget class="button" id="button2">
+		<widget class="GtkToolButton" id="button2">
 		  <property name="visible">True</property>
 		  <property name="tooltip" translatable="yes">Load a config file</property>
 		  <property name="label" translatable="yes">Load</property>
 		  <property name="use_underline">True</property>
-		  <property name="stock_pixmap">gtk-open</property>
-		  <signal name="pressed" handler="on_load_pressed"/>
+		  <property name="stock_id">gtk-open</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
+		  <signal name="clicked" handler="on_load_clicked"/>
 		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">True</property>
+		</packing>
 	      </child>
 
 	      <child>
-		<widget class="button" id="button3">
+		<widget class="GtkToolButton" id="button3">
 		  <property name="visible">True</property>
 		  <property name="tooltip" translatable="yes">Save a config file</property>
 		  <property name="label" translatable="yes">Save</property>
 		  <property name="use_underline">True</property>
-		  <property name="stock_pixmap">gtk-save</property>
-		  <signal name="pressed" handler="on_save_pressed"/>
+		  <property name="stock_id">gtk-save</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
+		  <signal name="clicked" handler="on_save_clicked"/>
 		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">True</property>
+		</packing>
 	      </child>
 
 	      <child>
-		<widget class="GtkVSeparator" id="vseparator2">
+		<widget class="GtkToolItem" id="toolitem2">
 		  <property name="visible">True</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
+
+		  <child>
+		    <widget class="GtkVSeparator" id="vseparator2">
+		      <property name="visible">True</property>
+		    </widget>
+		  </child>
 		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">False</property>
+		</packing>
 	      </child>
 
 	      <child>
-		<widget class="button" id="button4">
+		<widget class="GtkToolButton" id="button4">
 		  <property name="visible">True</property>
 		  <property name="tooltip" translatable="yes">Single view</property>
 		  <property name="label" translatable="yes">Single</property>
 		  <property name="use_underline">True</property>
-		  <property name="stock_pixmap">gtk-missing-image</property>
+		  <property name="stock_id">gtk-missing-image</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
 		  <signal name="clicked" handler="on_single_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:39 GMT"/>
 		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">True</property>
+		</packing>
 	      </child>
 
 	      <child>
-		<widget class="button" id="button5">
+		<widget class="GtkToolButton" id="button5">
 		  <property name="visible">True</property>
 		  <property name="tooltip" translatable="yes">Split view</property>
 		  <property name="label" translatable="yes">Split</property>
 		  <property name="use_underline">True</property>
-		  <property name="stock_pixmap">gtk-missing-image</property>
+		  <property name="stock_id">gtk-missing-image</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
 		  <signal name="clicked" handler="on_split_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:45 GMT"/>
 		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">True</property>
+		</packing>
 	      </child>
 
 	      <child>
-		<widget class="button" id="button6">
+		<widget class="GtkToolButton" id="button6">
 		  <property name="visible">True</property>
 		  <property name="tooltip" translatable="yes">Full view</property>
 		  <property name="label" translatable="yes">Full</property>
 		  <property name="use_underline">True</property>
-		  <property name="stock_pixmap">gtk-missing-image</property>
+		  <property name="stock_id">gtk-missing-image</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
 		  <signal name="clicked" handler="on_full_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:50 GMT"/>
 		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">True</property>
+		</packing>
 	      </child>
 
 	      <child>
-		<widget class="GtkVSeparator" id="vseparator3">
+		<widget class="GtkToolItem" id="toolitem3">
 		  <property name="visible">True</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
+
+		  <child>
+		    <widget class="GtkVSeparator" id="vseparator3">
+		      <property name="visible">True</property>
+		    </widget>
+		  </child>
 		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">False</property>
+		</packing>
 	      </child>
 
 	      <child>
-		<widget class="button" id="button7">
+		<widget class="GtkToolButton" id="button7">
 		  <property name="visible">True</property>
 		  <property name="tooltip" translatable="yes">Collapse the whole tree in the right frame</property>
 		  <property name="label" translatable="yes">Collapse</property>
 		  <property name="use_underline">True</property>
-		  <signal name="pressed" handler="on_collapse_pressed"/>
+		  <property name="stock_id">gtk-remove</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
+		  <signal name="clicked" handler="on_collapse_clicked"/>
 		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">True</property>
+		</packing>
 	      </child>
 
 	      <child>
-		<widget class="button" id="button8">
+		<widget class="GtkToolButton" id="button8">
 		  <property name="visible">True</property>
 		  <property name="tooltip" translatable="yes">Expand the whole tree in the right frame</property>
 		  <property name="label" translatable="yes">Expand</property>
 		  <property name="use_underline">True</property>
-		  <signal name="pressed" handler="on_expand_pressed"/>
+		  <property name="stock_id">gtk-add</property>
+		  <property name="visible_horizontal">True</property>
+		  <property name="visible_vertical">True</property>
+		  <property name="is_important">False</property>
+		  <signal name="clicked" handler="on_expand_clicked"/>
 		</widget>
+		<packing>
+		  <property name="expand">False</property>
+		  <property name="homogeneous">True</property>
+		</packing>
 	      </child>
 	    </widget>
 	  </child>
@@ -505,6 +608,8 @@
 		      <property name="visible">True</property>
 		      <property name="can_focus">True</property>
 		      <property name="editable">False</property>
+		      <property name="overwrite">False</property>
+		      <property name="accepts_tab">True</property>
 		      <property name="justification">GTK_JUSTIFY_LEFT</property>
 		      <property name="wrap_mode">GTK_WRAP_WORD</property>
 		      <property name="cursor_visible">True</property>
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 6be2738..2253f38 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -826,7 +826,8 @@
 			sid = sbsec->def_sid;
 			rc = 0;
 		} else {
-			rc = security_context_to_sid(context, rc, &sid);
+			rc = security_context_to_sid_default(context, rc, &sid,
+			                                     sbsec->def_sid);
 			if (rc) {
 				printk(KERN_WARNING "%s:  context_to_sid(%s) "
 				       "returned %d for dev=%s ino=%ld\n",
@@ -3125,12 +3126,12 @@
 
 		if (sk->sk_family == PF_INET) {
 			addr4 = (struct sockaddr_in *)address;
-			if (addrlen != sizeof(struct sockaddr_in))
+			if (addrlen < sizeof(struct sockaddr_in))
 				return -EINVAL;
 			snum = ntohs(addr4->sin_port);
 		} else {
 			addr6 = (struct sockaddr_in6 *)address;
-			if (addrlen != sizeof(struct sockaddr_in6))
+			if (addrlen < SIN6_LEN_RFC2133)
 				return -EINVAL;
 			snum = ntohs(addr6->sin6_port);
 		}
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index fa187c9..71c0a19 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -65,6 +65,8 @@
 int security_context_to_sid(char *scontext, u32 scontext_len,
 	u32 *out_sid);
 
+int security_context_to_sid_default(char *scontext, u32 scontext_len, u32 *out_sid, u32 def_sid);
+
 int security_get_user_sids(u32 callsid, char *username,
 			   u32 **sids, u32 *nel);
 
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index 756036b..d4c32c3 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -15,6 +15,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/errno.h>
+#include "sidtab.h"
 #include "mls.h"
 #include "policydb.h"
 #include "services.h"
@@ -208,6 +209,26 @@
 }
 
 /*
+ * Copies the MLS range from `src' into `dst'.
+ */
+static inline int mls_copy_context(struct context *dst,
+				   struct context *src)
+{
+	int l, rc = 0;
+
+	/* Copy the MLS range from the source context */
+	for (l = 0; l < 2; l++) {
+		dst->range.level[l].sens = src->range.level[l].sens;
+		rc = ebitmap_cpy(&dst->range.level[l].cat,
+				 &src->range.level[l].cat);
+		if (rc)
+			break;
+	}
+
+	return rc;
+}
+
+/*
  * Set the MLS fields in the security context structure
  * `context' based on the string representation in
  * the string `*scontext'.  Update `*scontext' to
@@ -216,10 +237,20 @@
  *
  * This function modifies the string in place, inserting
  * NULL characters to terminate the MLS fields.
+ *
+ * If a def_sid is provided and no MLS field is present,
+ * copy the MLS field of the associated default context.
+ * Used for upgraded to MLS systems where objects may lack
+ * MLS fields.
+ *
+ * Policy read-lock must be held for sidtab lookup.
+ *
  */
 int mls_context_to_sid(char oldc,
 		       char **scontext,
-		       struct context *context)
+		       struct context *context,
+		       struct sidtab *s,
+		       u32 def_sid)
 {
 
 	char delim;
@@ -231,9 +262,23 @@
 	if (!selinux_mls_enabled)
 		return 0;
 
-	/* No MLS component to the security context. */
-	if (!oldc)
+	/*
+	 * No MLS component to the security context, try and map to
+	 * default if provided.
+	 */
+	if (!oldc) {
+		struct context *defcon;
+
+		if (def_sid == SECSID_NULL)
+			goto out;
+
+		defcon = sidtab_search(s, def_sid);
+		if (!defcon)
+			goto out;
+
+		rc = mls_copy_context(context, defcon);
 		goto out;
+	}
 
 	/* Extract low sensitivity. */
 	scontextp = p = *scontext;
@@ -334,26 +379,6 @@
 }
 
 /*
- * Copies the MLS range from `src' into `dst'.
- */
-static inline int mls_copy_context(struct context *dst,
-				   struct context *src)
-{
-	int l, rc = 0;
-
-	/* Copy the MLS range from the source context */
-	for (l = 0; l < 2; l++) {
-		dst->range.level[l].sens = src->range.level[l].sens;
-		rc = ebitmap_cpy(&dst->range.level[l].cat,
-				 &src->range.level[l].cat);
-		if (rc)
-			break;
-	}
-
-	return rc;
-}
-
-/*
  * Copies the effective MLS range from `src' into `dst'.
  */
 static inline int mls_scopy_context(struct context *dst,
diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h
index 0d37bea..03de697 100644
--- a/security/selinux/ss/mls.h
+++ b/security/selinux/ss/mls.h
@@ -23,7 +23,9 @@
 
 int mls_context_to_sid(char oldc,
 	               char **scontext,
-		       struct context *context);
+		       struct context *context,
+		       struct sidtab *s,
+		       u32 def_sid);
 
 int mls_convert_context(struct policydb *oldp,
 			struct policydb *newp,
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 922bb45..0141204 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -601,18 +601,7 @@
 
 }
 
-/**
- * security_context_to_sid - Obtain a SID for a given security context.
- * @scontext: security context
- * @scontext_len: length in bytes
- * @sid: security identifier, SID
- *
- * Obtains a SID associated with the security context that
- * has the string representation specified by @scontext.
- * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
- * memory is available, or 0 on success.
- */
-int security_context_to_sid(char *scontext, u32 scontext_len, u32 *sid)
+static int security_context_to_sid_core(char *scontext, u32 scontext_len, u32 *sid, u32 def_sid)
 {
 	char *scontext2;
 	struct context context;
@@ -703,7 +692,7 @@
 
 	context.type = typdatum->value;
 
-	rc = mls_context_to_sid(oldc, &p, &context);
+	rc = mls_context_to_sid(oldc, &p, &context, &sidtab, def_sid);
 	if (rc)
 		goto out_unlock;
 
@@ -727,6 +716,46 @@
 	return rc;
 }
 
+/**
+ * security_context_to_sid - Obtain a SID for a given security context.
+ * @scontext: security context
+ * @scontext_len: length in bytes
+ * @sid: security identifier, SID
+ *
+ * Obtains a SID associated with the security context that
+ * has the string representation specified by @scontext.
+ * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
+ * memory is available, or 0 on success.
+ */
+int security_context_to_sid(char *scontext, u32 scontext_len, u32 *sid)
+{
+	return security_context_to_sid_core(scontext, scontext_len,
+	                                    sid, SECSID_NULL);
+}
+
+/**
+ * security_context_to_sid_default - Obtain a SID for a given security context,
+ * falling back to specified default if needed.
+ *
+ * @scontext: security context
+ * @scontext_len: length in bytes
+ * @sid: security identifier, SID
+ * @def_sid: default SID to assign on errror
+ *
+ * Obtains a SID associated with the security context that
+ * has the string representation specified by @scontext.
+ * The default SID is passed to the MLS layer to be used to allow
+ * kernel labeling of the MLS field if the MLS field is not present
+ * (for upgrading to MLS without full relabel).
+ * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
+ * memory is available, or 0 on success.
+ */
+int security_context_to_sid_default(char *scontext, u32 scontext_len, u32 *sid, u32 def_sid)
+{
+	return security_context_to_sid_core(scontext, scontext_len,
+	                                    sid, def_sid);
+}
+
 static int compute_sid_handle_invalid_context(
 	struct context *scontext,
 	struct context *tcontext,
diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig
index 34c1740..2e4a5e0 100644
--- a/sound/arm/Kconfig
+++ b/sound/arm/Kconfig
@@ -20,5 +20,17 @@
 	select SND_PCM
 	select SND_AC97_CODEC
 
-endmenu
+config SND_PXA2XX_PCM
+	tristate
+	select SND_PCM
 
+config SND_PXA2XX_AC97
+	tristate "AC97 driver for the Intel PXA2xx chip"
+	depends on ARCH_PXA && SND
+	select SND_PXA2XX_PCM
+	select SND_AC97_CODEC
+	help
+	  Say Y or M if you want to support any AC97 codec attached to
+	  the PXA2xx AC97 interface.
+
+endmenu
diff --git a/sound/arm/Makefile b/sound/arm/Makefile
index f74ec28..103f136 100644
--- a/sound/arm/Makefile
+++ b/sound/arm/Makefile
@@ -3,9 +3,11 @@
 #
 
 snd-sa11xx-uda1341-objs := sa11xx-uda1341.o
-
-# Toplevel Module Dependency
-obj-$(CONFIG_SND_SA11XX_UDA1341) += snd-sa11xx-uda1341.o 
-
-obj-$(CONFIG_SND_ARMAACI)	+= snd-aaci.o
 snd-aaci-objs			:= aaci.o devdma.o
+snd-pxa2xx-pcm-objs := pxa2xx-pcm.o
+snd-pxa2xx-ac97-objs := pxa2xx-ac97.o
+
+obj-$(CONFIG_SND_SA11XX_UDA1341) += snd-sa11xx-uda1341.o 
+obj-$(CONFIG_SND_ARMAACI)	+= snd-aaci.o
+obj-$(CONFIG_SND_PXA2XX_PCM) += snd-pxa2xx-pcm.o
+obj-$(CONFIG_SND_PXA2XX_AC97) += snd-pxa2xx-ac97.o
diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c
new file mode 100644
index 0000000..4605230
--- /dev/null
+++ b/sound/arm/pxa2xx-ac97.c
@@ -0,0 +1,410 @@
+/*
+ * linux/sound/pxa2xx-ac97.c -- AC97 support for the Intel PXA2xx chip.
+ *
+ * Author:	Nicolas Pitre
+ * Created:	Dec 02, 2004
+ * Copyright:	MontaVista Software Inc.
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+
+#include <asm/irq.h>
+#include <asm/semaphore.h>
+#include <asm/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/audio.h>
+
+#include "pxa2xx-pcm.h"
+
+
+static DECLARE_MUTEX(car_mutex);
+static DECLARE_WAIT_QUEUE_HEAD(gsr_wq);
+static volatile long gsr_bits;
+
+static unsigned short pxa2xx_ac97_read(ac97_t *ac97, unsigned short reg)
+{
+	unsigned short val = -1;
+	volatile u32 *reg_addr;
+
+	down(&car_mutex);
+	if (CAR & CAR_CAIP) {
+		printk(KERN_CRIT"%s: CAR_CAIP already set\n", __FUNCTION__);
+		goto out;
+	}
+
+	/* set up primary or secondary codec space */
+	reg_addr = (ac97->num & 1) ? &SAC_REG_BASE : &PAC_REG_BASE;
+	reg_addr += (reg >> 1);
+
+	/* start read access across the ac97 link */
+	gsr_bits = 0;
+	val = *reg_addr;
+	if (reg == AC97_GPIO_STATUS)
+		goto out;
+	wait_event_timeout(gsr_wq, gsr_bits & GSR_SDONE, 1);
+	if (!gsr_bits & GSR_SDONE) {
+		printk(KERN_ERR "%s: read error (ac97_reg=%d GSR=%#lx)\n",
+				__FUNCTION__, reg, gsr_bits);
+		val = -1;
+		goto out;
+	}
+
+	/* valid data now */
+	gsr_bits = 0;
+	val = *reg_addr;			
+	/* but we've just started another cycle... */
+	wait_event_timeout(gsr_wq, gsr_bits & GSR_SDONE, 1);
+
+out:	up(&car_mutex);
+	return val;
+}
+
+static void pxa2xx_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val)
+{
+	volatile u32 *reg_addr;
+
+	down(&car_mutex);
+
+	if (CAR & CAR_CAIP) {
+		printk(KERN_CRIT "%s: CAR_CAIP already set\n", __FUNCTION__);
+		goto out;
+	}
+
+	/* set up primary or secondary codec space */
+	reg_addr = (ac97->num & 1) ? &SAC_REG_BASE : &PAC_REG_BASE;
+	reg_addr += (reg >> 1);
+	gsr_bits = 0;
+	*reg_addr = val;
+	wait_event_timeout(gsr_wq, gsr_bits & GSR_CDONE, 1);
+	if (!gsr_bits & GSR_SDONE)
+		printk(KERN_ERR "%s: write error (ac97_reg=%d GSR=%#lx)\n",
+				__FUNCTION__, reg, gsr_bits);
+
+out:	up(&car_mutex);
+}
+
+static void pxa2xx_ac97_reset(ac97_t *ac97)
+{
+	/* First, try cold reset */
+	GCR &=  GCR_COLD_RST;  /* clear everything but nCRST */
+	GCR &= ~GCR_COLD_RST;  /* then assert nCRST */
+
+	gsr_bits = 0;
+#ifdef CONFIG_PXA27x
+	/* PXA27x Developers Manual section 13.5.2.2.1 */
+	pxa_set_cken(1 << 31, 1);
+	udelay(5);
+	pxa_set_cken(1 << 31, 0);
+	GCR = GCR_COLD_RST;
+	udelay(50);
+#else
+	GCR = GCR_COLD_RST;
+	GCR |= GCR_CDONE_IE|GCR_SDONE_IE;
+	wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
+#endif
+
+	if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR))) {
+		printk(KERN_INFO "%s: cold reset timeout (GSR=%#lx)\n",
+				 __FUNCTION__, gsr_bits);
+
+		/* let's try warm reset */
+		gsr_bits = 0;
+#ifdef CONFIG_PXA27x
+		/* warm reset broken on Bulverde,
+		   so manually keep AC97 reset high */
+		pxa_gpio_mode(113 | GPIO_OUT | GPIO_DFLT_HIGH); 
+		udelay(10);
+		GCR |= GCR_WARM_RST;
+		pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
+		udelay(50);
+#else
+		GCR |= GCR_WARM_RST|GCR_PRIRDY_IEN|GCR_SECRDY_IEN;;
+		wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
+#endif			
+
+		if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)))
+			printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n",
+					 __FUNCTION__, gsr_bits);
+	}
+
+	GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
+	GCR |= GCR_SDONE_IE|GCR_CDONE_IE;
+}
+
+static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	long status;
+
+	status = GSR;
+	if (status) {
+		GSR = status;
+		gsr_bits |= status;
+		wake_up(&gsr_wq);
+
+#ifdef CONFIG_PXA27x
+		/* Although we don't use those we still need to clear them
+		   since they tend to spuriously trigger when MMC is used
+		   (hardware bug? go figure)... */
+		MISR = MISR_EOC;
+		PISR = PISR_EOC;
+		MCSR = MCSR_EOC;
+#endif
+
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+static ac97_bus_ops_t pxa2xx_ac97_ops = {
+	.read	= pxa2xx_ac97_read,
+	.write	= pxa2xx_ac97_write,
+	.reset	= pxa2xx_ac97_reset,
+};
+
+static pxa2xx_pcm_dma_params_t pxa2xx_ac97_pcm_out = {
+	.name			= "AC97 PCM out",
+	.dev_addr		= __PREG(PCDR),
+	.drcmr			= &DRCMRTXPCDR,
+	.dcmd			= DCMD_INCSRCADDR | DCMD_FLOWTRG |
+				  DCMD_BURST32 | DCMD_WIDTH4,
+};
+
+static pxa2xx_pcm_dma_params_t pxa2xx_ac97_pcm_in = {
+	.name			= "AC97 PCM in",
+	.dev_addr		= __PREG(PCDR),
+	.drcmr			= &DRCMRRXPCDR,
+	.dcmd			= DCMD_INCTRGADDR | DCMD_FLOWSRC |
+				  DCMD_BURST32 | DCMD_WIDTH4,
+};
+
+static snd_pcm_t *pxa2xx_ac97_pcm;
+static ac97_t *pxa2xx_ac97_ac97;
+
+static int pxa2xx_ac97_pcm_startup(snd_pcm_substream_t *substream)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	pxa2xx_audio_ops_t *platform_ops;
+	int r;
+
+	runtime->hw.channels_min = 2;
+	runtime->hw.channels_max = 2;
+
+	r = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+	    AC97_RATES_FRONT_DAC : AC97_RATES_ADC;
+	runtime->hw.rates = pxa2xx_ac97_ac97->rates[r];
+	snd_pcm_limit_hw_rates(runtime);
+
+       	platform_ops = substream->pcm->card->dev->platform_data;
+	if (platform_ops && platform_ops->startup)
+		return platform_ops->startup(substream, platform_ops->priv);
+	else
+		return 0;
+}
+
+static void pxa2xx_ac97_pcm_shutdown(snd_pcm_substream_t *substream)
+{
+	pxa2xx_audio_ops_t *platform_ops;
+
+       	platform_ops = substream->pcm->card->dev->platform_data;
+	if (platform_ops && platform_ops->shutdown)
+		platform_ops->shutdown(substream, platform_ops->priv);
+}
+
+static int pxa2xx_ac97_pcm_prepare(snd_pcm_substream_t *substream)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+		  AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
+	return snd_ac97_set_rate(pxa2xx_ac97_ac97, reg, runtime->rate);
+}
+
+static pxa2xx_pcm_client_t pxa2xx_ac97_pcm_client = {
+	.playback_params	= &pxa2xx_ac97_pcm_out,
+	.capture_params		= &pxa2xx_ac97_pcm_in,
+	.startup		= pxa2xx_ac97_pcm_startup,
+	.shutdown		= pxa2xx_ac97_pcm_shutdown,
+	.prepare		= pxa2xx_ac97_pcm_prepare,
+};
+
+#ifdef CONFIG_PM
+
+static int pxa2xx_ac97_do_suspend(snd_card_t *card, unsigned int state)
+{
+	if (card->power_state != SNDRV_CTL_POWER_D3cold) {
+		pxa2xx_audio_ops_t *platform_ops = card->dev->platform_data;
+		snd_pcm_suspend_all(pxa2xx_ac97_pcm);
+		snd_ac97_suspend(pxa2xx_ac97_ac97);
+		snd_power_change_state(card, SNDRV_CTL_POWER_D3cold);
+		if (platform_ops && platform_ops->suspend)
+			platform_ops->suspend(platform_ops->priv);
+		GCR |= GCR_ACLINK_OFF;
+		pxa_set_cken(CKEN2_AC97, 0);
+	}
+
+	return 0;
+}
+
+static int pxa2xx_ac97_do_resume(snd_card_t *card, unsigned int state)
+{
+	if (card->power_state != SNDRV_CTL_POWER_D0) {
+		pxa2xx_audio_ops_t *platform_ops = card->dev->platform_data;
+		pxa_set_cken(CKEN2_AC97, 1);
+		if (platform_ops && platform_ops->resume)
+			platform_ops->resume(platform_ops->priv);
+		snd_ac97_resume(pxa2xx_ac97_ac97);
+		snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+	}
+
+	return 0;
+}
+
+static int pxa2xx_ac97_suspend(struct device *_dev, u32 state, u32 level)
+{
+	snd_card_t *card = dev_get_drvdata(_dev);
+	int ret = 0;
+
+	if (card && level == SUSPEND_DISABLE)
+		ret = pxa2xx_ac97_do_suspend(card, SNDRV_CTL_POWER_D3cold);
+
+	return ret;
+}
+
+static int pxa2xx_ac97_resume(struct device *_dev, u32 level)
+{
+	snd_card_t *card = dev_get_drvdata(_dev);
+	int ret = 0;
+
+	if (card && level == RESUME_ENABLE)
+		ret = pxa2xx_ac97_do_resume(card, SNDRV_CTL_POWER_D0);
+
+	return ret;
+}
+
+#else
+#define pxa2xx_ac97_suspend	NULL
+#define pxa2xx_ac97_resume	NULL
+#endif
+
+static int pxa2xx_ac97_probe(struct device *dev)
+{
+	snd_card_t *card;
+	ac97_bus_t *ac97_bus;
+	ac97_template_t ac97_template;
+	int ret;
+
+	ret = -ENOMEM;
+	card = snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+			    THIS_MODULE, 0);
+	if (!card)
+		goto err;
+
+	card->dev = dev;
+	strncpy(card->driver, dev->driver->name, sizeof(card->driver));
+
+	ret = pxa2xx_pcm_new(card, &pxa2xx_ac97_pcm_client, &pxa2xx_ac97_pcm);
+	if (ret)
+		goto err;
+
+	ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, 0, "AC97", NULL);
+	if (ret < 0)
+		goto err;
+
+	pxa_gpio_mode(GPIO31_SYNC_AC97_MD);
+	pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD);
+	pxa_gpio_mode(GPIO28_BITCLK_AC97_MD);
+	pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD);
+#ifdef CONFIG_PXA27x
+	/* Use GPIO 113 as AC97 Reset on Bulverde */
+	pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
+#endif
+	pxa_set_cken(CKEN2_AC97, 1);
+
+	ret = snd_ac97_bus(card, 0, &pxa2xx_ac97_ops, NULL, &ac97_bus);
+	if (ret)
+		goto err;
+	memset(&ac97_template, 0, sizeof(ac97_template));
+	ret = snd_ac97_mixer(ac97_bus, &ac97_template, &pxa2xx_ac97_ac97);
+	if (ret)
+		goto err;
+
+	snprintf(card->shortname, sizeof(card->shortname),
+		 "%s", snd_ac97_get_short_name(pxa2xx_ac97_ac97));
+	snprintf(card->longname, sizeof(card->longname),
+		 "%s (%s)", dev->driver->name, card->mixername);
+
+	snd_card_set_pm_callback(card, pxa2xx_ac97_do_suspend,
+				 pxa2xx_ac97_do_resume, NULL);
+	ret = snd_card_register(card);
+	if (ret == 0) {
+		dev_set_drvdata(dev, card);
+		return 0;
+	}
+
+ err:
+	if (card)
+		snd_card_free(card);
+	if (CKEN & CKEN2_AC97) {
+		GCR |= GCR_ACLINK_OFF;
+		free_irq(IRQ_AC97, NULL);
+		pxa_set_cken(CKEN2_AC97, 0);
+	}
+	return ret;
+}
+
+static int pxa2xx_ac97_remove(struct device *dev)
+{
+	snd_card_t *card = dev_get_drvdata(dev);
+
+	if (card) {
+		snd_card_free(card);
+		dev_set_drvdata(dev, NULL);
+		GCR |= GCR_ACLINK_OFF;
+		free_irq(IRQ_AC97, NULL);
+		pxa_set_cken(CKEN2_AC97, 0);
+	}
+
+	return 0;
+}
+
+static struct device_driver pxa2xx_ac97_driver = {
+	.name		= "pxa2xx-ac97",
+	.bus		= &platform_bus_type,
+	.probe		= pxa2xx_ac97_probe,
+	.remove		= pxa2xx_ac97_remove,
+	.suspend	= pxa2xx_ac97_suspend,
+	.resume		= pxa2xx_ac97_resume,
+};
+
+static int __init pxa2xx_ac97_init(void)
+{
+	return driver_register(&pxa2xx_ac97_driver);
+}
+
+static void __exit pxa2xx_ac97_exit(void)
+{
+	driver_unregister(&pxa2xx_ac97_driver);
+}
+
+module_init(pxa2xx_ac97_init);
+module_exit(pxa2xx_ac97_exit);
+
+MODULE_AUTHOR("Nicolas Pitre");
+MODULE_DESCRIPTION("AC97 driver for the Intel PXA2xx chip");
+MODULE_LICENSE("GPL");
diff --git a/sound/arm/pxa2xx-pcm.c b/sound/arm/pxa2xx-pcm.c
new file mode 100644
index 0000000..b1eb53b
--- /dev/null
+++ b/sound/arm/pxa2xx-pcm.c
@@ -0,0 +1,367 @@
+/*
+ * linux/sound/arm/pxa2xx-pcm.c -- ALSA PCM interface for the Intel PXA2xx chip
+ *
+ * Author:	Nicolas Pitre
+ * Created:	Nov 30, 2004
+ * Copyright:	(C) 2004 MontaVista Software, Inc.
+ *
+ * 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/device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+#include <asm/dma.h>
+#include <asm/hardware.h>
+#include <asm/arch/pxa-regs.h>
+
+#include "pxa2xx-pcm.h"
+
+
+static const snd_pcm_hardware_t pxa2xx_pcm_hardware = {
+	.info			= SNDRV_PCM_INFO_MMAP |
+				  SNDRV_PCM_INFO_MMAP_VALID |
+				  SNDRV_PCM_INFO_INTERLEAVED |
+				  SNDRV_PCM_INFO_PAUSE,
+	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
+	.period_bytes_min	= 32,
+	.period_bytes_max	= 8192 - 32,
+	.periods_min		= 1,
+	.periods_max		= PAGE_SIZE/sizeof(pxa_dma_desc),
+	.buffer_bytes_max	= 128 * 1024,
+	.fifo_size		= 32,
+};
+
+struct pxa2xx_runtime_data {
+	int dma_ch;
+	pxa2xx_pcm_dma_params_t *params;
+	pxa_dma_desc *dma_desc_array;
+	dma_addr_t dma_desc_array_phys;
+};
+
+static int pxa2xx_pcm_hw_params(snd_pcm_substream_t *substream,
+				snd_pcm_hw_params_t *params)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	struct pxa2xx_runtime_data *rtd = runtime->private_data;
+	size_t totsize = params_buffer_bytes(params);
+	size_t period = params_period_bytes(params);
+	pxa_dma_desc *dma_desc;
+	dma_addr_t dma_buff_phys, next_desc_phys;
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+	runtime->dma_bytes = totsize;
+
+	dma_desc = rtd->dma_desc_array;
+	next_desc_phys = rtd->dma_desc_array_phys;
+	dma_buff_phys = runtime->dma_addr;
+	do {
+		next_desc_phys += sizeof(pxa_dma_desc);
+		dma_desc->ddadr = next_desc_phys;
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			dma_desc->dsadr = dma_buff_phys;
+			dma_desc->dtadr = rtd->params->dev_addr;
+		} else {
+			dma_desc->dsadr = rtd->params->dev_addr;
+			dma_desc->dtadr = dma_buff_phys;
+		}
+		if (period > totsize)
+			period = totsize;
+		dma_desc->dcmd = rtd->params->dcmd | period | DCMD_ENDIRQEN;
+		dma_desc++;
+		dma_buff_phys += period;
+	} while (totsize -= period);
+	dma_desc[-1].ddadr = rtd->dma_desc_array_phys;
+
+	return 0;
+}
+
+static int pxa2xx_pcm_hw_free(snd_pcm_substream_t *substream)
+{
+	struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
+
+	*rtd->params->drcmr = 0;
+	snd_pcm_set_runtime_buffer(substream, NULL);
+	return 0;
+}
+
+static int pxa2xx_pcm_prepare(snd_pcm_substream_t *substream)
+{
+	pxa2xx_pcm_client_t *client = substream->private_data;
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	struct pxa2xx_runtime_data *rtd = runtime->private_data;
+
+	DCSR(rtd->dma_ch) &= ~DCSR_RUN;
+	DCSR(rtd->dma_ch) = 0;
+	DCMD(rtd->dma_ch) = 0;
+	*rtd->params->drcmr = rtd->dma_ch | DRCMR_MAPVLD;
+
+	return client->prepare(substream);
+}
+
+static int pxa2xx_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
+{
+	struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		DDADR(rtd->dma_ch) = rtd->dma_desc_array_phys;
+		DCSR(rtd->dma_ch) = DCSR_RUN;
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		DCSR(rtd->dma_ch) &= ~DCSR_RUN;
+		break;
+
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		DCSR(rtd->dma_ch) |= DCSR_RUN;
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id, struct pt_regs *regs)
+{
+	snd_pcm_substream_t *substream = dev_id;
+	struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
+	int dcsr;
+
+	dcsr = DCSR(dma_ch);
+	DCSR(dma_ch) = dcsr & ~DCSR_STOPIRQEN;
+
+	if (dcsr & DCSR_ENDINTR) {
+		snd_pcm_period_elapsed(substream);
+	} else {
+		printk( KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n",
+			rtd->params->name, dma_ch, dcsr );
+		snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+	}
+}
+
+static snd_pcm_uframes_t pxa2xx_pcm_pointer(snd_pcm_substream_t *substream)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	struct pxa2xx_runtime_data *rtd = runtime->private_data;
+	dma_addr_t ptr = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+			 DSADR(rtd->dma_ch) : DTADR(rtd->dma_ch);
+	snd_pcm_uframes_t x = bytes_to_frames(runtime, ptr - runtime->dma_addr);
+	if (x == runtime->buffer_size)
+		x = 0;
+	return x;
+}
+
+static int
+pxa2xx_pcm_hw_rule_mult32(snd_pcm_hw_params_t *params, snd_pcm_hw_rule_t *rule)
+{
+	snd_interval_t *i = hw_param_interval(params, rule->var);
+	int changed = 0;
+
+	if (i->min & 31) {
+		i->min = (i->min & ~31) + 32;
+		i->openmin = 0;
+		changed = 1;
+	}
+
+	if (i->max & 31) {
+		i->max &= ~31;
+		i->openmax = 0;
+		changed = 1;
+	}
+
+	return changed;
+}
+
+static int pxa2xx_pcm_open(snd_pcm_substream_t *substream)
+{
+	pxa2xx_pcm_client_t *client = substream->private_data;
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	struct pxa2xx_runtime_data *rtd;
+	int ret;
+
+	runtime->hw = pxa2xx_pcm_hardware;
+
+	/*
+	 * For mysterious reasons (and despite what the manual says)
+	 * playback samples are lost if the DMA count is not a multiple
+	 * of the DMA burst size.  Let's add a rule to enforce that.
+	 */
+	ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+				  pxa2xx_pcm_hw_rule_mult32, NULL,
+				  SNDRV_PCM_HW_PARAM_PERIOD_BYTES, -1);
+	if (ret)
+		goto out;
+	ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+				  pxa2xx_pcm_hw_rule_mult32, NULL,
+				  SNDRV_PCM_HW_PARAM_BUFFER_BYTES, -1);
+	if (ret)
+		goto out;
+
+	ret = -ENOMEM;
+	rtd = kmalloc(sizeof(*rtd), GFP_KERNEL);
+	if (!rtd)
+		goto out;
+	rtd->dma_desc_array =
+		dma_alloc_writecombine(substream->pcm->card->dev, PAGE_SIZE,
+				       &rtd->dma_desc_array_phys, GFP_KERNEL);
+	if (!rtd->dma_desc_array)
+		goto err1;
+
+	rtd->params = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+		      client->playback_params : client->capture_params;
+	ret = pxa_request_dma(rtd->params->name, DMA_PRIO_LOW,
+			      pxa2xx_pcm_dma_irq, substream);
+	if (ret < 0)
+		goto err2;
+	rtd->dma_ch = ret;
+
+	runtime->private_data = rtd;
+	ret = client->startup(substream);
+	if (!ret)
+		goto out;
+
+	pxa_free_dma(rtd->dma_ch);
+ err2:
+	dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE,
+			      rtd->dma_desc_array, rtd->dma_desc_array_phys);
+ err1:
+	kfree(rtd);
+ out:
+	return ret;
+}
+
+static int pxa2xx_pcm_close(snd_pcm_substream_t *substream)
+{
+	pxa2xx_pcm_client_t *client = substream->private_data;
+	struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
+
+	pxa_free_dma(rtd->dma_ch);
+	client->shutdown(substream);
+	dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE,
+			      rtd->dma_desc_array, rtd->dma_desc_array_phys);
+	kfree(rtd);
+	return 0;
+}
+
+static int
+pxa2xx_pcm_mmap(snd_pcm_substream_t *substream, struct vm_area_struct *vma)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	return dma_mmap_writecombine(substream->pcm->card->dev, vma,
+				     runtime->dma_area,
+				     runtime->dma_addr,
+				     runtime->dma_bytes);
+}
+
+static snd_pcm_ops_t pxa2xx_pcm_ops = {
+	.open		= pxa2xx_pcm_open,
+	.close		= pxa2xx_pcm_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= pxa2xx_pcm_hw_params,
+	.hw_free	= pxa2xx_pcm_hw_free,
+	.prepare	= pxa2xx_pcm_prepare,
+	.trigger	= pxa2xx_pcm_trigger,
+	.pointer	= pxa2xx_pcm_pointer,
+	.mmap		= pxa2xx_pcm_mmap,
+};
+
+static int pxa2xx_pcm_preallocate_dma_buffer(snd_pcm_t *pcm, int stream)
+{
+	snd_pcm_substream_t *substream = pcm->streams[stream].substream;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+	size_t size = pxa2xx_pcm_hardware.buffer_bytes_max;
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->private_data = NULL;
+	buf->area = dma_alloc_writecombine(pcm->card->dev, size,
+					   &buf->addr, GFP_KERNEL);
+	if (!buf->area)
+		return -ENOMEM;
+	buf->bytes = size;
+	return 0;
+}
+
+static void pxa2xx_pcm_free_dma_buffers(snd_pcm_t *pcm)
+{
+	snd_pcm_substream_t *substream;
+	struct snd_dma_buffer *buf;
+	int stream;
+
+	for (stream = 0; stream < 2; stream++) {
+		substream = pcm->streams[stream].substream;
+		if (!substream)
+			continue;
+		buf = &substream->dma_buffer;
+		if (!buf->area)
+			continue;
+		dma_free_writecombine(pcm->card->dev, buf->bytes,
+				      buf->area, buf->addr);
+		buf->area = NULL;
+	}
+}
+
+static u64 pxa2xx_pcm_dmamask = 0xffffffff;
+
+int pxa2xx_pcm_new(snd_card_t *card, pxa2xx_pcm_client_t *client, snd_pcm_t **rpcm)
+{
+	snd_pcm_t *pcm;
+	int play = client->playback_params ? 1 : 0;
+	int capt = client->capture_params ? 1 : 0;
+	int ret;
+
+	ret = snd_pcm_new(card, "PXA2xx-PCM", 0, play, capt, &pcm);
+	if (ret)
+		goto out;
+
+	pcm->private_data = client;
+	pcm->private_free = pxa2xx_pcm_free_dma_buffers;
+
+	if (!card->dev->dma_mask)
+		card->dev->dma_mask = &pxa2xx_pcm_dmamask;
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = 0xffffffff;
+
+	if (play) {
+		int stream = SNDRV_PCM_STREAM_PLAYBACK;
+		snd_pcm_set_ops(pcm, stream, &pxa2xx_pcm_ops);
+		ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, stream);
+		if (ret)
+			goto out;
+	}
+	if (capt) {
+		int stream = SNDRV_PCM_STREAM_CAPTURE;
+		snd_pcm_set_ops(pcm, stream, &pxa2xx_pcm_ops);
+		ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, stream);
+		if (ret)
+			goto out;
+	}
+
+	if (rpcm)
+		*rpcm = pcm;
+	ret = 0;
+
+ out:
+	return ret;
+}
+
+EXPORT_SYMBOL(pxa2xx_pcm_new);
+
+MODULE_AUTHOR("Nicolas Pitre");
+MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module");
+MODULE_LICENSE("GPL");
diff --git a/sound/arm/pxa2xx-pcm.h b/sound/arm/pxa2xx-pcm.h
new file mode 100644
index 0000000..4351759
--- /dev/null
+++ b/sound/arm/pxa2xx-pcm.h
@@ -0,0 +1,29 @@
+/*
+ * linux/sound/arm/pxa2xx-pcm.h -- ALSA PCM interface for the Intel PXA2xx chip
+ *
+ * Author:	Nicolas Pitre
+ * Created:	Nov 30, 2004
+ * Copyright:	MontaVista Software, Inc.
+ *
+ * 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.
+ */
+
+typedef struct {
+	char *name;			/* stream identifier */
+	u32 dcmd;			/* DMA descriptor dcmd field */
+	volatile u32 *drcmr;		/* the DMA request channel to use */
+	u32 dev_addr;			/* device physical address for DMA */
+} pxa2xx_pcm_dma_params_t;
+	
+typedef struct {
+	pxa2xx_pcm_dma_params_t *playback_params;
+	pxa2xx_pcm_dma_params_t *capture_params;
+	int (*startup)(snd_pcm_substream_t *);
+	void (*shutdown)(snd_pcm_substream_t *);
+	int (*prepare)(snd_pcm_substream_t *);
+} pxa2xx_pcm_client_t;
+
+extern int pxa2xx_pcm_new(snd_card_t *, pxa2xx_pcm_client_t *, snd_pcm_t **);
+
diff --git a/sound/core/device.c b/sound/core/device.c
index 18c71f9..ca00ad7 100644
--- a/sound/core/device.c
+++ b/sound/core/device.c
@@ -28,7 +28,7 @@
 /**
  * snd_device_new - create an ALSA device component
  * @card: the card instance
- * @type: the device type, SNDRV_DEV_TYPE_XXX
+ * @type: the device type, SNDRV_DEV_XXX
  * @device_data: the data pointer of this device
  * @ops: the operator table
  *
@@ -46,7 +46,9 @@
 {
 	snd_device_t *dev;
 
-	snd_assert(card != NULL && device_data != NULL && ops != NULL, return -ENXIO);
+	snd_assert(card != NULL, return -ENXIO);
+	snd_assert(device_data != NULL, return -ENXIO);
+	snd_assert(ops != NULL, return -ENXIO);
 	dev = kcalloc(1, sizeof(*dev), GFP_KERNEL);
 	if (dev == NULL)
 		return -ENOMEM;
@@ -102,7 +104,7 @@
 }
 
 /**
- * snd_device_free - disconnect the device
+ * snd_device_disconnect - disconnect the device
  * @card: the card instance
  * @device_data: the data pointer to disconnect
  *
@@ -118,7 +120,7 @@
 {
 	struct list_head *list;
 	snd_device_t *dev;
-	
+
 	snd_assert(card != NULL, return -ENXIO);
 	snd_assert(device_data != NULL, return -ENXIO);
 	list_for_each(list, &card->devices) {
@@ -154,8 +156,9 @@
 	struct list_head *list;
 	snd_device_t *dev;
 	int err;
-	
-	snd_assert(card != NULL && device_data != NULL, return -ENXIO);
+
+	snd_assert(card != NULL, return -ENXIO);
+	snd_assert(device_data != NULL, return -ENXIO);
 	list_for_each(list, &card->devices) {
 		dev = snd_device(list);
 		if (dev->device_data != device_data)
diff --git a/sound/core/info.c b/sound/core/info.c
index 5e122bb..7f8bdf7 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -702,7 +702,7 @@
 }
 
 /**
- * snd_info_get_line - parse a string token
+ * snd_info_get_str - parse a string token
  * @dest: the buffer to store the string token
  * @src: the original string
  * @len: the max. length of token - 1
@@ -939,7 +939,8 @@
 {
 	struct proc_dir_entry *root;
 
-	snd_assert(entry != NULL && entry->p != NULL, return -ENXIO);
+	snd_assert(entry != NULL, return -ENXIO);
+	snd_assert(entry->p != NULL, return -ENXIO);
 	root = entry->parent == NULL ? snd_proc_root : entry->parent->p;
 	snd_assert(root, return -ENXIO);
 	down(&info_mutex);
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c
index dbc23e3..0213256 100644
--- a/sound/core/memalloc.c
+++ b/sound/core/memalloc.c
@@ -105,7 +105,8 @@
  */
 
 static void *snd_dma_hack_alloc_coherent(struct device *dev, size_t size,
-					 dma_addr_t *dma_handle, int flags)
+					 dma_addr_t *dma_handle,
+					 unsigned int __nocast flags)
 {
 	void *ret;
 	u64 dma_mask, coherent_dma_mask;
diff --git a/sound/core/memory.c b/sound/core/memory.c
index c1fb28e..f689557 100644
--- a/sound/core/memory.c
+++ b/sound/core/memory.c
@@ -89,7 +89,7 @@
 	}
 }
 
-static void *__snd_kmalloc(size_t size, int flags, void *caller)
+static void *__snd_kmalloc(size_t size, unsigned int __nocast flags, void *caller)
 {
 	unsigned long cpu_flags;
 	struct snd_alloc_track *t;
@@ -111,12 +111,12 @@
 }
 
 #define _snd_kmalloc(size, flags) __snd_kmalloc((size), (flags), __builtin_return_address(0));
-void *snd_hidden_kmalloc(size_t size, int flags)
+void *snd_hidden_kmalloc(size_t size, unsigned int __nocast flags)
 {
 	return _snd_kmalloc(size, flags);
 }
 
-void *snd_hidden_kcalloc(size_t n, size_t size, int flags)
+void *snd_hidden_kcalloc(size_t n, size_t size, unsigned int __nocast flags)
 {
 	void *ret = NULL;
 	if (n != 0 && size > INT_MAX / n)
@@ -184,7 +184,7 @@
 	snd_wrapper_vfree(obj);
 }
 
-char *snd_hidden_kstrdup(const char *s, int flags)
+char *snd_hidden_kstrdup(const char *s, unsigned int __nocast flags)
 {
 	int len;
 	char *buf;
diff --git a/sound/core/seq/Makefile b/sound/core/seq/Makefile
index 64cb50d..402e2b4 100644
--- a/sound/core/seq/Makefile
+++ b/sound/core/seq/Makefile
@@ -38,7 +38,7 @@
 obj-$(call sequencer,$(CONFIG_SND_RAWMIDI)) += snd-seq-midi.o snd-seq-midi-event.o
 obj-$(call sequencer,$(CONFIG_SND_OPL3_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
 obj-$(call sequencer,$(CONFIG_SND_OPL4_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
-obj-$(call sequencer,$(CONFIG_SND_GUS_SYNTH)) += snd-seq-instr.o
+obj-$(call sequencer,$(CONFIG_SND_GUS_SYNTH)) += snd-seq-midi-emul.o snd-seq-instr.o
 obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-seq-midi-emul.o snd-seq-virmidi.o
 obj-$(call sequencer,$(CONFIG_SND_EMU10K1)) += snd-seq-midi-emul.o snd-seq-virmidi.o
 obj-$(call sequencer,$(CONFIG_SND_TRIDENT)) += snd-seq-midi-emul.o snd-seq-instr.o
diff --git a/sound/core/seq/instr/ainstr_gf1.c b/sound/core/seq/instr/ainstr_gf1.c
index 0779c41..32e91c6 100644
--- a/sound/core/seq/instr/ainstr_gf1.c
+++ b/sound/core/seq/instr/ainstr_gf1.c
@@ -50,7 +50,8 @@
 {
 	gf1_wave_t *wp, *prev;
 	gf1_xwave_t xp;
-	int err, gfp_mask;
+	int err;
+	unsigned int gfp_mask;
 	unsigned int real_size;
 	
 	gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL;
diff --git a/sound/core/seq/instr/ainstr_iw.c b/sound/core/seq/instr/ainstr_iw.c
index 39ff72b..2622b86 100644
--- a/sound/core/seq/instr/ainstr_iw.c
+++ b/sound/core/seq/instr/ainstr_iw.c
@@ -58,7 +58,7 @@
 					       iwffff_xenv_t *ex,
 					       char __user **data,
 					       long *len,
-					       int gfp_mask)
+					       unsigned int __nocast gfp_mask)
 {
 	__u32 stype;
 	iwffff_env_record_t *rp, *rp_last;
@@ -128,7 +128,8 @@
 {
 	iwffff_wave_t *wp, *prev;
 	iwffff_xwave_t xp;
-	int err, gfp_mask;
+	int err;
+	unsigned int gfp_mask;
 	unsigned int real_size;
 	
 	gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL;
@@ -234,7 +235,8 @@
 	iwffff_xinstrument_t ix;
 	iwffff_layer_t *lp, *prev_lp;
 	iwffff_xlayer_t lx;
-	int err, gfp_mask;
+	int err;
+	unsigned int gfp_mask;
 
 	if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE)
 		return -EINVAL;
diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c
index 57be915..4374829 100644
--- a/sound/core/seq/seq_midi.c
+++ b/sound/core/seq/seq_midi.c
@@ -134,7 +134,7 @@
 	seq_midisynth_t *msynth = (seq_midisynth_t *) private_data;
 	unsigned char msg[10];	/* buffer for constructing midi messages */
 	snd_rawmidi_substream_t *substream;
-	int res;
+	int len;
 
 	snd_assert(msynth != NULL, return -EINVAL);
 	substream = msynth->output_rfile.output;
@@ -146,20 +146,16 @@
 			snd_printd("seq_midi: invalid sysex event flags = 0x%x\n", ev->flags);
 			return 0;
 		}
-		res = snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)dump_midi, substream);
+		snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)dump_midi, substream);
 		snd_midi_event_reset_decode(msynth->parser);
-		if (res < 0)
-			return res;
 	} else {
 		if (msynth->parser == NULL)
 			return -EIO;
-		res = snd_midi_event_decode(msynth->parser, msg, sizeof(msg), ev);
-		if (res < 0)
-			return res;
-		if ((res = dump_midi(substream, msg, res)) < 0) {
+		len = snd_midi_event_decode(msynth->parser, msg, sizeof(msg), ev);
+		if (len < 0)
+			return 0;
+		if (dump_midi(substream, msg, len) < 0)
 			snd_midi_event_reset_decode(msynth->parser);
-			return res;
-		}
 	}
 	return 0;
 }
diff --git a/sound/core/wrappers.c b/sound/core/wrappers.c
index 9f39302..508e6d6 100644
--- a/sound/core/wrappers.c
+++ b/sound/core/wrappers.c
@@ -27,7 +27,7 @@
 #include <linux/fs.h>
 
 #ifdef CONFIG_SND_DEBUG_MEMORY
-void *snd_wrapper_kmalloc(size_t size, int flags)
+void *snd_wrapper_kmalloc(size_t size, unsigned int __nocast flags)
 {
 	return kmalloc(size, flags);
 }
diff --git a/sound/drivers/vx/vx_uer.c b/sound/drivers/vx/vx_uer.c
index 1811471..4fc38bd 100644
--- a/sound/drivers/vx/vx_uer.c
+++ b/sound/drivers/vx/vx_uer.c
@@ -162,34 +162,24 @@
 
 static int vx_calc_clock_from_freq(vx_core_t *chip, int freq)
 {
-#define XX_FECH48000                    0x0000004B
-#define XX_FECH32000                    0x00000171
-#define XX_FECH24000                    0x0000024B
-#define XX_FECH16000                    0x00000371
-#define XX_FECH12000                    0x0000044B
-#define XX_FECH8000                     0x00000571
-#define XX_FECH44100                    0x0000007F
-#define XX_FECH29400                    0x0000016F
-#define XX_FECH22050                    0x0000027F
-#define XX_FECH14000                    0x000003EF
-#define XX_FECH11025                    0x0000047F
-#define XX_FECH7350                     0x000005BF
+	int hexfreq;
 
-	switch (freq) {
-	case 48000:     return XX_FECH48000;
-	case 44100:     return XX_FECH44100;
-	case 32000:     return XX_FECH32000;
-	case 29400:     return XX_FECH29400;
-	case 24000:     return XX_FECH24000;
-	case 22050:     return XX_FECH22050;
-	case 16000:     return XX_FECH16000;
-	case 14000:     return XX_FECH14000;
-	case 12000:     return XX_FECH12000;
-	case 11025:     return XX_FECH11025;
-	case 8000:      return XX_FECH8000;
-	case 7350:      return XX_FECH7350;
-	default:        return freq;   /* The value is already correct */
-	}
+	snd_assert(freq > 0, return 0);
+
+	hexfreq = (28224000 * 10) / freq;
+	hexfreq = (hexfreq + 5) / 10;
+
+	/* max freq = 55125 Hz */
+	snd_assert(hexfreq > 0x00000200, return 0);
+
+	if (hexfreq <= 0x03ff)
+		return hexfreq - 0x00000201;
+	if (hexfreq <= 0x07ff) 
+		return (hexfreq / 2) - 1;
+	if (hexfreq <= 0x0fff)
+		return (hexfreq / 4) + 0x000001ff;
+
+	return 0x5fe; 	/* min freq = 6893 Hz */
 }
 
 
diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c
index f5e6018..5adde30 100644
--- a/sound/i2c/other/ak4114.c
+++ b/sound/i2c/other/ak4114.c
@@ -554,7 +554,6 @@
 		if (snd_pcm_running(ak4114->capture_substream)) {
 			// printk("rate changed (%i <- %i)\n", runtime->rate, res);
 			snd_pcm_stop(ak4114->capture_substream, SNDRV_PCM_STATE_DRAINING);
-			wake_up(&runtime->sleep);
 			res = 1;
 		}
 		snd_pcm_stream_unlock_irqrestore(ak4114->capture_substream, _flags);
diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c
index 94bbd34..a636d9c 100644
--- a/sound/isa/gus/gus_main.c
+++ b/sound/isa/gus/gus_main.c
@@ -417,11 +417,13 @@
 	return 0;
 }
 
+#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
 static void snd_gus_seq_dev_free(snd_seq_device_t *seq_dev)
 {
 	snd_gus_card_t *gus = seq_dev->private_data;
 	gus->seq_dev = NULL;
 }
+#endif
 
 int snd_gus_initialize(snd_gus_card_t *gus)
 {
diff --git a/sound/isa/wavefront/wavefront_fx.c b/sound/isa/wavefront/wavefront_fx.c
index 0e13623..3237968 100644
--- a/sound/isa/wavefront/wavefront_fx.c
+++ b/sound/isa/wavefront/wavefront_fx.c
@@ -34,7 +34,7 @@
 
 /* weird stuff, derived from port I/O tracing with dosemu */
 
-unsigned char page_zero[] __initdata = {
+static unsigned char page_zero[] __initdata = {
 0x01, 0x7c, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf5, 0x00,
 0x11, 0x00, 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x13, 0x00, 0x00,
 0x00, 0x14, 0x02, 0x76, 0x00, 0x60, 0x00, 0x80, 0x02, 0x00, 0x00,
@@ -61,7 +61,7 @@
 0x1d, 0x02, 0xdf
 };
 
-unsigned char page_one[] __initdata = {
+static unsigned char page_one[] __initdata = {
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x19, 0x00,
 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xd8, 0x00, 0x00,
 0x02, 0x20, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x01,
@@ -88,7 +88,7 @@
 0x60, 0x00, 0x1b
 };
 
-unsigned char page_two[] __initdata = {
+static unsigned char page_two[] __initdata = {
 0xc4, 0x00, 0x44, 0x07, 0x44, 0x00, 0x40, 0x25, 0x01, 0x06, 0xc4,
 0x07, 0x40, 0x25, 0x01, 0x00, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -103,7 +103,7 @@
 0x46, 0x05, 0x46, 0x07, 0x46, 0x07, 0x44
 };
 
-unsigned char page_three[] __initdata = {
+static unsigned char page_three[] __initdata = {
 0x07, 0x40, 0x00, 0x00, 0x00, 0x47, 0x00, 0x40, 0x00, 0x40, 0x06,
 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -118,7 +118,7 @@
 0x02, 0x00, 0x42, 0x00, 0xc0, 0x00, 0x40
 };
 
-unsigned char page_four[] __initdata = {
+static unsigned char page_four[] __initdata = {
 0x63, 0x03, 0x26, 0x02, 0x2c, 0x00, 0x24, 0x00, 0x2e, 0x02, 0x02,
 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -133,7 +133,7 @@
 0x02, 0x62, 0x02, 0x20, 0x01, 0x21, 0x01
 };
 
-unsigned char page_six[] __initdata = {
+static unsigned char page_six[] __initdata = {
 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x06, 0x00,
 0x00, 0x08, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x0e,
 0x00, 0x00, 0x10, 0x00, 0x00, 0x12, 0x00, 0x00, 0x14, 0x00, 0x00,
@@ -154,7 +154,7 @@
 0x80, 0x00, 0x7e, 0x80, 0x80
 };
 
-unsigned char page_seven[] __initdata = {
+static unsigned char page_seven[] __initdata = {
 0x0f, 0xff, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
 0x08, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f,
@@ -181,7 +181,7 @@
 0x00, 0x02, 0x00
 };
 
-unsigned char page_zero_v2[] __initdata = {
+static unsigned char page_zero_v2[] __initdata = {
 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -193,7 +193,7 @@
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 
-unsigned char page_one_v2[] __initdata = {
+static unsigned char page_one_v2[] __initdata = {
 0x01, 0xc0, 0x01, 0xfa, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -205,21 +205,21 @@
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 
-unsigned char page_two_v2[] __initdata = {
+static unsigned char page_two_v2[] __initdata = {
 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00
 };
-unsigned char page_three_v2[] __initdata = {
+static unsigned char page_three_v2[] __initdata = {
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00
 };
-unsigned char page_four_v2[] __initdata = {
+static unsigned char page_four_v2[] __initdata = {
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -227,7 +227,7 @@
 0x00, 0x00, 0x00, 0x00
 };
 
-unsigned char page_seven_v2[] __initdata = {
+static unsigned char page_seven_v2[] __initdata = {
 0x0f, 0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -239,7 +239,7 @@
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 
-unsigned char mod_v2[] __initdata = {
+static unsigned char mod_v2[] __initdata = {
 0x01, 0x00, 0x02, 0x00, 0x01, 0x01, 0x02, 0x00, 0x01, 0x02, 0x02,
 0x00, 0x01, 0x03, 0x02, 0x00, 0x01, 0x04, 0x02, 0x00, 0x01, 0x05,
 0x02, 0x00, 0x01, 0x06, 0x02, 0x00, 0x01, 0x07, 0x02, 0x00, 0xb0,
@@ -269,7 +269,7 @@
 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x05, 0x02, 0x01, 0x01,
 0x06, 0x02, 0x01, 0x01, 0x07, 0x02, 0x01
 };
-unsigned char coefficients[] __initdata = {
+static unsigned char coefficients[] __initdata = {
 0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x00, 0x4b, 0x03,
 0x11, 0x00, 0x4d, 0x01, 0x32, 0x07, 0x46, 0x00, 0x00, 0x07, 0x49,
 0x00, 0x00, 0x07, 0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x01,
@@ -305,14 +305,14 @@
 0x06, 0x6c, 0x4c, 0x6c, 0x06, 0x50, 0x52, 0xe2, 0x06, 0x42, 0x02,
 0xba
 };
-unsigned char coefficients2[] __initdata = {
+static unsigned char coefficients2[] __initdata = {
 0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x45, 0x0f,
 0xff, 0x07, 0x48, 0x0f, 0xff, 0x07, 0x7b, 0x04, 0xcc, 0x07, 0x7d,
 0x04, 0xcc, 0x07, 0x7c, 0x00, 0x00, 0x07, 0x7e, 0x00, 0x00, 0x07,
 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x47, 0x00, 0x00,
 0x07, 0x4a, 0x00, 0x00, 0x07, 0x4c, 0x00, 0x00, 0x07, 0x4e, 0x00, 0x00
 };
-unsigned char coefficients3[] __initdata = {
+static unsigned char coefficients3[] __initdata = {
 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x28, 0x00, 0x51, 0x00,
 0x51, 0x00, 0x7a, 0x00, 0x7a, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0xcc,
 0x00, 0xcc, 0x00, 0xf5, 0x00, 0xf5, 0x01, 0x1e, 0x01, 0x1e, 0x01,
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index a4b72cd..6983eea 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -367,6 +367,7 @@
 		ac97->regs[reg] = value;
 		ac97->bus->ops->write(ac97, reg, value);
 	}
+	set_bit(reg, ac97->reg_accessed);
 	up(&ac97->reg_mutex);
 	return change;
 }
@@ -410,6 +411,7 @@
 		ac97->regs[reg] = new;
 		ac97->bus->ops->write(ac97, reg, new);
 	}
+	set_bit(reg, ac97->reg_accessed);
 	return change;
 }
 
@@ -1076,6 +1078,11 @@
 	for (i = 0 ; i < ARRAY_SIZE(cbit); i++) {
 		unsigned short val;
 		snd_ac97_write(ac97, reg, 0x8080 | cbit[i] | (cbit[i] << 8));
+		/* Do the read twice due to buffers on some ac97 codecs.
+		 * e.g. The STAC9704 returns exactly what you wrote the the register
+		 * if you read it immediately. This causes the detect routine to fail.
+		 */
+		val = snd_ac97_read(ac97, reg);
 		val = snd_ac97_read(ac97, reg);
 		if (! *lo_max && (val & 0x7f) == cbit[i])
 			*lo_max = max[i];
@@ -2224,7 +2231,7 @@
  */
 void snd_ac97_resume(ac97_t *ac97)
 {
-	int i;
+	unsigned long end_time;
 
 	if (ac97->bus->ops->reset) {
 		ac97->bus->ops->reset(ac97);
@@ -2242,26 +2249,26 @@
 	snd_ac97_write(ac97, AC97_POWERDOWN, ac97->regs[AC97_POWERDOWN]);
 	if (ac97_is_audio(ac97)) {
 		ac97->bus->ops->write(ac97, AC97_MASTER, 0x8101);
-		for (i = HZ/10; i >= 0; i--) {
+		end_time = jiffies + msecs_to_jiffies(100);
+		do {
 			if (snd_ac97_read(ac97, AC97_MASTER) == 0x8101)
 				break;
 			set_current_state(TASK_UNINTERRUPTIBLE);
 			schedule_timeout(1);
-		}
+		} while (time_after_eq(end_time, jiffies));
 		/* FIXME: extra delay */
 		ac97->bus->ops->write(ac97, AC97_MASTER, 0x8000);
-		if (snd_ac97_read(ac97, AC97_MASTER) != 0x8000) {
-			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout(HZ/4);
-		}
+		if (snd_ac97_read(ac97, AC97_MASTER) != 0x8000)
+			msleep(250);
 	} else {
-		for (i = HZ/10; i >= 0; i--) {
+		end_time = jiffies + msecs_to_jiffies(100);
+		do {
 			unsigned short val = snd_ac97_read(ac97, AC97_EXTENDED_MID);
 			if (val != 0xffff && (val & 1) != 0)
 				break;
 			set_current_state(TASK_UNINTERRUPTIBLE);
 			schedule_timeout(1);
-		}
+		} while (time_after_eq(end_time, jiffies));
 	}
 __reset_ready:
 
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index a15eb85..66edc85 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -1528,6 +1528,9 @@
 	},
 	AC97_SURROUND_JACK_MODE_CTL,
 	AC97_CHANNEL_MODE_CTL,
+
+	AC97_SINGLE("Headphone Jack Sense", AC97_AD_JACK_SPDIF, 10, 1, 0),
+	AC97_SINGLE("Line Jack Sense", AC97_AD_JACK_SPDIF, 12, 1, 0),
 };
 
 static int patch_ad1888_specific(ac97_t *ac97)
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
index eb5c36d..f08ae71f 100644
--- a/sound/pci/ali5451/ali5451.c
+++ b/sound/pci/ali5451/ali5451.c
@@ -399,7 +399,7 @@
 	unsigned long end_time;
 	unsigned int res;
 	
-	end_time = jiffies + 10 * (HZ >> 2);
+	end_time = jiffies + 10 * msecs_to_jiffies(250);
 	do {
 		res = snd_ali_5451_peek(codec,port);
 		if (! (res & 0x8000))
@@ -422,7 +422,7 @@
 	dwChk1 = snd_ali_5451_peek(codec, ALI_STIMER);
 	dwChk2 = snd_ali_5451_peek(codec, ALI_STIMER);
 
-	end_time = jiffies + 10 * (HZ >> 2);
+	end_time = jiffies + 10 * msecs_to_jiffies(250);
 	do {
 		dwChk2 = snd_ali_5451_peek(codec, ALI_STIMER);
 		if (dwChk2 != dwChk1)
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index a6b4b8d..8d20029 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -265,6 +265,7 @@
  */
 static struct pci_device_id snd_atiixp_ids[] = {
 	{ 0x1002, 0x434d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB200 */
+	{ 0x1002, 0x4378, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB400 */
 	{ 0, }
 };
 
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c
index 4725b4a..f5a4ac1 100644
--- a/sound/pci/cmipci.c
+++ b/sound/pci/cmipci.c
@@ -306,7 +306,7 @@
 #define CM_REG_FM_PCI		0x50
 
 /*
- * for CMI-8338 .. this is not valid for CMI-8738.
+ * access from SB-mixer port
  */
 #define CM_REG_EXTENT_IND	0xf0
 #define CM_VPHONE_MASK		0xe0	/* Phone volume control (0-3) << 5 */
@@ -315,6 +315,7 @@
 #define CM_VSPKM		0x08	/* Speaker mute control, default high */
 #define CM_RLOOPREN		0x04    /* Rec. R-channel enable */
 #define CM_RLOOPLEN		0x02	/* Rec. L-channel enable */
+#define CM_VADMIC3		0x01	/* Mic record boost */
 
 /*
  * CMI-8338 spec ver 0.5 (this is not valid for CMI-8738):
@@ -2135,8 +2136,12 @@
 	CMIPCI_MIXER_VOL_STEREO("Aux Playback Volume", CM_REG_AUX_VOL, 4, 0, 15),
 	CMIPCI_MIXER_SW_STEREO("Aux Playback Switch", CM_REG_MIXER2, CM_VAUXLM_SHIFT, CM_VAUXRM_SHIFT, 0),
 	CMIPCI_MIXER_SW_STEREO("Aux Capture Switch", CM_REG_MIXER2, CM_RAUXLEN_SHIFT, CM_RAUXREN_SHIFT, 0),
-	CMIPCI_MIXER_SW_MONO("Mic Boost", CM_REG_MIXER2, CM_MICGAINZ_SHIFT, 1),
+	CMIPCI_MIXER_SW_MONO("Mic Boost Playback Switch", CM_REG_MIXER2, CM_MICGAINZ_SHIFT, 1),
 	CMIPCI_MIXER_VOL_MONO("Mic Capture Volume", CM_REG_MIXER2, CM_VADMIC_SHIFT, 7),
+	CMIPCI_SB_VOL_MONO("Phone Playback Volume", CM_REG_EXTENT_IND, 5, 7),
+	CMIPCI_DOUBLE("Phone Playback Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 4, 4, 1, 0, 0),
+	CMIPCI_DOUBLE("PC Speaker Playnack Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 3, 3, 1, 0, 0),
+	CMIPCI_DOUBLE("Mic Boost Capture Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 0, 0, 1, 0, 0),
 };
 
 /*
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
index fd4c50c..ff28af1 100644
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -2400,8 +2400,7 @@
 		if ((err = snd_ac97_read(ac97, AC97_REC_GAIN)) == 0x8a05)
 			return;
 
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(HZ/100);
+		msleep(10);
 	} while (time_after_eq(end_time, jiffies));
 
 	snd_printk("CS46xx secondary codec dont respond!\n");  
@@ -2435,8 +2434,7 @@
 			err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97[codec]);
 			return err;
 		}
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout(HZ/100);
+		msleep(10);
 	}
 	snd_printdd("snd_cs46xx: codec %d detection timeout\n", codec);
 	return -ENXIO;
@@ -3018,8 +3016,7 @@
 	/*
          *  Wait until the PLL has stabilized.
 	 */
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(HZ/10); /* 100ms */
+	msleep(100);
 
 	/*
 	 *  Turn on clocking of the core so that we can setup the serial ports.
@@ -3072,8 +3069,7 @@
 		 */
 		if (snd_cs46xx_peekBA0(chip, BA0_ACSTS) & ACSTS_CRDY)
 			goto ok1;
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout((HZ+99)/100);
+		msleep(10);
 	}
 
 
@@ -3122,8 +3118,7 @@
 		 */
 		if ((snd_cs46xx_peekBA0(chip, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) == (ACISV_ISV3 | ACISV_ISV4))
 			goto ok2;
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout((HZ+99)/100);
+		msleep(10);
 	}
 
 #ifndef CONFIG_SND_CS46XX_NEW_DSP
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c
index 2085a99..b17142c 100644
--- a/sound/pci/emu10k1/emu10k1.c
+++ b/sound/pci/emu10k1/emu10k1.c
@@ -52,6 +52,7 @@
 static int max_synth_voices[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 64};
 static int max_buffer_size[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 128};
 static int enable_ir[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
+static uint subsystem[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; /* Force card subsystem model */
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for the EMU10K1 soundcard.");
@@ -71,7 +72,8 @@
 MODULE_PARM_DESC(max_buffer_size, "Maximum sample buffer size in MB.");
 module_param_array(enable_ir, bool, NULL, 0444);
 MODULE_PARM_DESC(enable_ir, "Enable IR.");
-
+module_param_array(subsystem, uint, NULL, 0444);
+MODULE_PARM_DESC(subsystem, "Force card subsystem model.");
 /*
  * Class 0401: 1102:0008 (rev 00) Subsystem: 1102:1001 -> Audigy2 Value  Model:SB0400
  */
@@ -122,7 +124,7 @@
 		max_buffer_size[dev] = 1024;
 	if ((err = snd_emu10k1_create(card, pci, extin[dev], extout[dev],
 				      (long)max_buffer_size[dev] * 1024 * 1024,
-				      enable_ir[dev],
+				      enable_ir[dev], subsystem[dev],
 				      &emu)) < 0) {
 		snd_card_free(card);
 		return err;
@@ -140,7 +142,7 @@
 		return err;
 	}
 	/* This stores the periods table. */
-	if (emu->audigy && emu->revision == 4) { /* P16V */	
+	if (emu->card_capabilities->ca0151_chip) { /* P16V */	
 		if(snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), 1024, &emu->p16v_buffer) < 0) {
 			snd_p16v_free(emu);
 			return -ENOMEM;
@@ -161,7 +163,7 @@
 		snd_card_free(card);
 		return err;
 	}
-	if (emu->audigy && emu->revision == 4) { /* P16V */	
+	if (emu->card_capabilities->ca0151_chip) { /* P16V */	
 		if ((err = snd_p16v_pcm(emu, 4, NULL)) < 0) {
 			snd_card_free(card);
 			return err;
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index a341e75..746b51e 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -191,7 +191,7 @@
 		/* Set playback routing. */
 		snd_emu10k1_ptr20_write(emu, CAPTURE_P16V_SOURCE, 0, 0x78e4);
 	}
-	if (emu->audigy && (emu->serial == 0x10011102) ) { /* audigy2 Value */
+	if (emu->card_capabilities->ca0108_chip) { /* audigy2 Value */
 		/* Hacks for Alice3 to work independent of haP16V driver */
 		u32 tmp;
 
@@ -253,6 +253,8 @@
 			     HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG);
 		else
 			outl(HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG);
+	/* FIXME: Remove all these emu->model and replace it with a card recognition parameter,
+	 * e.g. card_capabilities->joystick */
 	} else if (emu->model == 0x20 ||
 	    emu->model == 0xc400 ||
 	    (emu->model == 0x21 && emu->revision < 6))
@@ -299,12 +301,12 @@
 	if (emu->audigy) {
 		outl(inl(emu->port + A_IOCFG) & ~0x44, emu->port + A_IOCFG);
  
-		if (emu->revision == 4) { /* audigy2 */
+		if (emu->card_capabilities->ca0151_chip) { /* audigy2 */
 			/* Unmute Analog now.  Set GPO6 to 1 for Apollo.
 			 * This has to be done after init ALice3 I2SOut beyond 48KHz.
 			 * So, sequence is important. */
 			outl(inl(emu->port + A_IOCFG) | 0x0040, emu->port + A_IOCFG);
-		} else if (emu->serial == 0x10011102) { /* audigy2 value */
+		} else if (emu->card_capabilities->ca0108_chip) { /* audigy2 value */
 			/* Unmute Analog now. */
 			outl(inl(emu->port + A_IOCFG) | 0x0060, emu->port + A_IOCFG);
 		} else {
@@ -614,6 +616,7 @@
 
 static emu_chip_details_t emu_chip_details[] = {
 	/* Audigy 2 Value AC3 out does not work yet. Need to find out how to turn off interpolators.*/
+	/* Tested by James@superbug.co.uk 3rd July 2005 */
 	{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10011102,
 	 .driver = "Audigy2", .name = "Audigy 2 Value [SB0400]", 
 	 .id = "Audigy2",
@@ -627,6 +630,14 @@
 	 .emu10k2_chip = 1,
 	 .ca0108_chip = 1,
 	 .ac97_chip = 1} ,
+	/* Tested by James@superbug.co.uk 8th July 2005. No sound available yet. */
+	{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40011102,
+	 .driver = "Audigy2", .name = "E-mu 1212m [4001]", 
+	 .id = "EMU1212m",
+	 .emu10k2_chip = 1,
+	 .ca0102_chip = 1,
+	 .ecard = 1} ,
+	/* Tested by James@superbug.co.uk 3rd July 2005 */
 	{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102,
 	 .driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]", 
 	 .id = "Audigy2",
@@ -687,19 +698,19 @@
 	 .ca0151_chip = 1,
 	 .spdif_bug = 1,
 	 .ac97_chip = 1} ,
-	{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10020052,
-	 .driver = "Audigy", .name = "Audigy 1 ES [SB0160]", 
-	 .id = "Audigy",
-	 .emu10k2_chip = 1,
-	 .ca0102_chip = 1,
-	 .spdif_bug = 1,
-	 .ac97_chip = 1} ,
 	{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00531102,
 	 .driver = "Audigy", .name = "Audigy 1 [SB0090]", 
 	 .id = "Audigy",
 	 .emu10k2_chip = 1,
 	 .ca0102_chip = 1,
 	 .ac97_chip = 1} ,
+	{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00521102,
+	 .driver = "Audigy", .name = "Audigy 1 ES [SB0160]", 
+	 .id = "Audigy",
+	 .emu10k2_chip = 1,
+	 .ca0102_chip = 1,
+	 .spdif_bug = 1,
+	 .ac97_chip = 1} ,
 	{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00511102,
 	 .driver = "Audigy", .name = "Audigy 1 [SB0090]", 
 	 .id = "Audigy",
@@ -712,96 +723,8 @@
 	 .emu10k2_chip = 1,
 	 .ca0102_chip = 1,
 	 .ac97_chip = 1} ,
-	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x40011102,
-	 .driver = "EMU10K1", .name = "E-mu APS [4001]", 
-	 .id = "APS",
-	 .emu10k1_chip = 1,
-	 .ecard = 1} ,
-	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80611102,
-	 .driver = "EMU10K1", .name = "SBLive! Player 5.1 [SB0060]", 
-	 .id = "Live",
-	 .emu10k1_chip = 1,
-	 .ac97_chip = 1,
-	 .sblive51 = 1} ,
-	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80641102,
-	 .driver = "EMU10K1", .name = "SB Live 5.1", 
-	 .id = "Live",
-	 .emu10k1_chip = 1,
-	 .ac97_chip = 1,
-	 .sblive51 = 1} ,
-	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80401102,
-	 .driver = "EMU10K1", .name = "SBLive! Platinum [CT4760P]", 
-	 .id = "Live",
-	 .emu10k1_chip = 1,
-	 .ac97_chip = 1} ,
-	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x00211102,
-	 .driver = "EMU10K1", .name = "SBLive! [CT4620]", 
-	 .id = "Live",
-	 .emu10k1_chip = 1,
-	 .ac97_chip = 1,
-	 .sblive51 = 1} ,
-	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x00201102,
-	 .driver = "EMU10K1", .name = "SBLive! Value [CT4670]", 
-	 .id = "Live",
-	 .emu10k1_chip = 1,
-	 .ac97_chip = 1,
-	 .sblive51 = 1} ,
-	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80221102,
-	 .driver = "EMU10K1", .name = "SBLive! Value [CT4780]", 
-	 .id = "Live",
-	 .emu10k1_chip = 1,
-	 .ac97_chip = 1,
-	 .sblive51 = 1} ,
-	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80231102,
-	 .driver = "EMU10K1", .name = "SB PCI512 [CT4790]", 
-	 .id = "Live",
-	 .emu10k1_chip = 1,
-	 .ac97_chip = 1,
-	 .sblive51 = 1} ,
-	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80261102,
-	 .driver = "EMU10K1", .name = "SBLive! Value [CT4830]", 
-	 .id = "Live",
-	 .emu10k1_chip = 1,
-	 .ac97_chip = 1,
-	 .sblive51 = 1} ,
-	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80311102,
-	 .driver = "EMU10K1", .name = "SBLive! Value [CT4831]", 
-	 .id = "Live",
-	 .emu10k1_chip = 1,
-	 .ac97_chip = 1,
-	 .sblive51 = 1} ,
-	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80271102,
-	 .driver = "EMU10K1", .name = "SBLive! Value [CT4832]", 
-	 .id = "Live",
-	 .emu10k1_chip = 1,
-	 .ac97_chip = 1,
-	 .sblive51 = 1} ,
-	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80511102,
-	 .driver = "EMU10K1", .name = "SBLive! Value [CT4850]", 
-	 .id = "Live",
-	 .emu10k1_chip = 1,
-	 .ac97_chip = 1,
-	 .sblive51 = 1} ,
-	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80281102,
-	 .driver = "EMU10K1", .name = "SBLive! Value [CT4870]", 
-	 .id = "Live",
-	 .emu10k1_chip = 1,
-	 .ac97_chip = 1,
-	 .sblive51 = 1} ,
-	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80321102,
-	 .driver = "EMU10K1", .name = "SBLive! Value [CT4871]", 
-	 .id = "Live",
-	 .emu10k1_chip = 1,
-	 .ac97_chip = 1,
-	 .sblive51 = 1} ,
-	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80611102,
-	 .driver = "EMU10K1", .name = "SBLive! Value [SB0060]", 
-	 .id = "Live",
-	 .emu10k1_chip = 1,
-	 .ac97_chip = 1,
-	 .sblive51 = 1} ,
-	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80691102,
-	 .driver = "EMU10K1", .name = "SBLive! Value [SB0101]", 
+	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806B1102,
+	 .driver = "EMU10K1", .name = "SBLive! [SB0105]", 
 	 .id = "Live",
 	 .emu10k1_chip = 1,
 	 .ac97_chip = 1,
@@ -812,8 +735,91 @@
 	 .emu10k1_chip = 1,
 	 .ac97_chip = 1,
 	 .sblive51 = 1} ,
-	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806B1102,
-	 .driver = "EMU10K1", .name = "SBLive! [SB0105]", 
+	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80691102,
+	 .driver = "EMU10K1", .name = "SBLive! Value [SB0101]", 
+	 .id = "Live",
+	 .emu10k1_chip = 1,
+	 .ac97_chip = 1,
+	 .sblive51 = 1} ,
+	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80641102,
+	 .driver = "EMU10K1", .name = "SB Live 5.1", 
+	 .id = "Live",
+	 .emu10k1_chip = 1,
+	 .ac97_chip = 1,
+	 .sblive51 = 1} ,
+	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80611102,
+	 .driver = "EMU10K1", .name = "SBLive! Player 5.1 [SB0060]", 
+	 .id = "Live",
+	 .emu10k1_chip = 1,
+	 .ac97_chip = 1,
+	 .sblive51 = 1} ,
+	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80511102,
+	 .driver = "EMU10K1", .name = "SBLive! Value [CT4850]", 
+	 .id = "Live",
+	 .emu10k1_chip = 1,
+	 .ac97_chip = 1,
+	 .sblive51 = 1} ,
+	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80401102,
+	 .driver = "EMU10K1", .name = "SBLive! Platinum [CT4760P]", 
+	 .id = "Live",
+	 .emu10k1_chip = 1,
+	 .ac97_chip = 1} ,
+	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80321102,
+	 .driver = "EMU10K1", .name = "SBLive! Value [CT4871]", 
+	 .id = "Live",
+	 .emu10k1_chip = 1,
+	 .ac97_chip = 1,
+	 .sblive51 = 1} ,
+	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80311102,
+	 .driver = "EMU10K1", .name = "SBLive! Value [CT4831]", 
+	 .id = "Live",
+	 .emu10k1_chip = 1,
+	 .ac97_chip = 1,
+	 .sblive51 = 1} ,
+	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80281102,
+	 .driver = "EMU10K1", .name = "SBLive! Value [CT4870]", 
+	 .id = "Live",
+	 .emu10k1_chip = 1,
+	 .ac97_chip = 1,
+	 .sblive51 = 1} ,
+	/* Tested by James@superbug.co.uk 3rd July 2005 */
+	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80271102,
+	 .driver = "EMU10K1", .name = "SBLive! Value [CT4832]", 
+	 .id = "Live",
+	 .emu10k1_chip = 1,
+	 .ac97_chip = 1,
+	 .sblive51 = 1} ,
+	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80261102,
+	 .driver = "EMU10K1", .name = "SBLive! Value [CT4830]", 
+	 .id = "Live",
+	 .emu10k1_chip = 1,
+	 .ac97_chip = 1,
+	 .sblive51 = 1} ,
+	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80231102,
+	 .driver = "EMU10K1", .name = "SB PCI512 [CT4790]", 
+	 .id = "Live",
+	 .emu10k1_chip = 1,
+	 .ac97_chip = 1,
+	 .sblive51 = 1} ,
+	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80221102,
+	 .driver = "EMU10K1", .name = "SBLive! Value [CT4780]", 
+	 .id = "Live",
+	 .emu10k1_chip = 1,
+	 .ac97_chip = 1,
+	 .sblive51 = 1} ,
+	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x40011102,
+	 .driver = "EMU10K1", .name = "E-mu APS [4001]", 
+	 .id = "APS",
+	 .emu10k1_chip = 1,
+	 .ecard = 1} ,
+	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x00211102,
+	 .driver = "EMU10K1", .name = "SBLive! [CT4620]", 
+	 .id = "Live",
+	 .emu10k1_chip = 1,
+	 .ac97_chip = 1,
+	 .sblive51 = 1} ,
+	{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x00201102,
+	 .driver = "EMU10K1", .name = "SBLive! Value [CT4670]", 
 	 .id = "Live",
 	 .emu10k1_chip = 1,
 	 .ac97_chip = 1,
@@ -833,6 +839,7 @@
 		       unsigned short extout_mask,
 		       long max_cache_bytes,
 		       int enable_ir,
+		       uint subsystem,
 		       emu10k1_t ** remu)
 {
 	emu10k1_t *emu;
@@ -878,10 +885,16 @@
 
 	for (c = emu_chip_details; c->vendor; c++) {
 		if (c->vendor == pci->vendor && c->device == pci->device) {
-			if (c->subsystem && c->subsystem != emu->serial)
-				continue;
-			if (c->revision && c->revision != emu->revision)
-				continue;
+			if (subsystem) {
+				if (c->subsystem && (c->subsystem == subsystem) ) {
+					break;
+				} else continue;
+			} else {
+				if (c->subsystem && (c->subsystem != emu->serial) )
+					continue;
+				if (c->revision && c->revision != emu->revision)
+					continue;
+			}
 			break;
 		}
 	}
@@ -892,10 +905,14 @@
 		return -ENOENT;
 	}
 	emu->card_capabilities = c;
-	if (c->subsystem != 0)
+	if (c->subsystem && !subsystem)
 		snd_printdd("Sound card name=%s\n", c->name);
-	else
-		snd_printdd("Sound card name=%s, vendor=0x%x, device=0x%x, subsystem=0x%x\n", c->name, pci->vendor, pci->device, emu->serial);
+	else if (subsystem) 
+		snd_printdd("Sound card name=%s, vendor=0x%x, device=0x%x, subsystem=0x%x. Forced to subsytem=0x%x\n",
+		       	c->name, pci->vendor, pci->device, emu->serial, c->subsystem);
+	else 
+		snd_printdd("Sound card name=%s, vendor=0x%x, device=0x%x, subsystem=0x%x.\n",
+		      	c->name, pci->vendor, pci->device, emu->serial);
 	
 	if (!*card->id && c->id) {
 		int i, n = 0;
diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c
index 98f9801..a169133 100644
--- a/sound/pci/emu10k1/p16v.c
+++ b/sound/pci/emu10k1/p16v.c
@@ -822,7 +822,7 @@
 static snd_kcontrol_new_t snd_p16v_volume_control_analog_front =
 {
         .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
-        .name =         "HD Analog Front Volume",
+        .name =         "HD Analog Front Playback Volume",
         .info =         snd_p16v_volume_info,
         .get =          snd_p16v_volume_get_analog_front,
         .put =          snd_p16v_volume_put_analog_front
@@ -831,7 +831,7 @@
 static snd_kcontrol_new_t snd_p16v_volume_control_analog_center_lfe =
 {
         .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
-        .name =         "HD Analog Center/LFE Volume",
+        .name =         "HD Analog Center/LFE Playback Volume",
         .info =         snd_p16v_volume_info,
         .get =          snd_p16v_volume_get_analog_center_lfe,
         .put =          snd_p16v_volume_put_analog_center_lfe
@@ -840,7 +840,7 @@
 static snd_kcontrol_new_t snd_p16v_volume_control_analog_unknown =
 {
         .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
-        .name =         "HD Analog Unknown Volume",
+        .name =         "HD Analog Unknown Playback Volume",
         .info =         snd_p16v_volume_info,
         .get =          snd_p16v_volume_get_analog_unknown,
         .put =          snd_p16v_volume_put_analog_unknown
@@ -849,7 +849,7 @@
 static snd_kcontrol_new_t snd_p16v_volume_control_analog_rear =
 {
         .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
-        .name =         "HD Analog Rear Volume",
+        .name =         "HD Analog Rear Playback Volume",
         .info =         snd_p16v_volume_info,
         .get =          snd_p16v_volume_get_analog_rear,
         .put =          snd_p16v_volume_put_analog_rear
@@ -858,7 +858,7 @@
 static snd_kcontrol_new_t snd_p16v_volume_control_spdif_front =
 {
         .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
-        .name =         "HD SPDIF Front Volume",
+        .name =         "HD SPDIF Front Playback Volume",
         .info =         snd_p16v_volume_info,
         .get =          snd_p16v_volume_get_spdif_front,
         .put =          snd_p16v_volume_put_spdif_front
@@ -867,7 +867,7 @@
 static snd_kcontrol_new_t snd_p16v_volume_control_spdif_center_lfe =
 {
         .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
-        .name =         "HD SPDIF Center/LFE Volume",
+        .name =         "HD SPDIF Center/LFE Playback Volume",
         .info =         snd_p16v_volume_info,
         .get =          snd_p16v_volume_get_spdif_center_lfe,
         .put =          snd_p16v_volume_put_spdif_center_lfe
@@ -876,7 +876,7 @@
 static snd_kcontrol_new_t snd_p16v_volume_control_spdif_unknown =
 {
         .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
-        .name =         "HD SPDIF Unknown Volume",
+        .name =         "HD SPDIF Unknown Playback Volume",
         .info =         snd_p16v_volume_info,
         .get =          snd_p16v_volume_get_spdif_unknown,
         .put =          snd_p16v_volume_put_spdif_unknown
@@ -885,7 +885,7 @@
 static snd_kcontrol_new_t snd_p16v_volume_control_spdif_rear =
 {
         .iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
-        .name =         "HD SPDIF Rear Volume",
+        .name =         "HD SPDIF Rear Playback Volume",
         .info =         snd_p16v_volume_info,
         .get =          snd_p16v_volume_get_spdif_rear,
         .put =          snd_p16v_volume_put_spdif_rear
@@ -936,7 +936,7 @@
 static snd_kcontrol_new_t snd_p16v_capture_source __devinitdata =
 {
 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
-	.name =		"HD Capture source",
+	.name =		"HD source Capture",
 	.info =		snd_p16v_capture_source_info,
 	.get =		snd_p16v_capture_source_get,
 	.put =		snd_p16v_capture_source_put
@@ -985,7 +985,7 @@
 static snd_kcontrol_new_t snd_p16v_capture_channel __devinitdata =
 {
 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
-	.name =		"HD Capture channel",
+	.name =		"HD channel Capture",
 	.info =		snd_p16v_capture_channel_info,
 	.get =		snd_p16v_capture_channel_get,
 	.put =		snd_p16v_capture_channel_put
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index 4e63498..78a81f3 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -685,6 +685,15 @@
 	return 0;
 }
 
+static void snd_es1371_codec_wait(ac97_t *ac97)
+{
+	msleep(750);
+	snd_es1371_codec_read(ac97, AC97_RESET);
+	snd_es1371_codec_read(ac97, AC97_VENDOR_ID1);
+	snd_es1371_codec_read(ac97, AC97_VENDOR_ID2);
+	msleep(50);
+}
+
 static void snd_es1371_adc_rate(ensoniq_t * ensoniq, unsigned int rate)
 {
 	unsigned int n, truncm, freq, result;
@@ -1585,6 +1594,7 @@
 	static ac97_bus_ops_t ops = {
 		.write = snd_es1371_codec_write,
 		.read = snd_es1371_codec_read,
+		.wait = snd_es1371_codec_wait,
 	};
 
 	if ((err = snd_ac97_bus(card, 0, &ops, NULL, &pbus)) < 0)
@@ -2008,21 +2018,11 @@
 		if (pci->vendor == es1371_ac97_reset_hack[idx].vid &&
 		    pci->device == es1371_ac97_reset_hack[idx].did &&
 		    ensoniq->rev == es1371_ac97_reset_hack[idx].rev) {
-		        unsigned long tmo;
-			signed long tmo2;
-
 			ensoniq->cssr |= ES_1371_ST_AC97_RST;
 			outl(ensoniq->cssr, ES_REG(ensoniq, STATUS));
 			/* need to delay around 20ms(bleech) to give
 			some CODECs enough time to wakeup */
-			tmo = jiffies + (HZ / 50) + 1;
-			while (1) {
-				tmo2 = tmo - jiffies;
-				if (tmo2 <= 0)
-					break;
-				set_current_state(TASK_UNINTERRUPTIBLE);
-				schedule_timeout(tmo2);
-			}
+			msleep(20);
 			break;
 		}
 	/* AC'97 warm reset to start the bitclk */
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index 327a341..9d7a287 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -664,11 +664,6 @@
 	return result;
 }
 
-#define big_mdelay(msec) do {\
-	set_current_state(TASK_UNINTERRUPTIBLE);\
-	schedule_timeout(((msec) * HZ + 999) / 1000);\
-} while (0)
-	
 /* Wait for the codec bus to be free */
 static int snd_es1968_ac97_wait(es1968_t *chip)
 {
@@ -1809,8 +1804,7 @@
 	snd_es1968_trigger_apu(chip, apu, ESM_APU_16BITLINEAR);
 	do_gettimeofday(&start_time);
 	spin_unlock_irq(&chip->reg_lock);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(HZ / 20); /* 50 msec */
+	msleep(50);
 	spin_lock_irq(&chip->reg_lock);
 	offset = __apu_get_register(chip, apu, 5);
 	do_gettimeofday(&stop_time);
@@ -2093,7 +2087,7 @@
 	outw(0x0000, ioaddr + 0x60);	/* write 0 to gpio 0 */
 	udelay(20);
 	outw(0x0001, ioaddr + 0x60);	/* write 1 to gpio 1 */
-	big_mdelay(20);
+	msleep(20);
 
 	outw(save_68 | 0x1, ioaddr + 0x68);	/* now restore .. */
 	outw((inw(ioaddr + 0x38) & 0xfffc) | 0x1, ioaddr + 0x38);
@@ -2109,7 +2103,7 @@
 	outw(0x0001, ioaddr + 0x60);	/* write 1 to gpio */
 	udelay(20);
 	outw(0x0009, ioaddr + 0x60);	/* write 9 to gpio */
-	big_mdelay(500);
+	msleep(500);
 	//outw(inw(ioaddr + 0x38) & 0xfffc, ioaddr + 0x38);
 	outw(inw(ioaddr + 0x3a) & 0xfffc, ioaddr + 0x3a);
 	outw(inw(ioaddr + 0x3c) & 0xfffc, ioaddr + 0x3c);
@@ -2135,7 +2129,7 @@
 
 		if (w > 10000) {
 			outb(inb(ioaddr + 0x37) | 0x08, ioaddr + 0x37);	/* do a software reset */
-			big_mdelay(500);	/* oh my.. */
+			msleep(500);	/* oh my.. */
 			outb(inb(ioaddr + 0x37) & ~0x08,
 				ioaddr + 0x37);
 			udelay(1);
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 5999156..dd0d99d 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -262,6 +262,9 @@
 #define AC_PINCTL_OUT_EN		(1<<6)
 #define AC_PINCTL_HP_EN			(1<<7)
 
+/* Unsolicited response - 8bit */
+#define AC_USRSP_EN			(1<<7)
+
 /* configuration default - 32bit */
 #define AC_DEFCFG_SEQUENCE		(0xf<<0)
 #define AC_DEFCFG_DEF_ASSOC		(0xf<<4)
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 5e0cca3..288ab07 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -178,6 +178,9 @@
 #define ICH6_INT_CTRL_EN	0x40000000	/* controller interrupt enable bit */
 #define ICH6_INT_GLOBAL_EN	0x80000000	/* global interrupt enable bit */
 
+/* GCTL unsolicited response enable bit */
+#define ICH6_GCTL_UREN		(1<<8)
+
 /* GCTL reset bit */
 #define ICH6_GCTL_RESET		(1<<0)
 
@@ -562,6 +565,9 @@
 		return -EBUSY;
 	}
 
+	/* Accept unsolicited responses */
+	azx_writel(chip, GCTL, azx_readl(chip, GCTL) | ICH6_GCTL_UREN);
+
 	/* detect codecs */
 	if (! chip->codec_mask) {
 		chip->codec_mask = azx_readw(chip, STATESTS);
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c
index 2d6e3e3..86f195f 100644
--- a/sound/pci/hda/patch_cmedia.c
+++ b/sound/pci/hda/patch_cmedia.c
@@ -408,7 +408,7 @@
 		/* search for an empty channel */
 		for (j = 0; j < cfg->line_outs; j++) {
 			if (! assigned[j]) {
-				spec->dac_nids[i] = i + 0x03;
+				spec->dac_nids[i] = j + 0x03;
 				assigned[j] = 1;
 				break;
 			}
@@ -444,11 +444,10 @@
 			len = snd_hda_get_connections(codec, nid, conn, 4);
 			for (k = 0; k < len; k++)
 				if (conn[k] == spec->dac_nids[i]) {
-					spec->multi_init[j].param = j;
+					spec->multi_init[j].param = k;
 					break;
 				}
 			j++;
-			break;
 		}
 	}
 	return 0;
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index bab8984..9b85699 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -40,6 +40,7 @@
 	ALC880_W810,
 	ALC880_Z71V,
 	ALC880_AUTO,
+	ALC880_6ST,
 	ALC880_6ST_DIG,
 	ALC880_F1734,
 	ALC880_ASUS,
@@ -119,6 +120,7 @@
 	unsigned int num_kctl_alloc, num_kctl_used;
 	snd_kcontrol_new_t *kctl_alloc;
 	struct hda_input_mux private_imux;
+	hda_nid_t private_dac_nids[4];
 };
 
 
@@ -1547,9 +1549,10 @@
 	{ .pci_subvendor = 0x8086, .pci_subdevice = 0xa100, .config = ALC880_5ST_DIG },
 	{ .pci_subvendor = 0x1565, .pci_subdevice = 0x8202, .config = ALC880_5ST_DIG },
 	{ .pci_subvendor = 0x1019, .pci_subdevice = 0xa880, .config = ALC880_5ST_DIG },
-	{ .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_5ST_DIG },
+	/* { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_5ST_DIG }, */ /* conflict with 6stack */
 	{ .pci_subvendor = 0x1695, .pci_subdevice = 0x400d, .config = ALC880_5ST_DIG },
-	{ .pci_subvendor = 0x0000, .pci_subdevice = 0x8086, .config = ALC880_5ST_DIG },
+	/* note subvendor = 0 below */
+	/* { .pci_subvendor = 0x0000, .pci_subdevice = 0x8086, .config = ALC880_5ST_DIG }, */
 
 	{ .modelname = "w810", .config = ALC880_W810 },
 	{ .pci_subvendor = 0x161f, .pci_subdevice = 0x203d, .config = ALC880_W810 },
@@ -1557,7 +1560,10 @@
 	{ .modelname = "z71v", .config = ALC880_Z71V },
 	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_Z71V },
 
-	{ .modelname = "6statack-digout", .config = ALC880_6ST_DIG },
+	{ .modelname = "6stack", .config = ALC880_6ST },
+	{ .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_6ST }, /* Acer APFV */
+
+	{ .modelname = "6stack-digout", .config = ALC880_6ST_DIG },
 	{ .pci_subvendor = 0x2668, .pci_subdevice = 0x8086, .config = ALC880_6ST_DIG },
 	{ .pci_subvendor = 0x8086, .pci_subdevice = 0x2668, .config = ALC880_6ST_DIG },
 	{ .pci_subvendor = 0x1462, .pci_subdevice = 0x1150, .config = ALC880_6ST_DIG },
@@ -1644,6 +1650,15 @@
 		.channel_mode = alc880_fivestack_modes,
 		.input_mux = &alc880_capture_source,
 	},
+	[ALC880_6ST] = {
+		.mixers = { alc880_six_stack_mixer },
+		.init_verbs = { alc880_volume_init_verbs, alc880_pin_6stack_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc880_6st_dac_nids),
+		.dac_nids = alc880_6st_dac_nids,
+		.num_channel_mode = ARRAY_SIZE(alc880_sixstack_modes),
+		.channel_mode = alc880_sixstack_modes,
+		.input_mux = &alc880_6stack_capture_source,
+	},
 	[ALC880_6ST_DIG] = {
 		.mixers = { alc880_six_stack_mixer },
 		.init_verbs = { alc880_volume_init_verbs, alc880_pin_6stack_init_verbs },
@@ -1656,7 +1671,8 @@
 	},
 	[ALC880_W810] = {
 		.mixers = { alc880_w810_base_mixer },
-		.init_verbs = { alc880_volume_init_verbs, alc880_pin_w810_init_verbs },
+		.init_verbs = { alc880_volume_init_verbs, alc880_pin_w810_init_verbs,
+				alc880_gpio2_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc880_w810_dac_nids),
 		.dac_nids = alc880_w810_dac_nids,
 		.dig_out_nid = ALC880_DIGOUT_NID,
@@ -1666,8 +1682,7 @@
 	},
 	[ALC880_Z71V] = {
 		.mixers = { alc880_z71v_mixer },
-		.init_verbs = { alc880_volume_init_verbs, alc880_pin_z71v_init_verbs,
-				alc880_gpio2_init_verbs },
+		.init_verbs = { alc880_volume_init_verbs, alc880_pin_z71v_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc880_z71v_dac_nids),
 		.dac_nids = alc880_z71v_dac_nids,
 		.dig_out_nid = ALC880_DIGOUT_NID,
@@ -1809,6 +1824,7 @@
 	int i, j;
 
 	memset(assigned, 0, sizeof(assigned));
+	spec->multiout.dac_nids = spec->private_dac_nids;
 
 	/* check the pins hardwired to audio widget */
 	for (i = 0; i < cfg->line_outs; i++) {
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 013be2e..9d503da 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -30,32 +30,37 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <sound/core.h>
+#include <sound/asoundef.h>
 #include "hda_codec.h"
 #include "hda_local.h"
 
 #undef STAC_TEST
 
+#define NUM_CONTROL_ALLOC	32
+#define STAC_HP_EVENT		0x37
+#define STAC_UNSOL_ENABLE 	(AC_USRSP_EN | STAC_HP_EVENT)
+
 struct sigmatel_spec {
+	snd_kcontrol_new_t *mixers[4];
+	unsigned int num_mixers;
+
+	unsigned int surr_switch: 1;
+
 	/* playback */
 	struct hda_multi_out multiout;
-	hda_nid_t playback_nid;
+	hda_nid_t dac_nids[4];
 
 	/* capture */
 	hda_nid_t *adc_nids;
 	unsigned int num_adcs;
 	hda_nid_t *mux_nids;
 	unsigned int num_muxes;
-	hda_nid_t capture_nid;
 	hda_nid_t dig_in_nid;
 
-	/* power management*/
-	hda_nid_t *pstate_nids;
-	unsigned int num_pstates;
-
+#ifdef STAC_TEST
 	/* pin widgets */
 	hda_nid_t *pin_nids;
 	unsigned int num_pins;
-#ifdef STAC_TEST
 	unsigned int *pin_configs;
 #endif
 
@@ -64,16 +69,20 @@
 	snd_kcontrol_new_t *mixer;
 
 	/* capture source */
-	struct hda_input_mux input_mux;
-	char input_labels[HDA_MAX_NUM_INPUTS][16];
+	struct hda_input_mux *input_mux;
 	unsigned int cur_mux[2];
 
 	/* channel mode */
 	unsigned int num_ch_modes;
 	unsigned int cur_ch_mode;
-	const struct sigmatel_channel_mode *channel_modes;
 
-	struct hda_pcm pcm_rec[1];	/* PCM information */
+	struct hda_pcm pcm_rec[2];	/* PCM information */
+
+	/* dynamic controls and input_mux */
+	struct auto_pin_cfg autocfg;
+	unsigned int num_kctl_alloc, num_kctl_used;
+	snd_kcontrol_new_t *kctl_alloc;
+	struct hda_input_mux private_imux;
 };
 
 static hda_nid_t stac9200_adc_nids[1] = {
@@ -88,14 +97,6 @@
         0x02,
 };
 
-static hda_nid_t stac9200_pstate_nids[3] = {
-	0x01, 0x02, 0x03,
-};
-
-static hda_nid_t stac9200_pin_nids[8] = {
-	0x08, 0x09, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
-};
-
 static hda_nid_t stac922x_adc_nids[2] = {
         0x06, 0x07,
 };
@@ -104,24 +105,22 @@
         0x12, 0x13,
 };
 
-static hda_nid_t stac922x_dac_nids[4] = {
-        0x02, 0x03, 0x04, 0x05,
-};
-
-static hda_nid_t stac922x_pstate_nids[8] = {
-	0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x11,
+#ifdef STAC_TEST
+static hda_nid_t stac9200_pin_nids[8] = {
+	0x08, 0x09, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
 };
 
 static hda_nid_t stac922x_pin_nids[10] = {
 	0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
 	0x0f, 0x10, 0x11, 0x15, 0x1b,
 };
+#endif
 
 static int stac92xx_mux_enum_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct sigmatel_spec *spec = codec->spec;
-	return snd_hda_input_mux_info(&spec->input_mux, uinfo);
+	return snd_hda_input_mux_info(spec->input_mux, uinfo);
 }
 
 static int stac92xx_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
@@ -140,26 +139,64 @@
 	struct sigmatel_spec *spec = codec->spec;
 	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
 
-	return snd_hda_input_mux_put(codec, &spec->input_mux, ucontrol,
+	return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
 				     spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]);
 }
 
-static struct hda_verb stac9200_ch2_init[] = {
+static struct hda_verb stac9200_core_init[] = {
 	/* set dac0mux for dac converter */
-	{ 0x07, 0x701, 0x00},
+	{ 0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
 	{}
 };
 
-static struct hda_verb stac922x_ch2_init[] = {
+static struct hda_verb stac922x_core_init[] = {
 	/* set master volume and direct control */	
-	{ 0x16, 0x70f, 0xff},
+	{ 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
 	{}
 };
 
-struct sigmatel_channel_mode {
-	unsigned int channels;
-	const struct hda_verb *sequence;
-};
+static int stac922x_channel_modes[3] = {2, 6, 8};
+
+static int stac922x_ch_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = spec->num_ch_modes;
+	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+	sprintf(uinfo->value.enumerated.name, "%dch",
+		stac922x_channel_modes[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int stac922x_ch_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+
+	ucontrol->value.enumerated.item[0] = spec->cur_ch_mode;
+	return 0;
+}
+
+static int stac922x_ch_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct sigmatel_spec *spec = codec->spec;
+
+	if (ucontrol->value.enumerated.item[0] >= spec->num_ch_modes)
+		ucontrol->value.enumerated.item[0] = spec->num_ch_modes;
+	if (ucontrol->value.enumerated.item[0] == spec->cur_ch_mode &&
+	    ! codec->in_resume)
+		return 0;
+
+	spec->cur_ch_mode = ucontrol->value.enumerated.item[0];
+	spec->multiout.max_channels = stac922x_channel_modes[spec->cur_ch_mode];
+
+	return 1;
+}
 
 static snd_kcontrol_new_t stac9200_mixer[] = {
 	HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT),
@@ -174,13 +211,12 @@
 	},
 	HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT),
 	HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Input Mux Volume", 0x0c, 0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Capture Mux Volume", 0x0c, 0, HDA_OUTPUT),
 	{ } /* end */
 };
 
+/* This needs to be generated dynamically based on sequence */
 static snd_kcontrol_new_t stac922x_mixer[] = {
-	HDA_CODEC_VOLUME("PCM Playback Volume", 0x2, 0x0, HDA_OUTPUT),
-	HDA_CODEC_MUTE("PCM Playback Switch", 0x2, 0x0, HDA_OUTPUT),
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Input Source",
@@ -195,14 +231,38 @@
 	{ } /* end */
 };
 
+static snd_kcontrol_new_t stac922x_ch_mode_mixer[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Channel Mode",
+		.info = stac922x_ch_mode_info,
+		.get = stac922x_ch_mode_get,
+		.put = stac922x_ch_mode_put,
+	},
+	{ } /* end */
+};
+
 static int stac92xx_build_controls(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec = codec->spec;
 	int err;
+	int i;
 
 	err = snd_hda_add_new_ctls(codec, spec->mixer);
 	if (err < 0)
 		return err;
+
+	for (i = 0; i < spec->num_mixers; i++) {
+		err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
+		if (err < 0)
+			return err;
+	}
+
+	if (spec->surr_switch) {
+		err = snd_hda_add_new_ctls(codec, stac922x_ch_mode_mixer);
+		if (err < 0)
+			return err;
+	}
 	if (spec->multiout.dig_out_nid) {
 		err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
 		if (err < 0)
@@ -222,9 +282,9 @@
 	0x02a19020, 0x01a19021, 0x90100140, 0x01813122,
 };
 
-static unsigned int stac922x_pin_configs[14] = {
-	0x40000100, 0x40000100, 0x40000100, 0x01114010,
-	0x01813122, 0x40000100, 0x01447010, 0x01c47010,
+static unsigned int stac922x_pin_configs[10] = {
+	0x01014010, 0x01014011, 0x01014012, 0x0221401f,
+	0x01813122, 0x01014014, 0x01441030, 0x01c41030,
 	0x40000100, 0x40000100,
 };
 
@@ -255,170 +315,6 @@
 }
 #endif
 
-static int stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid, unsigned int value)
-{
-	unsigned int pin_ctl;
-
-	pin_ctl = snd_hda_codec_read(codec, nid, 0,
-				     AC_VERB_GET_PIN_WIDGET_CONTROL,
-				     0x00);
-	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-			    pin_ctl | value);
-
-	return 0;
-}
-
-static int stac92xx_set_vref(struct hda_codec *codec, hda_nid_t nid)
-{
-	unsigned int vref_caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP) >> AC_PINCAP_VREF_SHIFT;
-	unsigned int vref_ctl = AC_PINCTL_VREF_HIZ;
-
-	if (vref_caps & AC_PINCAP_VREF_100)
-		vref_ctl = AC_PINCTL_VREF_100;
-	else if (vref_caps & AC_PINCAP_VREF_80)
-		vref_ctl = AC_PINCTL_VREF_80;
-	else if (vref_caps & AC_PINCAP_VREF_50)
-		vref_ctl = AC_PINCTL_VREF_50;
-	else if (vref_caps & AC_PINCAP_VREF_GRD)
-		vref_ctl = AC_PINCTL_VREF_GRD;
-
-	stac92xx_set_pinctl(codec, nid, vref_ctl);
-	
-	return 0;
-}
-
-/*
- * retrieve the default device type from the default config value
- */
-#define get_defcfg_type(cfg) ((cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT)
-#define get_defcfg_location(cfg) ((cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT)
-
-static int stac92xx_config_pin(struct hda_codec *codec, hda_nid_t nid, unsigned int pin_cfg)
-{
-	struct sigmatel_spec *spec = codec->spec;
-	u32 location = get_defcfg_location(pin_cfg);
-	char *label;
-	const char *type = NULL;
-	int ainput = 0;
-
-	switch(get_defcfg_type(pin_cfg)) {
-		case AC_JACK_HP_OUT:
-			/* Enable HP amp */
-			stac92xx_set_pinctl(codec, nid, AC_PINCTL_HP_EN);
-			/* Fall through */
-		case AC_JACK_SPDIF_OUT:
-		case AC_JACK_LINE_OUT:
-		case AC_JACK_SPEAKER:
-			/* Enable output */
-			stac92xx_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
-			break;
-		case AC_JACK_SPDIF_IN:
-			stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN);
-			break;
-		case AC_JACK_MIC_IN:
-			if ((location & 0x0f) == AC_JACK_LOC_FRONT)
-				type = "Front Mic";
-			else
-				type = "Mic";
-			ainput = 1;
-			/* Set vref */
-			stac92xx_set_vref(codec, nid);
-			stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN);
-			break;
-		case AC_JACK_CD:
-			type = "CD";
-			ainput = 1;
-			stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN);
-			break;
-		case AC_JACK_LINE_IN:
-			if ((location & 0x0f) == AC_JACK_LOC_FRONT)
-				type = "Front Line";
-			else
-				type = "Line";
-			ainput = 1;
-			stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN);
-			break;
-		case AC_JACK_AUX:
-			if ((location & 0x0f) == AC_JACK_LOC_FRONT)
-				type = "Front Aux";
-			else
-				type = "Aux";
-			ainput = 1;
-			stac92xx_set_pinctl(codec, nid, AC_PINCTL_IN_EN);
-			break;
-	}
-
-	if (ainput) {
-		hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
-		int i, j, num_cons, index = -1;
-		if (!type)
-			type = "Input";
-		label = spec->input_labels[spec->input_mux.num_items];
-		strcpy(label, type);
-		spec->input_mux.items[spec->input_mux.num_items].label = label;
-		for (i=0; i<spec->num_muxes; i++) {
-			num_cons = snd_hda_get_connections(codec, spec->mux_nids[i], con_lst, HDA_MAX_NUM_INPUTS);
-			for (j=0; j<num_cons; j++)
-				if (con_lst[j] == nid) {
-					index = j;
-					break;
-				}
-			if (index >= 0)
-				break;
-		}
-		spec->input_mux.items[spec->input_mux.num_items].index = index;
-		spec->input_mux.num_items++;
-	}
-
-	return 0;
-}
-
-static int stac92xx_config_pins(struct hda_codec *codec)
-{
-	struct sigmatel_spec *spec = codec->spec;
-	int i;
-	unsigned int pin_cfg;
-
-	for (i=0; i < spec->num_pins; i++) {
-		/* Default to disabled */
-		snd_hda_codec_write(codec, spec->pin_nids[i], 0,
-				    AC_VERB_SET_PIN_WIDGET_CONTROL,
-				    0x00);
-
-		pin_cfg = snd_hda_codec_read(codec, spec->pin_nids[i], 0,
-					     AC_VERB_GET_CONFIG_DEFAULT,
-					     0x00);
-		if (((pin_cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT) == AC_JACK_PORT_NONE)
-			continue;	/* Move on */
-
-		stac92xx_config_pin(codec, spec->pin_nids[i], pin_cfg);
-	}
-
-	return 0;
-}
-
-static int stac92xx_init(struct hda_codec *codec)
-{
-	struct sigmatel_spec *spec = codec->spec;
-	int i;
-
-	for (i=0; i < spec->num_pstates; i++)
-		snd_hda_codec_write(codec, spec->pstate_nids[i], 0,
-				    AC_VERB_SET_POWER_STATE, 0x00);
-
-	mdelay(100);
-
-	snd_hda_sequence_write(codec, spec->init);
-
-#ifdef STAC_TEST
-	stac92xx_set_config_regs(codec);
-#endif
-
-	stac92xx_config_pins(codec);
-
-	return 0;
-}
-
 /*
  * Analog playback callbacks
  */
@@ -430,6 +326,56 @@
 	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream);
 }
 
+/*
+ * set up the i/o for analog out
+ * when the digital out is available, copy the front out to digital out, too.
+ */
+static int stac92xx_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_out *mout,
+				     unsigned int stream_tag,
+				     unsigned int format,
+				     snd_pcm_substream_t *substream)
+{
+	hda_nid_t *nids = mout->dac_nids;
+	int chs = substream->runtime->channels;
+	int i;
+
+	down(&codec->spdif_mutex);
+	if (mout->dig_out_nid && mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
+		if (chs == 2 &&
+		    snd_hda_is_supported_format(codec, mout->dig_out_nid, format) &&
+		    ! (codec->spdif_status & IEC958_AES0_NONAUDIO)) {
+			mout->dig_out_used = HDA_DIG_ANALOG_DUP;
+			/* setup digital receiver */
+			snd_hda_codec_setup_stream(codec, mout->dig_out_nid,
+						   stream_tag, 0, format);
+		} else {
+			mout->dig_out_used = 0;
+			snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 0, 0, 0);
+		}
+	}
+	up(&codec->spdif_mutex);
+
+	/* front */
+	snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, 0, format);
+	if (mout->hp_nid)
+		/* headphone out will just decode front left/right (stereo) */
+		snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format);
+	/* surrounds */
+	if (mout->max_channels > 2)
+		for (i = 1; i < mout->num_dacs; i++) {
+			if ((mout->max_channels == 6) && (i == 3))
+				break;
+			if (chs >= (i + 1) * 2) /* independent out */
+				snd_hda_codec_setup_stream(codec, nids[i], stream_tag, i * 2,
+						format);
+			else /* copy front */
+				snd_hda_codec_setup_stream(codec, nids[i], stream_tag, 0,
+						format);
+		}
+	return 0;
+}
+
+
 static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 					 struct hda_codec *codec,
 					 unsigned int stream_tag,
@@ -437,7 +383,7 @@
 					 snd_pcm_substream_t *substream)
 {
 	struct sigmatel_spec *spec = codec->spec;
-	return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
+	return stac92xx_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
 						format, substream);
 }
 
@@ -516,7 +462,7 @@
 static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
 	.substreams = 1,
 	.channels_min = 2,
-	.channels_max = 2,
+	.channels_max = 8,
 	.nid = 0x02, /* NID to query formats and rates */
 	.ops = {
 		.open = stac92xx_playback_pcm_open,
@@ -544,11 +490,9 @@
 	codec->num_pcms = 1;
 	codec->pcm_info = info;
 
-	info->name = "STAC92xx";
+	info->name = "STAC92xx Analog";
 	info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback;
-	info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->playback_nid;
 	info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture;
-	info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->capture_nid;
 
 	if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
 		codec->num_pcms++;
@@ -567,21 +511,413 @@
 	return 0;
 }
 
+enum {
+	STAC_CTL_WIDGET_VOL,
+	STAC_CTL_WIDGET_MUTE,
+};
+
+static snd_kcontrol_new_t stac92xx_control_templates[] = {
+	HDA_CODEC_VOLUME(NULL, 0, 0, 0),
+	HDA_CODEC_MUTE(NULL, 0, 0, 0),
+};
+
+/* add dynamic controls */
+static int stac92xx_add_control(struct sigmatel_spec *spec, int type, const char *name, unsigned long val)
+{
+	snd_kcontrol_new_t *knew;
+
+	if (spec->num_kctl_used >= spec->num_kctl_alloc) {
+		int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC;
+
+		knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); /* array + terminator */
+		if (! knew)
+			return -ENOMEM;
+		if (spec->kctl_alloc) {
+			memcpy(knew, spec->kctl_alloc, sizeof(*knew) * spec->num_kctl_alloc);
+			kfree(spec->kctl_alloc);
+		}
+		spec->kctl_alloc = knew;
+		spec->num_kctl_alloc = num;
+	}
+
+	knew = &spec->kctl_alloc[spec->num_kctl_used];
+	*knew = stac92xx_control_templates[type];
+	knew->name = kstrdup(name, GFP_KERNEL);
+	if (! knew->name)
+		return -ENOMEM;
+	knew->private_value = val;
+	spec->num_kctl_used++;
+	return 0;
+}
+
+/* fill in the dac_nids table from the parsed pin configuration */
+static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	hda_nid_t nid;
+	int i;
+
+	/* check the pins hardwired to audio widget */
+	for (i = 0; i < cfg->line_outs; i++) {
+		nid = cfg->line_out_pins[i];
+		spec->multiout.dac_nids[i] = snd_hda_codec_read(codec, nid, 0,
+					AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
+	}
+
+	spec->multiout.num_dacs = cfg->line_outs;
+
+	return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, const struct auto_pin_cfg *cfg)
+{
+	char name[32];
+	static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" };
+	hda_nid_t nid;
+	int i, err;
+
+	for (i = 0; i < cfg->line_outs; i++) {
+		if (! spec->multiout.dac_nids[i])
+			continue;
+
+		nid = spec->multiout.dac_nids[i];
+
+		if (i == 2) {
+			/* Center/LFE */
+			if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, "Center Playback Volume",
+					       HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0)
+				return err;
+			if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, "LFE Playback Volume",
+					       HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0)
+				return err;
+			if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, "Center Playback Switch",
+					       HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT))) < 0)
+				return err;
+			if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, "LFE Playback Switch",
+					       HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0)
+				return err;
+		} else {
+			sprintf(name, "%s Playback Volume", chname[i]);
+			if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
+					       HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
+				return err;
+			sprintf(name, "%s Playback Switch", chname[i]);
+			if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, name,
+					       HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
+				return err;
+		}
+	}
+
+	return 0;
+}
+
+/* add playback controls for HP output */
+static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, struct auto_pin_cfg *cfg)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	hda_nid_t pin = cfg->hp_pin;
+	hda_nid_t nid;
+	int i, err;
+	unsigned int wid_caps;
+
+	if (! pin)
+		return 0;
+
+	wid_caps = snd_hda_param_read(codec, pin, AC_PAR_AUDIO_WIDGET_CAP);
+	if (wid_caps & AC_WCAP_UNSOL_CAP)
+		/* Enable unsolicited responses on the HP widget */
+		snd_hda_codec_write(codec, pin, 0,
+				AC_VERB_SET_UNSOLICITED_ENABLE,
+				STAC_UNSOL_ENABLE);
+
+	nid = snd_hda_codec_read(codec, pin, 0, AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
+	for (i = 0; i < cfg->line_outs; i++) {
+		if (! spec->multiout.dac_nids[i])
+			continue;
+		if (spec->multiout.dac_nids[i] == nid)
+			return 0;
+	}
+
+	spec->multiout.hp_nid = nid;
+
+	/* control HP volume/switch on the output mixer amp */
+	if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, "Headphone Playback Volume",
+					HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
+		return err;
+	if ((err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, "Headphone Playback Switch",
+					HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
+		return err;
+
+	return 0;
+}
+
+/* create playback/capture controls for input pins */
+static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	static char *labels[AUTO_PIN_LAST] = {
+		"Mic", "Front Mic", "Line", "Front Line", "CD", "Aux"
+	};
+	struct hda_input_mux *imux = &spec->private_imux;
+	hda_nid_t con_lst[HDA_MAX_NUM_INPUTS];
+	int i, j, k;
+
+	for (i = 0; i < AUTO_PIN_LAST; i++) {
+		int index = -1;
+		if (cfg->input_pins[i]) {
+			imux->items[imux->num_items].label = labels[i];
+
+			for (j=0; j<spec->num_muxes; j++) {
+				int num_cons = snd_hda_get_connections(codec, spec->mux_nids[j], con_lst, HDA_MAX_NUM_INPUTS);
+				for (k=0; k<num_cons; k++)
+					if (con_lst[k] == cfg->input_pins[i]) {
+						index = k;
+					 	break;
+					}
+				if (index >= 0)
+					break;
+			}
+			imux->items[imux->num_items].index = index;
+			imux->num_items++;
+		}
+	}
+
+	return 0;
+}
+
+static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
+
+{
+	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
+}
+
+static void stac92xx_auto_init_multi_out(struct hda_codec *codec)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	int i;
+
+	for (i = 0; i < spec->autocfg.line_outs; i++) {
+		hda_nid_t nid = spec->autocfg.line_out_pins[i];
+		stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN);
+	}
+}
+
+static void stac92xx_auto_init_hp_out(struct hda_codec *codec)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	hda_nid_t pin;
+
+	pin = spec->autocfg.hp_pin;
+	if (pin) /* connect to front */
+		stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
+}
+
+static int stac922x_parse_auto_config(struct hda_codec *codec)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	int err;
+
+	if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg)) < 0)
+		return err;
+	if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
+		return err;
+	if (! spec->autocfg.line_outs && ! spec->autocfg.hp_pin)
+		return 0; /* can't find valid pin config */
+
+	if ((err = stac92xx_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
+	    (err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg)) < 0 ||
+	    (err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
+		return err;
+
+	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
+	if (spec->multiout.max_channels > 2) {
+		spec->surr_switch = 1;
+		spec->cur_ch_mode = 1;
+		spec->num_ch_modes = 2;
+		if (spec->multiout.max_channels == 8) {
+			spec->cur_ch_mode++;
+			spec->num_ch_modes++;
+		}
+	}
+
+	if (spec->autocfg.dig_out_pin) {
+		spec->multiout.dig_out_nid = 0x08;
+		stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_out_pin, AC_PINCTL_OUT_EN);
+	}
+	if (spec->autocfg.dig_in_pin) {
+		spec->dig_in_nid = 0x09;
+		stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_in_pin, AC_PINCTL_IN_EN);
+	}
+
+	if (spec->kctl_alloc)
+		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+
+	spec->input_mux = &spec->private_imux;
+
+	return 1;
+}
+
+static int stac9200_parse_auto_config(struct hda_codec *codec)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	int err;
+
+	if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg)) < 0)
+		return err;
+
+	if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
+		return err;
+
+	if (spec->autocfg.dig_out_pin) {
+		spec->multiout.dig_out_nid = 0x05;
+		stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_out_pin, AC_PINCTL_OUT_EN);
+	}
+	if (spec->autocfg.dig_in_pin) {
+		spec->dig_in_nid = 0x04;
+		stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_in_pin, AC_PINCTL_IN_EN);
+	}
+
+	if (spec->kctl_alloc)
+		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+
+	spec->input_mux = &spec->private_imux;
+
+	return 1;
+}
+
+static int stac92xx_init_pstate(struct hda_codec *codec)
+{
+       hda_nid_t nid, nid_start;
+       int nodes;
+
+	snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_POWER_STATE, 0x00);
+
+       nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid_start);
+       for (nid = nid_start; nid < nodes + nid_start; nid++) {
+               unsigned int wid_caps = snd_hda_param_read(codec, nid,
+                                                  AC_PAR_AUDIO_WIDGET_CAP);
+		if (wid_caps & AC_WCAP_POWER)
+			snd_hda_codec_write(codec, nid, 0,
+                                    AC_VERB_SET_POWER_STATE, 0x00);
+	}
+
+	mdelay(100);
+
+	return 0;
+}
+
+static int stac92xx_init(struct hda_codec *codec)
+{
+	struct sigmatel_spec *spec = codec->spec;
+
+	stac92xx_init_pstate(codec);
+
+	snd_hda_sequence_write(codec, spec->init);
+
+	stac92xx_auto_init_multi_out(codec);
+	stac92xx_auto_init_hp_out(codec);
+
+	return 0;
+}
+
 static void stac92xx_free(struct hda_codec *codec)
 {
-	kfree(codec->spec);
+	struct sigmatel_spec *spec = codec->spec;
+	int i;
+
+	if (! spec)
+		return;
+
+	if (spec->kctl_alloc) {
+		for (i = 0; i < spec->num_kctl_used; i++)
+			kfree(spec->kctl_alloc[i].name);
+		kfree(spec->kctl_alloc);
+	}
+
+	kfree(spec);
 }
 
+static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
+				unsigned int flag)
+{
+	unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
+			0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
+	snd_hda_codec_write(codec, nid, 0,
+			AC_VERB_SET_PIN_WIDGET_CONTROL,
+			pin_ctl | flag);
+}
+
+static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
+				  unsigned int flag)
+{
+	unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
+			0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
+	snd_hda_codec_write(codec, nid, 0,
+			AC_VERB_SET_PIN_WIDGET_CONTROL,
+			pin_ctl & ~flag);
+}
+
+static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+	int i, presence;
+
+	if ((res >> 26) != STAC_HP_EVENT)
+		return;
+
+	presence = snd_hda_codec_read(codec, cfg->hp_pin, 0,
+			AC_VERB_GET_PIN_SENSE, 0x00) >> 31;
+
+	if (presence) {
+		/* disable lineouts, enable hp */
+		for (i = 0; i < cfg->line_outs; i++)
+			stac92xx_reset_pinctl(codec, cfg->line_out_pins[i],
+						AC_PINCTL_OUT_EN);
+		stac92xx_set_pinctl(codec, cfg->hp_pin, AC_PINCTL_OUT_EN);
+	} else {
+		/* enable lineouts, disable hp */
+		for (i = 0; i < cfg->line_outs; i++)
+			stac92xx_set_pinctl(codec, cfg->line_out_pins[i],
+						AC_PINCTL_OUT_EN);
+		stac92xx_reset_pinctl(codec, cfg->hp_pin, AC_PINCTL_OUT_EN);
+	}
+} 
+
+#ifdef CONFIG_PM
+static int stac92xx_resume(struct hda_codec *codec)
+{
+	struct sigmatel_spec *spec = codec->spec;
+	int i;
+
+	stac92xx_init(codec);
+	for (i = 0; i < spec->num_mixers; i++)
+		snd_hda_resume_ctls(codec, spec->mixers[i]);
+	if (spec->multiout.dig_out_nid)
+		snd_hda_resume_spdif_out(codec);
+	if (spec->dig_in_nid)
+		snd_hda_resume_spdif_in(codec);
+
+	return 0;
+}
+#endif
+
 static struct hda_codec_ops stac92xx_patch_ops = {
 	.build_controls = stac92xx_build_controls,
 	.build_pcms = stac92xx_build_pcms,
 	.init = stac92xx_init,
 	.free = stac92xx_free,
+	.unsol_event = stac92xx_unsol_event,
+#ifdef CONFIG_PM
+	.resume = stac92xx_resume,
+#endif
 };
 
 static int patch_stac9200(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec;
+	int err;
 
 	spec  = kcalloc(1, sizeof(*spec), GFP_KERNEL);
 	if (spec == NULL)
@@ -589,26 +925,27 @@
 
 	codec->spec = spec;
 
+#ifdef STAC_TEST
+	spec->pin_nids = stac9200_pin_nids;
+	spec->num_pins = 8;
+	spec->pin_configs = stac9200_pin_configs;
+	stac92xx_set_config_regs(codec);
+#endif
 	spec->multiout.max_channels = 2;
 	spec->multiout.num_dacs = 1;
 	spec->multiout.dac_nids = stac9200_dac_nids;
-	spec->multiout.dig_out_nid = 0x05;
-	spec->dig_in_nid = 0x04;
 	spec->adc_nids = stac9200_adc_nids;
 	spec->mux_nids = stac9200_mux_nids;
 	spec->num_muxes = 1;
-	spec->input_mux.num_items = 0;
-	spec->pstate_nids = stac9200_pstate_nids;
-	spec->num_pstates = 3;
-	spec->pin_nids = stac9200_pin_nids;
-#ifdef STAC_TEST
-	spec->pin_configs = stac9200_pin_configs;
-#endif
-	spec->num_pins = 8;
-	spec->init = stac9200_ch2_init;
+
+	spec->init = stac9200_core_init;
 	spec->mixer = stac9200_mixer;
-	spec->playback_nid = 0x02;
-	spec->capture_nid = 0x03;
+
+	err = stac9200_parse_auto_config(codec);
+	if (err < 0) {
+		stac92xx_free(codec);
+		return err;
+	}
 
 	codec->patch_ops = stac92xx_patch_ops;
 
@@ -618,6 +955,7 @@
 static int patch_stac922x(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec;
+	int err;
 
 	spec  = kcalloc(1, sizeof(*spec), GFP_KERNEL);
 	if (spec == NULL)
@@ -625,26 +963,26 @@
 
 	codec->spec = spec;
 
-	spec->multiout.max_channels = 2;
-	spec->multiout.num_dacs = 4;
-	spec->multiout.dac_nids = stac922x_dac_nids;
-	spec->multiout.dig_out_nid = 0x08;
-	spec->dig_in_nid = 0x09;
+#ifdef STAC_TEST
+	spec->num_pins = 10;
+	spec->pin_nids = stac922x_pin_nids;
+	spec->pin_configs = stac922x_pin_configs;
+	stac92xx_set_config_regs(codec);
+#endif
 	spec->adc_nids = stac922x_adc_nids;
 	spec->mux_nids = stac922x_mux_nids;
 	spec->num_muxes = 2;
-	spec->input_mux.num_items = 0;
-	spec->pstate_nids = stac922x_pstate_nids;
-	spec->num_pstates = 8;
-	spec->pin_nids = stac922x_pin_nids;
-#ifdef STAC_TEST
-	spec->pin_configs = stac922x_pin_configs;
-#endif
-	spec->num_pins = 10;
-	spec->init = stac922x_ch2_init;
+
+	spec->init = stac922x_core_init;
 	spec->mixer = stac922x_mixer;
-	spec->playback_nid = 0x02;
-	spec->capture_nid = 0x06;
+
+	spec->multiout.dac_nids = spec->dac_nids;
+
+	err = stac922x_parse_auto_config(codec);
+	if (err < 0) {
+		stac92xx_free(codec);
+		return err;
+	}
 
 	codec->patch_ops = stac92xx_patch_ops;
 
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index 28ac005..d7af3e4 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -424,6 +424,7 @@
 	unsigned xbox: 1;		/* workaround for Xbox AC'97 detection */
 
 	int spdif_idx;	/* SPDIF BAR index; *_SPBAR or -1 if use PCMOUT */
+	unsigned int sdm_saved;	/* SDM reg value */
 
 	ac97_bus_t *ac97_bus;
 	ac97_t *ac97[3];
@@ -2373,6 +2374,9 @@
 	for (i = 0; i < 3; i++)
 		if (chip->ac97[i])
 			snd_ac97_suspend(chip->ac97[i]);
+	if (chip->device_type == DEVICE_INTEL_ICH4)
+		chip->sdm_saved = igetbyte(chip, ICHREG(SDM));
+
 	if (chip->irq >= 0)
 		free_irq(chip->irq, (void *)chip);
 	pci_disable_device(chip->pci);
@@ -2390,6 +2394,16 @@
 	synchronize_irq(chip->irq);
 	snd_intel8x0_chip_init(chip, 1);
 
+	/* re-initialize mixer stuff */
+	if (chip->device_type == DEVICE_INTEL_ICH4) {
+		/* enable separate SDINs for ICH4 */
+		iputbyte(chip, ICHREG(SDM), chip->sdm_saved);
+		/* use slot 10/11 for SPDIF */
+		iputdword(chip, ICHREG(GLOB_CNT),
+			  (igetdword(chip, ICHREG(GLOB_CNT)) & ~ICH_PCM_SPDIF_MASK) |
+			  ICH_PCM_SPDIF_1011);
+	}
+
 	/* refill nocache */
 	if (chip->fix_nocache)
 		fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 1);
@@ -2455,8 +2469,7 @@
 	}
 	do_gettimeofday(&start_time);
 	spin_unlock_irq(&chip->reg_lock);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(HZ / 20);
+	msleep(50);
 	spin_lock_irq(&chip->reg_lock);
 	/* check the position */
 	pos = ichdev->fragsize1;
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index 52c5859..39b5e7d 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -1050,11 +1050,6 @@
  * lowlevel functions
  */
 
-#define big_mdelay(msec) do {\
-	set_current_state(TASK_UNINTERRUPTIBLE);\
-	schedule_timeout(((msec) * HZ) / 1000);\
-} while (0)
-	
 static inline void snd_m3_outw(m3_t *chip, u16 value, unsigned long reg)
 {
 	outw(value, chip->iobase + reg);
@@ -1096,7 +1091,7 @@
 static void snd_m3_assp_halt(m3_t *chip)
 {
 	chip->reset_state = snd_m3_inb(chip, DSP_PORT_CONTROL_REG_B) & ~REGB_STOP_CLOCK;
-	big_mdelay(10);
+	msleep(10);
 	snd_m3_outb(chip, chip->reset_state & ~REGB_ENABLE_RESET, DSP_PORT_CONTROL_REG_B);
 }
 
@@ -2108,9 +2103,9 @@
 	 */
 	tmp = inw(io + RING_BUS_CTRL_A);
 	outw(RAC_SDFS_ENABLE|LAC_SDFS_ENABLE, io + RING_BUS_CTRL_A);
-	big_mdelay(20);
+	msleep(20);
 	outw(tmp, io + RING_BUS_CTRL_A);
-	big_mdelay(50);
+	msleep(50);
 #endif
 }
 
@@ -2525,9 +2520,13 @@
 snd_m3_enable_ints(m3_t *chip)
 {
 	unsigned long io = chip->iobase;
+	unsigned short val;
 
 	/* TODO: MPU401 not supported yet */
-	outw(ASSP_INT_ENABLE | HV_INT_ENABLE /*| MPU401_INT_ENABLE*/, io + HOST_INT_CTRL);
+	val = ASSP_INT_ENABLE /*| MPU401_INT_ENABLE*/;
+	if (chip->hv_quirk && (chip->hv_quirk->config & HV_CTRL_ENABLE))
+		val |= HV_INT_ENABLE;
+	outw(val, io + HOST_INT_CTRL);
 	outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE,
 	     io + ASSP_CONTROL_C);
 }
@@ -2589,7 +2588,7 @@
 	snd_pcm_suspend_all(chip->pcm);
 	snd_ac97_suspend(chip->ac97);
 
-	big_mdelay(10); /* give the assp a chance to idle.. */
+	msleep(10); /* give the assp a chance to idle.. */
 
 	snd_m3_assp_halt(chip);
 
@@ -2697,6 +2696,8 @@
 	}
 
 	spin_lock_init(&chip->reg_lock);
+	spin_lock_init(&chip->ac97_lock);
+
 	switch (pci->device) {
 	case PCI_DEVICE_ID_ESS_ALLEGRO:
 	case PCI_DEVICE_ID_ESS_ALLEGRO_1:
@@ -2765,6 +2766,8 @@
 	snd_m3_assp_init(chip);
 	snd_m3_amp_enable(chip, 1);
 
+	tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip);
+
 	if (request_irq(pci->irq, snd_m3_interrupt, SA_INTERRUPT|SA_SHIRQ,
 			card->driver, (void *)chip)) {
 		snd_printk("unable to grab IRQ %d\n", pci->irq);
@@ -2786,9 +2789,6 @@
 		return err;
 	}
 
-	spin_lock_init(&chip->ac97_lock);
-	tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip);
-
 	if ((err = snd_m3_mixer(chip)) < 0)
 		return err;
 
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
index 082c0d0..6c868d9 100644
--- a/sound/pci/mixart/mixart.c
+++ b/sound/pci/mixart/mixart.c
@@ -445,9 +445,9 @@
 
 static int mixart_sync_nonblock_events(mixart_mgr_t *mgr)
 {
-	int timeout = HZ;
+	unsigned long timeout = jiffies + HZ;
 	while (atomic_read(&mgr->msg_processed) > 0) {
-		if (! timeout--) {
+		if (time_after(jiffies, timeout)) {
 			snd_printk(KERN_ERR "mixart: cannot process nonblock events!\n");
 			return -EBUSY;
 		}
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index a673cc4..796621d 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -445,6 +445,7 @@
 	u32                   control2_register;     /* cached value */
 	u32                   creg_spdif;
 	u32                   creg_spdif_stream;
+	int                   clock_source_locked;
 	char                 *card_name;	     /* digiface/multiface */
 	HDSP_IO_Type          io_type;               /* ditto, but for code use */
         unsigned short        firmware_rev;
@@ -678,8 +679,7 @@
 		}
 
 		if ((1000 / HZ) < 3000) {
-			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout((3000 * HZ + 999) / 1000);
+			ssleep(3);
 		} else {
 			mdelay(3000);
 		}
@@ -2095,6 +2095,34 @@
 	return change;
 }
 
+static int snd_hdsp_info_clock_source_lock(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_hdsp_get_clock_source_lock(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	hdsp_t *hdsp = snd_kcontrol_chip(kcontrol);
+	
+	ucontrol->value.integer.value[0] = hdsp->clock_source_locked;
+	return 0;
+}
+
+static int snd_hdsp_put_clock_source_lock(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	hdsp_t *hdsp = snd_kcontrol_chip(kcontrol);
+	int change;
+
+	change = (int)ucontrol->value.integer.value[0] != hdsp->clock_source_locked;
+	if (change)
+		hdsp->clock_source_locked = ucontrol->value.integer.value[0];
+	return change;
+}
+
 #define HDSP_DA_GAIN(xname, xindex) \
 { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \
   .name = xname, \
@@ -3117,6 +3145,15 @@
 HDSP_SPDIF_NON_AUDIO("IEC958 Non-audio Bit", 0),
 /* 'Sample Clock Source' complies with the alsa control naming scheme */ 
 HDSP_CLOCK_SOURCE("Sample Clock Source", 0),
+{
+	/* FIXME: should be PCM or MIXER? */
+	/* .iface = SNDRV_CTL_ELEM_IFACE_PCM, */
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Sample Clock Source Locking",
+	.info = snd_hdsp_info_clock_source_lock,
+	.get = snd_hdsp_get_clock_source_lock,
+	.put = snd_hdsp_put_clock_source_lock,
+},
 HDSP_SYSTEM_CLOCK_MODE("System Clock Mode", 0),
 HDSP_PREF_SYNC_REF("Preferred Sync Reference", 0),
 HDSP_AUTOSYNC_REF("AutoSync Reference", 0),
@@ -3349,6 +3386,7 @@
 	snd_iprintf (buffer, "System Clock Mode: %s\n", system_clock_mode);
 
 	snd_iprintf (buffer, "System Clock Frequency: %d\n", hdsp->system_sample_rate);
+	snd_iprintf (buffer, "System Clock Locked: %s\n", hdsp->clock_source_locked ? "Yes" : "No");
 		
 	snd_iprintf(buffer, "\n");
 
@@ -3853,13 +3891,14 @@
 	 */
 
 	spin_lock_irq(&hdsp->lock);
-	if ((err = hdsp_set_rate(hdsp, params_rate(params), 0)) < 0) {
-		spin_unlock_irq(&hdsp->lock);
-		_snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE);
-		return err;
-	} else {
-		spin_unlock_irq(&hdsp->lock);
+	if (! hdsp->clock_source_locked) {
+		if ((err = hdsp_set_rate(hdsp, params_rate(params), 0)) < 0) {
+			spin_unlock_irq(&hdsp->lock);
+			_snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE);
+			return err;
+		}
 	}
+	spin_unlock_irq(&hdsp->lock);
 
 	if ((err = hdsp_set_interrupt_interval(hdsp, params_period_size(params))) < 0) {
 		_snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
@@ -4284,13 +4323,17 @@
 
 	snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
 	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hdsp_hw_constraints_period_sizes);
-	if (hdsp->io_type == H9632) {
-		runtime->hw.channels_min = hdsp->qs_out_channels;
-		runtime->hw.channels_max = hdsp->ss_out_channels;
+	if (hdsp->clock_source_locked) {
+		runtime->hw.rate_min = runtime->hw.rate_max = hdsp->system_sample_rate;
+	} else if (hdsp->io_type == H9632) {
 		runtime->hw.rate_max = 192000;
 		runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
 		snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hdsp_hw_constraints_9632_sample_rates);
 	}
+	if (hdsp->io_type == H9632) {
+		runtime->hw.channels_min = hdsp->qs_out_channels;
+		runtime->hw.channels_max = hdsp->ss_out_channels;
+	}	
 	
 	snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
 			     snd_hdsp_hw_rule_out_channels, hdsp,
@@ -5036,8 +5079,7 @@
 	if (!is_9652 && !is_9632) {
 		/* we wait 2 seconds to let freshly inserted cardbus cards do their hardware init */
  		if ((1000 / HZ) < 2000) {
-			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout((2000 * HZ + 999) / 1000);
+			ssleep(2);
 		} else {
 			mdelay(2000);
 		}
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
index a09b0fb..29d89bfb 100644
--- a/sound/pci/trident/trident_main.c
+++ b/sound/pci/trident/trident_main.c
@@ -472,6 +472,7 @@
 		break;
 	default:
 		snd_BUG();
+		return;
 	}
 
 	outb(voice->number, TRID_REG(trident, T4D_LFO_GC_CIR));
@@ -3152,8 +3153,7 @@
 	switch (mode) {
 		case GAMEPORT_MODE_COOKED:
 			outb(GAMEPORT_MODE_ADC, TRID_REG(chip, GAMEPORT_GCR));
-			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout(1 + 20 * HZ / 1000); /* 20msec */
+			msleep(20);
 			return 0;
 		case GAMEPORT_MODE_RAW:
 			outb(0, TRID_REG(chip, GAMEPORT_GCR));
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index 42c48f0..4889600 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -547,8 +547,7 @@
 	int err;
 	err = snd_via82xx_codec_ready(chip, ac97->num);
 	/* here we need to wait fairly for long time.. */
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(HZ/2);
+	msleep(500);
 }
 
 static void snd_via82xx_codec_write(ac97_t *ac97,
@@ -1847,7 +1846,7 @@
 static int snd_via82xx_chip_init(via82xx_t *chip)
 {
 	unsigned int val;
-	int max_count;
+	unsigned long end_time;
 	unsigned char pval;
 
 #if 0 /* broken on K7M? */
@@ -1889,14 +1888,14 @@
 	}
 
 	/* wait until codec ready */
-	max_count = ((3 * HZ) / 4) + 1;
+	end_time = jiffies + msecs_to_jiffies(750);
 	do {
 		pci_read_config_byte(chip->pci, VIA_ACLINK_STAT, &pval);
 		if (pval & VIA_ACLINK_C00_READY) /* primary codec ready */
 			break;
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout(1);
-	} while (--max_count > 0);
+	} while (time_before(jiffies, end_time));
 
 	if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY)
 		snd_printk("AC'97 codec is not ready [0x%x]\n", val);
@@ -1905,7 +1904,7 @@
 	snd_via82xx_codec_xwrite(chip, VIA_REG_AC97_READ |
 				 VIA_REG_AC97_SECONDARY_VALID |
 				 (VIA_REG_AC97_CODEC_ID_SECONDARY << VIA_REG_AC97_CODEC_ID_SHIFT));
-	max_count = ((3 * HZ) / 4) + 1;
+	end_time = jiffies + msecs_to_jiffies(750);
 	snd_via82xx_codec_xwrite(chip, VIA_REG_AC97_READ |
 				 VIA_REG_AC97_SECONDARY_VALID |
 				 (VIA_REG_AC97_CODEC_ID_SECONDARY << VIA_REG_AC97_CODEC_ID_SHIFT));
@@ -1916,7 +1915,7 @@
 		}
 		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(1);
-	} while (--max_count > 0);
+	} while (time_before(jiffies, end_time));
 	/* This is ok, the most of motherboards have only one codec */
 
       __ac97_ok2:
@@ -2178,7 +2177,7 @@
 		{ .subvendor = 0x147b, .subdevice = 0x1413, .action = VIA_DXS_ENABLE }, /* ABIT KV8 Pro */
 		{ .subvendor = 0x147b, .subdevice = 0x1415, .action = VIA_DXS_NO_VRA }, /* Abit AV8 */
 		{ .subvendor = 0x14ff, .subdevice = 0x0403, .action = VIA_DXS_ENABLE }, /* Twinhead mobo */
-		{ .subvendor = 0x14ff, .subdevice = 0x0408, .action = VIA_DXS_NO_VRA }, /* Twinhead mobo */
+		{ .subvendor = 0x14ff, .subdevice = 0x0408, .action = VIA_DXS_SRC }, /* Twinhead laptop */
 		{ .subvendor = 0x1584, .subdevice = 0x8120, .action = VIA_DXS_ENABLE }, /* Gericom/Targa/Vobis/Uniwill laptop */
 		{ .subvendor = 0x1584, .subdevice = 0x8123, .action = VIA_DXS_NO_VRA }, /* Uniwill (Targa Visionary XP-210) */
 		{ .subvendor = 0x161f, .subdevice = 0x202b, .action = VIA_DXS_NO_VRA }, /* Amira Note book */
@@ -2187,6 +2186,7 @@
 		{ .subvendor = 0x1695, .subdevice = 0x3005, .action = VIA_DXS_ENABLE }, /* EPoX EP-8K9A */
 		{ .subvendor = 0x1849, .subdevice = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */
 		{ .subvendor = 0x1919, .subdevice = 0x200a, .action = VIA_DXS_NO_VRA }, /* Soltek SL-K8Tpro-939 */
+		{ .subvendor = 0x4005, .subdevice = 0x4710, .action = VIA_DXS_SRC },	/* MSI K7T266 Pro2 (MS-6380 V2.0) BIOS 3.7 */
 		{ } /* terminator */
 	};
 	struct dxs_whitelist *w;
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c
index 5896d28..4a9779c 100644
--- a/sound/pci/via82xx_modem.c
+++ b/sound/pci/via82xx_modem.c
@@ -408,8 +408,7 @@
 	int err;
 	err = snd_via82xx_codec_ready(chip, ac97->num);
 	/* here we need to wait fairly for long time.. */
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(HZ/2);
+	msleep(500);
 }
 
 static void snd_via82xx_codec_write(ac97_t *ac97,
@@ -923,7 +922,7 @@
 static int snd_via82xx_chip_init(via82xx_t *chip)
 {
 	unsigned int val;
-	int max_count;
+	unsigned long end_time;
 	unsigned char pval;
 
 	pci_read_config_byte(chip->pci, VIA_MC97_CTRL, &pval);
@@ -962,14 +961,14 @@
 	}
 
 	/* wait until codec ready */
-	max_count = ((3 * HZ) / 4) + 1;
+	end_time = jiffies + msecs_to_jiffies(750);
 	do {
 		pci_read_config_byte(chip->pci, VIA_ACLINK_STAT, &pval);
 		if (pval & VIA_ACLINK_C00_READY) /* primary codec ready */
 			break;
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout(1);
-	} while (--max_count > 0);
+	} while (time_before(jiffies, end_time));
 
 	if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY)
 		snd_printk("AC'97 codec is not ready [0x%x]\n", val);
@@ -977,7 +976,7 @@
 	snd_via82xx_codec_xwrite(chip, VIA_REG_AC97_READ |
 				 VIA_REG_AC97_SECONDARY_VALID |
 				 (VIA_REG_AC97_CODEC_ID_SECONDARY << VIA_REG_AC97_CODEC_ID_SHIFT));
-	max_count = ((3 * HZ) / 4) + 1;
+	end_time = jiffies + msecs_to_jiffies(750);
 	snd_via82xx_codec_xwrite(chip, VIA_REG_AC97_READ |
 				 VIA_REG_AC97_SECONDARY_VALID |
 				 (VIA_REG_AC97_CODEC_ID_SECONDARY << VIA_REG_AC97_CODEC_ID_SHIFT));
@@ -988,7 +987,7 @@
 		}
 		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(1);
-	} while (--max_count > 0);
+	} while (time_before(jiffies, end_time));
 	/* This is ok, the most of motherboards have only one codec */
 
       __ac97_ok2:
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
index 2ae7961..d54f88a 100644
--- a/sound/pci/ymfpci/ymfpci_main.c
+++ b/sound/pci/ymfpci/ymfpci_main.c
@@ -84,16 +84,16 @@
 
 static int snd_ymfpci_codec_ready(ymfpci_t *chip, int secondary)
 {
-	signed long end_time;
+	unsigned long end_time;
 	u32 reg = secondary ? YDSXGR_SECSTATUSADR : YDSXGR_PRISTATUSADR;
 	
-	end_time = (jiffies + ((3 * HZ) / 4)) + 1;
+	end_time = jiffies + msecs_to_jiffies(750);
 	do {
 		if ((snd_ymfpci_readw(chip, reg) & 0x8000) == 0)
 			return 0;
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout(1);
-	} while (end_time - (signed long)jiffies >= 0);
+	} while (time_before(jiffies, end_time));
 	snd_printk("codec_ready: codec %i is not ready [0x%x]\n", secondary, snd_ymfpci_readw(chip, reg));
 	return -EBUSY;
 }
diff --git a/sound/pcmcia/Kconfig b/sound/pcmcia/Kconfig
index 3611e29..5d1b0b7 100644
--- a/sound/pcmcia/Kconfig
+++ b/sound/pcmcia/Kconfig
@@ -8,23 +8,12 @@
 	depends on SND && PCMCIA && ISA
 	select SND_VX_LIB
 	help
-	  Say Y here to include support for Digigram VXpocket
-	  soundcards.
+	  Say Y here to include support for Digigram VXpocket and
+	  VXpocket 440 soundcards.
 
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-vxpocket.
 
-config SND_VXP440
-	tristate "Digigram VXpocket 440"
-	depends on SND && PCMCIA && ISA
-	select SND_VX_LIB
-	help
-	  Say Y here to include support for Digigram VXpocket 440
-	  soundcards.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called snd-vxp440.
-
 config SND_PDAUDIOCF
 	tristate "Sound Core PDAudioCF"
 	depends on SND && PCMCIA && ISA
diff --git a/sound/pcmcia/vx/Makefile b/sound/pcmcia/vx/Makefile
index f35dfa1..54971f0 100644
--- a/sound/pcmcia/vx/Makefile
+++ b/sound/pcmcia/vx/Makefile
@@ -3,9 +3,6 @@
 # Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
 #
 
-snd-vx-cs-objs := vx_entry.o vxp_ops.o vxp_mixer.o
-snd-vxpocket-objs := vxpocket.o
-snd-vxp440-objs := vxp440.o
+snd-vxpocket-objs := vxpocket.o vxp_ops.o vxp_mixer.o
 
-obj-$(CONFIG_SND_VXPOCKET) += snd-vxpocket.o snd-vx-cs.o
-obj-$(CONFIG_SND_VXP440) += snd-vxp440.o snd-vx-cs.o
+obj-$(CONFIG_SND_VXPOCKET) += snd-vxpocket.o
diff --git a/sound/pcmcia/vx/vx_entry.c b/sound/pcmcia/vx/vx_entry.c
deleted file mode 100644
index df7a39b..0000000
--- a/sound/pcmcia/vx/vx_entry.c
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- * Driver for Digigram VXpocket soundcards
- *
- * PCMCIA entry part
- *
- * Copyright (c) 2002 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
- */
-
-#include <sound/driver.h>
-#include <sound/core.h>
-#include "vxpocket.h"
-#include <pcmcia/ciscode.h>
-#include <pcmcia/cisreg.h>
-
-
-MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
-MODULE_DESCRIPTION("Common routines for Digigram PCMCIA VX drivers");
-MODULE_LICENSE("GPL");
-
-/*
- * prototypes
- */
-static void vxpocket_config(dev_link_t *link);
-
-
-static void vxpocket_release(dev_link_t *link)
-{
-	if (link->state & DEV_CONFIG) {
-		/* release cs resources */
-		pcmcia_release_configuration(link->handle);
-		pcmcia_release_io(link->handle, &link->io);
-		pcmcia_release_irq(link->handle, &link->irq);
-		link->state &= ~DEV_CONFIG;
-	}
-}
-
-/*
- * destructor
- */
-static int snd_vxpocket_free(vx_core_t *chip)
-{
-	struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip;
-	struct snd_vxp_entry *hw;
-	dev_link_t *link = &vxp->link;
-
-	vxpocket_release(link);
-
-	/* Break the link with Card Services */
-	if (link->handle)
-		pcmcia_deregister_client(link->handle);
-
-	hw = vxp->hw_entry;
-	if (hw)
-		hw->card_list[vxp->index] = NULL;
-	chip->card = NULL;
-	kfree(chip->dev);
-
-	snd_vx_free_firmware(chip);
-	kfree(chip);
-	return 0;
-}
-
-static int snd_vxpocket_dev_free(snd_device_t *device)
-{
-	vx_core_t *chip = device->device_data;
-	return snd_vxpocket_free(chip);
-}
-
-/*
- * snd_vxpocket_attach - attach callback for cs
- * @hw: the hardware information
- */
-dev_link_t *snd_vxpocket_attach(struct snd_vxp_entry *hw)
-{
-	client_reg_t client_reg;	/* Register with cardmgr */
-	dev_link_t *link;		/* Info for cardmgr */
-	int i, ret;
-	vx_core_t *chip;
-	struct snd_vxpocket *vxp;
-	snd_card_t *card;
-	static snd_device_ops_t ops = {
-		.dev_free =	snd_vxpocket_dev_free,
-	};
-
-	snd_printdd(KERN_DEBUG "vxpocket_attach called\n");
-	/* find an empty slot from the card list */
-	for (i = 0; i < SNDRV_CARDS; i++) {
-		if (! hw->card_list[i])
-			break;
-	}
-	if (i >= SNDRV_CARDS) {
-		snd_printk(KERN_ERR "vxpocket: too many cards found\n");
-		return NULL;
-	}
-	if (! hw->enable_table[i])
-		return NULL; /* disabled explicitly */
-
-	/* ok, create a card instance */
-	card = snd_card_new(hw->index_table[i], hw->id_table[i], THIS_MODULE, 0);
-	if (card == NULL) {
-		snd_printk(KERN_ERR "vxpocket: cannot create a card instance\n");
-		return NULL;
-	}
-
-	chip = snd_vx_create(card, hw->hardware, hw->ops,
-			     sizeof(struct snd_vxpocket) - sizeof(vx_core_t));
-	if (! chip)
-		return NULL;
-
-#ifdef SND_VX_FW_LOADER
-	/* fake a device here since pcmcia doesn't give a valid device... */
-	chip->dev = kcalloc(1, sizeof(*chip->dev), GFP_KERNEL);
-	if (! chip->dev) {
-		snd_printk(KERN_ERR "vxp: can't malloc chip->dev\n");
-		kfree(chip);
-		snd_card_free(card);
-		return NULL;
-	}
-	device_initialize(chip->dev);
-	sprintf(chip->dev->bus_id, "vxpocket%d", i);
-#endif
-
-	if (snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops) < 0) {
-		kfree(chip);
-		snd_card_free(card);
-		return NULL;
-	}
-
-	vxp = (struct snd_vxpocket *)chip;
-	vxp->index = i;
-	vxp->hw_entry = hw;
-	chip->ibl.size = hw->ibl[i];
-	hw->card_list[i] = chip;
-
-	link = &vxp->link;
-	link->priv = chip;
-
-	link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
-	link->io.NumPorts1 = 16;
-
-	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
-	// link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
-
-	link->irq.IRQInfo1 = IRQ_LEVEL_ID;
-	link->irq.Handler = &snd_vx_irq_handler;
-	link->irq.Instance = chip;
-
-	link->conf.Attributes = CONF_ENABLE_IRQ;
-	link->conf.Vcc = 50;
-	link->conf.IntType = INT_MEMORY_AND_IO;
-	link->conf.ConfigIndex = 1;
-	link->conf.Present = PRESENT_OPTION;
-
-	/* Register with Card Services */
-	memset(&client_reg, 0, sizeof(client_reg));
-	client_reg.dev_info = hw->dev_info;
-	client_reg.Version = 0x0210;
-	client_reg.event_callback_args.client_data = link;
-
-	ret = pcmcia_register_client(&link->handle, &client_reg);
-	if (ret != CS_SUCCESS) {
-		cs_error(link->handle, RegisterClient, ret);
-		snd_card_free(card);
-		return NULL;
-	}
-
-	/* Chain drivers */
-	link->next = hw->dev_list;
-	hw->dev_list = link;
-
-	/* snd_card_set_pm_callback(card, snd_vxpocket_suspend, snd_vxpocket_resume, chip); */
-
-	return link;
-}
-
-
-/**
- * snd_vxpocket_assign_resources - initialize the hardware and card instance.
- * @port: i/o port for the card
- * @irq: irq number for the card
- *
- * this function assigns the specified port and irq, boot the card,
- * create pcm and control instances, and initialize the rest hardware.
- *
- * returns 0 if successful, or a negative error code.
- */
-static int snd_vxpocket_assign_resources(vx_core_t *chip, int port, int irq)
-{
-	int err;
-	snd_card_t *card = chip->card;
-	struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip;
-
-	snd_printdd(KERN_DEBUG "vxpocket assign resources: port = 0x%x, irq = %d\n", port, irq);
-	vxp->port = port;
-
-	sprintf(card->shortname, "Digigram %s", card->driver);
-	sprintf(card->longname, "%s at 0x%x, irq %i",
-		card->shortname, port, irq);
-
-	chip->irq = irq;
-
-	if ((err = snd_vx_setup_firmware(chip)) < 0)
-		return err;
-
-	return 0;
-}
-
-
-/*
- * snd_vxpocket_detach - detach callback for cs
- * @hw: the hardware information
- */
-void snd_vxpocket_detach(struct snd_vxp_entry *hw, dev_link_t *link)
-{
-	vx_core_t *chip;
-
-	if (! link)
-		return;
-
-	chip = link->priv;
-
-	snd_printdd(KERN_DEBUG "vxpocket_detach called\n");
-	/* Remove the interface data from the linked list */
-	if (hw) {
-		dev_link_t **linkp;
-		/* Locate device structure */
-		for (linkp = &hw->dev_list; *linkp; linkp = &(*linkp)->next)
-			if (*linkp == link) {
-				*linkp = link->next;
-				break;
-			}
-	}
-	chip->chip_status |= VX_STAT_IS_STALE; /* to be sure */
-	snd_card_disconnect(chip->card);
-	snd_card_free_in_thread(chip->card);
-}
-
-/*
- * configuration callback
- */
-
-#define CS_CHECK(fn, ret) \
-do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
-
-static void vxpocket_config(dev_link_t *link)
-{
-	client_handle_t handle = link->handle;
-	vx_core_t *chip = link->priv;
-	struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip;
-	tuple_t tuple;
-	cisparse_t *parse = NULL;
-	u_short buf[32];
-	int last_fn, last_ret;
-
-	snd_printdd(KERN_DEBUG "vxpocket_config called\n");
-	parse = kmalloc(sizeof(*parse), GFP_KERNEL);
-	if (! parse) {
-		snd_printk(KERN_ERR "vx: cannot allocate\n");
-		return;
-	}
-	tuple.Attributes = 0;
-	tuple.TupleData = (cisdata_t *)buf;
-	tuple.TupleDataMax = sizeof(buf);
-	tuple.TupleOffset = 0;
-	tuple.DesiredTuple = CISTPL_CONFIG;
-	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
-	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
-	CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, parse));
-	link->conf.ConfigBase = parse->config.base;
-	link->conf.Present = parse->config.rmask[0];
-
-	/* Configure card */
-	link->state |= DEV_CONFIG;
-
-	CS_CHECK(RequestIO, pcmcia_request_io(handle, &link->io));
-	CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
-	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
-
-	if (snd_vxpocket_assign_resources(chip, link->io.BasePort1, link->irq.AssignedIRQ) < 0)
-		goto failed;
-
-	link->dev = &vxp->node;
-	link->state &= ~DEV_CONFIG_PENDING;
-	kfree(parse);
-	return;
-
-cs_failed:
-	cs_error(link->handle, last_fn, last_ret);
-failed:
-	pcmcia_release_configuration(link->handle);
-	pcmcia_release_io(link->handle, &link->io);
-	pcmcia_release_irq(link->handle, &link->irq);
-	link->state &= ~DEV_CONFIG;
-	kfree(parse);
-}
-
-
-/*
- * event callback
- */
-int vxpocket_event(event_t event, int priority, event_callback_args_t *args)
-{
-	dev_link_t *link = args->client_data;
-	vx_core_t *chip = link->priv;
-
-	switch (event) {
-	case CS_EVENT_CARD_REMOVAL:
-		snd_printdd(KERN_DEBUG "CARD_REMOVAL..\n");
-		link->state &= ~DEV_PRESENT;
-		if (link->state & DEV_CONFIG) {
-			chip->chip_status |= VX_STAT_IS_STALE;
-		}
-		break;
-	case CS_EVENT_CARD_INSERTION:
-		snd_printdd(KERN_DEBUG "CARD_INSERTION..\n");
-		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-		vxpocket_config(link);
-		break;
-#ifdef CONFIG_PM
-	case CS_EVENT_PM_SUSPEND:
-		snd_printdd(KERN_DEBUG "SUSPEND\n");
-		link->state |= DEV_SUSPEND;
-		if (chip && chip->card->pm_suspend) {
-			snd_printdd(KERN_DEBUG "snd_vx_suspend calling\n");
-			chip->card->pm_suspend(chip->card, PMSG_SUSPEND);
-		}
-		/* Fall through... */
-	case CS_EVENT_RESET_PHYSICAL:
-		snd_printdd(KERN_DEBUG "RESET_PHYSICAL\n");
-		if (link->state & DEV_CONFIG)
-			pcmcia_release_configuration(link->handle);
-		break;
-	case CS_EVENT_PM_RESUME:
-		snd_printdd(KERN_DEBUG "RESUME\n");
-		link->state &= ~DEV_SUSPEND;
-		/* Fall through... */
-	case CS_EVENT_CARD_RESET:
-		snd_printdd(KERN_DEBUG "CARD_RESET\n");
-		if (DEV_OK(link)) {
-			//struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip;
-			snd_printdd(KERN_DEBUG "requestconfig...\n");
-			pcmcia_request_configuration(link->handle, &link->conf);
-			if (chip && chip->card->pm_resume) {
-				snd_printdd(KERN_DEBUG "calling snd_vx_resume\n");
-				chip->card->pm_resume(chip->card);
-			}
-		}
-		snd_printdd(KERN_DEBUG "resume done!\n");
-		break;
-#endif
-	}
-	return 0;
-}
-
-/*
- * exported stuffs
- */
-EXPORT_SYMBOL(snd_vxpocket_ops);
-EXPORT_SYMBOL(snd_vxpocket_attach);
-EXPORT_SYMBOL(vxpocket_event);
-EXPORT_SYMBOL(snd_vxpocket_detach);
diff --git a/sound/pcmcia/vx/vxp440.c b/sound/pcmcia/vx/vxp440.c
deleted file mode 100644
index 59190a8..0000000
--- a/sound/pcmcia/vx/vxp440.c
+++ /dev/null
@@ -1,14 +0,0 @@
-#define COMPILE_VXP440
-
-/*
- add the following as /etc/pcmcia/vxp440.conf:
-
-  device "snd-vxp440"
-    class "audio" module "snd-vxp440"
-
-  card "Digigram VX-POCKET440"
-    manfid 0x01f1, 0x0100
-    bind "snd-vxp440"
-*/
-
-#include "vxpocket.c"
diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c
index 62d6fa1..3a82161 100644
--- a/sound/pcmcia/vx/vxpocket.c
+++ b/sound/pcmcia/vx/vxpocket.c
@@ -24,21 +24,17 @@
 #include <linux/moduleparam.h>
 #include <sound/core.h>
 #include "vxpocket.h"
+#include <pcmcia/ciscode.h>
+#include <pcmcia/cisreg.h>
 #include <sound/initval.h>
 
 /*
  */
 
-#ifdef COMPILE_VXP440
-#define CARD_NAME	"VXPocket440"
-#else
-#define CARD_NAME	"VXPocket"
-#endif
-
 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
-MODULE_DESCRIPTION("Digigram " CARD_NAME);
+MODULE_DESCRIPTION("Digigram VXPocket");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("{{Digigram," CARD_NAME "}}");
+MODULE_SUPPORTED_DEVICE("{{Digigram,VXPocket},{Digigram,VXPocket440}}");
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
@@ -46,82 +42,405 @@
 static int ibl[SNDRV_CARDS];
 
 module_param_array(index, int, NULL, 0444);
-MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
+MODULE_PARM_DESC(index, "Index value for VXPocket soundcard.");
 module_param_array(id, charp, NULL, 0444);
-MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
+MODULE_PARM_DESC(id, "ID string for VXPocket soundcard.");
 module_param_array(enable, bool, NULL, 0444);
-MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
+MODULE_PARM_DESC(enable, "Enable VXPocket soundcard.");
 module_param_array(ibl, int, NULL, 0444);
-MODULE_PARM_DESC(ibl, "Capture IBL size for " CARD_NAME " soundcard.");
+MODULE_PARM_DESC(ibl, "Capture IBL size for VXPocket soundcard.");
  
 
 /*
  */
 
-#ifdef COMPILE_VXP440
+static unsigned int card_alloc;
+static dev_link_t *dev_list;		/* Linked list of devices */
+static dev_info_t dev_info = "snd-vxpocket";
 
-/* 1 DSP, 1 sync UER, 1 sync World Clock (NIY) */
-/* SMPTE (NIY) */
-/* 2 stereo analog input (line/micro) */
-/* 2 stereo analog output */
-/* Only output levels can be modified */
-/* UER, but only for the first two inputs and outputs. */
 
-#define NUM_CODECS	2
-#define CARD_TYPE	VX_TYPE_VXP440
-#define DEV_INFO	"snd-vxp440"
+static int vxpocket_event(event_t event, int priority, event_callback_args_t *args);
 
-#else
 
-/* 1 DSP, 1 sync UER */
-/* 1 programmable clock (NIY) */
-/* 1 stereo analog input (line/micro) */
-/* 1 stereo analog output */
-/* Only output levels can be modified */
+/*
+ */
+static void vxpocket_release(dev_link_t *link)
+{
+	if (link->state & DEV_CONFIG) {
+		/* release cs resources */
+		pcmcia_release_configuration(link->handle);
+		pcmcia_release_io(link->handle, &link->io);
+		pcmcia_release_irq(link->handle, &link->irq);
+		link->state &= ~DEV_CONFIG;
+	}
+	if (link->handle) {
+		/* Break the link with Card Services */
+		pcmcia_deregister_client(link->handle);
+		link->handle = NULL;
+	}
+}
 
-#define NUM_CODECS	1
-#define CARD_TYPE	VX_TYPE_VXPOCKET
-#define DEV_INFO	"snd-vxpocket"
+/*
+ * destructor, called from snd_card_free_in_thread()
+ */
+static int snd_vxpocket_dev_free(snd_device_t *device)
+{
+	vx_core_t *chip = device->device_data;
 
-#endif
+	snd_vx_free_firmware(chip);
+	kfree(chip);
+	return 0;
+}
 
-static dev_info_t dev_info = DEV_INFO;
 
-static struct snd_vx_hardware vxp_hw = {
-	.name = CARD_NAME,
-	.type = CARD_TYPE,
+/*
+ * Hardware information
+ */
+
+/* VX-pocket V2
+ *
+ * 1 DSP, 1 sync UER
+ * 1 programmable clock (NIY)
+ * 1 stereo analog input (line/micro)
+ * 1 stereo analog output
+ * Only output levels can be modified
+ */
+
+static struct snd_vx_hardware vxpocket_hw = {
+	.name = "VXPocket",
+	.type = VX_TYPE_VXPOCKET,
 
 	/* hardware specs */
-	.num_codecs = NUM_CODECS,
-	.num_ins = NUM_CODECS,
-	.num_outs = NUM_CODECS,
+	.num_codecs = 1,
+	.num_ins = 1,
+	.num_outs = 1,
 	.output_level_max = VX_ANALOG_OUT_LEVEL_MAX,
 };	
 
-static struct snd_vxp_entry hw_entry = {
-	.dev_info = &dev_info,
+/* VX-pocket 440
+ *
+ * 1 DSP, 1 sync UER, 1 sync World Clock (NIY)
+ * SMPTE (NIY)
+ * 2 stereo analog input (line/micro)
+ * 2 stereo analog output
+ * Only output levels can be modified
+ * UER, but only for the first two inputs and outputs.
+ */
 
-	/* module parameters */
-	.index_table = index,
-	.id_table = id,
-	.enable_table = enable,
-	.ibl = ibl,
+static struct snd_vx_hardware vxp440_hw = {
+	.name = "VXPocket440",
+	.type = VX_TYPE_VXP440,
 
-	/* h/w config */
-	.hardware = &vxp_hw,
-	.ops = &snd_vxpocket_ops,
-};
+	/* hardware specs */
+	.num_codecs = 2,
+	.num_ins = 2,
+	.num_outs = 2,
+	.output_level_max = VX_ANALOG_OUT_LEVEL_MAX,
+};	
+
+
+/*
+ * create vxpocket instance
+ */
+static struct snd_vxpocket *snd_vxpocket_new(snd_card_t *card, int ibl)
+{
+	client_reg_t client_reg;	/* Register with cardmgr */
+	dev_link_t *link;		/* Info for cardmgr */
+	vx_core_t *chip;
+	struct snd_vxpocket *vxp;
+	int ret;
+	static snd_device_ops_t ops = {
+		.dev_free =	snd_vxpocket_dev_free,
+	};
+
+	chip = snd_vx_create(card, &vxpocket_hw, &snd_vxpocket_ops,
+			     sizeof(struct snd_vxpocket) - sizeof(vx_core_t));
+	if (! chip)
+		return NULL;
+
+	if (snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops) < 0) {
+		kfree(chip);
+		return NULL;
+	}
+	chip->ibl.size = ibl;
+
+	vxp = (struct snd_vxpocket *)chip;
+
+	link = &vxp->link;
+	link->priv = chip;
+
+	link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+	link->io.NumPorts1 = 16;
+
+	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+
+	link->irq.IRQInfo1 = IRQ_LEVEL_ID;
+	link->irq.Handler = &snd_vx_irq_handler;
+	link->irq.Instance = chip;
+
+	link->conf.Attributes = CONF_ENABLE_IRQ;
+	link->conf.Vcc = 50;
+	link->conf.IntType = INT_MEMORY_AND_IO;
+	link->conf.ConfigIndex = 1;
+	link->conf.Present = PRESENT_OPTION;
+
+	/* Register with Card Services */
+	memset(&client_reg, 0, sizeof(client_reg));
+	client_reg.dev_info = &dev_info;
+	client_reg.EventMask = 
+		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL
+#ifdef CONFIG_PM
+		| CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET
+		| CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME
+#endif
+		;
+	client_reg.event_handler = &vxpocket_event;
+	client_reg.Version = 0x0210;
+	client_reg.event_callback_args.client_data = link;
+
+	ret = pcmcia_register_client(&link->handle, &client_reg);
+	if (ret != CS_SUCCESS) {
+		cs_error(link->handle, RegisterClient, ret);
+		return NULL;
+	}
+
+	return vxp;
+}
+
+
+/**
+ * snd_vxpocket_assign_resources - initialize the hardware and card instance.
+ * @port: i/o port for the card
+ * @irq: irq number for the card
+ *
+ * this function assigns the specified port and irq, boot the card,
+ * create pcm and control instances, and initialize the rest hardware.
+ *
+ * returns 0 if successful, or a negative error code.
+ */
+static int snd_vxpocket_assign_resources(vx_core_t *chip, int port, int irq)
+{
+	int err;
+	snd_card_t *card = chip->card;
+	struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip;
+
+	snd_printdd(KERN_DEBUG "vxpocket assign resources: port = 0x%x, irq = %d\n", port, irq);
+	vxp->port = port;
+
+	sprintf(card->shortname, "Digigram %s", card->driver);
+	sprintf(card->longname, "%s at 0x%x, irq %i",
+		card->shortname, port, irq);
+
+	chip->irq = irq;
+
+	if ((err = snd_vx_setup_firmware(chip)) < 0)
+		return err;
+
+	return 0;
+}
+
+
+/*
+ * configuration callback
+ */
+
+#define CS_CHECK(fn, ret) \
+do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
+
+static void vxpocket_config(dev_link_t *link)
+{
+	client_handle_t handle = link->handle;
+	vx_core_t *chip = link->priv;
+	struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip;
+	tuple_t tuple;
+	cisparse_t *parse;
+	u_short buf[32];
+	int last_fn, last_ret;
+
+	snd_printdd(KERN_DEBUG "vxpocket_config called\n");
+	parse = kmalloc(sizeof(*parse), GFP_KERNEL);
+	if (! parse) {
+		snd_printk(KERN_ERR "vx: cannot allocate\n");
+		return;
+	}
+	tuple.Attributes = 0;
+	tuple.TupleData = (cisdata_t *)buf;
+	tuple.TupleDataMax = sizeof(buf);
+	tuple.TupleOffset = 0;
+	tuple.DesiredTuple = CISTPL_CONFIG;
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
+	CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, parse));
+	link->conf.ConfigBase = parse->config.base;
+	link->conf.Present = parse->config.rmask[0];
+
+	/* redefine hardware record according to the VERSION1 string */
+	tuple.DesiredTuple = CISTPL_VERS_1;
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
+	CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, parse));
+	if (! strcmp(parse->version_1.str + parse->version_1.ofs[1], "VX-POCKET")) {
+		snd_printdd("VX-pocket is detected\n");
+	} else {
+		snd_printdd("VX-pocket 440 is detected\n");
+		/* overwrite the hardware information */
+		chip->hw = &vxp440_hw;
+		chip->type = vxp440_hw.type;
+		strcpy(chip->card->driver, vxp440_hw.name);
+	}
+
+	/* Configure card */
+	link->state |= DEV_CONFIG;
+
+	CS_CHECK(RequestIO, pcmcia_request_io(handle, &link->io));
+	CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
+	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
+
+	chip->dev = &handle_to_dev(link->handle);
+
+	if (snd_vxpocket_assign_resources(chip, link->io.BasePort1, link->irq.AssignedIRQ) < 0)
+		goto failed;
+
+	link->dev = &vxp->node;
+	link->state &= ~DEV_CONFIG_PENDING;
+	kfree(parse);
+	return;
+
+cs_failed:
+	cs_error(link->handle, last_fn, last_ret);
+failed:
+	pcmcia_release_configuration(link->handle);
+	pcmcia_release_io(link->handle, &link->io);
+	pcmcia_release_irq(link->handle, &link->irq);
+	link->state &= ~DEV_CONFIG;
+	kfree(parse);
+}
+
+
+/*
+ * event callback
+ */
+static int vxpocket_event(event_t event, int priority, event_callback_args_t *args)
+{
+	dev_link_t *link = args->client_data;
+	vx_core_t *chip = link->priv;
+
+	switch (event) {
+	case CS_EVENT_CARD_REMOVAL:
+		snd_printdd(KERN_DEBUG "CARD_REMOVAL..\n");
+		link->state &= ~DEV_PRESENT;
+		if (link->state & DEV_CONFIG)
+			chip->chip_status |= VX_STAT_IS_STALE;
+		break;
+	case CS_EVENT_CARD_INSERTION:
+		snd_printdd(KERN_DEBUG "CARD_INSERTION..\n");
+		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+		vxpocket_config(link);
+		break;
+#ifdef CONFIG_PM
+	case CS_EVENT_PM_SUSPEND:
+		snd_printdd(KERN_DEBUG "SUSPEND\n");
+		link->state |= DEV_SUSPEND;
+		if (chip && chip->card->pm_suspend) {
+			snd_printdd(KERN_DEBUG "snd_vx_suspend calling\n");
+			chip->card->pm_suspend(chip->card, PMSG_SUSPEND);
+		}
+		/* Fall through... */
+	case CS_EVENT_RESET_PHYSICAL:
+		snd_printdd(KERN_DEBUG "RESET_PHYSICAL\n");
+		if (link->state & DEV_CONFIG)
+			pcmcia_release_configuration(link->handle);
+		break;
+	case CS_EVENT_PM_RESUME:
+		snd_printdd(KERN_DEBUG "RESUME\n");
+		link->state &= ~DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_CARD_RESET:
+		snd_printdd(KERN_DEBUG "CARD_RESET\n");
+		if (DEV_OK(link)) {
+			//struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip;
+			snd_printdd(KERN_DEBUG "requestconfig...\n");
+			pcmcia_request_configuration(link->handle, &link->conf);
+			if (chip && chip->card->pm_resume) {
+				snd_printdd(KERN_DEBUG "calling snd_vx_resume\n");
+				chip->card->pm_resume(chip->card);
+			}
+		}
+		snd_printdd(KERN_DEBUG "resume done!\n");
+		break;
+#endif
+	}
+	return 0;
+}
+
 
 /*
  */
 static dev_link_t *vxp_attach(void)
 {
-	return snd_vxpocket_attach(&hw_entry);
+	snd_card_t *card;
+	struct snd_vxpocket *vxp;
+	int i;
+
+	/* find an empty slot from the card list */
+	for (i = 0; i < SNDRV_CARDS; i++) {
+		if (! card_alloc & (1 << i))
+			break;
+	}
+	if (i >= SNDRV_CARDS) {
+		snd_printk(KERN_ERR "vxpocket: too many cards found\n");
+		return NULL;
+	}
+	if (! enable[i])
+		return NULL; /* disabled explicitly */
+
+	/* ok, create a card instance */
+	card = snd_card_new(index[i], id[i], THIS_MODULE, 0);
+	if (card == NULL) {
+		snd_printk(KERN_ERR "vxpocket: cannot create a card instance\n");
+		return NULL;
+	}
+
+	vxp = snd_vxpocket_new(card, ibl[i]);
+	if (! vxp) {
+		snd_card_free(card);
+		return NULL;
+	}
+
+	vxp->index = index[i];
+	card_alloc |= 1 << i;
+
+	/* Chain drivers */
+	vxp->link.next = dev_list;
+	dev_list = &vxp->link;
+
+	return &vxp->link;
 }
 
 static void vxp_detach(dev_link_t *link)
 {
-	snd_vxpocket_detach(&hw_entry, link);
+	struct snd_vxpocket *vxp;
+	vx_core_t *chip;
+	dev_link_t **linkp;
+
+	if (! link)
+		return;
+
+	vxp = link->priv;
+	chip = (vx_core_t *)vxp;
+	card_alloc &= ~(1 << vxp->index);
+
+	/* Remove the interface data from the linked list */
+	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+		if (*linkp == link) {
+			*linkp = link->next;
+			break;
+		}
+
+	chip->chip_status |= VX_STAT_IS_STALE; /* to be sure */
+	snd_card_disconnect(chip->card);
+	vxpocket_release(link);
+	snd_card_free_in_thread(chip->card);
 }
 
 /*
@@ -137,7 +456,7 @@
 static struct pcmcia_driver vxp_cs_driver = {
 	.owner		= THIS_MODULE,
 	.drv		= {
-		.name	= DEV_INFO,
+		.name	= "snd-vxpocket",
 	},
 	.attach		= vxp_attach,
 	.detach		= vxp_detach,
@@ -152,7 +471,7 @@
 static void __exit exit_vxpocket(void)
 {
 	pcmcia_unregister_driver(&vxp_cs_driver);
-	BUG_ON(hw_entry.dev_list != NULL);
+	BUG_ON(dev_list != NULL);
 }
 
 module_init(init_vxpocket);
diff --git a/sound/pcmcia/vx/vxpocket.h b/sound/pcmcia/vx/vxpocket.h
index 4462c04..70754aa 100644
--- a/sound/pcmcia/vx/vxpocket.h
+++ b/sound/pcmcia/vx/vxpocket.h
@@ -28,24 +28,6 @@
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 
-struct snd_vxp_entry {
-	dev_info_t *dev_info;
-
-	/* module parameters */
-	int *index_table;
-	char **id_table;
-	int *enable_table;
-	int *ibl;
-
-	/* h/w config */
-	struct snd_vx_hardware *hardware;
-	struct snd_vx_ops *ops;
-
-	/* slots */
-	vx_core_t *card_list[SNDRV_CARDS];
-	dev_link_t *dev_list;		/* Linked list of devices */
-};
-
 struct snd_vxpocket {
 
 	vx_core_t core;
@@ -57,8 +39,7 @@
 	unsigned int regCDSP;	/* current CDSP register */
 	unsigned int regDIALOG;	/* current DIALOG register */
 
-	int index;
-	struct snd_vxp_entry *hw_entry;
+	int index;	/* card index */
 
 	/* pcmcia stuff */
 	dev_link_t link;
@@ -70,12 +51,6 @@
 void vx_set_mic_boost(vx_core_t *chip, int boost);
 void vx_set_mic_level(vx_core_t *chip, int level);
 
-/*
- * pcmcia stuff
- */
-dev_link_t *snd_vxpocket_attach(struct snd_vxp_entry *hw);
-void snd_vxpocket_detach(struct snd_vxp_entry *hw, dev_link_t *link);
-
 int vxp_add_mic_controls(vx_core_t *chip);
 
 /* Constants used to access the CDSP register (0x08). */
diff --git a/sound/ppc/awacs.c b/sound/ppc/awacs.c
index 061e52d..758ca1b 100644
--- a/sound/ppc/awacs.c
+++ b/sound/ppc/awacs.c
@@ -103,7 +103,7 @@
 	snd_pmac_awacs_write_noreg(chip, 1, chip->awacs_reg[1]);
 	if (chip->manufacturer == 0x1)
 		/* delay for broken crystal part */
-		big_mdelay(750);
+		msleep(750);
 	snd_pmac_awacs_write_noreg(chip, 1,
 				   chip->awacs_reg[1] | MASK_RECALIBRATE | MASK_CMUTE | MASK_AMUTE);
 	snd_pmac_awacs_write_noreg(chip, 1, chip->awacs_reg[1]);
@@ -653,10 +653,10 @@
 {
 	if (machine_is_compatible("PowerBook3,1")
 	    || machine_is_compatible("PowerBook3,2")) {
-		big_mdelay(100);
+		msleep(100);
 		snd_pmac_awacs_write_reg(chip, 1,
 			chip->awacs_reg[1] & ~MASK_PAROUT);
-		big_mdelay(300);
+		msleep(300);
 	}
 
 	awacs_restore_all_regs(chip);
diff --git a/sound/ppc/pmac.h b/sound/ppc/pmac.h
index 582db52..ae3bb6c 100644
--- a/sound/ppc/pmac.h
+++ b/sound/ppc/pmac.h
@@ -212,9 +212,4 @@
 
 int snd_pmac_add_automute(pmac_t *chip);
 
-#define big_mdelay(msec) do {\
-	set_current_state(TASK_UNINTERRUPTIBLE);\
-	schedule_timeout(((msec) * HZ + 999) / 1000);\
-} while (0)
-
 #endif /* __PMAC_H */
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c
index 36c5d5d..b94437c 100644
--- a/sound/ppc/tumbler.c
+++ b/sound/ppc/tumbler.c
@@ -945,7 +945,7 @@
 			check_mute(chip, &mix->line_mute, 0, mix->auto_mute_notify,
 				   chip->lineout_sw_ctl);
 		if (mix->anded_reset)
-			big_mdelay(10);
+			msleep(10);
 		check_mute(chip, &mix->amp_mute, 1, mix->auto_mute_notify,
 			   chip->speaker_sw_ctl);
 		mix->drc_enable = 0;
@@ -954,7 +954,7 @@
 		check_mute(chip, &mix->amp_mute, 0, mix->auto_mute_notify,
 			   chip->speaker_sw_ctl);
 		if (mix->anded_reset)
-			big_mdelay(10);
+			msleep(10);
 		check_mute(chip, &mix->hp_mute, 1, mix->auto_mute_notify,
 			   chip->master_sw_ctl);
 		if (mix->line_mute.addr != 0)
@@ -1109,22 +1109,22 @@
 		DBG("(I) codec anded reset !\n");
 		write_audio_gpio(&mix->hp_mute, 0);
 		write_audio_gpio(&mix->amp_mute, 0);
-		big_mdelay(200);
+		msleep(200);
 		write_audio_gpio(&mix->hp_mute, 1);
 		write_audio_gpio(&mix->amp_mute, 1);
-		big_mdelay(100);
+		msleep(100);
 		write_audio_gpio(&mix->hp_mute, 0);
 		write_audio_gpio(&mix->amp_mute, 0);
-		big_mdelay(100);
+		msleep(100);
 	} else {
 		DBG("(I) codec normal reset !\n");
 
 		write_audio_gpio(&mix->audio_reset, 0);
-		big_mdelay(200);
+		msleep(200);
 		write_audio_gpio(&mix->audio_reset, 1);
-		big_mdelay(100);
+		msleep(100);
 		write_audio_gpio(&mix->audio_reset, 0);
-		big_mdelay(100);
+		msleep(100);
 	}
 }
 
diff --git a/sound/sparc/Kconfig b/sound/sparc/Kconfig
index 2358df1..25a8a55 100644
--- a/sound/sparc/Kconfig
+++ b/sound/sparc/Kconfig
@@ -7,12 +7,30 @@
 	tristate "Sun AMD7930"
 	depends on SBUS && SND
 	select SND_PCM
+	help
+	  Say Y here to include support for AMD7930 sound device on Sun.
 
-#  dep_tristate 'Sun DBRI' CONFIG_SND_SUN_DBRI $CONFIG_SND
+	  To compile this driver as a module, choose M here: the module
+	  will be called snd-sun-amd7930.
+
 config SND_SUN_CS4231
 	tristate "Sun CS4231"
 	depends on SND
 	select SND_PCM
+	help
+	  Say Y here to include support for CS4231 sound device on Sun.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called snd-sun-cs4231.
+
+config SND_SUN_DBRI
+	tristate "Sun DBRI"
+	depends on SND && SBUS
+	select SND_PCM
+	help
+	  Say Y here to include support for DBRI sound device on Sun.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called snd-sun-dbri.
 
 endmenu
-
diff --git a/sound/sparc/Makefile b/sound/sparc/Makefile
index 6809cc9..3cd89c6 100644
--- a/sound/sparc/Makefile
+++ b/sound/sparc/Makefile
@@ -4,9 +4,9 @@
 #
 
 snd-sun-amd7930-objs := amd7930.o
-#snd-sun-dbri-objs := dbri.o
 snd-sun-cs4231-objs := cs4231.o
+snd-sun-dbri-objs := dbri.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
+obj-$(CONFIG_SND_SUN_DBRI) += snd-sun-dbri.o
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c
new file mode 100644
index 0000000..941c7b1
--- /dev/null
+++ b/sound/sparc/dbri.c
@@ -0,0 +1,2729 @@
+/*
+ * Driver for DBRI sound chip found on Sparcs.
+ * Copyright (C) 2004 Martin Habets (mhabets@users.sourceforge.net)
+ *
+ * Based entirely upon drivers/sbus/audio/dbri.c which is:
+ * 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 <sound/driver.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/info.h>
+#include <sound/control.h>
+#include <sound/initval.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/sbus.h>
+#include <asm/atomic.h>
+
+MODULE_AUTHOR("Rudolf Koenig, Brent Baccala and Martin Habets");
+MODULE_DESCRIPTION("Sun DBRI");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{Sun,DBRI}}");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for Sun DBRI soundcard.");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for Sun DBRI soundcard.");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable Sun DBRI soundcard.");
+
+#define DBRI_DEBUG
+
+#define D_INT	(1<<0)
+#define D_GEN	(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_param(dbri_debug, int, 0444);
+MODULE_PARM_DESC(dbri_debug, "Debug value for Sun DBRI soundcard.");
+
+#ifdef DBRI_DEBUG
+static char *cmds[] = {
+	"WAIT", "PAUSE", "JUMP", "IIQ", "REX", "SDP", "CDP", "DTS",
+	"SSP", "CHI", "NT", "TE", "CDEC", "TEST", "CDM", "RESRV"
+};
+
+#define dprintk(a, x...) if(dbri_debug & a) printk(KERN_DEBUG x)
+
+#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 */
+
+/***************************************************************************
+	CS4215 specific definitions and structures
+****************************************************************************/
+
+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;
+	__u8 precision;		/* In bits, either 8 or 16 */
+	__u8 channels;		/* 1 or 2 */
+};
+
+/*
+ * 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 */
+
+/***************************************************************************
+		DBRI specific definitions and structures
+****************************************************************************/
+
+/* 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_NO_PIPES	32
+
+#define DBRI_MM_ONB	1
+#define DBRI_MM_SB	2
+
+#define DBRI_REC	0
+#define DBRI_PLAY	1
+#define DBRI_NO_STREAMS	2
+
+/* One transmit/receive descriptor */
+struct dbri_mem {
+	volatile __u32 word1;
+	volatile __u32 ba;	/* Transmit/Receive Buffer Address */
+	volatile __u32 nda;	/* Next Descriptor Address */
+	volatile __u32 word4;
+};
+
+/* 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 };
+
+struct dbri_pipe {
+	u32 sdp;		/* SDP command word */
+	enum in_or_out direction;
+	int nextpipe;		/* Next pipe in linked list */
+	int prevpipe;
+	int cycle;		/* Offset of timeslot (bits) */
+	int length;		/* Length of timeslot (bits) */
+	int first_desc;		/* Index of first descriptor */
+	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 */
+	unsigned int len;
+};
+
+/* Per stream (playback or record) information */
+typedef struct dbri_streaminfo {
+	snd_pcm_substream_t *substream;
+	u32 dvma_buffer;	/* Device view of Alsa DMA buffer */
+	int left;		/* # of bytes left in DMA buffer  */
+	int size;		/* Size of DMA buffer             */
+	size_t offset;		/* offset in user buffer          */
+	int pipe;		/* Data pipe used                 */
+	int left_gain;		/* mixer elements                 */
+	int right_gain;
+	int balance;
+} dbri_streaminfo_t;
+
+/* This structure holds the information for both chips (DBRI & CS4215) */
+typedef struct snd_dbri {
+	snd_card_t *card;	/* ALSA card */
+	snd_pcm_t *pcm;
+
+	int regs_size, irq;	/* Needed for unload */
+	struct sbus_dev *sdev;	/* SBUS device info */
+	spinlock_t lock;
+
+	volatile struct dbri_dma *dma;	/* Pointer to our DMA block */
+	u32 dma_dvma;		/* DBRI visible DMA address */
+
+	void __iomem *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[DBRI_NO_PIPES];	/* 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 */
+				/* per stream (playback/record) info */
+	struct dbri_streaminfo stream_info[DBRI_NO_STREAMS];
+
+	struct snd_dbri *next;
+} snd_dbri_t;
+
+/* Needed for the ALSA macros to work */
+#define chip_t snd_dbri_t
+
+#define DBRI_MAX_VOLUME		63	/* Output volume */
+#define DBRI_MAX_GAIN		15	/* Input gain */
+#define DBRI_RIGHT_BALANCE	255
+#define DBRI_MID_BALANCE	(DBRI_RIGHT_BALANCE >> 1)
+
+/* 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 */
+			/* Maximum buffer size per TD: almost 8Kb */
+#define DBRI_TD_MAXCNT	((1 << 13) - 1)
+
+/* 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)	/* Valid bytes in the buffer */
+
+/* stream_info[] access */
+/* Translate the ALSA direction into the array index */
+#define DBRI_STREAMNO(substream)				\
+		(substream->stream == 				\
+		 SNDRV_PCM_STREAM_PLAYBACK? DBRI_PLAY: DBRI_REC)
+
+/* Return a pointer to dbri_streaminfo */
+#define DBRI_STREAM(dbri, substream)	&dbri->stream_info[DBRI_STREAMNO(substream)]
+
+static snd_dbri_t *dbri_list = NULL;	/* All DBRI devices */
+
+/*
+ * 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(KERN_ERR "DBRI reverse_bytes: unsupported length\n");
+	};
+
+	return b;
+}
+
+/*
+****************************************************************************
+************** 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.
+
+*/
+
+enum dbri_lock_t { NoGetLock, GetLock };
+
+static volatile s32 *dbri_cmdlock(snd_dbri_t * dbri, enum dbri_lock_t get)
+{
+#ifndef SMP
+	if ((get == GetLock) && spin_is_locked(&dbri->lock)) {
+		printk(KERN_ERR "DBRI: cmdlock called while in spinlock.");
+	}
+#endif
+
+	/*if (get == GetLock) spin_lock(&dbri->lock); */
+	return &dbri->dma->cmd[0];
+}
+
+static void dbri_process_interrupt_buffer(snd_dbri_t *);
+
+static void dbri_cmdsend(snd_dbri_t * dbri, volatile s32 * cmd)
+{
+	int MAXLOOPS = 1000000;
+	int maxloops = MAXLOOPS;
+	volatile s32 *ptr;
+
+	for (ptr = &dbri->dma->cmd[0]; ptr < cmd; ptr++) {
+		dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr);
+	}
+
+	if ((cmd - &dbri->dma->cmd[0]) >= DBRI_NO_CMDS - 1) {
+		printk("DBRI: Command buffer overflow! (bug in driver)\n");
+		/* Ignore the last part. */
+		cmd = &dbri->dma->cmd[DBRI_NO_CMDS - 3];
+	}
+
+	*(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(KERN_ERR "DBRI: Chip never completed command buffer\n");
+		dprintk(D_CMD, "DBRI: Chip never completed command buffer\n");
+	} else {
+		while ((--maxloops) > 0 && (!dbri->wait_seen))
+			dbri_process_interrupt_buffer(dbri);
+		if (maxloops == 0) {
+			printk(KERN_ERR "DBRI: Chip never acked WAIT\n");
+			dprintk(D_CMD, "DBRI: Chip never acked WAIT\n");
+		} else {
+			dprintk(D_CMD, "Chip completed command "
+				"buffer (%d)\n", MAXLOOPS - maxloops);
+		}
+	}
+
+	/*spin_unlock(&dbri->lock); */
+}
+
+/* Lock must be held when calling this */
+static void dbri_reset(snd_dbri_t * dbri)
+{
+	int i;
+
+	dprintk(D_GEN, "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);
+}
+
+/* Lock must not be held before calling this */
+static void dbri_initialize(snd_dbri_t * dbri)
+{
+	volatile s32 *cmd;
+	u32 dma_addr, tmp;
+	unsigned long flags;
+	int n;
+
+	spin_lock_irqsave(&dbri->lock, flags);
+
+	dbri_reset(dbri);
+
+	cmd = dbri_cmdlock(dbri, NoGetLock);
+	dprintk(D_GEN, "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;
+
+	/* Initialize pipes */
+	for (n = 0; n < DBRI_NO_PIPES; n++)
+		dbri->pipes[n].desc = dbri->pipes[n].first_desc = -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
+	 */
+	dma_addr = dbri->dma_dvma + dbri_dma_off(intr, 0);
+	*(cmd++) = DBRI_CMD(D_IIQ, 0, 0);
+	*(cmd++) = dma_addr;
+
+	dbri_cmdsend(dbri, cmd);
+	spin_unlock_irqrestore(&dbri->lock, flags);
+}
+
+/*
+****************************************************************************
+************************** 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(snd_dbri_t * dbri, int pipe)
+{
+	return ((pipe >= 0) && (dbri->pipes[pipe].desc != -1));
+}
+
+/* reset_pipe(dbri, pipe)
+ *
+ * Called on an in-use pipe to clear anything being transmitted or received
+ * Lock must be held before calling this.
+ */
+static void reset_pipe(snd_dbri_t * 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, NoGetLock);
+	*(cmd++) = DBRI_CMD(D_SDP, 0, sdp | D_SDP_C | D_SDP_P);
+	*(cmd++) = 0;
+	dbri_cmdsend(dbri, cmd);
+
+	desc = dbri->pipes[pipe].first_desc;
+	while (desc != -1) {
+		dbri->descs[desc].inuse = 0;
+		desc = dbri->descs[desc].next;
+	}
+
+	dbri->pipes[pipe].desc = -1;
+	dbri->pipes[pipe].first_desc = -1;
+}
+
+/* FIXME: direction as an argument? */
+static void setup_pipe(snd_dbri_t * 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;
+	dbri->pipes[pipe].first_desc = -1;
+	if (sdp & D_SDP_TO_SER)
+		dbri->pipes[pipe].direction = PIPEoutput;
+	else
+		dbri->pipes[pipe].direction = PIPEinput;
+
+	reset_pipe(dbri, pipe);
+}
+
+/* FIXME: direction not needed */
+static void link_time_slot(snd_dbri_t * 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, NoGetLock);
+
+	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);
+}
+
+static void unlink_time_slot(snd_dbri_t * 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, NoGetLock);
+
+	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(snd_dbri_t * 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, GetLock);
+
+	*(cmd++) = DBRI_CMD(D_SSP, 0, pipe);
+	*(cmd++) = data;
+
+	dbri_cmdsend(dbri, cmd);
+}
+
+static void recv_fixed(snd_dbri_t * 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;
+}
+
+/* setup_descs()
+ *
+ * Setup 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.
+ *
+ * This function takes a stream number pointing to a data buffer,
+ * and 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 int setup_descs(snd_dbri_t * dbri, int streamno, unsigned int period)
+{
+	dbri_streaminfo_t *info = &dbri->stream_info[streamno];
+	__u32 dvma_buffer;
+	int desc = 0;
+	int len;
+	int first_desc = -1;
+	int last_desc = -1;
+
+	if (info->pipe < 0 || info->pipe > 15) {
+		printk("DBRI: setup_descs: Illegal pipe number\n");
+		return -2;
+	}
+
+	if (dbri->pipes[info->pipe].sdp == 0) {
+		printk("DBRI: setup_descs: Uninitialized pipe %d\n",
+		       info->pipe);
+		return -2;
+	}
+
+	dvma_buffer = info->dvma_buffer;
+	len = info->size;
+
+	if (streamno == DBRI_PLAY) {
+		if (!(dbri->pipes[info->pipe].sdp & D_SDP_TO_SER)) {
+			printk("DBRI: setup_descs: Called on receive pipe %d\n",
+			       info->pipe);
+			return -2;
+		}
+	} else {
+		if (dbri->pipes[info->pipe].sdp & D_SDP_TO_SER) {
+			printk
+			    ("DBRI: setup_descs: Called on transmit pipe %d\n",
+			     info->pipe);
+			return -2;
+		}
+		/* Should be able to queue multiple buffers to receive on a pipe */
+		if (pipe_active(dbri, info->pipe)) {
+			printk("DBRI: recv_on_pipe: Called on active pipe %d\n",
+			       info->pipe);
+			return -2;
+		}
+
+		/* Make sure buffer size is multiple of four */
+		len &= ~3;
+	}
+
+	while (len > 0) {
+		int mylen;
+
+		for (; desc < DBRI_NO_DESCS; desc++) {
+			if (!dbri->descs[desc].inuse)
+				break;
+		}
+		if (desc == DBRI_NO_DESCS) {
+			printk("DBRI: setup_descs: No descriptors\n");
+			return -1;
+		}
+
+		if (len > DBRI_TD_MAXCNT) {
+			mylen = DBRI_TD_MAXCNT;	/* 8KB - 1 */
+		} else {
+			mylen = len;
+		}
+		if (mylen > period) {
+			mylen = period;
+		}
+
+		dbri->descs[desc].inuse = 1;
+		dbri->descs[desc].next = -1;
+		dbri->dma->desc[desc].ba = dvma_buffer;
+		dbri->dma->desc[desc].nda = 0;
+
+		if (streamno == DBRI_PLAY) {
+			dbri->descs[desc].len = mylen;
+			dbri->dma->desc[desc].word1 = DBRI_TD_CNT(mylen);
+			dbri->dma->desc[desc].word4 = 0;
+			if (first_desc != -1)
+				dbri->dma->desc[desc].word1 |= DBRI_TD_M;
+		} else {
+			dbri->descs[desc].len = 0;
+			dbri->dma->desc[desc].word1 = 0;
+			dbri->dma->desc[desc].word4 =
+			    DBRI_RD_B | DBRI_RD_BCNT(mylen);
+		}
+
+		if (first_desc == -1) {
+			first_desc = desc;
+		} else {
+			dbri->descs[last_desc].next = desc;
+			dbri->dma->desc[last_desc].nda =
+			    dbri->dma_dvma + dbri_dma_off(desc, desc);
+		}
+
+		last_desc = desc;
+		dvma_buffer += mylen;
+		len -= mylen;
+	}
+
+	if (first_desc == -1 || last_desc == -1) {
+		printk("DBRI: setup_descs: Not enough descriptors available\n");
+		return -1;
+	}
+
+	dbri->dma->desc[last_desc].word1 &= ~DBRI_TD_M;
+	if (streamno == DBRI_PLAY) {
+		dbri->dma->desc[last_desc].word1 |=
+		    DBRI_TD_I | DBRI_TD_F | DBRI_TD_B;
+	}
+	dbri->pipes[info->pipe].first_desc = first_desc;
+	dbri->pipes[info->pipe].desc = first_desc;
+
+	for (desc = first_desc; desc != -1; desc = dbri->descs[desc].next) {
+		dprintk(D_DESC, "DESC %d: %08x %08x %08x %08x\n",
+			desc,
+			dbri->dma->desc[desc].word1,
+			dbri->dma->desc[desc].ba,
+			dbri->dma->desc[desc].nda, dbri->dma->desc[desc].word4);
+	}
+	return 0;
+}
+
+/*
+****************************************************************************
+************************** 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(snd_dbri_t * dbri, enum master_or_slave master_or_slave,
+		      int bits_per_frame)
+{
+	volatile s32 *cmd;
+	int val;
+	static int chi_initialized = 0;	/* FIXME: mutex? */
+
+	if (!chi_initialized) {
+
+		cmd = dbri_cmdlock(dbri, GetLock);
+
+		/* 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, GetLock);
+	}
+
+	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 cs4215_setup_pipes(snd_dbri_t * 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);
+}
+
+static int cs4215_init_data(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;
+
+	mm->status = 0;
+	mm->version = 0xff;
+	mm->precision = 8;	/* For ULAW */
+	mm->channels = 2;
+
+	return 0;
+}
+
+static void cs4215_setdata(snd_dbri_t * dbri, int muted)
+{
+	if (muted) {
+		dbri->mm.data[0] |= 63;
+		dbri->mm.data[1] |= 63;
+		dbri->mm.data[2] &= ~15;
+		dbri->mm.data[3] &= ~15;
+	} else {
+		/* Start by setting the playback attenuation. */
+		dbri_streaminfo_t *info = &dbri->stream_info[DBRI_PLAY];
+		int left_gain = info->left_gain % 64;
+		int right_gain = info->right_gain % 64;
+
+		if (info->balance < DBRI_MID_BALANCE) {
+			right_gain *= info->balance;
+			right_gain /= DBRI_MID_BALANCE;
+		} else {
+			left_gain *= DBRI_RIGHT_BALANCE - info->balance;
+			left_gain /= DBRI_MID_BALANCE;
+		}
+
+		dbri->mm.data[0] &= ~0x3f;	/* Reset the volume bits */
+		dbri->mm.data[1] &= ~0x3f;
+		dbri->mm.data[0] |= (DBRI_MAX_VOLUME - left_gain);
+		dbri->mm.data[1] |= (DBRI_MAX_VOLUME - right_gain);
+
+		/* Now set the recording gain. */
+		info = &dbri->stream_info[DBRI_REC];
+		left_gain = info->left_gain % 16;
+		right_gain = info->right_gain % 16;
+		dbri->mm.data[2] |= CS4215_LG(left_gain);
+		dbri->mm.data[3] |= CS4215_RG(right_gain);
+	}
+
+	xmit_fixed(dbri, 20, *(int *)dbri->mm.data);
+}
+
+/*
+ * Set the CS4215 to data mode.
+ */
+static void cs4215_open(snd_dbri_t * dbri)
+{
+	int data_width;
+	u32 tmp;
+
+	dprintk(D_MM, "cs4215_open: %d channels, %d bits\n",
+		dbri->mm.channels, dbri->mm.precision);
+
+	/* Temporarily mute outputs, and wait 1/8000 sec (125 us)
+	 * to make sure this takes.  This avoids clicking noises.
+	 */
+
+	cs4215_setdata(dbri, 1);
+	udelay(125);
+
+	/*
+	 * 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->mm.channels * dbri->mm.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);
+
+	/* FIXME: enable CHI after _setdata? */
+	tmp = sbus_readl(dbri->regs + REG0);
+	tmp |= D_C;		/* Enable CHI */
+	sbus_writel(tmp, dbri->regs + REG0);
+
+	cs4215_setdata(dbri, 0);
+}
+
+/*
+ * Send the control information (i.e. audio format)
+ */
+static int cs4215_setctrl(snd_dbri_t * dbri)
+{
+	int i, val;
+	u32 tmp;
+
+	/* FIXME - 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.
+	 */
+
+	cs4215_setdata(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);
+	dprintk(D_MM, "cs4215_setctrl: reg2=0x%x\n", val);
+	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);
+
+	for (i = 64; ((dbri->mm.status & 0xe4) != 0x20); --i) {
+		udelay(125);
+	}
+	if (i == 0) {
+		dprintk(D_MM, "CS4215 didn't respond to CLB (0x%02x)\n",
+			dbri->mm.status);
+		return -1;
+	}
+
+	/* Disable changes to our copy of the version number, as we are about
+	 * to leave control mode.
+	 */
+	recv_fixed(dbri, 19, NULL);
+
+	/* 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);
+
+	cs4215_setdata(dbri, 0);
+
+	return 0;
+}
+
+/*
+ * Setup the codec with the sampling rate, audio format and number of
+ * channels.
+ * As part of the process we resend the settings for the data
+ * timeslots as well.
+ */
+static int cs4215_prepare(snd_dbri_t * dbri, unsigned int rate,
+			  snd_pcm_format_t format, unsigned int channels)
+{
+	int freq_idx;
+	int ret = 0;
+
+	/* Lookup index for this rate */
+	for (freq_idx = 0; CS4215_FREQ[freq_idx].freq != 0; freq_idx++) {
+		if (CS4215_FREQ[freq_idx].freq == rate)
+			break;
+	}
+	if (CS4215_FREQ[freq_idx].freq != rate) {
+		printk(KERN_WARNING "DBRI: Unsupported rate %d Hz\n", rate);
+		return -1;
+	}
+
+	switch (format) {
+	case SNDRV_PCM_FORMAT_MU_LAW:
+		dbri->mm.ctrl[1] = CS4215_DFR_ULAW;
+		dbri->mm.precision = 8;
+		break;
+	case SNDRV_PCM_FORMAT_A_LAW:
+		dbri->mm.ctrl[1] = CS4215_DFR_ALAW;
+		dbri->mm.precision = 8;
+		break;
+	case SNDRV_PCM_FORMAT_U8:
+		dbri->mm.ctrl[1] = CS4215_DFR_LINEAR8;
+		dbri->mm.precision = 8;
+		break;
+	case SNDRV_PCM_FORMAT_S16_BE:
+		dbri->mm.ctrl[1] = CS4215_DFR_LINEAR16;
+		dbri->mm.precision = 16;
+		break;
+	default:
+		printk(KERN_WARNING "DBRI: Unsupported format %d\n", format);
+		return -1;
+	}
+
+	/* Add rate parameters */
+	dbri->mm.ctrl[1] |= CS4215_FREQ[freq_idx].csval;
+	dbri->mm.ctrl[2] = CS4215_XCLK |
+	    CS4215_BSEL_128 | CS4215_FREQ[freq_idx].xtal;
+
+	dbri->mm.channels = channels;
+	/* Stereo bit: 8 bit stereo not working yet. */
+	if ((channels > 1) && (dbri->mm.precision == 16))
+		dbri->mm.ctrl[1] |= CS4215_DFR_STEREO;
+
+	ret = cs4215_setctrl(dbri);
+	if (ret == 0)
+		cs4215_open(dbri);	/* set codec to data mode */
+
+	return ret;
+}
+
+/*
+ *
+ */
+static int cs4215_init(snd_dbri_t * dbri)
+{
+	u32 reg2 = sbus_readl(dbri->regs + REG2);
+	dprintk(D_MM, "cs4215_init: reg2=0x%x\n", reg2);
+
+	/* Look for the cs4215 chips */
+	if (reg2 & D_PIO2) {
+		dprintk(D_MM, "Onboard CS4215 detected\n");
+		dbri->mm.onboard = 1;
+	}
+	if (reg2 & D_PIO0) {
+		dprintk(D_MM, "Speakerbox detected\n");
+		dbri->mm.onboard = 0;
+
+		if (reg2 & D_PIO2) {
+			printk(KERN_INFO "DBRI: Using speakerbox / "
+			       "ignoring onboard mmcodec.\n");
+			sbus_writel(D_ENPIO2, dbri->regs + REG2);
+		}
+	}
+
+	if (!(reg2 & (D_PIO0 | D_PIO2))) {
+		printk(KERN_ERR "DBRI: no mmcodec found.\n");
+		return -EIO;
+	}
+
+	cs4215_setup_pipes(dbri);
+
+	cs4215_init_data(&dbri->mm);
+
+	/* Enable capture of the status & version timeslots. */
+	recv_fixed(dbri, 18, &dbri->mm.status);
+	recv_fixed(dbri, 19, &dbri->mm.version);
+
+	dbri->mm.offset = dbri->mm.onboard ? 0 : 8;
+	if (cs4215_setctrl(dbri) == -1 || dbri->mm.version == 0xff) {
+		dprintk(D_MM, "CS4215 failed probe at offset %d\n",
+			dbri->mm.offset);
+		return -EIO;
+	}
+	dprintk(D_MM, "Found CS4215 at offset %d\n", dbri->mm.offset);
+
+	return 0;
+}
+
+/*
+****************************************************************************
+*************************** 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.
+
+*/
+
+/* xmit_descs()
+ *
+ * Transmit the current TD's for recording/playing, if needed.
+ * For playback, ALSA has filled the DMA memory with new data (we hope).
+ */
+static void xmit_descs(unsigned long data)
+{
+	snd_dbri_t *dbri = (snd_dbri_t *) data;
+	dbri_streaminfo_t *info;
+	volatile s32 *cmd;
+	unsigned long flags;
+	int first_td;
+
+	if (dbri == NULL)
+		return;		/* Disabled */
+
+	/* First check the recording stream for buffer overflow */
+	info = &dbri->stream_info[DBRI_REC];
+	spin_lock_irqsave(&dbri->lock, flags);
+
+	if ((info->left >= info->size) && (info->pipe >= 0)) {
+		first_td = dbri->pipes[info->pipe].first_desc;
+
+		dprintk(D_DESC, "xmit_descs rec @ TD %d\n", first_td);
+
+		/* Stream could be closed by the time we run. */
+		if (first_td < 0) {
+			goto play;
+		}
+
+		cmd = dbri_cmdlock(dbri, NoGetLock);
+		*(cmd++) = DBRI_CMD(D_SDP, 0,
+				    dbri->pipes[info->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);
+
+		/* Reset our admin of the pipe & bytes read. */
+		dbri->pipes[info->pipe].desc = first_td;
+		info->left = 0;
+	}
+
+play:
+	spin_unlock_irqrestore(&dbri->lock, flags);
+
+	/* Now check the playback stream for buffer underflow */
+	info = &dbri->stream_info[DBRI_PLAY];
+	spin_lock_irqsave(&dbri->lock, flags);
+
+	if ((info->left <= 0) && (info->pipe >= 0)) {
+		first_td = dbri->pipes[info->pipe].first_desc;
+
+		dprintk(D_DESC, "xmit_descs play @ TD %d\n", first_td);
+
+		/* Stream could be closed by the time we run. */
+		if (first_td < 0) {
+			spin_unlock_irqrestore(&dbri->lock, flags);
+			return;
+		}
+
+		cmd = dbri_cmdlock(dbri, NoGetLock);
+		*(cmd++) = DBRI_CMD(D_SDP, 0,
+				    dbri->pipes[info->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);
+
+		/* Reset our admin of the pipe & bytes written. */
+		dbri->pipes[info->pipe].desc = first_td;
+		info->left = info->size;
+	}
+	spin_unlock_irqrestore(&dbri->lock, flags);
+}
+
+DECLARE_TASKLET(xmit_descs_task, xmit_descs, 0);
+
+/* 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(snd_dbri_t * dbri, int pipe)
+{
+	dbri_streaminfo_t *info;
+	int td;
+	int status;
+
+	info = &dbri->stream_info[DBRI_PLAY];
+
+	td = dbri->pipes[pipe].desc;
+	while (td >= 0) {
+		if (td >= DBRI_NO_DESCS) {
+			printk(KERN_ERR "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, "TD %d, status 0x%02x\n", td, status);
+
+		dbri->dma->desc[td].word4 = 0;	/* Reset it for next time. */
+		info->offset += dbri->descs[td].len;
+		info->left -= dbri->descs[td].len;
+
+		/* On the last TD, transmit them all again. */
+		if (dbri->descs[td].next == -1) {
+			if (info->left > 0) {
+				printk(KERN_WARNING
+				       "%d bytes left after last transfer.\n",
+				       info->left);
+				info->left = 0;
+			}
+			tasklet_schedule(&xmit_descs_task);
+		}
+
+		td = dbri->descs[td].next;
+		dbri->pipes[pipe].desc = td;
+	}
+
+	/* Notify ALSA */
+	if (spin_is_locked(&dbri->lock)) {
+		spin_unlock(&dbri->lock);
+		snd_pcm_period_elapsed(info->substream);
+		spin_lock(&dbri->lock);
+	} else
+		snd_pcm_period_elapsed(info->substream);
+}
+
+static void reception_complete_intr(snd_dbri_t * dbri, int pipe)
+{
+	dbri_streaminfo_t *info;
+	int rd = dbri->pipes[pipe].desc;
+	s32 status;
+
+	if (rd < 0 || rd >= DBRI_NO_DESCS) {
+		printk(KERN_ERR "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;
+	dbri->dma->desc[rd].word1 = 0;	/* Reset it for next time. */
+
+	info = &dbri->stream_info[DBRI_REC];
+	info->offset += DBRI_RD_CNT(status);
+	info->left += DBRI_RD_CNT(status);
+
+	/* FIXME: Check status */
+
+	dprintk(D_INT, "Recv RD %d, status 0x%02x, len %d\n",
+		rd, DBRI_RD_STATUS(status), DBRI_RD_CNT(status));
+
+	/* On the last TD, transmit them all again. */
+	if (dbri->descs[rd].next == -1) {
+		if (info->left > info->size) {
+			printk(KERN_WARNING
+			       "%d bytes recorded in %d size buffer.\n",
+			       info->left, info->size);
+		}
+		tasklet_schedule(&xmit_descs_task);
+	}
+
+	/* Notify ALSA */
+	if (spin_is_locked(&dbri->lock)) {
+		spin_unlock(&dbri->lock);
+		snd_pcm_period_elapsed(info->substream);
+		spin_lock(&dbri->lock);
+	} else
+		snd_pcm_period_elapsed(info->substream);
+}
+
+static void dbri_process_one_interrupt(snd_dbri_t * 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);
+#ifdef DBRI_DEBUG
+	int rval = D_INTR_GETRVAL(x);
+#endif
+
+	if (channel == D_INTR_CMD) {
+		dprintk(D_CMD, "INTR: Command: %-5s  Value:%d\n",
+			cmds[command], val);
+	} else {
+		dprintk(D_INT, "INTR: Chan:%d Code:%d Val:%#x\n",
+			channel, code, rval);
+	}
+
+	if (channel == D_INTR_CMD && command == D_WAIT) {
+		dbri->wait_seen++;
+		return;
+	}
+
+	switch (code) {
+	case D_INTR_BRDY:
+		reception_complete_intr(dbri, channel);
+		break;
+	case D_INTR_XCMP:
+	case D_INTR_MINT:
+		transmission_complete_intr(dbri, channel);
+		break;
+	case 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, NoGetLock);
+			*(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);
+		}
+		break;
+	case 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;
+		break;
+	default:
+		if (channel != D_INTR_CMD)
+			printk(KERN_WARNING
+			       "DBRI: Ignored Interrupt: %d (0x%x)\n", code, x);
+	}
+}
+
+/* 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(snd_dbri_t * 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++;
+
+		dbri_process_one_interrupt(dbri, x);
+	}
+}
+
+static irqreturn_t snd_dbri_interrupt(int irq, void *dev_id,
+				      struct pt_regs *regs)
+{
+	snd_dbri_t *dbri = dev_id;
+	static int errcnt = 0;
+	int x;
+
+	if (dbri == NULL)
+		return IRQ_NONE;
+	spin_lock(&dbri->lock);
+
+	/*
+	 * Read it, so the interrupt goes away.
+	 */
+	x = sbus_readl(dbri->regs + REG1);
+
+	if (x & (D_MRR | D_MLE | D_LBG | D_MBE)) {
+		u32 tmp;
+
+		if (x & D_MRR)
+			printk(KERN_ERR
+			       "DBRI: Multiple Error Ack on SBus reg1=0x%x\n",
+			       x);
+		if (x & D_MLE)
+			printk(KERN_ERR
+			       "DBRI: Multiple Late Error on SBus reg1=0x%x\n",
+			       x);
+		if (x & D_LBG)
+			printk(KERN_ERR
+			       "DBRI: Lost Bus Grant on SBus reg1=0x%x\n", x);
+		if (x & D_MBE)
+			printk(KERN_ERR
+			       "DBRI: Burst Error on SBus reg1=0x%x\n", x);
+
+		/* 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.
+		 */
+		if ((++errcnt) % 10 == 0) {
+			dprintk(D_INT, "Interrupt errors exceeded.\n");
+			dbri_reset(dbri);
+		} else {
+			tmp = sbus_readl(dbri->regs + REG0);
+			tmp &= ~(D_D);
+			sbus_writel(tmp, dbri->regs + REG0);
+		}
+	}
+
+	dbri_process_interrupt_buffer(dbri);
+
+	/* FIXME: Write 0 into regs to ACK interrupt */
+
+	spin_unlock(&dbri->lock);
+
+	return IRQ_HANDLED;
+}
+
+/****************************************************************************
+		PCM Interface
+****************************************************************************/
+static snd_pcm_hardware_t snd_dbri_pcm_hw = {
+	.info			= (SNDRV_PCM_INFO_MMAP |
+				   SNDRV_PCM_INFO_INTERLEAVED |
+				   SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				   SNDRV_PCM_INFO_MMAP_VALID),
+	.formats		= SNDRV_PCM_FMTBIT_MU_LAW |
+				  SNDRV_PCM_FMTBIT_A_LAW |
+				  SNDRV_PCM_FMTBIT_U8 |
+				  SNDRV_PCM_FMTBIT_S16_BE,
+	.rates			= SNDRV_PCM_RATE_8000_48000,
+	.rate_min		= 8000,
+	.rate_max		= 48000,
+	.channels_min		= 1,
+	.channels_max		= 2,
+	.buffer_bytes_max	= (64 * 1024),
+	.period_bytes_min	= 1,
+	.period_bytes_max	= DBRI_TD_MAXCNT,
+	.periods_min		= 1,
+	.periods_max		= 1024,
+};
+
+static int snd_dbri_open(snd_pcm_substream_t * substream)
+{
+	snd_dbri_t *dbri = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	dbri_streaminfo_t *info = DBRI_STREAM(dbri, substream);
+	unsigned long flags;
+
+	dprintk(D_USR, "open audio output.\n");
+	runtime->hw = snd_dbri_pcm_hw;
+
+	spin_lock_irqsave(&dbri->lock, flags);
+	info->substream = substream;
+	info->left = 0;
+	info->offset = 0;
+	info->dvma_buffer = 0;
+	info->pipe = -1;
+	spin_unlock_irqrestore(&dbri->lock, flags);
+
+	cs4215_open(dbri);
+
+	return 0;
+}
+
+static int snd_dbri_close(snd_pcm_substream_t * substream)
+{
+	snd_dbri_t *dbri = snd_pcm_substream_chip(substream);
+	dbri_streaminfo_t *info = DBRI_STREAM(dbri, substream);
+
+	dprintk(D_USR, "close audio output.\n");
+	info->substream = NULL;
+	info->left = 0;
+	info->offset = 0;
+
+	return 0;
+}
+
+static int snd_dbri_hw_params(snd_pcm_substream_t * substream,
+			      snd_pcm_hw_params_t * hw_params)
+{
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	snd_dbri_t *dbri = snd_pcm_substream_chip(substream);
+	dbri_streaminfo_t *info = DBRI_STREAM(dbri, substream);
+	int direction;
+	int ret;
+
+	/* set sampling rate, audio format and number of channels */
+	ret = cs4215_prepare(dbri, params_rate(hw_params),
+			     params_format(hw_params),
+			     params_channels(hw_params));
+	if (ret != 0)
+		return ret;
+
+	if ((ret = snd_pcm_lib_malloc_pages(substream,
+				params_buffer_bytes(hw_params))) < 0) {
+		snd_printk(KERN_ERR "malloc_pages failed with %d\n", ret);
+		return ret;
+	}
+
+	/* hw_params can get called multiple times. Only map the DMA once.
+	 */
+	if (info->dvma_buffer == 0) {
+		if (DBRI_STREAMNO(substream) == DBRI_PLAY)
+			direction = SBUS_DMA_TODEVICE;
+		else
+			direction = SBUS_DMA_FROMDEVICE;
+
+		info->dvma_buffer = sbus_map_single(dbri->sdev,
+					runtime->dma_area,
+					params_buffer_bytes(hw_params),
+					direction);
+	}
+
+	direction = params_buffer_bytes(hw_params);
+	dprintk(D_USR, "hw_params: %d bytes, dvma=%x\n",
+		direction, info->dvma_buffer);
+	return 0;
+}
+
+static int snd_dbri_hw_free(snd_pcm_substream_t * substream)
+{
+	snd_dbri_t *dbri = snd_pcm_substream_chip(substream);
+	dbri_streaminfo_t *info = DBRI_STREAM(dbri, substream);
+	int direction;
+	dprintk(D_USR, "hw_free.\n");
+
+	/* hw_free can get called multiple times. Only unmap the DMA once.
+	 */
+	if (info->dvma_buffer) {
+		if (DBRI_STREAMNO(substream) == DBRI_PLAY)
+			direction = SBUS_DMA_TODEVICE;
+		else
+			direction = SBUS_DMA_FROMDEVICE;
+
+		sbus_unmap_single(dbri->sdev, info->dvma_buffer,
+				  substream->runtime->buffer_size, direction);
+		info->dvma_buffer = 0;
+	}
+	info->pipe = -1;
+
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static int snd_dbri_prepare(snd_pcm_substream_t * substream)
+{
+	snd_dbri_t *dbri = snd_pcm_substream_chip(substream);
+	dbri_streaminfo_t *info = DBRI_STREAM(dbri, substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	int ret;
+
+	info->size = snd_pcm_lib_buffer_bytes(substream);
+	if (DBRI_STREAMNO(substream) == DBRI_PLAY)
+		info->pipe = 4;	/* Send pipe */
+	else {
+		info->pipe = 6;	/* Receive pipe */
+		info->left = info->size;	/* To trigger submittal */
+	}
+
+	spin_lock_irq(&dbri->lock);
+
+	/* Setup the all the transmit/receive desciptors to cover the
+	 * whole DMA buffer.
+	 */
+	ret = setup_descs(dbri, DBRI_STREAMNO(substream),
+			  snd_pcm_lib_period_bytes(substream));
+
+	runtime->stop_threshold = DBRI_TD_MAXCNT / runtime->channels;
+
+	spin_unlock_irq(&dbri->lock);
+
+	dprintk(D_USR, "prepare audio output. %d bytes\n", info->size);
+	return ret;
+}
+
+static int snd_dbri_trigger(snd_pcm_substream_t * substream, int cmd)
+{
+	snd_dbri_t *dbri = snd_pcm_substream_chip(substream);
+	dbri_streaminfo_t *info = DBRI_STREAM(dbri, substream);
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		dprintk(D_USR, "start audio, period is %d bytes\n",
+			(int)snd_pcm_lib_period_bytes(substream));
+		/* Enable & schedule the tasklet that re-submits the TDs. */
+		xmit_descs_task.data = (unsigned long)dbri;
+		tasklet_schedule(&xmit_descs_task);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		dprintk(D_USR, "stop audio.\n");
+		/* Make the tasklet bail out immediately. */
+		xmit_descs_task.data = 0;
+		reset_pipe(dbri, info->pipe);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static snd_pcm_uframes_t snd_dbri_pointer(snd_pcm_substream_t * substream)
+{
+	snd_dbri_t *dbri = snd_pcm_substream_chip(substream);
+	dbri_streaminfo_t *info = DBRI_STREAM(dbri, substream);
+	snd_pcm_uframes_t ret;
+
+	ret = bytes_to_frames(substream->runtime, info->offset)
+		% substream->runtime->buffer_size;
+	dprintk(D_USR, "I/O pointer: %ld frames, %d bytes left.\n",
+		ret, info->left);
+	return ret;
+}
+
+static snd_pcm_ops_t snd_dbri_ops = {
+	.open = snd_dbri_open,
+	.close = snd_dbri_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = snd_dbri_hw_params,
+	.hw_free = snd_dbri_hw_free,
+	.prepare = snd_dbri_prepare,
+	.trigger = snd_dbri_trigger,
+	.pointer = snd_dbri_pointer,
+};
+
+static int __devinit snd_dbri_pcm(snd_dbri_t * dbri)
+{
+	snd_pcm_t *pcm;
+	int err;
+
+	if ((err = snd_pcm_new(dbri->card,
+			       /* ID */		    "sun_dbri",
+			       /* 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_dbri_ops);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_dbri_ops);
+
+	pcm->private_data = dbri;
+	pcm->info_flags = 0;
+	strcpy(pcm->name, dbri->card->shortname);
+	dbri->pcm = pcm;
+
+	if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm,
+			SNDRV_DMA_TYPE_CONTINUOUS,
+			snd_dma_continuous_data(GFP_KERNEL),
+			64 * 1024, 64 * 1024)) < 0) {
+		return err;
+	}
+
+	return 0;
+}
+
+/*****************************************************************************
+			Mixer interface
+*****************************************************************************/
+
+static int snd_cs4215_info_volume(snd_kcontrol_t * kcontrol,
+				  snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0;
+	if (kcontrol->private_value == DBRI_PLAY) {
+		uinfo->value.integer.max = DBRI_MAX_VOLUME;
+	} else {
+		uinfo->value.integer.max = DBRI_MAX_GAIN;
+	}
+	return 0;
+}
+
+static int snd_cs4215_get_volume(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol)
+{
+	snd_dbri_t *dbri = snd_kcontrol_chip(kcontrol);
+	dbri_streaminfo_t *info;
+	snd_assert(dbri != NULL, return -EINVAL);
+	info = &dbri->stream_info[kcontrol->private_value];
+	snd_assert(info != NULL, return -EINVAL);
+
+	ucontrol->value.integer.value[0] = info->left_gain;
+	ucontrol->value.integer.value[1] = info->right_gain;
+	return 0;
+}
+
+static int snd_cs4215_put_volume(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol)
+{
+	snd_dbri_t *dbri = snd_kcontrol_chip(kcontrol);
+	dbri_streaminfo_t *info = &dbri->stream_info[kcontrol->private_value];
+	unsigned long flags;
+	int changed = 0;
+
+	if (info->left_gain != ucontrol->value.integer.value[0]) {
+		info->left_gain = ucontrol->value.integer.value[0];
+		changed = 1;
+	}
+	if (info->right_gain != ucontrol->value.integer.value[1]) {
+		info->right_gain = ucontrol->value.integer.value[1];
+		changed = 1;
+	}
+	if (changed == 1) {
+		/* First mute outputs, and wait 1/8000 sec (125 us)
+		 * to make sure this takes.  This avoids clicking noises.
+		 */
+		spin_lock_irqsave(&dbri->lock, flags);
+
+		cs4215_setdata(dbri, 1);
+		udelay(125);
+		cs4215_setdata(dbri, 0);
+
+		spin_unlock_irqrestore(&dbri->lock, flags);
+	}
+	return changed;
+}
+
+static int snd_cs4215_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;
+}
+
+static int snd_cs4215_get_single(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol)
+{
+	snd_dbri_t *dbri = snd_kcontrol_chip(kcontrol);
+	int elem = kcontrol->private_value & 0xff;
+	int shift = (kcontrol->private_value >> 8) & 0xff;
+	int mask = (kcontrol->private_value >> 16) & 0xff;
+	int invert = (kcontrol->private_value >> 24) & 1;
+	snd_assert(dbri != NULL, return -EINVAL);
+
+	if (elem < 4) {
+		ucontrol->value.integer.value[0] =
+		    (dbri->mm.data[elem] >> shift) & mask;
+	} else {
+		ucontrol->value.integer.value[0] =
+		    (dbri->mm.ctrl[elem - 4] >> shift) & mask;
+	}
+
+	if (invert == 1) {
+		ucontrol->value.integer.value[0] =
+		    mask - ucontrol->value.integer.value[0];
+	}
+	return 0;
+}
+
+static int snd_cs4215_put_single(snd_kcontrol_t * kcontrol,
+				 snd_ctl_elem_value_t * ucontrol)
+{
+	snd_dbri_t *dbri = snd_kcontrol_chip(kcontrol);
+	unsigned long flags;
+	int elem = kcontrol->private_value & 0xff;
+	int shift = (kcontrol->private_value >> 8) & 0xff;
+	int mask = (kcontrol->private_value >> 16) & 0xff;
+	int invert = (kcontrol->private_value >> 24) & 1;
+	int changed = 0;
+	unsigned short val;
+	snd_assert(dbri != NULL, return -EINVAL);
+
+	val = (ucontrol->value.integer.value[0] & mask);
+	if (invert == 1)
+		val = mask - val;
+	val <<= shift;
+
+	if (elem < 4) {
+		dbri->mm.data[elem] = (dbri->mm.data[elem] &
+				       ~(mask << shift)) | val;
+		changed = (val != dbri->mm.data[elem]);
+	} else {
+		dbri->mm.ctrl[elem - 4] = (dbri->mm.ctrl[elem - 4] &
+					   ~(mask << shift)) | val;
+		changed = (val != dbri->mm.ctrl[elem - 4]);
+	}
+
+	dprintk(D_GEN, "put_single: mask=0x%x, changed=%d, "
+		"mixer-value=%ld, mm-value=0x%x\n",
+		mask, changed, ucontrol->value.integer.value[0],
+		dbri->mm.data[elem & 3]);
+
+	if (changed) {
+		/* First mute outputs, and wait 1/8000 sec (125 us)
+		 * to make sure this takes.  This avoids clicking noises.
+		 */
+		spin_lock_irqsave(&dbri->lock, flags);
+
+		cs4215_setdata(dbri, 1);
+		udelay(125);
+		cs4215_setdata(dbri, 0);
+
+		spin_unlock_irqrestore(&dbri->lock, flags);
+	}
+	return changed;
+}
+
+/* Entries 0-3 map to the 4 data timeslots, entries 4-7 map to the 4 control
+   timeslots. Shift is the bit offset in the timeslot, mask defines the
+   number of bits. invert is a boolean for use with attenuation.
+ */
+#define CS4215_SINGLE(xname, entry, shift, mask, invert) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+  .info = snd_cs4215_info_single, \
+  .get = snd_cs4215_get_single, .put = snd_cs4215_put_single, \
+  .private_value = entry | (shift << 8) | (mask << 16) | (invert << 24) },
+
+static snd_kcontrol_new_t dbri_controls[] __devinitdata = {
+	{
+	 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	 .name  = "Playback Volume",
+	 .info  = snd_cs4215_info_volume,
+	 .get   = snd_cs4215_get_volume,
+	 .put   = snd_cs4215_put_volume,
+	 .private_value = DBRI_PLAY,
+	 },
+	CS4215_SINGLE("Headphone switch", 0, 7, 1, 0)
+	CS4215_SINGLE("Line out switch", 0, 6, 1, 0)
+	CS4215_SINGLE("Speaker switch", 1, 6, 1, 0)
+	{
+	 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	 .name  = "Capture Volume",
+	 .info  = snd_cs4215_info_volume,
+	 .get   = snd_cs4215_get_volume,
+	 .put   = snd_cs4215_put_volume,
+	 .private_value = DBRI_REC,
+	 },
+	/* FIXME: mic/line switch */
+	CS4215_SINGLE("Line in switch", 2, 4, 1, 0)
+	CS4215_SINGLE("High Pass Filter switch", 5, 7, 1, 0)
+	CS4215_SINGLE("Monitor Volume", 3, 4, 0xf, 1)
+	CS4215_SINGLE("Mic boost", 4, 4, 1, 1)
+};
+
+#define NUM_CS4215_CONTROLS (sizeof(dbri_controls)/sizeof(snd_kcontrol_new_t))
+
+static int __init snd_dbri_mixer(snd_dbri_t * dbri)
+{
+	snd_card_t *card;
+	int idx, err;
+
+	snd_assert(dbri != NULL && dbri->card != NULL, return -EINVAL);
+
+	card = dbri->card;
+	strcpy(card->mixername, card->shortname);
+
+	for (idx = 0; idx < NUM_CS4215_CONTROLS; idx++) {
+		if ((err = snd_ctl_add(card,
+				       snd_ctl_new1(&dbri_controls[idx],
+						    dbri))) < 0)
+			return err;
+	}
+
+	for (idx = DBRI_REC; idx < DBRI_NO_STREAMS; idx++) {
+		dbri->stream_info[idx].left_gain = 0;
+		dbri->stream_info[idx].right_gain = 0;
+		dbri->stream_info[idx].balance = DBRI_MID_BALANCE;
+	}
+
+	return 0;
+}
+
+/****************************************************************************
+			/proc interface
+****************************************************************************/
+static void dbri_regs_read(snd_info_entry_t * entry, snd_info_buffer_t * buffer)
+{
+	snd_dbri_t *dbri = entry->private_data;
+
+	snd_iprintf(buffer, "REG0: 0x%x\n", sbus_readl(dbri->regs + REG0));
+	snd_iprintf(buffer, "REG2: 0x%x\n", sbus_readl(dbri->regs + REG2));
+	snd_iprintf(buffer, "REG8: 0x%x\n", sbus_readl(dbri->regs + REG8));
+	snd_iprintf(buffer, "REG9: 0x%x\n", sbus_readl(dbri->regs + REG9));
+}
+
+#ifdef DBRI_DEBUG
+static void dbri_debug_read(snd_info_entry_t * entry,
+			    snd_info_buffer_t * buffer)
+{
+	snd_dbri_t *dbri = entry->private_data;
+	int pipe;
+	snd_iprintf(buffer, "debug=%d\n", dbri_debug);
+
+	snd_iprintf(buffer, "CHI pipe in=%d, out=%d\n",
+		    dbri->chi_in_pipe, dbri->chi_out_pipe);
+	for (pipe = 0; pipe < 32; pipe++) {
+		if (pipe_active(dbri, pipe)) {
+			struct dbri_pipe *pptr = &dbri->pipes[pipe];
+			snd_iprintf(buffer,
+				    "Pipe %d: %s SDP=0x%x desc=%d, "
+				    "len=%d @ %d prev: %d next %d\n",
+				    pipe,
+				    (pptr->direction ==
+				     PIPEinput ? "input" : "output"), pptr->sdp,
+				    pptr->desc, pptr->length, pptr->cycle,
+				    pptr->prevpipe, pptr->nextpipe);
+		}
+	}
+}
+
+static void dbri_debug_write(snd_info_entry_t * entry,
+			     snd_info_buffer_t * buffer)
+{
+	char line[80];
+	int i;
+
+	if (snd_info_get_line(buffer, line, 80) == 0) {
+		sscanf(line, "%d\n", &i);
+		dbri_debug = i & 0x3f;
+	}
+}
+#endif
+
+void snd_dbri_proc(snd_dbri_t * dbri)
+{
+	snd_info_entry_t *entry;
+	int err;
+
+	err = snd_card_proc_new(dbri->card, "regs", &entry);
+	snd_info_set_text_ops(entry, dbri, 1024, dbri_regs_read);
+
+#ifdef DBRI_DEBUG
+	err = snd_card_proc_new(dbri->card, "debug", &entry);
+	snd_info_set_text_ops(entry, dbri, 4096, dbri_debug_read);
+	entry->mode = S_IFREG | S_IRUGO | S_IWUSR; /* Writable for root */
+	entry->c.text.write_size = 256;
+	entry->c.text.write = dbri_debug_write;
+#endif
+}
+
+/*
+****************************************************************************
+**************************** Initialization ********************************
+****************************************************************************
+*/
+static void snd_dbri_free(snd_dbri_t * dbri);
+
+static int __init snd_dbri_create(snd_card_t * card,
+				  struct sbus_dev *sdev,
+				  struct linux_prom_irqs *irq, int dev)
+{
+	snd_dbri_t *dbri = card->private_data;
+	int err;
+
+	spin_lock_init(&dbri->lock);
+	dbri->card = card;
+	dbri->sdev = sdev;
+	dbri->irq = irq->pri;
+	dbri->dbri_version = sdev->prom_name[9];
+
+	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, "DMA Cmd Block 0x%p (0x%08x)\n",
+		dbri->dma, dbri->dma_dvma);
+
+	/* Map the registers into memory. */
+	dbri->regs_size = sdev->reg_addrs[0].reg_size;
+	dbri->regs = sbus_ioremap(&sdev->resource[0], 0,
+				  dbri->regs_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);
+		return -EIO;
+	}
+
+	err = request_irq(dbri->irq, snd_dbri_interrupt, SA_SHIRQ,
+			  "DBRI audio", 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);
+		return err;
+	}
+
+	/* Do low level initialization of the DBRI and CS4215 chips */
+	dbri_initialize(dbri);
+	err = cs4215_init(dbri);
+	if (err) {
+		snd_dbri_free(dbri);
+		return err;
+	}
+
+	dbri->next = dbri_list;
+	dbri_list = dbri;
+
+	return 0;
+}
+
+static void snd_dbri_free(snd_dbri_t * dbri)
+{
+	dprintk(D_GEN, "snd_dbri_free\n");
+	dbri_reset(dbri);
+
+	if (dbri->irq)
+		free_irq(dbri->irq, dbri);
+
+	if (dbri->regs)
+		sbus_iounmap(dbri->regs, dbri->regs_size);
+
+	if (dbri->dma)
+		sbus_free_consistent(dbri->sdev, sizeof(struct dbri_dma),
+				     (void *)dbri->dma, dbri->dma_dvma);
+}
+
+static int __init dbri_attach(int prom_node, struct sbus_dev *sdev)
+{
+	snd_dbri_t *dbri;
+	struct linux_prom_irqs irq;
+	struct resource *rp;
+	snd_card_t *card;
+	static int dev = 0;
+	int err;
+
+	if (sdev->prom_name[9] < 'e') {
+		printk(KERN_ERR "DBRI: unsupported chip version %c found.\n",
+		       sdev->prom_name[9]);
+		return -EIO;
+	}
+
+	if (dev >= SNDRV_CARDS)
+		return -ENODEV;
+	if (!enable[dev]) {
+		dev++;
+		return -ENOENT;
+	}
+
+	prom_getproperty(prom_node, "intr", (char *)&irq, sizeof(irq));
+
+	card = snd_card_new(index[dev], id[dev], THIS_MODULE,
+			    sizeof(snd_dbri_t));
+	if (card == NULL)
+		return -ENOMEM;
+
+	strcpy(card->driver, "DBRI");
+	strcpy(card->shortname, "Sun DBRI");
+	rp = &sdev->resource[0];
+	sprintf(card->longname, "%s at 0x%02lx:0x%08lx, irq %s",
+		card->shortname,
+		rp->flags & 0xffL, rp->start, __irq_itoa(irq.pri));
+
+	if ((err = snd_dbri_create(card, sdev, &irq, dev)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+	dbri = (snd_dbri_t *) card->private_data;
+	if ((err = snd_dbri_pcm(dbri)) < 0) {
+		snd_dbri_free(dbri);
+		snd_card_free(card);
+		return err;
+	}
+
+	if ((err = snd_dbri_mixer(dbri)) < 0) {
+		snd_dbri_free(dbri);
+		snd_card_free(card);
+		return err;
+	}
+
+	/* /proc file handling */
+	snd_dbri_proc(dbri);
+
+	if ((err = snd_card_register(card)) < 0) {
+		snd_dbri_free(dbri);
+		snd_card_free(card);
+		return err;
+	}
+
+	printk(KERN_INFO "audio%d at %p (irq %d) is DBRI(%c)+CS4215(%d)\n",
+	       dev, dbri->regs,
+	       dbri->irq, dbri->dbri_version, dbri->mm.version);
+	dev++;
+
+	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;
+	int found = 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 (dbri_attach(sdev->prom_node, sdev) == 0)
+				found++;
+		}
+	}
+
+	return (found > 0) ? 0 : -EIO;
+}
+
+static void __exit dbri_exit(void)
+{
+	snd_dbri_t *this = dbri_list;
+
+	while (this != NULL) {
+		snd_dbri_t *next = this->next;
+		snd_card_t *card = this->card;
+
+		snd_dbri_free(this);
+		snd_card_free(card);
+		this = next;
+	}
+	dbri_list = NULL;
+}
+
+module_init(dbri_init);
+module_exit(dbri_exit);
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index b5e734d..8298c46 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -153,6 +153,7 @@
 	unsigned int format;     /* USB data format */
 	unsigned int datapipe;   /* the data i/o pipe */
 	unsigned int syncpipe;   /* 1 - async out or adaptive in */
+	unsigned int datainterval;	/* log_2 of data packet interval */
 	unsigned int syncinterval;  /* P for adaptive mode, 0 otherwise */
 	unsigned int freqn;      /* nominal sampling rate in fs/fps in Q16.16 format */
 	unsigned int freqm;      /* momentary sampling rate in fs/fps in Q16.16 format */
@@ -518,7 +519,8 @@
 		if (subs->fill_max)
 			counts = subs->maxframesize; /* fixed */
 		else {
-			subs->phase = (subs->phase & 0xffff) + subs->freqm;
+			subs->phase = (subs->phase & 0xffff)
+				+ (subs->freqm << subs->datainterval);
 			counts = subs->phase >> 16;
 			if (counts > subs->maxframesize)
 				counts = subs->maxframesize;
@@ -790,7 +792,7 @@
  */
 static int wait_clear_urbs(snd_usb_substream_t *subs)
 {
-	int timeout = HZ;
+	unsigned long end_time = jiffies + msecs_to_jiffies(1000);
 	unsigned int i;
 	int alive;
 
@@ -810,7 +812,7 @@
 			break;
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout(1);
-	} while (--timeout > 0);
+	} while (time_before(jiffies, end_time));
 	if (alive)
 		snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
 	return 0;
@@ -899,16 +901,19 @@
 	else
 		subs->freqn = get_usb_high_speed_rate(rate);
 	subs->freqm = subs->freqn;
-	subs->freqmax = subs->freqn + (subs->freqn >> 2); /* max. allowed frequency */
-	subs->phase = 0;
-
-	/* calculate the max. size of packet */
-	maxsize = ((subs->freqmax + 0xffff) * (frame_bits >> 3)) >> 16;
-	if (subs->maxpacksize && maxsize > subs->maxpacksize) {
-		//snd_printd(KERN_DEBUG "maxsize %d is greater than defined size %d\n",
-		//	   maxsize, subs->maxpacksize);
+	/* calculate max. frequency */
+	if (subs->maxpacksize) {
+		/* whatever fits into a max. size packet */
 		maxsize = subs->maxpacksize;
+		subs->freqmax = (maxsize / (frame_bits >> 3))
+				<< (16 - subs->datainterval);
+	} else {
+		/* no max. packet size: just take 25% higher than nominal */
+		subs->freqmax = subs->freqn + (subs->freqn >> 2);
+		maxsize = ((subs->freqmax + 0xffff) * (frame_bits >> 3))
+				>> (16 - subs->datainterval);
 	}
+	subs->phase = 0;
 
 	if (subs->fill_max)
 		subs->curpacksize = subs->maxpacksize;
@@ -918,7 +923,7 @@
 	if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
 		urb_packs = nrpacks;
 	else
-		urb_packs = nrpacks * 8;
+		urb_packs = (nrpacks * 8) >> subs->datainterval;
 
 	/* allocate a temporary buffer for playback */
 	if (is_playback) {
@@ -991,7 +996,7 @@
 		u->urb->pipe = subs->datapipe;
 		u->urb->transfer_flags = URB_ISO_ASAP;
 		u->urb->number_of_packets = u->packets;
-		u->urb->interval = 1;
+		u->urb->interval = 1 << subs->datainterval;
 		u->urb->context = u;
 		u->urb->complete = snd_usb_complete_callback(snd_complete_urb);
 	}
@@ -1195,6 +1200,12 @@
 		subs->datapipe = usb_sndisocpipe(dev, ep);
 	else
 		subs->datapipe = usb_rcvisocpipe(dev, ep);
+	if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH &&
+	    get_endpoint(alts, 0)->bInterval >= 1 &&
+	    get_endpoint(alts, 0)->bInterval <= 4)
+		subs->datainterval = get_endpoint(alts, 0)->bInterval - 1;
+	else
+		subs->datainterval = 0;
 	subs->syncpipe = subs->syncinterval = 0;
 	subs->maxpacksize = fmt->maxpacksize;
 	subs->fill_max = 0;
@@ -2397,10 +2408,9 @@
 	if (chip->usb_id == USB_ID(0x041e, 0x3000) ||
 	    chip->usb_id == USB_ID(0x041e, 0x3020)) {
 		if (fmt[3] == USB_FORMAT_TYPE_I &&
-		    stream == SNDRV_PCM_STREAM_PLAYBACK &&
 		    fp->rates != SNDRV_PCM_RATE_48000 &&
 		    fp->rates != SNDRV_PCM_RATE_96000)
-			return -1; /* use 48k only */
+			return -1;
 	}
 #endif
 	return 0;
@@ -2492,8 +2502,10 @@
 		fp->altset_idx = i;
 		fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
 		fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
-		/* FIXME: decode wMaxPacketSize of high bandwith endpoints */
 		fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
+		if (snd_usb_get_speed(dev) == USB_SPEED_HIGH)
+			fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1)
+					* (fp->maxpacksize & 0x7ff);
 		fp->attributes = csep[3];
 
 		/* some quirks for attributes here */
@@ -2723,7 +2735,8 @@
  * to detect the sample rate is by looking at wMaxPacketSize.
  */
 static int create_ua700_ua25_quirk(snd_usb_audio_t *chip,
-				   struct usb_interface *iface)
+				   struct usb_interface *iface,
+				   const snd_usb_audio_quirk_t *quirk)
 {
 	static const struct audioformat ua_format = {
 		.format = SNDRV_PCM_FORMAT_S24_3LE,
@@ -2814,7 +2827,9 @@
 /*
  * Create a stream for an Edirol UA-1000 interface.
  */
-static int create_ua1000_quirk(snd_usb_audio_t *chip, struct usb_interface *iface)
+static int create_ua1000_quirk(snd_usb_audio_t *chip,
+			       struct usb_interface *iface,
+			       const snd_usb_audio_quirk_t *quirk)
 {
 	static const struct audioformat ua1000_format = {
 		.format = SNDRV_PCM_FORMAT_S32_LE,
@@ -2891,6 +2906,13 @@
 	return 0;
 }
 
+static int ignore_interface_quirk(snd_usb_audio_t *chip,
+				  struct usb_interface *iface,
+				  const snd_usb_audio_quirk_t *quirk)
+{
+	return 0;
+}
+
 
 /*
  * boot quirks
@@ -2926,8 +2948,6 @@
 
 static int snd_usb_audigy2nx_boot_quirk(struct usb_device *dev)
 {
-#if 0
-	/* TODO: enable this when high speed synchronization actually works */
 	u8 buf = 1;
 
 	snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), 0x2a,
@@ -2939,7 +2959,6 @@
 				1, 2000, NULL, 0, 1000);
 		return -ENODEV;
 	}
-#endif
 	return 0;
 }
 
@@ -2956,28 +2975,28 @@
 				struct usb_interface *iface,
 				const snd_usb_audio_quirk_t *quirk)
 {
-	switch (quirk->type) {
-	case QUIRK_MIDI_FIXED_ENDPOINT:
-	case QUIRK_MIDI_YAMAHA:
-	case QUIRK_MIDI_MIDIMAN:
-	case QUIRK_MIDI_NOVATION:
-	case QUIRK_MIDI_MOTU:
-	case QUIRK_MIDI_EMAGIC:
-		return snd_usb_create_midi_interface(chip, iface, quirk);
-	case QUIRK_COMPOSITE:
-		return create_composite_quirk(chip, iface, quirk);
-	case QUIRK_AUDIO_FIXED_ENDPOINT:
-		return create_fixed_stream_quirk(chip, iface, quirk);
-	case QUIRK_AUDIO_STANDARD_INTERFACE:
-	case QUIRK_MIDI_STANDARD_INTERFACE:
-		return create_standard_interface_quirk(chip, iface, quirk);
-	case QUIRK_AUDIO_EDIROL_UA700_UA25:
-		return create_ua700_ua25_quirk(chip, iface);
-	case QUIRK_AUDIO_EDIROL_UA1000:
-		return create_ua1000_quirk(chip, iface);
-	case QUIRK_IGNORE_INTERFACE:
-		return 0;
-	default:
+	typedef int (*quirk_func_t)(snd_usb_audio_t *, struct usb_interface *,
+				    const snd_usb_audio_quirk_t *);
+	static const quirk_func_t quirk_funcs[] = {
+		[QUIRK_IGNORE_INTERFACE] = ignore_interface_quirk,
+		[QUIRK_COMPOSITE] = create_composite_quirk,
+		[QUIRK_MIDI_STANDARD_INTERFACE] = snd_usb_create_midi_interface,
+		[QUIRK_MIDI_FIXED_ENDPOINT] = snd_usb_create_midi_interface,
+		[QUIRK_MIDI_YAMAHA] = snd_usb_create_midi_interface,
+		[QUIRK_MIDI_MIDIMAN] = snd_usb_create_midi_interface,
+		[QUIRK_MIDI_NOVATION] = snd_usb_create_midi_interface,
+		[QUIRK_MIDI_RAW] = snd_usb_create_midi_interface,
+		[QUIRK_MIDI_EMAGIC] = snd_usb_create_midi_interface,
+		[QUIRK_MIDI_MIDITECH] = snd_usb_create_midi_interface,
+		[QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_interface_quirk,
+		[QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,
+		[QUIRK_AUDIO_EDIROL_UA700_UA25] = create_ua700_ua25_quirk,
+		[QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk,
+	};
+
+	if (quirk->type < QUIRK_TYPE_COUNT) {
+		return quirk_funcs[quirk->type](chip, iface, quirk);
+	} else {
 		snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type);
 		return -ENXIO;
 	}
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index aedb42a..ad9eab2 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -153,20 +153,24 @@
 #define QUIRK_NO_INTERFACE		-2
 #define QUIRK_ANY_INTERFACE		-1
 
-/* quirk type */
-#define QUIRK_MIDI_FIXED_ENDPOINT	0
-#define QUIRK_MIDI_YAMAHA		1
-#define QUIRK_MIDI_MIDIMAN		2
-#define QUIRK_COMPOSITE			3
-#define QUIRK_AUDIO_FIXED_ENDPOINT	4
-#define QUIRK_AUDIO_STANDARD_INTERFACE	5
-#define QUIRK_MIDI_STANDARD_INTERFACE	6
-#define QUIRK_AUDIO_EDIROL_UA700_UA25	7
-#define QUIRK_AUDIO_EDIROL_UA1000	8
-#define QUIRK_IGNORE_INTERFACE		9
-#define QUIRK_MIDI_NOVATION		10
-#define QUIRK_MIDI_MOTU			11
-#define QUIRK_MIDI_EMAGIC		12
+enum quirk_type {
+	QUIRK_IGNORE_INTERFACE,
+	QUIRK_COMPOSITE,
+	QUIRK_MIDI_STANDARD_INTERFACE,
+	QUIRK_MIDI_FIXED_ENDPOINT,
+	QUIRK_MIDI_YAMAHA,
+	QUIRK_MIDI_MIDIMAN,
+	QUIRK_MIDI_NOVATION,
+	QUIRK_MIDI_RAW,
+	QUIRK_MIDI_EMAGIC,
+	QUIRK_MIDI_MIDITECH,
+	QUIRK_AUDIO_STANDARD_INTERFACE,
+	QUIRK_AUDIO_FIXED_ENDPOINT,
+	QUIRK_AUDIO_EDIROL_UA700_UA25,
+	QUIRK_AUDIO_EDIROL_UA1000,
+
+	QUIRK_TYPE_COUNT
+};
 
 typedef struct snd_usb_audio_quirk snd_usb_audio_quirk_t;
 typedef struct snd_usb_midi_endpoint_info snd_usb_midi_endpoint_info_t;
@@ -175,7 +179,7 @@
 	const char *vendor_name;
 	const char *product_name;
 	int16_t ifnum;
-	int16_t type;
+	uint16_t type;
 	const void *data;
 };
 
@@ -205,11 +209,13 @@
 
 /* for QUIRK_IGNORE_INTERFACE, data is NULL */
 
-/* for QUIRK_MIDI_NOVATION and _MOTU, data is NULL */
+/* for QUIRK_MIDI_NOVATION and _RAW, data is NULL */
 
 /* for QUIRK_MIDI_EMAGIC, data points to a snd_usb_midi_endpoint_info
  * structure (out_cables and in_cables only) */
 
+/* for QUIRK_MIDI_MIDITECH, data is NULL */
+
 /*
  */
 
diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c
index bee7006..5778a9b 100644
--- a/sound/usb/usbmidi.c
+++ b/sound/usb/usbmidi.c
@@ -524,16 +524,16 @@
 };
 
 /*
- * Mark of the Unicorn USB MIDI protocol: raw MIDI.
+ * "raw" protocol: used by the MOTU FastLane.
  */
 
-static void snd_usbmidi_motu_input(snd_usb_midi_in_endpoint_t* ep,
-				   uint8_t* buffer, int buffer_length)
+static void snd_usbmidi_raw_input(snd_usb_midi_in_endpoint_t* ep,
+				  uint8_t* buffer, int buffer_length)
 {
 	snd_usbmidi_input_data(ep, 0, buffer, buffer_length);
 }
 
-static void snd_usbmidi_motu_output(snd_usb_midi_out_endpoint_t* ep)
+static void snd_usbmidi_raw_output(snd_usb_midi_out_endpoint_t* ep)
 {
 	int count;
 
@@ -549,9 +549,9 @@
 	ep->urb->transfer_buffer_length = count;
 }
 
-static struct usb_protocol_ops snd_usbmidi_motu_ops = {
-	.input = snd_usbmidi_motu_input,
-	.output = snd_usbmidi_motu_output,
+static struct usb_protocol_ops snd_usbmidi_raw_ops = {
+	.input = snd_usbmidi_raw_input,
+	.output = snd_usbmidi_raw_output,
 };
 
 /*
@@ -1505,8 +1505,8 @@
 			umidi->usb_protocol_ops = &snd_usbmidi_novation_ops;
 			err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
 			break;
-		case QUIRK_MIDI_MOTU:
-			umidi->usb_protocol_ops = &snd_usbmidi_motu_ops;
+		case QUIRK_MIDI_RAW:
+			umidi->usb_protocol_ops = &snd_usbmidi_raw_ops;
 			err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
 			break;
 		case QUIRK_MIDI_EMAGIC:
@@ -1515,6 +1515,9 @@
 			       sizeof(snd_usb_midi_endpoint_info_t));
 			err = snd_usbmidi_detect_endpoints(umidi, &endpoints[0], 1);
 			break;
+		case QUIRK_MIDI_MIDITECH:
+			err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
+			break;
 		default:
 			snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type);
 			err = -ENXIO;
diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h
index f513564..f74e652 100644
--- a/sound/usb/usbquirks.h
+++ b/sound/usb/usbquirks.h
@@ -116,6 +116,7 @@
 YAMAHA_DEVICE(0x103a, NULL),
 YAMAHA_DEVICE(0x103b, NULL),
 YAMAHA_DEVICE(0x103c, NULL),
+YAMAHA_DEVICE(0x103d, NULL),
 YAMAHA_DEVICE(0x2000, "DGP-7"),
 YAMAHA_DEVICE(0x2001, "DGP-5"),
 YAMAHA_DEVICE(0x2002, NULL),
@@ -1259,7 +1260,12 @@
 /* Mark of the Unicorn devices */
 {
 	/* thanks to Robert A. Lerche <ral 'at' msbit.com> */
-	USB_DEVICE(0x07fd, 0x0001),
+	.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
+		       USB_DEVICE_ID_MATCH_PRODUCT |
+		       USB_DEVICE_ID_MATCH_DEV_SUBCLASS,
+	.idVendor = 0x07fd,
+	.idProduct = 0x0001,
+	.bDeviceSubClass = 2,
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "MOTU",
 		.product_name = "Fastlane",
@@ -1268,7 +1274,7 @@
 		.data = & (const snd_usb_audio_quirk_t[]) {
 			{
 				.ifnum = 0,
-				.type = QUIRK_MIDI_MOTU
+				.type = QUIRK_MIDI_RAW
 			},
 			{
 				.ifnum = 1,
@@ -1373,6 +1379,25 @@
 },
 
 {
+	USB_DEVICE(0x4752, 0x0011),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Miditech",
+		.product_name = "Midistart-2",
+		.ifnum = 0,
+		.type = QUIRK_MIDI_MIDITECH
+	}
+},
+{
+	USB_DEVICE(0x7104, 0x2202),
+	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
+		.vendor_name = "Miditech",
+		.product_name = "MidiStudio-2",
+		.ifnum = 0,
+		.type = QUIRK_MIDI_MIDITECH
+	}
+},
+
+{
 	/*
 	 * Some USB MIDI devices don't have an audio control interface,
 	 * so we have to grab MIDI streaming interfaces here.
diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c
index bef9b0c..0281a36 100644
--- a/sound/usb/usx2y/usX2Yhwdep.c
+++ b/sound/usb/usx2y/usX2Yhwdep.c
@@ -232,8 +232,7 @@
 	if (err)
 		return err;
 	if (dsp->index == 1) {
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(HZ/4);			// give the device some time 
+		msleep(250);				// give the device some time
 		err = usX2Y_AsyncSeq04_init(priv);
 		if (err) {
 			snd_printk("usX2Y_AsyncSeq04_init error \n");
diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c
index bb2c8e9..ef280612 100644
--- a/sound/usb/usx2y/usx2yhwdeppcm.c
+++ b/sound/usb/usx2y/usx2yhwdeppcm.c
@@ -50,6 +50,7 @@
    Currently rawusb dma pcm buffer transport (this file) is only available to snd-usb-usx2y. 
 */
 
+#include <linux/delay.h>
 #include "usbusx2yaudio.c"
 
 #if defined(USX2Y_NRPACKS_VARIABLE) || (!defined(USX2Y_NRPACKS_VARIABLE) &&  USX2Y_NRPACKS == 1)
@@ -520,11 +521,8 @@
 		usX2Y->hwdep_pcm_shm->playback_iso_start = -1;
 		if (atomic_read(&subs->state) < state_PREPARED) {
 			while (usX2Y_iso_frames_per_buffer(runtime, usX2Y) > usX2Y->hwdep_pcm_shm->captured_iso_frames) {
-				signed long timeout;
 				snd_printd("Wait: iso_frames_per_buffer=%i,captured_iso_frames=%i\n", usX2Y_iso_frames_per_buffer(runtime, usX2Y), usX2Y->hwdep_pcm_shm->captured_iso_frames);
-				set_current_state(TASK_INTERRUPTIBLE);
-				timeout = schedule_timeout(HZ/100 + 1);
-				if (signal_pending(current)) {
+				if (msleep_interruptible(10)) {
 					err = -ERESTARTSYS;
 					goto up_prepare_mutex;
 				}