Merge git://git.kernel.org/pub/scm/linux/kernel/git/perex/alsa

* git://git.kernel.org/pub/scm/linux/kernel/git/perex/alsa: (124 commits)
  [ALSA] version 1.0.11rc4
  [PATCH] Intruduce DMA_28BIT_MASK
  [ALSA] hda-codec - Add support for ASUS P4GPL-X
  [ALSA] hda-codec - Add support for HP nx9420 laptop
  [ALSA] Fix memory leaks in error path of control.c
  [ALSA] AMD Au1x00: AC'97 controller is memory mapped
  [ALSA] AMD Au1x00: fix DMA init/cleanup
  [ALSA] hda-codec - Fix generic auto-configurator
  [ALSA] hda-codec - Fix BIOS auto-configuration
  [ALSA] Fixes typos in Audiophile-USB.txt
  [ALSA] ice1712 - typo fixes for dxr_enable module option
  [ALSA] AMD Au1x00: make driver build after cleanup
  [ALSA] ice1712 - Fix wrong value types for enum items
  [ALSA] fix resource leak in usbmixer
  [ALSA] Fix gus_pcm dereference before NULL
  [ALSA] Fix seq_clientmgr dereferences before NULL check
  [ALSA] hda-codec - Fix for Samsung R65 and ASUS A6J
  [ALSA] hda-codec - Add support for VAIO FE550G and SZ110
  [ALSA] usb-audio: add Maya44 mixer control names
  [ALSA] usb-audio: add Casio PL-40R support
  ...
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index 36b511c..1def604 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -513,6 +513,8 @@
 
     This module supports multiple cards and autoprobe.
     
+    The power-management is supported.
+
   Module snd-ens1371
   ------------------
 
@@ -526,6 +528,8 @@
 
     This module supports multiple cards and autoprobe.
     
+    The power-management is supported.
+
   Module snd-es968
   ----------------
 
@@ -671,6 +675,8 @@
 
     model	- force the model name
     position_fix - Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)
+    single_cmd  - Use single immediate commands to communicate with
+		codecs (for debugging only)
 
     This module supports one card and autoprobe.
 
@@ -694,13 +700,34 @@
 	  asus		3-jack
 	  uniwill	3-jack
 	  F1734		2-jack
+	  lg		LG laptop (m1 express dual)
 	  test		for testing/debugging purpose, almost all controls can be
 			adjusted.  Appearing only when compiled with
 			$CONFIG_SND_DEBUG=y
+	  auto		auto-config reading BIOS (default)
 
 	ALC260
 	  hp		HP machines
 	  fujitsu	Fujitsu S7020
+	  acer		Acer TravelMate
+	  basic		fixed pin assignment (old default model)
+	  auto		auto-config reading BIOS (default)
+
+	ALC262
+	  fujitsu	Fujitsu Laptop
+	  basic		fixed pin assignment w/o SPDIF
+	  auto		auto-config reading BIOS (default)
+
+	ALC882/883/885
+	  3stack-dig	3-jack with SPDIF I/O
+	  6stck-dig	6-jack digital with SPDIF I/O
+	  auto		auto-config reading BIOS (default)
+
+	ALC861
+	  3stack	3-jack
+	  3stack-dig	3-jack with SPDIF I/O
+	  6stack-dig	6-jack with SPDIF I/O
+	  auto		auto-config reading BIOS (default)
 
 	CMI9880
 	  minimal	3-jack in back
@@ -710,6 +737,28 @@
 	  allout	5-jack in back, 2-jack in front, SPDIF out
 	  auto		auto-config reading BIOS (default)
 
+	AD1981
+	  basic		3-jack (default)
+	  hp		HP nx6320
+
+	AD1986A
+	  6stack	6-jack, separate surrounds (default)
+	  3stack	3-stack, shared surrounds
+	  laptop	2-channel only (FSC V2060, Samsung M50)
+	  laptop-eapd	2-channel with EAPD (Samsung R65, ASUS A6J)
+
+	AD1988
+	  6stack	6-jack
+	  6stack-dig	ditto with SPDIF
+	  3stack	3-jack
+	  3stack-dig	ditto with SPDIF
+	  laptop	3-jack with hp-jack automute
+	  laptop-dig	ditto with SPDIF
+	  auto		auto-confgi reading BIOS (default)
+
+	STAC7661(?)
+	  vaio		Setup for VAIO FE550G/SZ110
+
     If the default configuration doesn't work and one of the above
     matches with your device, report it together with the PCI
     subsystem ID (output of "lspci -nv") to ALSA BTS or alsa-devel
@@ -723,6 +772,17 @@
 	    (Usually SD_LPLIB register is more accurate than the
 	    position buffer.)
 
+    NB: If you get many "azx_get_response timeout" messages at
+    loading, it's likely a problem of interrupts (e.g. ACPI irq
+    routing).  Try to boot with options like "pci=noacpi".  Also, you
+    can try "single_cmd=1" module option.  This will switch the
+    communication method between HDA controller and codecs to the
+    single immediate commands instead of CORB/RIRB.  Basically, the
+    single command mode is provided only for BIOS, and you won't get
+    unsolicited events, too.  But, at least, this works independently
+    from the irq.  Remember this is a last resort, and should be
+    avoided as much as possible...
+    
     The power-management is supported.
 
   Module snd-hdsp
@@ -802,6 +862,7 @@
   ------------------
 
     Module for Envy24HT (VT/ICE1724), Envy24PT (VT1720) based PCI sound cards.
+			* MidiMan M Audio Revolution 5.1
 			* MidiMan M Audio Revolution 7.1
 			* AMP Ltd AUDIO2000
 			* TerraTec Aureon 5.1 Sky
@@ -810,6 +871,7 @@
 			* TerraTec Phase 22
 			* TerraTec Phase 28
 			* AudioTrak Prodigy 7.1
+			* AudioTrak Prodigy 7.1LT
 			* AudioTrak Prodigy 192
 			* Pontis MS300
 			* Albatron K8X800 Pro II 
@@ -820,9 +882,9 @@
 			* Shuttle SN25P
 
     model       - Use the given board model, one of the following:
-		  revo71, amp2000, prodigy71, prodigy192, aureon51,
-		  aureon71, universe, k8x800, phase22, phase28, ms300,
-		  av710
+		  revo51, revo71, amp2000, prodigy71, prodigy71lt,
+		  prodigy192, aureon51, aureon71, universe,
+		  k8x800, phase22, phase28, ms300, av710
 
     This module supports multiple cards and autoprobe.
 
@@ -1353,6 +1415,9 @@
 
     vid             - Vendor ID for the device (optional)
     pid             - Product ID for the device (optional)
+    device_setup    - Device specific magic number (optional)
+                    - Influence depends on the device
+                    - Default: 0x0000 
 
     This module supports multiple devices, autoprobe and hotplugging.
 
diff --git a/Documentation/sound/alsa/Audiophile-Usb.txt b/Documentation/sound/alsa/Audiophile-Usb.txt
new file mode 100644
index 0000000..4692c8e
--- /dev/null
+++ b/Documentation/sound/alsa/Audiophile-Usb.txt
@@ -0,0 +1,333 @@
+	Guide to using M-Audio Audiophile USB with ALSA and Jack	v1.2
+	========================================================
+
+	    Thibault Le Meur <Thibault.LeMeur@supelec.fr>
+
+This document is a guide to using the M-Audio Audiophile USB (tm) device with 
+ALSA and JACK.
+
+1 - Audiophile USB Specs and correct usage
+==========================================
+This part is a reminder of important facts about the functions and limitations 
+of the device.
+
+The device has 4 audio interfaces, and 2 MIDI ports:
+ * Analog Stereo Input (Ai)
+   - This port supports 2 pairs of line-level audio inputs (1/4" TS and RCA) 
+   - When the 1/4" TS (jack) connectors are connected, the RCA connectors
+     are disabled
+ * Analog Stereo Output (Ao)
+ * Digital Stereo Input (Di)
+ * Digital Stereo Output (Do)
+ * Midi In (Mi)
+ * Midi Out (Mo)
+
+The internal DAC/ADC has the following caracteristics:
+* sample depth of 16 or 24 bits
+* sample rate from 8kHz to 96kHz
+* Two ports can't use different sample depths at the same time.Moreover, the 
+Audiophile USB documentation gives the following Warning: "Please exit any 
+audio application running before switching between bit depths"
+
+Due to the USB 1.1 bandwidth limitation, a limited number of interfaces can be 
+activated at the same time depending on the audio mode selected:
+ * 16-bit/48kHz ==> 4 channels in/ 4 channels out
+   - Ai+Ao+Di+Do
+ * 24-bit/48kHz ==> 4 channels in/2 channels out, 
+                    or 2 channels in/4 channels out
+   - Ai+Ao+Do or Ai+Di+Ao or Ai+Di+Do or Di+Ao+Do
+ * 24-bit/96kHz ==> 2 channels in, or 2 channels out (half duplex only)
+   - Ai or Ao or Di or Do
+
+Important facts about the Digital interface:
+--------------------------------------------
+ * The Do port additionnaly supports surround-encoded AC-3 and DTS passthrough, 
+though I haven't tested it under linux
+   - Note that in this setup only the Do interface can be enabled
+ * Apart from recording an audio digital stream, enabling the Di port is a way 
+to synchronize the device to an external sample clock
+   - As a consequence, the Di port must be enable only if an active Digital 
+source is connected
+   - Enabling Di when no digital source is connected can result in a 
+synchronization error (for instance sound played at an odd sample rate)
+
+
+2 - Audiophile USB support in ALSA
+==================================
+
+2.1 - MIDI ports
+----------------
+The Audiophile USB MIDI ports will be automatically supported once the 
+following modules have been loaded:
+ * snd-usb-audio
+ * snd-seq
+ * snd-seq-midi
+
+No additionnal setting is required.
+
+2.2 - Audio ports
+-----------------
+
+Audio functions of the Audiophile USB device are handled by the snd-usb-audio 
+module. This module can work in a default mode (without any device-specific 
+parameter), or in an advanced mode with the device-specific parameter called 
+"device_setup".
+
+2.2.1 - Default Alsa driver mode
+
+The default behaviour of the snd-usb-audio driver is to parse the device 
+capabilities at startup and enable all functions inside the device (including 
+all ports at any sample rates and any sample depths supported). This approach 
+has the advantage to let the driver easily switch from sample rates/depths 
+automatically according to the need of the application claiming the device.
+
+In this case the Audiophile ports are mapped to alsa pcm devices in the 
+following way (I suppose the device's index is 1):
+ * hw:1,0 is Ao in playback and Di in capture
+ * hw:1,1 is Do in playback and Ai in capture
+ * hw:1,2 is Do in AC3/DTS passthrough mode
+
+You must note as well that the device uses Big Endian byte encoding so that 
+supported audio format are S16_BE  for 16-bit depth modes and S24_3BE for 
+24-bits depth mode. One exception is the hw:1,2 port which is Little Endian 
+compliant and thus uses S16_LE.
+
+Examples:
+ * playing a S24_3BE encoded raw file to the Ao port
+   % aplay -D hw:1,0 -c2 -t raw -r48000 -fS24_3BE test.raw
+ * recording a  S24_3BE encoded raw file from the Ai port
+   % arecord -D hw:1,1 -c2  -t raw -r48000 -fS24_3BE test.raw
+ * playing a S16_BE encoded raw file to the Do port
+   % aplay -D hw:1,1 -c2 -t raw -r48000 -fS16_BE test.raw
+
+If you're happy with the default Alsa driver setup and don't experience any 
+issue with this mode, then you can skip the following chapter.
+
+2.2.2 - Advanced module setup
+
+Due to the hardware constraints described above, the device initialization made 
+by the Alsa driver in default mode may result in a corrupted state of the 
+device. For instance, a particularly annoying issue is that the sound captured 
+from the Ai port sounds distorted (as if boosted with an excessive high volume 
+gain).
+
+For people having this problem, the snd-usb-audio module has a new module 
+parameter called "device_setup".
+
+2.2.2.1 - Initializing the working mode of the Audiohile USB
+
+As far as the Audiohile USB device is concerned, this value let the user 
+specify:
+ * the sample depth
+ * the sample rate
+ * whether the Di port is used or not 
+
+Here is a list of supported device_setup values for this device:
+ * device_setup=0x00 (or omitted)
+   - Alsa driver default mode
+   - maintains backward compatibility with setups that do not use this 
+     parameter by not introducing any change
+   - results sometimes in corrupted sound as decribed earlier
+ * device_setup=0x01
+   - 16bits 48kHz mode with Di disabled
+   - Ai,Ao,Do can be used at the same time
+   - hw:1,0 is not available in capture mode
+   - hw:1,2 is not available
+ * device_setup=0x11
+   - 16bits 48kHz mode with Di enabled
+   - Ai,Ao,Di,Do can be used at the same time
+   - hw:1,0 is available in capture mode
+   - hw:1,2 is not available
+ * device_setup=0x09
+   - 24bits 48kHz mode with Di disabled
+   - Ai,Ao,Do can be used at the same time
+   - hw:1,0 is not available in capture mode
+   - hw:1,2 is not available
+ * device_setup=0x19
+   - 24bits 48kHz mode with Di enabled
+   - 3 ports from {Ai,Ao,Di,Do} can be used at the same time
+   - hw:1,0 is available in capture mode and an active digital source must be 
+     connected to Di
+   - hw:1,2 is not available
+ * device_setup=0x0D or 0x10
+   - 24bits 96kHz mode
+   - Di is enabled by default for this mode but does not need to be connected 
+     to an active source
+   - Only 1 port from {Ai,Ao,Di,Do} can be used at the same time
+   - hw:1,0 is available in captured mode
+   - hw:1,2 is not available
+ * device_setup=0x03
+   - 16bits 48kHz mode with only the Do port enabled 
+   - AC3 with DTS passthru (not tested)
+   - Caution with this setup the Do port is mapped to the pcm device hw:1,0
+
+2.2.2.2 - Setting and switching configurations with the device_setup parameter
+
+The parameter can be given:
+ * By manually probing the device (as root):
+   # modprobe -r snd-usb-audio
+   # modprobe snd-usb-audio index=1 device_setup=0x09
+ * Or while configuring the modules options in your modules configuration file
+   - For Fedora distributions, edit the /etc/modprobe.conf file:
+       alias snd-card-1 snd-usb-audio
+       options snd-usb-audio index=1 device_setup=0x09
+
+IMPORTANT NOTE WHEN SWITCHING CONFIGURATION:
+-------------------------------------------
+ * You may need to _first_ intialize the module with the correct device_setup 
+   parameter and _only_after_ turn on the Audiophile USB device
+ * This is especially true when switching the sample depth:
+   - first trun off the device
+   - de-register the snd-usb-audio module
+   - change the device_setup parameter (by either manually reprobing the module 
+     or changing modprobe.conf)
+   - turn on the device
+
+2.2.2.3 - Audiophile USB's device_setup structure
+
+If you want to understand the device_setup magic numbers for the Audiophile 
+USB, you need some very basic understanding of binary computation. However, 
+this is not required to use the parameter and you may skip thi section.
+
+The device_setup is one byte long and its structure is the following:
+
+       +---+---+---+---+---+---+---+---+
+       | b7| b6| b5| b4| b3| b2| b1| b0|
+       +---+---+---+---+---+---+---+---+
+       | 0 | 0 | 0 | Di|24B|96K|DTS|SET|
+       +---+---+---+---+---+---+---+---+
+
+Where:
+ * b0 is the "SET" bit
+   - it MUST be set if device_setup is initialized 
+ * b1 is the "DTS" bit
+   - it is set only for Digital output with DTS/AC3
+   - this setup is not tested
+ * b2 is the Rate selection flag
+   - When set to "1" the rate range is 48.1-96kHz
+   - Otherwise the sample rate range is 8-48kHz
+ * b3 is the bit depth selection flag
+   - When set to "1" samples are 24bits long
+   - Otherwise they are 16bits long
+   - Note that b2 implies b3 as the 96kHz mode is only supported for 24 bits 
+     samples
+ * b4 is the Digital input flag
+   - When set to "1" the device assumes that an active digital source is 
+     connected 
+   - You shouldn't enable Di if no source is seen on the port (this leads to 
+     synchronization issues)
+   - b4 is implied by b2 (since only one port is enabled at a time no synch 
+     error can occur) 
+ * b5 to b7 are reserved for future uses, and must be set to "0"
+   - might become Ao, Do, Ai, for b7, b6, b4 respectively
+
+Caution:
+ * there is no check on the value you will give to device_setup
+   - for instance choosing 0x05 (16bits 96kHz) will fail back to 0x09 since 
+     b2 implies b3. But _there_will_be_no_warning_ in /var/log/messages
+ * Hardware constraints due to the USB bus limitation aren't checked
+   - choosing b2 will prepare all interfaces for 24bits/96kHz but you'll
+     only be able to use one at the same time
+
+2.2.3 -  USB implementation details for this device
+
+You may safely skip this section if you're not interrested in driver 
+development.
+
+This section describes some internals aspect of the device and summarize the 
+data I got by usb-snooping the windows and linux drivers.
+
+The M-Audio Audiophile USB has 7 USB Interfaces:
+a "USB interface":
+ * USB Interface nb.0
+ * USB Interface nb.1
+   - Audio Control function
+ * USB Interface nb.2
+   - Analog Output
+ * USB Interface nb.3
+   - Digital Output
+ * USB Interface nb.4
+   - Analog Input
+ * USB Interface nb.5
+   - Digital Input
+ * USB Interface nb.6
+   - MIDI interface compliant with the MIDIMAN quirk 
+
+Each interface has 5 altsettings (AltSet 1,2,3,4,5) except:
+ * Interface 3 (Digital Out) has an extra Alset nb.6 
+ * Interface 5 (Digital In) does not have Alset nb.3 and 5 
+
+Here is a short description of the AltSettings capabilities:
+ * AltSettings 1 corresponds to
+  - 24-bit depth, 48.1-96kHz sample mode
+  - Adaptive playback (Ao and Do), Synch capture (Ai), or Asynch capture (Di)
+ * AltSettings 2 corresponds to
+  - 24-bit depth, 8-48kHz sample mode
+  - Asynch capture and playback  (Ao,Ai,Do,Di)
+ * AltSettings 3 corresponds to
+  - 24-bit depth, 8-48kHz sample mode
+  - Synch capture (Ai) and Adaptive playback (Ao,Do)
+ * AltSettings 4 corresponds to
+  - 16-bit depth, 8-48kHz sample mode
+  - Asynch capture and playback  (Ao,Ai,Do,Di)
+ * AltSettings 5 corresponds to
+  - 16-bit depth, 8-48kHz sample mode
+  - Synch capture (Ai) and Adaptive playback (Ao,Do)
+ * AltSettings 6 corresponds to
+  - 16-bit depth, 8-48kHz sample mode
+  - Synch playback (Do), audio format type III IEC1937_AC-3
+
+In order to ensure a correct intialization of the device, the driver 
+_must_know_ how the device will be used:
+ * if DTS is choosen, only Interface 2 with AltSet nb.6 must be
+   registered
+ * if 96KHz only AltSets nb.1 of each interface must be selected
+ * if samples are using 24bits/48KHz then AltSet 2 must me used if
+   Digital input is connected, and only AltSet nb.3 if Digital input
+   is not connected
+ * if samples are using 16bits/48KHz then AltSet 4 must me used if
+   Digital input is connected, and only AltSet nb.5 if Digital input
+   is not connected
+
+When device_setup is given as a parameter to the snd-usb-audio module, the 
+parse_audio_enpoint function uses a quirk called 
+"audiophile_skip_setting_quirk" in order to prevent AltSettings not 
+corresponding to device_setup from being registered in the driver.
+
+3 - Audiophile USB and Jack support
+===================================
+
+This section deals with support of the Audiophile USB device in Jack.
+The main issue regarding this support is that the device is Big Endian 
+compliant.
+
+3.1 - Using the plug alsa plugin
+--------------------------------
+
+Jack doesn't directly support big endian devices. Thus, one way to have support 
+for this device with Alsa is to use the Alsa "plug" converter.
+
+For instance here is one way to run Jack with 2 playback channels on Ao and 2 
+capture channels from Ai:
+  % jackd -R -dalsa -dplughw:1 -r48000 -p256 -n2 -D -Cplughw:1,1
+
+
+However you may see the following warning message:
+"You appear to be using the ALSA software "plug" layer, probably a result of 
+using the "default" ALSA device. This is less efficient than it could be. 
+Consider using a hardware device instead rather than using the plug layer."
+
+
+3.2 - Patching alsa to use direct pcm device
+-------------------------------------------
+A patch for Jack by Andreas Steinmetz adds support for Big Endian devices. 
+However it has not been included in the CVS tree.
+
+You can find it at the following URL:
+http://sourceforge.net/tracker/index.php?func=detail&aid=1289682&group_id=39687&
+atid=425939
+
+After having applied the patch you can run jackd with the following command 
+line:
+  % jackd -R -dalsa -Phw:1,0 -r48000 -p128 -n2 -D -Chw:1,1
+
diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
index 4251085..6dc9d9f 100644
--- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
+++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
@@ -1834,7 +1834,7 @@
           mychip_set_sample_format(chip, runtime->format);
           mychip_set_sample_rate(chip, runtime->rate);
           mychip_set_channels(chip, runtime->channels);
-          mychip_set_dma_setup(chip, runtime->dma_area,
+          mychip_set_dma_setup(chip, runtime->dma_addr,
                                chip->buffer_size,
                                chip->period_size);
           return 0;
@@ -3388,7 +3388,7 @@
           .name = "PCM Playback Switch",
           .index = 0,
           .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
-          .private_values = 0xffff,
+          .private_value = 0xffff,
           .info = my_control_info,
           .get = my_control_get,
           .put = my_control_put
@@ -3449,7 +3449,7 @@
       </para>
 
       <para>
-        The <structfield>private_values</structfield> field contains
+        The <structfield>private_value</structfield> field contains
       an arbitrary long integer value for this record. When using
       generic <structfield>info</structfield>,
       <structfield>get</structfield> and
diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c
index d5bda60..98356f8 100644
--- a/arch/arm/mach-pxa/mainstone.c
+++ b/arch/arm/mach-pxa/mainstone.c
@@ -157,14 +157,14 @@
 	.resource	= smc91x_resources,
 };
 
-static int mst_audio_startup(snd_pcm_substream_t *substream, void *priv)
+static int mst_audio_startup(struct snd_pcm_substream *substream, void *priv)
 {
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		MST_MSCWR2 &= ~MST_MSCWR2_AC97_SPKROFF;
 	return 0;
 }
 
-static void mst_audio_shutdown(snd_pcm_substream_t *substream, void *priv)
+static void mst_audio_shutdown(struct snd_pcm_substream *substream, void *priv)
 {
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 		MST_MSCWR2 |= MST_MSCWR2_AC97_SPKROFF;
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
index bffef1d..3170b8f 100644
--- a/drivers/media/video/cx88/cx88-alsa.c
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -63,7 +63,7 @@
 	/* audio controls */
 	int                        irq;
 
-	snd_card_t                 *card;
+	struct snd_card            *card;
 
 	spinlock_t                 reg_lock;
 
@@ -82,7 +82,7 @@
 	struct cx88_buffer   *buf;
 
 	long opened;
-	snd_pcm_substream_t *substream;
+	struct snd_pcm_substream *substream;
 
 };
 typedef struct cx88_audio_dev snd_cx88_card_t;
@@ -96,7 +96,7 @@
 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] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
-static snd_card_t *snd_cx88_cards[SNDRV_CARDS];
+static struct snd_card *snd_cx88_cards[SNDRV_CARDS];
 
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable cx88x soundcard. default enabled.");
@@ -320,7 +320,7 @@
 /*
  * Digital hardware definition
  */
-static snd_pcm_hardware_t snd_cx88_digital_hw = {
+static struct snd_pcm_hardware snd_cx88_digital_hw = {
 	.info = SNDRV_PCM_INFO_MMAP |
 		SNDRV_PCM_INFO_INTERLEAVED |
 		SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -342,16 +342,16 @@
 /*
  * audio pcm capture runtime free
  */
-static void snd_card_cx88_runtime_free(snd_pcm_runtime_t *runtime)
+static void snd_card_cx88_runtime_free(struct snd_pcm_runtime *runtime)
 {
 }
 /*
  * audio pcm capture open callback
  */
-static int snd_cx88_pcm_open(snd_pcm_substream_t *substream)
+static int snd_cx88_pcm_open(struct snd_pcm_substream *substream)
 {
 	snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
-	snd_pcm_runtime_t *runtime = substream->runtime;
+	struct snd_pcm_runtime *runtime = substream->runtime;
 	int err;
 
 	if (test_and_set_bit(0, &chip->opened))
@@ -380,7 +380,7 @@
 /*
  * audio close callback
  */
-static int snd_cx88_close(snd_pcm_substream_t *substream)
+static int snd_cx88_close(struct snd_pcm_substream *substream)
 {
 	snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
 
@@ -393,8 +393,8 @@
 /*
  * hw_params callback
  */
-static int snd_cx88_hw_params(snd_pcm_substream_t * substream,
-				 snd_pcm_hw_params_t * hw_params)
+static int snd_cx88_hw_params(struct snd_pcm_substream * substream,
+			      struct snd_pcm_hw_params * hw_params)
 {
 	snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
 	struct cx88_buffer *buf;
@@ -453,7 +453,7 @@
 /*
  * hw free callback
  */
-static int snd_cx88_hw_free(snd_pcm_substream_t * substream)
+static int snd_cx88_hw_free(struct snd_pcm_substream * substream)
 {
 
 	snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
@@ -469,7 +469,7 @@
 /*
  * prepare callback
  */
-static int snd_cx88_prepare(snd_pcm_substream_t *substream)
+static int snd_cx88_prepare(struct snd_pcm_substream *substream)
 {
 	return 0;
 }
@@ -478,7 +478,7 @@
 /*
  * trigger callback
  */
-static int snd_cx88_card_trigger(snd_pcm_substream_t *substream, int cmd)
+static int snd_cx88_card_trigger(struct snd_pcm_substream *substream, int cmd)
 {
 	snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
 	int err;
@@ -505,10 +505,10 @@
 /*
  * pointer callback
  */
-static snd_pcm_uframes_t snd_cx88_pointer(snd_pcm_substream_t *substream)
+static snd_pcm_uframes_t snd_cx88_pointer(struct snd_pcm_substream *substream)
 {
 	snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
-	snd_pcm_runtime_t *runtime = substream->runtime;
+	struct snd_pcm_runtime *runtime = substream->runtime;
 
 	if (chip->read_count) {
 		chip->read_count -= snd_pcm_lib_period_bytes(substream);
@@ -525,7 +525,7 @@
 /*
  * operators
  */
-static snd_pcm_ops_t snd_cx88_pcm_ops = {
+static struct snd_pcm_ops snd_cx88_pcm_ops = {
 	.open = snd_cx88_pcm_open,
 	.close = snd_cx88_close,
 	.ioctl = snd_pcm_lib_ioctl,
@@ -542,7 +542,7 @@
 static int __devinit snd_cx88_pcm(snd_cx88_card_t *chip, int device, char *name)
 {
 	int err;
-	snd_pcm_t *pcm;
+	struct snd_pcm *pcm;
 
 	err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm);
 	if (err < 0)
@@ -557,7 +557,8 @@
 /****************************************************************************
 				CONTROL INTERFACE
  ****************************************************************************/
-static int snd_cx88_capture_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *info)
+static int snd_cx88_capture_volume_info(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_info *info)
 {
 	info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 	info->count = 1;
@@ -568,7 +569,8 @@
 }
 
 /* OK - TODO: test it */
-static int snd_cx88_capture_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value)
+static int snd_cx88_capture_volume_get(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *value)
 {
 	snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
 	struct cx88_core *core=chip->core;
@@ -579,7 +581,8 @@
 }
 
 /* OK - TODO: test it */
-static int snd_cx88_capture_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value)
+static int snd_cx88_capture_volume_put(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *value)
 {
 	snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
 	struct cx88_core *core=chip->core;
@@ -595,7 +598,7 @@
 	return v != old_control;
 }
 
-static snd_kcontrol_new_t snd_cx88_capture_volume = {
+static struct snd_kcontrol_new snd_cx88_capture_volume = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Capture Volume",
 	.info = snd_cx88_capture_volume_info,
@@ -641,7 +644,7 @@
 /*
  * Component Destructor
  */
-static void snd_cx88_dev_free(snd_card_t * card)
+static void snd_cx88_dev_free(struct snd_card * card)
 {
 	snd_cx88_card_t *chip = card->private_data;
 
@@ -654,8 +657,9 @@
  */
 
 static int devno;
-static int __devinit snd_cx88_create(snd_card_t *card, struct pci_dev *pci,
-				    snd_cx88_card_t **rchip)
+static int __devinit snd_cx88_create(struct snd_card *card,
+				     struct pci_dev *pci,
+				     snd_cx88_card_t **rchip)
 {
 	snd_cx88_card_t   *chip;
 	struct cx88_core  *core;
@@ -726,7 +730,7 @@
 static int __devinit cx88_audio_initdev(struct pci_dev *pci,
 				    const struct pci_device_id *pci_id)
 {
-	snd_card_t       *card;
+	struct snd_card  *card;
 	snd_cx88_card_t  *chip;
 	int              err;
 
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index 64e2c10..aca84d2 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -71,7 +71,7 @@
  */
 
 typedef struct snd_card_saa7134 {
-	snd_card_t *card;
+	struct snd_card *card;
 	spinlock_t mixer_lock;
 	int mixer_volume[MIXER_ADDR_LAST+1][2];
 	int capture_source[MIXER_ADDR_LAST+1][2];
@@ -95,10 +95,10 @@
 
 	spinlock_t lock;
 
-	snd_pcm_substream_t *substream;
+	struct snd_pcm_substream *substream;
 } snd_card_saa7134_pcm_t;
 
-static snd_card_t *snd_saa7134_cards[SNDRV_CARDS];
+static struct snd_card *snd_saa7134_cards[SNDRV_CARDS];
 
 
 /*
@@ -251,10 +251,10 @@
  *
  */
 
-static int snd_card_saa7134_capture_trigger(snd_pcm_substream_t * substream,
+static int snd_card_saa7134_capture_trigger(struct snd_pcm_substream * substream,
 					  int cmd)
 {
-	snd_pcm_runtime_t *runtime = substream->runtime;
+	struct snd_pcm_runtime *runtime = substream->runtime;
 	snd_card_saa7134_pcm_t *pcm = runtime->private_data;
 	struct saa7134_dev *dev=pcm->dev;
 	int err = 0;
@@ -332,9 +332,9 @@
  *
  */
 
-static int snd_card_saa7134_capture_prepare(snd_pcm_substream_t * substream)
+static int snd_card_saa7134_capture_prepare(struct snd_pcm_substream * substream)
 {
-	snd_pcm_runtime_t *runtime = substream->runtime;
+	struct snd_pcm_runtime *runtime = substream->runtime;
 	int bswap, sign;
 	u32 fmt, control;
 	snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
@@ -421,9 +421,10 @@
  *
  */
 
-static snd_pcm_uframes_t snd_card_saa7134_capture_pointer(snd_pcm_substream_t * substream)
+static snd_pcm_uframes_t
+snd_card_saa7134_capture_pointer(struct snd_pcm_substream * substream)
 {
-	snd_pcm_runtime_t *runtime = substream->runtime;
+	struct snd_pcm_runtime *runtime = substream->runtime;
 	snd_card_saa7134_pcm_t *pcm = runtime->private_data;
 	struct saa7134_dev *dev=pcm->dev;
 
@@ -441,7 +442,7 @@
  * ALSA hardware capabilities definition
  */
 
-static snd_pcm_hardware_t snd_card_saa7134_capture =
+static struct snd_pcm_hardware snd_card_saa7134_capture =
 {
 	.info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -464,7 +465,7 @@
 	.periods_max =		1024,
 };
 
-static void snd_card_saa7134_runtime_free(snd_pcm_runtime_t *runtime)
+static void snd_card_saa7134_runtime_free(struct snd_pcm_runtime *runtime)
 {
 	snd_card_saa7134_pcm_t *pcm = runtime->private_data;
 
@@ -481,8 +482,8 @@
  *
  */
 
-static int snd_card_saa7134_hw_params(snd_pcm_substream_t * substream,
-				    snd_pcm_hw_params_t * hw_params)
+static int snd_card_saa7134_hw_params(struct snd_pcm_substream * substream,
+				      struct snd_pcm_hw_params * hw_params)
 {
 	snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
 	struct saa7134_dev *dev;
@@ -561,7 +562,7 @@
  *
  */
 
-static int snd_card_saa7134_hw_free(snd_pcm_substream_t * substream)
+static int snd_card_saa7134_hw_free(struct snd_pcm_substream * substream)
 {
 	snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
 	struct saa7134_dev *dev;
@@ -587,7 +588,7 @@
  *
  */
 
-static int snd_card_saa7134_capture_close(snd_pcm_substream_t * substream)
+static int snd_card_saa7134_capture_close(struct snd_pcm_substream * substream)
 {
 	return 0;
 }
@@ -602,9 +603,9 @@
  *
  */
 
-static int snd_card_saa7134_capture_open(snd_pcm_substream_t * substream)
+static int snd_card_saa7134_capture_open(struct snd_pcm_substream * substream)
 {
-	snd_pcm_runtime_t *runtime = substream->runtime;
+	struct snd_pcm_runtime *runtime = substream->runtime;
 	snd_card_saa7134_pcm_t *pcm;
 	snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
 	struct saa7134_dev *dev = saa7134->dev;
@@ -640,7 +641,7 @@
  * ALSA capture callbacks definition
  */
 
-static snd_pcm_ops_t snd_card_saa7134_capture_ops = {
+static struct snd_pcm_ops snd_card_saa7134_capture_ops = {
 	.open =			snd_card_saa7134_capture_open,
 	.close =		snd_card_saa7134_capture_close,
 	.ioctl =		snd_pcm_lib_ioctl,
@@ -661,7 +662,7 @@
 
 static int snd_card_saa7134_pcm(snd_card_saa7134_t *saa7134, int device)
 {
-	snd_pcm_t *pcm;
+	struct snd_pcm *pcm;
 	int err;
 
 	if ((err = snd_pcm_new(saa7134->card, "SAA7134 PCM", device, 0, 1, &pcm)) < 0)
@@ -679,7 +680,8 @@
   .get = snd_saa7134_volume_get, .put = snd_saa7134_volume_put, \
   .private_value = addr }
 
-static int snd_saa7134_volume_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
+static int snd_saa7134_volume_info(struct snd_kcontrol * kcontrol,
+				   struct snd_ctl_elem_info * uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 	uinfo->count = 2;
@@ -688,7 +690,8 @@
 	return 0;
 }
 
-static int snd_saa7134_volume_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static int snd_saa7134_volume_get(struct snd_kcontrol * kcontrol,
+				  struct snd_ctl_elem_value * ucontrol)
 {
 	snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
 	int addr = kcontrol->private_value;
@@ -698,7 +701,8 @@
 	return 0;
 }
 
-static int snd_saa7134_volume_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static int snd_saa7134_volume_put(struct snd_kcontrol * kcontrol,
+				  struct snd_ctl_elem_value * ucontrol)
 {
 	snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
 	int change, addr = kcontrol->private_value;
@@ -729,7 +733,8 @@
   .get = snd_saa7134_capsrc_get, .put = snd_saa7134_capsrc_put, \
   .private_value = addr }
 
-static int snd_saa7134_capsrc_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
+static int snd_saa7134_capsrc_info(struct snd_kcontrol * kcontrol,
+				   struct snd_ctl_elem_info * uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
 	uinfo->count = 2;
@@ -738,7 +743,8 @@
 	return 0;
 }
 
-static int snd_saa7134_capsrc_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static int snd_saa7134_capsrc_get(struct snd_kcontrol * kcontrol,
+				  struct snd_ctl_elem_value * ucontrol)
 {
 	snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
 	int addr = kcontrol->private_value;
@@ -751,7 +757,8 @@
 	return 0;
 }
 
-static int snd_saa7134_capsrc_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+static int snd_saa7134_capsrc_put(struct snd_kcontrol * kcontrol,
+				  struct snd_ctl_elem_value * ucontrol)
 {
 	snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
 	int change, addr = kcontrol->private_value;
@@ -828,7 +835,7 @@
 	return change;
 }
 
-static snd_kcontrol_new_t snd_saa7134_controls[] = {
+static struct snd_kcontrol_new snd_saa7134_controls[] = {
 SAA713x_VOLUME("Video Volume", 0, MIXER_ADDR_TVTUNER),
 SAA713x_CAPSRC("Video Capture Switch", 0, MIXER_ADDR_TVTUNER),
 SAA713x_VOLUME("Line Volume", 1, MIXER_ADDR_LINE1),
@@ -847,7 +854,7 @@
 
 static int snd_card_saa7134_new_mixer(snd_card_saa7134_t * chip)
 {
-	snd_card_t *card = chip->card;
+	struct snd_card *card = chip->card;
 	unsigned int idx;
 	int err;
 
@@ -861,7 +868,7 @@
 	return 0;
 }
 
-static void snd_saa7134_free(snd_card_t * card)
+static void snd_saa7134_free(struct snd_card * card)
 {
 	snd_card_saa7134_t *chip = card->private_data;
 
@@ -888,7 +895,7 @@
 static int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum)
 {
 
-	snd_card_t *card;
+	struct snd_card *card;
 	snd_card_saa7134_t *chip;
 	int err;
 
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 17ba34f..ce1c2e0 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -397,7 +397,7 @@
 	unsigned int               read_offset;
 	unsigned int               read_count;
 	void *			   priv_data;
-	snd_pcm_substream_t 	   *substream;
+	struct snd_pcm_substream   *substream;
 };
 
 /* IR input */
diff --git a/include/asm-arm/arch-pxa/audio.h b/include/asm-arm/arch-pxa/audio.h
index 60976f8..17eccd7 100644
--- a/include/asm-arm/arch-pxa/audio.h
+++ b/include/asm-arm/arch-pxa/audio.h
@@ -6,8 +6,8 @@
 #include <sound/pcm.h>
 
 typedef struct {
-	int (*startup)(snd_pcm_substream_t *, void *);
-	void (*shutdown)(snd_pcm_substream_t *, void *);
+	int (*startup)(struct snd_pcm_substream *, void *);
+	void (*shutdown)(struct snd_pcm_substream *, void *);
 	void (*suspend)(void *);
 	void (*resume)(void *);
 	void *priv;
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index 2d80cc7..a873106 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -20,6 +20,7 @@
 #define DMA_31BIT_MASK	0x000000007fffffffULL
 #define DMA_30BIT_MASK	0x000000003fffffffULL
 #define DMA_29BIT_MASK	0x000000001fffffffULL
+#define DMA_28BIT_MASK	0x000000000fffffffULL
 
 #include <asm/dma-mapping.h>
 
diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h
index b0b3ea7..b45a737 100644
--- a/include/sound/ac97_codec.h
+++ b/include/sound/ac97_codec.h
@@ -433,6 +433,12 @@
 	struct snd_info_entry *proc;
 };
 
+/* static resolution table */
+struct snd_ac97_res_table {
+	unsigned short reg;	/* register */
+	unsigned short bits;	/* resolution bitmask */
+};
+
 struct snd_ac97_template {
 	void *private_data;
 	void (*private_free) (struct snd_ac97 *ac97);
@@ -440,8 +446,7 @@
 	unsigned short num;	/* number of codec: 0 = primary, 1 = secondary */
 	unsigned short addr;	/* physical address of codec [0-3] */
 	unsigned int scaps;	/* driver capabilities */
-	unsigned int limited_regs; /* allow limited registers only */
-	DECLARE_BITMAP(reg_accessed, 0x80); /* bit flags */
+	const struct snd_ac97_res_table *res_table;	/* static resolution */
 };
 
 struct snd_ac97 {
@@ -456,20 +461,20 @@
 	struct snd_info_entry *proc_regs;
 	unsigned short subsystem_vendor;
 	unsigned short subsystem_device;
-	struct semaphore reg_mutex;
-	struct semaphore page_mutex;	/* mutex for AD18xx multi-codecs and paging (2.3) */
+	struct mutex reg_mutex;
+	struct mutex page_mutex;	/* mutex for AD18xx multi-codecs and paging (2.3) */
 	unsigned short num;	/* number of codec: 0 = primary, 1 = secondary */
 	unsigned short addr;	/* physical address of codec [0-3] */
 	unsigned int id;	/* identification of codec */
 	unsigned short caps;	/* capabilities (register 0) */
 	unsigned short ext_id;	/* extended feature identification (register 28) */
 	unsigned short ext_mid;	/* extended modem ID (register 3C) */
+	const struct snd_ac97_res_table *res_table;	/* static resolution */
 	unsigned int scaps;	/* driver capabilities */
 	unsigned int flags;	/* specific code */
 	unsigned int rates[6];	/* see AC97_RATES_* defines */
 	unsigned int spdif_status;
 	unsigned short regs[0x80]; /* register cache */
-	unsigned int limited_regs; /* allow limited registers only */
 	DECLARE_BITMAP(reg_accessed, 0x80); /* bit flags */
 	union {			/* vendor specific code */
 		struct {
diff --git a/include/sound/ad1848.h b/include/sound/ad1848.h
index 1a2759f..57af1fe 100644
--- a/include/sound/ad1848.h
+++ b/include/sound/ad1848.h
@@ -154,7 +154,7 @@
 #endif
 
 	spinlock_t reg_lock;
-	struct semaphore open_mutex;
+	struct mutex open_mutex;
 };
 
 /* exported functions */
diff --git a/include/sound/ak4531_codec.h b/include/sound/ak4531_codec.h
index edf0407..fb30faa 100644
--- a/include/sound/ak4531_codec.h
+++ b/include/sound/ak4531_codec.h
@@ -71,7 +71,7 @@
 	void (*private_free) (struct snd_ak4531 *ak4531);
 	/* --- */
 	unsigned char regs[0x20];
-	struct semaphore reg_mutex;
+	struct mutex reg_mutex;
 };
 
 int snd_ak4531_mixer(struct snd_card *card, struct snd_ak4531 *_ak4531,
diff --git a/include/sound/core.h b/include/sound/core.h
index 3093e3d..144bdc2 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -23,7 +23,7 @@
  */
 
 #include <linux/sched.h>		/* wake_up() */
-#include <asm/semaphore.h>		/* struct semaphore */
+#include <linux/mutex.h>		/* struct mutex */
 #include <linux/rwsem.h>		/* struct rw_semaphore */
 #include <linux/workqueue.h>		/* struct workqueue_struct */
 #include <linux/pm.h>			/* pm_message_t */
@@ -137,7 +137,7 @@
 
 #ifdef CONFIG_PM
 	unsigned int power_state;	/* power state */
-	struct semaphore power_lock;	/* power lock */
+	struct mutex power_lock;	/* power lock */
 	wait_queue_head_t power_sleep;
 #endif
 
@@ -150,12 +150,12 @@
 #ifdef CONFIG_PM
 static inline void snd_power_lock(struct snd_card *card)
 {
-	down(&card->power_lock);
+	mutex_lock(&card->power_lock);
 }
 
 static inline void snd_power_unlock(struct snd_card *card)
 {
-	up(&card->power_lock);
+	mutex_unlock(&card->power_lock);
 }
 
 static inline unsigned int snd_power_get_state(struct snd_card *card)
diff --git a/include/sound/cs4231.h b/include/sound/cs4231.h
index ac6a5d8..60b5b92 100644
--- a/include/sound/cs4231.h
+++ b/include/sound/cs4231.h
@@ -248,8 +248,8 @@
 	unsigned int c_dma_size;
 
 	spinlock_t reg_lock;
-	struct semaphore mce_mutex;
-	struct semaphore open_mutex;
+	struct mutex mce_mutex;
+	struct mutex open_mutex;
 
 	int (*rate_constraint) (struct snd_pcm_runtime *runtime);
 	void (*set_playback_format) (struct snd_cs4231 *chip, struct snd_pcm_hw_params *hw_params, unsigned char pdfr);
diff --git a/include/sound/cs46xx.h b/include/sound/cs46xx.h
index 199b509..80b2979 100644
--- a/include/sound/cs46xx.h
+++ b/include/sound/cs46xx.h
@@ -1711,7 +1711,7 @@
 	int current_gpio;
 #endif
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
-	struct semaphore spos_mutex;
+	struct mutex spos_mutex;
 
 	struct dsp_spos_instance * dsp_spos_instance;
 
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
index 951e40d..186e00a 100644
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -33,6 +33,7 @@
 #include <sound/pcm-indirect.h>
 #include <sound/timer.h>
 #include <linux/interrupt.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 
 /* ------------------- DEFINES -------------------- */
@@ -1022,7 +1023,7 @@
 	int gpr_size;			/* size of allocated GPR controls */
 	int gpr_count;			/* count of used kcontrols */
 	struct list_head gpr_ctl;	/* GPR controls */
-	struct semaphore lock;
+	struct mutex lock;
 	struct snd_emu10k1_fx8010_pcm pcm[8];
 	spinlock_t irq_lock;
 	struct snd_emu10k1_fx8010_irq *irq_handlers;
@@ -1122,7 +1123,6 @@
 	spinlock_t reg_lock;
 	spinlock_t emu_lock;
 	spinlock_t voice_lock;
-	struct semaphore ptb_lock;
 
 	struct snd_emu10k1_voice voices[NUM_G];
 	struct snd_emu10k1_voice p16v_voices[4];
diff --git a/include/sound/emux_synth.h b/include/sound/emux_synth.h
index b2d6b2a..d8cb51b 100644
--- a/include/sound/emux_synth.h
+++ b/include/sound/emux_synth.h
@@ -113,7 +113,7 @@
 	struct snd_emux_voice *voices;	/* Voices (EMU 'channel') */
 	int use_time;	/* allocation counter */
 	spinlock_t voice_lock;	/* Lock for voice access */
-	struct semaphore register_mutex;
+	struct mutex register_mutex;
 	int client;		/* For the sequencer client */
 	int ports[SNDRV_EMUX_MAX_PORTS];	/* The ports for this device */
 	struct snd_emux_port *portptrs[SNDRV_EMUX_MAX_PORTS];
diff --git a/include/sound/gus.h b/include/sound/gus.h
index 63da50f..68a664a 100644
--- a/include/sound/gus.h
+++ b/include/sound/gus.h
@@ -209,7 +209,7 @@
 	struct snd_gf1_bank_info banks_16[4];
 	struct snd_gf1_mem_block *first;
 	struct snd_gf1_mem_block *last;
-	struct semaphore memory_mutex;
+	struct mutex memory_mutex;
 };
 
 struct snd_gf1_dma_block {
@@ -467,8 +467,8 @@
 	spinlock_t dma_lock;
 	spinlock_t pcm_volume_level_lock;
 	spinlock_t uart_cmd_lock;
-	struct semaphore dma_mutex;
-	struct semaphore register_mutex;
+	struct mutex dma_mutex;
+	struct mutex register_mutex;
 };
 
 /* I/O functions for GF1/InterWave chip - gus_io.c */
diff --git a/include/sound/hwdep.h b/include/sound/hwdep.h
index c679e5b..94c387b 100644
--- a/include/sound/hwdep.h
+++ b/include/sound/hwdep.h
@@ -60,7 +60,7 @@
 	void *private_data;
 	void (*private_free) (struct snd_hwdep *hwdep);
 
-	struct semaphore open_mutex;
+	struct mutex open_mutex;
 	int used;
 	unsigned int dsp_loaded;
 	unsigned int exclusive: 1;
diff --git a/include/sound/i2c.h b/include/sound/i2c.h
index 81eb23e..d125ff8 100644
--- a/include/sound/i2c.h
+++ b/include/sound/i2c.h
@@ -55,7 +55,7 @@
 	struct snd_card *card;	/* card which I2C belongs to */
 	char name[32];		/* some useful label */
 
-	struct semaphore lock_mutex;
+	struct mutex lock_mutex;
 
 	struct snd_i2c_bus *master;	/* master bus when SCK/SCL is shared */
 	struct list_head buses;	/* master: slave buses sharing SCK/SCL, slave: link list */
@@ -84,17 +84,17 @@
 static inline void snd_i2c_lock(struct snd_i2c_bus *bus)
 {
 	if (bus->master)
-		down(&bus->master->lock_mutex);
+		mutex_lock(&bus->master->lock_mutex);
 	else
-		down(&bus->lock_mutex);
+		mutex_lock(&bus->lock_mutex);
 }
 
 static inline void snd_i2c_unlock(struct snd_i2c_bus *bus)
 {
 	if (bus->master)
-		up(&bus->master->lock_mutex);
+		mutex_unlock(&bus->master->lock_mutex);
 	else
-		up(&bus->lock_mutex);
+		mutex_unlock(&bus->lock_mutex);
 }
 
 int snd_i2c_sendbytes(struct snd_i2c_device *device, unsigned char *bytes, int count);
diff --git a/include/sound/info.h b/include/sound/info.h
index 8ea5c74..f23d838 100644
--- a/include/sound/info.h
+++ b/include/sound/info.h
@@ -84,7 +84,7 @@
 	void *private_data;
 	void (*private_free)(struct snd_info_entry *entry);
 	struct proc_dir_entry *p;
-	struct semaphore access;
+	struct mutex access;
 };
 
 #if defined(CONFIG_SND_OSSEMUL) && defined(CONFIG_PROC_FS)
diff --git a/include/sound/mixer_oss.h b/include/sound/mixer_oss.h
index ca5b482..197b9e3 100644
--- a/include/sound/mixer_oss.h
+++ b/include/sound/mixer_oss.h
@@ -61,7 +61,7 @@
 			  unsigned int active_index);
 	void *private_data_recsrc;
 	void (*private_free_recsrc)(struct snd_mixer_oss *mixer);
-	struct semaphore reg_mutex;
+	struct mutex reg_mutex;
 	struct snd_info_entry *proc_entry;
 	int oss_dev_alloc;
 	/* --- */
diff --git a/include/sound/opl3.h b/include/sound/opl3.h
index 8339264..4449071 100644
--- a/include/sound/opl3.h
+++ b/include/sound/opl3.h
@@ -53,6 +53,7 @@
 
 #include "driver.h"
 #include <linux/time.h>
+#include <linux/mutex.h>
 #include "core.h"
 #include "hwdep.h"
 #include "timer.h"
@@ -312,7 +313,7 @@
 	int sys_timer_status;		/* system timer run status */
 	spinlock_t sys_timer_lock;	/* Lock for system timer access */
 #endif
-	struct semaphore access_mutex;	/* locking */
+	struct mutex access_mutex;	/* locking */
 };
 
 /* opl3.c */
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 314268a..15b8856 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -420,7 +420,7 @@
 	char id[64];
 	char name[80];
 	struct snd_pcm_str streams[2];
-	struct semaphore open_mutex;
+	struct mutex open_mutex;
 	wait_queue_head_t open_wait;
 	void *private_data;
 	void (*private_free) (struct snd_pcm *pcm);
diff --git a/include/sound/pcm_oss.h b/include/sound/pcm_oss.h
index fddaddd..bff0778e 100644
--- a/include/sound/pcm_oss.h
+++ b/include/sound/pcm_oss.h
@@ -56,8 +56,10 @@
 	size_t mmap_bytes;
 	char *buffer;				/* vmallocated period */
 	size_t buffer_used;			/* used length from period buffer */
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
 	struct snd_pcm_plugin *plugin_first;
 	struct snd_pcm_plugin *plugin_last;
+#endif
 	unsigned int prev_hw_ptr_interrupt;
 };
 
@@ -73,7 +75,7 @@
 
 struct snd_pcm_oss_stream {
 	struct snd_pcm_oss_setup *setup_list;	/* setup list */
-        struct semaphore setup_mutex;
+	struct mutex setup_mutex;
 	struct snd_info_entry *proc_entry;
 };
 
diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h
index d19bddf..584e73d 100644
--- a/include/sound/rawmidi.h
+++ b/include/sound/rawmidi.h
@@ -26,7 +26,7 @@
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
 #include <linux/wait.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
 #include "seq_device.h"
@@ -130,7 +130,7 @@
 	void *private_data;
 	void (*private_free) (struct snd_rawmidi *rmidi);
 
-	struct semaphore open_mutex;
+	struct mutex open_mutex;
 	wait_queue_head_t open_wait;
 
 	struct snd_info_entry *dev;
diff --git a/include/sound/sb16_csp.h b/include/sound/sb16_csp.h
index 3b44d4b..caf6fe2 100644
--- a/include/sound/sb16_csp.h
+++ b/include/sound/sb16_csp.h
@@ -158,7 +158,7 @@
 	struct snd_kcontrol *qsound_switch;
 	struct snd_kcontrol *qsound_space;
 
-	struct semaphore access_mutex;	/* locking */
+	struct mutex access_mutex;	/* locking */
 };
 
 int snd_sb_csp_new(struct snd_sb *chip, int device, struct snd_hwdep ** rhwdep);
diff --git a/include/sound/seq_instr.h b/include/sound/seq_instr.h
index db764f0..f2db03b 100644
--- a/include/sound/seq_instr.h
+++ b/include/sound/seq_instr.h
@@ -64,7 +64,7 @@
 
 	spinlock_t lock;
 	spinlock_t ops_lock;
-	struct semaphore ops_mutex;
+	struct mutex ops_mutex;
 	unsigned long ops_flags;
 };
 
diff --git a/include/sound/soundfont.h b/include/sound/soundfont.h
index 61a010c..f95d99b 100644
--- a/include/sound/soundfont.h
+++ b/include/sound/soundfont.h
@@ -93,7 +93,7 @@
 	int sample_locked;	/* locked time for sample */
 	struct snd_sf_callback callback;	/* callback functions */
 	int presets_locked;
-	struct semaphore presets_mutex;
+	struct mutex presets_mutex;
 	spinlock_t lock;
 	struct snd_util_memhdr *memhdr;
 };
diff --git a/include/sound/util_mem.h b/include/sound/util_mem.h
index 69944bbb..a1fb706 100644
--- a/include/sound/util_mem.h
+++ b/include/sound/util_mem.h
@@ -1,5 +1,7 @@
 #ifndef __SOUND_UTIL_MEM_H
 #define __SOUND_UTIL_MEM_H
+
+#include <linux/mutex.h>
 /*
  *  Copyright (C) 2000 Takashi Iwai <tiwai@suse.de>
  *
@@ -40,7 +42,7 @@
 	int nblocks;			/* # of allocated blocks */
 	unsigned int used;		/* used memory size */
 	int block_extra_size;		/* extra data size of chunk */
-	struct semaphore block_mutex;	/* lock */
+	struct mutex block_mutex;	/* lock */
 };
 
 /*
diff --git a/include/sound/version.h b/include/sound/version.h
index 919da0d..4f0e658 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.11rc2"
-#define CONFIG_SND_DATE " (Wed Jan 04 08:57:20 2006 UTC)"
+#define CONFIG_SND_VERSION "1.0.11rc4"
+#define CONFIG_SND_DATE " (Wed Mar 22 10:27:24 2006 UTC)"
diff --git a/include/sound/vx_core.h b/include/sound/vx_core.h
index 5fd6f33..9821a61 100644
--- a/include/sound/vx_core.h
+++ b/include/sound/vx_core.h
@@ -206,7 +206,7 @@
 	int audio_monitor[4];			/* playback hw-monitor level */
 	unsigned char audio_monitor_active[4];	/* playback hw-monitor mute/unmute */
 
-	struct semaphore mixer_mutex;
+	struct mutex mixer_mutex;
 
 	const struct firmware *firmware[4]; /* loaded firmware data */
 };
diff --git a/include/sound/ymfpci.h b/include/sound/ymfpci.h
index d567bfd..d41cda9 100644
--- a/include/sound/ymfpci.h
+++ b/include/sound/ymfpci.h
@@ -269,9 +269,10 @@
 	enum snd_ymfpci_pcm_type type;
 	struct snd_pcm_substream *substream;
 	struct snd_ymfpci_voice *voices[2];	/* playback only */
-	unsigned int running: 1;
-	unsigned int output_front: 1;
-	unsigned int output_rear: 1;
+	unsigned int running: 1,
+	             output_front: 1,
+	             output_rear: 1,
+	             swap_rear: 1;
 	unsigned int update_pcm_vol;
 	u32 period_size;		/* cached from runtime->period_size */
 	u32 buffer_size;		/* cached from runtime->buffer_size */
@@ -344,6 +345,7 @@
 	struct snd_kcontrol *spdif_pcm_ctl;
 	int mode_dup4ch;
 	int rear_opened;
+	int rear_swap;
 	int spdif_opened;
 	struct {
 		u16 left;
@@ -376,7 +378,7 @@
 int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm);
 int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm);
 int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm);
-int snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch);
+int snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch, int rear_swap);
 int snd_ymfpci_timer(struct snd_ymfpci *chip, int device);
 
 #endif /* __SOUND_YMFPCI_H */
diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c
index 149feb4..5f22d70 100644
--- a/sound/arm/aaci.c
+++ b/sound/arm/aaci.c
@@ -73,7 +73,7 @@
 	if (ac97->num >= 4)
 		return;
 
-	down(&aaci->ac97_sem);
+	mutex_lock(&aaci->ac97_sem);
 
 	aaci_ac97_select_codec(aaci, ac97);
 
@@ -91,7 +91,7 @@
 		v = readl(aaci->base + AACI_SLFR);
 	} while (v & (SLFR_1TXB|SLFR_2TXB));
 
-	up(&aaci->ac97_sem);
+	mutex_unlock(&aaci->ac97_sem);
 }
 
 /*
@@ -105,7 +105,7 @@
 	if (ac97->num >= 4)
 		return ~0;
 
-	down(&aaci->ac97_sem);
+	mutex_lock(&aaci->ac97_sem);
 
 	aaci_ac97_select_codec(aaci, ac97);
 
@@ -145,7 +145,7 @@
 		v = ~0;
 	}
 
-	up(&aaci->ac97_sem);
+	mutex_unlock(&aaci->ac97_sem);
 	return v;
 }
 
@@ -783,7 +783,7 @@
 		 card->shortname, dev->res.start, dev->irq[0]);
 
 	aaci = card->private_data;
-	init_MUTEX(&aaci->ac97_sem);
+	mutex_init(&aaci->ac97_sem);
 	spin_lock_init(&aaci->lock);
 	aaci->card = card;
 	aaci->dev = dev;
diff --git a/sound/arm/aaci.h b/sound/arm/aaci.h
index 83f73c2..0629519 100644
--- a/sound/arm/aaci.h
+++ b/sound/arm/aaci.h
@@ -227,7 +227,7 @@
 	unsigned int		fifosize;
 
 	/* AC'97 */
-	struct semaphore	ac97_sem;
+	struct mutex		ac97_sem;
 	ac97_bus_t		*ac97_bus;
 
 	u32			maincr;
diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c
index 3acbc60..599aff8 100644
--- a/sound/arm/pxa2xx-ac97.c
+++ b/sound/arm/pxa2xx-ac97.c
@@ -25,7 +25,7 @@
 #include <sound/initval.h>
 
 #include <asm/irq.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <asm/hardware.h>
 #include <asm/arch/pxa-regs.h>
 #include <asm/arch/audio.h>
@@ -33,7 +33,7 @@
 #include "pxa2xx-pcm.h"
 
 
-static DECLARE_MUTEX(car_mutex);
+static DEFINE_MUTEX(car_mutex);
 static DECLARE_WAIT_QUEUE_HEAD(gsr_wq);
 static volatile long gsr_bits;
 
@@ -52,7 +52,7 @@
 	unsigned short val = -1;
 	volatile u32 *reg_addr;
 
-	down(&car_mutex);
+	mutex_lock(&car_mutex);
 
 	/* set up primary or secondary codec space */
 	reg_addr = (ac97->num & 1) ? &SAC_REG_BASE : &PAC_REG_BASE;
@@ -79,7 +79,7 @@
 	/* but we've just started another cycle... */
 	wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1);
 
-out:	up(&car_mutex);
+out:	mutex_unlock(&car_mutex);
 	return val;
 }
 
@@ -87,7 +87,7 @@
 {
 	volatile u32 *reg_addr;
 
-	down(&car_mutex);
+	mutex_lock(&car_mutex);
 
 	/* set up primary or secondary codec space */
 	reg_addr = (ac97->num & 1) ? &SAC_REG_BASE : &PAC_REG_BASE;
@@ -101,7 +101,7 @@
 		printk(KERN_ERR "%s: write error (ac97_reg=%d GSR=%#lx)\n",
 				__FUNCTION__, reg, GSR | gsr_bits);
 
-	up(&car_mutex);
+	mutex_unlock(&car_mutex);
 }
 
 static void pxa2xx_ac97_reset(struct snd_ac97 *ac97)
diff --git a/sound/core/Kconfig b/sound/core/Kconfig
index f79755f..9dd121b 100644
--- a/sound/core/Kconfig
+++ b/sound/core/Kconfig
@@ -73,6 +73,15 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-pcm-oss.
 
+config SND_PCM_OSS_PLUGINS
+	bool "OSS PCM (digital audio) API - Include plugin system"
+	depends on SND_PCM_OSS
+        default y
+	help
+          If you disable this option, the ALSA's OSS PCM API will not
+          support conversion of channels, formats and rates. It will
+          behave like most of new OSS/Free drivers in 2.4/2.6 kernels.
+
 config SND_SEQUENCER_OSS
 	bool "OSS Sequencer API"
 	depends on SND && SND_SEQUENCER
@@ -130,6 +139,15 @@
 	  Say Y here to support the obsolete ALSA PCM API (ver.0.9.0 rc3
 	  or older).
 
+config SND_VERBOSE_PROCFS
+	bool "Verbose procfs contents"
+	depends on SND
+	default y
+	help
+	  Say Y here to include code for verbose procfs contents (provides
+          usefull information to developers when a problem occurs). On the
+          other side, it makes the ALSA subsystem larger.
+
 config SND_VERBOSE_PRINTK
 	bool "Verbose printk"
 	depends on SND
diff --git a/sound/core/control.c b/sound/core/control.c
index 0c29679..5747453 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -309,28 +309,29 @@
 {
 	struct snd_ctl_elem_id id;
 	unsigned int idx;
+	int err = -EINVAL;
 
-	snd_assert(card != NULL, return -EINVAL);
 	if (! kcontrol)
-		return -EINVAL;
-	snd_assert(kcontrol->info != NULL, return -EINVAL);
+		return err;
+	snd_assert(card != NULL, goto error);
+	snd_assert(kcontrol->info != NULL, goto error);
 	id = kcontrol->id;
 	down_write(&card->controls_rwsem);
 	if (snd_ctl_find_id(card, &id)) {
 		up_write(&card->controls_rwsem);
-		snd_ctl_free_one(kcontrol);
 		snd_printd(KERN_ERR "control %i:%i:%i:%s:%i is already present\n",
 					id.iface,
 					id.device,
 					id.subdevice,
 					id.name,
 					id.index);
-		return -EBUSY;
+		err = -EBUSY;
+		goto error;
 	}
 	if (snd_ctl_find_hole(card, kcontrol->count) < 0) {
 		up_write(&card->controls_rwsem);
-		snd_ctl_free_one(kcontrol);
-		return -ENOMEM;
+		err = -ENOMEM;
+		goto error;
 	}
 	list_add_tail(&kcontrol->list, &card->controls);
 	card->controls_count += kcontrol->count;
@@ -340,6 +341,10 @@
 	for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++)
 		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
 	return 0;
+
+ error:
+	snd_ctl_free_one(kcontrol);
+	return err;
 }
 
 /**
@@ -658,7 +663,11 @@
 
 	if (copy_from_user(&info, _info, sizeof(info)))
 		return -EFAULT;
-	result = snd_ctl_elem_info(ctl, &info);
+	snd_power_lock(ctl->card);
+	result = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0, NULL);
+	if (result >= 0)
+		result = snd_ctl_elem_info(ctl, &info);
+	snd_power_unlock(ctl->card);
 	if (result >= 0)
 		if (copy_to_user(_info, &info, sizeof(info)))
 			return -EFAULT;
@@ -708,7 +717,11 @@
 		kfree(control);
 		return -EFAULT;
 	}
-	result = snd_ctl_elem_read(card, control);
+	snd_power_lock(card);
+	result = snd_power_wait(card, SNDRV_CTL_POWER_D0, NULL);
+	if (result >= 0)
+		result = snd_ctl_elem_read(card, control);
+	snd_power_unlock(card);
 	if (result >= 0)
 		if (copy_to_user(_control, control, sizeof(*control)))
 			result = -EFAULT;
@@ -758,6 +771,7 @@
 				   struct snd_ctl_elem_value __user *_control)
 {
 	struct snd_ctl_elem_value *control;
+	struct snd_card *card;
 	int result;
 
 	control = kmalloc(sizeof(*control), GFP_KERNEL);
@@ -767,7 +781,12 @@
 		kfree(control);
 		return -EFAULT;
 	}
-	result = snd_ctl_elem_write(file->card, file, control);
+	card = file->card;
+	snd_power_lock(card);
+	result = snd_power_wait(card, SNDRV_CTL_POWER_D0, NULL);
+	if (result >= 0)
+		result = snd_ctl_elem_write(card, file, control);
+	snd_power_unlock(card);
 	if (result >= 0)
 		if (copy_to_user(_control, control, sizeof(*control)))
 			result = -EFAULT;
diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c
index a529b62..84fef50 100644
--- a/sound/core/control_compat.c
+++ b/sound/core/control_compat.c
@@ -107,7 +107,13 @@
 	 */
 	if (get_user(data->value.enumerated.item, &data32->value.enumerated.item))
 		goto error;
-	err = snd_ctl_elem_info(ctl, data);
+
+	snd_power_lock(ctl->card);
+	err = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0, NULL);
+	if (err >= 0)
+		err = snd_ctl_elem_info(ctl, data);
+	snd_power_unlock(ctl->card);
+
 	if (err < 0)
 		goto error;
 	/* restore info to 32bit */
@@ -286,9 +292,14 @@
 
 	if ((err = copy_ctl_value_from_user(card, data, data32, &type, &count)) < 0)
 		goto error;
-	if ((err = snd_ctl_elem_read(card, data)) < 0)
-		goto error;
-	err = copy_ctl_value_to_user(data32, data, type, count);
+
+	snd_power_lock(card);
+	err = snd_power_wait(card, SNDRV_CTL_POWER_D0, NULL);
+	if (err >= 0)
+		err = snd_ctl_elem_read(card, data);
+	snd_power_unlock(card);
+	if (err >= 0)
+		err = copy_ctl_value_to_user(data32, data, type, count);
  error:
 	kfree(data);
 	return err;
@@ -298,17 +309,23 @@
 					  struct snd_ctl_elem_value32 __user *data32)
 {
 	struct snd_ctl_elem_value *data;
+	struct snd_card *card = file->card;
 	int err, type, count;
 
 	data = kzalloc(sizeof(*data), GFP_KERNEL);
 	if (data == NULL)
 		return -ENOMEM;
 
-	if ((err = copy_ctl_value_from_user(file->card, data, data32, &type, &count)) < 0)
+	if ((err = copy_ctl_value_from_user(card, data, data32, &type, &count)) < 0)
 		goto error;
-	if ((err = snd_ctl_elem_write(file->card, file, data)) < 0)
-		goto error;
-	err = copy_ctl_value_to_user(data32, data, type, count);
+
+	snd_power_lock(card);
+	err = snd_power_wait(card, SNDRV_CTL_POWER_D0, NULL);
+	if (err >= 0)
+		err = snd_ctl_elem_write(card, file, data);
+	snd_power_unlock(card);
+	if (err >= 0)
+		err = copy_ctl_value_to_user(data32, data, type, count);
  error:
 	kfree(data);
 	return err;
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
index 618c43b..2524e66 100644
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -25,6 +25,7 @@
 #include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/time.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/minors.h>
@@ -36,7 +37,7 @@
 MODULE_LICENSE("GPL");
 
 static LIST_HEAD(snd_hwdep_devices);
-static DECLARE_MUTEX(register_mutex);
+static DEFINE_MUTEX(register_mutex);
 
 static int snd_hwdep_free(struct snd_hwdep *hwdep);
 static int snd_hwdep_dev_free(struct snd_device *device);
@@ -111,7 +112,7 @@
 
 	init_waitqueue_entry(&wait, current);
 	add_wait_queue(&hw->open_wait, &wait);
-	down(&hw->open_mutex);
+	mutex_lock(&hw->open_mutex);
 	while (1) {
 		if (hw->exclusive && hw->used > 0) {
 			err = -EBUSY;
@@ -128,9 +129,9 @@
 		} else
 			break;
 		set_current_state(TASK_INTERRUPTIBLE);
-		up(&hw->open_mutex);
+		mutex_unlock(&hw->open_mutex);
 		schedule();
-		down(&hw->open_mutex);
+		mutex_lock(&hw->open_mutex);
 		if (signal_pending(current)) {
 			err = -ERESTARTSYS;
 			break;
@@ -147,7 +148,7 @@
 				hw->ops.release(hw, file);
 		}
 	}
-	up(&hw->open_mutex);
+	mutex_unlock(&hw->open_mutex);
 	if (err < 0)
 		module_put(hw->card->module);
 	return err;
@@ -157,7 +158,7 @@
 {
 	int err = -ENXIO;
 	struct snd_hwdep *hw = file->private_data;
-	down(&hw->open_mutex);
+	mutex_lock(&hw->open_mutex);
 	if (hw->ops.release) {
 		err = hw->ops.release(hw, file);
 		wake_up(&hw->open_wait);
@@ -165,7 +166,7 @@
 	if (hw->used > 0)
 		hw->used--;
 	snd_card_file_remove(hw->card, file);
-	up(&hw->open_mutex);
+	mutex_unlock(&hw->open_mutex);
 	module_put(hw->card->module);
 	return err;
 }
@@ -272,7 +273,7 @@
 
 			if (get_user(device, (int __user *)arg))
 				return -EFAULT;
-			down(&register_mutex);
+			mutex_lock(&register_mutex);
 			device = device < 0 ? 0 : device + 1;
 			while (device < SNDRV_MINOR_HWDEPS) {
 				if (snd_hwdep_search(card, device))
@@ -281,7 +282,7 @@
 			}
 			if (device >= SNDRV_MINOR_HWDEPS)
 				device = -1;
-			up(&register_mutex);
+			mutex_unlock(&register_mutex);
 			if (put_user(device, (int __user *)arg))
 				return -EFAULT;
 			return 0;
@@ -294,13 +295,13 @@
 
 			if (get_user(device, &info->device))
 				return -EFAULT;
-			down(&register_mutex);
+			mutex_lock(&register_mutex);
 			hwdep = snd_hwdep_search(card, device);
 			if (hwdep)
 				err = snd_hwdep_info(hwdep, info);
 			else
 				err = -ENXIO;
-			up(&register_mutex);
+			mutex_unlock(&register_mutex);
 			return err;
 		}
 	}
@@ -375,7 +376,7 @@
 		return err;
 	}
 	init_waitqueue_head(&hwdep->open_wait);
-	init_MUTEX(&hwdep->open_mutex);
+	mutex_init(&hwdep->open_mutex);
 	*rhwdep = hwdep;
 	return 0;
 }
@@ -401,9 +402,9 @@
 	int err;
 	char name[32];
 
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	if (snd_hwdep_search(hwdep->card, hwdep->device)) {
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return -EBUSY;
 	}
 	list_add_tail(&hwdep->list, &snd_hwdep_devices);
@@ -414,7 +415,7 @@
 		snd_printk(KERN_ERR "unable to register hardware dependent device %i:%i\n",
 			   hwdep->card->number, hwdep->device);
 		list_del(&hwdep->list);
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return err;
 	}
 #ifdef CONFIG_SND_OSSEMUL
@@ -434,7 +435,7 @@
 		}
 	}
 #endif
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	return 0;
 }
 
@@ -443,9 +444,9 @@
 	struct snd_hwdep *hwdep = device->device_data;
 
 	snd_assert(hwdep != NULL, return -ENXIO);
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	if (snd_hwdep_search(hwdep->card, hwdep->device) != hwdep) {
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return -EINVAL;
 	}
 #ifdef CONFIG_SND_OSSEMUL
@@ -454,7 +455,7 @@
 #endif
 	snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device);
 	list_del(&hwdep->list);
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	return snd_hwdep_free(hwdep);
 }
 
@@ -469,13 +470,13 @@
 	struct list_head *p;
 	struct snd_hwdep *hwdep;
 
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	list_for_each(p, &snd_hwdep_devices) {
 		hwdep = list_entry(p, struct snd_hwdep, list);
 		snd_iprintf(buffer, "%02i-%02i: %s\n",
 			    hwdep->card->number, hwdep->device, hwdep->name);
 	}
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 }
 
 static struct snd_info_entry *snd_hwdep_proc_entry;
diff --git a/sound/core/info.c b/sound/core/info.c
index af123e3..2582b74 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -31,6 +31,7 @@
 #include <sound/version.h>
 #include <linux/proc_fs.h>
 #include <linux/devfs_fs_kernel.h>
+#include <linux/mutex.h>
 #include <stdarg.h>
 
 /*
@@ -68,7 +69,7 @@
 	return 1;
 }
 
-static DECLARE_MUTEX(info_mutex);
+static DEFINE_MUTEX(info_mutex);
 
 struct snd_info_private_data {
 	struct snd_info_buffer *rbuffer;
@@ -265,11 +266,11 @@
 	struct proc_dir_entry *p;
 	int mode, err;
 
-	down(&info_mutex);
+	mutex_lock(&info_mutex);
 	p = PDE(inode);
 	entry = p == NULL ? NULL : (struct snd_info_entry *)p->data;
 	if (entry == NULL || entry->disconnected) {
-		up(&info_mutex);
+		mutex_unlock(&info_mutex);
 		return -ENODEV;
 	}
 	if (!try_module_get(entry->module)) {
@@ -361,13 +362,13 @@
 		break;
 	}
 	file->private_data = data;
-	up(&info_mutex);
+	mutex_unlock(&info_mutex);
 	if (entry->content == SNDRV_INFO_CONTENT_TEXT &&
 	    (mode == O_RDONLY || mode == O_RDWR)) {
 		if (entry->c.text.read) {
-			down(&entry->access);
+			mutex_lock(&entry->access);
 			entry->c.text.read(entry, data->rbuffer);
-			up(&entry->access);
+			mutex_unlock(&entry->access);
 		}
 	}
 	return 0;
@@ -375,7 +376,7 @@
       __error:
 	module_put(entry->module);
       __error1:
-	up(&info_mutex);
+	mutex_unlock(&info_mutex);
 	return err;
 }
 
@@ -747,7 +748,7 @@
 	}
 	entry->mode = S_IFREG | S_IRUGO;
 	entry->content = SNDRV_INFO_CONTENT_TEXT;
-	init_MUTEX(&entry->access);
+	mutex_init(&entry->access);
 	return entry;
 }
 
@@ -896,10 +897,10 @@
 
 	snd_assert(entry != NULL, return -ENXIO);
 	root = entry->parent == NULL ? snd_proc_root : entry->parent->p;
-	down(&info_mutex);
+	mutex_lock(&info_mutex);
 	p = snd_create_proc_entry(entry->name, entry->mode, root);
 	if (!p) {
-		up(&info_mutex);
+		mutex_unlock(&info_mutex);
 		return -ENOMEM;
 	}
 	p->owner = entry->module;
@@ -908,7 +909,7 @@
 	p->size = entry->size;
 	p->data = entry;
 	entry->p = p;
-	up(&info_mutex);
+	mutex_unlock(&info_mutex);
 	return 0;
 }
 
@@ -929,9 +930,9 @@
 	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);
+	mutex_lock(&info_mutex);
 	snd_remove_proc_entry(root, entry->p);
-	up(&info_mutex);
+	mutex_unlock(&info_mutex);
 	snd_info_free_entry(entry);
 	return 0;
 }
diff --git a/sound/core/info_oss.c b/sound/core/info_oss.c
index 820f477..f9ce854 100644
--- a/sound/core/info_oss.c
+++ b/sound/core/info_oss.c
@@ -28,6 +28,7 @@
 #include <sound/info.h>
 #include <sound/version.h>
 #include <linux/utsname.h>
+#include <linux/mutex.h>
 
 #if defined(CONFIG_SND_OSSEMUL) && defined(CONFIG_PROC_FS)
 
@@ -35,7 +36,7 @@
  *  OSS compatible part
  */
 
-static DECLARE_MUTEX(strings);
+static DEFINE_MUTEX(strings);
 static char *snd_sndstat_strings[SNDRV_CARDS][SNDRV_OSS_INFO_DEV_COUNT];
 static struct snd_info_entry *snd_sndstat_proc_entry;
 
@@ -45,7 +46,7 @@
 
 	snd_assert(dev >= 0 && dev < SNDRV_OSS_INFO_DEV_COUNT, return -ENXIO);
 	snd_assert(num >= 0 && num < SNDRV_CARDS, return -ENXIO);
-	down(&strings);
+	mutex_lock(&strings);
 	if (string == NULL) {
 		if ((x = snd_sndstat_strings[num][dev]) != NULL) {
 			kfree(x);
@@ -54,12 +55,12 @@
 	} else {
 		x = kstrdup(string, GFP_KERNEL);
 		if (x == NULL) {
-			up(&strings);
+			mutex_unlock(&strings);
 			return -ENOMEM;
 		}
 	}
 	snd_sndstat_strings[num][dev] = x;
-	up(&strings);
+	mutex_unlock(&strings);
 	return 0;
 }
 
@@ -71,7 +72,7 @@
 	char *str;
 
 	snd_iprintf(buf, "\n%s:", id);
-	down(&strings);
+	mutex_lock(&strings);
 	for (idx = 0; idx < SNDRV_CARDS; idx++) {
 		str = snd_sndstat_strings[idx][dev];
 		if (str) {
@@ -82,7 +83,7 @@
 			snd_iprintf(buf, "%i: %s\n", idx, str);
 		}
 	}
-	up(&strings);
+	mutex_unlock(&strings);
 	if (ok < 0)
 		snd_iprintf(buf, " NOT ENABLED IN CONFIG\n");
 	return ok;
diff --git a/sound/core/init.c b/sound/core/init.c
index 7581668..ad68761 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -145,7 +145,7 @@
 	init_waitqueue_head(&card->shutdown_sleep);
 	INIT_WORK(&card->free_workq, snd_card_free_thread, card);
 #ifdef CONFIG_PM
-	init_MUTEX(&card->power_lock);
+	mutex_init(&card->power_lock);
 	init_waitqueue_head(&card->power_sleep);
 #endif
 	/* the control interface cannot be accessed from the user space until */
@@ -169,11 +169,44 @@
       	return NULL;
 }
 
+static loff_t snd_disconnect_llseek(struct file *file, loff_t offset, int orig)
+{
+	return -ENODEV;
+}
+
+static ssize_t snd_disconnect_read(struct file *file, char __user *buf,
+				   size_t count, loff_t *offset)
+{
+	return -ENODEV;
+}
+
+static ssize_t snd_disconnect_write(struct file *file, const char __user *buf,
+				    size_t count, loff_t *offset)
+{
+	return -ENODEV;
+}
+
 static unsigned int snd_disconnect_poll(struct file * file, poll_table * wait)
 {
 	return POLLERR | POLLNVAL;
 }
 
+static long snd_disconnect_ioctl(struct file *file,
+				 unsigned int cmd, unsigned long arg)
+{
+	return -ENODEV;
+}
+
+static int snd_disconnect_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	return -ENODEV;
+}
+
+static int snd_disconnect_fasync(int fd, struct file *file, int on)
+{
+	return -ENODEV;
+}
+
 /**
  *  snd_card_disconnect - disconnect all APIs from the file-operations (user space)
  *  @card: soundcard structure
@@ -224,7 +257,16 @@
 		memset(f_ops, 0, sizeof(*f_ops));
 		f_ops->owner = file->f_op->owner;
 		f_ops->release = file->f_op->release;
+		f_ops->llseek = snd_disconnect_llseek;
+		f_ops->read = snd_disconnect_read;
+		f_ops->write = snd_disconnect_write;
 		f_ops->poll = snd_disconnect_poll;
+		f_ops->unlocked_ioctl = snd_disconnect_ioctl;
+#ifdef CONFIG_COMPAT
+		f_ops->compat_ioctl = snd_disconnect_ioctl;
+#endif
+		f_ops->mmap = snd_disconnect_mmap;
+		f_ops->fasync = snd_disconnect_fasync;
 
 		s_f_ops->next = card->s_f_ops;
 		card->s_f_ops = s_f_ops;
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c
index 19b3dcb..3fc6f97 100644
--- a/sound/core/memalloc.c
+++ b/sound/core/memalloc.c
@@ -31,7 +31,7 @@
 #include <asm/uaccess.h>
 #include <linux/dma-mapping.h>
 #include <linux/moduleparam.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <sound/memalloc.h>
 #ifdef CONFIG_SBUS
 #include <asm/sbus.h>
@@ -54,7 +54,7 @@
 /*
  */
 
-static DECLARE_MUTEX(list_mutex);
+static DEFINE_MUTEX(list_mutex);
 static LIST_HEAD(mem_list_head);
 
 /* buffer preservation list */
@@ -83,7 +83,7 @@
  *  Hacks
  */
 
-#if defined(__i386__) || defined(__ppc__) || defined(__x86_64__)
+#if defined(__i386__)
 /*
  * A hack to allocate large buffers via dma_alloc_coherent()
  *
@@ -141,10 +141,6 @@
 
 #endif /* arch */
 
-#if ! defined(__arm__)
-#define NEED_RESERVE_PAGES
-#endif
-
 /*
  *
  *  Generic memory allocators
@@ -163,20 +159,6 @@
 	snd_allocated_pages -= 1 << order;
 }
 
-static void mark_pages(struct page *page, int order)
-{
-	struct page *last_page = page + (1 << order);
-	while (page < last_page)
-		SetPageReserved(page++);
-}
-
-static void unmark_pages(struct page *page, int order)
-{
-	struct page *last_page = page + (1 << order);
-	while (page < last_page)
-		ClearPageReserved(page++);
-}
-
 /**
  * snd_malloc_pages - allocate pages with the given size
  * @size: the size to allocate in bytes
@@ -195,10 +177,8 @@
 	snd_assert(gfp_flags != 0, return NULL);
 	gfp_flags |= __GFP_COMP;	/* compound page lets parts be mapped */
 	pg = get_order(size);
-	if ((res = (void *) __get_free_pages(gfp_flags, pg)) != NULL) {
-		mark_pages(virt_to_page(res), pg);
+	if ((res = (void *) __get_free_pages(gfp_flags, pg)) != NULL)
 		inc_snd_pages(pg);
-	}
 	return res;
 }
 
@@ -217,7 +197,6 @@
 		return;
 	pg = get_order(size);
 	dec_snd_pages(pg);
-	unmark_pages(virt_to_page(ptr), pg);
 	free_pages((unsigned long) ptr, pg);
 }
 
@@ -242,12 +221,8 @@
 		| __GFP_NORETRY /* don't trigger OOM-killer */
 		| __GFP_NOWARN; /* no stack trace print - this call is non-critical */
 	res = dma_alloc_coherent(dev, PAGE_SIZE << pg, dma, gfp_flags);
-	if (res != NULL) {
-#ifdef NEED_RESERVE_PAGES
-		mark_pages(virt_to_page(res), pg); /* should be dma_to_page() */
-#endif
+	if (res != NULL)
 		inc_snd_pages(pg);
-	}
 
 	return res;
 }
@@ -262,9 +237,6 @@
 		return;
 	pg = get_order(size);
 	dec_snd_pages(pg);
-#ifdef NEED_RESERVE_PAGES
-	unmark_pages(virt_to_page(ptr), pg); /* should be dma_to_page() */
-#endif
 	dma_free_coherent(dev, PAGE_SIZE << pg, ptr, dma);
 }
 
@@ -440,7 +412,7 @@
 
 	snd_assert(dmab, return 0);
 
-	down(&list_mutex);
+	mutex_lock(&list_mutex);
 	list_for_each(p, &mem_list_head) {
 		mem = list_entry(p, struct snd_mem_list, list);
 		if (mem->id == id &&
@@ -452,11 +424,11 @@
 			if (dmab->dev.dev == NULL)
 				dmab->dev.dev = dev;
 			kfree(mem);
-			up(&list_mutex);
+			mutex_unlock(&list_mutex);
 			return dmab->bytes;
 		}
 	}
-	up(&list_mutex);
+	mutex_unlock(&list_mutex);
 	return 0;
 }
 
@@ -477,11 +449,11 @@
 	mem = kmalloc(sizeof(*mem), GFP_KERNEL);
 	if (! mem)
 		return -ENOMEM;
-	down(&list_mutex);
+	mutex_lock(&list_mutex);
 	mem->buffer = *dmab;
 	mem->id = id;
 	list_add_tail(&mem->list, &mem_list_head);
-	up(&list_mutex);
+	mutex_unlock(&list_mutex);
 	return 0;
 }
 
@@ -493,7 +465,7 @@
 	struct list_head *p;
 	struct snd_mem_list *mem;
 
-	down(&list_mutex);
+	mutex_lock(&list_mutex);
 	while (! list_empty(&mem_list_head)) {
 		p = mem_list_head.next;
 		mem = list_entry(p, struct snd_mem_list, list);
@@ -501,7 +473,7 @@
 		snd_dma_free_pages(&mem->buffer);
 		kfree(mem);
 	}
-	up(&list_mutex);
+	mutex_unlock(&list_mutex);
 }
 
 
@@ -522,7 +494,7 @@
 	int devno;
 	static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG", "SBUS" };
 
-	down(&list_mutex);
+	mutex_lock(&list_mutex);
 	len += snprintf(page + len, count - len,
 			"pages  : %li bytes (%li pages per %likB)\n",
 			pages * PAGE_SIZE, pages, PAGE_SIZE / 1024);
@@ -537,7 +509,7 @@
 				"  addr = 0x%lx, size = %d bytes\n",
 				(unsigned long)mem->buffer.addr, (int)mem->buffer.bytes);
 	}
-	up(&list_mutex);
+	mutex_unlock(&list_mutex);
 	return len;
 }
 
diff --git a/sound/core/oss/copy.c b/sound/core/oss/copy.c
index d6a04c2..6658fac 100644
--- a/sound/core/oss/copy.c
+++ b/sound/core/oss/copy.c
@@ -20,6 +20,9 @@
  */
 
 #include <sound/driver.h>
+
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
+
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -85,3 +88,5 @@
 	*r_plugin = plugin;
 	return 0;
 }
+
+#endif
diff --git a/sound/core/oss/io.c b/sound/core/oss/io.c
index 322702e..b6e7ce3 100644
--- a/sound/core/oss/io.c
+++ b/sound/core/oss/io.c
@@ -20,6 +20,9 @@
  */
   
 #include <sound/driver.h>
+
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
+
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -132,3 +135,5 @@
 	*r_plugin = plugin;
 	return 0;
 }
+
+#endif
diff --git a/sound/core/oss/linear.c b/sound/core/oss/linear.c
index 8cbfa41..5b1bcdc 100644
--- a/sound/core/oss/linear.c
+++ b/sound/core/oss/linear.c
@@ -21,6 +21,9 @@
  */
 
 #include <sound/driver.h>
+
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
+
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -103,7 +106,7 @@
 	return frames;
 }
 
-int conv_index(int src_format, int dst_format)
+static int conv_index(int src_format, int dst_format)
 {
 	int src_endian, dst_endian, sign, src_width, dst_width;
 
@@ -156,3 +159,5 @@
 	*r_plugin = plugin;
 	return 0;
 }
+
+#endif
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index f08e65a..9c68bc3 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -1095,7 +1095,7 @@
 	struct snd_mixer_oss *mixer = entry->private_data;
 	int i;
 
-	down(&mixer->reg_mutex);
+	mutex_lock(&mixer->reg_mutex);
 	for (i = 0; i < SNDRV_OSS_MAX_MIXERS; i++) {
 		struct slot *p;
 
@@ -1110,7 +1110,7 @@
 		else
 			snd_iprintf(buffer, "\"\" 0\n");
 	}
-	up(&mixer->reg_mutex);
+	mutex_unlock(&mixer->reg_mutex);
 }
 
 static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
@@ -1134,9 +1134,9 @@
 		cptr = snd_info_get_str(str, cptr, sizeof(str));
 		if (! *str) {
 			/* remove the entry */
-			down(&mixer->reg_mutex);
+			mutex_lock(&mixer->reg_mutex);
 			mixer_slot_clear(&mixer->slots[ch]);
-			up(&mixer->reg_mutex);
+			mutex_unlock(&mixer->reg_mutex);
 			continue;
 		}
 		snd_info_get_str(idxstr, cptr, sizeof(idxstr));
@@ -1145,7 +1145,7 @@
 			snd_printk(KERN_ERR "mixer_oss: invalid index %d\n", idx);
 			continue;
 		}
-		down(&mixer->reg_mutex);
+		mutex_lock(&mixer->reg_mutex);
 		slot = (struct slot *)mixer->slots[ch].private_data;
 		if (slot && slot->assigned &&
 		    slot->assigned->index == idx && ! strcmp(slot->assigned->name, str))
@@ -1168,7 +1168,7 @@
 			kfree(tbl);
 		}
 	__unlock:
-		up(&mixer->reg_mutex);
+		mutex_unlock(&mixer->reg_mutex);
 	}
 }
 
@@ -1288,7 +1288,7 @@
 		mixer = kcalloc(2, sizeof(*mixer), GFP_KERNEL);
 		if (mixer == NULL)
 			return -ENOMEM;
-		init_MUTEX(&mixer->reg_mutex);
+		mutex_init(&mixer->reg_mutex);
 		sprintf(name, "mixer%i%i", card->number, 0);
 		if ((err = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER,
 						   card, 0,
diff --git a/sound/core/oss/mulaw.c b/sound/core/oss/mulaw.c
index 14f5578..2eb1880 100644
--- a/sound/core/oss/mulaw.c
+++ b/sound/core/oss/mulaw.c
@@ -22,6 +22,9 @@
  */
   
 #include <sound/driver.h>
+
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
+
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -262,6 +265,25 @@
 	return frames;
 }
 
+static int getput_index(int format)
+{
+	int sign, width, endian;
+	sign = !snd_pcm_format_signed(format);
+	width = snd_pcm_format_width(format) / 8 - 1;
+	if (width < 0 || width > 3) {
+		snd_printk(KERN_ERR "snd-pcm-oss: invalid format %d\n", format);
+		width = 0;
+	}
+#ifdef SNDRV_LITTLE_ENDIAN
+	endian = snd_pcm_format_big_endian(format);
+#else
+	endian = snd_pcm_format_little_endian(format);
+#endif
+	if (endian < 0)
+		endian = 0;
+	return width * 4 + endian * 2 + sign;
+}
+
 int snd_pcm_plugin_build_mulaw(struct snd_pcm_substream *plug,
 			       struct snd_pcm_plugin_format *src_format,
 			       struct snd_pcm_plugin_format *dst_format,
@@ -306,3 +328,5 @@
 	*r_plugin = plugin;
 	return 0;
 }
+
+#endif
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index 7fd0723..f8302b7 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -78,6 +78,7 @@
 	set_fs(fs);
 }
 
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
 static int snd_pcm_oss_plugin_clear(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
@@ -122,6 +123,7 @@
 	}
 	return 0;
 }
+#endif /* CONFIG_SND_PCM_OSS_PLUGINS */
 
 static long snd_pcm_oss_bytes(struct snd_pcm_substream *substream, long frames)
 {
@@ -412,6 +414,7 @@
 	oss_frame_size = snd_pcm_format_physical_width(params_format(params)) *
 			 params_channels(params) / 8;
 
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
 	snd_pcm_oss_plugin_clear(substream);
 	if (!direct) {
 		/* add necessary plugins */
@@ -441,6 +444,7 @@
 			}
 		}
 	}
+#endif
 
 	err = snd_pcm_oss_period_size(substream, params, sparams);
 	if (err < 0)
@@ -498,11 +502,13 @@
 	runtime->oss.periods = params_periods(sparams);
 	oss_period_size = snd_pcm_plug_client_size(substream, params_period_size(sparams));
 	snd_assert(oss_period_size >= 0, err = -EINVAL; goto failure);
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
 	if (runtime->oss.plugin_first) {
 		err = snd_pcm_plug_alloc(substream, oss_period_size);
 		if (err < 0)
 			goto failure;
 	}
+#endif
 	oss_period_size *= oss_frame_size;
 
 	oss_buffer_size = oss_period_size * runtime->oss.periods;
@@ -784,6 +790,7 @@
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	snd_pcm_sframes_t frames, frames1;
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
 	if (runtime->oss.plugin_first) {
 		struct snd_pcm_plugin_channel *channels;
 		size_t oss_frame_bytes = (runtime->oss.plugin_first->src_width * runtime->oss.plugin_first->src_format.channels) / 8;
@@ -800,7 +807,9 @@
 		if (frames1 <= 0)
 			return frames1;
 		bytes = frames1 * oss_frame_bytes;
-	} else {
+	} else
+#endif
+	{
 		frames = bytes_to_frames(runtime, bytes);
 		frames1 = snd_pcm_oss_write3(substream, buf, frames, in_kernel);
 		if (frames1 <= 0)
@@ -871,6 +880,7 @@
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	snd_pcm_sframes_t frames, frames1;
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
 	char __user *final_dst = (char __user *)buf;
 	if (runtime->oss.plugin_first) {
 		struct snd_pcm_plugin_channel *channels;
@@ -887,7 +897,9 @@
 		bytes = frames1 * oss_frame_bytes;
 		if (!in_kernel && copy_to_user(final_dst, buf, bytes))
 			return -EFAULT;
-	} else {
+	} else
+#endif
+	{
 		frames = bytes_to_frames(runtime, bytes);
 		frames1 = snd_pcm_oss_read3(substream, buf, frames, in_kernel);
 		if (frames1 <= 0)
@@ -1631,10 +1643,10 @@
 	const char *ptr, *ptrl;
 	struct snd_pcm_oss_setup *setup;
 
-	down(&pcm->streams[stream].oss.setup_mutex);
+	mutex_lock(&pcm->streams[stream].oss.setup_mutex);
 	for (setup = pcm->streams[stream].oss.setup_list; setup; setup = setup->next) {
 		if (!strcmp(setup->task_name, task_name)) {
-			up(&pcm->streams[stream].oss.setup_mutex);
+			mutex_unlock(&pcm->streams[stream].oss.setup_mutex);
 			return setup;
 		}
 	}
@@ -1650,12 +1662,12 @@
 	}
 	for (setup = pcm->streams[stream].oss.setup_list; setup; setup = setup->next) {
 		if (!strcmp(setup->task_name, ptrl)) {
-			up(&pcm->streams[stream].oss.setup_mutex);
+			mutex_unlock(&pcm->streams[stream].oss.setup_mutex);
 			return setup;
 		}
 	}
       __not_found:
-	up(&pcm->streams[stream].oss.setup_mutex);
+	mutex_unlock(&pcm->streams[stream].oss.setup_mutex);
 	return NULL;
 }
 
@@ -1692,7 +1704,9 @@
 	struct snd_pcm_runtime *runtime;
 	runtime = substream->runtime;
 	vfree(runtime->oss.buffer);
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
 	snd_pcm_oss_plugin_clear(substream);
+#endif
 	substream->oss.file = NULL;
 	substream->oss.oss = 0;
 }
@@ -1881,7 +1895,7 @@
 
 	init_waitqueue_entry(&wait, current);
 	add_wait_queue(&pcm->open_wait, &wait);
-	down(&pcm->open_mutex);
+	mutex_lock(&pcm->open_mutex);
 	while (1) {
 		err = snd_pcm_oss_open_file(file, pcm, &pcm_oss_file,
 					    iminor(inode), psetup, csetup);
@@ -1895,16 +1909,16 @@
 		} else
 			break;
 		set_current_state(TASK_INTERRUPTIBLE);
-		up(&pcm->open_mutex);
+		mutex_unlock(&pcm->open_mutex);
 		schedule();
-		down(&pcm->open_mutex);
+		mutex_lock(&pcm->open_mutex);
 		if (signal_pending(current)) {
 			err = -ERESTARTSYS;
 			break;
 		}
 	}
 	remove_wait_queue(&pcm->open_wait, &wait);
-	up(&pcm->open_mutex);
+	mutex_unlock(&pcm->open_mutex);
 	if (err < 0)
 		goto __error;
 	return err;
@@ -1930,9 +1944,9 @@
 	snd_assert(substream != NULL, return -ENXIO);
 	pcm = substream->pcm;
 	snd_pcm_oss_sync(pcm_oss_file);
-	down(&pcm->open_mutex);
+	mutex_lock(&pcm->open_mutex);
 	snd_pcm_oss_release_file(pcm_oss_file);
-	up(&pcm->open_mutex);
+	mutex_unlock(&pcm->open_mutex);
 	wake_up(&pcm->open_wait);
 	module_put(pcm->card->module);
 	snd_card_file_remove(pcm->card, file);
@@ -2246,8 +2260,10 @@
 		if ((err = snd_pcm_oss_change_params(substream)) < 0)
 			return err;
 	}
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
 	if (runtime->oss.plugin_first != NULL)
 		return -EIO;
+#endif
 
 	if (area->vm_pgoff != 0)
 		return -EINVAL;
@@ -2277,7 +2293,7 @@
 {
 	struct snd_pcm_str *pstr = entry->private_data;
 	struct snd_pcm_oss_setup *setup = pstr->oss.setup_list;
-	down(&pstr->oss.setup_mutex);
+	mutex_lock(&pstr->oss.setup_mutex);
 	while (setup) {
 		snd_iprintf(buffer, "%s %u %u%s%s%s%s%s%s\n",
 			    setup->task_name,
@@ -2291,7 +2307,7 @@
 			    setup->nosilence ? " no-silence" : "");
 		setup = setup->next;
 	}
-	up(&pstr->oss.setup_mutex);
+	mutex_unlock(&pstr->oss.setup_mutex);
 }
 
 static void snd_pcm_oss_proc_free_setup_list(struct snd_pcm_str * pstr)
@@ -2321,12 +2337,12 @@
 	struct snd_pcm_oss_setup *setup, *setup1, template;
 
 	while (!snd_info_get_line(buffer, line, sizeof(line))) {
-		down(&pstr->oss.setup_mutex);
+		mutex_lock(&pstr->oss.setup_mutex);
 		memset(&template, 0, sizeof(template));
 		ptr = snd_info_get_str(task_name, line, sizeof(task_name));
 		if (!strcmp(task_name, "clear") || !strcmp(task_name, "erase")) {
 			snd_pcm_oss_proc_free_setup_list(pstr);
-			up(&pstr->oss.setup_mutex);
+			mutex_unlock(&pstr->oss.setup_mutex);
 			continue;
 		}
 		for (setup = pstr->oss.setup_list; setup; setup = setup->next) {
@@ -2378,7 +2394,7 @@
 		}
 		if (setup)
 			*setup = template;
-		up(&pstr->oss.setup_mutex);
+		mutex_unlock(&pstr->oss.setup_mutex);
 	}
 }
 
diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c
index 7e86768..0e67dd2 100644
--- a/sound/core/oss/pcm_plugin.c
+++ b/sound/core/oss/pcm_plugin.c
@@ -25,6 +25,9 @@
 #endif
 
 #include <sound/driver.h>
+
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
+
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/vmalloc.h>
@@ -36,26 +39,6 @@
 #define snd_pcm_plug_first(plug) ((plug)->runtime->oss.plugin_first)
 #define snd_pcm_plug_last(plug) ((plug)->runtime->oss.plugin_last)
 
-static int snd_pcm_plugin_src_channels_mask(struct snd_pcm_plugin *plugin,
-					    unsigned long *dst_vmask,
-					    unsigned long **src_vmask)
-{
-	unsigned long *vmask = plugin->src_vmask;
-	bitmap_copy(vmask, dst_vmask, plugin->src_format.channels);
-	*src_vmask = vmask;
-	return 0;
-}
-
-static int snd_pcm_plugin_dst_channels_mask(struct snd_pcm_plugin *plugin,
-					    unsigned long *src_vmask,
-					    unsigned long **dst_vmask)
-{
-	unsigned long *vmask = plugin->dst_vmask;
-	bitmap_copy(vmask, src_vmask, plugin->dst_format.channels);
-	*dst_vmask = vmask;
-	return 0;
-}
-
 /*
  *  because some cards might have rates "very close", we ignore
  *  all "resampling" requests within +-5%
@@ -193,19 +176,7 @@
 		snd_pcm_plugin_free(plugin);
 		return -ENOMEM;
 	}
-	plugin->src_vmask = bitmap_alloc(src_format->channels);
-	if (plugin->src_vmask == NULL) {
-		snd_pcm_plugin_free(plugin);
-		return -ENOMEM;
-	}
-	plugin->dst_vmask = bitmap_alloc(dst_format->channels);
-	if (plugin->dst_vmask == NULL) {
-		snd_pcm_plugin_free(plugin);
-		return -ENOMEM;
-	}
 	plugin->client_channels = snd_pcm_plugin_client_channels;
-	plugin->src_channels_mask = snd_pcm_plugin_src_channels_mask;
-	plugin->dst_channels_mask = snd_pcm_plugin_dst_channels_mask;
 	*ret = plugin;
 	return 0;
 }
@@ -218,8 +189,6 @@
 		plugin->private_free(plugin);
 	kfree(plugin->buf_channels);
 	vfree(plugin->buf);
-	kfree(plugin->src_vmask);
-	kfree(plugin->dst_vmask);
 	kfree(plugin);
 	return 0;
 }
@@ -429,24 +398,14 @@
 		 dstformat.channels);
 
 	/* Format change (linearization) */
-	if ((srcformat.format != dstformat.format ||
-	     !rate_match(srcformat.rate, dstformat.rate) ||
-	     srcformat.channels != dstformat.channels) &&
-	    !snd_pcm_format_linear(srcformat.format)) {
-		if (snd_pcm_format_linear(dstformat.format))
-			tmpformat.format = dstformat.format;
-		else
-			tmpformat.format = SNDRV_PCM_FORMAT_S16;
-		switch (srcformat.format) {
-		case SNDRV_PCM_FORMAT_MU_LAW:
-			err = snd_pcm_plugin_build_mulaw(plug,
-							 &srcformat, &tmpformat,
-							 &plugin);
-			break;
-		default:
+	if (! rate_match(srcformat.rate, dstformat.rate) &&
+	    ! snd_pcm_format_linear(srcformat.format)) {
+		if (srcformat.format != SNDRV_PCM_FORMAT_MU_LAW)
 			return -EINVAL;
-		}
-		pdprintf("format change: src=%i, dst=%i returns %i\n", srcformat.format, tmpformat.format, err);
+		tmpformat.format = SNDRV_PCM_FORMAT_S16;
+		err = snd_pcm_plugin_build_mulaw(plug,
+						 &srcformat, &tmpformat,
+						 &plugin);
 		if (err < 0)
 			return err;
 		err = snd_pcm_plugin_append(plugin);
@@ -460,35 +419,11 @@
 
 	/* channels reduction */
 	if (srcformat.channels > dstformat.channels) {
-		int sv = srcformat.channels;
-		int dv = dstformat.channels;
-		int *ttable = kcalloc(dv * sv, sizeof(*ttable), GFP_KERNEL);
-		if (ttable == NULL)
-			return -ENOMEM;
-#if 1
-		if (sv == 2 && dv == 1) {
-			ttable[0] = HALF;
-			ttable[1] = HALF;
-		} else
-#endif
-		{
-			int v;
-			for (v = 0; v < dv; ++v)
-				ttable[v * sv + v] = FULL;
-		}
 		tmpformat.channels = dstformat.channels;
-		if (rate_match(srcformat.rate, dstformat.rate) &&
-		    snd_pcm_format_linear(dstformat.format))
-			tmpformat.format = dstformat.format;
-		err = snd_pcm_plugin_build_route(plug,
-						 &srcformat, &tmpformat,
-						 ttable, &plugin);
-		kfree(ttable);
+		err = snd_pcm_plugin_build_route(plug, &srcformat, &tmpformat, &plugin);
 		pdprintf("channels reduction: src=%i, dst=%i returns %i\n", srcformat.channels, tmpformat.channels, err);
-		if (err < 0) {
-			snd_pcm_plugin_free(plugin);
+		if (err < 0)
 			return err;
-		}
 		err = snd_pcm_plugin_append(plugin);
 		if (err < 0) {
 			snd_pcm_plugin_free(plugin);
@@ -500,18 +435,29 @@
 
 	/* rate resampling */
 	if (!rate_match(srcformat.rate, dstformat.rate)) {
+		if (srcformat.format != SNDRV_PCM_FORMAT_S16) {
+			/* convert to S16 for resampling */
+			tmpformat.format = SNDRV_PCM_FORMAT_S16;
+			err = snd_pcm_plugin_build_linear(plug,
+							  &srcformat, &tmpformat,
+							  &plugin);
+			if (err < 0)
+				return err;
+			err = snd_pcm_plugin_append(plugin);
+			if (err < 0) {
+				snd_pcm_plugin_free(plugin);
+				return err;
+			}
+			srcformat = tmpformat;
+			src_access = dst_access;
+		}
 		tmpformat.rate = dstformat.rate;
-		if (srcformat.channels == dstformat.channels &&
-		    snd_pcm_format_linear(dstformat.format))
-			tmpformat.format = dstformat.format;
         	err = snd_pcm_plugin_build_rate(plug,
         					&srcformat, &tmpformat,
 						&plugin);
 		pdprintf("rate down resampling: src=%i, dst=%i returns %i\n", srcformat.rate, tmpformat.rate, err);
-		if (err < 0) {
-			snd_pcm_plugin_free(plugin);
+		if (err < 0)
 			return err;
-		}      					    
 		err = snd_pcm_plugin_append(plugin);
 		if (err < 0) {
 			snd_pcm_plugin_free(plugin);
@@ -521,56 +467,11 @@
 		src_access = dst_access;
         }
 
-	/* channels extension  */
-	if (srcformat.channels < dstformat.channels) {
-		int sv = srcformat.channels;
-		int dv = dstformat.channels;
-		int *ttable = kcalloc(dv * sv, sizeof(*ttable), GFP_KERNEL);
-		if (ttable == NULL)
-			return -ENOMEM;
-#if 0
-		{
-			int v;
-			for (v = 0; v < sv; ++v)
-				ttable[v * sv + v] = FULL;
-		}
-#else
-		{
-			/* Playback is spreaded on all channels */
-			int vd, vs;
-			for (vd = 0, vs = 0; vd < dv; ++vd) {
-				ttable[vd * sv + vs] = FULL;
-				vs++;
-				if (vs == sv)
-					vs = 0;
-			}
-		}
-#endif
-		tmpformat.channels = dstformat.channels;
-		if (snd_pcm_format_linear(dstformat.format))
-			tmpformat.format = dstformat.format;
-		err = snd_pcm_plugin_build_route(plug,
-						 &srcformat, &tmpformat,
-						 ttable, &plugin);
-		kfree(ttable);
-		pdprintf("channels extension: src=%i, dst=%i returns %i\n", srcformat.channels, tmpformat.channels, err);
-		if (err < 0) {
-			snd_pcm_plugin_free(plugin);
-			return err;
-		}      					    
-		err = snd_pcm_plugin_append(plugin);
-		if (err < 0) {
-			snd_pcm_plugin_free(plugin);
-			return err;
-		}
-		srcformat = tmpformat;
-		src_access = dst_access;
-	}
-
 	/* format change */
 	if (srcformat.format != dstformat.format) {
 		tmpformat.format = dstformat.format;
-		if (tmpformat.format == SNDRV_PCM_FORMAT_MU_LAW) {
+		if (srcformat.format == SNDRV_PCM_FORMAT_MU_LAW ||
+		    tmpformat.format == SNDRV_PCM_FORMAT_MU_LAW) {
 			err = snd_pcm_plugin_build_mulaw(plug,
 							 &srcformat, &tmpformat,
 							 &plugin);
@@ -595,6 +496,22 @@
 		src_access = dst_access;
 	}
 
+	/* channels extension */
+	if (srcformat.channels < dstformat.channels) {
+		tmpformat.channels = dstformat.channels;
+		err = snd_pcm_plugin_build_route(plug, &srcformat, &tmpformat, &plugin);
+		pdprintf("channels extension: src=%i, dst=%i returns %i\n", srcformat.channels, tmpformat.channels, err);
+		if (err < 0)
+			return err;
+		err = snd_pcm_plugin_append(plugin);
+		if (err < 0) {
+			snd_pcm_plugin_free(plugin);
+			return err;
+		}
+		srcformat = tmpformat;
+		src_access = dst_access;
+	}
+
 	/* de-interleave */
 	if (src_access != dst_access) {
 		err = snd_pcm_plugin_build_copy(plug,
@@ -650,92 +567,6 @@
 	return count;
 }
 
-static int snd_pcm_plug_playback_channels_mask(struct snd_pcm_substream *plug,
-					       unsigned long *client_vmask)
-{
-	struct snd_pcm_plugin *plugin = snd_pcm_plug_last(plug);
-	if (plugin == NULL) {
-		return 0;
-	} else {
-		int schannels = plugin->dst_format.channels;
-		DECLARE_BITMAP(bs, schannels);
-		unsigned long *srcmask;
-		unsigned long *dstmask = bs;
-		int err;
-		bitmap_fill(dstmask, schannels);
-
-		while (1) {
-			err = plugin->src_channels_mask(plugin, dstmask, &srcmask);
-			if (err < 0)
-				return err;
-			dstmask = srcmask;
-			if (plugin->prev == NULL)
-				break;
-			plugin = plugin->prev;
-		}
-		bitmap_and(client_vmask, client_vmask, dstmask, plugin->src_format.channels);
-		return 0;
-	}
-}
-
-static int snd_pcm_plug_playback_disable_useless_channels(struct snd_pcm_substream *plug,
-							  struct snd_pcm_plugin_channel *src_channels)
-{
-	struct snd_pcm_plugin *plugin = snd_pcm_plug_first(plug);
-	unsigned int nchannels = plugin->src_format.channels;
-	DECLARE_BITMAP(bs, nchannels);
-	unsigned long *srcmask = bs;
-	int err;
-	unsigned int channel;
-	for (channel = 0; channel < nchannels; channel++) {
-		if (src_channels[channel].enabled)
-			set_bit(channel, srcmask);
-		else
-			clear_bit(channel, srcmask);
-	}
-	err = snd_pcm_plug_playback_channels_mask(plug, srcmask);
-	if (err < 0)
-		return err;
-	for (channel = 0; channel < nchannels; channel++) {
-		if (!test_bit(channel, srcmask))
-			src_channels[channel].enabled = 0;
-	}
-	return 0;
-}
-
-static int snd_pcm_plug_capture_disable_useless_channels(struct snd_pcm_substream *plug,
-							 struct snd_pcm_plugin_channel *src_channels,
-							 struct snd_pcm_plugin_channel *client_channels)
-{
-	struct snd_pcm_plugin *plugin = snd_pcm_plug_last(plug);
-	unsigned int nchannels = plugin->dst_format.channels;
-	DECLARE_BITMAP(bs, nchannels);
-	unsigned long *dstmask = bs;
-	unsigned long *srcmask;
-	int err;
-	unsigned int channel;
-	for (channel = 0; channel < nchannels; channel++) {
-		if (client_channels[channel].enabled)
-			set_bit(channel, dstmask);
-		else
-			clear_bit(channel, dstmask);
-	}
-	while (plugin) {
-		err = plugin->src_channels_mask(plugin, dstmask, &srcmask);
-		if (err < 0)
-			return err;
-		dstmask = srcmask;
-		plugin = plugin->prev;
-	}
-	plugin = snd_pcm_plug_first(plug);
-	nchannels = plugin->src_format.channels;
-	for (channel = 0; channel < nchannels; channel++) {
-		if (!test_bit(channel, dstmask))
-			src_channels[channel].enabled = 0;
-	}
-	return 0;
-}
-
 snd_pcm_sframes_t snd_pcm_plug_write_transfer(struct snd_pcm_substream *plug, struct snd_pcm_plugin_channel *src_channels, snd_pcm_uframes_t size)
 {
 	struct snd_pcm_plugin *plugin, *next;
@@ -743,9 +574,6 @@
 	int err;
 	snd_pcm_sframes_t frames = size;
 
-	if ((err = snd_pcm_plug_playback_disable_useless_channels(plug, src_channels)) < 0)
-		return err;
-	
 	plugin = snd_pcm_plug_first(plug);
 	while (plugin && frames > 0) {
 		if ((next = plugin->next) != NULL) {
@@ -790,10 +618,6 @@
 				return err;
 			}
 			frames = err;
-			if (!plugin->prev) {
-				if ((err = snd_pcm_plug_capture_disable_useless_channels(plug, dst_channels, dst_channels_final)) < 0)
-					return err;
-			}
 		} else {
 			dst_channels = dst_channels_final;
 		}
@@ -916,3 +740,5 @@
 	}
 	return 0;
 }
+
+#endif
diff --git a/sound/core/oss/pcm_plugin.h b/sound/core/oss/pcm_plugin.h
index 29198da..3be91b3 100644
--- a/sound/core/oss/pcm_plugin.h
+++ b/sound/core/oss/pcm_plugin.h
@@ -22,12 +22,7 @@
  *
  */
 
-#include <linux/bitmap.h>
-
-static inline unsigned long *bitmap_alloc(unsigned int nbits)
-{
-	return kmalloc(BITS_TO_LONGS(nbits), GFP_KERNEL);
-}
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
 
 #define snd_pcm_plug_stream(plug) ((plug)->stream)
 
@@ -69,12 +64,6 @@
 	snd_pcm_sframes_t (*client_channels)(struct snd_pcm_plugin *plugin,
 					     snd_pcm_uframes_t frames,
 					     struct snd_pcm_plugin_channel **channels);
-	int (*src_channels_mask)(struct snd_pcm_plugin *plugin,
-				 unsigned long *dst_vmask,
-				 unsigned long **src_vmask);
-	int (*dst_channels_mask)(struct snd_pcm_plugin *plugin,
-				 unsigned long *src_vmask,
-				 unsigned long **dst_vmask);
 	snd_pcm_sframes_t (*transfer)(struct snd_pcm_plugin *plugin,
 				      const struct snd_pcm_plugin_channel *src_channels,
 				      struct snd_pcm_plugin_channel *dst_channels,
@@ -90,8 +79,6 @@
 	char *buf;
 	snd_pcm_uframes_t buf_frames;
 	struct snd_pcm_plugin_channel *buf_channels;
-	unsigned long *src_vmask;
-	unsigned long *dst_vmask;
 	char extra_data[0];
 };
 
@@ -128,7 +115,6 @@
 int snd_pcm_plugin_build_route(struct snd_pcm_substream *handle,
 			       struct snd_pcm_plugin_format *src_format,
 			       struct snd_pcm_plugin_format *dst_format,
-			       int *ttable,
 		               struct snd_pcm_plugin **r_plugin);
 int snd_pcm_plugin_build_copy(struct snd_pcm_substream *handle,
 			      struct snd_pcm_plugin_format *src_format,
@@ -181,15 +167,13 @@
 				     void **bufs, snd_pcm_uframes_t frames,
 				     int in_kernel);
 
-#define ROUTE_PLUGIN_RESOLUTION 16
+#else
 
-int getput_index(int format);
-int copy_index(int format);
-int conv_index(int src_format, int dst_format);
+static inline snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t drv_size) { return drv_size; }
+static inline snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t clt_size) { return clt_size; }
+static inline int snd_pcm_plug_slave_format(int format, struct snd_mask *format_mask) { return format; }
 
-void zero_channel(struct snd_pcm_plugin *plugin,
-		  const struct snd_pcm_plugin_channel *dst_channel,
-		  size_t samples);
+#endif
 
 #ifdef PLUGIN_DEBUG
 #define pdprintf( fmt, args... ) printk( "plugin: " fmt, ##args)
diff --git a/sound/core/oss/plugin_ops.h b/sound/core/oss/plugin_ops.h
index 0607e95..1f5bde4 100644
--- a/sound/core/oss/plugin_ops.h
+++ b/sound/core/oss/plugin_ops.h
@@ -362,172 +362,6 @@
 }
 #endif
 
-#if 0
-#ifdef GET32_LABELS
-/* src_wid src_endswap unsigned */
-static void *get32_labels[4 * 2 * 2] = {
-	&&get32_xxx1_1000,	 /*  8h -> 32h */
-	&&get32_xxx1_9000,	 /*  8h ^> 32h */
-	&&get32_xxx1_1000,	 /*  8s -> 32h */
-	&&get32_xxx1_9000,	 /*  8s ^> 32h */
-	&&get32_xx12_1200,	 /* 16h -> 32h */
-	&&get32_xx12_9200,	 /* 16h ^> 32h */
-	&&get32_xx12_2100,	 /* 16s -> 32h */
-	&&get32_xx12_A100,	 /* 16s ^> 32h */
-	&&get32_x123_1230,	 /* 24h -> 32h */
-	&&get32_x123_9230,	 /* 24h ^> 32h */
-	&&get32_123x_3210,	 /* 24s -> 32h */
-	&&get32_123x_B210,	 /* 24s ^> 32h */
-	&&get32_1234_1234,	 /* 32h -> 32h */
-	&&get32_1234_9234,	 /* 32h ^> 32h */
-	&&get32_1234_4321,	 /* 32s -> 32h */
-	&&get32_1234_C321,	 /* 32s ^> 32h */
-};
-#endif
-
-#ifdef GET32_END
-while (0) {
-get32_xxx1_1000: sample = (u_int32_t)as_u8(src) << 24; goto GET32_END;
-get32_xxx1_9000: sample = (u_int32_t)(as_u8(src) ^ 0x80) << 24; goto GET32_END;
-get32_xx12_1200: sample = (u_int32_t)as_u16(src) << 16; goto GET32_END;
-get32_xx12_9200: sample = (u_int32_t)(as_u16(src) ^ 0x8000) << 16; goto GET32_END;
-get32_xx12_2100: sample = (u_int32_t)swab16(as_u16(src)) << 16; goto GET32_END;
-get32_xx12_A100: sample = (u_int32_t)swab16(as_u16(src) ^ 0x80) << 16; goto GET32_END;
-get32_x123_1230: sample = as_u32(src) << 8; goto GET32_END;
-get32_x123_9230: sample = (as_u32(src) << 8) ^ 0x80000000; goto GET32_END;
-get32_123x_3210: sample = swab32(as_u32(src) >> 8); goto GET32_END;
-get32_123x_B210: sample = swab32((as_u32(src) >> 8) ^ 0x80); goto GET32_END;
-get32_1234_1234: sample = as_u32(src); goto GET32_END;
-get32_1234_9234: sample = as_u32(src) ^ 0x80000000; goto GET32_END;
-get32_1234_4321: sample = swab32(as_u32(src)); goto GET32_END;
-get32_1234_C321: sample = swab32(as_u32(src) ^ 0x80); goto GET32_END;
-}
-#endif
-#endif
-
-#ifdef PUT_U32_LABELS
-/* dst_wid dst_endswap unsigned */
-static void *put_u32_labels[4 * 2 * 2] = {
-	&&put_u32_1234_xxx9,	 /* u32h ->  s8h */
-	&&put_u32_1234_xxx1,	 /* u32h ->  u8h */
-	&&put_u32_1234_xxx9,	 /* u32h ->  s8s */
-	&&put_u32_1234_xxx1,	 /* u32h ->  u8s */
-	&&put_u32_1234_xx92,	 /* u32h -> s16h */
-	&&put_u32_1234_xx12,	 /* u32h -> u16h */
-	&&put_u32_1234_xx29,	 /* u32h -> s16s */
-	&&put_u32_1234_xx21,	 /* u32h -> u16s */
-	&&put_u32_1234_x923,	 /* u32h -> s24h */
-	&&put_u32_1234_x123,	 /* u32h -> u24h */
-	&&put_u32_1234_329x,	 /* u32h -> s24s */
-	&&put_u32_1234_321x,	 /* u32h -> u24s */
-	&&put_u32_1234_9234,	 /* u32h -> s32h */
-	&&put_u32_1234_1234,	 /* u32h -> u32h */
-	&&put_u32_1234_4329,	 /* u32h -> s32s */
-	&&put_u32_1234_4321,	 /* u32h -> u32s */
-};
-#endif
-
-#ifdef PUT_U32_END
-while (0) {
-put_u32_1234_xxx1: as_u8(dst) = sample >> 24; goto PUT_U32_END;
-put_u32_1234_xxx9: as_u8(dst) = (sample >> 24) ^ 0x80; goto PUT_U32_END;
-put_u32_1234_xx12: as_u16(dst) = sample >> 16; goto PUT_U32_END;
-put_u32_1234_xx92: as_u16(dst) = (sample >> 16) ^ 0x8000; goto PUT_U32_END;
-put_u32_1234_xx21: as_u16(dst) = swab16(sample >> 16); goto PUT_U32_END;
-put_u32_1234_xx29: as_u16(dst) = swab16(sample >> 16) ^ 0x80; goto PUT_U32_END;
-put_u32_1234_x123: as_u32(dst) = sample >> 8; goto PUT_U32_END;
-put_u32_1234_x923: as_u32(dst) = (sample >> 8) ^ 0x800000; goto PUT_U32_END;
-put_u32_1234_321x: as_u32(dst) = swab32(sample) << 8; goto PUT_U32_END;
-put_u32_1234_329x: as_u32(dst) = (swab32(sample) ^ 0x80) << 8; goto PUT_U32_END;
-put_u32_1234_1234: as_u32(dst) = sample; goto PUT_U32_END;
-put_u32_1234_9234: as_u32(dst) = sample ^ 0x80000000; goto PUT_U32_END;
-put_u32_1234_4321: as_u32(dst) = swab32(sample); goto PUT_U32_END;
-put_u32_1234_4329: as_u32(dst) = swab32(sample) ^ 0x80; goto PUT_U32_END;
-}
-#endif
-
-#ifdef GET_U_LABELS
-/* width endswap unsigned*/
-static void *get_u_labels[4 * 2 * 2] = {
-	&&get_u_s8,	/* s8  ->  u8  */
-	&&get_u_u8,	/* u8  ->  u8  */
-	&&get_u_s8,	/* s8  ->  u8  */
-	&&get_u_u8,	/* u8  ->  u8  */
-	&&get_u_s16h,	/* s16h -> u16h */
-	&&get_u_u16h,	/* u16h -> u16h */
-	&&get_u_s16s,	/* s16s -> u16h */
-	&&get_u_u16s,	/* u16s -> u16h */
-	&&get_u_s24h,	/* s24h -> u32h */
-	&&get_u_u24h,	/* u24h -> u32h */
-	&&get_u_s24s,	/* s24s -> u32h */
-	&&get_u_u24s,	/* u24s -> u32h */
-	&&get_u_s32h,	/* s32h -> u32h */
-	&&get_u_u32h,	/* u32h -> u32h */
-	&&get_u_s32s,	/* s32s -> u32h */
-	&&get_u_u32s,	/* u32s -> u32h */
-};
-#endif
-
-#ifdef GET_U_END
-while (0) {
-get_u_s8: sample = as_u8(src) ^ 0x80; goto GET_U_END;
-get_u_u8: sample = as_u8(src); goto GET_U_END;
-get_u_s16h: sample = as_u16(src) ^ 0x8000; goto GET_U_END;
-get_u_u16h: sample = as_u16(src); goto GET_U_END;
-get_u_s16s: sample = swab16(as_u16(src) ^ 0x80); goto GET_U_END;
-get_u_u16s: sample = swab16(as_u16(src)); goto GET_U_END;
-get_u_s24h: sample = (as_u32(src) ^ 0x800000); goto GET_U_END;
-get_u_u24h: sample = as_u32(src); goto GET_U_END;
-get_u_s24s: sample = swab32(as_u32(src) ^ 0x800000); goto GET_U_END;
-get_u_u24s: sample = swab32(as_u32(src)); goto GET_U_END;
-get_u_s32h: sample = as_u32(src) ^ 0x80000000; goto GET_U_END;
-get_u_u32h: sample = as_u32(src); goto GET_U_END;
-get_u_s32s: sample = swab32(as_u32(src) ^ 0x80); goto GET_U_END;
-get_u_u32s: sample = swab32(as_u32(src)); goto GET_U_END;
-}
-#endif
-
-#if 0
-#ifdef PUT_LABELS
-/* width endswap unsigned */
-static void *put_labels[4 * 2 * 2] = {
-	&&put_s8,	/* s8  ->  s8  */
-	&&put_u8,	/* u8  ->  s8  */
-	&&put_s8,	/* s8  ->  s8  */
-	&&put_u8,	/* u8  ->  s8  */
-	&&put_s16h,	/* s16h -> s16h */
-	&&put_u16h,	/* u16h -> s16h */
-	&&put_s16s,	/* s16s -> s16h */
-	&&put_u16s,	/* u16s -> s16h */
-	&&put_s24h,	/* s24h -> s32h */
-	&&put_u24h,	/* u24h -> s32h */
-	&&put_s24s,	/* s24s -> s32h */
-	&&put_u24s,	/* u24s -> s32h */
-	&&put_s32h,	/* s32h -> s32h */
-	&&put_u32h,	/* u32h -> s32h */
-	&&put_s32s,	/* s32s -> s32h */
-	&&put_u32s,	/* u32s -> s32h */
-};
-#endif
-
-#ifdef PUT_END
-put_s8: as_s8(dst) = sample; goto PUT_END;
-put_u8: as_u8(dst) = sample ^ 0x80; goto PUT_END;
-put_s16h: as_s16(dst) = sample; goto PUT_END;
-put_u16h: as_u16(dst) = sample ^ 0x8000; goto PUT_END;
-put_s16s: as_s16(dst) = swab16(sample); goto PUT_END;
-put_u16s: as_u16(dst) = swab16(sample ^ 0x80); goto PUT_END;
-put_s24h: as_s24(dst) = sample & 0xffffff; goto PUT_END;
-put_u24h: as_u24(dst) = sample ^ 0x80000000; goto PUT_END;
-put_s24s: as_s24(dst) = swab32(sample & 0xffffff); goto PUT_END;
-put_u24s: as_u24(dst) = swab32(sample ^ 0x80); goto PUT_END;
-put_s32h: as_s32(dst) = sample; goto PUT_END;
-put_u32h: as_u32(dst) = sample ^ 0x80000000; goto PUT_END;
-put_s32s: as_s32(dst) = swab32(sample); goto PUT_END;
-put_u32s: as_u32(dst) = swab32(sample ^ 0x80); goto PUT_END;
-#endif
-#endif
-
 #undef as_u8
 #undef as_u16
 #undef as_u32
diff --git a/sound/core/oss/rate.c b/sound/core/oss/rate.c
index 4854cef..18d8a0f 100644
--- a/sound/core/oss/rate.c
+++ b/sound/core/oss/rate.c
@@ -20,6 +20,9 @@
  */
   
 #include <sound/driver.h>
+
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
+
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -47,7 +50,6 @@
 	unsigned int pitch;
 	unsigned int pos;
 	rate_f func;
-	int get, put;
 	snd_pcm_sframes_t old_src_frames, old_dst_frames;
 	struct rate_channel channels[0];
 };
@@ -71,21 +73,12 @@
 	unsigned int pos = 0;
 	signed int val;
 	signed short S1, S2;
-	char *src, *dst;
+	signed short *src, *dst;
 	unsigned int channel;
 	int src_step, dst_step;
 	int src_frames1, dst_frames1;
 	struct rate_priv *data = (struct rate_priv *)plugin->extra_data;
 	struct rate_channel *rchannels = data->channels;
-
-#define GET_S16_LABELS
-#define PUT_S16_LABELS
-#include "plugin_ops.h"
-#undef GET_S16_LABELS
-#undef PUT_S16_LABELS
-	void *get = get_s16_labels[data->get];
-	void *put = put_s16_labels[data->put];
-	signed short sample = 0;
 	
 	for (channel = 0; channel < plugin->src_format.channels; channel++) {
 		pos = data->pos;
@@ -98,10 +91,12 @@
 			continue;
 		}
 		dst_channels[channel].enabled = 1;
-		src = (char *)src_channels[channel].area.addr + src_channels[channel].area.first / 8;
-		dst = (char *)dst_channels[channel].area.addr + dst_channels[channel].area.first / 8;
-		src_step = src_channels[channel].area.step / 8;
-		dst_step = dst_channels[channel].area.step / 8;
+		src = (signed short *)src_channels[channel].area.addr +
+			src_channels[channel].area.first / 8 / 2;
+		dst = (signed short *)dst_channels[channel].area.addr +
+			dst_channels[channel].area.first / 8 / 2;
+		src_step = src_channels[channel].area.step / 8 / 2;
+		dst_step = dst_channels[channel].area.step / 8 / 2;
 		src_frames1 = src_frames;
 		dst_frames1 = dst_frames;
 		while (dst_frames1-- > 0) {
@@ -109,12 +104,7 @@
 				pos &= R_MASK;
 				S1 = S2;
 				if (src_frames1-- > 0) {
-					goto *get;
-#define GET_S16_END after_get
-#include "plugin_ops.h"
-#undef GET_S16_END
-				after_get:
-					S2 = sample;
+					S2 = *src;
 					src += src_step;
 				}
 			}
@@ -123,12 +113,7 @@
 				val = -32768;
 			else if (val > 32767)
 				val = 32767;
-			sample = val;
-			goto *put;
-#define PUT_S16_END after_put
-#include "plugin_ops.h"
-#undef PUT_S16_END
-		after_put:
+			*dst = val;
 			dst += dst_step;
 			pos += data->pitch;
 		}
@@ -147,21 +132,12 @@
 	unsigned int pos = 0;
 	signed int val;
 	signed short S1, S2;
-	char *src, *dst;
+	signed short *src, *dst;
 	unsigned int channel;
 	int src_step, dst_step;
 	int src_frames1, dst_frames1;
 	struct rate_priv *data = (struct rate_priv *)plugin->extra_data;
 	struct rate_channel *rchannels = data->channels;
-	
-#define GET_S16_LABELS
-#define PUT_S16_LABELS
-#include "plugin_ops.h"
-#undef GET_S16_LABELS
-#undef PUT_S16_LABELS
-	void *get = get_s16_labels[data->get];
-	void *put = put_s16_labels[data->put];
-	signed short sample = 0;
 
 	for (channel = 0; channel < plugin->src_format.channels; ++channel) {
 		pos = data->pos;
@@ -174,21 +150,18 @@
 			continue;
 		}
 		dst_channels[channel].enabled = 1;
-		src = (char *)src_channels[channel].area.addr + src_channels[channel].area.first / 8;
-		dst = (char *)dst_channels[channel].area.addr + dst_channels[channel].area.first / 8;
-		src_step = src_channels[channel].area.step / 8;
-		dst_step = dst_channels[channel].area.step / 8;
+		src = (signed short *)src_channels[channel].area.addr +
+			src_channels[channel].area.first / 8 / 2;
+		dst = (signed short *)dst_channels[channel].area.addr +
+			dst_channels[channel].area.first / 8 / 2;
+		src_step = src_channels[channel].area.step / 8 / 2;
+		dst_step = dst_channels[channel].area.step / 8 / 2;
 		src_frames1 = src_frames;
 		dst_frames1 = dst_frames;
 		while (dst_frames1 > 0) {
 			S1 = S2;
 			if (src_frames1-- > 0) {
-				goto *get;
-#define GET_S16_END after_get
-#include "plugin_ops.h"
-#undef GET_S16_END
-			after_get:
-				S2 = sample;
+				S1 = *src;
 				src += src_step;
 			}
 			if (pos & ~R_MASK) {
@@ -198,12 +171,7 @@
 					val = -32768;
 				else if (val > 32767)
 					val = 32767;
-				sample = val;
-				goto *put;
-#define PUT_S16_END after_put
-#include "plugin_ops.h"
-#undef PUT_S16_END
-			after_put:
+				*dst = val;
 				dst += dst_step;
 				dst_frames1--;
 			}
@@ -343,8 +311,8 @@
 
 	snd_assert(src_format->channels == dst_format->channels, return -ENXIO);
 	snd_assert(src_format->channels > 0, return -ENXIO);
-	snd_assert(snd_pcm_format_linear(src_format->format) != 0, return -ENXIO);
-	snd_assert(snd_pcm_format_linear(dst_format->format) != 0, return -ENXIO);
+	snd_assert(src_format->format == SNDRV_PCM_FORMAT_S16, return -ENXIO);
+	snd_assert(dst_format->format == SNDRV_PCM_FORMAT_S16, return -ENXIO);
 	snd_assert(src_format->rate != dst_format->rate, return -ENXIO);
 
 	err = snd_pcm_plugin_build(plug, "rate conversion",
@@ -355,11 +323,6 @@
 	if (err < 0)
 		return err;
 	data = (struct rate_priv *)plugin->extra_data;
-	data->get = getput_index(src_format->format);
-	snd_assert(data->get >= 0 && data->get < 4*2*2, return -EINVAL);
-	data->put = getput_index(dst_format->format);
-	snd_assert(data->put >= 0 && data->put < 4*2*2, return -EINVAL);
-
 	if (src_format->rate < dst_format->rate) {
 		data->pitch = ((src_format->rate << SHIFT) + (dst_format->rate >> 1)) / dst_format->rate;
 		data->func = resample_expand;
@@ -377,3 +340,5 @@
 	*r_plugin = plugin;
 	return 0;
 }
+
+#endif
diff --git a/sound/core/oss/route.c b/sound/core/oss/route.c
index 726c5ca..46917dc 100644
--- a/sound/core/oss/route.c
+++ b/sound/core/oss/route.c
@@ -1,5 +1,5 @@
 /*
- *  Attenuated route Plug-In
+ *  Route Plug-In
  *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
  *
  *
@@ -20,502 +20,93 @@
  */
 
 #include <sound/driver.h>
+
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
+
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include "pcm_plugin.h"
 
-/* The best possible hack to support missing optimization in gcc 2.7.2.3 */
-#if ROUTE_PLUGIN_RESOLUTION & (ROUTE_PLUGIN_RESOLUTION - 1) != 0
-#define div(a) a /= ROUTE_PLUGIN_RESOLUTION
-#elif ROUTE_PLUGIN_RESOLUTION == 16
-#define div(a) a >>= 4
-#else
-#error "Add some code here"
-#endif
-
-struct ttable_dst;
-
-typedef void (*route_channel_f)(struct snd_pcm_plugin *plugin,
-				const struct snd_pcm_plugin_channel *src_channels,
-				struct snd_pcm_plugin_channel *dst_channel,
-				struct ttable_dst *ttable, snd_pcm_uframes_t frames);
-
-struct ttable_src {
-	int channel;
-	int as_int;
-};
-
-struct ttable_dst {
-	int att;	/* Attenuated */
-	unsigned int nsrcs;
-	struct ttable_src *srcs;
-	route_channel_f func;
-};
-
-struct route_priv {
-	enum {R_UINT32=0, R_UINT64=1} sum_type;
-	int get, put;
-	int conv;
-	int src_sample_size;
-	struct ttable_dst ttable[0];
-};
-
-union sum {
-	u_int32_t as_uint32;
-	u_int64_t as_uint64;
-};
-
-
-static void route_to_channel_from_zero(struct snd_pcm_plugin *plugin,
-				       const struct snd_pcm_plugin_channel *src_channels,
-				       struct snd_pcm_plugin_channel *dst_channel,
-				       struct ttable_dst *ttable,
-				       snd_pcm_uframes_t frames)
+static void zero_areas(struct snd_pcm_plugin_channel *dvp, int ndsts,
+		       snd_pcm_uframes_t frames, int format)
 {
-	if (dst_channel->wanted)
-		snd_pcm_area_silence(&dst_channel->area, 0, frames, plugin->dst_format.format);
-	dst_channel->enabled = 0;
-}
-
-static void route_to_channel_from_one(struct snd_pcm_plugin *plugin,
-				      const struct snd_pcm_plugin_channel *src_channels,
-				      struct snd_pcm_plugin_channel *dst_channel,
-				      struct ttable_dst *ttable,
-				      snd_pcm_uframes_t frames)
-{
-#define CONV_LABELS
-#include "plugin_ops.h"
-#undef CONV_LABELS
-	struct route_priv *data = (struct route_priv *)plugin->extra_data;
-	void *conv;
-	const struct snd_pcm_plugin_channel *src_channel = NULL;
-	unsigned int srcidx;
-	char *src, *dst;
-	int src_step, dst_step;
-	for (srcidx = 0; srcidx < ttable->nsrcs; ++srcidx) {
-		src_channel = &src_channels[ttable->srcs[srcidx].channel];
-		if (src_channel->area.addr != NULL)
-			break;
-	}
-	if (srcidx == ttable->nsrcs) {
-		route_to_channel_from_zero(plugin, src_channels, dst_channel, ttable, frames);
-		return;
-	}
-
-	dst_channel->enabled = 1;
-	conv = conv_labels[data->conv];
-	src = src_channel->area.addr + src_channel->area.first / 8;
-	src_step = src_channel->area.step / 8;
-	dst = dst_channel->area.addr + dst_channel->area.first / 8;
-	dst_step = dst_channel->area.step / 8;
-	while (frames-- > 0) {
-		goto *conv;
-#define CONV_END after
-#include "plugin_ops.h"
-#undef CONV_END
-	after:
-		src += src_step;
-		dst += dst_step;
+	int dst = 0;
+	for (; dst < ndsts; ++dst) {
+		if (dvp->wanted)
+			snd_pcm_area_silence(&dvp->area, 0, frames, format);
+		dvp->enabled = 0;
+		dvp++;
 	}
 }
 
-static void route_to_channel(struct snd_pcm_plugin *plugin,
-			     const struct snd_pcm_plugin_channel *src_channels,
+static inline void copy_area(const struct snd_pcm_plugin_channel *src_channel,
 			     struct snd_pcm_plugin_channel *dst_channel,
-			     struct ttable_dst *ttable, snd_pcm_uframes_t frames)
+			     snd_pcm_uframes_t frames, int format)
 {
-#define GET_U_LABELS
-#define PUT_U32_LABELS
-#include "plugin_ops.h"
-#undef GET_U_LABELS
-#undef PUT_U32_LABELS
-	static void *zero_labels[2] = { &&zero_int32, &&zero_int64 };
-	/* sum_type att */
-	static void *add_labels[2 * 2] = { &&add_int32_noatt, &&add_int32_att,
-				    &&add_int64_noatt, &&add_int64_att,
-	};
-	/* sum_type att shift */
-	static void *norm_labels[2 * 2 * 4] = { NULL,
-					 &&norm_int32_8_noatt,
-					 &&norm_int32_16_noatt,
-					 &&norm_int32_24_noatt,
-					 NULL,
-					 &&norm_int32_8_att,
-					 &&norm_int32_16_att,
-					 &&norm_int32_24_att,
-					 &&norm_int64_0_noatt,
-					 &&norm_int64_8_noatt,
-					 &&norm_int64_16_noatt,
-					 &&norm_int64_24_noatt,
-					 &&norm_int64_0_att,
-					 &&norm_int64_8_att,
-					 &&norm_int64_16_att,
-					 &&norm_int64_24_att,
-	};
-	struct route_priv *data = (struct route_priv *)plugin->extra_data;
-	void *zero, *get, *add, *norm, *put_u32;
-	int nsrcs = ttable->nsrcs;
-	char *dst;
-	int dst_step;
-	char *srcs[nsrcs];
-	int src_steps[nsrcs];
-	struct ttable_src src_tt[nsrcs];
-	u_int32_t sample = 0;
-	int srcidx, srcidx1 = 0;
-	for (srcidx = 0; srcidx < nsrcs; ++srcidx) {
-		const struct snd_pcm_plugin_channel *src_channel = &src_channels[ttable->srcs[srcidx].channel];
-		if (!src_channel->enabled)
-			continue;
-		srcs[srcidx1] = src_channel->area.addr + src_channel->area.first / 8;
-		src_steps[srcidx1] = src_channel->area.step / 8;
-		src_tt[srcidx1] = ttable->srcs[srcidx];
-		srcidx1++;
-	}
-	nsrcs = srcidx1;
-	if (nsrcs == 0) {
-		route_to_channel_from_zero(plugin, src_channels, dst_channel, ttable, frames);
-		return;
-	} else if (nsrcs == 1 && src_tt[0].as_int == ROUTE_PLUGIN_RESOLUTION) {
-		route_to_channel_from_one(plugin, src_channels, dst_channel, ttable, frames);
-		return;
-	}
-
 	dst_channel->enabled = 1;
-	zero = zero_labels[data->sum_type];
-	get = get_u_labels[data->get];
-	add = add_labels[data->sum_type * 2 + ttable->att];
-	norm = norm_labels[data->sum_type * 8 + ttable->att * 4 + 4 - data->src_sample_size];
-	put_u32 = put_u32_labels[data->put];
-	dst = dst_channel->area.addr + dst_channel->area.first / 8;
-	dst_step = dst_channel->area.step / 8;
-
-	while (frames-- > 0) {
-		struct ttable_src *ttp = src_tt;
-		union sum sum;
-
-		/* Zero sum */
-		goto *zero;
-	zero_int32:
-		sum.as_uint32 = 0;
-		goto zero_end;
-	zero_int64: 
-		sum.as_uint64 = 0;
-		goto zero_end;
-	zero_end:
-		for (srcidx = 0; srcidx < nsrcs; ++srcidx) {
-			char *src = srcs[srcidx];
-			
-			/* Get sample */
-			goto *get;
-#define GET_U_END after_get
-#include "plugin_ops.h"
-#undef GET_U_END
-		after_get:
-
-			/* Sum */
-			goto *add;
-		add_int32_att:
-			sum.as_uint32 += sample * ttp->as_int;
-			goto after_sum;
-		add_int32_noatt:
-			if (ttp->as_int)
-				sum.as_uint32 += sample;
-			goto after_sum;
-		add_int64_att:
-			sum.as_uint64 += (u_int64_t) sample * ttp->as_int;
-			goto after_sum;
-		add_int64_noatt:
-			if (ttp->as_int)
-				sum.as_uint64 += sample;
-			goto after_sum;
-		after_sum:
-			srcs[srcidx] += src_steps[srcidx];
-			ttp++;
-		}
-		
-		/* Normalization */
-		goto *norm;
-	norm_int32_8_att:
-		sum.as_uint64 = sum.as_uint32;
-	norm_int64_8_att:
-		sum.as_uint64 <<= 8;
-	norm_int64_0_att:
-		div(sum.as_uint64);
-		goto norm_int;
-
-	norm_int32_16_att:
-		sum.as_uint64 = sum.as_uint32;
-	norm_int64_16_att:
-		sum.as_uint64 <<= 16;
-		div(sum.as_uint64);
-		goto norm_int;
-
-	norm_int32_24_att:
-		sum.as_uint64 = sum.as_uint32;
-	norm_int64_24_att:
-		sum.as_uint64 <<= 24;
-		div(sum.as_uint64);
-		goto norm_int;
-
-	norm_int32_8_noatt:
-		sum.as_uint64 = sum.as_uint32;
-	norm_int64_8_noatt:
-		sum.as_uint64 <<= 8;
-		goto norm_int;
-
-	norm_int32_16_noatt:
-		sum.as_uint64 = sum.as_uint32;
-	norm_int64_16_noatt:
-		sum.as_uint64 <<= 16;
-		goto norm_int;
-
-	norm_int32_24_noatt:
-		sum.as_uint64 = sum.as_uint32;
-	norm_int64_24_noatt:
-		sum.as_uint64 <<= 24;
-		goto norm_int;
-
-	norm_int64_0_noatt:
-	norm_int:
-		if (sum.as_uint64 > (u_int32_t)0xffffffff)
-			sample = (u_int32_t)0xffffffff;
-		else
-			sample = sum.as_uint64;
-		goto after_norm;
-
-	after_norm:
-		
-		/* Put sample */
-		goto *put_u32;
-#define PUT_U32_END after_put_u32
-#include "plugin_ops.h"
-#undef PUT_U32_END
-	after_put_u32:
-		
-		dst += dst_step;
-	}
-}
-
-static int route_src_channels_mask(struct snd_pcm_plugin *plugin,
-				   unsigned long *dst_vmask,
-				   unsigned long **src_vmask)
-{
-	struct route_priv *data = (struct route_priv *)plugin->extra_data;
-	int schannels = plugin->src_format.channels;
-	int dchannels = plugin->dst_format.channels;
-	unsigned long *vmask = plugin->src_vmask;
-	int channel;
-	struct ttable_dst *dp = data->ttable;
-	bitmap_zero(vmask, schannels);
-	for (channel = 0; channel < dchannels; channel++, dp++) {
-		unsigned int src;
-		struct ttable_src *sp;
-		if (!test_bit(channel, dst_vmask))
-			continue;
-		sp = dp->srcs;
-		for (src = 0; src < dp->nsrcs; src++, sp++)
-			set_bit(sp->channel, vmask);
-	}
-	*src_vmask = vmask;
-	return 0;
-}
-
-static int route_dst_channels_mask(struct snd_pcm_plugin *plugin,
-				   unsigned long *src_vmask,
-				   unsigned long **dst_vmask)
-{
-	struct route_priv *data = (struct route_priv *)plugin->extra_data;
-	int dchannels = plugin->dst_format.channels;
-	unsigned long *vmask = plugin->dst_vmask;
-	int channel;
-	struct ttable_dst *dp = data->ttable;
-	bitmap_zero(vmask, dchannels);
-	for (channel = 0; channel < dchannels; channel++, dp++) {
-		unsigned int src;
-		struct ttable_src *sp;
-		sp = dp->srcs;
-		for (src = 0; src < dp->nsrcs; src++, sp++) {
-			if (test_bit(sp->channel, src_vmask)) {
-				set_bit(channel, vmask);
-				break;
-			}
-		}
-	}
-	*dst_vmask = vmask;
-	return 0;
-}
-
-static void route_free(struct snd_pcm_plugin *plugin)
-{
-	struct route_priv *data = (struct route_priv *)plugin->extra_data;
-	unsigned int dst_channel;
-	for (dst_channel = 0; dst_channel < plugin->dst_format.channels; ++dst_channel) {
-		kfree(data->ttable[dst_channel].srcs);
-	}
-}
-
-static int route_load_ttable(struct snd_pcm_plugin *plugin, 
-			     const int *src_ttable)
-{
-	struct route_priv *data;
-	unsigned int src_channel, dst_channel;
-	const int *sptr;
-	struct ttable_dst *dptr;
-	if (src_ttable == NULL)
-		return 0;
-	data = (struct route_priv *)plugin->extra_data;
-	dptr = data->ttable;
-	sptr = src_ttable;
-	plugin->private_free = route_free;
-	for (dst_channel = 0; dst_channel < plugin->dst_format.channels; ++dst_channel) {
-		int t = 0;
-		int att = 0;
-		int nsrcs = 0;
-		struct ttable_src srcs[plugin->src_format.channels];
-		for (src_channel = 0; src_channel < plugin->src_format.channels; ++src_channel) {
-			snd_assert(*sptr >= 0 || *sptr <= FULL, return -ENXIO);
-			if (*sptr != 0) {
-				srcs[nsrcs].channel = src_channel;
-				srcs[nsrcs].as_int = *sptr;
-				if (*sptr != FULL)
-					att = 1;
-				t += *sptr;
-				nsrcs++;
-			}
-			sptr++;
-		}
-		dptr->att = att;
-		dptr->nsrcs = nsrcs;
-		if (nsrcs == 0)
-			dptr->func = route_to_channel_from_zero;
-		else if (nsrcs == 1 && !att)
-			dptr->func = route_to_channel_from_one;
-		else
-			dptr->func = route_to_channel;
-		if (nsrcs > 0) {
-                        int srcidx;
-			dptr->srcs = kcalloc(nsrcs, sizeof(*srcs), GFP_KERNEL);
-                        for(srcidx = 0; srcidx < nsrcs; srcidx++)
-				dptr->srcs[srcidx] = srcs[srcidx];
-		} else
-			dptr->srcs = NULL;
-		dptr++;
-	}
-	return 0;
+	snd_pcm_area_copy(&src_channel->area, 0, &dst_channel->area, 0, frames, format);
 }
 
 static snd_pcm_sframes_t route_transfer(struct snd_pcm_plugin *plugin,
-			      const struct snd_pcm_plugin_channel *src_channels,
-			      struct snd_pcm_plugin_channel *dst_channels,
-			      snd_pcm_uframes_t frames)
+					const struct snd_pcm_plugin_channel *src_channels,
+					struct snd_pcm_plugin_channel *dst_channels,
+					snd_pcm_uframes_t frames)
 {
-	struct route_priv *data;
-	int src_nchannels, dst_nchannels;
-	int dst_channel;
-	struct ttable_dst *ttp;
+	int nsrcs, ndsts, dst;
 	struct snd_pcm_plugin_channel *dvp;
+	int format;
 
 	snd_assert(plugin != NULL && src_channels != NULL && dst_channels != NULL, return -ENXIO);
 	if (frames == 0)
 		return 0;
-	data = (struct route_priv *)plugin->extra_data;
 
-	src_nchannels = plugin->src_format.channels;
-	dst_nchannels = plugin->dst_format.channels;
+	nsrcs = plugin->src_format.channels;
+	ndsts = plugin->dst_format.channels;
 
-#ifdef CONFIG_SND_DEBUG
-	{
-		int src_channel;
-		for (src_channel = 0; src_channel < src_nchannels; ++src_channel) {
-			snd_assert(src_channels[src_channel].area.first % 8 == 0 ||
-				   src_channels[src_channel].area.step % 8 == 0,
-				   return -ENXIO);
-		}
-		for (dst_channel = 0; dst_channel < dst_nchannels; ++dst_channel) {
-			snd_assert(dst_channels[dst_channel].area.first % 8 == 0 ||
-				   dst_channels[dst_channel].area.step % 8 == 0,
-				   return -ENXIO);
-		}
-	}
-#endif
-
-	ttp = data->ttable;
+	format = plugin->dst_format.format;
 	dvp = dst_channels;
-	for (dst_channel = 0; dst_channel < dst_nchannels; ++dst_channel) {
-		ttp->func(plugin, src_channels, dvp, ttp, frames);
-		dvp++;
-		ttp++;
+	if (nsrcs <= 1) {
+		/* expand to all channels */
+		for (dst = 0; dst < ndsts; ++dst) {
+			copy_area(src_channels, dvp, frames, format);
+			dvp++;
+		}
+		return frames;
 	}
-	return frames;
-}
 
-int getput_index(int format)
-{
-	int sign, width, endian;
-	sign = !snd_pcm_format_signed(format);
-	width = snd_pcm_format_width(format) / 8 - 1;
-	if (width < 0 || width > 3) {
-		snd_printk(KERN_ERR "snd-pcm-oss: invalid format %d\n", format);
-		width = 0;
+	for (dst = 0; dst < ndsts && dst < nsrcs; ++dst) {
+		copy_area(src_channels, dvp, frames, format);
+		dvp++;
+		src_channels++;
 	}
-#ifdef SNDRV_LITTLE_ENDIAN
-	endian = snd_pcm_format_big_endian(format);
-#else
-	endian = snd_pcm_format_little_endian(format);
-#endif
-	if (endian < 0)
-		endian = 0;
-	return width * 4 + endian * 2 + sign;
+	if (dst < ndsts)
+		zero_areas(dvp, ndsts - dst, frames, format);
+	return frames;
 }
 
 int snd_pcm_plugin_build_route(struct snd_pcm_substream *plug,
 			       struct snd_pcm_plugin_format *src_format,
 			       struct snd_pcm_plugin_format *dst_format,
-			       int *ttable,
 			       struct snd_pcm_plugin **r_plugin)
 {
-	struct route_priv *data;
 	struct snd_pcm_plugin *plugin;
 	int err;
 
 	snd_assert(r_plugin != NULL, return -ENXIO);
 	*r_plugin = NULL;
 	snd_assert(src_format->rate == dst_format->rate, return -ENXIO);
-	snd_assert(snd_pcm_format_linear(src_format->format) != 0 &&
-		   snd_pcm_format_linear(dst_format->format) != 0,
-		   return -ENXIO);
+	snd_assert(src_format->format == dst_format->format, return -ENXIO);
 
-	err = snd_pcm_plugin_build(plug, "attenuated route conversion",
-				   src_format, dst_format,
-				   sizeof(struct route_priv) +
-				   sizeof(data->ttable[0]) * dst_format->channels,
-				   &plugin);
+	err = snd_pcm_plugin_build(plug, "route conversion",
+				   src_format, dst_format, 0, &plugin);
 	if (err < 0)
 		return err;
 
-	data = (struct route_priv *)plugin->extra_data;
-
-	data->get = getput_index(src_format->format);
-	snd_assert(data->get >= 0 && data->get < 4*2*2, return -EINVAL);
-	data->put = getput_index(dst_format->format);
-	snd_assert(data->get >= 0 && data->get < 4*2*2, return -EINVAL);
-	data->conv = conv_index(src_format->format, dst_format->format);
-
-	if (snd_pcm_format_width(src_format->format) == 32)
-		data->sum_type = R_UINT64;
-	else
-		data->sum_type = R_UINT32;
-	data->src_sample_size = snd_pcm_format_width(src_format->format) / 8;
-
-	if ((err = route_load_ttable(plugin, ttable)) < 0) {
-		snd_pcm_plugin_free(plugin);
-		return err;
-	}
 	plugin->transfer = route_transfer;
-	plugin->src_channels_mask = route_src_channels_mask;
-	plugin->dst_channels_mask = route_dst_channels_mask;
 	*r_plugin = plugin;
 	return 0;
 }
+
+#endif
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 28ca61eb..3da6a38 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -23,6 +23,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/time.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/minors.h>
 #include <sound/pcm.h>
@@ -35,7 +36,7 @@
 
 static LIST_HEAD(snd_pcm_devices);
 static LIST_HEAD(snd_pcm_notify_list);
-static DECLARE_MUTEX(register_mutex);
+static DEFINE_MUTEX(register_mutex);
 
 static int snd_pcm_free(struct snd_pcm *pcm);
 static int snd_pcm_dev_free(struct snd_device *device);
@@ -67,7 +68,7 @@
 
 			if (get_user(device, (int __user *)arg))
 				return -EFAULT;
-			down(&register_mutex);
+			mutex_lock(&register_mutex);
 			device = device < 0 ? 0 : device + 1;
 			while (device < SNDRV_PCM_DEVICES) {
 				if (snd_pcm_search(card, device))
@@ -76,7 +77,7 @@
 			}
 			if (device == SNDRV_PCM_DEVICES)
 				device = -1;
-			up(&register_mutex);
+			mutex_unlock(&register_mutex);
 			if (put_user(device, (int __user *)arg))
 				return -EFAULT;
 			return 0;
@@ -100,7 +101,7 @@
 				return -EINVAL;
 			if (get_user(subdevice, &info->subdevice))
 				return -EFAULT;
-			down(&register_mutex);
+			mutex_lock(&register_mutex);
 			pcm = snd_pcm_search(card, device);
 			if (pcm == NULL) {
 				err = -ENXIO;
@@ -125,7 +126,7 @@
 			}
 			err = snd_pcm_info_user(substream, info);
 		_error:
-			up(&register_mutex);
+			mutex_unlock(&register_mutex);
 			return err;
 		}
 	case SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE:
@@ -140,6 +141,9 @@
 	}
 	return -ENOIOCTLCMD;
 }
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_SND_VERBOSE_PROCFS)
+
 #define STATE(v) [SNDRV_PCM_STATE_##v] = #v
 #define STREAM(v) [SNDRV_PCM_STREAM_##v] = #v
 #define READY(v) [SNDRV_PCM_READY_##v] = #v
@@ -197,7 +201,6 @@
 	return snd_pcm_format_names[format];
 }
 
-#ifdef CONFIG_PROC_FS
 static char *snd_pcm_stream_names[] = {
 	STREAM(PLAYBACK),
 	STREAM(CAPTURE),
@@ -260,6 +263,7 @@
 
 #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
 #include <linux/soundcard.h>
+
 static const char *snd_pcm_oss_format_name(int format)
 {
 	switch (format) {
@@ -622,7 +626,7 @@
 	struct snd_pcm_substream *substream, *prev;
 
 #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
-	init_MUTEX(&pstr->oss.setup_mutex);
+	mutex_init(&pstr->oss.setup_mutex);
 #endif
 	pstr->stream = stream;
 	pstr->pcm = pcm;
@@ -716,7 +720,7 @@
 		snd_pcm_free(pcm);
 		return err;
 	}
-	init_MUTEX(&pcm->open_mutex);
+	mutex_init(&pcm->open_mutex);
 	init_waitqueue_head(&pcm->open_wait);
 	if ((err = snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops)) < 0) {
 		snd_pcm_free(pcm);
@@ -902,9 +906,9 @@
 	struct snd_pcm *pcm = device->device_data;
 
 	snd_assert(pcm != NULL && device != NULL, return -ENXIO);
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	if (snd_pcm_search(pcm->card, pcm->device)) {
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return -EBUSY;
 	}
 	list_add_tail(&pcm->list, &snd_pcm_devices);
@@ -928,7 +932,7 @@
 					       pcm, str)) < 0)
 		{
 			list_del(&pcm->list);
-			up(&register_mutex);
+			mutex_unlock(&register_mutex);
 			return err;
 		}
 		for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
@@ -939,7 +943,7 @@
 		notify = list_entry(list, struct snd_pcm_notify, list);
 		notify->n_register(pcm);
 	}
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	return 0;
 }
 
@@ -950,7 +954,7 @@
 	struct snd_pcm_substream *substream;
 	int cidx;
 
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	list_del_init(&pcm->list);
 	for (cidx = 0; cidx < 2; cidx++)
 		for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
@@ -961,7 +965,7 @@
 		notify = list_entry(list, struct snd_pcm_notify, list);
 		notify->n_disconnect(pcm);
 	}
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	return 0;
 }
 
@@ -973,7 +977,7 @@
 	struct snd_pcm *pcm = device->device_data;
 
 	snd_assert(pcm != NULL, return -ENXIO);
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	list_del(&pcm->list);
 	for (cidx = 0; cidx < 2; cidx++) {
 		devtype = -1;
@@ -994,7 +998,7 @@
 		notify = list_entry(list, struct snd_pcm_notify, list);
 		notify->n_unregister(pcm);
 	}
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	return snd_pcm_free(pcm);
 }
 
@@ -1003,7 +1007,7 @@
 	struct list_head *p;
 
 	snd_assert(notify != NULL && notify->n_register != NULL && notify->n_unregister != NULL, return -EINVAL);
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	if (nfree) {
 		list_del(&notify->list);
 		list_for_each(p, &snd_pcm_devices)
@@ -1014,7 +1018,7 @@
 		list_for_each(p, &snd_pcm_devices)
 			notify->n_register(list_entry(p, struct snd_pcm, list));
 	}
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	return 0;
 }
 
@@ -1029,7 +1033,7 @@
 	struct list_head *p;
 	struct snd_pcm *pcm;
 
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	list_for_each(p, &snd_pcm_devices) {
 		pcm = list_entry(p, struct snd_pcm, list);
 		snd_iprintf(buffer, "%02i-%02i: %s : %s",
@@ -1042,7 +1046,7 @@
 				    pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count);
 		snd_iprintf(buffer, "\n");
 	}
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 }
 
 static struct snd_info_entry *snd_pcm_proc_entry = NULL;
@@ -1101,7 +1105,6 @@
 EXPORT_SYMBOL(snd_pcm_notify);
 EXPORT_SYMBOL(snd_pcm_open_substream);
 EXPORT_SYMBOL(snd_pcm_release_substream);
-EXPORT_SYMBOL(snd_pcm_format_name);
   /* pcm_native.c */
 EXPORT_SYMBOL(snd_pcm_link_rwlock);
 #ifdef CONFIG_PM
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index f3d5de7..01f150f 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -2112,7 +2112,7 @@
 	}
 	init_waitqueue_entry(&wait, current);
 	add_wait_queue(&pcm->open_wait, &wait);
-	down(&pcm->open_mutex);
+	mutex_lock(&pcm->open_mutex);
 	while (1) {
 		err = snd_pcm_open_file(file, pcm, stream, &pcm_file);
 		if (err >= 0)
@@ -2125,16 +2125,16 @@
 		} else
 			break;
 		set_current_state(TASK_INTERRUPTIBLE);
-		up(&pcm->open_mutex);
+		mutex_unlock(&pcm->open_mutex);
 		schedule();
-		down(&pcm->open_mutex);
+		mutex_lock(&pcm->open_mutex);
 		if (signal_pending(current)) {
 			err = -ERESTARTSYS;
 			break;
 		}
 	}
 	remove_wait_queue(&pcm->open_wait, &wait);
-	up(&pcm->open_mutex);
+	mutex_unlock(&pcm->open_mutex);
 	if (err < 0)
 		goto __error;
 	return err;
@@ -2160,9 +2160,9 @@
 	pcm = substream->pcm;
 	snd_pcm_drop(substream);
 	fasync_helper(-1, file, 0, &substream->runtime->fasync);
-	down(&pcm->open_mutex);
+	mutex_lock(&pcm->open_mutex);
 	snd_pcm_release_file(pcm_file);
-	up(&pcm->open_mutex);
+	mutex_unlock(&pcm->open_mutex);
 	wake_up(&pcm->open_wait);
 	module_put(pcm->card->module);
 	snd_card_file_remove(pcm->card, file);
@@ -2539,6 +2539,14 @@
 		return snd_pcm_drain(substream);
 	case SNDRV_PCM_IOCTL_DROP:
 		return snd_pcm_drop(substream);
+	case SNDRV_PCM_IOCTL_PAUSE:
+	{
+		int res;
+		snd_pcm_stream_lock_irq(substream);
+		res = snd_pcm_pause(substream, (int)(unsigned long)arg);
+		snd_pcm_stream_unlock_irq(substream);
+		return res;
+	}
 	}
 	snd_printd("unknown ioctl = 0x%x\n", cmd);
 	return -ENOTTY;
@@ -2619,14 +2627,6 @@
 		__put_user(result, _frames);
 		return result < 0 ? result : 0;
 	}
-	case SNDRV_PCM_IOCTL_PAUSE:
-	{
-		int res;
-		snd_pcm_stream_lock_irq(substream);
-		res = snd_pcm_pause(substream, (int)(unsigned long)arg);
-		snd_pcm_stream_unlock_irq(substream);
-		return res;
-	}
 	}
 	return snd_pcm_common_ioctl1(substream, cmd, arg);
 }
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index d4d124e..6b7a367 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -28,6 +28,7 @@
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/wait.h>
+#include <linux/mutex.h>
 #include <linux/moduleparam.h>
 #include <linux/delay.h>
 #include <linux/wait.h>
@@ -57,7 +58,7 @@
 static int snd_rawmidi_dev_unregister(struct snd_device *device);
 
 static LIST_HEAD(snd_rawmidi_devices);
-static DECLARE_MUTEX(register_mutex);
+static DEFINE_MUTEX(register_mutex);
 
 static struct snd_rawmidi *snd_rawmidi_search(struct snd_card *card, int device)
 {
@@ -237,9 +238,9 @@
 
 	if (rfile)
 		rfile->input = rfile->output = NULL;
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	rmidi = snd_rawmidi_search(card, device);
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	if (rmidi == NULL) {
 		err = -ENODEV;
 		goto __error1;
@@ -249,7 +250,7 @@
 		goto __error1;
 	}
 	if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK))
-		down(&rmidi->open_mutex);
+		mutex_lock(&rmidi->open_mutex);
 	if (mode & SNDRV_RAWMIDI_LFLG_INPUT) {
 		if (!(rmidi->info_flags & SNDRV_RAWMIDI_INFO_INPUT)) {
 			err = -ENXIO;
@@ -359,7 +360,7 @@
 		soutput = NULL;
 	}
 	if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK))
-		up(&rmidi->open_mutex);
+		mutex_unlock(&rmidi->open_mutex);
 	if (rfile) {
 		rfile->rmidi = rmidi;
 		rfile->input = sinput;
@@ -374,7 +375,7 @@
 		snd_rawmidi_runtime_free(soutput);
 	module_put(rmidi->card->module);
 	if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK))
-		up(&rmidi->open_mutex);
+		mutex_unlock(&rmidi->open_mutex);
       __error1:
 	return err;
 }
@@ -422,7 +423,7 @@
 	}
 	init_waitqueue_entry(&wait, current);
 	add_wait_queue(&rmidi->open_wait, &wait);
-	down(&rmidi->open_mutex);
+	mutex_lock(&rmidi->open_mutex);
 	while (1) {
 		subdevice = -1;
 		down_read(&card->controls_rwsem);
@@ -446,9 +447,9 @@
 		} else
 			break;
 		set_current_state(TASK_INTERRUPTIBLE);
-		up(&rmidi->open_mutex);
+		mutex_unlock(&rmidi->open_mutex);
 		schedule();
-		down(&rmidi->open_mutex);
+		mutex_lock(&rmidi->open_mutex);
 		if (signal_pending(current)) {
 			err = -ERESTARTSYS;
 			break;
@@ -467,7 +468,7 @@
 		snd_card_file_remove(card, file);
 		kfree(rawmidi_file);
 	}
-	up(&rmidi->open_mutex);
+	mutex_unlock(&rmidi->open_mutex);
 	return err;
 }
 
@@ -480,7 +481,7 @@
 	snd_assert(rfile != NULL, return -ENXIO);
 	snd_assert(rfile->input != NULL || rfile->output != NULL, return -ENXIO);
 	rmidi = rfile->rmidi;
-	down(&rmidi->open_mutex);
+	mutex_lock(&rmidi->open_mutex);
 	if (rfile->input != NULL) {
 		substream = rfile->input;
 		rfile->input = NULL;
@@ -514,7 +515,7 @@
 		}
 		rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_opened--;
 	}
-	up(&rmidi->open_mutex);
+	mutex_unlock(&rmidi->open_mutex);
 	module_put(rmidi->card->module);
 	return 0;
 }
@@ -576,9 +577,9 @@
 	struct snd_rawmidi_substream *substream;
 	struct list_head *list;
 
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	rmidi = snd_rawmidi_search(card, info->device);
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	if (!rmidi)
 		return -ENXIO;
 	if (info->stream < 0 || info->stream > 1)
@@ -818,7 +819,7 @@
 		
 		if (get_user(device, (int __user *)argp))
 			return -EFAULT;
-		down(&register_mutex);
+		mutex_lock(&register_mutex);
 		device = device < 0 ? 0 : device + 1;
 		while (device < SNDRV_RAWMIDI_DEVICES) {
 			if (snd_rawmidi_search(card, device))
@@ -827,7 +828,7 @@
 		}
 		if (device == SNDRV_RAWMIDI_DEVICES)
 			device = -1;
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		if (put_user(device, (int __user *)argp))
 			return -EFAULT;
 		return 0;
@@ -1314,7 +1315,7 @@
 
 	rmidi = entry->private_data;
 	snd_iprintf(buffer, "%s\n\n", rmidi->name);
-	down(&rmidi->open_mutex);
+	mutex_lock(&rmidi->open_mutex);
 	if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT) {
 		list_for_each(list, &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) {
 			substream = list_entry(list, struct snd_rawmidi_substream, list);
@@ -1355,7 +1356,7 @@
 			}
 		}
 	}
-	up(&rmidi->open_mutex);
+	mutex_unlock(&rmidi->open_mutex);
 }
 
 /*
@@ -1436,7 +1437,7 @@
 	}
 	rmidi->card = card;
 	rmidi->device = device;
-	init_MUTEX(&rmidi->open_mutex);
+	mutex_init(&rmidi->open_mutex);
 	init_waitqueue_head(&rmidi->open_wait);
 	if (id != NULL)
 		strlcpy(rmidi->id, id, sizeof(rmidi->id));
@@ -1507,9 +1508,9 @@
 
 	if (rmidi->device >= SNDRV_RAWMIDI_DEVICES)
 		return -ENOMEM;
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	if (snd_rawmidi_search(rmidi->card, rmidi->device)) {
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return -EBUSY;
 	}
 	list_add_tail(&rmidi->list, &snd_rawmidi_devices);
@@ -1519,14 +1520,14 @@
 				       &snd_rawmidi_f_ops, rmidi, name)) < 0) {
 		snd_printk(KERN_ERR "unable to register rawmidi device %i:%i\n", rmidi->card->number, rmidi->device);
 		list_del(&rmidi->list);
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return err;
 	}
 	if (rmidi->ops && rmidi->ops->dev_register &&
 	    (err = rmidi->ops->dev_register(rmidi)) < 0) {
 		snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device);
 		list_del(&rmidi->list);
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return err;
 	}
 #ifdef CONFIG_SND_OSSEMUL
@@ -1553,7 +1554,7 @@
 		}
 	}
 #endif /* CONFIG_SND_OSSEMUL */
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	sprintf(name, "midi%d", rmidi->device);
 	entry = snd_info_create_card_entry(rmidi->card, name, rmidi->card->proc_root);
 	if (entry) {
@@ -1583,9 +1584,9 @@
 {
 	struct snd_rawmidi *rmidi = device->device_data;
 
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	list_del_init(&rmidi->list);
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	return 0;
 }
 
@@ -1594,7 +1595,7 @@
 	struct snd_rawmidi *rmidi = device->device_data;
 
 	snd_assert(rmidi != NULL, return -ENXIO);
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	list_del(&rmidi->list);
 	if (rmidi->proc_entry) {
 		snd_info_unregister(rmidi->proc_entry);
@@ -1616,7 +1617,7 @@
 	if (rmidi->ops && rmidi->ops->dev_unregister)
 		rmidi->ops->dev_unregister(rmidi);
 	snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device);
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
 	if (rmidi->seq_dev) {
 		snd_device_free(rmidi->card, rmidi->seq_dev);
diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c
index c98f0ba..b991978 100644
--- a/sound/core/seq/oss/seq_oss.c
+++ b/sound/core/seq/oss/seq_oss.c
@@ -24,6 +24,7 @@
 #include <linux/init.h>
 #include <linux/smp_lock.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/minors.h>
 #include <sound/initval.h>
@@ -124,7 +125,7 @@
  * ALSA minor device interface
  */
 
-static DECLARE_MUTEX(register_mutex);
+static DEFINE_MUTEX(register_mutex);
 
 static int
 odev_open(struct inode *inode, struct file *file)
@@ -136,9 +137,9 @@
 	else
 		level = SNDRV_SEQ_OSS_MODE_SYNTH;
 
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	rc = snd_seq_oss_open(file, level);
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 
 	return rc;
 }
@@ -153,9 +154,9 @@
 
 	snd_seq_oss_drain_write(dp);
 
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	snd_seq_oss_release(dp);
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 
 	return 0;
 }
@@ -224,13 +225,13 @@
 {
 	int rc;
 
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	if ((rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER,
 					  NULL, 0,
 					  &seq_oss_f_ops, NULL,
 					  SNDRV_SEQ_OSS_DEVNAME)) < 0) {
 		snd_printk(KERN_ERR "can't register device seq\n");
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return rc;
 	}
 	if ((rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC,
@@ -239,24 +240,24 @@
 					  SNDRV_SEQ_OSS_DEVNAME)) < 0) {
 		snd_printk(KERN_ERR "can't register device music\n");
 		snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, NULL, 0);
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return rc;
 	}
 	debug_printk(("device registered\n"));
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	return 0;
 }
 
 static void
 unregister_device(void)
 {
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	debug_printk(("device unregistered\n"));
 	if (snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC, NULL, 0) < 0)		
 		snd_printk(KERN_ERR "error unregister device music\n");
 	if (snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, NULL, 0) < 0)
 		snd_printk(KERN_ERR "error unregister device seq\n");
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 }
 
 /*
@@ -270,12 +271,12 @@
 static void
 info_read(struct snd_info_entry *entry, struct snd_info_buffer *buf)
 {
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	snd_iprintf(buf, "OSS sequencer emulation version %s\n", SNDRV_SEQ_OSS_VERSION_STR);
 	snd_seq_oss_system_info_read(buf);
 	snd_seq_oss_synth_info_read(buf);
 	snd_seq_oss_midi_info_read(buf);
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 }
 
 
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index fd2032e..bb15d9e 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -67,7 +67,7 @@
 #define SNDRV_SEQ_LFLG_OPEN	(SNDRV_SEQ_LFLG_INPUT|SNDRV_SEQ_LFLG_OUTPUT)
 
 static DEFINE_SPINLOCK(clients_lock);
-static DECLARE_MUTEX(register_mutex);
+static DEFINE_MUTEX(register_mutex);
 
 /*
  * client table
@@ -237,7 +237,7 @@
 	client->type = NO_CLIENT;
 	snd_use_lock_init(&client->use_lock);
 	rwlock_init(&client->ports_lock);
-	init_MUTEX(&client->ports_mutex);
+	mutex_init(&client->ports_mutex);
 	INIT_LIST_HEAD(&client->ports_list_head);
 
 	/* find free slot in the client table */
@@ -290,7 +290,7 @@
 
 static void seq_free_client(struct snd_seq_client * client)
 {
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	switch (client->type) {
 	case NO_CLIENT:
 		snd_printk(KERN_WARNING "Seq: Trying to free unused client %d\n",
@@ -306,7 +306,7 @@
 		snd_printk(KERN_ERR "Seq: Trying to free client %d with undefined type = %d\n",
 			   client->number, client->type);
 	}
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 
 	snd_seq_system_client_ev_client_exit(client->number);
 }
@@ -322,11 +322,11 @@
 	struct snd_seq_client *client;
 	struct snd_seq_user_client *user;
 
-	if (down_interruptible(&register_mutex))
+	if (mutex_lock_interruptible(&register_mutex))
 		return -ERESTARTSYS;
 	client = seq_create_client1(-1, SNDRV_SEQ_DEFAULT_EVENTS);
 	if (client == NULL) {
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return -ENOMEM;	/* failure code */
 	}
 
@@ -346,14 +346,14 @@
 		if (user->fifo == NULL) {
 			seq_free_client1(client);
 			kfree(client);
-			up(&register_mutex);
+			mutex_unlock(&register_mutex);
 			return -ENOMEM;
 		}
 	}
 
 	usage_alloc(&client_usage, 1);
 	client->type = USER_CLIENT;
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 
 	c = client->number;
 	file->private_data = client;
@@ -1743,7 +1743,7 @@
 	if (queue == NULL)
 		return -EINVAL;
 
-	if (down_interruptible(&queue->timer_mutex)) {
+	if (mutex_lock_interruptible(&queue->timer_mutex)) {
 		queuefree(queue);
 		return -ERESTARTSYS;
 	}
@@ -1756,7 +1756,7 @@
 		timer.u.alsa.id = tmr->alsa_id;
 		timer.u.alsa.resolution = tmr->preferred_resolution;
 	}
-	up(&queue->timer_mutex);
+	mutex_unlock(&queue->timer_mutex);
 	queuefree(queue);
 	
 	if (copy_to_user(arg, &timer, sizeof(timer)))
@@ -1785,7 +1785,7 @@
 		q = queueptr(timer.queue);
 		if (q == NULL)
 			return -ENXIO;
-		if (down_interruptible(&q->timer_mutex)) {
+		if (mutex_lock_interruptible(&q->timer_mutex)) {
 			queuefree(q);
 			return -ERESTARTSYS;
 		}
@@ -1797,7 +1797,7 @@
 			tmr->preferred_resolution = timer.u.alsa.resolution;
 		}
 		result = snd_seq_queue_timer_open(timer.queue);
-		up(&q->timer_mutex);
+		mutex_unlock(&q->timer_mutex);
 		queuefree(q);
 	} else {
 		return -EPERM;
@@ -1866,8 +1866,7 @@
 	info.output_pool = cptr->pool->size;
 	info.output_room = cptr->pool->room;
 	info.output_free = info.output_pool;
-	if (cptr->pool)
-		info.output_free = snd_seq_unused_cells(cptr->pool);
+	info.output_free = snd_seq_unused_cells(cptr->pool);
 	if (cptr->type == USER_CLIENT) {
 		info.input_pool = cptr->data.user.fifo_pool_size;
 		info.input_free = info.input_pool;
@@ -2230,7 +2229,7 @@
 	if (card == NULL && client_index >= SNDRV_SEQ_GLOBAL_CLIENTS)
 		return -EINVAL;
 
-	if (down_interruptible(&register_mutex))
+	if (mutex_lock_interruptible(&register_mutex))
 		return -ERESTARTSYS;
 
 	if (card) {
@@ -2243,7 +2242,7 @@
 	/* empty write queue as default */
 	client = seq_create_client1(client_index, 0);
 	if (client == NULL) {
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return -EBUSY;	/* failure code */
 	}
 	usage_alloc(&client_usage, 1);
@@ -2256,7 +2255,7 @@
 	va_end(args);
 
 	client->type = KERNEL_CLIENT;
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 
 	/* make others aware this new client */
 	snd_seq_system_client_ev_client_start(client->number);
@@ -2464,7 +2463,7 @@
 {
 	struct list_head *l;
 
-	down(&client->ports_mutex);
+	mutex_lock(&client->ports_mutex);
 	list_for_each(l, &client->ports_list_head) {
 		struct snd_seq_client_port *p = list_entry(l, struct snd_seq_client_port, list);
 		snd_iprintf(buffer, "  Port %3d : \"%s\" (%c%c%c%c)\n",
@@ -2476,7 +2475,7 @@
 		snd_seq_info_dump_subscribers(buffer, &p->c_src, 1, "    Connecting To: ");
 		snd_seq_info_dump_subscribers(buffer, &p->c_dest, 0, "    Connected From: ");
 	}
-	up(&client->ports_mutex);
+	mutex_unlock(&client->ports_mutex);
 }
 
 
@@ -2550,16 +2549,16 @@
 {
 	int err;
 
-	if (down_interruptible(&register_mutex))
+	if (mutex_lock_interruptible(&register_mutex))
 		return -ERESTARTSYS;
 
 	if ((err = snd_register_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0,
 				       &snd_seq_f_ops, NULL, "seq")) < 0) {
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return err;
 	}
 	
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 
 	return 0;
 }
diff --git a/sound/core/seq/seq_clientmgr.h b/sound/core/seq/seq_clientmgr.h
index 450091c..5e04e20 100644
--- a/sound/core/seq/seq_clientmgr.h
+++ b/sound/core/seq/seq_clientmgr.h
@@ -58,7 +58,7 @@
 	int num_ports;		/* number of ports */
 	struct list_head ports_list_head;
 	rwlock_t ports_lock;
-	struct semaphore ports_mutex;
+	struct mutex ports_mutex;
 	int convert32;		/* convert 32->64bit */
 
 	/* output pool */
diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c
index 9ece443..d9a3e5a 100644
--- a/sound/core/seq/seq_device.c
+++ b/sound/core/seq/seq_device.c
@@ -45,6 +45,7 @@
 #include <sound/initval.h>
 #include <linux/kmod.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
 
 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
 MODULE_DESCRIPTION("ALSA sequencer device management");
@@ -69,7 +70,7 @@
 	struct list_head dev_list;	/* list of devices */
 	int num_devices;	/* number of associated devices */
 	int num_init_devices;	/* number of initialized devices */
-	struct semaphore reg_mutex;
+	struct mutex reg_mutex;
 
 	struct list_head list;	/* next driver */
 };
@@ -77,7 +78,7 @@
 
 static LIST_HEAD(opslist);
 static int num_ops;
-static DECLARE_MUTEX(ops_mutex);
+static DEFINE_MUTEX(ops_mutex);
 #ifdef CONFIG_PROC_FS
 static struct snd_info_entry *info_entry = NULL;
 #endif
@@ -108,7 +109,7 @@
 {
 	struct list_head *head;
 
-	down(&ops_mutex);
+	mutex_lock(&ops_mutex);
 	list_for_each(head, &opslist) {
 		struct ops_list *ops = list_entry(head, struct ops_list, list);
 		snd_iprintf(buffer, "snd-%s%s%s%s,%d\n",
@@ -118,7 +119,7 @@
 				ops->driver & DRIVER_LOCKED ? ",locked" : "",
 				ops->num_devices);
 	}
-	up(&ops_mutex);	
+	mutex_unlock(&ops_mutex);
 }
 #endif
  
@@ -154,20 +155,20 @@
 	if (! current->fs->root)
 		return;
 
-	down(&ops_mutex);
+	mutex_lock(&ops_mutex);
 	list_for_each(head, &opslist) {
 		struct ops_list *ops = list_entry(head, struct ops_list, list);
 		if (! (ops->driver & DRIVER_LOADED) &&
 		    ! (ops->driver & DRIVER_REQUESTED)) {
 			ops->used++;
-			up(&ops_mutex);
+			mutex_unlock(&ops_mutex);
 			ops->driver |= DRIVER_REQUESTED;
 			request_module("snd-%s", ops->id);
-			down(&ops_mutex);
+			mutex_lock(&ops_mutex);
 			ops->used--;
 		}
 	}
-	up(&ops_mutex);
+	mutex_unlock(&ops_mutex);
 #endif
 }
 
@@ -214,10 +215,10 @@
 	dev->status = SNDRV_SEQ_DEVICE_FREE;
 
 	/* add this device to the list */
-	down(&ops->reg_mutex);
+	mutex_lock(&ops->reg_mutex);
 	list_add_tail(&dev->list, &ops->dev_list);
 	ops->num_devices++;
-	up(&ops->reg_mutex);
+	mutex_unlock(&ops->reg_mutex);
 
 	unlock_driver(ops);
 	
@@ -246,10 +247,10 @@
 		return -ENXIO;
 
 	/* remove the device from the list */
-	down(&ops->reg_mutex);
+	mutex_lock(&ops->reg_mutex);
 	list_del(&dev->list);
 	ops->num_devices--;
-	up(&ops->reg_mutex);
+	mutex_unlock(&ops->reg_mutex);
 
 	free_device(dev, ops);
 	if (dev->private_free)
@@ -344,7 +345,7 @@
 		return -EBUSY;
 	}
 
-	down(&ops->reg_mutex);
+	mutex_lock(&ops->reg_mutex);
 	/* copy driver operators */
 	ops->ops = *entry;
 	ops->driver |= DRIVER_LOADED;
@@ -355,7 +356,7 @@
 		struct snd_seq_device *dev = list_entry(head, struct snd_seq_device, list);
 		init_device(dev, ops);
 	}
-	up(&ops->reg_mutex);
+	mutex_unlock(&ops->reg_mutex);
 
 	unlock_driver(ops);
 	snd_seq_autoload_unlock();
@@ -378,17 +379,17 @@
 
 	/* set up driver entry */
 	strlcpy(ops->id, id, sizeof(ops->id));
-	init_MUTEX(&ops->reg_mutex);
+	mutex_init(&ops->reg_mutex);
 	ops->driver = DRIVER_EMPTY;
 	INIT_LIST_HEAD(&ops->dev_list);
 	/* lock this instance */
 	ops->used = 1;
 
 	/* register driver entry */
-	down(&ops_mutex);
+	mutex_lock(&ops_mutex);
 	list_add_tail(&ops->list, &opslist);
 	num_ops++;
-	up(&ops_mutex);
+	mutex_unlock(&ops_mutex);
 
 	return ops;
 }
@@ -414,7 +415,7 @@
 	}
 
 	/* close and release all devices associated with this driver */
-	down(&ops->reg_mutex);
+	mutex_lock(&ops->reg_mutex);
 	ops->driver |= DRIVER_LOCKED; /* do not remove this driver recursively */
 	list_for_each(head, &ops->dev_list) {
 		struct snd_seq_device *dev = list_entry(head, struct snd_seq_device, list);
@@ -425,7 +426,7 @@
 	if (ops->num_init_devices > 0)
 		snd_printk(KERN_ERR "free_driver: init_devices > 0!! (%d)\n",
 			   ops->num_init_devices);
-	up(&ops->reg_mutex);
+	mutex_unlock(&ops->reg_mutex);
 
 	unlock_driver(ops);
 
@@ -443,7 +444,7 @@
 {
 	struct list_head *head;
 
-	down(&ops_mutex);
+	mutex_lock(&ops_mutex);
 	head = opslist.next;
 	while (head != &opslist) {
 		struct ops_list *ops = list_entry(head, struct ops_list, list);
@@ -456,7 +457,7 @@
 		} else
 			head = head->next;
 	}
-	up(&ops_mutex);
+	mutex_unlock(&ops_mutex);
 }
 
 /*
@@ -519,16 +520,16 @@
 {
 	struct list_head *head;
 
-	down(&ops_mutex);
+	mutex_lock(&ops_mutex);
 	list_for_each(head, &opslist) {
 		struct ops_list *ops = list_entry(head, struct ops_list, list);
 		if (strcmp(ops->id, id) == 0) {
 			ops->used++;
-			up(&ops_mutex);
+			mutex_unlock(&ops_mutex);
 			return ops;
 		}
 	}
-	up(&ops_mutex);
+	mutex_unlock(&ops_mutex);
 	if (create_if_empty)
 		return create_driver(id);
 	return NULL;
@@ -536,9 +537,9 @@
 
 static void unlock_driver(struct ops_list *ops)
 {
-	down(&ops_mutex);
+	mutex_lock(&ops_mutex);
 	ops->used--;
-	up(&ops_mutex);
+	mutex_unlock(&ops_mutex);
 }
 
 
diff --git a/sound/core/seq/seq_instr.c b/sound/core/seq/seq_instr.c
index 4874520..f30d171 100644
--- a/sound/core/seq/seq_instr.c
+++ b/sound/core/seq/seq_instr.c
@@ -36,7 +36,7 @@
 	if (!(list->flags & SNDRV_SEQ_INSTR_FLG_DIRECT)) {
 		spin_lock_irqsave(&list->ops_lock, list->ops_flags);
 	} else {
-		down(&list->ops_mutex);
+		mutex_lock(&list->ops_mutex);
 	}
 }
 
@@ -45,7 +45,7 @@
 	if (!(list->flags & SNDRV_SEQ_INSTR_FLG_DIRECT)) {
 		spin_unlock_irqrestore(&list->ops_lock, list->ops_flags);
 	} else {
-		up(&list->ops_mutex);
+		mutex_unlock(&list->ops_mutex);
 	}
 }
 
@@ -82,7 +82,7 @@
 		return NULL;
 	spin_lock_init(&list->lock);
 	spin_lock_init(&list->ops_lock);
-	init_MUTEX(&list->ops_mutex);
+	mutex_init(&list->ops_mutex);
 	list->owner = -1;
 	return list;
 }
diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c
index ce0df86..9caa137 100644
--- a/sound/core/seq/seq_midi.c
+++ b/sound/core/seq/seq_midi.c
@@ -32,7 +32,7 @@
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/moduleparam.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/rawmidi.h>
 #include <sound/seq_kernel.h>
@@ -70,7 +70,7 @@
 };
 
 static struct seq_midisynth_client *synths[SNDRV_CARDS];
-static DECLARE_MUTEX(register_mutex);
+static DEFINE_MUTEX(register_mutex);
 
 /* handle rawmidi input event (MIDI v1.0 stream) */
 static void snd_midi_input_event(struct snd_rawmidi_substream *substream)
@@ -308,13 +308,13 @@
 	if (ports > (256 / SNDRV_RAWMIDI_DEVICES))
 		ports = 256 / SNDRV_RAWMIDI_DEVICES;
 
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	client = synths[card->number];
 	if (client == NULL) {
 		newclient = 1;
 		client = kzalloc(sizeof(*client), GFP_KERNEL);
 		if (client == NULL) {
-			up(&register_mutex);
+			mutex_unlock(&register_mutex);
 			kfree(info);
 			return -ENOMEM;
 		}
@@ -324,7 +324,7 @@
 				(const char *)info->name : "External MIDI");
 		if (client->seq_client < 0) {
 			kfree(client);
-			up(&register_mutex);
+			mutex_unlock(&register_mutex);
 			kfree(info);
 			return -ENOMEM;
 		}
@@ -397,7 +397,7 @@
 	client->num_ports++;
 	if (newclient)
 		synths[card->number] = client;
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	kfree(info);
 	kfree(port);
 	return 0;	/* success */
@@ -414,7 +414,7 @@
 	}
 	kfree(info);
 	kfree(port);
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	return -ENOMEM;
 }
 
@@ -427,10 +427,10 @@
 	struct snd_card *card = dev->card;
 	int device = dev->device, p, ports;
 	
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	client = synths[card->number];
 	if (client == NULL || client->ports[device] == NULL) {
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return -ENODEV;
 	}
 	ports = client->ports_per_device[device];
@@ -446,7 +446,7 @@
 		synths[card->number] = NULL;
 		kfree(client);
 	}
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	return 0;
 }
 
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c
index 2b384fd..41e078c 100644
--- a/sound/core/seq/seq_ports.c
+++ b/sound/core/seq/seq_ports.c
@@ -159,7 +159,7 @@
 	port_subs_info_init(&new_port->c_dest);
 
 	num = port >= 0 ? port : 0;
-	down(&client->ports_mutex);
+	mutex_lock(&client->ports_mutex);
 	write_lock_irqsave(&client->ports_lock, flags);
 	list_for_each(l, &client->ports_list_head) {
 		struct snd_seq_client_port *p = list_entry(l, struct snd_seq_client_port, list);
@@ -173,7 +173,7 @@
 	client->num_ports++;
 	new_port->addr.port = num;	/* store the port number in the port */
 	write_unlock_irqrestore(&client->ports_lock, flags);
-	up(&client->ports_mutex);
+	mutex_unlock(&client->ports_mutex);
 	sprintf(new_port->name, "port-%d", num);
 
 	return new_port;
@@ -292,7 +292,7 @@
 	struct list_head *l;
 	struct snd_seq_client_port *found = NULL;
 
-	down(&client->ports_mutex);
+	mutex_lock(&client->ports_mutex);
 	write_lock_irqsave(&client->ports_lock, flags);
 	list_for_each(l, &client->ports_list_head) {
 		struct snd_seq_client_port *p = list_entry(l, struct snd_seq_client_port, list);
@@ -305,7 +305,7 @@
 		}
 	}
 	write_unlock_irqrestore(&client->ports_lock, flags);
-	up(&client->ports_mutex);
+	mutex_unlock(&client->ports_mutex);
 	if (found)
 		return port_delete(client, found);
 	else
@@ -321,7 +321,7 @@
 	/* move the port list to deleted_list, and
 	 * clear the port list in the client data.
 	 */
-	down(&client->ports_mutex);
+	mutex_lock(&client->ports_mutex);
 	write_lock_irqsave(&client->ports_lock, flags);
 	if (! list_empty(&client->ports_list_head)) {
 		__list_add(&deleted_list,
@@ -341,7 +341,7 @@
 		snd_seq_system_client_ev_port_exit(port->addr.client, port->addr.port);
 		port_delete(client, port);
 	}
-	up(&client->ports_mutex);
+	mutex_unlock(&client->ports_mutex);
 	return 0;
 }
 
diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c
index 9cf20f0..9b87bb0 100644
--- a/sound/core/seq/seq_queue.c
+++ b/sound/core/seq/seq_queue.c
@@ -119,7 +119,7 @@
 
 	spin_lock_init(&q->owner_lock);
 	spin_lock_init(&q->check_lock);
-	init_MUTEX(&q->timer_mutex);
+	mutex_init(&q->timer_mutex);
 	snd_use_lock_init(&q->use_lock);
 	q->queue = -1;
 
@@ -516,7 +516,7 @@
 	queue = queueptr(queueid);
 	if (queue == NULL)
 		return -EINVAL;
-	down(&queue->timer_mutex);
+	mutex_lock(&queue->timer_mutex);
 	if (use) {
 		if (!test_and_set_bit(client, queue->clients_bitmap))
 			queue->clients++;
@@ -531,7 +531,7 @@
 	} else {
 		snd_seq_timer_close(queue);
 	}
-	up(&queue->timer_mutex);
+	mutex_unlock(&queue->timer_mutex);
 	queuefree(queue);
 	return 0;
 }
diff --git a/sound/core/seq/seq_queue.h b/sound/core/seq/seq_queue.h
index 8884385..30c8111 100644
--- a/sound/core/seq/seq_queue.h
+++ b/sound/core/seq/seq_queue.h
@@ -54,7 +54,7 @@
 	/* clients which uses this queue (bitmap) */
 	DECLARE_BITMAP(clients_bitmap, SNDRV_SEQ_MAX_CLIENTS);
 	unsigned int clients;	/* users of this queue */
-	struct semaphore timer_mutex;
+	struct mutex timer_mutex;
 
 	snd_use_lock_t use_lock;
 };
diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c
index 14fd1a6..f4edec6 100644
--- a/sound/core/seq/seq_virmidi.c
+++ b/sound/core/seq/seq_virmidi.c
@@ -167,7 +167,7 @@
 			return;		/* ignored */
 		}
 		if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) {
-			if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, 0, 0) < 0)
+			if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, in_atomic(), 0) < 0)
 				return;
 			vmidi->event.type = SNDRV_SEQ_EVENT_NONE;
 		}
@@ -186,7 +186,7 @@
 				pbuf += res;
 				count -= res;
 				if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) {
-					if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, 0, 0) < 0)
+					if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, in_atomic(), 0) < 0)
 						return;
 					vmidi->event.type = SNDRV_SEQ_EVENT_NONE;
 				}
diff --git a/sound/core/sound.c b/sound/core/sound.c
index a8eda02..4d28e52 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -33,6 +33,7 @@
 #include <sound/initval.h>
 #include <linux/kmod.h>
 #include <linux/devfs_fs_kernel.h>
+#include <linux/mutex.h>
 
 #define SNDRV_OS_MINORS 256
 
@@ -61,7 +62,7 @@
 int snd_ecards_limit;
 
 static struct snd_minor *snd_minors[SNDRV_OS_MINORS];
-static DECLARE_MUTEX(sound_mutex);
+static DEFINE_MUTEX(sound_mutex);
 
 extern struct class *sound_class;
 
@@ -120,15 +121,15 @@
 	struct snd_minor *mreg;
 	void *private_data;
 
-	if (minor > ARRAY_SIZE(snd_minors))
+	if (minor >= ARRAY_SIZE(snd_minors))
 		return NULL;
-	down(&sound_mutex);
+	mutex_lock(&sound_mutex);
 	mreg = snd_minors[minor];
 	if (mreg && mreg->type == type)
 		private_data = mreg->private_data;
 	else
 		private_data = NULL;
-	up(&sound_mutex);
+	mutex_unlock(&sound_mutex);
 	return private_data;
 }
 
@@ -139,7 +140,7 @@
 	struct file_operations *old_fops;
 	int err = 0;
 
-	if (minor > ARRAY_SIZE(snd_minors))
+	if (minor >= ARRAY_SIZE(snd_minors))
 		return -ENODEV;
 	mptr = snd_minors[minor];
 	if (mptr == NULL) {
@@ -256,7 +257,7 @@
 	preg->f_ops = f_ops;
 	preg->private_data = private_data;
 	strcpy(preg->name, name);
-	down(&sound_mutex);
+	mutex_lock(&sound_mutex);
 #ifdef CONFIG_SND_DYNAMIC_MINORS
 	minor = snd_find_free_minor();
 #else
@@ -265,7 +266,7 @@
 		minor = -EBUSY;
 #endif
 	if (minor < 0) {
-		up(&sound_mutex);
+		mutex_unlock(&sound_mutex);
 		kfree(preg);
 		return minor;
 	}
@@ -276,7 +277,7 @@
 		device = card->dev;
 	class_device_create(sound_class, NULL, MKDEV(major, minor), device, "%s", name);
 
-	up(&sound_mutex);
+	mutex_unlock(&sound_mutex);
 	return 0;
 }
 
@@ -297,7 +298,7 @@
 	struct snd_minor *mptr;
 
 	cardnum = card ? card->number : -1;
-	down(&sound_mutex);
+	mutex_lock(&sound_mutex);
 	for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor)
 		if ((mptr = snd_minors[minor]) != NULL &&
 		    mptr->type == type &&
@@ -305,7 +306,7 @@
 		    mptr->device == dev)
 			break;
 	if (minor == ARRAY_SIZE(snd_minors)) {
-		up(&sound_mutex);
+		mutex_unlock(&sound_mutex);
 		return -EINVAL;
 	}
 
@@ -315,7 +316,7 @@
 	class_device_destroy(sound_class, MKDEV(major, minor));
 
 	snd_minors[minor] = NULL;
-	up(&sound_mutex);
+	mutex_unlock(&sound_mutex);
 	kfree(mptr);
 	return 0;
 }
@@ -354,7 +355,7 @@
 	int minor;
 	struct snd_minor *mptr;
 
-	down(&sound_mutex);
+	mutex_lock(&sound_mutex);
 	for (minor = 0; minor < SNDRV_OS_MINORS; ++minor) {
 		if (!(mptr = snd_minors[minor]))
 			continue;
@@ -371,7 +372,7 @@
 			snd_iprintf(buffer, "%3i:        : %s\n", minor,
 				    snd_device_type_name(mptr->type));
 	}
-	up(&sound_mutex);
+	mutex_unlock(&sound_mutex);
 }
 
 int __init snd_minor_info_init(void)
diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c
index d0be32b..4023d3b 100644
--- a/sound/core/sound_oss.c
+++ b/sound/core/sound_oss.c
@@ -34,26 +34,27 @@
 #include <sound/minors.h>
 #include <sound/info.h>
 #include <linux/sound.h>
+#include <linux/mutex.h>
 
 #define SNDRV_OSS_MINORS 128
 
 static struct snd_minor *snd_oss_minors[SNDRV_OSS_MINORS];
-static DECLARE_MUTEX(sound_oss_mutex);
+static DEFINE_MUTEX(sound_oss_mutex);
 
 void *snd_lookup_oss_minor_data(unsigned int minor, int type)
 {
 	struct snd_minor *mreg;
 	void *private_data;
 
-	if (minor > ARRAY_SIZE(snd_oss_minors))
+	if (minor >= ARRAY_SIZE(snd_oss_minors))
 		return NULL;
-	down(&sound_oss_mutex);
+	mutex_lock(&sound_oss_mutex);
 	mreg = snd_oss_minors[minor];
 	if (mreg && mreg->type == type)
 		private_data = mreg->private_data;
 	else
 		private_data = NULL;
-	up(&sound_oss_mutex);
+	mutex_unlock(&sound_oss_mutex);
 	return private_data;
 }
 
@@ -117,7 +118,7 @@
 	preg->device = dev;
 	preg->f_ops = f_ops;
 	preg->private_data = private_data;
-	down(&sound_oss_mutex);
+	mutex_lock(&sound_oss_mutex);
 	snd_oss_minors[minor] = preg;
 	minor_unit = SNDRV_MINOR_OSS_DEVICE(minor);
 	switch (minor_unit) {
@@ -143,7 +144,7 @@
 			goto __end;
 		snd_oss_minors[track2] = preg;
 	}
-	up(&sound_oss_mutex);
+	mutex_unlock(&sound_oss_mutex);
 	return 0;
 
       __end:
@@ -152,7 +153,7 @@
       	if (register1 >= 0)
       		unregister_sound_special(register1);
 	snd_oss_minors[minor] = NULL;
-	up(&sound_oss_mutex);
+	mutex_unlock(&sound_oss_mutex);
 	kfree(preg);
       	return -EBUSY;
 }
@@ -168,10 +169,10 @@
 		return 0;
 	if (minor < 0)
 		return minor;
-	down(&sound_oss_mutex);
+	mutex_lock(&sound_oss_mutex);
 	mptr = snd_oss_minors[minor];
 	if (mptr == NULL) {
-		up(&sound_oss_mutex);
+		mutex_unlock(&sound_oss_mutex);
 		return -ENOENT;
 	}
 	unregister_sound_special(minor);
@@ -191,7 +192,7 @@
 		snd_oss_minors[track2] = NULL;
 	}
 	snd_oss_minors[minor] = NULL;
-	up(&sound_oss_mutex);
+	mutex_unlock(&sound_oss_mutex);
 	kfree(mptr);
 	return 0;
 }
@@ -229,7 +230,7 @@
 	int minor;
 	struct snd_minor *mptr;
 
-	down(&sound_oss_mutex);
+	mutex_lock(&sound_oss_mutex);
 	for (minor = 0; minor < SNDRV_OSS_MINORS; ++minor) {
 		if (!(mptr = snd_oss_minors[minor]))
 			continue;
@@ -241,7 +242,7 @@
 			snd_iprintf(buffer, "%3i:       : %s\n", minor,
 				    snd_oss_device_type_name(mptr->type));
 	}
-	up(&sound_oss_mutex);
+	mutex_unlock(&sound_oss_mutex);
 }
 
 
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 2425b97..cdeeb63 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -25,6 +25,7 @@
 #include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/time.h>
+#include <linux/mutex.h>
 #include <linux/moduleparam.h>
 #include <linux/string.h>
 #include <sound/core.h>
@@ -70,7 +71,7 @@
 	struct timespec tstamp;		/* trigger tstamp */
 	wait_queue_head_t qchange_sleep;
 	struct fasync_struct *fasync;
-	struct semaphore tread_sem;
+	struct mutex tread_sem;
 };
 
 /* list of timers */
@@ -82,7 +83,7 @@
 /* lock for slave active lists */
 static DEFINE_SPINLOCK(slave_active_lock);
 
-static DECLARE_MUTEX(register_mutex);
+static DEFINE_MUTEX(register_mutex);
 
 static int snd_timer_free(struct snd_timer *timer);
 static int snd_timer_dev_free(struct snd_device *device);
@@ -252,10 +253,10 @@
 			snd_printd("invalid slave class %i\n", tid->dev_sclass);
 			return -EINVAL;
 		}
-		down(&register_mutex);
+		mutex_lock(&register_mutex);
 		timeri = snd_timer_instance_new(owner, NULL);
 		if (!timeri) {
-			up(&register_mutex);
+			mutex_unlock(&register_mutex);
 			return -ENOMEM;
 		}
 		timeri->slave_class = tid->dev_sclass;
@@ -263,37 +264,37 @@
 		timeri->flags |= SNDRV_TIMER_IFLG_SLAVE;
 		list_add_tail(&timeri->open_list, &snd_timer_slave_list);
 		snd_timer_check_slave(timeri);
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		*ti = timeri;
 		return 0;
 	}
 
 	/* open a master instance */
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	timer = snd_timer_find(tid);
 #ifdef CONFIG_KMOD
 	if (timer == NULL) {
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		snd_timer_request(tid);
-		down(&register_mutex);
+		mutex_lock(&register_mutex);
 		timer = snd_timer_find(tid);
 	}
 #endif
 	if (!timer) {
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return -ENODEV;
 	}
 	if (!list_empty(&timer->open_list_head)) {
 		timeri = list_entry(timer->open_list_head.next,
 				    struct snd_timer_instance, open_list);
 		if (timeri->flags & SNDRV_TIMER_IFLG_EXCLUSIVE) {
-			up(&register_mutex);
+			mutex_unlock(&register_mutex);
 			return -EBUSY;
 		}
 	}
 	timeri = snd_timer_instance_new(owner, timer);
 	if (!timeri) {
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return -ENOMEM;
 	}
 	timeri->slave_class = tid->dev_sclass;
@@ -302,7 +303,7 @@
 		timer->hw.open(timer);
 	list_add_tail(&timeri->open_list, &timer->open_list_head);
 	snd_timer_check_master(timeri);
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	*ti = timeri;
 	return 0;
 }
@@ -333,9 +334,9 @@
 			spin_lock_irq(&slave_active_lock);
 		}
 		spin_unlock_irq(&slave_active_lock);
-		down(&register_mutex);
+		mutex_lock(&register_mutex);
 		list_del(&timeri->open_list);
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 	} else {
 		timer = timeri->timer;
 		/* wait, until the active callback is finished */
@@ -346,7 +347,7 @@
 			spin_lock_irq(&timer->lock);
 		}
 		spin_unlock_irq(&timer->lock);
-		down(&register_mutex);
+		mutex_lock(&register_mutex);
 		list_del(&timeri->open_list);
 		if (timer && list_empty(&timer->open_list_head) &&
 		    timer->hw.close)
@@ -362,7 +363,7 @@
 			slave->timer = NULL;
 			spin_unlock_irq(&slave_active_lock);
 		}
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 	}
 	if (timeri->private_free)
 		timeri->private_free(timeri);
@@ -835,7 +836,7 @@
 	    !timer->hw.resolution && timer->hw.c_resolution == NULL)
 	    	return -EINVAL;
 
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	list_for_each(p, &snd_timer_list) {
 		timer1 = list_entry(p, struct snd_timer, device_list);
 		if (timer1->tmr_class > timer->tmr_class)
@@ -857,11 +858,11 @@
 		if (timer1->tmr_subdevice < timer->tmr_subdevice)
 			continue;
 		/* conflicts.. */
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		return -EBUSY;
 	}
 	list_add_tail(&timer->device_list, p);
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	return 0;
 }
 
@@ -871,7 +872,7 @@
 	struct snd_timer_instance *ti;
 
 	snd_assert(timer != NULL, return -ENXIO);
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	if (! list_empty(&timer->open_list_head)) {
 		snd_printk(KERN_WARNING "timer 0x%lx is busy?\n", (long)timer);
 		list_for_each_safe(p, n, &timer->open_list_head) {
@@ -881,7 +882,7 @@
 		}
 	}
 	list_del(&timer->device_list);
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	return snd_timer_free(timer);
 }
 
@@ -1065,7 +1066,7 @@
 	struct snd_timer_instance *ti;
 	struct list_head *p, *q;
 
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	list_for_each(p, &snd_timer_list) {
 		timer = list_entry(p, struct snd_timer, device_list);
 		switch (timer->tmr_class) {
@@ -1105,7 +1106,7 @@
 		}
 		spin_unlock_irqrestore(&timer->lock, flags);
 	}
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 }
 
 static struct snd_info_entry *snd_timer_proc_entry = NULL;
@@ -1269,7 +1270,7 @@
 		return -ENOMEM;
 	spin_lock_init(&tu->qlock);
 	init_waitqueue_head(&tu->qchange_sleep);
-	init_MUTEX(&tu->tread_sem);
+	mutex_init(&tu->tread_sem);
 	tu->ticks = 1;
 	tu->queue_size = 128;
 	tu->queue = kmalloc(tu->queue_size * sizeof(struct snd_timer_read),
@@ -1325,7 +1326,7 @@
 
 	if (copy_from_user(&id, _tid, sizeof(id)))
 		return -EFAULT;
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	if (id.dev_class < 0) {		/* first item */
 		if (list_empty(&snd_timer_list))
 			snd_timer_user_zero_id(&id);
@@ -1407,7 +1408,7 @@
 			snd_timer_user_zero_id(&id);
 		}
 	}
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	if (copy_to_user(_tid, &id, sizeof(*_tid)))
 		return -EFAULT;
 	return 0;
@@ -1432,7 +1433,7 @@
 	tid = ginfo->tid;
 	memset(ginfo, 0, sizeof(*ginfo));
 	ginfo->tid = tid;
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	t = snd_timer_find(&tid);
 	if (t != NULL) {
 		ginfo->card = t->card ? t->card->number : -1;
@@ -1451,7 +1452,7 @@
 	} else {
 		err = -ENODEV;
 	}
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	if (err >= 0 && copy_to_user(_ginfo, ginfo, sizeof(*ginfo)))
 		err = -EFAULT;
 	kfree(ginfo);
@@ -1467,7 +1468,7 @@
 
 	if (copy_from_user(&gparams, _gparams, sizeof(gparams)))
 		return -EFAULT;
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	t = snd_timer_find(&gparams.tid);
 	if (!t) {
 		err = -ENODEV;
@@ -1483,7 +1484,7 @@
 	}
 	err = t->hw.set_period(t, gparams.period_num, gparams.period_den);
 _error:
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	return err;
 }
 
@@ -1500,7 +1501,7 @@
 	tid = gstatus.tid;
 	memset(&gstatus, 0, sizeof(gstatus));
 	gstatus.tid = tid;
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	t = snd_timer_find(&tid);
 	if (t != NULL) {
 		if (t->hw.c_resolution)
@@ -1517,7 +1518,7 @@
 	} else {
 		err = -ENODEV;
 	}
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	if (err >= 0 && copy_to_user(_gstatus, &gstatus, sizeof(gstatus)))
 		err = -EFAULT;
 	return err;
@@ -1532,7 +1533,7 @@
 	int err = 0;
 
 	tu = file->private_data;
-	down(&tu->tread_sem);
+	mutex_lock(&tu->tread_sem);
 	if (tu->timeri) {
 		snd_timer_close(tu->timeri);
 		tu->timeri = NULL;
@@ -1576,7 +1577,7 @@
 	}
 
       __err:
-      	up(&tu->tread_sem);
+      	mutex_unlock(&tu->tread_sem);
 	return err;
 }
 
@@ -1797,17 +1798,17 @@
 	{
 		int xarg;
 
-		down(&tu->tread_sem);
+		mutex_lock(&tu->tread_sem);
 		if (tu->timeri)	{	/* too late */
-			up(&tu->tread_sem);
+			mutex_unlock(&tu->tread_sem);
 			return -EBUSY;
 		}
 		if (get_user(xarg, p)) {
-			up(&tu->tread_sem);
+			mutex_unlock(&tu->tread_sem);
 			return -EFAULT;
 		}
 		tu->tread = xarg ? 1 : 0;
-		up(&tu->tread_sem);
+		mutex_unlock(&tu->tread_sem);
 		return 0;
 	}
 	case SNDRV_TIMER_IOCTL_GINFO:
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c
index 14e1a67..e35fd57 100644
--- a/sound/drivers/dummy.c
+++ b/sound/drivers/dummy.c
@@ -669,8 +669,10 @@
 		return err;
 
 	cards = 0;
-	for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
+	for (i = 0; i < SNDRV_CARDS; i++) {
 		struct platform_device *device;
+		if (! enable[i])
+			continue;
 		device = platform_device_register_simple(SND_DUMMY_DRIVER,
 							 i, NULL, 0);
 		if (IS_ERR(device)) {
diff --git a/sound/drivers/mpu401/mpu401.c b/sound/drivers/mpu401/mpu401.c
index 915589a..9d10d79 100644
--- a/sound/drivers/mpu401/mpu401.c
+++ b/sound/drivers/mpu401/mpu401.c
@@ -240,8 +240,10 @@
 		return err;
 
 	devices = 0;
-	for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
+	for (i = 0; i < SNDRV_CARDS; i++) {
 		struct platform_device *device;
+		if (! enable[i])
+			continue;
 #ifdef CONFIG_PNP
 		if (pnp[i])
 			continue;
diff --git a/sound/drivers/opl3/opl3_lib.c b/sound/drivers/opl3/opl3_lib.c
index 1e0c76b..4f85569 100644
--- a/sound/drivers/opl3/opl3_lib.c
+++ b/sound/drivers/opl3/opl3_lib.c
@@ -358,7 +358,7 @@
 	opl3->hardware = hardware;
 	spin_lock_init(&opl3->reg_lock);
 	spin_lock_init(&opl3->timer_lock);
-	init_MUTEX(&opl3->access_mutex);
+	mutex_init(&opl3->access_mutex);
 
 	if ((err = snd_device_new(card, SNDRV_DEV_CODEC, opl3, &ops)) < 0) {
 		snd_opl3_free(opl3);
diff --git a/sound/drivers/opl3/opl3_oss.c b/sound/drivers/opl3/opl3_oss.c
index 0345ae6..fccf019 100644
--- a/sound/drivers/opl3/opl3_oss.c
+++ b/sound/drivers/opl3/opl3_oss.c
@@ -104,8 +104,10 @@
 							  voices, voices,
 							  name);
 	if (opl3->oss_chset->port < 0) {
+		int port;
+		port = opl3->oss_chset->port;
 		snd_midi_channel_free_set(opl3->oss_chset);
-		return opl3->oss_chset->port;
+		return port;
 	}
 	return 0;
 }
@@ -136,10 +138,10 @@
 	arg->oper = oss_callback;
 	arg->private_data = opl3;
 
-	snd_opl3_oss_create_port(opl3);
-
-	/* register to OSS synth table */
-	snd_device_register(opl3->card, dev);
+	if (snd_opl3_oss_create_port(opl3)) {
+		/* register to OSS synth table */
+		snd_device_register(opl3->card, dev);
+	}
 }
 
 /* unregister */
diff --git a/sound/drivers/opl3/opl3_seq.c b/sound/drivers/opl3/opl3_seq.c
index c4ead79..57becf3 100644
--- a/sound/drivers/opl3/opl3_seq.c
+++ b/sound/drivers/opl3/opl3_seq.c
@@ -52,13 +52,13 @@
 {
 	int idx;
 
-	down(&opl3->access_mutex);
+	mutex_lock(&opl3->access_mutex);
 	if (opl3->used) {
-		up(&opl3->access_mutex);
+		mutex_unlock(&opl3->access_mutex);
 		return -EBUSY;
 	}
 	opl3->used++;
-	up(&opl3->access_mutex);
+	mutex_unlock(&opl3->access_mutex);
 
 	snd_opl3_reset(opl3);
 
@@ -91,9 +91,9 @@
 	spin_unlock_irqrestore(&opl3->sys_timer_lock, flags);
 
 	snd_opl3_reset(opl3);
-	down(&opl3->access_mutex);
+	mutex_lock(&opl3->access_mutex);
 	opl3->used--;
-	up(&opl3->access_mutex);
+	mutex_unlock(&opl3->access_mutex);
 }
 
 static int snd_opl3_synth_use(void *private_data, struct snd_seq_port_subscribe * info)
@@ -207,8 +207,10 @@
 						      16, voices,
 						      name);
 	if (opl3->chset->port < 0) {
+		int port;
+		port = opl3->chset->port;
 		snd_midi_channel_free_set(opl3->chset);
-		return opl3->chset->port;
+		return port;
 	}
 	return 0;
 }
@@ -218,7 +220,7 @@
 static int snd_opl3_seq_new_device(struct snd_seq_device *dev)
 {
 	struct snd_opl3 *opl3;
-	int client;
+	int client, err;
 	char name[32];
 	int opl_ver;
 
@@ -239,7 +241,11 @@
 	if (client < 0)
 		return client;
 
-	snd_opl3_synth_create_port(opl3);
+	if ((err = snd_opl3_synth_create_port(opl3)) < 0) {
+		snd_seq_delete_kernel_client(client);
+		opl3->seq_client = -1;
+		return err;
+	}
 
 	/* initialize instrument list */
 	opl3->ilist = snd_seq_instr_list_new();
diff --git a/sound/drivers/opl3/opl3_synth.c b/sound/drivers/opl3/opl3_synth.c
index 3534a0e..6db503f 100644
--- a/sound/drivers/opl3/opl3_synth.c
+++ b/sound/drivers/opl3/opl3_synth.c
@@ -76,13 +76,13 @@
 {
 	struct snd_opl3 *opl3 = hw->private_data;
 
-	down(&opl3->access_mutex);
+	mutex_lock(&opl3->access_mutex);
 	if (opl3->used) {
-		up(&opl3->access_mutex);
+		mutex_unlock(&opl3->access_mutex);
 		return -EAGAIN;
 	}
 	opl3->used++;
-	up(&opl3->access_mutex);
+	mutex_unlock(&opl3->access_mutex);
 
 	return 0;
 }
@@ -179,9 +179,9 @@
 	struct snd_opl3 *opl3 = hw->private_data;
 
 	snd_opl3_reset(opl3);
-	down(&opl3->access_mutex);
+	mutex_lock(&opl3->access_mutex);
 	opl3->used--;
-	up(&opl3->access_mutex);
+	mutex_unlock(&opl3->access_mutex);
 
 	return 0;
 }
diff --git a/sound/drivers/opl4/opl4_lib.c b/sound/drivers/opl4/opl4_lib.c
index ddfc10d..4bc860a 100644
--- a/sound/drivers/opl4/opl4_lib.c
+++ b/sound/drivers/opl4/opl4_lib.c
@@ -214,7 +214,7 @@
 	opl4->fm_port = fm_port;
 	opl4->pcm_port = pcm_port;
 	spin_lock_init(&opl4->reg_lock);
-	init_MUTEX(&opl4->access_mutex);
+	mutex_init(&opl4->access_mutex);
 
 	err = snd_opl4_detect(opl4);
 	if (err < 0) {
diff --git a/sound/drivers/opl4/opl4_local.h b/sound/drivers/opl4/opl4_local.h
index 7e088a4..470e5a7 100644
--- a/sound/drivers/opl4/opl4_local.h
+++ b/sound/drivers/opl4/opl4_local.h
@@ -182,7 +182,7 @@
 	struct snd_info_entry *proc_entry;
 	int memory_access;
 #endif
-	struct semaphore access_mutex;
+	struct mutex access_mutex;
 
 #if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
 	int used;
diff --git a/sound/drivers/opl4/opl4_proc.c b/sound/drivers/opl4/opl4_proc.c
index f4b4e74..e552ec3 100644
--- a/sound/drivers/opl4/opl4_proc.c
+++ b/sound/drivers/opl4/opl4_proc.c
@@ -28,13 +28,13 @@
 {
 	struct snd_opl4 *opl4 = entry->private_data;
 
-	down(&opl4->access_mutex);
+	mutex_lock(&opl4->access_mutex);
 	if (opl4->memory_access) {
-		up(&opl4->access_mutex);
+		mutex_unlock(&opl4->access_mutex);
 		return -EBUSY;
 	}
 	opl4->memory_access++;
-	up(&opl4->access_mutex);
+	mutex_unlock(&opl4->access_mutex);
 	return 0;
 }
 
@@ -43,9 +43,9 @@
 {
 	struct snd_opl4 *opl4 = entry->private_data;
 
-	down(&opl4->access_mutex);
+	mutex_lock(&opl4->access_mutex);
 	opl4->memory_access--;
-	up(&opl4->access_mutex);
+	mutex_unlock(&opl4->access_mutex);
 	return 0;
 }
 
diff --git a/sound/drivers/opl4/opl4_seq.c b/sound/drivers/opl4/opl4_seq.c
index e348032..dc0dcdc 100644
--- a/sound/drivers/opl4/opl4_seq.c
+++ b/sound/drivers/opl4/opl4_seq.c
@@ -62,10 +62,10 @@
 	struct snd_opl4 *opl4 = private_data;
 	int err;
 
-	down(&opl4->access_mutex);
+	mutex_lock(&opl4->access_mutex);
 
 	if (opl4->used) {
-		up(&opl4->access_mutex);
+		mutex_unlock(&opl4->access_mutex);
 		return -EBUSY;
 	}
 	opl4->used++;
@@ -73,12 +73,12 @@
 	if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM) {
 		err = snd_opl4_seq_use_inc(opl4);
 		if (err < 0) {
-			up(&opl4->access_mutex);
+			mutex_unlock(&opl4->access_mutex);
 			return err;
 		}
 	}
 
-	up(&opl4->access_mutex);
+	mutex_unlock(&opl4->access_mutex);
 
 	snd_opl4_synth_reset(opl4);
 	return 0;
@@ -90,9 +90,9 @@
 
 	snd_opl4_synth_shutdown(opl4);
 
-	down(&opl4->access_mutex);
+	mutex_lock(&opl4->access_mutex);
 	opl4->used--;
-	up(&opl4->access_mutex);
+	mutex_unlock(&opl4->access_mutex);
 
 	if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM)
 		snd_opl4_seq_use_dec(opl4);
diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c
index 112ddf7..1a7fbef 100644
--- a/sound/drivers/serial-u16550.c
+++ b/sound/drivers/serial-u16550.c
@@ -789,6 +789,7 @@
 
 	if ((err = snd_uart16550_detect(uart)) <= 0) {
 		printk(KERN_ERR "no UART detected at 0x%lx\n", iobase);
+		snd_uart16550_free(uart);
 		return -ENODEV;
 	}
 
@@ -989,8 +990,10 @@
 		return err;
 
 	cards = 0;
-	for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
+	for (i = 0; i < SNDRV_CARDS; i++) {
 		struct platform_device *device;
+		if (! enable[i])
+			continue;
 		device = platform_device_register_simple(SND_SERIAL_DRIVER,
 							 i, NULL, 0);
 		if (IS_ERR(device)) {
diff --git a/sound/drivers/virmidi.c b/sound/drivers/virmidi.c
index 4258723..a3ee306 100644
--- a/sound/drivers/virmidi.c
+++ b/sound/drivers/virmidi.c
@@ -163,8 +163,10 @@
 		return err;
 
 	cards = 0;
-	for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
+	for (i = 0; i < SNDRV_CARDS; i++) {
 		struct platform_device *device;
+		if (! enable[i])
+			continue;
 		device = platform_device_register_simple(SND_VIRMIDI_DRIVER,
 							 i, NULL, 0);
 		if (IS_ERR(device)) {
diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c
index 43f615d..fa4a2b5 100644
--- a/sound/drivers/vx/vx_core.c
+++ b/sound/drivers/vx/vx_core.c
@@ -778,7 +778,7 @@
 	chip->type = hw->type;
 	chip->ops = ops;
 	tasklet_init(&chip->tq, vx_interrupt, (unsigned long)chip);
-	init_MUTEX(&chip->mixer_mutex);
+	mutex_init(&chip->mixer_mutex);
 
 	chip->card = card;
 	card->private_data = chip;
diff --git a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c
index 8ec2c60..c1d7fcd 100644
--- a/sound/drivers/vx/vx_mixer.c
+++ b/sound/drivers/vx/vx_mixer.c
@@ -427,10 +427,10 @@
 {
 	struct vx_core *chip = snd_kcontrol_chip(kcontrol);
 	int codec = kcontrol->id.index;
-	down(&chip->mixer_mutex);
+	mutex_lock(&chip->mixer_mutex);
 	ucontrol->value.integer.value[0] = chip->output_level[codec][0];
 	ucontrol->value.integer.value[1] = chip->output_level[codec][1];
-	up(&chip->mixer_mutex);
+	mutex_unlock(&chip->mixer_mutex);
 	return 0;
 }
 
@@ -438,7 +438,7 @@
 {
 	struct vx_core *chip = snd_kcontrol_chip(kcontrol);
 	int codec = kcontrol->id.index;
-	down(&chip->mixer_mutex);
+	mutex_lock(&chip->mixer_mutex);
 	if (ucontrol->value.integer.value[0] != chip->output_level[codec][0] ||
 	    ucontrol->value.integer.value[1] != chip->output_level[codec][1]) {
 		vx_set_analog_output_level(chip, codec,
@@ -446,10 +446,10 @@
 					   ucontrol->value.integer.value[1]);
 		chip->output_level[codec][0] = ucontrol->value.integer.value[0];
 		chip->output_level[codec][1] = ucontrol->value.integer.value[1];
-		up(&chip->mixer_mutex);
+		mutex_unlock(&chip->mixer_mutex);
 		return 1;
 	}
-	up(&chip->mixer_mutex);
+	mutex_unlock(&chip->mixer_mutex);
 	return 0;
 }
 
@@ -502,14 +502,14 @@
 static int vx_audio_src_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
 	struct vx_core *chip = snd_kcontrol_chip(kcontrol);
-	down(&chip->mixer_mutex);
+	mutex_lock(&chip->mixer_mutex);
 	if (chip->audio_source_target != ucontrol->value.enumerated.item[0]) {
 		chip->audio_source_target = ucontrol->value.enumerated.item[0];
 		vx_sync_audio_source(chip);
-		up(&chip->mixer_mutex);
+		mutex_unlock(&chip->mixer_mutex);
 		return 1;
 	}
-	up(&chip->mixer_mutex);
+	mutex_unlock(&chip->mixer_mutex);
 	return 0;
 }
 
@@ -550,14 +550,14 @@
 static int vx_clock_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
 	struct vx_core *chip = snd_kcontrol_chip(kcontrol);
-	down(&chip->mixer_mutex);
+	mutex_lock(&chip->mixer_mutex);
 	if (chip->clock_mode != ucontrol->value.enumerated.item[0]) {
 		chip->clock_mode = ucontrol->value.enumerated.item[0];
 		vx_set_clock(chip, chip->freq);
-		up(&chip->mixer_mutex);
+		mutex_unlock(&chip->mixer_mutex);
 		return 1;
 	}
-	up(&chip->mixer_mutex);
+	mutex_unlock(&chip->mixer_mutex);
 	return 0;
 }
 
@@ -587,10 +587,10 @@
 	int audio = kcontrol->private_value & 0xff;
 	int capture = (kcontrol->private_value >> 8) & 1;
 
-	down(&chip->mixer_mutex);
+	mutex_lock(&chip->mixer_mutex);
 	ucontrol->value.integer.value[0] = chip->audio_gain[capture][audio];
 	ucontrol->value.integer.value[1] = chip->audio_gain[capture][audio+1];
-	up(&chip->mixer_mutex);
+	mutex_unlock(&chip->mixer_mutex);
 	return 0;
 }
 
@@ -600,15 +600,15 @@
 	int audio = kcontrol->private_value & 0xff;
 	int capture = (kcontrol->private_value >> 8) & 1;
 
-	down(&chip->mixer_mutex);
+	mutex_lock(&chip->mixer_mutex);
 	if (ucontrol->value.integer.value[0] != chip->audio_gain[capture][audio] ||
 	    ucontrol->value.integer.value[1] != chip->audio_gain[capture][audio+1]) {
 		vx_set_audio_gain(chip, audio, capture, ucontrol->value.integer.value[0]);
 		vx_set_audio_gain(chip, audio+1, capture, ucontrol->value.integer.value[1]);
-		up(&chip->mixer_mutex);
+		mutex_unlock(&chip->mixer_mutex);
 		return 1;
 	}
-	up(&chip->mixer_mutex);
+	mutex_unlock(&chip->mixer_mutex);
 	return 0;
 }
 
@@ -617,10 +617,10 @@
 	struct vx_core *chip = snd_kcontrol_chip(kcontrol);
 	int audio = kcontrol->private_value & 0xff;
 
-	down(&chip->mixer_mutex);
+	mutex_lock(&chip->mixer_mutex);
 	ucontrol->value.integer.value[0] = chip->audio_monitor[audio];
 	ucontrol->value.integer.value[1] = chip->audio_monitor[audio+1];
-	up(&chip->mixer_mutex);
+	mutex_unlock(&chip->mixer_mutex);
 	return 0;
 }
 
@@ -629,17 +629,17 @@
 	struct vx_core *chip = snd_kcontrol_chip(kcontrol);
 	int audio = kcontrol->private_value & 0xff;
 
-	down(&chip->mixer_mutex);
+	mutex_lock(&chip->mixer_mutex);
 	if (ucontrol->value.integer.value[0] != chip->audio_monitor[audio] ||
 	    ucontrol->value.integer.value[1] != chip->audio_monitor[audio+1]) {
 		vx_set_monitor_level(chip, audio, ucontrol->value.integer.value[0],
 				     chip->audio_monitor_active[audio]);
 		vx_set_monitor_level(chip, audio+1, ucontrol->value.integer.value[1],
 				     chip->audio_monitor_active[audio+1]);
-		up(&chip->mixer_mutex);
+		mutex_unlock(&chip->mixer_mutex);
 		return 1;
 	}
-	up(&chip->mixer_mutex);
+	mutex_unlock(&chip->mixer_mutex);
 	return 0;
 }
 
@@ -657,10 +657,10 @@
 	struct vx_core *chip = snd_kcontrol_chip(kcontrol);
 	int audio = kcontrol->private_value & 0xff;
 
-	down(&chip->mixer_mutex);
+	mutex_lock(&chip->mixer_mutex);
 	ucontrol->value.integer.value[0] = chip->audio_active[audio];
 	ucontrol->value.integer.value[1] = chip->audio_active[audio+1];
-	up(&chip->mixer_mutex);
+	mutex_unlock(&chip->mixer_mutex);
 	return 0;
 }
 
@@ -669,15 +669,15 @@
 	struct vx_core *chip = snd_kcontrol_chip(kcontrol);
 	int audio = kcontrol->private_value & 0xff;
 
-	down(&chip->mixer_mutex);
+	mutex_lock(&chip->mixer_mutex);
 	if (ucontrol->value.integer.value[0] != chip->audio_active[audio] ||
 	    ucontrol->value.integer.value[1] != chip->audio_active[audio+1]) {
 		vx_set_audio_switch(chip, audio, ucontrol->value.integer.value[0]);
 		vx_set_audio_switch(chip, audio+1, ucontrol->value.integer.value[1]);
-		up(&chip->mixer_mutex);
+		mutex_unlock(&chip->mixer_mutex);
 		return 1;
 	}
-	up(&chip->mixer_mutex);
+	mutex_unlock(&chip->mixer_mutex);
 	return 0;
 }
 
@@ -686,10 +686,10 @@
 	struct vx_core *chip = snd_kcontrol_chip(kcontrol);
 	int audio = kcontrol->private_value & 0xff;
 
-	down(&chip->mixer_mutex);
+	mutex_lock(&chip->mixer_mutex);
 	ucontrol->value.integer.value[0] = chip->audio_monitor_active[audio];
 	ucontrol->value.integer.value[1] = chip->audio_monitor_active[audio+1];
-	up(&chip->mixer_mutex);
+	mutex_unlock(&chip->mixer_mutex);
 	return 0;
 }
 
@@ -698,17 +698,17 @@
 	struct vx_core *chip = snd_kcontrol_chip(kcontrol);
 	int audio = kcontrol->private_value & 0xff;
 
-	down(&chip->mixer_mutex);
+	mutex_lock(&chip->mixer_mutex);
 	if (ucontrol->value.integer.value[0] != chip->audio_monitor_active[audio] ||
 	    ucontrol->value.integer.value[1] != chip->audio_monitor_active[audio+1]) {
 		vx_set_monitor_level(chip, audio, chip->audio_monitor[audio],
 				     ucontrol->value.integer.value[0]);
 		vx_set_monitor_level(chip, audio+1, chip->audio_monitor[audio+1],
 				     ucontrol->value.integer.value[1]);
-		up(&chip->mixer_mutex);
+		mutex_unlock(&chip->mixer_mutex);
 		return 1;
 	}
-	up(&chip->mixer_mutex);
+	mutex_unlock(&chip->mixer_mutex);
 	return 0;
 }
 
@@ -756,12 +756,12 @@
 {
 	struct vx_core *chip = snd_kcontrol_chip(kcontrol);
 
-	down(&chip->mixer_mutex);
+	mutex_lock(&chip->mixer_mutex);
 	ucontrol->value.iec958.status[0] = (chip->uer_bits >> 0) & 0xff;
 	ucontrol->value.iec958.status[1] = (chip->uer_bits >> 8) & 0xff;
 	ucontrol->value.iec958.status[2] = (chip->uer_bits >> 16) & 0xff;
 	ucontrol->value.iec958.status[3] = (chip->uer_bits >> 24) & 0xff;
-	up(&chip->mixer_mutex);
+	mutex_unlock(&chip->mixer_mutex);
         return 0;
 }
 
@@ -783,14 +783,14 @@
 	      (ucontrol->value.iec958.status[1] << 8) |
 	      (ucontrol->value.iec958.status[2] << 16) |
 	      (ucontrol->value.iec958.status[3] << 24);
-	down(&chip->mixer_mutex);
+	mutex_lock(&chip->mixer_mutex);
 	if (chip->uer_bits != val) {
 		chip->uer_bits = val;
 		vx_set_iec958_status(chip, val);
-		up(&chip->mixer_mutex);
+		mutex_unlock(&chip->mixer_mutex);
 		return 1;
 	}
-	up(&chip->mixer_mutex);
+	mutex_unlock(&chip->mixer_mutex);
 	return 0;
 }
 
diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c
index 464109e..c4af849 100644
--- a/sound/drivers/vx/vx_pcm.c
+++ b/sound/drivers/vx/vx_pcm.c
@@ -98,10 +98,9 @@
 static int snd_pcm_free_vmalloc_buffer(struct snd_pcm_substream *subs)
 {
 	struct snd_pcm_runtime *runtime = subs->runtime;
-	if (runtime->dma_area) {
-		vfree(runtime->dma_area);
-		runtime->dma_area = NULL;
-	}
+
+	vfree(runtime->dma_area);
+	runtime->dma_area = NULL;
 	return 0;
 }
 
@@ -1254,9 +1253,13 @@
 
 	/* allocate pipes */
 	chip->playback_pipes = kmalloc(sizeof(struct vx_pipe *) * chip->audio_outs, GFP_KERNEL);
-	chip->capture_pipes = kmalloc(sizeof(struct vx_pipe *) * chip->audio_ins, GFP_KERNEL);
-	if (! chip->playback_pipes || ! chip->capture_pipes)
+	if (!chip->playback_pipes)
 		return -ENOMEM;
+	chip->capture_pipes = kmalloc(sizeof(struct vx_pipe *) * chip->audio_ins, GFP_KERNEL);
+	if (!chip->capture_pipes) {
+		kfree(chip->playback_pipes);
+		return -ENOMEM;
+	}
 
 	memset(chip->playback_pipes, 0, sizeof(struct vx_pipe *) * chip->audio_outs);
 	memset(chip->capture_pipes, 0, sizeof(struct vx_pipe *) * chip->audio_ins);
diff --git a/sound/i2c/cs8427.c b/sound/i2c/cs8427.c
index 9deba80..cb89f7e 100644
--- a/sound/i2c/cs8427.c
+++ b/sound/i2c/cs8427.c
@@ -291,11 +291,13 @@
 {
 	struct cs8427 *chip;
 	unsigned long end_time;
-	int data;
+	int data, aes3input = 0;
 
 	snd_assert(cs8427, return);
 	chip = cs8427->private_data;
 	snd_i2c_lock(cs8427->bus);
+	if ((chip->regmap[CS8427_REG_CLOCKSOURCE] & CS8427_RXDAES3INPUT) == CS8427_RXDAES3INPUT)  /* AES3 bit is set */
+		aes3input = 1;
 	chip->regmap[CS8427_REG_CLOCKSOURCE] &= ~(CS8427_RUN | CS8427_RXDMASK);
 	snd_cs8427_reg_write(cs8427, CS8427_REG_CLOCKSOURCE,
 			     chip->regmap[CS8427_REG_CLOCKSOURCE]);
@@ -316,7 +318,8 @@
 	}
 	snd_i2c_lock(cs8427->bus);
 	chip->regmap[CS8427_REG_CLOCKSOURCE] &= ~CS8427_RXDMASK;
-	chip->regmap[CS8427_REG_CLOCKSOURCE] |= CS8427_RXDAES3INPUT;
+	if (aes3input)
+		chip->regmap[CS8427_REG_CLOCKSOURCE] |= CS8427_RXDAES3INPUT;
 	snd_cs8427_reg_write(cs8427, CS8427_REG_CLOCKSOURCE,
 			     chip->regmap[CS8427_REG_CLOCKSOURCE]);
 	snd_i2c_unlock(cs8427->bus);
diff --git a/sound/i2c/i2c.c b/sound/i2c/i2c.c
index c4e1f2c..edfe76f 100644
--- a/sound/i2c/i2c.c
+++ b/sound/i2c/i2c.c
@@ -88,7 +88,7 @@
 	bus = kzalloc(sizeof(*bus), GFP_KERNEL);
 	if (bus == NULL)
 		return -ENOMEM;
-	init_MUTEX(&bus->lock_mutex);
+	mutex_init(&bus->lock_mutex);
 	INIT_LIST_HEAD(&bus->devices);
 	INIT_LIST_HEAD(&bus->buses);
 	bus->card = card;
diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c
index ac0d808..fd8fe16 100644
--- a/sound/isa/ad1816a/ad1816a_lib.c
+++ b/sound/isa/ad1816a/ad1816a_lib.c
@@ -1,4 +1,3 @@
-
 /*
     ad1816a.c - lowlevel code for Analog Devices AD1816A chip.
     Copyright (C) 1999-2000 by Massimo Piccioni <dafastidio@libero.it>
@@ -175,7 +174,7 @@
 
 
 static int snd_ad1816a_trigger(struct snd_ad1816a *chip, unsigned char what,
-			       int channel, int cmd)
+			       int channel, int cmd, int iscapture)
 {
 	int error = 0;
 
@@ -184,10 +183,14 @@
 	case SNDRV_PCM_TRIGGER_STOP:
 		spin_lock(&chip->lock);
 		cmd = (cmd == SNDRV_PCM_TRIGGER_START) ? 0xff: 0x00;
-		if (what & AD1816A_PLAYBACK_ENABLE)
+		/* if (what & AD1816A_PLAYBACK_ENABLE) */
+		/* That is not valid, because playback and capture enable
+		 * are the same bit pattern, just to different addresses
+		 */
+		if (! iscapture)
 			snd_ad1816a_out_mask(chip, AD1816A_PLAYBACK_CONFIG,
 				AD1816A_PLAYBACK_ENABLE, cmd);
-		if (what & AD1816A_CAPTURE_ENABLE)
+		else
 			snd_ad1816a_out_mask(chip, AD1816A_CAPTURE_CONFIG,
 				AD1816A_CAPTURE_ENABLE, cmd);
 		spin_unlock(&chip->lock);
@@ -204,14 +207,14 @@
 {
 	struct snd_ad1816a *chip = snd_pcm_substream_chip(substream);
 	return snd_ad1816a_trigger(chip, AD1816A_PLAYBACK_ENABLE,
-		SNDRV_PCM_STREAM_PLAYBACK, cmd);
+				   SNDRV_PCM_STREAM_PLAYBACK, cmd, 0);
 }
 
 static int snd_ad1816a_capture_trigger(struct snd_pcm_substream *substream, int cmd)
 {
 	struct snd_ad1816a *chip = snd_pcm_substream_chip(substream);
 	return snd_ad1816a_trigger(chip, AD1816A_CAPTURE_ENABLE,
-		SNDRV_PCM_STREAM_CAPTURE, cmd);
+				   SNDRV_PCM_STREAM_CAPTURE, cmd, 1);
 }
 
 static int snd_ad1816a_hw_params(struct snd_pcm_substream *substream,
diff --git a/sound/isa/ad1848/ad1848.c b/sound/isa/ad1848/ad1848.c
index e091bbe..326a057 100644
--- a/sound/isa/ad1848/ad1848.c
+++ b/sound/isa/ad1848/ad1848.c
@@ -187,8 +187,10 @@
 		return err;
 
 	cards = 0;
-	for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
+	for (i = 0; i < SNDRV_CARDS; i++) {
 		struct platform_device *device;
+		if (! enable[i])
+			continue;
 		device = platform_device_register_simple(SND_AD1848_DRIVER,
 							 i, NULL, 0);
 		if (IS_ERR(device)) {
diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c
index b78530d..e0f8baa 100644
--- a/sound/isa/ad1848/ad1848_lib.c
+++ b/sound/isa/ad1848/ad1848_lib.c
@@ -387,9 +387,9 @@
 {
 	unsigned long flags;
 
-	down(&chip->open_mutex);
+	mutex_lock(&chip->open_mutex);
 	if (chip->mode & AD1848_MODE_OPEN) {
-		up(&chip->open_mutex);
+		mutex_unlock(&chip->open_mutex);
 		return -EAGAIN;
 	}
 	snd_ad1848_mce_down(chip);
@@ -432,7 +432,7 @@
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 
 	chip->mode = mode;
-	up(&chip->open_mutex);
+	mutex_unlock(&chip->open_mutex);
 
 	return 0;
 }
@@ -441,9 +441,9 @@
 {
 	unsigned long flags;
 
-	down(&chip->open_mutex);
+	mutex_lock(&chip->open_mutex);
 	if (!chip->mode) {
-		up(&chip->open_mutex);
+		mutex_unlock(&chip->open_mutex);
 		return;
 	}
 	/* disable IRQ */
@@ -471,7 +471,7 @@
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 
 	chip->mode = 0;
-	up(&chip->open_mutex);
+	mutex_unlock(&chip->open_mutex);
 }
 
 /*
@@ -889,7 +889,7 @@
 	if (chip == NULL)
 		return -ENOMEM;
 	spin_lock_init(&chip->reg_lock);
-	init_MUTEX(&chip->open_mutex);
+	mutex_init(&chip->open_mutex);
 	chip->card = card;
 	chip->port = port;
 	chip->irq = -1;
@@ -1202,10 +1202,8 @@
 	strlcpy(ctl->id.name, name, sizeof(ctl->id.name));
 	ctl->id.index = index;
 	ctl->private_value = value;
-	if ((err = snd_ctl_add(chip->card, ctl)) < 0) {
-		snd_ctl_free_one(ctl);
+	if ((err = snd_ctl_add(chip->card, ctl)) < 0)
 		return err;
-	}
 	return 0;
 }
 
diff --git a/sound/isa/cs423x/cs4231.c b/sound/isa/cs423x/cs4231.c
index ab67b5c..a30dcd9 100644
--- a/sound/isa/cs423x/cs4231.c
+++ b/sound/isa/cs423x/cs4231.c
@@ -203,8 +203,10 @@
 		return err;
 
 	cards = 0;
-	for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
+	for (i = 0; i < SNDRV_CARDS; i++) {
 		struct platform_device *device;
+		if (! enable[i])
+			continue;
 		device = platform_device_register_simple(SND_CS4231_DRIVER,
 							 i, NULL, 0);
 		if (IS_ERR(device)) {
diff --git a/sound/isa/cs423x/cs4231_lib.c b/sound/isa/cs423x/cs4231_lib.c
index eab7eb5..823db82 100644
--- a/sound/isa/cs423x/cs4231_lib.c
+++ b/sound/isa/cs423x/cs4231_lib.c
@@ -531,7 +531,7 @@
 	unsigned long flags;
 	int full_calib = 1;
 
-	down(&chip->mce_mutex);
+	mutex_lock(&chip->mce_mutex);
 	snd_cs4231_calibrate_mute(chip, 1);
 	if (chip->hardware == CS4231_HW_CS4231A ||
 	    (chip->hardware & CS4231_HW_CS4232_MASK)) {
@@ -560,7 +560,7 @@
 		snd_cs4231_mce_down(chip);
 	}
 	snd_cs4231_calibrate_mute(chip, 0);
-	up(&chip->mce_mutex);
+	mutex_unlock(&chip->mce_mutex);
 }
 
 static void snd_cs4231_capture_format(struct snd_cs4231 *chip,
@@ -570,7 +570,7 @@
 	unsigned long flags;
 	int full_calib = 1;
 
-	down(&chip->mce_mutex);
+	mutex_lock(&chip->mce_mutex);
 	snd_cs4231_calibrate_mute(chip, 1);
 	if (chip->hardware == CS4231_HW_CS4231A ||
 	    (chip->hardware & CS4231_HW_CS4232_MASK)) {
@@ -603,7 +603,7 @@
 		snd_cs4231_mce_down(chip);
 	}
 	snd_cs4231_calibrate_mute(chip, 0);
-	up(&chip->mce_mutex);
+	mutex_unlock(&chip->mce_mutex);
 }
 
 /*
@@ -709,15 +709,15 @@
 {
 	unsigned long flags;
 
-	down(&chip->open_mutex);
+	mutex_lock(&chip->open_mutex);
 	if ((chip->mode & mode) ||
 	    ((chip->mode & CS4231_MODE_OPEN) && chip->single_dma)) {
-		up(&chip->open_mutex);
+		mutex_unlock(&chip->open_mutex);
 		return -EAGAIN;
 	}
 	if (chip->mode & CS4231_MODE_OPEN) {
 		chip->mode |= mode;
-		up(&chip->open_mutex);
+		mutex_unlock(&chip->open_mutex);
 		return 0;
 	}
 	/* ok. now enable and ack CODEC IRQ */
@@ -737,7 +737,7 @@
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 
 	chip->mode = mode;
-	up(&chip->open_mutex);
+	mutex_unlock(&chip->open_mutex);
 	return 0;
 }
 
@@ -745,10 +745,10 @@
 {
 	unsigned long flags;
 
-	down(&chip->open_mutex);
+	mutex_lock(&chip->open_mutex);
 	chip->mode &= ~mode;
 	if (chip->mode & CS4231_MODE_OPEN) {
-		up(&chip->open_mutex);
+		mutex_unlock(&chip->open_mutex);
 		return;
 	}
 	snd_cs4231_calibrate_mute(chip, 1);
@@ -785,7 +785,7 @@
 	snd_cs4231_calibrate_mute(chip, 0);
 
 	chip->mode = 0;
-	up(&chip->open_mutex);
+	mutex_unlock(&chip->open_mutex);
 }
 
 /*
@@ -1408,8 +1408,8 @@
 	chip->hwshare = hwshare;
 
 	spin_lock_init(&chip->reg_lock);
-	init_MUTEX(&chip->mce_mutex);
-	init_MUTEX(&chip->open_mutex);
+	mutex_init(&chip->mce_mutex);
+	mutex_init(&chip->open_mutex);
 	chip->card = card;
 	chip->rate_constraint = snd_cs4231_xrate;
 	chip->set_playback_format = snd_cs4231_playback_format;
@@ -1538,8 +1538,8 @@
 		return err;
 
 	spin_lock_init(&chip->reg_lock);
-	init_MUTEX(&chip->mce_mutex);
-	init_MUTEX(&chip->open_mutex);
+	mutex_init(&chip->mce_mutex);
+	mutex_init(&chip->open_mutex);
 
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cs4231_playback_ops);
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cs4231_capture_ops);
diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c
index 99a4213..4060918 100644
--- a/sound/isa/cs423x/cs4236.c
+++ b/sound/isa/cs423x/cs4236.c
@@ -771,9 +771,9 @@
 	if ((err = platform_driver_register(&cs423x_nonpnp_driver)) < 0)
 		return err;
 
-	for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
+	for (i = 0; i < SNDRV_CARDS; i++) {
 		struct platform_device *device;
-		if (is_isapnp_selected(i))
+		if (! enable[i] || is_isapnp_selected(i))
 			continue;
 		device = platform_device_register_simple(CS423X_DRIVER,
 							 i, NULL, 0);
diff --git a/sound/isa/cs423x/cs4236_lib.c b/sound/isa/cs423x/cs4236_lib.c
index e36981d..7a5a6c7 100644
--- a/sound/isa/cs423x/cs4236_lib.c
+++ b/sound/isa/cs423x/cs4236_lib.c
@@ -644,7 +644,7 @@
 	val2 = (chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)] & ~0x7f) | val2;
 	change = val1 != chip->eimage[CS4236_REG(CS4236_LEFT_MASTER)] || val2 != chip->eimage[CS4236_REG(CS4236_RIGHT_MASTER)];
 	snd_cs4236_ext_out(chip, CS4236_LEFT_MASTER, val1);
-	snd_cs4236_ext_out(chip, CS4236_RIGHT_MASTER, val1);
+	snd_cs4236_ext_out(chip, CS4236_RIGHT_MASTER, val2);
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 	return change;
 }
@@ -841,7 +841,7 @@
 	
 	enable = ucontrol->value.integer.value[0] & 1;
 
-	down(&chip->mce_mutex);
+	mutex_lock(&chip->mce_mutex);
 	snd_cs4231_mce_up(chip);
 	spin_lock_irqsave(&chip->reg_lock, flags);
 	val = (chip->image[CS4231_ALT_FEATURE_1] & ~0x0e) | (0<<2) | (enable << 1);
@@ -854,7 +854,7 @@
 	snd_cs4236_ctrl_out(chip, 4, val);
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 	snd_cs4231_mce_down(chip);
-	up(&chip->mce_mutex);
+	mutex_unlock(&chip->mce_mutex);
 
 #if 0
 	printk("set valid: ALT = 0x%x, C3 = 0x%x, C4 = 0x%x, C5 = 0x%x, C6 = 0x%x, C8 = 0x%x\n",
diff --git a/sound/isa/es1688/es1688.c b/sound/isa/es1688/es1688.c
index 50d23cf..2b69fc8 100644
--- a/sound/isa/es1688/es1688.c
+++ b/sound/isa/es1688/es1688.c
@@ -207,8 +207,10 @@
 		return err;
 
 	cards = 0;
-	for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
+	for (i = 0; i < SNDRV_CARDS; i++) {
 		struct platform_device *device;
+		if (! enable[i])
+			continue;
 		device = platform_device_register_simple(ES1688_DRIVER,
 							 i, NULL, 0);
 		if (IS_ERR(device)) {
diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c
index 08f032b..721955d 100644
--- a/sound/isa/es18xx.c
+++ b/sound/isa/es18xx.c
@@ -49,6 +49,10 @@
  * - contrarily to some pages in DS_1869.PDF the rates can be set
  *   independently.
  *
+ * - Zoom Video is implemented by sharing the FM DAC, thus the user can
+ *   have either FM playback or Video playback but not both simultaneously.
+ *   The Video Playback Switch mixer control toggles this choice.
+ *
  * BUGS:
  *
  * - There is a major trouble I noted:
@@ -63,7 +67,16 @@
  *
  */
 
-
+/*
+ * ES1879 NOTES:
+ * - When Zoom Video is enabled (reg 0x71 bit 6 toggled on) the PCM playback
+ *   seems to be effected (speaker_test plays a lower frequency). Can't find
+ *   anything in the datasheet to account for this, so a Video Playback Switch
+ *   control has been included to allow ZV to be enabled only when necessary.
+ *   Then again on at least one test system the 0x71 bit 6 enable bit is not 
+ *   needed for ZV, so maybe the datasheet is entirely wrong here.
+ */
+ 
 #include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/err.h>
@@ -148,7 +161,7 @@
 #define ES18XX_DUPLEX_SAME 0x0010	/* Playback and record must share the same rate */
 #define ES18XX_NEW_RATE	0x0020	/* More precise rate setting */
 #define ES18XX_AUXB	0x0040	/* AuxB mixer control */
-#define ES18XX_HWV	0x0080	/* Has hardware volume */
+#define ES18XX_HWV	0x0080	/* Has seperate hardware volume mixer controls*/
 #define ES18XX_MONO	0x0100	/* Mono_in mixer control */
 #define ES18XX_I2S	0x0200	/* I2S mixer control */
 #define ES18XX_MUTEREC	0x0400	/* Record source can be muted */
@@ -788,9 +801,12 @@
 
 	/* Hardware volume */
 	if (status & HWV_IRQ) {
-		int split = snd_es18xx_mixer_read(chip, 0x64) & 0x80;
-		snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hw_switch->id);
-		snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hw_volume->id);
+		int split = 0;
+		if (chip->caps & ES18XX_HWV) {
+			split = snd_es18xx_mixer_read(chip, 0x64) & 0x80;
+			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hw_switch->id);
+			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hw_volume->id);
+		}
 		if (!split) {
 			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_switch->id);
 			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_volume->id);
@@ -939,37 +955,118 @@
  *  MIXER part
  */
 
+/* Record source mux routines:
+ * Depending on the chipset this mux switches between 4, 5, or 8 possible inputs.
+ * bit table for the 4/5 source mux:
+ * reg 1C:
+ *  b2 b1 b0   muxSource
+ *   x  0  x   microphone
+ *   0  1  x   CD
+ *   1  1  0   line
+ *   1  1  1   mixer
+ * if it's "mixer" and it's a 5 source mux chipset then reg 7A bit 3 determines
+ * either the play mixer or the capture mixer.
+ *
+ * "map4Source" translates from source number to reg bit pattern
+ * "invMap4Source" translates from reg bit pattern to source number
+ */
+
 static int snd_es18xx_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
 {
-	static char *texts[8] = {
+	static char *texts4Source[4] = {
+		"Mic", "CD", "Line", "Master"
+	};
+	static char *texts5Source[5] = {
+		"Mic", "CD", "Line", "Master", "Mix"
+	};
+	static char *texts8Source[8] = {
 		"Mic", "Mic Master", "CD", "AOUT",
 		"Mic1", "Mix", "Line", "Master"
 	};
+	struct snd_es18xx *chip = snd_kcontrol_chip(kcontrol);
 
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->count = 1;
-	uinfo->value.enumerated.items = 8;
-	if (uinfo->value.enumerated.item > 7)
-		uinfo->value.enumerated.item = 7;
-	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+	switch (chip->version) {
+	case 0x1868:
+	case 0x1878:
+		uinfo->value.enumerated.items = 4;
+		if (uinfo->value.enumerated.item > 3)
+			uinfo->value.enumerated.item = 3;
+		strcpy(uinfo->value.enumerated.name, texts4Source[uinfo->value.enumerated.item]);
+		break;
+	case 0x1887:
+	case 0x1888:
+		uinfo->value.enumerated.items = 5;
+		if (uinfo->value.enumerated.item > 4)
+			uinfo->value.enumerated.item = 4;
+		strcpy(uinfo->value.enumerated.name, texts5Source[uinfo->value.enumerated.item]);
+		break;
+	case 0x1869: /* DS somewhat contradictory for 1869: could be be 5 or 8 */
+	case 0x1879:
+		uinfo->value.enumerated.items = 8;
+		if (uinfo->value.enumerated.item > 7)
+			uinfo->value.enumerated.item = 7;
+		strcpy(uinfo->value.enumerated.name, texts8Source[uinfo->value.enumerated.item]);
+		break;
+	default:
+		return -EINVAL;
+	}
 	return 0;
 }
 
 static int snd_es18xx_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
+	static unsigned char invMap4Source[8] = {0, 0, 1, 1, 0, 0, 2, 3};
 	struct snd_es18xx *chip = snd_kcontrol_chip(kcontrol);
-	ucontrol->value.enumerated.item[0] = snd_es18xx_mixer_read(chip, 0x1c) & 0x07;
+	int muxSource = snd_es18xx_mixer_read(chip, 0x1c) & 0x07;
+	if (!(chip->version == 0x1869 || chip->version == 0x1879)) {
+		muxSource = invMap4Source[muxSource];
+		if (muxSource==3 && 
+		    (chip->version == 0x1887 || chip->version == 0x1888) &&
+		    (snd_es18xx_mixer_read(chip, 0x7a) & 0x08)
+		) 
+			muxSource = 4;
+	}
+	ucontrol->value.enumerated.item[0] = muxSource;
 	return 0;
 }
 
 static int snd_es18xx_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
+	static unsigned char map4Source[4] = {0, 2, 6, 7};
 	struct snd_es18xx *chip = snd_kcontrol_chip(kcontrol);
 	unsigned char val = ucontrol->value.enumerated.item[0];
-	
-	if (val > 7)
+	unsigned char retVal = 0;
+
+	switch (chip->version) {
+ /* 5 source chips */
+	case 0x1887:
+	case 0x1888:
+		if (val > 4)
+			return -EINVAL;
+		if (val == 4) {
+			retVal = snd_es18xx_mixer_bits(chip, 0x7a, 0x08, 0x08) != 0x08;
+			val = 3;
+		} else
+			retVal = snd_es18xx_mixer_bits(chip, 0x7a, 0x08, 0x00) != 0x00;
+ /* 4 source chips */
+	case 0x1868:
+	case 0x1878:
+		if (val > 3)
+			return -EINVAL;
+		val = map4Source[val];
+		break;
+ /* 8 source chips */
+	case 0x1869:
+	case 0x1879:
+		if (val > 7)
+			return -EINVAL;
+		break;
+	default:
 		return -EINVAL;
-	return snd_es18xx_mixer_bits(chip, 0x1c, 0x07, val) != val;
+	}
+	return (snd_es18xx_mixer_bits(chip, 0x1c, 0x07, val) != val) || retVal;
 }
 
 static int snd_es18xx_info_spatializer_enable(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
@@ -1191,19 +1288,22 @@
 	return change;
 }
 
+/* Mixer controls
+ * These arrays contain setup data for mixer controls.
+ * 
+ * The controls that are universal to all chipsets are fully initialized
+ * here.
+ */
 static struct snd_kcontrol_new snd_es18xx_base_controls[] = {
 ES18XX_DOUBLE("Master Playback Volume", 0, 0x60, 0x62, 0, 0, 63, 0),
 ES18XX_DOUBLE("Master Playback Switch", 0, 0x60, 0x62, 6, 6, 1, 1),
 ES18XX_DOUBLE("Line Playback Volume", 0, 0x3e, 0x3e, 4, 0, 15, 0),
 ES18XX_DOUBLE("CD Playback Volume", 0, 0x38, 0x38, 4, 0, 15, 0),
 ES18XX_DOUBLE("FM Playback Volume", 0, 0x36, 0x36, 4, 0, 15, 0),
-ES18XX_DOUBLE("Mono Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0),
 ES18XX_DOUBLE("Mic Playback Volume", 0, 0x1a, 0x1a, 4, 0, 15, 0),
 ES18XX_DOUBLE("Aux Playback Volume", 0, 0x3a, 0x3a, 4, 0, 15, 0),
-ES18XX_SINGLE("PC Speaker Playback Volume", 0, 0x3c, 0, 7, 0),
 ES18XX_SINGLE("Record Monitor", 0, 0xa8, 3, 1, 0),
 ES18XX_DOUBLE("Capture Volume", 0, 0xb4, 0xb4, 4, 0, 15, 0),
-ES18XX_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1),
 {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Capture Source",
@@ -1213,19 +1313,37 @@
 }
 };
 
-static struct snd_kcontrol_new snd_es18xx_mono_in_control = 
-ES18XX_DOUBLE("Mono Input Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0);
-
 static struct snd_kcontrol_new snd_es18xx_recmix_controls[] = {
 ES18XX_DOUBLE("PCM Capture Volume", 0, 0x69, 0x69, 4, 0, 15, 0),
 ES18XX_DOUBLE("Mic Capture Volume", 0, 0x68, 0x68, 4, 0, 15, 0),
 ES18XX_DOUBLE("Line Capture Volume", 0, 0x6e, 0x6e, 4, 0, 15, 0),
 ES18XX_DOUBLE("FM Capture Volume", 0, 0x6b, 0x6b, 4, 0, 15, 0),
-ES18XX_DOUBLE("Mono Capture Volume", 0, 0x6f, 0x6f, 4, 0, 15, 0),
 ES18XX_DOUBLE("CD Capture Volume", 0, 0x6a, 0x6a, 4, 0, 15, 0),
 ES18XX_DOUBLE("Aux Capture Volume", 0, 0x6c, 0x6c, 4, 0, 15, 0)
 };
 
+/*
+ * The chipset specific mixer controls
+ */
+static struct snd_kcontrol_new snd_es18xx_opt_speaker =
+	ES18XX_SINGLE("PC Speaker Playback Volume", 0, 0x3c, 0, 7, 0);
+
+static struct snd_kcontrol_new snd_es18xx_opt_1869[] = {
+ES18XX_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1),
+ES18XX_SINGLE("Video Playback Switch", 0, 0x7f, 0, 1, 0),
+ES18XX_DOUBLE("Mono Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0),
+ES18XX_DOUBLE("Mono Capture Volume", 0, 0x6f, 0x6f, 4, 0, 15, 0)
+};
+
+static struct snd_kcontrol_new snd_es18xx_opt_1878 =
+	ES18XX_DOUBLE("Video Playback Volume", 0, 0x68, 0x68, 4, 0, 15, 0);
+
+static struct snd_kcontrol_new snd_es18xx_opt_1879[] = {
+ES18XX_SINGLE("Video Playback Switch", 0, 0x71, 6, 1, 0),
+ES18XX_DOUBLE("Video Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0),
+ES18XX_DOUBLE("Video Capture Volume", 0, 0x6f, 0x6f, 4, 0, 15, 0)
+};
+
 static struct snd_kcontrol_new snd_es18xx_pcm1_controls[] = {
 ES18XX_DOUBLE("PCM Playback Volume", 0, 0x14, 0x14, 4, 0, 15, 0),
 };
@@ -1270,7 +1388,6 @@
 ES18XX_SINGLE("Hardware Master Volume Split", 0, 0x64, 7, 1, 0),
 };
 
-#if 0
 static int __devinit snd_es18xx_config_read(struct snd_es18xx *chip, unsigned char reg)
 {
 	int data;
@@ -1281,7 +1398,6 @@
         spin_unlock_irqrestore(&chip->ctrl_lock, flags);
 	return data;
 }
-#endif
 
 static void __devinit snd_es18xx_config_write(struct snd_es18xx *chip, 
 					      unsigned char reg, unsigned char data)
@@ -1427,6 +1543,17 @@
 		snd_es18xx_mixer_write(chip, 0x58, 0x94);
 		snd_es18xx_mixer_write(chip, 0x5a, 0x80);
 	}
+	/* Flip the "enable I2S" bits for those chipsets that need it */
+	switch (chip->version) {
+	case 0x1879:
+		//Leaving I2S enabled on the 1879 screws up the PCM playback (rate effected somehow)
+		//so a Switch control has been added to toggle this 0x71 bit on/off:
+		//snd_es18xx_mixer_bits(chip, 0x71, 0x40, 0x40);
+		/* Note: we fall through on purpose here. */
+	case 0x1878:
+		snd_es18xx_config_write(chip, 0x29, snd_es18xx_config_read(chip, 0x29) | 0x40);
+		break;
+	}
 	/* Mute input source */
 	if (chip->caps & ES18XX_MUTEREC)
 		mask = 0x10;
@@ -1476,11 +1603,14 @@
 	}
 			
         outb(0x40, chip->port + 0x04);
+	udelay(10);
 	hi = inb(chip->port + 0x05);
+	udelay(10);
 	lo = inb(chip->port + 0x05);
 	if (hi != lo) {
 		chip->version = hi << 8 | lo;
 		chip->ctrl_port = inb(chip->port + 0x05) << 8;
+		udelay(10);
 		chip->ctrl_port += inb(chip->port + 0x05);
 
 		if ((chip->res_ctrl_port = request_region(chip->ctrl_port, 8, "ES18xx - CTRL")) == NULL) {
@@ -1519,22 +1649,22 @@
 
 	switch (chip->version) {
 	case 0x1868:
-		chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_CONTROL | ES18XX_HWV;
+		chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_CONTROL;
 		break;
 	case 0x1869:
 		chip->caps = ES18XX_PCM2 | ES18XX_SPATIALIZER | ES18XX_RECMIX | ES18XX_NEW_RATE | ES18XX_AUXB | ES18XX_MONO | ES18XX_MUTEREC | ES18XX_CONTROL | ES18XX_HWV;
 		break;
 	case 0x1878:
-		chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_I2S | ES18XX_CONTROL | ES18XX_HWV;
+		chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_I2S | ES18XX_CONTROL;
 		break;
 	case 0x1879:
 		chip->caps = ES18XX_PCM2 | ES18XX_SPATIALIZER | ES18XX_RECMIX | ES18XX_NEW_RATE | ES18XX_AUXB | ES18XX_I2S | ES18XX_CONTROL | ES18XX_HWV;
 		break;
 	case 0x1887:
-		chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME | ES18XX_HWV;
+		chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME;
 		break;
 	case 0x1888:
-		chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME | ES18XX_HWV;
+		chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME;
 		break;
 	default:
 		snd_printk(KERN_ERR "[0x%lx] unsupported chip ES%x\n",
@@ -1778,10 +1908,6 @@
 		}
 	}
 
-	if (chip->caps & ES18XX_MONO) {
-		if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_mono_in_control, chip))) < 0)
-			return err;
-	}
 	if (chip->caps & ES18XX_RECMIX) {
 		for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_recmix_controls); idx++) {
 			if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_recmix_controls[idx], chip))) < 0)
@@ -1819,6 +1945,36 @@
 			
 		}
 	}
+	/* finish initializing other chipset specific controls
+	 */
+	if (chip->version != 0x1868) {
+		err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_opt_speaker,
+						     chip));
+		if (err < 0)
+			return err;
+	}
+	if (chip->version == 0x1869) {
+		for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_opt_1869); idx++) {
+			err = snd_ctl_add(card,
+					  snd_ctl_new1(&snd_es18xx_opt_1869[idx],
+						       chip));
+			if (err < 0)
+				return err;
+		}
+	} else if (chip->version == 0x1878) {
+		err = snd_ctl_add(card, snd_ctl_new1(&snd_es18xx_opt_1878,
+						     chip));
+		if (err < 0)
+			return err;
+	} else if (chip->version == 0x1879) {
+		for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_opt_1879); idx++) {
+			err = snd_ctl_add(card,
+					  snd_ctl_new1(&snd_es18xx_opt_1879[idx],
+						       chip));
+			if (err < 0)
+				return err;
+		}
+	}
 	return 0;
 }
        
@@ -1927,6 +2083,7 @@
 	err = pnp_activate_dev(acard->devc);
 	if (err < 0) {
 		snd_printk(KERN_ERR PFX "PnP control configure failure (out of resources?)\n");
+		kfree(cfg);
 		return -EAGAIN;
 	}
 	snd_printdd("pnp: port=0x%lx\n", pnp_port_start(acard->devc, 0));
@@ -2225,9 +2382,9 @@
 	if ((err = platform_driver_register(&snd_es18xx_nonpnp_driver)) < 0)
 		return err;
 
-	for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
+	for (i = 0; i < SNDRV_CARDS; i++) {
 		struct platform_device *device;
-		if (is_isapnp_selected(i))
+		if (! enable[i] || is_isapnp_selected(i))
 			continue;
 		device = platform_device_register_simple(ES18XX_DRIVER,
 							 i, NULL, 0);
diff --git a/sound/isa/gus/gus_dma.c b/sound/isa/gus/gus_dma.c
index 930f4bc..44ee5d3 100644
--- a/sound/isa/gus/gus_dma.c
+++ b/sound/isa/gus/gus_dma.c
@@ -149,10 +149,10 @@
 
 int snd_gf1_dma_init(struct snd_gus_card * gus)
 {
-	down(&gus->dma_mutex);
+	mutex_lock(&gus->dma_mutex);
 	gus->gf1.dma_shared++;
 	if (gus->gf1.dma_shared > 1) {
-		up(&gus->dma_mutex);
+		mutex_unlock(&gus->dma_mutex);
 		return 0;
 	}
 	gus->gf1.interrupt_handler_dma_write = snd_gf1_dma_interrupt;
@@ -160,7 +160,7 @@
 	gus->gf1.dma_data_pcm_last =
 	gus->gf1.dma_data_synth = 
 	gus->gf1.dma_data_synth_last = NULL;
-	up(&gus->dma_mutex);
+	mutex_unlock(&gus->dma_mutex);
 	return 0;
 }
 
@@ -168,7 +168,7 @@
 {
 	struct snd_gf1_dma_block *block;
 
-	down(&gus->dma_mutex);
+	mutex_lock(&gus->dma_mutex);
 	gus->gf1.dma_shared--;
 	if (!gus->gf1.dma_shared) {
 		snd_dma_disable(gus->gf1.dma1);
@@ -185,7 +185,7 @@
 		gus->gf1.dma_data_pcm_last =
 		gus->gf1.dma_data_synth_last = NULL;
 	}
-	up(&gus->dma_mutex);
+	mutex_unlock(&gus->dma_mutex);
 	return 0;
 }
 
diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c
index 6d15b3d..53eeaf3 100644
--- a/sound/isa/gus/gus_main.c
+++ b/sound/isa/gus/gus_main.c
@@ -225,7 +225,7 @@
 	spin_lock_init(&gus->dma_lock);
 	spin_lock_init(&gus->pcm_volume_level_lock);
 	spin_lock_init(&gus->uart_cmd_lock);
-	init_MUTEX(&gus->dma_mutex);
+	mutex_init(&gus->dma_mutex);
 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, gus, &ops)) < 0) {
 		snd_gus_free(gus);
 		return err;
diff --git a/sound/isa/gus/gus_mem.c b/sound/isa/gus/gus_mem.c
index e8bdb86..3c0d27a 100644
--- a/sound/isa/gus/gus_mem.c
+++ b/sound/isa/gus/gus_mem.c
@@ -34,9 +34,9 @@
 void snd_gf1_mem_lock(struct snd_gf1_mem * alloc, int xup)
 {
 	if (!xup) {
-		down(&alloc->memory_mutex);
+		mutex_lock(&alloc->memory_mutex);
 	} else {
-		up(&alloc->memory_mutex);
+		mutex_unlock(&alloc->memory_mutex);
 	}
 }
 
@@ -59,7 +59,7 @@
 				alloc->first = nblock;
 			else
 				nblock->prev->next = nblock;
-			up(&alloc->memory_mutex);
+			mutex_unlock(&alloc->memory_mutex);
 			return NULL;
 		}
 		pblock = pblock->next;
@@ -80,7 +80,7 @@
 {
 	if (block->share) {	/* ok.. shared block */
 		block->share--;
-		up(&alloc->memory_mutex);
+		mutex_unlock(&alloc->memory_mutex);
 		return 0;
 	}
 	if (alloc->first == block) {
@@ -244,7 +244,7 @@
 #endif
 
 	alloc = &gus->gf1.mem_alloc;
-	init_MUTEX(&alloc->memory_mutex);
+	mutex_init(&alloc->memory_mutex);
 	alloc->first = alloc->last = NULL;
 	if (!gus->gf1.memory)
 		return 0;
@@ -299,7 +299,7 @@
 
 	gus = entry->private_data;
 	alloc = &gus->gf1.mem_alloc;
-	down(&alloc->memory_mutex);
+	mutex_lock(&alloc->memory_mutex);
 	snd_iprintf(buffer, "8-bit banks       : \n    ");
 	for (i = 0; i < 4; i++)
 		snd_iprintf(buffer, "0x%06x (%04ik)%s", alloc->banks_8[i].address, alloc->banks_8[i].size >> 10, i + 1 < 4 ? "," : "");
@@ -343,7 +343,7 @@
 	}
 	snd_iprintf(buffer, "  Total: memory = %i, used = %i, free = %i\n",
 		    total, used, total - used);
-	up(&alloc->memory_mutex);
+	mutex_unlock(&alloc->memory_mutex);
 #if 0
 	ultra_iprintf(buffer, "  Verify: free = %i, max 8-bit block = %i, max 16-bit block = %i\n",
 		      ultra_memory_free_size(card, &card->gf1.mem_alloc),
diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c
index d082939..c7f95e7 100644
--- a/sound/isa/gus/gus_pcm.c
+++ b/sound/isa/gus/gus_pcm.c
@@ -114,8 +114,6 @@
 	unsigned char pan;
 	unsigned int voice;
 
-	if (substream == NULL)
-		return;
 	spin_lock_irqsave(&pcmp->lock, flags);
 	if (pcmp->flags & SNDRV_GF1_PCM_PFLG_ACTIVE) {
 		spin_unlock_irqrestore(&pcmp->lock, flags);
diff --git a/sound/isa/gus/gus_synth.c b/sound/isa/gus/gus_synth.c
index 85a1b05..2767cc1 100644
--- a/sound/isa/gus/gus_synth.c
+++ b/sound/isa/gus/gus_synth.c
@@ -55,9 +55,9 @@
 
 	if (info->voices > 32)
 		return -EINVAL;
-	down(&gus->register_mutex);
+	mutex_lock(&gus->register_mutex);
 	if (!snd_gus_use_inc(gus)) {
-		up(&gus->register_mutex);
+		mutex_unlock(&gus->register_mutex);
 		return -EFAULT;
 	}
 	for (idx = 0; idx < info->voices; idx++) {
@@ -65,12 +65,12 @@
 		if (voice == NULL) {
 			snd_gus_synth_free_voices(gus, info->sender.client, info->sender.port);
 			snd_gus_use_dec(gus);
-			up(&gus->register_mutex);
+			mutex_unlock(&gus->register_mutex);
 			return -EBUSY;
 		}
 		voice->index = idx;
 	}
-	up(&gus->register_mutex);
+	mutex_unlock(&gus->register_mutex);
 	return 0;
 }
 
@@ -79,10 +79,10 @@
 	struct snd_gus_port * port = private_data;
 	struct snd_gus_card * gus = port->gus;
 
-	down(&gus->register_mutex);
+	mutex_lock(&gus->register_mutex);
 	snd_gus_synth_free_voices(gus, info->sender.client, info->sender.port);
 	snd_gus_use_dec(gus);
-	up(&gus->register_mutex);
+	mutex_unlock(&gus->register_mutex);
 	return 0;
 }
 
@@ -223,7 +223,7 @@
 	if (gus == NULL)
 		return -EINVAL;
 
-	init_MUTEX(&gus->register_mutex);
+	mutex_init(&gus->register_mutex);
 	gus->gf1.seq_client = -1;
 	
 	/* allocate new client */
diff --git a/sound/isa/gus/gusclassic.c b/sound/isa/gus/gusclassic.c
index 91c2191..26dccfe 100644
--- a/sound/isa/gus/gusclassic.c
+++ b/sound/isa/gus/gusclassic.c
@@ -247,8 +247,10 @@
 		return err;
 
 	cards = 0;
-	for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
+	for (i = 0; i < SNDRV_CARDS; i++) {
 		struct platform_device *device;
+		if (! enable[i])
+			continue;
 		device = platform_device_register_simple(GUSCLASSIC_DRIVER,
 							 i, NULL, 0);
 		if (IS_ERR(device)) {
diff --git a/sound/isa/gus/gusextreme.c b/sound/isa/gus/gusextreme.c
index 239f16e..31dc205 100644
--- a/sound/isa/gus/gusextreme.c
+++ b/sound/isa/gus/gusextreme.c
@@ -357,8 +357,10 @@
 		return err;
 
 	cards = 0;
-	for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
+	for (i = 0; i < SNDRV_CARDS; i++) {
 		struct platform_device *device;
+		if (! enable[i])
+			continue;
 		device = platform_device_register_simple(GUSEXTREME_DRIVER,
 							 i, NULL, 0);
 		if (IS_ERR(device)) {
diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c
index d4d2b2a..cafb9b6 100644
--- a/sound/isa/gus/gusmax.c
+++ b/sound/isa/gus/gusmax.c
@@ -384,8 +384,10 @@
 		return err;
 
 	cards = 0;
-	for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
+	for (i = 0; i < SNDRV_CARDS; i++) {
 		struct platform_device *device;
+		if (! enable[i])
+			continue;
 		device = platform_device_register_simple(GUSMAX_DRIVER,
 							 i, NULL, 0);
 		if (IS_ERR(device)) {
diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c
index 9838d99..2cacd0f 100644
--- a/sound/isa/gus/interwave.c
+++ b/sound/isa/gus/interwave.c
@@ -935,8 +935,10 @@
 	if ((err = platform_driver_register(&snd_interwave_driver)) < 0)
 		return err;
 
-	for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
+	for (i = 0; i < SNDRV_CARDS; i++) {
 		struct platform_device *device;
+		if (! enable[i])
+			continue;
 #ifdef CONFIG_PNP
 		if (isapnp[i])
 			continue;
diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c
index 9d84319..56fcd8a 100644
--- a/sound/isa/opl3sa2.c
+++ b/sound/isa/opl3sa2.c
@@ -949,8 +949,10 @@
 	if ((err = platform_driver_register(&snd_opl3sa2_nonpnp_driver)) < 0)
 		return err;
 
-	for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
+	for (i = 0; i < SNDRV_CARDS; i++) {
 		struct platform_device *device;
+		if (! enable[i])
+			continue;
 #ifdef CONFIG_PNP
 		if (isapnp[i])
 			continue;
diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c
index 63d96be..65b28cb 100644
--- a/sound/isa/opti9xx/opti92x-ad1848.c
+++ b/sound/isa/opti9xx/opti92x-ad1848.c
@@ -2088,9 +2088,11 @@
 	int error;
 	struct platform_device *device;
 
+#ifdef CONFIG_PNP
 	pnp_register_card_driver(&opti9xx_pnpc_driver);
 	if (snd_opti9xx_pnp_is_probed)
 		return 0;
+#endif
 	if (! is_isapnp_selected()) {
 		error = platform_driver_register(&snd_opti9xx_driver);
 		if (error < 0)
@@ -2102,7 +2104,9 @@
 		}
 		platform_driver_unregister(&snd_opti9xx_driver);
 	}
+#ifdef CONFIG_PNP
 	pnp_unregister_card_driver(&opti9xx_pnpc_driver);
+#endif
 #ifdef MODULE
 	printk(KERN_ERR "no OPTi " CHIP_NAME " soundcard found\n");
 #endif
@@ -2115,7 +2119,9 @@
 		platform_device_unregister(snd_opti9xx_platform_device);
 		platform_driver_unregister(&snd_opti9xx_driver);
 	}
+#ifdef CONFIG_PNP
 	pnp_unregister_card_driver(&opti9xx_pnpc_driver);
+#endif
 }
 
 module_init(alsa_card_opti9xx_init)
diff --git a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c
index 0667bd1..5737ab7 100644
--- a/sound/isa/sb/sb16.c
+++ b/sound/isa/sb/sb16.c
@@ -712,9 +712,9 @@
 	if ((err = platform_driver_register(&snd_sb16_nonpnp_driver)) < 0)
 		return err;
 
-	for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
+	for (i = 0; i < SNDRV_CARDS; i++) {
 		struct platform_device *device;
-		if (is_isapnp_selected(i))
+		if (! enable[i] || is_isapnp_selected(i))
 			continue;
 		device = platform_device_register_simple(SND_SB16_DRIVER,
 							 i, NULL, 0);
diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c
index 9c2b5ef..9703c68 100644
--- a/sound/isa/sb/sb16_csp.c
+++ b/sound/isa/sb/sb16_csp.c
@@ -138,7 +138,7 @@
 	p->ops.csp_stop = snd_sb_csp_stop;
 	p->ops.csp_qsound_transfer = snd_sb_csp_qsound_transfer;
 
-	init_MUTEX(&p->access_mutex);
+	mutex_init(&p->access_mutex);
 	sprintf(hw->name, "CSP v%d.%d", (version >> 4), (version & 0x0f));
 	hw->iface = SNDRV_HWDEP_IFACE_SB16CSP;
 	hw->private_data = p;
@@ -265,13 +265,13 @@
  */
 static int snd_sb_csp_use(struct snd_sb_csp * p)
 {
-	down(&p->access_mutex);
+	mutex_lock(&p->access_mutex);
 	if (p->used) {
-		up(&p->access_mutex);
+		mutex_unlock(&p->access_mutex);
 		return -EAGAIN;
 	}
 	p->used++;
-	up(&p->access_mutex);
+	mutex_unlock(&p->access_mutex);
 
 	return 0;
 
@@ -282,9 +282,9 @@
  */
 static int snd_sb_csp_unuse(struct snd_sb_csp * p)
 {
-	down(&p->access_mutex);
+	mutex_lock(&p->access_mutex);
 	p->used--;
-	up(&p->access_mutex);
+	mutex_unlock(&p->access_mutex);
 
 	return 0;
 }
diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c
index 60ee79c..3efa23d 100644
--- a/sound/isa/sb/sb8.c
+++ b/sound/isa/sb/sb8.c
@@ -258,8 +258,10 @@
 		return err;
 
 	cards = 0;
-	for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
+	for (i = 0; i < SNDRV_CARDS; i++) {
 		struct platform_device *device;
+		if (! enable[i])
+			continue;
 		device = platform_device_register_simple(SND_SB8_DRIVER,
 							 i, NULL, 0);
 		if (IS_ERR(device)) {
diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c
index 1a6ee34..490b1ca 100644
--- a/sound/isa/sb/sb_mixer.c
+++ b/sound/isa/sb/sb_mixer.c
@@ -453,10 +453,8 @@
 	strlcpy(ctl->id.name, name, sizeof(ctl->id.name));
 	ctl->id.index = index;
 	ctl->private_value = value;
-	if ((err = snd_ctl_add(chip->card, ctl)) < 0) {
-		snd_ctl_free_one(ctl);
+	if ((err = snd_ctl_add(chip->card, ctl)) < 0)
 		return err;
-	}
 	return 0;
 }
 
diff --git a/sound/isa/sgalaxy.c b/sound/isa/sgalaxy.c
index 0dbbb35..a60e66a 100644
--- a/sound/isa/sgalaxy.c
+++ b/sound/isa/sgalaxy.c
@@ -360,8 +360,10 @@
 		return err;
 
 	cards = 0;
-	for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
+	for (i = 0; i < SNDRV_CARDS; i++) {
 		struct platform_device *device;
+		if (! enable[i])
+			continue;
 		device = platform_device_register_simple(SND_SGALAXY_DRIVER,
 							 i, NULL, 0);
 		if (IS_ERR(device)) {
diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c
index fa3ab96..c0115bf 100644
--- a/sound/isa/wavefront/wavefront.c
+++ b/sound/isa/wavefront/wavefront.c
@@ -710,8 +710,10 @@
 	if ((err = platform_driver_register(&snd_wavefront_driver)) < 0)
 		return err;
 
-	for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
+	for (i = 0; i < SNDRV_CARDS; i++) {
 		struct platform_device *device;
+		if (! enable[i])
+			continue;
 #ifdef CONFIG_PNP
 		if (isapnp[i])
 			continue;
diff --git a/sound/mips/au1x00.c b/sound/mips/au1x00.c
index 6d8f8b3e..cf476fe 100644
--- a/sound/mips/au1x00.c
+++ b/sound/mips/au1x00.c
@@ -43,6 +43,7 @@
 #include <sound/core.h>
 #include <sound/initval.h>
 #include <sound/pcm.h>
+#include <sound/pcm_params.h>
 #include <sound/ac97_codec.h>
 #include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-au1x00/au1000_dma.h>
@@ -153,6 +154,7 @@
 {
 	struct snd_pcm_substream *substream = stream->substream;
 	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct au1000_period *pointer;
 	unsigned long dma_start;
 	int i;
 
@@ -559,12 +561,13 @@
 		.read = snd_au1000_ac97_read,
 	};
 
-	if ((au1000->ac97_res_port = request_region(AC97C_CONFIG,
-	       		sizeof(struct au1000_ac97_reg), "Au1x00 AC97")) == NULL) {
+	if ((au1000->ac97_res_port = request_mem_region(CPHYSADDR(AC97C_CONFIG),
+	       		0x100000, "Au1x00 AC97")) == NULL) {
 		snd_printk(KERN_ERR "ALSA AC97: can't grap AC97 port\n");
 		return -EBUSY;
 	}
-	au1000->ac97_ioport = (struct au1000_ac97_reg *) au1000->ac97_res_port->start;
+	au1000->ac97_ioport = (struct au1000_ac97_reg *)
+		KSEG1ADDR(au1000->ac97_res_port->start);
 
 	spin_lock_init(&au1000->ac97_lock);
 
@@ -610,14 +613,17 @@
 		release_and_free_resource(au1000->ac97_res_port);
 	}
 
-	if (au1000->stream[PLAYBACK]->dma >= 0)
-		free_au1000_dma(au1000->stream[PLAYBACK]->dma);
+	if (au1000->stream[PLAYBACK]) {
+	  	if (au1000->stream[PLAYBACK]->dma >= 0)
+			free_au1000_dma(au1000->stream[PLAYBACK]->dma);
+		kfree(au1000->stream[PLAYBACK]);
+	}
 
-	if (au1000->stream[CAPTURE]->dma >= 0)
-		free_au1000_dma(au1000->stream[CAPTURE]->dma);
-
-	kfree(au1000->stream[PLAYBACK]);
-	kfree(au1000->stream[CAPTURE]);
+	if (au1000->stream[CAPTURE]) {
+		if (au1000->stream[CAPTURE]->dma >= 0)
+			free_au1000_dma(au1000->stream[CAPTURE]->dma);
+		kfree(au1000->stream[CAPTURE]);
+	}
 }
 
 
@@ -636,15 +642,19 @@
 
 	card->private_free = snd_au1000_free;
 	au1000 = card->private_data;
-	/* so that snd_au1000_free will work as intended */
 	au1000->card = card;
-	au1000->stream[PLAYBACK]->dma = -1;
-	au1000->stream[CAPTURE]->dma = -1;
- 	au1000->ac97_res_port = NULL;
+
 	au1000->stream[PLAYBACK] = kmalloc(sizeof(struct audio_stream), GFP_KERNEL);
-	au1000->stream[CAPTURE] = kmalloc(sizeof(struct audio_stream), GFP_KERNEL);
+	au1000->stream[CAPTURE ] = kmalloc(sizeof(struct audio_stream), GFP_KERNEL);
+	/* so that snd_au1000_free will work as intended */
+ 	au1000->ac97_res_port = NULL;
+	if (au1000->stream[PLAYBACK])
+		au1000->stream[PLAYBACK]->dma = -1;
+	if (au1000->stream[CAPTURE ])
+		au1000->stream[CAPTURE ]->dma = -1;
+
 	if (au1000->stream[PLAYBACK] == NULL ||
-	    au1000->stream[CAPTURE] == NULL) {
+	    au1000->stream[CAPTURE ] == NULL) {
 		snd_card_free(card);
 		return -ENOMEM;
 	}
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index 3020ca2..278319b 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -28,6 +28,7 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/ac97_codec.h>
@@ -149,7 +150,7 @@
 { 0x49544561, 0xffffffff, "IT2646E",		patch_it2646,	NULL },
 { 0x4e534300, 0xffffffff, "LM4540,43,45,46,48",	NULL,		NULL }, // only guess --jk
 { 0x4e534331, 0xffffffff, "LM4549",		NULL,		NULL },
-{ 0x4e534350, 0xffffffff, "LM4550",		NULL,		NULL },
+{ 0x4e534350, 0xffffffff, "LM4550",		patch_lm4550,  	NULL }, // volume wrap fix 
 { 0x50534304, 0xffffffff, "UCB1400",		NULL,		NULL },
 { 0x53494c20, 0xffffffe0, "Si3036,8",		mpatch_si3036,	mpatch_si3036, AC97_MODEM_PATCH },
 { 0x54524102, 0xffffffff, "TR28022",		NULL,		NULL },
@@ -191,9 +192,6 @@
 
 static int snd_ac97_valid_reg(struct snd_ac97 *ac97, unsigned short reg)
 {
-	if (ac97->limited_regs && ! test_bit(reg, ac97->reg_accessed))
-  		return 0;
-
 	/* filter some registers for buggy codecs */
 	switch (ac97->id) {
 	case AC97_ID_AK4540:
@@ -296,11 +294,11 @@
 {
 	if (!snd_ac97_valid_reg(ac97, reg))
 		return;
-	down(&ac97->reg_mutex);
+	mutex_lock(&ac97->reg_mutex);
 	ac97->regs[reg] = value;
 	ac97->bus->ops->write(ac97, reg, value);
 	set_bit(reg, ac97->reg_accessed);
-	up(&ac97->reg_mutex);
+	mutex_unlock(&ac97->reg_mutex);
 }
 
 /**
@@ -321,14 +319,14 @@
 
 	if (!snd_ac97_valid_reg(ac97, reg))
 		return -EINVAL;
-	down(&ac97->reg_mutex);
+	mutex_lock(&ac97->reg_mutex);
 	change = ac97->regs[reg] != value;
 	if (change) {
 		ac97->regs[reg] = value;
 		ac97->bus->ops->write(ac97, reg, value);
 	}
 	set_bit(reg, ac97->reg_accessed);
-	up(&ac97->reg_mutex);
+	mutex_unlock(&ac97->reg_mutex);
 	return change;
 }
 
@@ -351,9 +349,9 @@
 
 	if (!snd_ac97_valid_reg(ac97, reg))
 		return -EINVAL;
-	down(&ac97->reg_mutex);
+	mutex_lock(&ac97->reg_mutex);
 	change = snd_ac97_update_bits_nolock(ac97, reg, mask, value);
-	up(&ac97->reg_mutex);
+	mutex_unlock(&ac97->reg_mutex);
 	return change;
 }
 
@@ -380,12 +378,12 @@
 	int change;
 	unsigned short old, new, cfg;
 
-	down(&ac97->page_mutex);
+	mutex_lock(&ac97->page_mutex);
 	old = ac97->spec.ad18xx.pcmreg[codec];
 	new = (old & ~mask) | value;
 	change = old != new;
 	if (change) {
-		down(&ac97->reg_mutex);
+		mutex_lock(&ac97->reg_mutex);
 		cfg = snd_ac97_read_cache(ac97, AC97_AD_SERIAL_CFG);
 		ac97->spec.ad18xx.pcmreg[codec] = new;
 		/* select single codec */
@@ -397,9 +395,9 @@
 		/* select all codecs */
 		ac97->bus->ops->write(ac97, AC97_AD_SERIAL_CFG,
 				 cfg | 0x7000);
-		up(&ac97->reg_mutex);
+		mutex_unlock(&ac97->reg_mutex);
 	}
-	up(&ac97->page_mutex);
+	mutex_unlock(&ac97->page_mutex);
 	return change;
 }
 
@@ -467,7 +465,7 @@
 	    (ac97->ext_id & AC97_EI_REV_MASK) >= AC97_EI_REV_23 &&
 	    (reg >= 0x60 && reg < 0x70)) {
 		unsigned short page = (kcontrol->private_value >> 26) & 0x0f;
-		down(&ac97->page_mutex); /* lock paging */
+		mutex_lock(&ac97->page_mutex); /* lock paging */
 		page_save = snd_ac97_read(ac97, AC97_INT_PAGING) & AC97_PAGE_MASK;
 		snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page);
 	}
@@ -478,7 +476,7 @@
 {
 	if (page_save >= 0) {
 		snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page_save);
-		up(&ac97->page_mutex); /* unlock paging */
+		mutex_unlock(&ac97->page_mutex); /* unlock paging */
 	}
 }
 
@@ -674,12 +672,12 @@
 {
 	struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
 
-	down(&ac97->reg_mutex);
+	mutex_lock(&ac97->reg_mutex);
 	ucontrol->value.iec958.status[0] = ac97->spdif_status & 0xff;
 	ucontrol->value.iec958.status[1] = (ac97->spdif_status >> 8) & 0xff;
 	ucontrol->value.iec958.status[2] = (ac97->spdif_status >> 16) & 0xff;
 	ucontrol->value.iec958.status[3] = (ac97->spdif_status >> 24) & 0xff;
-	up(&ac97->reg_mutex);
+	mutex_unlock(&ac97->reg_mutex);
 	return 0;
 }
                         
@@ -718,7 +716,7 @@
 		}
 	}
 
-	down(&ac97->reg_mutex);
+	mutex_lock(&ac97->reg_mutex);
 	change = ac97->spdif_status != new;
 	ac97->spdif_status = new;
 
@@ -746,7 +744,7 @@
 			snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF); /* turn on again */
                 }
 	}
-	up(&ac97->reg_mutex);
+	mutex_unlock(&ac97->reg_mutex);
 
 	return change;
 }
@@ -763,7 +761,7 @@
 
 	value = (ucontrol->value.integer.value[0] & mask);
 
-	down(&ac97->reg_mutex);
+	mutex_lock(&ac97->reg_mutex);
 	mask <<= shift;
 	value <<= shift;
 	old = snd_ac97_read_cache(ac97, reg);
@@ -777,7 +775,7 @@
 		if (extst & AC97_EA_SPDIF)
 			snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF); /* turn on again */
 	}
-	up(&ac97->reg_mutex);
+	mutex_unlock(&ac97->reg_mutex);
 	return change;
 }
 
@@ -888,10 +886,10 @@
 	struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
 	int codec = kcontrol->private_value & 3;
 	
-	down(&ac97->page_mutex);
+	mutex_lock(&ac97->page_mutex);
 	ucontrol->value.integer.value[0] = 31 - ((ac97->spec.ad18xx.pcmreg[codec] >> 0) & 31);
 	ucontrol->value.integer.value[1] = 31 - ((ac97->spec.ad18xx.pcmreg[codec] >> 8) & 31);
-	up(&ac97->page_mutex);
+	mutex_unlock(&ac97->page_mutex);
 	return 0;
 }
 
@@ -1007,9 +1005,6 @@
 		break;
 	}
 
-	if (ac97->limited_regs && test_bit(reg, ac97->reg_accessed))
-		return 1; /* allow without check */
-
 	val = snd_ac97_read(ac97, reg);
 	if (!(val & mask)) {
 		/* nothing seems to be here - mute flag is not set */
@@ -1029,6 +1024,18 @@
 	unsigned char max[3] = { 63, 31, 15 };
 	int i;
 
+	/* first look up the static resolution table */
+	if (ac97->res_table) {
+		const struct snd_ac97_res_table *tbl;
+		for (tbl = ac97->res_table; tbl->reg; tbl++) {
+			if (tbl->reg == reg) {
+				*lo_max = tbl->bits & 0xff;
+				*hi_max = (tbl->bits >> 8) & 0xff;
+				return;
+			}
+		}
+	}
+
 	*lo_max = *hi_max = 0;
 	for (i = 0 ; i < ARRAY_SIZE(cbit); i++) {
 		unsigned short val;
@@ -1853,11 +1860,10 @@
 	ac97->num = template->num;
 	ac97->addr = template->addr;
 	ac97->scaps = template->scaps;
-	ac97->limited_regs = template->limited_regs;
-	memcpy(ac97->reg_accessed, template->reg_accessed, sizeof(ac97->reg_accessed));
+	ac97->res_table = template->res_table;
 	bus->codec[ac97->num] = ac97;
-	init_MUTEX(&ac97->reg_mutex);
-	init_MUTEX(&ac97->page_mutex);
+	mutex_init(&ac97->reg_mutex);
+	mutex_init(&ac97->page_mutex);
 
 #ifdef CONFIG_PCI
 	if (ac97->pci) {
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index a444a78..4d9cf37 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -27,6 +27,8 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/control.h>
@@ -55,12 +57,12 @@
 	unsigned short page_save;
 	int ret;
 
-	down(&ac97->page_mutex);
+	mutex_lock(&ac97->page_mutex);
 	page_save = snd_ac97_read(ac97, AC97_INT_PAGING) & AC97_PAGE_MASK;
 	snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page);
 	ret = snd_ac97_update_bits(ac97, reg, mask, value);
 	snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page_save);
-	up(&ac97->page_mutex); /* unlock paging */
+	mutex_unlock(&ac97->page_mutex); /* unlock paging */
 	return ret;
 }
 
@@ -897,12 +899,12 @@
 	struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
 	int err;
 
-	down(&ac97->page_mutex);
+	mutex_lock(&ac97->page_mutex);
 	snd_ac97_write(ac97, AC97_SIGMATEL_BIAS1, 0xabba);
 	err = snd_ac97_update_bits(ac97, AC97_SIGMATEL_BIAS2, 0x0010,
 				   (ucontrol->value.integer.value[0] & 1) << 4);
 	snd_ac97_write(ac97, AC97_SIGMATEL_BIAS1, 0);
-	up(&ac97->page_mutex);
+	mutex_unlock(&ac97->page_mutex);
 	return err;
 }
 
@@ -2823,3 +2825,33 @@
 	snd_ac97_write_cache(ac97, 0x68, 0);
 	return 0;
 }
+
+/*
+ * LM 4550 Codec
+ *
+ * We use a static resolution table since LM4550 codec cannot be
+ * properly autoprobed to determine the resolution via
+ * check_volume_resolution().
+ */
+
+static struct snd_ac97_res_table lm4550_restbl[] = {
+	{ AC97_MASTER, 0x1f1f },
+	{ AC97_HEADPHONE, 0x1f1f },
+	{ AC97_MASTER_MONO, 0x001f },
+	{ AC97_PC_BEEP, 0x001f },	/* LSB is ignored */
+	{ AC97_PHONE, 0x001f },
+	{ AC97_MIC, 0x001f },
+	{ AC97_LINE, 0x1f1f },
+	{ AC97_CD, 0x1f1f },
+	{ AC97_VIDEO, 0x1f1f },
+	{ AC97_AUX, 0x1f1f },
+	{ AC97_PCM, 0x1f1f },
+	{ AC97_REC_GAIN, 0x0f0f },
+	{ } /* terminator */
+};
+
+int patch_lm4550(struct snd_ac97 *ac97)
+{
+	ac97->res_table = lm4550_restbl;
+	return 0;
+}
diff --git a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h
index 5060cb6..adcaa04 100644
--- a/sound/pci/ac97/ac97_patch.h
+++ b/sound/pci/ac97/ac97_patch.h
@@ -59,3 +59,4 @@
 int patch_vt1617a(struct snd_ac97 * ac97);
 int patch_it2646(struct snd_ac97 * ac97);
 int mpatch_si3036(struct snd_ac97 * ac97);
+int patch_lm4550(struct snd_ac97 * ac97);
diff --git a/sound/pci/ac97/ac97_pcm.c b/sound/pci/ac97/ac97_pcm.c
index c3e590b..512a358 100644
--- a/sound/pci/ac97/ac97_pcm.c
+++ b/sound/pci/ac97/ac97_pcm.c
@@ -27,6 +27,8 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/control.h>
@@ -206,7 +208,7 @@
 		mask = AC97_SC_SPSR_MASK;
 	}
 
-	down(&ac97->reg_mutex);
+	mutex_lock(&ac97->reg_mutex);
 	old = snd_ac97_read(ac97, reg) & mask;
 	if (old != bits) {
 		snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0);
@@ -231,7 +233,7 @@
 		ac97->spdif_status = sbits;
 	}
 	snd_ac97_update_bits_nolock(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF);
-	up(&ac97->reg_mutex);
+	mutex_unlock(&ac97->reg_mutex);
 	return 0;
 }
 
diff --git a/sound/pci/ac97/ac97_proc.c b/sound/pci/ac97/ac97_proc.c
index 7134b3f..4d523df 100644
--- a/sound/pci/ac97/ac97_proc.c
+++ b/sound/pci/ac97/ac97_proc.c
@@ -24,6 +24,8 @@
 
 #include <sound/driver.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/ac97_codec.h>
 #include <sound/asoundef.h>
@@ -338,7 +340,7 @@
 {
 	struct snd_ac97 *ac97 = entry->private_data;
 	
-	down(&ac97->page_mutex);
+	mutex_lock(&ac97->page_mutex);
 	if ((ac97->id & 0xffffff40) == AC97_ID_AD1881) {	// Analog Devices AD1881/85/86
 		int idx;
 		for (idx = 0; idx < 3; idx++)
@@ -364,7 +366,7 @@
 	} else {
 		snd_ac97_proc_read_main(ac97, buffer, 0);
 	}
-	up(&ac97->page_mutex);
+	mutex_unlock(&ac97->page_mutex);
 }
 
 #ifdef CONFIG_SND_DEBUG
@@ -374,7 +376,7 @@
 	struct snd_ac97 *ac97 = entry->private_data;
 	char line[64];
 	unsigned int reg, val;
-	down(&ac97->page_mutex);
+	mutex_lock(&ac97->page_mutex);
 	while (!snd_info_get_line(buffer, line, sizeof(line))) {
 		if (sscanf(line, "%x %x", &reg, &val) != 2)
 			continue;
@@ -382,7 +384,7 @@
 		if (reg < 0x80 && (reg & 1) == 0 && val <= 0xffff)
 			snd_ac97_write_cache(ac97, reg, val);
 	}
-	up(&ac97->page_mutex);
+	mutex_unlock(&ac97->page_mutex);
 }
 #endif
 
@@ -401,7 +403,7 @@
 {
 	struct snd_ac97 *ac97 = entry->private_data;
 
-	down(&ac97->page_mutex);
+	mutex_lock(&ac97->page_mutex);
 	if ((ac97->id & 0xffffff40) == AC97_ID_AD1881) {	// Analog Devices AD1881/85/86
 
 		int idx;
@@ -417,7 +419,7 @@
 	} else {
 		snd_ac97_proc_regs_read_main(ac97, buffer, 0);
 	}	
-	up(&ac97->page_mutex);
+	mutex_unlock(&ac97->page_mutex);
 }
 
 void snd_ac97_proc_init(struct snd_ac97 * ac97)
diff --git a/sound/pci/ac97/ak4531_codec.c b/sound/pci/ac97/ak4531_codec.c
index dcfb503..0fb7b34 100644
--- a/sound/pci/ac97/ak4531_codec.c
+++ b/sound/pci/ac97/ak4531_codec.c
@@ -23,6 +23,8 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/ak4531_codec.h>
 
@@ -82,9 +84,9 @@
 	int invert = (kcontrol->private_value >> 22) & 1;
 	int val;
 
-	down(&ak4531->reg_mutex);
+	mutex_lock(&ak4531->reg_mutex);
 	val = (ak4531->regs[reg] >> shift) & mask;
-	up(&ak4531->reg_mutex);
+	mutex_unlock(&ak4531->reg_mutex);
 	if (invert) {
 		val = mask - val;
 	}
@@ -107,11 +109,11 @@
 		val = mask - val;
 	}
 	val <<= shift;
-	down(&ak4531->reg_mutex);
+	mutex_lock(&ak4531->reg_mutex);
 	val = (ak4531->regs[reg] & ~(mask << shift)) | val;
 	change = val != ak4531->regs[reg];
 	ak4531->write(ak4531, reg, ak4531->regs[reg] = val);
-	up(&ak4531->reg_mutex);
+	mutex_unlock(&ak4531->reg_mutex);
 	return change;
 }
 
@@ -143,10 +145,10 @@
 	int invert = (kcontrol->private_value >> 22) & 1;
 	int left, right;
 
-	down(&ak4531->reg_mutex);
+	mutex_lock(&ak4531->reg_mutex);
 	left = (ak4531->regs[left_reg] >> left_shift) & mask;
 	right = (ak4531->regs[right_reg] >> right_shift) & mask;
-	up(&ak4531->reg_mutex);
+	mutex_unlock(&ak4531->reg_mutex);
 	if (invert) {
 		left = mask - left;
 		right = mask - right;
@@ -176,7 +178,7 @@
 	}
 	left <<= left_shift;
 	right <<= right_shift;
-	down(&ak4531->reg_mutex);
+	mutex_lock(&ak4531->reg_mutex);
 	if (left_reg == right_reg) {
 		left = (ak4531->regs[left_reg] & ~((mask << left_shift) | (mask << right_shift))) | left | right;
 		change = left != ak4531->regs[left_reg];
@@ -188,7 +190,7 @@
 		ak4531->write(ak4531, left_reg, ak4531->regs[left_reg] = left);
 		ak4531->write(ak4531, right_reg, ak4531->regs[right_reg] = right);
 	}
-	up(&ak4531->reg_mutex);
+	mutex_unlock(&ak4531->reg_mutex);
 	return change;
 }
 
@@ -215,12 +217,12 @@
 	int left_shift = (kcontrol->private_value >> 16) & 0x0f;
 	int right_shift = (kcontrol->private_value >> 24) & 0x0f;
 
-	down(&ak4531->reg_mutex);
+	mutex_lock(&ak4531->reg_mutex);
 	ucontrol->value.integer.value[0] = (ak4531->regs[reg1] >> left_shift) & 1;
 	ucontrol->value.integer.value[1] = (ak4531->regs[reg2] >> left_shift) & 1;
 	ucontrol->value.integer.value[2] = (ak4531->regs[reg1] >> right_shift) & 1;
 	ucontrol->value.integer.value[3] = (ak4531->regs[reg2] >> right_shift) & 1;
-	up(&ak4531->reg_mutex);
+	mutex_unlock(&ak4531->reg_mutex);
 	return 0;
 }
 
@@ -234,7 +236,7 @@
 	int change;
 	int val1, val2;
 
-	down(&ak4531->reg_mutex);
+	mutex_lock(&ak4531->reg_mutex);
 	val1 = ak4531->regs[reg1] & ~((1 << left_shift) | (1 << right_shift));
 	val2 = ak4531->regs[reg2] & ~((1 << left_shift) | (1 << right_shift));
 	val1 |= (ucontrol->value.integer.value[0] & 1) << left_shift;
@@ -244,7 +246,7 @@
 	change = val1 != ak4531->regs[reg1] || val2 != ak4531->regs[reg2];
 	ak4531->write(ak4531, reg1, ak4531->regs[reg1] = val1);
 	ak4531->write(ak4531, reg2, ak4531->regs[reg2] = val2);
-	up(&ak4531->reg_mutex);
+	mutex_unlock(&ak4531->reg_mutex);
 	return change;
 }
 
@@ -366,7 +368,7 @@
 	if (ak4531 == NULL)
 		return -ENOMEM;
 	*ak4531 = *_ak4531;
-	init_MUTEX(&ak4531->reg_mutex);
+	mutex_init(&ak4531->reg_mutex);
 	if ((err = snd_component_add(card, "AK4531")) < 0) {
 		snd_ak4531_free(ak4531);
 		return err;
diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c
index a208075..2aa5a7f 100644
--- a/sound/pci/ad1889.c
+++ b/sound/pci/ad1889.c
@@ -34,6 +34,7 @@
 
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/compiler.h>
@@ -909,10 +910,10 @@
 
 	if ((err = pci_enable_device(pci)) < 0)
 		return err;
-	
+
 	/* check PCI availability (32bit DMA) */
-	if (pci_set_dma_mask(pci, 0xffffffff) < 0 ||
-	    pci_set_consistent_dma_mask(pci, 0xffffffff) < 0) {
+	if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 ||
+	    pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) {
 		printk(KERN_ERR PFX "error setting 32-bit DMA mask.\n");
 		pci_disable_device(pci);
 		return -ENXIO;
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index b7217ad..12e6188 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -27,6 +27,7 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -277,7 +278,7 @@
 	unsigned int codec_not_ready_bits;	/* for codec detection */
 
 	int spdif_over_aclink;		/* passed from the module option */
-	struct semaphore open_mutex;	/* playback open mutex */
+	struct mutex open_mutex;	/* playback open mutex */
 };
 
 
@@ -1051,9 +1052,9 @@
 	struct atiixp *chip = snd_pcm_substream_chip(substream);
 	int err;
 
-	down(&chip->open_mutex);
+	mutex_lock(&chip->open_mutex);
 	err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 0);
-	up(&chip->open_mutex);
+	mutex_unlock(&chip->open_mutex);
 	if (err < 0)
 		return err;
 	substream->runtime->hw.channels_max = chip->max_channels;
@@ -1068,9 +1069,9 @@
 {
 	struct atiixp *chip = snd_pcm_substream_chip(substream);
 	int err;
-	down(&chip->open_mutex);
+	mutex_lock(&chip->open_mutex);
 	err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]);
-	up(&chip->open_mutex);
+	mutex_unlock(&chip->open_mutex);
 	return err;
 }
 
@@ -1090,12 +1091,12 @@
 {
 	struct atiixp *chip = snd_pcm_substream_chip(substream);
 	int err;
-	down(&chip->open_mutex);
+	mutex_lock(&chip->open_mutex);
 	if (chip->spdif_over_aclink) /* share DMA_PLAYBACK */
 		err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 2);
 	else
 		err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_SPDIF], -1);
-	up(&chip->open_mutex);
+	mutex_unlock(&chip->open_mutex);
 	return err;
 }
 
@@ -1103,12 +1104,12 @@
 {
 	struct atiixp *chip = snd_pcm_substream_chip(substream);
 	int err;
-	down(&chip->open_mutex);
+	mutex_lock(&chip->open_mutex);
 	if (chip->spdif_over_aclink)
 		err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]);
 	else
 		err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_SPDIF]);
-	up(&chip->open_mutex);
+	mutex_unlock(&chip->open_mutex);
 	return err;
 }
 
@@ -1560,7 +1561,7 @@
 	}
 
 	spin_lock_init(&chip->reg_lock);
-	init_MUTEX(&chip->open_mutex);
+	mutex_init(&chip->open_mutex);
 	chip->card = card;
 	chip->pci = pci;
 	chip->irq = -1;
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index 8d8fd5a..1d37660 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -27,6 +27,7 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -255,7 +256,7 @@
 	unsigned int codec_not_ready_bits;	/* for codec detection */
 
 	int spdif_over_aclink;		/* passed from the module option */
-	struct semaphore open_mutex;	/* playback open mutex */
+	struct mutex open_mutex;	/* playback open mutex */
 };
 
 
@@ -911,9 +912,9 @@
 	struct atiixp_modem *chip = snd_pcm_substream_chip(substream);
 	int err;
 
-	down(&chip->open_mutex);
+	mutex_lock(&chip->open_mutex);
 	err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 0);
-	up(&chip->open_mutex);
+	mutex_unlock(&chip->open_mutex);
 	if (err < 0)
 		return err;
 	return 0;
@@ -923,9 +924,9 @@
 {
 	struct atiixp_modem *chip = snd_pcm_substream_chip(substream);
 	int err;
-	down(&chip->open_mutex);
+	mutex_lock(&chip->open_mutex);
 	err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]);
-	up(&chip->open_mutex);
+	mutex_unlock(&chip->open_mutex);
 	return err;
 }
 
@@ -1233,7 +1234,7 @@
 	}
 
 	spin_lock_init(&chip->reg_lock);
-	init_MUTEX(&chip->open_mutex);
+	mutex_init(&chip->open_mutex);
 	chip->card = card;
 	chip->pci = pci;
 	chip->irq = -1;
diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c
index 7d9184f..126870e 100644
--- a/sound/pci/au88x0/au88x0.c
+++ b/sound/pci/au88x0/au88x0.c
@@ -151,14 +151,18 @@
 	// check PCI availability (DMA).
 	if ((err = pci_enable_device(pci)) < 0)
 		return err;
-	if (pci_set_dma_mask(pci, DMA_32BIT_MASK)) {
+	if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 ||
+	    pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) {
 		printk(KERN_ERR "error to set DMA mask\n");
+		pci_disable_device(pci);
 		return -ENXIO;
 	}
 
 	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
-	if (chip == NULL)
+	if (chip == NULL) {
+		pci_disable_device(pci);
 		return -ENOMEM;
+	}
 
 	chip->card = card;
 
@@ -208,6 +212,8 @@
 		goto alloc_out;
 	}
 
+	snd_card_set_dev(card, &pci->dev);
+
 	*rchip = chip;
 
 	return 0;
diff --git a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h
index c2ad267..d65ccb1 100644
--- a/sound/pci/au88x0/au88x0.h
+++ b/sound/pci/au88x0/au88x0.h
@@ -39,8 +39,8 @@
 #include "au88x0_wt.h"
 #endif
 
-#define	hwread(x,y) readl((x)+((y)>>2))
-#define	hwwrite(x,y,z) writel((z),(x)+((y)>>2))
+#define	hwread(x,y) readl((x)+(y))
+#define	hwwrite(x,y,z) writel((z),(x)+(y))
 
 /* Vortex MPU401 defines. */
 #define	MIDI_CLOCK_DIV		0x61
@@ -113,7 +113,7 @@
 	//int this_08;          /* Still unknown */
 	int fifo_enabled;	/* this_24 */
 	int fifo_status;	/* this_1c */
-	int dma_ctrl;		/* this_78 (ADB), this_7c (WT) */
+	u32 dma_ctrl;		/* this_78 (ADB), this_7c (WT) */
 	int dma_unknown;	/* this_74 (ADB), this_78 (WT). WDM: +8 */
 	int cfg0;
 	int cfg1;
@@ -178,7 +178,7 @@
 
 	/* PCI hardware resources */
 	unsigned long io;
-	unsigned long __iomem *mmio;
+	void __iomem *mmio;
 	unsigned int irq;
 	spinlock_t lock;
 
@@ -201,14 +201,14 @@
 				     int count);
 static void vortex_adbdma_setmode(vortex_t * vortex, int adbdma, int ie,
 				  int dir, int fmt, int d,
-				  unsigned long offset);
+				  u32 offset);
 static void vortex_adbdma_setstartbuffer(vortex_t * vortex, int adbdma, int sb);
 #ifndef CHIP_AU8810
 static void vortex_wtdma_setbuffers(vortex_t * vortex, int wtdma,
 				    struct snd_sg_buf * sgbuf, int size,
 				    int count);
 static void vortex_wtdma_setmode(vortex_t * vortex, int wtdma, int ie, int fmt, int d,	/*int e, */
-				 unsigned long offset);
+				 u32 offset);
 static void vortex_wtdma_setstartbuffer(vortex_t * vortex, int wtdma, int sb);
 #endif
 
diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c
index e3394fe..9cac02e 100644
--- a/sound/pci/au88x0/au88x0_core.c
+++ b/sound/pci/au88x0/au88x0_core.c
@@ -376,7 +376,7 @@
 
 static void vortex_mixer_init(vortex_t * vortex)
 {
-	unsigned long addr;
+	u32 addr;
 	int x;
 
 	// FIXME: get rid of this crap.
@@ -639,7 +639,7 @@
 
 static void vortex_srcblock_init(vortex_t * vortex)
 {
-	unsigned long addr;
+	u32 addr;
 	int x;
 	hwwrite(vortex->mmio, VORTEX_SRC_SOURCESIZE, 0x1ff);
 	/*
@@ -1035,7 +1035,7 @@
 static void vortex_fifo_init(vortex_t * vortex)
 {
 	int x;
-	unsigned long addr;
+	u32 addr;
 
 	/* ADB DMA channels fifos. */
 	addr = VORTEX_FIFO_ADBCTRL + ((NR_ADB - 1) * 4);
@@ -1054,7 +1054,7 @@
 		hwwrite(vortex->mmio, addr, FIFO_U0);
 		if (hwread(vortex->mmio, addr) != FIFO_U0)
 			printk(KERN_ERR
-			       "bad wt fifo reset (0x%08lx, 0x%08x)!\n",
+			       "bad wt fifo reset (0x%08x, 0x%08x)!\n",
 			       addr, hwread(vortex->mmio, addr));
 		vortex_fifo_clearwtdata(vortex, x, FIFO_SIZE);
 		addr -= 4;
@@ -1152,7 +1152,7 @@
 
 static void
 vortex_adbdma_setmode(vortex_t * vortex, int adbdma, int ie, int dir,
-		      int fmt, int d, unsigned long offset)
+		      int fmt, int d, u32 offset)
 {
 	stream_t *dma = &vortex->dma_adb[adbdma];
 
@@ -1411,7 +1411,7 @@
 
 static void
 vortex_wtdma_setmode(vortex_t * vortex, int wtdma, int ie, int fmt, int d,
-		     /*int e, */ unsigned long offset)
+		     /*int e, */ u32 offset)
 {
 	stream_t *dma = &vortex->dma_wt[wtdma];
 
diff --git a/sound/pci/au88x0/au88x0_eq.c b/sound/pci/au88x0/au88x0_eq.c
index c8280f8..64fbfbb 100644
--- a/sound/pci/au88x0/au88x0_eq.c
+++ b/sound/pci/au88x0/au88x0_eq.c
@@ -377,23 +377,23 @@
 
 #endif
 /* Global Control */
-static void vortex_EqHw_SetControlReg(vortex_t * vortex, unsigned long reg)
+static void vortex_EqHw_SetControlReg(vortex_t * vortex, u32 reg)
 {
 	hwwrite(vortex->mmio, 0x2b440, reg);
 }
 
-static void vortex_EqHw_SetSampleRate(vortex_t * vortex, int sr)
+static void vortex_EqHw_SetSampleRate(vortex_t * vortex, u32 sr)
 {
 	hwwrite(vortex->mmio, 0x2b440, ((sr & 0x1f) << 3) | 0xb800);
 }
 
 #if 0
-static void vortex_EqHw_GetControlReg(vortex_t * vortex, unsigned long *reg)
+static void vortex_EqHw_GetControlReg(vortex_t * vortex, u32 *reg)
 {
 	*reg = hwread(vortex->mmio, 0x2b440);
 }
 
-static void vortex_EqHw_GetSampleRate(vortex_t * vortex, int *sr)
+static void vortex_EqHw_GetSampleRate(vortex_t * vortex, u32 *sr)
 {
 	*sr = (hwread(vortex->mmio, 0x2b440) >> 3) & 0x1f;
 }
@@ -554,7 +554,7 @@
 
 #if 0
 static int
-vortex_Eqlzr_GetAllBands(vortex_t * vortex, u16 * gains, unsigned long *cnt)
+vortex_Eqlzr_GetAllBands(vortex_t * vortex, u16 * gains, s32 *cnt)
 {
 	eqlzr_t *eq = &(vortex->eq);
 	int si = 0;
@@ -586,7 +586,7 @@
 }
 
 static int
-vortex_Eqlzr_SetAllBands(vortex_t * vortex, u16 gains[], unsigned long count)
+vortex_Eqlzr_SetAllBands(vortex_t * vortex, u16 gains[], s32 count)
 {
 	eqlzr_t *eq = &(vortex->eq);
 	int i;
@@ -604,11 +604,10 @@
 }
 
 static void
-vortex_Eqlzr_SetA3dBypassGain(vortex_t * vortex, unsigned long a,
-			      unsigned long b)
+vortex_Eqlzr_SetA3dBypassGain(vortex_t * vortex, u32 a, u32 b)
 {
 	eqlzr_t *eq = &(vortex->eq);
-	int eax, ebx;
+	u32 eax, ebx;
 
 	eq->this58 = a;
 	eq->this5c = b;
@@ -624,7 +623,7 @@
 static void vortex_Eqlzr_ProgramA3dBypassGain(vortex_t * vortex)
 {
 	eqlzr_t *eq = &(vortex->eq);
-	int eax, ebx;
+	u32 eax, ebx;
 
 	if (eq->this54)
 		eax = eq->this0e;
@@ -641,7 +640,7 @@
 		vortex_EqHw_ZeroA3DIO(vortex);
 }
 
-static void vortex_Eqlzr_SetBypass(vortex_t * vortex, long bp)
+static void vortex_Eqlzr_SetBypass(vortex_t * vortex, u32 bp)
 {
 	eqlzr_t *eq = &(vortex->eq);
 	
@@ -651,8 +650,8 @@
 		vortex_EqHw_SetBypassGain(vortex, eq->this08, eq->this08);
 	} else {
 		/* EQ disabled. */
-		vortex_EqHw_SetLeftGainsTarget(vortex, (u16 *) (eq->this14));
-		vortex_EqHw_SetRightGainsTarget(vortex, (u16 *) (eq->this14));
+		vortex_EqHw_SetLeftGainsTarget(vortex, eq->this14_array);
+		vortex_EqHw_SetRightGainsTarget(vortex, eq->this14_array);
 		vortex_EqHw_SetBypassGain(vortex, eq->this0c, eq->this0c);
 	}
 	vortex_Eqlzr_ProgramA3dBypassGain(vortex);
@@ -706,7 +705,7 @@
 	eq->this5c = 0xffff;
 
 	/* Set gains. */
-	memset(eq->this14, 0, 2 * 10);
+	memset(eq->this14_array, 0, sizeof(eq->this14_array));
 
 	/* Actual init. */
 	vortex_EqHw_ZeroState(vortex);
@@ -792,7 +791,7 @@
 {
 	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
 	int i = kcontrol->private_value;
-	u16 gainL, gainR;
+	u16 gainL = 0, gainR = 0;
 
 	vortex_Eqlzr_GetLeftGain(vortex, i, &gainL);
 	vortex_Eqlzr_GetRightGain(vortex, i, &gainR);
@@ -806,7 +805,7 @@
 {
 	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
 	int changed = 0, i = kcontrol->private_value;
-	u16 gainL, gainR;
+	u16 gainL = 0, gainR = 0;
 
 	vortex_Eqlzr_GetLeftGain(vortex, i, &gainL);
 	vortex_Eqlzr_GetRightGain(vortex, i, &gainR);
diff --git a/sound/pci/au88x0/au88x0_eq.h b/sound/pci/au88x0/au88x0_eq.h
index e49bc62..474cd00 100644
--- a/sound/pci/au88x0/au88x0_eq.h
+++ b/sound/pci/au88x0/au88x0_eq.h
@@ -13,31 +13,28 @@
 typedef struct {
 	u16 LeftCoefs[50];	//0x4
 	u16 RightCoefs[50];	// 0x68
-	u16 LeftGains[20];	//0xd0
-	u16 RightGains[20];	//0xe4
+	u16 LeftGains[10];	//0xd0
+	u16 RightGains[10];	//0xe4
 } auxxEqCoeffSet_t;
 
 typedef struct {
-	unsigned int *this00;	/*CAsp4HwIO */
-	long this04;		/* How many filters for each side (default = 10) */
-	long this08;		/* inited to cero. Stereo flag? */
+	s32 this04;		/* How many filters for each side (default = 10) */
+	s32 this08;		/* inited to cero. Stereo flag? */
 } eqhw_t;
 
 typedef struct {
-	unsigned int *this00;	/*CAsp4Core */
 	eqhw_t this04;		/* CHwEq */
-	short this08;		/* Bad codec flag ? SetBypassGain: bypass gain */
-	short this0a;
-	short this0c;		/* SetBypassGain: bypass gain when this28 is not set. */
-	short this0e;
+	u16 this08;		/* Bad codec flag ? SetBypassGain: bypass gain */
+	u16 this0a;
+	u16 this0c;		/* SetBypassGain: bypass gain when this28 is not set. */
+	u16 this0e;
 
-	long this10;		/* How many gains are used for each side (right or left). */
-	u16 this14[32];		/* SetLeftGainsTarget: Left (and right?) EQ gains  */
-	long this24;
-	long this28;		/* flag related to EQ enabled or not. Gang flag ? */
-	long this54;		/* SetBypass */
-	long this58;
-	long this5c;
+	s32 this10;		/* How many gains are used for each side (right or left). */
+	u16 this14_array[10];	/* SetLeftGainsTarget: Left (and right?) EQ gains  */
+	s32 this28;		/* flag related to EQ enabled or not. Gang flag ? */
+	s32 this54;		/* SetBypass */
+	s32 this58;
+	s32 this5c;
 	/*0x60 */ auxxEqCoeffSet_t coefset;
 	/* 50 u16 word each channel. */
 	u16 this130[20];	/* Left and Right gains */
diff --git a/sound/pci/au88x0/au88x0_eqdata.c b/sound/pci/au88x0/au88x0_eqdata.c
index abf8d6a..ce8dca8 100644
--- a/sound/pci/au88x0/au88x0_eqdata.c
+++ b/sound/pci/au88x0/au88x0_eqdata.c
@@ -104,7 +104,11 @@
 };
 
 /*_rodataba0:*/
-static long eq_levels[32] = {
+static u16 eq_levels[64] = {
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
 	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
diff --git a/sound/pci/au88x0/au88x0_mpu401.c b/sound/pci/au88x0/au88x0_mpu401.c
index 8ba6dd3..873f486 100644
--- a/sound/pci/au88x0/au88x0_mpu401.c
+++ b/sound/pci/au88x0/au88x0_mpu401.c
@@ -95,7 +95,7 @@
 		return temp;
 	}
 #else
-	port = (unsigned long)(vortex->mmio + (VORTEX_MIDI_DATA >> 2));
+	port = (unsigned long)(vortex->mmio + VORTEX_MIDI_DATA);
 	if ((temp =
 	     snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_AUREAL, port,
 				 1, 0, 0, &rmidi)) != 0) {
@@ -105,7 +105,7 @@
 		return temp;
 	}
 	mpu = rmidi->private_data;
-	mpu->cport = (unsigned long)(vortex->mmio + (VORTEX_MIDI_CMD >> 2));
+	mpu->cport = (unsigned long)(vortex->mmio + VORTEX_MIDI_CMD);
 #endif
 	vortex->rmidi = rmidi;
 	return 0;
diff --git a/sound/pci/au88x0/au88x0_synth.c b/sound/pci/au88x0/au88x0_synth.c
index 65f375b..d3e662a 100644
--- a/sound/pci/au88x0/au88x0_synth.c
+++ b/sound/pci/au88x0/au88x0_synth.c
@@ -32,7 +32,7 @@
 					unsigned char mix, int a);
 static void vortex_fifo_wtinitialize(vortex_t * vortex, int fifo, int j);
 static int vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
-			    unsigned long val);
+			    u32 val);
 
 /* WT */
 
@@ -166,7 +166,7 @@
 /* WT hardware abstraction layer generic register interface. */
 static int
 vortex_wt_SetReg2(vortex_t * vortex, unsigned char reg, int wt,
-		  unsigned short val)
+		  u16 val)
 {
 	/*
 	   int eax, edx;
@@ -190,7 +190,7 @@
 #endif
 static int
 vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
-		 unsigned long val)
+		 u32 val)
 {
 	int ecx;
 
@@ -279,7 +279,7 @@
 
 static void vortex_wt_init(vortex_t * vortex)
 {
-	int var4, var8, varc, var10 = 0, edi;
+	u32 var4, var8, varc, var10 = 0, edi;
 
 	var10 &= 0xFFFFFFE3;
 	var10 |= 0x22;
@@ -353,7 +353,7 @@
 static void vortex_wt_SetFrequency(vortex_t * vortex, int wt, unsigned int sr)
 {
 	wt_voice_t *voice = &(vortex->wt_voice[wt]);
-	long int eax, edx;
+	u32 eax, edx;
 
 	//FIXME: 64 bit operation.
 	eax = ((sr << 0xf) * 0x57619F1) & 0xffffffff;
diff --git a/sound/pci/au88x0/au88x0_wt.h b/sound/pci/au88x0/au88x0_wt.h
index d536c88..38d98f8 100644
--- a/sound/pci/au88x0/au88x0_wt.h
+++ b/sound/pci/au88x0/au88x0_wt.h
@@ -53,11 +53,11 @@
 #endif
 
 typedef struct {
-	unsigned int parm0;	/* this_1E4 */
-	unsigned int parm1;	/* this_1E8 */
-	unsigned int parm2;	/* this_1EC */
-	unsigned int parm3;	/* this_1F0 */
-	unsigned int this_1D0;
+	u32 parm0;	/* this_1E4 */
+	u32 parm1;	/* this_1E8 */
+	u32 parm2;	/* this_1EC */
+	u32 parm3;	/* this_1F0 */
+	u32 this_1D0;
 } wt_voice_t;
 
 #endif				/* _AU88X0_WT_H */
diff --git a/sound/pci/au88x0/au88x0_xtalk.c b/sound/pci/au88x0/au88x0_xtalk.c
index df915fa..4534e18 100644
--- a/sound/pci/au88x0/au88x0_xtalk.c
+++ b/sound/pci/au88x0/au88x0_xtalk.c
@@ -562,7 +562,7 @@
 vortex_XtalkHw_SetDelay(vortex_t * vortex, unsigned short right,
 			unsigned short left)
 {
-	int esp0 = 0;
+	u32 esp0 = 0;
 
 	esp0 &= 0x1FFFFFFF;
 	esp0 |= 0xA0000000;
@@ -632,18 +632,18 @@
 /* Control/Global stuff */
 
 #if 0
-static void vortex_XtalkHw_SetControlReg(vortex_t * vortex, unsigned long ctrl)
+static void vortex_XtalkHw_SetControlReg(vortex_t * vortex, u32 ctrl)
 {
 	hwwrite(vortex->mmio, 0x24660, ctrl);
 }
-static void vortex_XtalkHw_GetControlReg(vortex_t * vortex, unsigned long *ctrl)
+static void vortex_XtalkHw_GetControlReg(vortex_t * vortex, u32 *ctrl)
 {
 	*ctrl = hwread(vortex->mmio, 0x24660);
 }
 #endif
-static void vortex_XtalkHw_SetSampleRate(vortex_t * vortex, int sr)
+static void vortex_XtalkHw_SetSampleRate(vortex_t * vortex, u32 sr)
 {
-	int temp;
+	u32 temp;
 
 	temp = (hwread(vortex->mmio, 0x24660) & 0x1FFFFFFF) | 0xC0000000;
 	temp = (temp & 0xffffff07) | ((sr & 0x1f) << 3);
@@ -651,7 +651,7 @@
 }
 
 #if 0
-static void vortex_XtalkHw_GetSampleRate(vortex_t * vortex, int *sr)
+static void vortex_XtalkHw_GetSampleRate(vortex_t * vortex, u32 *sr)
 {
 	*sr = (hwread(vortex->mmio, 0x24660) >> 3) & 0x1f;
 }
@@ -659,7 +659,7 @@
 #endif
 static void vortex_XtalkHw_Enable(vortex_t * vortex)
 {
-	int temp;
+	u32 temp;
 
 	temp = (hwread(vortex->mmio, 0x24660) & 0x1FFFFFFF) | 0xC0000000;
 	temp |= 1;
@@ -669,7 +669,7 @@
 
 static void vortex_XtalkHw_Disable(vortex_t * vortex)
 {
-	int temp;
+	u32 temp;
 
 	temp = (hwread(vortex->mmio, 0x24660) & 0x1FFFFFFF) | 0xC0000000;
 	temp &= 0xfffffffe;
diff --git a/sound/pci/au88x0/au88x0_xtalk.h b/sound/pci/au88x0/au88x0_xtalk.h
index 0b8d7b6..7f4534b 100644
--- a/sound/pci/au88x0/au88x0_xtalk.h
+++ b/sound/pci/au88x0/au88x0_xtalk.h
@@ -39,16 +39,16 @@
 #define XT_SPEAKER1		3
 #define XT_DIAMOND		4
 
-typedef long xtalk_dline_t[XTDLINE_SZ];
-typedef short xtalk_gains_t[XTGAINS_SZ];
-typedef short xtalk_instate_t[XTINST_SZ];
-typedef short xtalk_coefs_t[5][5];
-typedef short xtalk_state_t[5][4];
+typedef u32 xtalk_dline_t[XTDLINE_SZ];
+typedef u16 xtalk_gains_t[XTGAINS_SZ];
+typedef u16 xtalk_instate_t[XTINST_SZ];
+typedef u16 xtalk_coefs_t[5][5];
+typedef u16 xtalk_state_t[5][4];
 
 static void vortex_XtalkHw_SetGains(vortex_t * vortex,
 				    xtalk_gains_t const gains);
 static void vortex_XtalkHw_SetGainsAllChan(vortex_t * vortex);
-static void vortex_XtalkHw_SetSampleRate(vortex_t * vortex, int sr);
+static void vortex_XtalkHw_SetSampleRate(vortex_t * vortex, u32 sr);
 static void vortex_XtalkHw_ProgramPipe(vortex_t * vortex);
 static void vortex_XtalkHw_ProgramPipe(vortex_t * vortex);
 static void vortex_XtalkHw_ProgramXtalkWide(vortex_t * vortex);
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c
index c840a4c..7b44a8d 100644
--- a/sound/pci/bt87x.c
+++ b/sound/pci/bt87x.c
@@ -783,6 +783,8 @@
 	BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0xff01, 44100),
 	/* AVerMedia Studio No. 103, 203, ...? */
 	BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1461, 0x0003, 48000),
+	/* Leadtek Winfast tv 2000xp delux */
+	BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x107d, 0x6606, 32000),
 	{ }
 };
 MODULE_DEVICE_TABLE(pci, snd_bt87x_ids);
@@ -793,12 +795,15 @@
 	unsigned short subvendor, subdevice;
 } blacklist[] __devinitdata = {
 	{0x0071, 0x0101}, /* Nebula Electronics DigiTV */
+	{0x11bd, 0x001c}, /* Pinnacle PCTV Sat */
 	{0x11bd, 0x0026}, /* Pinnacle PCTV SAT CI */
 	{0x1461, 0x0761}, /* AVermedia AverTV DVB-T */
 	{0x1461, 0x0771}, /* AVermedia DVB-T 771 */
 	{0x1822, 0x0001}, /* Twinhan VisionPlus DVB-T */
+	{0x18ac, 0xd500}, /* DVICO FusionHDTV 5 Lite */
 	{0x18ac, 0xdb10}, /* DVICO FusionHDTV DVB-T Lite */
 	{0x270f, 0xfc00}, /* Chaintech Digitop DST-1000 DVB-S */
+	{0x7063, 0x2000}, /* pcHDTV HD-2000 TV */
 };
 
 static struct pci_driver driver;
@@ -816,13 +821,13 @@
 	for (i = 0; i < ARRAY_SIZE(blacklist); ++i)
 		if (blacklist[i].subvendor == pci->subsystem_vendor &&
 		    blacklist[i].subdevice == pci->subsystem_device) {
-			snd_printdd(KERN_INFO "card %#04x:%#04x has no audio\n",
-				    pci->subsystem_vendor, pci->subsystem_device);
+			snd_printdd(KERN_INFO "card %#04x-%#04x:%#04x has no audio\n",
+				    pci->device, pci->subsystem_vendor, pci->subsystem_device);
 			return -EBUSY;
 		}
 
-	snd_printk(KERN_INFO "unknown card %#04x:%#04x, using default rate 32000\n",
-		   pci->subsystem_vendor, pci->subsystem_device);
+	snd_printk(KERN_INFO "unknown card %#04x-%#04x:%#04x, using default rate 32000\n",
+	           pci->device, pci->subsystem_vendor, pci->subsystem_device);
 	snd_printk(KERN_DEBUG "please mail id, board name, and, "
 		   "if it works, the correct digital_rate option to "
 		   "<alsa-devel@lists.sf.net>\n");
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c
index c03b0a0..2ecbddb 100644
--- a/sound/pci/cmipci.c
+++ b/sound/pci/cmipci.c
@@ -29,6 +29,7 @@
 #include <linux/slab.h>
 #include <linux/gameport.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
@@ -439,7 +440,7 @@
 	struct snd_pcm_hardware *hw_info[3]; /* for playbacks */
 
 	int opened[2];	/* open mode */
-	struct semaphore open_mutex;
+	struct mutex open_mutex;
 
 	unsigned int mixer_insensitive: 1;
 	struct snd_kcontrol *mixer_res_ctl[CM_SAVED_MIXERS];
@@ -641,14 +642,14 @@
 {
 	struct cmipci *cm = snd_pcm_substream_chip(substream);
 	if (params_channels(hw_params) > 2) {
-		down(&cm->open_mutex);
+		mutex_lock(&cm->open_mutex);
 		if (cm->opened[CM_CH_PLAY]) {
-			up(&cm->open_mutex);
+			mutex_unlock(&cm->open_mutex);
 			return -EBUSY;
 		}
 		/* reserve the channel A */
 		cm->opened[CM_CH_PLAY] = CM_OPEN_PLAYBACK_MULTI;
-		up(&cm->open_mutex);
+		mutex_unlock(&cm->open_mutex);
 	}
 	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
 }
@@ -1461,9 +1462,9 @@
 	 * pcm framework doesn't pass file pointer before actually opened,
 	 * we can't know whether blocking mode or not in open callback..
 	 */
-	down(&cm->open_mutex);
+	mutex_lock(&cm->open_mutex);
 	if (cm->opened[ch]) {
-		up(&cm->open_mutex);
+		mutex_unlock(&cm->open_mutex);
 		return -EBUSY;
 	}
 	cm->opened[ch] = mode;
@@ -1475,7 +1476,7 @@
 		snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_ENDBDAC);
 		spin_unlock_irq(&cm->reg_lock);
 	}
-	up(&cm->open_mutex);
+	mutex_unlock(&cm->open_mutex);
 	return 0;
 }
 
@@ -1483,7 +1484,7 @@
 {
 	int ch = mode & CM_OPEN_CH_MASK;
 
-	down(&cm->open_mutex);
+	mutex_lock(&cm->open_mutex);
 	if (cm->opened[ch] == mode) {
 		if (cm->channel[ch].substream) {
 			snd_cmipci_ch_reset(cm, ch);
@@ -1499,7 +1500,7 @@
 			spin_unlock_irq(&cm->reg_lock);
 		}
 	}
-	up(&cm->open_mutex);
+	mutex_unlock(&cm->open_mutex);
 }
 
 /*
@@ -1546,7 +1547,7 @@
 	if ((err = open_device_check(cm, CM_OPEN_PLAYBACK2, substream)) < 0) /* use channel B */
 		return err;
 	runtime->hw = snd_cmipci_playback2;
-	down(&cm->open_mutex);
+	mutex_lock(&cm->open_mutex);
 	if (! cm->opened[CM_CH_PLAY]) {
 		if (cm->can_multi_ch) {
 			runtime->hw.channels_max = cm->max_channels;
@@ -1559,7 +1560,7 @@
 		}
 		snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000);
 	}
-	up(&cm->open_mutex);
+	mutex_unlock(&cm->open_mutex);
 	return 0;
 }
 
@@ -2844,7 +2845,7 @@
 	}
 
 	spin_lock_init(&cm->reg_lock);
-	init_MUTEX(&cm->open_mutex);
+	mutex_init(&cm->open_mutex);
 	cm->device = pci->device;
 	cm->card = card;
 	cm->pci = pci;
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
index 8fb275d..69dbf54 100644
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -53,6 +53,8 @@
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/gameport.h>
+#include <linux/mutex.h>
+
 
 #include <sound/core.h>
 #include <sound/control.h>
@@ -909,22 +911,22 @@
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
 	snd_assert (sample_rate != 0, return -ENXIO);
 
-	down (&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 
 	if (_cs46xx_adjust_sample_rate (chip,cpcm,sample_rate)) {
-		up (&chip->spos_mutex);
+		mutex_unlock(&chip->spos_mutex);
 		return -ENXIO;
 	}
 
 	snd_assert (cpcm->pcm_channel != NULL);
 	if (!cpcm->pcm_channel) {
-		up (&chip->spos_mutex);
+		mutex_unlock(&chip->spos_mutex);
 		return -ENXIO;
 	}
 
 
 	if (cs46xx_dsp_pcm_channel_set_period (chip,cpcm->pcm_channel,period_size)) {
-		 up (&chip->spos_mutex);
+		 mutex_unlock(&chip->spos_mutex);
 		 return -EINVAL;
 	 }
 
@@ -965,7 +967,7 @@
 		}
 		if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) {
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
-			up (&chip->spos_mutex);
+			mutex_unlock(&chip->spos_mutex);
 #endif
 			return err;
 		}
@@ -989,7 +991,7 @@
 	}
 
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
-	up (&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 #endif
 
 	return 0;
@@ -1319,7 +1321,7 @@
 
 	cpcm->substream = substream;
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
-	down (&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	cpcm->pcm_channel = NULL; 
 	cpcm->pcm_channel_id = pcm_channel_id;
 
@@ -1328,7 +1330,7 @@
 				   SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 
 				   &hw_constraints_period_sizes);
 
-	up (&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 #else
 	chip->playback_pcm = cpcm; /* HACK */
 #endif
@@ -1367,9 +1369,9 @@
 
 	snd_printdd("open raw iec958 channel\n");
 
-	down (&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	cs46xx_iec958_pre_open (chip);
-	up (&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	return _cs46xx_playback_open_channel(substream,DSP_IEC958_CHANNEL);
 }
@@ -1385,9 +1387,9 @@
 
 	err = snd_cs46xx_playback_close(substream);
 
-	down (&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	cs46xx_iec958_post_close (chip);
-	up (&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	return err;
 }
@@ -1428,12 +1430,12 @@
 	if (!cpcm) return -ENXIO;
 
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
-	down (&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	if (cpcm->pcm_channel) {
 		cs46xx_dsp_destroy_pcm_channel(chip,cpcm->pcm_channel);
 		cpcm->pcm_channel = NULL;
 	}
-	up (&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 #else
 	chip->playback_pcm = NULL;
 #endif
@@ -1848,7 +1850,7 @@
 
 	switch (kcontrol->private_value) {
 	case CS46XX_MIXER_SPDIF_OUTPUT_ELEMENT:
-		down (&chip->spos_mutex);
+		mutex_lock(&chip->spos_mutex);
 		change = (chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED);
 		if (ucontrol->value.integer.value[0] && !change) 
 			cs46xx_dsp_enable_spdif_out(chip);
@@ -1856,7 +1858,7 @@
 			cs46xx_dsp_disable_spdif_out(chip);
 
 		res = (change != (chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED));
-		up (&chip->spos_mutex);
+		mutex_unlock(&chip->spos_mutex);
 		break;
 	case CS46XX_MIXER_SPDIF_INPUT_ELEMENT:
 		change = chip->dsp_spos_instance->spdif_status_in;
@@ -1997,12 +1999,12 @@
 	struct snd_cs46xx *chip = snd_kcontrol_chip(kcontrol);
 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 
-	down (&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	ucontrol->value.iec958.status[0] = _wrap_all_bits((ins->spdif_csuv_default >> 24) & 0xff);
 	ucontrol->value.iec958.status[1] = _wrap_all_bits((ins->spdif_csuv_default >> 16) & 0xff);
 	ucontrol->value.iec958.status[2] = 0;
 	ucontrol->value.iec958.status[3] = _wrap_all_bits((ins->spdif_csuv_default) & 0xff);
-	up (&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	return 0;
 }
@@ -2015,7 +2017,7 @@
 	unsigned int val;
 	int change;
 
-	down (&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	val = ((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[0]) << 24) |
 		((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[2]) << 16) |
 		((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[3]))  |
@@ -2029,7 +2031,7 @@
 	if ( !(ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) )
 		cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV,val);
 
-	up (&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	return change;
 }
@@ -2050,12 +2052,12 @@
 	struct snd_cs46xx *chip = snd_kcontrol_chip(kcontrol);
 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 
-	down (&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	ucontrol->value.iec958.status[0] = _wrap_all_bits((ins->spdif_csuv_stream >> 24) & 0xff);
 	ucontrol->value.iec958.status[1] = _wrap_all_bits((ins->spdif_csuv_stream >> 16) & 0xff);
 	ucontrol->value.iec958.status[2] = 0;
 	ucontrol->value.iec958.status[3] = _wrap_all_bits((ins->spdif_csuv_stream) & 0xff);
-	up (&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	return 0;
 }
@@ -2068,7 +2070,7 @@
 	unsigned int val;
 	int change;
 
-	down (&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	val = ((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[0]) << 24) |
 		((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[1]) << 16) |
 		((unsigned int)_wrap_all_bits(ucontrol->value.iec958.status[3])) |
@@ -2082,7 +2084,7 @@
 	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN )
 		cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV,val);
 
-	up (&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	return change;
 }
@@ -3755,7 +3757,7 @@
 	}
 	spin_lock_init(&chip->reg_lock);
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
-	init_MUTEX(&chip->spos_mutex);
+	mutex_init(&chip->spos_mutex);
 #endif
 	chip->card = card;
 	chip->pci = pci;
diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c
index 445a448..f407d2a 100644
--- a/sound/pci/cs46xx/dsp_spos.c
+++ b/sound/pci/cs46xx/dsp_spos.c
@@ -28,6 +28,8 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/info.h>
@@ -235,7 +237,7 @@
 
 	if (ins->symbol_table.symbols == NULL) {
 		cs46xx_dsp_spos_destroy(chip);
-		return NULL;
+		goto error;
 	}
 
 	ins->code.offset = 0;
@@ -244,7 +246,7 @@
 
 	if (ins->code.data == NULL) {
 		cs46xx_dsp_spos_destroy(chip);
-		return NULL;
+		goto error;
 	}
 
 	ins->nscb = 0;
@@ -255,7 +257,7 @@
 
 	if (ins->modules == NULL) {
 		cs46xx_dsp_spos_destroy(chip);
-		return NULL;
+		goto error;
 	}
 
 	/* default SPDIF input sample rate
@@ -278,6 +280,10 @@
 	 /* left and right validity bits */ (1 << 13) | (1 << 12);
 
 	return ins;
+
+error:
+	kfree(ins);
+	return NULL;
 }
 
 void  cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip)
@@ -287,7 +293,7 @@
 
 	snd_assert(ins != NULL, return);
 
-	down(&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	for (i = 0; i < ins->nscb; ++i) {
 		if (ins->scbs[i].deleted) continue;
 
@@ -298,7 +304,7 @@
 	vfree(ins->symbol_table.symbols);
 	kfree(ins->modules);
 	kfree(ins);
-	up(&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 }
 
 int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * module)
@@ -497,7 +503,7 @@
 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 	int i,j;
 
-	down(&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	snd_iprintf(buffer, "MODULES:\n");
 	for ( i = 0; i < ins->nmodules; ++i ) {
 		snd_iprintf(buffer, "\n%s:\n", ins->modules[i].module_name);
@@ -510,7 +516,7 @@
 				    desc->segment_type,desc->offset, desc->size);
 		}
 	}
-	up(&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 }
 
 static void cs46xx_dsp_proc_task_tree_read (struct snd_info_entry *entry,
@@ -521,7 +527,7 @@
 	int i, j, col;
 	void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
 
-	down(&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	snd_iprintf(buffer, "TASK TREES:\n");
 	for ( i = 0; i < ins->ntask; ++i) {
 		snd_iprintf(buffer,"\n%04x %s:\n",ins->tasks[i].address,ins->tasks[i].task_name);
@@ -538,7 +544,7 @@
 	}
 
 	snd_iprintf(buffer,"\n");  
-	up(&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 }
 
 static void cs46xx_dsp_proc_scb_read (struct snd_info_entry *entry,
@@ -548,7 +554,7 @@
 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 	int i;
 
-	down(&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	snd_iprintf(buffer, "SCB's:\n");
 	for ( i = 0; i < ins->nscb; ++i) {
 		if (ins->scbs[i].deleted)
@@ -571,7 +577,7 @@
 	}
 
 	snd_iprintf(buffer,"\n");
-	up(&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 }
 
 static void cs46xx_dsp_proc_parameter_dump_read (struct snd_info_entry *entry,
@@ -852,14 +858,14 @@
 	}
 	ins->proc_scb_info_entry = entry;
 
-	down(&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	/* register/update SCB's entries on proc */
 	for (i = 0; i < ins->nscb; ++i) {
 		if (ins->scbs[i].deleted) continue;
 
 		cs46xx_dsp_proc_register_scb_desc (chip, (ins->scbs + i));
 	}
-	up(&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	return 0;
 }
@@ -899,12 +905,12 @@
 		ins->proc_task_info_entry = NULL;
 	}
 
-	down(&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	for (i = 0; i < ins->nscb; ++i) {
 		if (ins->scbs[i].deleted) continue;
 		cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) );
 	}
-	up(&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	if (ins->proc_dsp_dir) {
 		snd_info_unregister (ins->proc_dsp_dir);
@@ -1694,7 +1700,7 @@
 	snd_assert (ins->asynch_rx_scb == NULL,return -EINVAL);
 	snd_assert (ins->spdif_in_src != NULL,return -EINVAL);
 
-	down(&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 
 	if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_INPUT_CTRL_ENABLED) ) {
 		/* time countdown enable */
@@ -1738,7 +1744,7 @@
 
 	/* monitor state */
 	ins->spdif_status_in = 1;
-	up(&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	return 0;
 }
@@ -1750,7 +1756,7 @@
 	snd_assert (ins->asynch_rx_scb != NULL, return -EINVAL);
 	snd_assert (ins->spdif_in_src != NULL,return -EINVAL);	
 
-	down(&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 
 	/* Remove the asynchronous receiver SCB */
 	cs46xx_dsp_remove_scb (chip,ins->asynch_rx_scb);
@@ -1760,7 +1766,7 @@
 
 	/* monitor state */
 	ins->spdif_status_in = 0;
-	up(&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	/* restore amplifier */
 	chip->active_ctrl(chip, -1);
@@ -1776,10 +1782,10 @@
 	snd_assert (ins->pcm_input == NULL,return -EINVAL);
 	snd_assert (ins->ref_snoop_scb != NULL,return -EINVAL);
 
-	down(&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	ins->pcm_input = cs46xx_add_record_source(chip,ins->ref_snoop_scb,PCMSERIALIN_PCM_SCB_ADDR,
                                                   "PCMSerialInput_Wave");
-	up(&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	return 0;
 }
@@ -1790,10 +1796,10 @@
 
 	snd_assert (ins->pcm_input != NULL,return -EINVAL);
 
-	down(&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	cs46xx_dsp_remove_scb (chip,ins->pcm_input);
 	ins->pcm_input = NULL;
-	up(&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	return 0;
 }
@@ -1805,10 +1811,10 @@
 	snd_assert (ins->adc_input == NULL,return -EINVAL);
 	snd_assert (ins->codec_in_scb != NULL,return -EINVAL);
 
-	down(&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	ins->adc_input = cs46xx_add_record_source(chip,ins->codec_in_scb,PCMSERIALIN_SCB_ADDR,
 						  "PCMSerialInput_ADC");
-	up(&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	return 0;
 }
@@ -1819,10 +1825,10 @@
 
 	snd_assert (ins->adc_input != NULL,return -EINVAL);
 
-	down(&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	cs46xx_dsp_remove_scb (chip,ins->adc_input);
 	ins->adc_input = NULL;
-	up(&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	return 0;
 }
@@ -1869,7 +1875,7 @@
 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 	struct dsp_scb_descriptor * scb; 
 
-	down(&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	
 	/* main output */
 	scb = ins->master_mix_scb->sub_list_ptr;
@@ -1888,7 +1894,7 @@
 	ins->dac_volume_left = left;
 	ins->dac_volume_right = right;
 
-	up(&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	return 0;
 }
@@ -1897,7 +1903,7 @@
 {
 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 
-	down(&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 
 	if (ins->asynch_rx_scb != NULL)
 		cs46xx_dsp_scb_set_volume (chip,ins->asynch_rx_scb,
@@ -1906,7 +1912,7 @@
 	ins->spdif_input_volume_left = left;
 	ins->spdif_input_volume_right = right;
 
-	up(&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 
 	return 0;
 }
diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c
index d4e0fb3..2c4ee45 100644
--- a/sound/pci/cs46xx/dsp_spos_scb_lib.c
+++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c
@@ -28,6 +28,8 @@
 #include <linux/pm.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/info.h>
@@ -77,7 +79,7 @@
 
 	ins = chip->dsp_spos_instance;
 
-	down(&chip->spos_mutex);
+	mutex_lock(&chip->spos_mutex);
 	snd_iprintf(buffer,"%04x %s:\n",scb->address,scb->scb_name);
 
 	for (col = 0,j = 0;j < 0x10; j++,col++) {
@@ -105,7 +107,7 @@
 		    scb->task_entry->address);
 
 	snd_iprintf(buffer,"index [%d] ref_count [%d]\n",scb->index,scb->ref_count);  
-	up(&chip->spos_mutex);
+	mutex_unlock(&chip->spos_mutex);
 }
 #endif
 
diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c
index 02e3721..9fc7f38 100644
--- a/sound/pci/cs5535audio/cs5535audio.c
+++ b/sound/pci/cs5535audio/cs5535audio.c
@@ -62,7 +62,7 @@
 		tmp = cs_readl(cs5535au, ACC_CODEC_CNTL);
 		if (!(tmp & CMD_NEW))
 			break;
-		msleep(10);
+		udelay(1);
 	} while (--timeout);
 	if (!timeout)
 		snd_printk(KERN_ERR "Failure writing to cs5535 codec\n");
@@ -80,14 +80,14 @@
 	regdata |= CMD_NEW;
 
 	cs_writel(cs5535au, ACC_CODEC_CNTL, regdata);
-	wait_till_cmd_acked(cs5535au, 500);
+	wait_till_cmd_acked(cs5535au, 50);
 
 	timeout = 50;
 	do {
 		val = cs_readl(cs5535au, ACC_CODEC_STATUS);
 		if ((val & STS_NEW) && reg == (val >> 24))
 			break;
-		msleep(10);
+		udelay(1);
 	} while (--timeout);
 	if (!timeout)
 		snd_printk(KERN_ERR "Failure reading cs5535 codec\n");
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index 3c7043b..31cb9b4 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -36,6 +36,8 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <linux/mutex.h>
+
 
 #include <sound/core.h>
 #include <sound/emu10k1.h>
@@ -775,6 +777,14 @@
 
 static struct snd_emu_chip_details emu_chip_details[] = {
 	/* Audigy 2 Value AC3 out does not work yet. Need to find out how to turn off interpolators.*/
+	/* Audigy4 SB0400 */
+	{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10211102,
+	 .driver = "Audigy2", .name = "Audigy 4 [SB0400]", 
+	 .id = "Audigy2",
+	 .emu10k2_chip = 1,
+	 .ca0108_chip = 1,
+	 .spk71 = 1,
+	 .ac97_chip = 1} ,
 	/* Tested by James@superbug.co.uk 3rd July 2005 */
 	/* DSP: CA0108-IAT
 	 * DAC: CS4382-KQ
@@ -1097,8 +1107,7 @@
 	spin_lock_init(&emu->voice_lock);
 	spin_lock_init(&emu->synth_lock);
 	spin_lock_init(&emu->memblk_lock);
-	init_MUTEX(&emu->ptb_lock);
-	init_MUTEX(&emu->fx8010.lock);
+	mutex_init(&emu->fx8010.lock);
 	INIT_LIST_HEAD(&emu->mapped_link_head);
 	INIT_LIST_HEAD(&emu->mapped_order_link_head);
 	emu->pci = pci;
diff --git a/sound/pci/emu10k1/emu10k1_synth.c b/sound/pci/emu10k1/emu10k1_synth.c
index 1fa393f..204995a 100644
--- a/sound/pci/emu10k1/emu10k1_synth.c
+++ b/sound/pci/emu10k1/emu10k1_synth.c
@@ -62,7 +62,6 @@
 
 	if (snd_emux_register(emu, dev->card, arg->index, "Emu10k1") < 0) {
 		snd_emux_free(emu);
-		emu->hw = NULL;
 		return -ENOMEM;
 	}
 
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index 1107c8e..2208dbd 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -33,6 +33,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/slab.h>
 #include <linux/moduleparam.h>
 #include <sound/core.h>
@@ -893,24 +894,24 @@
 	static struct snd_device_ops ops = {
 		.dev_free = snd_emu10k1x_dev_free,
 	};
-  
+
 	*rchip = NULL;
-  
+
 	if ((err = pci_enable_device(pci)) < 0)
 		return err;
-	if (pci_set_dma_mask(pci, 0x0fffffff) < 0 ||
-	    pci_set_consistent_dma_mask(pci, 0x0fffffff) < 0) {
+	if (pci_set_dma_mask(pci, DMA_28BIT_MASK) < 0 ||
+	    pci_set_consistent_dma_mask(pci, DMA_28BIT_MASK) < 0) {
 		snd_printk(KERN_ERR "error to set 28bit mask DMA\n");
 		pci_disable_device(pci);
 		return -ENXIO;
 	}
-  
+
 	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
 	if (chip == NULL) {
 		pci_disable_device(pci);
 		return -ENOMEM;
 	}
-  
+
 	chip->card = card;
 	chip->pci = pci;
 	chip->irq = -1;
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index 5098372..dfba002 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -32,6 +32,8 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/init.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/emu10k1.h>
 
@@ -874,7 +876,7 @@
 {
 	int err = 0;
 
-	down(&emu->fx8010.lock);
+	mutex_lock(&emu->fx8010.lock);
 	if ((err = snd_emu10k1_verify_controls(emu, icode)) < 0)
 		goto __error;
 	strlcpy(emu->fx8010.name, icode->name, sizeof(emu->fx8010.name));
@@ -897,7 +899,7 @@
 	else
 		snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
       __error:
-	up(&emu->fx8010.lock);
+	mutex_unlock(&emu->fx8010.lock);
 	return err;
 }
 
@@ -906,7 +908,7 @@
 {
 	int err;
 
-	down(&emu->fx8010.lock);
+	mutex_lock(&emu->fx8010.lock);
 	strlcpy(icode->name, emu->fx8010.name, sizeof(icode->name));
 	/* ok, do the main job */
 	err = snd_emu10k1_gpr_peek(emu, icode);
@@ -916,7 +918,7 @@
 		err = snd_emu10k1_code_peek(emu, icode);
 	if (err >= 0)
 		err = snd_emu10k1_list_controls(emu, icode);
-	up(&emu->fx8010.lock);
+	mutex_unlock(&emu->fx8010.lock);
 	return err;
 }
 
@@ -932,7 +934,7 @@
 	if (ipcm->channels > 32)
 		return -EINVAL;
 	pcm = &emu->fx8010.pcm[ipcm->substream];
-	down(&emu->fx8010.lock);
+	mutex_lock(&emu->fx8010.lock);
 	spin_lock_irq(&emu->reg_lock);
 	if (pcm->opened) {
 		err = -EBUSY;
@@ -962,7 +964,7 @@
 	}
       __error:
 	spin_unlock_irq(&emu->reg_lock);
-	up(&emu->fx8010.lock);
+	mutex_unlock(&emu->fx8010.lock);
 	return err;
 }
 
@@ -976,7 +978,7 @@
 	if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
 		return -EINVAL;
 	pcm = &emu->fx8010.pcm[ipcm->substream];
-	down(&emu->fx8010.lock);
+	mutex_lock(&emu->fx8010.lock);
 	spin_lock_irq(&emu->reg_lock);
 	ipcm->channels = pcm->channels;
 	ipcm->tram_start = pcm->tram_start;
@@ -992,7 +994,7 @@
 	ipcm->res1 = ipcm->res2 = 0;
 	ipcm->pad = 0;
 	spin_unlock_irq(&emu->reg_lock);
-	up(&emu->fx8010.lock);
+	mutex_unlock(&emu->fx8010.lock);
 	return err;
 }
 
@@ -2308,9 +2310,9 @@
 			return -EPERM;
 		if (get_user(addr, (unsigned int __user *)argp))
 			return -EFAULT;
-		down(&emu->fx8010.lock);
+		mutex_lock(&emu->fx8010.lock);
 		res = snd_emu10k1_fx8010_tram_setup(emu, addr);
-		up(&emu->fx8010.lock);
+		mutex_unlock(&emu->fx8010.lock);
 		return res;
 	case SNDRV_EMU10K1_IOCTL_STOP:
 		if (!capable(CAP_SYS_ADMIN))
diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c
index 68c795c..e7ec986 100644
--- a/sound/pci/emu10k1/memory.c
+++ b/sound/pci/emu10k1/memory.c
@@ -24,6 +24,8 @@
 #include <sound/driver.h>
 #include <linux/pci.h>
 #include <linux/time.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/emu10k1.h>
 
@@ -302,10 +304,10 @@
 	hdr = emu->memhdr;
 	snd_assert(hdr, return NULL);
 
-	down(&hdr->block_mutex);
+	mutex_lock(&hdr->block_mutex);
 	blk = search_empty(emu, runtime->dma_bytes);
 	if (blk == NULL) {
-		up(&hdr->block_mutex);
+		mutex_unlock(&hdr->block_mutex);
 		return NULL;
 	}
 	/* fill buffer addresses but pointers are not stored so that
@@ -318,14 +320,14 @@
 		if (idx >= sgbuf->pages) {
 			printk(KERN_ERR "emu: pages overflow! (%d-%d) for %d\n",
 			       blk->first_page, blk->last_page, sgbuf->pages);
-			up(&hdr->block_mutex);
+			mutex_unlock(&hdr->block_mutex);
 			return NULL;
 		}
 #endif
 		addr = sgbuf->table[idx].addr;
 		if (! is_valid_page(emu, addr)) {
 			printk(KERN_ERR "emu: failure page = %d\n", idx);
-			up(&hdr->block_mutex);
+			mutex_unlock(&hdr->block_mutex);
 			return NULL;
 		}
 		emu->page_addr_table[page] = addr;
@@ -337,10 +339,10 @@
 	err = snd_emu10k1_memblk_map(emu, blk);
 	if (err < 0) {
 		__snd_util_mem_free(hdr, (struct snd_util_memblk *)blk);
-		up(&hdr->block_mutex);
+		mutex_unlock(&hdr->block_mutex);
 		return NULL;
 	}
-	up(&hdr->block_mutex);
+	mutex_unlock(&hdr->block_mutex);
 	return (struct snd_util_memblk *)blk;
 }
 
@@ -369,19 +371,19 @@
 	struct snd_emu10k1_memblk *blk;
 	struct snd_util_memhdr *hdr = hw->memhdr; 
 
-	down(&hdr->block_mutex);
+	mutex_lock(&hdr->block_mutex);
 	blk = (struct snd_emu10k1_memblk *)__snd_util_mem_alloc(hdr, size);
 	if (blk == NULL) {
-		up(&hdr->block_mutex);
+		mutex_unlock(&hdr->block_mutex);
 		return NULL;
 	}
 	if (synth_alloc_pages(hw, blk)) {
 		__snd_util_mem_free(hdr, (struct snd_util_memblk *)blk);
-		up(&hdr->block_mutex);
+		mutex_unlock(&hdr->block_mutex);
 		return NULL;
 	}
 	snd_emu10k1_memblk_map(hw, blk);
-	up(&hdr->block_mutex);
+	mutex_unlock(&hdr->block_mutex);
 	return (struct snd_util_memblk *)blk;
 }
 
@@ -396,14 +398,14 @@
 	struct snd_emu10k1_memblk *blk = (struct snd_emu10k1_memblk *)memblk;
 	unsigned long flags;
 
-	down(&hdr->block_mutex);
+	mutex_lock(&hdr->block_mutex);
 	spin_lock_irqsave(&emu->memblk_lock, flags);
 	if (blk->mapped_page >= 0)
 		unmap_memblk(emu, blk);
 	spin_unlock_irqrestore(&emu->memblk_lock, flags);
 	synth_free_pages(emu, blk);
 	 __snd_util_mem_free(hdr, memblk);
-	up(&hdr->block_mutex);
+	mutex_unlock(&hdr->block_mutex);
 	return 0;
 }
 
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index 55aaf11..a5533c8 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -35,6 +35,8 @@
 #include <linux/slab.h>
 #include <linux/gameport.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
@@ -379,7 +381,7 @@
 
 struct ensoniq {
 	spinlock_t reg_lock;
-	struct semaphore src_mutex;
+	struct mutex src_mutex;
 
 	int irq;
 
@@ -609,7 +611,7 @@
 	struct ensoniq *ensoniq = ac97->private_data;
 	unsigned int t, x;
 
-	down(&ensoniq->src_mutex);
+	mutex_lock(&ensoniq->src_mutex);
 	for (t = 0; t < POLL_COUNT; t++) {
 		if (!(inl(ES_REG(ensoniq, 1371_CODEC)) & ES_1371_CODEC_WIP)) {
 			/* save the current state for latter */
@@ -634,11 +636,11 @@
 			/* restore SRC reg */
 			snd_es1371_wait_src_ready(ensoniq);
 			outl(x, ES_REG(ensoniq, 1371_SMPRATE));
-			up(&ensoniq->src_mutex);
+			mutex_unlock(&ensoniq->src_mutex);
 			return;
 		}
 	}
-	up(&ensoniq->src_mutex);
+	mutex_unlock(&ensoniq->src_mutex);
 	snd_printk(KERN_ERR "codec write timeout at 0x%lx [0x%x]\n",
 		   ES_REG(ensoniq, 1371_CODEC), inl(ES_REG(ensoniq, 1371_CODEC)));
 }
@@ -650,7 +652,7 @@
 	unsigned int t, x, fail = 0;
 
       __again:
-	down(&ensoniq->src_mutex);
+	mutex_lock(&ensoniq->src_mutex);
 	for (t = 0; t < POLL_COUNT; t++) {
 		if (!(inl(ES_REG(ensoniq, 1371_CODEC)) & ES_1371_CODEC_WIP)) {
 			/* save the current state for latter */
@@ -683,11 +685,11 @@
 			/* now wait for the stinkin' data (RDY) */
 			for (t = 0; t < POLL_COUNT; t++) {
 				if ((x = inl(ES_REG(ensoniq, 1371_CODEC))) & ES_1371_CODEC_RDY) {
-					up(&ensoniq->src_mutex);
+					mutex_unlock(&ensoniq->src_mutex);
 					return ES_1371_CODEC_READ(x);
 				}
 			}
-			up(&ensoniq->src_mutex);
+			mutex_unlock(&ensoniq->src_mutex);
 			if (++fail > 10) {
 				snd_printk(KERN_ERR "codec read timeout (final) "
 					   "at 0x%lx, reg = 0x%x [0x%x]\n",
@@ -698,7 +700,7 @@
 			goto __again;
 		}
 	}
-	up(&ensoniq->src_mutex);
+	mutex_unlock(&ensoniq->src_mutex);
 	snd_printk(KERN_ERR "es1371: codec read timeout at 0x%lx [0x%x]\n",
 		   ES_REG(ensoniq, 1371_CODEC), inl(ES_REG(ensoniq, 1371_CODEC)));
 	return 0;
@@ -717,7 +719,7 @@
 {
 	unsigned int n, truncm, freq, result;
 
-	down(&ensoniq->src_mutex);
+	mutex_lock(&ensoniq->src_mutex);
 	n = rate / 3000;
 	if ((1 << n) & ((1 << 15) | (1 << 13) | (1 << 11) | (1 << 9)))
 		n--;
@@ -742,14 +744,14 @@
 	snd_es1371_src_write(ensoniq, ES_SMPREG_ADC + ES_SMPREG_VFREQ_FRAC, freq & 0x7fff);
 	snd_es1371_src_write(ensoniq, ES_SMPREG_VOL_ADC, n << 8);
 	snd_es1371_src_write(ensoniq, ES_SMPREG_VOL_ADC + 1, n << 8);
-	up(&ensoniq->src_mutex);
+	mutex_unlock(&ensoniq->src_mutex);
 }
 
 static void snd_es1371_dac1_rate(struct ensoniq * ensoniq, unsigned int rate)
 {
 	unsigned int freq, r;
 
-	down(&ensoniq->src_mutex);
+	mutex_lock(&ensoniq->src_mutex);
 	freq = ((rate << 15) + 1500) / 3000;
 	r = (snd_es1371_wait_src_ready(ensoniq) & (ES_1371_SRC_DISABLE |
 						   ES_1371_DIS_P2 | ES_1371_DIS_R1)) |
@@ -763,14 +765,14 @@
 	r = (snd_es1371_wait_src_ready(ensoniq) & (ES_1371_SRC_DISABLE |
 						   ES_1371_DIS_P2 | ES_1371_DIS_R1));
 	outl(r, ES_REG(ensoniq, 1371_SMPRATE));
-	up(&ensoniq->src_mutex);
+	mutex_unlock(&ensoniq->src_mutex);
 }
 
 static void snd_es1371_dac2_rate(struct ensoniq * ensoniq, unsigned int rate)
 {
 	unsigned int freq, r;
 
-	down(&ensoniq->src_mutex);
+	mutex_lock(&ensoniq->src_mutex);
 	freq = ((rate << 15) + 1500) / 3000;
 	r = (snd_es1371_wait_src_ready(ensoniq) & (ES_1371_SRC_DISABLE |
 						   ES_1371_DIS_P1 | ES_1371_DIS_R1)) |
@@ -785,7 +787,7 @@
 	r = (snd_es1371_wait_src_ready(ensoniq) & (ES_1371_SRC_DISABLE |
 						   ES_1371_DIS_P1 | ES_1371_DIS_R1));
 	outl(r, ES_REG(ensoniq, 1371_SMPRATE));
-	up(&ensoniq->src_mutex);
+	mutex_unlock(&ensoniq->src_mutex);
 }
 
 #endif /* CHIP1371 */
@@ -2061,6 +2063,13 @@
 #ifdef CHIP1371	
 	snd_ac97_suspend(ensoniq->u.es1371.ac97);
 #else
+	/* try to reset AK4531 */
+	outw(ES_1370_CODEC_WRITE(AK4531_RESET, 0x02), ES_REG(ensoniq, 1370_CODEC));
+	inw(ES_REG(ensoniq, 1370_CODEC));
+	udelay(100);
+	outw(ES_1370_CODEC_WRITE(AK4531_RESET, 0x03), ES_REG(ensoniq, 1370_CODEC));
+	inw(ES_REG(ensoniq, 1370_CODEC));
+	udelay(100);
 	snd_ak4531_suspend(ensoniq->u.es1370.ak4531);
 #endif	
 	pci_set_power_state(pci, PCI_D3hot);
@@ -2116,7 +2125,7 @@
 		return -ENOMEM;
 	}
 	spin_lock_init(&ensoniq->reg_lock);
-	init_MUTEX(&ensoniq->src_mutex);
+	mutex_init(&ensoniq->src_mutex);
 	ensoniq->card = card;
 	ensoniq->pci = pci;
 	ensoniq->irq = -1;
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index 3747a43..dd465a1 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -100,9 +100,12 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/slab.h>
 #include <linux/gameport.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/mpu401.h>
@@ -569,7 +572,7 @@
 	u16 maestro_map[32];
 	int bobclient;		/* active timer instancs */
 	int bob_freq;		/* timer frequency */
-	struct semaphore memory_mutex;	/* memory lock */
+	struct mutex memory_mutex;	/* memory lock */
 
 	/* APU states */
 	unsigned char apu[NR_APUS];
@@ -1356,13 +1359,13 @@
 	struct list_head *p;
 	int max_size = 0;
 	
-	down(&chip->memory_mutex);
+	mutex_lock(&chip->memory_mutex);
 	list_for_each(p, &chip->buf_list) {
 		struct esm_memory *buf = list_entry(p, struct esm_memory, list);
 		if (buf->empty && buf->buf.bytes > max_size)
 			max_size = buf->buf.bytes;
 	}
-	up(&chip->memory_mutex);
+	mutex_unlock(&chip->memory_mutex);
 	if (max_size >= 128*1024)
 		max_size = 127*1024;
 	return max_size;
@@ -1375,20 +1378,20 @@
 	struct list_head *p;
 	
 	size = ((size + ESM_MEM_ALIGN - 1) / ESM_MEM_ALIGN) * ESM_MEM_ALIGN;
-	down(&chip->memory_mutex);
+	mutex_lock(&chip->memory_mutex);
 	list_for_each(p, &chip->buf_list) {
 		buf = list_entry(p, struct esm_memory, list);
 		if (buf->empty && buf->buf.bytes >= size)
 			goto __found;
 	}
-	up(&chip->memory_mutex);
+	mutex_unlock(&chip->memory_mutex);
 	return NULL;
 
 __found:
 	if (buf->buf.bytes > size) {
 		struct esm_memory *chunk = kmalloc(sizeof(*chunk), GFP_KERNEL);
 		if (chunk == NULL) {
-			up(&chip->memory_mutex);
+			mutex_unlock(&chip->memory_mutex);
 			return NULL;
 		}
 		chunk->buf = buf->buf;
@@ -1400,7 +1403,7 @@
 		list_add(&chunk->list, &buf->list);
 	}
 	buf->empty = 0;
-	up(&chip->memory_mutex);
+	mutex_unlock(&chip->memory_mutex);
 	return buf;
 }
 
@@ -1409,7 +1412,7 @@
 {
 	struct esm_memory *chunk;
 
-	down(&chip->memory_mutex);
+	mutex_lock(&chip->memory_mutex);
 	buf->empty = 1;
 	if (buf->list.prev != &chip->buf_list) {
 		chunk = list_entry(buf->list.prev, struct esm_memory, list);
@@ -1428,7 +1431,7 @@
 			kfree(chunk);
 		}
 	}
-	up(&chip->memory_mutex);
+	mutex_unlock(&chip->memory_mutex);
 }
 
 static void snd_es1968_free_dmabuf(struct es1968 *chip)
@@ -2559,8 +2562,8 @@
 	if ((err = pci_enable_device(pci)) < 0)
 		return err;
 	/* check, if we can restrict PCI DMA transfers to 28 bits */
-	if (pci_set_dma_mask(pci, 0x0fffffff) < 0 ||
-	    pci_set_consistent_dma_mask(pci, 0x0fffffff) < 0) {
+	if (pci_set_dma_mask(pci, DMA_28BIT_MASK) < 0 ||
+	    pci_set_consistent_dma_mask(pci, DMA_28BIT_MASK) < 0) {
 		snd_printk(KERN_ERR "architecture does not support 28bit PCI busmaster DMA\n");
 		pci_disable_device(pci);
 		return -ENXIO;
@@ -2579,7 +2582,7 @@
 	INIT_LIST_HEAD(&chip->buf_list);
 	INIT_LIST_HEAD(&chip->substream_list);
 	spin_lock_init(&chip->ac97_lock);
-	init_MUTEX(&chip->memory_mutex);
+	mutex_init(&chip->memory_mutex);
 	tasklet_init(&chip->hwvol_tq, es1968_update_hw_volume, (unsigned long)chip);
 	chip->card = card;
 	chip->pci = pci;
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 4a6dd97..b42dff7 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -25,6 +25,7 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include "hda_codec.h"
 #include <sound/asoundef.h>
@@ -76,12 +77,12 @@
 				unsigned int verb, unsigned int parm)
 {
 	unsigned int res;
-	down(&codec->bus->cmd_mutex);
+	mutex_lock(&codec->bus->cmd_mutex);
 	if (! codec->bus->ops.command(codec, nid, direct, verb, parm))
 		res = codec->bus->ops.get_response(codec);
 	else
 		res = (unsigned int)-1;
-	up(&codec->bus->cmd_mutex);
+	mutex_unlock(&codec->bus->cmd_mutex);
 	return res;
 }
 
@@ -101,9 +102,9 @@
 			 unsigned int verb, unsigned int parm)
 {
 	int err;
-	down(&codec->bus->cmd_mutex);
+	mutex_lock(&codec->bus->cmd_mutex);
 	err = codec->bus->ops.command(codec, nid, direct, verb, parm);
-	up(&codec->bus->cmd_mutex);
+	mutex_unlock(&codec->bus->cmd_mutex);
 	return err;
 }
 
@@ -371,7 +372,7 @@
 	bus->modelname = temp->modelname;
 	bus->ops = temp->ops;
 
-	init_MUTEX(&bus->cmd_mutex);
+	mutex_init(&bus->cmd_mutex);
 	INIT_LIST_HEAD(&bus->codec_list);
 
 	if ((err = snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops)) < 0) {
@@ -523,13 +524,19 @@
 
 	codec->bus = bus;
 	codec->addr = codec_addr;
-	init_MUTEX(&codec->spdif_mutex);
+	mutex_init(&codec->spdif_mutex);
 	init_amp_hash(codec);
 
 	list_add_tail(&codec->list, &bus->codec_list);
 	bus->caddr_tbl[codec_addr] = codec;
 
 	codec->vendor_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_VENDOR_ID);
+	if (codec->vendor_id == -1)
+		/* read again, hopefully the access method was corrected
+		 * in the last read...
+		 */
+		codec->vendor_id = snd_hda_param_read(codec, AC_NODE_ROOT,
+						      AC_PAR_VENDOR_ID);
 	codec->subsystem_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_SUBSYSTEM_ID);
 	codec->revision_id = snd_hda_param_read(codec, AC_NODE_ROOT, AC_PAR_REV_ID);
 
@@ -722,7 +729,8 @@
 /*
  * read AMP value.  The volume is between 0 to 0x7f, 0x80 = mute bit.
  */
-static int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int index)
+int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch,
+			   int direction, int index)
 {
 	struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, index));
 	if (! info)
@@ -733,7 +741,8 @@
 /*
  * update the AMP value, mask = bit mask to set, val = the value
  */
-static int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int mask, int val)
+int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
+			     int direction, int idx, int mask, int val)
 {
 	struct hda_amp_info *info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, idx));
 
@@ -881,12 +890,12 @@
 	unsigned long pval;
 	int err;
 
-	down(&codec->spdif_mutex); /* reuse spdif_mutex */
+	mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
 	pval = kcontrol->private_value;
 	kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */
 	err = snd_hda_mixer_amp_switch_get(kcontrol, ucontrol);
 	kcontrol->private_value = pval;
-	up(&codec->spdif_mutex);
+	mutex_unlock(&codec->spdif_mutex);
 	return err;
 }
 
@@ -896,7 +905,7 @@
 	unsigned long pval;
 	int i, indices, err = 0, change = 0;
 
-	down(&codec->spdif_mutex); /* reuse spdif_mutex */
+	mutex_lock(&codec->spdif_mutex); /* reuse spdif_mutex */
 	pval = kcontrol->private_value;
 	indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT;
 	for (i = 0; i < indices; i++) {
@@ -907,7 +916,7 @@
 		change |= err;
 	}
 	kcontrol->private_value = pval;
-	up(&codec->spdif_mutex);
+	mutex_unlock(&codec->spdif_mutex);
 	return err < 0 ? err : change;
 }
 
@@ -1011,7 +1020,7 @@
 	unsigned short val;
 	int change;
 
-	down(&codec->spdif_mutex);
+	mutex_lock(&codec->spdif_mutex);
 	codec->spdif_status = ucontrol->value.iec958.status[0] |
 		((unsigned int)ucontrol->value.iec958.status[1] << 8) |
 		((unsigned int)ucontrol->value.iec958.status[2] << 16) |
@@ -1026,7 +1035,7 @@
 		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_2, val >> 8);
 	}
 
-	up(&codec->spdif_mutex);
+	mutex_unlock(&codec->spdif_mutex);
 	return change;
 }
 
@@ -1054,7 +1063,7 @@
 	unsigned short val;
 	int change;
 
-	down(&codec->spdif_mutex);
+	mutex_lock(&codec->spdif_mutex);
 	val = codec->spdif_ctls & ~1;
 	if (ucontrol->value.integer.value[0])
 		val |= 1;
@@ -1066,7 +1075,7 @@
 				    AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT |
 				    AC_AMP_SET_OUTPUT | ((val & 1) ? 0 : 0x80));
 	}
-	up(&codec->spdif_mutex);
+	mutex_unlock(&codec->spdif_mutex);
 	return change;
 }
 
@@ -1150,13 +1159,13 @@
 	unsigned int val = !!ucontrol->value.integer.value[0];
 	int change;
 
-	down(&codec->spdif_mutex);
+	mutex_lock(&codec->spdif_mutex);
 	change = codec->spdif_in_enable != val;
 	if (change || codec->in_resume) {
 		codec->spdif_in_enable = val;
 		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, val);
 	}
-	up(&codec->spdif_mutex);
+	mutex_unlock(&codec->spdif_mutex);
 	return change;
 }
 
@@ -1824,13 +1833,13 @@
  */
 int snd_hda_multi_out_dig_open(struct hda_codec *codec, struct hda_multi_out *mout)
 {
-	down(&codec->spdif_mutex);
+	mutex_lock(&codec->spdif_mutex);
 	if (mout->dig_out_used) {
-		up(&codec->spdif_mutex);
+		mutex_unlock(&codec->spdif_mutex);
 		return -EBUSY; /* already being used */
 	}
 	mout->dig_out_used = HDA_DIG_EXCLUSIVE;
-	up(&codec->spdif_mutex);
+	mutex_unlock(&codec->spdif_mutex);
 	return 0;
 }
 
@@ -1839,9 +1848,9 @@
  */
 int snd_hda_multi_out_dig_close(struct hda_codec *codec, struct hda_multi_out *mout)
 {
-	down(&codec->spdif_mutex);
+	mutex_lock(&codec->spdif_mutex);
 	mout->dig_out_used = 0;
-	up(&codec->spdif_mutex);
+	mutex_unlock(&codec->spdif_mutex);
 	return 0;
 }
 
@@ -1869,7 +1878,7 @@
 	int chs = substream->runtime->channels;
 	int i;
 
-	down(&codec->spdif_mutex);
+	mutex_lock(&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) &&
@@ -1883,13 +1892,20 @@
 			snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 0, 0, 0);
 		}
 	}
-	up(&codec->spdif_mutex);
+	mutex_unlock(&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);
+	/* extra outputs copied from front */
+	for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
+		if (mout->extra_out_nid[i])
+			snd_hda_codec_setup_stream(codec,
+						   mout->extra_out_nid[i],
+						   stream_tag, 0, format);
+
 	/* surrounds */
 	for (i = 1; i < mout->num_dacs; i++) {
 		if (chs >= (i + 1) * 2) /* independent out */
@@ -1914,12 +1930,17 @@
 		snd_hda_codec_setup_stream(codec, nids[i], 0, 0, 0);
 	if (mout->hp_nid)
 		snd_hda_codec_setup_stream(codec, mout->hp_nid, 0, 0, 0);
-	down(&codec->spdif_mutex);
+	for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++)
+		if (mout->extra_out_nid[i])
+			snd_hda_codec_setup_stream(codec,
+						   mout->extra_out_nid[i],
+						   0, 0, 0);
+	mutex_lock(&codec->spdif_mutex);
 	if (mout->dig_out_nid && mout->dig_out_used == HDA_DIG_ANALOG_DUP) {
 		snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 0, 0, 0);
 		mout->dig_out_used = 0;
 	}
-	up(&codec->spdif_mutex);
+	mutex_unlock(&codec->spdif_mutex);
 	return 0;
 }
 
@@ -1935,13 +1956,29 @@
 	return 0;
 }
 
-/* parse all pin widgets and store the useful pin nids to cfg */
+/*
+ * Parse all pin widgets and store the useful pin nids to cfg
+ *
+ * The number of line-outs or any primary output is stored in line_outs,
+ * and the corresponding output pins are assigned to line_out_pins[],
+ * in the order of front, rear, CLFE, side, ...
+ *
+ * If more extra outputs (speaker and headphone) are found, the pins are
+ * assisnged to hp_pin and speaker_pins[], respectively.  If no line-out jack
+ * is detected, one of speaker of HP pins is assigned as the primary
+ * output, i.e. to line_out_pins[0].  So, line_outs is always positive
+ * if any analog output exists.
+ * 
+ * The analog input pins are assigned to input_pins array.
+ * The digital input/output pins are assigned to dig_in_pin and dig_out_pin,
+ * respectively.
+ */
 int snd_hda_parse_pin_def_config(struct hda_codec *codec, struct auto_pin_cfg *cfg,
 				 hda_nid_t *ignore_nids)
 {
 	hda_nid_t nid, nid_start;
 	int i, j, nodes;
-	short seq, sequences[4], assoc_line_out;
+	short seq, assoc_line_out, sequences[ARRAY_SIZE(cfg->line_out_pins)];
 
 	memset(cfg, 0, sizeof(*cfg));
 
@@ -1983,7 +2020,10 @@
 			cfg->line_outs++;
 			break;
 		case AC_JACK_SPEAKER:
-			cfg->speaker_pin = nid;
+			if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins))
+				continue;
+			cfg->speaker_pins[cfg->speaker_outs] = nid;
+			cfg->speaker_outs++;
 			break;
 		case AC_JACK_HP_OUT:
 			cfg->hp_pin = nid;
@@ -2048,6 +2088,46 @@
 		break;
 	}
 
+	/*
+	 * debug prints of the parsed results
+	 */
+	snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
+		   cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1],
+		   cfg->line_out_pins[2], cfg->line_out_pins[3],
+		   cfg->line_out_pins[4]);
+	snd_printd("   speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
+		   cfg->speaker_outs, cfg->speaker_pins[0],
+		   cfg->speaker_pins[1], cfg->speaker_pins[2],
+		   cfg->speaker_pins[3], cfg->speaker_pins[4]);
+	snd_printd("   hp=0x%x, dig_out=0x%x, din_in=0x%x\n",
+		   cfg->hp_pin, cfg->dig_out_pin, cfg->dig_in_pin);
+	snd_printd("   inputs: mic=0x%x, fmic=0x%x, line=0x%x, fline=0x%x,"
+		   " cd=0x%x, aux=0x%x\n",
+		   cfg->input_pins[AUTO_PIN_MIC],
+		   cfg->input_pins[AUTO_PIN_FRONT_MIC],
+		   cfg->input_pins[AUTO_PIN_LINE],
+		   cfg->input_pins[AUTO_PIN_FRONT_LINE],
+		   cfg->input_pins[AUTO_PIN_CD],
+		   cfg->input_pins[AUTO_PIN_AUX]);
+
+	/*
+	 * FIX-UP: if no line-outs are detected, try to use speaker or HP pin
+	 * as a primary output
+	 */
+	if (! cfg->line_outs) {
+		if (cfg->speaker_outs) {
+			cfg->line_outs = cfg->speaker_outs;
+			memcpy(cfg->line_out_pins, cfg->speaker_pins,
+			       sizeof(cfg->speaker_pins));
+			cfg->speaker_outs = 0;
+			memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins));
+		} else if (cfg->hp_pin) {
+			cfg->line_outs = 1;
+			cfg->line_out_pins[0] = cfg->hp_pin;
+			cfg->hp_pin = 0;
+		}
+	}
+
 	return 0;
 }
 
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 63e26c7..40520e9 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -438,7 +438,7 @@
 	struct list_head codec_list;
 	struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1]; /* caddr -> codec */
 
-	struct semaphore cmd_mutex;
+	struct mutex cmd_mutex;
 
 	/* unsolicited event queue */
 	struct hda_bus_unsolicited *unsol;
@@ -559,7 +559,7 @@
 	int amp_info_size;
 	struct hda_amp_info *amp_info;
 
-	struct semaphore spdif_mutex;
+	struct mutex spdif_mutex;
 	unsigned int spdif_status;	/* IEC958 status bits */
 	unsigned short spdif_ctls;	/* SPDIF control bits */
 	unsigned int spdif_in_enable;	/* SPDIF input enable? */
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 39edfcf..85ad164a 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -47,10 +47,10 @@
 
 /* patch-specific record */
 struct hda_gspec {
-	struct hda_gnode *dac_node;	/* DAC node */
-	struct hda_gnode *out_pin_node;	/* Output pin (Line-Out) node */
-	struct hda_gnode *pcm_vol_node;	/* Node for PCM volume */
-	unsigned int pcm_vol_index;	/* connection of PCM volume */
+	struct hda_gnode *dac_node[2];	/* DAC node */
+	struct hda_gnode *out_pin_node[2];	/* Output pin (Line-Out) node */
+	struct hda_gnode *pcm_vol_node[2];	/* Node for PCM volume */
+	unsigned int pcm_vol_index[2];	/* connection of PCM volume */
 
 	struct hda_gnode *adc_node;	/* ADC node */
 	struct hda_gnode *cap_vol_node;	/* Node for capture volume */
@@ -69,8 +69,12 @@
 /*
  * retrieve the default device type from the default config value
  */
-#define defcfg_type(node) (((node)->def_cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT)
-#define defcfg_location(node) (((node)->def_cfg & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT)
+#define defcfg_type(node) (((node)->def_cfg & AC_DEFCFG_DEVICE) >> \
+			   AC_DEFCFG_DEVICE_SHIFT)
+#define defcfg_location(node) (((node)->def_cfg & AC_DEFCFG_LOCATION) >> \
+			       AC_DEFCFG_LOCATION_SHIFT)
+#define defcfg_port_conn(node) (((node)->def_cfg & AC_DEFCFG_PORT_CONN) >> \
+				AC_DEFCFG_PORT_CONN_SHIFT)
 
 /*
  * destructor
@@ -261,7 +265,7 @@
  * returns 0 if not found, 1 if found, or a negative error code.
  */
 static int parse_output_path(struct hda_codec *codec, struct hda_gspec *spec,
-			     struct hda_gnode *node)
+			     struct hda_gnode *node, int dac_idx)
 {
 	int i, err;
 	struct hda_gnode *child;
@@ -276,14 +280,14 @@
 			return 0;
 		}
 		snd_printdd("AUD_OUT found %x\n", node->nid);
-		if (spec->dac_node) {
+		if (spec->dac_node[dac_idx]) {
 			/* already DAC node is assigned, just unmute & connect */
-			return node == spec->dac_node;
+			return node == spec->dac_node[dac_idx];
 		}
-		spec->dac_node = node;
+		spec->dac_node[dac_idx] = node;
 		if (node->wid_caps & AC_WCAP_OUT_AMP) {
-			spec->pcm_vol_node = node;
-			spec->pcm_vol_index = 0;
+			spec->pcm_vol_node[dac_idx] = node;
+			spec->pcm_vol_index[dac_idx] = 0;
 		}
 		return 1; /* found */
 	}
@@ -292,7 +296,7 @@
 		child = hda_get_node(spec, node->conn_list[i]);
 		if (! child)
 			continue;
-		err = parse_output_path(codec, spec, child);
+		err = parse_output_path(codec, spec, child, dac_idx);
 		if (err < 0)
 			return err;
 		else if (err > 0) {
@@ -303,13 +307,13 @@
 				select_input_connection(codec, node, i);
 			unmute_input(codec, node, i);
 			unmute_output(codec, node);
-			if (! spec->pcm_vol_node) {
+			if (! spec->pcm_vol_node[dac_idx]) {
 				if (node->wid_caps & AC_WCAP_IN_AMP) {
-					spec->pcm_vol_node = node;
-					spec->pcm_vol_index = i;
+					spec->pcm_vol_node[dac_idx] = node;
+					spec->pcm_vol_index[dac_idx] = i;
 				} else if (node->wid_caps & AC_WCAP_OUT_AMP) {
-					spec->pcm_vol_node = node;
-					spec->pcm_vol_index = 0;
+					spec->pcm_vol_node[dac_idx] = node;
+					spec->pcm_vol_index[dac_idx] = 0;
 				}
 			}
 			return 1;
@@ -339,6 +343,8 @@
 		/* output capable? */
 		if (! (node->pin_caps & AC_PINCAP_OUT))
 			continue;
+		if (defcfg_port_conn(node) == AC_JACK_PORT_NONE)
+			continue; /* unconnected */
 		if (jack_type >= 0) {
 			if (jack_type != defcfg_type(node))
 				continue;
@@ -350,10 +356,15 @@
 				continue;
 		}
 		clear_check_flags(spec);
-		err = parse_output_path(codec, spec, node);
+		err = parse_output_path(codec, spec, node, 0);
 		if (err < 0)
 			return NULL;
-		else if (err > 0) {
+		if (! err && spec->out_pin_node[0]) {
+			err = parse_output_path(codec, spec, node, 1);
+			if (err < 0)
+				return NULL;
+		}
+		if (err > 0) {
 			/* unmute the PIN output */
 			unmute_output(codec, node);
 			/* set PIN-Out enable */
@@ -381,20 +392,28 @@
 	/* first, look for the line-out pin */
 	node = parse_output_jack(codec, spec, AC_JACK_LINE_OUT);
 	if (node) /* found, remember the PIN node */
-		spec->out_pin_node = node;
+		spec->out_pin_node[0] = node;
+	else {
+		/* if no line-out is found, try speaker out */
+		node = parse_output_jack(codec, spec, AC_JACK_SPEAKER);
+		if (node)
+			spec->out_pin_node[0] = node;
+	}
 	/* look for the HP-out pin */
 	node = parse_output_jack(codec, spec, AC_JACK_HP_OUT);
 	if (node) {
-		if (! spec->out_pin_node)
-			spec->out_pin_node = node;
+		if (! spec->out_pin_node[0])
+			spec->out_pin_node[0] = node;
+		else
+			spec->out_pin_node[1] = node;
 	}
 
-	if (! spec->out_pin_node) {
+	if (! spec->out_pin_node[0]) {
 		/* no line-out or HP pins found,
 		 * then choose for the first output pin
 		 */
-		spec->out_pin_node = parse_output_jack(codec, spec, -1);
-		if (! spec->out_pin_node)
+		spec->out_pin_node[0] = parse_output_jack(codec, spec, -1);
+		if (! spec->out_pin_node[0])
 			snd_printd("hda_generic: no proper output path found\n");
 	}
 
@@ -505,6 +524,9 @@
 	if (! (node->pin_caps & AC_PINCAP_IN))
 		return 0;
 
+	if (defcfg_port_conn(node) == AC_JACK_PORT_NONE)
+		return 0; /* unconnected */
+
 	if (node->wid_caps & AC_WCAP_DIGITAL)
 		return 0; /* skip SPDIF */
 
@@ -703,12 +725,16 @@
 static int build_output_controls(struct hda_codec *codec)
 {
 	struct hda_gspec *spec = codec->spec;
-	int err;
+	static const char *types[2] = { "Master", "Headphone" };
+	int i, err;
 
-	err = create_mixer(codec, spec->pcm_vol_node, spec->pcm_vol_index,
-			   "PCM", "Playback");
-	if (err < 0)
-		return err;
+	for (i = 0; i < 2 && spec->pcm_vol_node[i]; i++) {
+		err = create_mixer(codec, spec->pcm_vol_node[i],
+				   spec->pcm_vol_index[i],
+				   types[i], "Playback");
+		if (err < 0)
+			return err;
+	}
 	return 0;
 }
 
@@ -805,7 +831,7 @@
 	int err;
 	const char *type;
 
-	if (! spec->out_pin_node)
+	if (! spec->out_pin_node[0])
 		return 0;
 
 	list_for_each(p, &spec->nid_list) {
@@ -820,7 +846,8 @@
 			if (check_existing_control(codec, type, "Playback"))
 				continue;
 			clear_check_flags(spec);
-			err = parse_loopback_path(codec, spec, spec->out_pin_node,
+			err = parse_loopback_path(codec, spec,
+						  spec->out_pin_node[0],
 						  node, type);
 			if (err < 0)
 				return err;
@@ -855,12 +882,37 @@
 	.channels_max = 2,
 };
 
+static int generic_pcm2_prepare(struct hda_pcm_stream *hinfo,
+				struct hda_codec *codec,
+				unsigned int stream_tag,
+				unsigned int format,
+				struct snd_pcm_substream *substream)
+{
+	struct hda_gspec *spec = codec->spec;
+
+	snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format);
+	snd_hda_codec_setup_stream(codec, spec->dac_node[1]->nid,
+				   stream_tag, 0, format);
+	return 0;
+}
+
+static int generic_pcm2_cleanup(struct hda_pcm_stream *hinfo,
+				struct hda_codec *codec,
+				struct snd_pcm_substream *substream)
+{
+	struct hda_gspec *spec = codec->spec;
+
+	snd_hda_codec_setup_stream(codec, hinfo->nid, 0, 0, 0);
+	snd_hda_codec_setup_stream(codec, spec->dac_node[1]->nid, 0, 0, 0);
+	return 0;
+}
+
 static int build_generic_pcms(struct hda_codec *codec)
 {
 	struct hda_gspec *spec = codec->spec;
 	struct hda_pcm *info = &spec->pcm_rec;
 
-	if (! spec->dac_node && ! spec->adc_node) {
+	if (! spec->dac_node[0] && ! spec->adc_node) {
 		snd_printd("hda_generic: no PCM found\n");
 		return 0;
 	}
@@ -869,9 +921,13 @@
 	codec->pcm_info = info;
 
 	info->name = "HDA Generic";
-	if (spec->dac_node) {
+	if (spec->dac_node[0]) {
 		info->stream[0] = generic_pcm_playback;
-		info->stream[0].nid = spec->dac_node->nid;
+		info->stream[0].nid = spec->dac_node[0]->nid;
+		if (spec->dac_node[1]) {
+			info->stream[0].ops.prepare = generic_pcm2_prepare;
+			info->stream[0].ops.cleanup = generic_pcm2_cleanup;
+		}
 	}
 	if (spec->adc_node) {
 		info->stream[1] = generic_pcm_playback;
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index fd12b69..c096606 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -43,6 +43,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/initval.h>
 #include "hda_codec.h"
@@ -53,6 +54,7 @@
 static char *model;
 static int position_fix;
 static int probe_mask = -1;
+static int single_cmd;
 
 module_param(index, int, 0444);
 MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
@@ -64,6 +66,8 @@
 MODULE_PARM_DESC(position_fix, "Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size).");
 module_param(probe_mask, int, 0444);
 MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1).");
+module_param(single_cmd, bool, 0444);
+MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs (for debugging only).");
 
 
 /* just for backward compatibility */
@@ -235,12 +239,6 @@
 #define NVIDIA_HDA_ENABLE_COHBITS     0x0f
 
 /*
- * Use CORB/RIRB for communication from/to codecs.
- * This is the way recommended by Intel (see below).
- */
-#define USE_CORB_RIRB
-
-/*
  */
 
 struct azx_dev {
@@ -252,7 +250,6 @@
 	unsigned int fragsize;		/* size of each period in bytes */
 	unsigned int frags;		/* number for period in the play buffer */
 	unsigned int fifo_size;		/* FIFO size */
-	unsigned int last_pos;		/* last updated period position */
 
 	void __iomem *sd_addr;		/* stream descriptor pointer */
 
@@ -263,10 +260,11 @@
 	unsigned int format_val;	/* format value to be set in the controller and the codec */
 	unsigned char stream_tag;	/* assigned stream */
 	unsigned char index;		/* stream index */
+	/* for sanity check of position buffer */
+	unsigned int period_intr;
 
 	unsigned int opened: 1;
 	unsigned int running: 1;
-	unsigned int period_updating: 1;
 };
 
 /* CORB/RIRB */
@@ -300,7 +298,7 @@
 
 	/* locks */
 	spinlock_t reg_lock;
-	struct semaphore open_mutex;
+	struct mutex open_mutex;
 
 	/* streams (x num_streams) */
 	struct azx_dev *azx_dev;
@@ -325,6 +323,7 @@
 	/* flags */
 	int position_fix;
 	unsigned int initialized: 1;
+	unsigned int single_cmd: 1;
 };
 
 /* driver types */
@@ -388,7 +387,6 @@
  * Interface for HD codec
  */
 
-#ifdef USE_CORB_RIRB
 /*
  * CORB / RIRB interface
  */
@@ -436,11 +434,7 @@
 	/* set N=1, get RIRB response interrupt for new entry */
 	azx_writew(chip, RINTCNT, 1);
 	/* enable rirb dma and response irq */
-#ifdef USE_CORB_RIRB
 	azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN);
-#else
-	azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN);
-#endif
 	chip->rirb.rp = chip->rirb.cmds = 0;
 }
 
@@ -452,8 +446,8 @@
 }
 
 /* send a command */
-static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
-			unsigned int verb, unsigned int para)
+static int azx_corb_send_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
+			     unsigned int verb, unsigned int para)
 {
 	struct azx *chip = codec->bus->private_data;
 	unsigned int wp;
@@ -509,18 +503,21 @@
 }
 
 /* receive a response */
-static unsigned int azx_get_response(struct hda_codec *codec)
+static unsigned int azx_rirb_get_response(struct hda_codec *codec)
 {
 	struct azx *chip = codec->bus->private_data;
 	int timeout = 50;
 
 	while (chip->rirb.cmds) {
 		if (! --timeout) {
-			if (printk_ratelimit())
-				snd_printk(KERN_ERR
-					"azx_get_response timeout\n");
+			snd_printk(KERN_ERR
+				   "hda_intel: azx_get_response timeout, "
+				   "switching to single_cmd mode...\n");
 			chip->rirb.rp = azx_readb(chip, RIRBWP);
 			chip->rirb.cmds = 0;
+			/* switch to single_cmd mode */
+			chip->single_cmd = 1;
+			azx_free_cmd_io(chip);
 			return -1;
 		}
 		msleep(1);
@@ -528,7 +525,6 @@
 	return chip->rirb.res; /* the last value */
 }
 
-#else
 /*
  * Use the single immediate command instead of CORB/RIRB for simplicity
  *
@@ -539,13 +535,10 @@
  *       I left the codes, however, for debugging/testing purposes.
  */
 
-#define azx_alloc_cmd_io(chip)	0
-#define azx_init_cmd_io(chip)
-#define azx_free_cmd_io(chip)
-
 /* send a command */
-static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
-			unsigned int verb, unsigned int para)
+static int azx_single_send_cmd(struct hda_codec *codec, hda_nid_t nid,
+			       int direct, unsigned int verb,
+			       unsigned int para)
 {
 	struct azx *chip = codec->bus->private_data;
 	u32 val;
@@ -573,7 +566,7 @@
 }
 
 /* receive a response */
-static unsigned int azx_get_response(struct hda_codec *codec)
+static unsigned int azx_single_get_response(struct hda_codec *codec)
 {
 	struct azx *chip = codec->bus->private_data;
 	int timeout = 50;
@@ -588,9 +581,35 @@
 	return (unsigned int)-1;
 }
 
-#define azx_update_rirb(chip)
+/*
+ * The below are the main callbacks from hda_codec.
+ *
+ * They are just the skeleton to call sub-callbacks according to the
+ * current setting of chip->single_cmd.
+ */
 
-#endif /* USE_CORB_RIRB */
+/* send a command */
+static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid,
+			int direct, unsigned int verb,
+			unsigned int para)
+{
+	struct azx *chip = codec->bus->private_data;
+	if (chip->single_cmd)
+		return azx_single_send_cmd(codec, nid, direct, verb, para);
+	else
+		return azx_corb_send_cmd(codec, nid, direct, verb, para);
+}
+
+/* get a response */
+static unsigned int azx_get_response(struct hda_codec *codec)
+{
+	struct azx *chip = codec->bus->private_data;
+	if (chip->single_cmd)
+		return azx_single_get_response(codec);
+	else
+		return azx_rirb_get_response(codec);
+}
+
 
 /* reset codec link */
 static int azx_reset(struct azx *chip)
@@ -737,7 +756,8 @@
 	azx_int_enable(chip);
 
 	/* initialize the codec command I/O */
-	azx_init_cmd_io(chip);
+	if (! chip->single_cmd)
+		azx_init_cmd_io(chip);
 
 	/* program the position buffer */
 	azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr);
@@ -784,11 +804,10 @@
 		if (status & azx_dev->sd_int_sta_mask) {
 			azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
 			if (azx_dev->substream && azx_dev->running) {
-				azx_dev->period_updating = 1;
+				azx_dev->period_intr++;
 				spin_unlock(&chip->reg_lock);
 				snd_pcm_period_elapsed(azx_dev->substream);
 				spin_lock(&chip->reg_lock);
-				azx_dev->period_updating = 0;
 			}
 		}
 	}
@@ -796,7 +815,7 @@
 	/* clear rirb int */
 	status = azx_readb(chip, RIRBSTS);
 	if (status & RIRB_INT_MASK) {
-		if (status & RIRB_INT_RESPONSE)
+		if (! chip->single_cmd && (status & RIRB_INT_RESPONSE))
 			azx_update_rirb(chip);
 		azx_writeb(chip, RIRBSTS, RIRB_INT_MASK);
 	}
@@ -1002,10 +1021,10 @@
 	unsigned long flags;
 	int err;
 
-	down(&chip->open_mutex);
+	mutex_lock(&chip->open_mutex);
 	azx_dev = azx_assign_device(chip, substream->stream);
 	if (azx_dev == NULL) {
-		up(&chip->open_mutex);
+		mutex_unlock(&chip->open_mutex);
 		return -EBUSY;
 	}
 	runtime->hw = azx_pcm_hw;
@@ -1017,7 +1036,7 @@
 	snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
 	if ((err = hinfo->ops.open(hinfo, apcm->codec, substream)) < 0) {
 		azx_release_device(azx_dev);
-		up(&chip->open_mutex);
+		mutex_unlock(&chip->open_mutex);
 		return err;
 	}
 	spin_lock_irqsave(&chip->reg_lock, flags);
@@ -1026,7 +1045,7 @@
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 
 	runtime->private_data = azx_dev;
-	up(&chip->open_mutex);
+	mutex_unlock(&chip->open_mutex);
 	return 0;
 }
 
@@ -1038,14 +1057,14 @@
 	struct azx_dev *azx_dev = get_azx_dev(substream);
 	unsigned long flags;
 
-	down(&chip->open_mutex);
+	mutex_lock(&chip->open_mutex);
 	spin_lock_irqsave(&chip->reg_lock, flags);
 	azx_dev->substream = NULL;
 	azx_dev->running = 0;
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 	azx_release_device(azx_dev);
 	hinfo->ops.close(hinfo, apcm->codec, substream);
-	up(&chip->open_mutex);
+	mutex_unlock(&chip->open_mutex);
 	return 0;
 }
 
@@ -1099,7 +1118,6 @@
 		azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1;
 	else
 		azx_dev->fifo_size = 0;
-	azx_dev->last_pos = 0;
 
 	return hinfo->ops.prepare(hinfo, apcm->codec, azx_dev->stream_tag,
 				  azx_dev->format_val, substream);
@@ -1147,10 +1165,20 @@
 	struct azx_dev *azx_dev = get_azx_dev(substream);
 	unsigned int pos;
 
-	if (chip->position_fix == POS_FIX_POSBUF) {
+	if (chip->position_fix == POS_FIX_POSBUF ||
+	    chip->position_fix == POS_FIX_AUTO) {
 		/* use the position buffer */
 		pos = *azx_dev->posbuf;
+		if (chip->position_fix == POS_FIX_AUTO &&
+		    azx_dev->period_intr == 1 && ! pos) {
+			printk(KERN_WARNING
+			       "hda-intel: Invalid position buffer, "
+			       "using LPIB read method instead.\n");
+			chip->position_fix = POS_FIX_NONE;
+			goto read_lpib;
+		}
 	} else {
+	read_lpib:
 		/* read LPIB */
 		pos = azx_sd_readl(azx_dev, SD_LPIB);
 		if (chip->position_fix == POS_FIX_FIFO)
@@ -1415,13 +1443,14 @@
 	}
 
 	spin_lock_init(&chip->reg_lock);
-	init_MUTEX(&chip->open_mutex);
+	mutex_init(&chip->open_mutex);
 	chip->card = card;
 	chip->pci = pci;
 	chip->irq = -1;
 	chip->driver_type = driver_type;
 
-	chip->position_fix = position_fix ? position_fix : POS_FIX_POSBUF;
+	chip->position_fix = position_fix;
+	chip->single_cmd = single_cmd;
 
 #if BITS_PER_LONG != 64
 	/* Fix up base address on ULI M5461 */
@@ -1492,8 +1521,9 @@
 		goto errout;
 	}
 	/* allocate CORB/RIRB */
-	if ((err = azx_alloc_cmd_io(chip)) < 0)
-		goto errout;
+	if (! chip->single_cmd)
+		if ((err = azx_alloc_cmd_io(chip)) < 0)
+			goto errout;
 
 	/* initialize streams */
 	azx_init_stream(chip);
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index c82d2a7..14e8aa2 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -66,6 +66,11 @@
 int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo);
 int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
 int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
+/* lowlevel accessor with caching; use carefully */
+int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch,
+			   int direction, int index);
+int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
+			     int direction, int idx, int mask, int val);
 
 /* mono switch binding multiple inputs */
 #define HDA_BIND_MUTE_MONO(xname, nid, channel, indices, direction) \
@@ -130,6 +135,7 @@
 	int num_dacs;		/* # of DACs, must be more than 1 */
 	hda_nid_t *dac_nids;	/* DAC list */
 	hda_nid_t hp_nid;	/* optional DAC for HP, 0 when not exists */
+	hda_nid_t extra_out_nid[3];	/* optional DACs, 0 when not exists */
 	hda_nid_t dig_out_nid;	/* digital out audio widget */
 	int max_channels;	/* currently supported analog channels */
 	int dig_out_used;	/* current usage of digital out (HDA_DIG_XXX) */
@@ -216,7 +222,8 @@
 struct auto_pin_cfg {
 	int line_outs;
 	hda_nid_t line_out_pins[5]; /* sorted in the order of Front/Surr/CLFE/Side */
-	hda_nid_t speaker_pin;
+	int speaker_outs;
+	hda_nid_t speaker_pins[5];
 	hda_nid_t hp_pin;
 	hda_nid_t input_pins[AUTO_PIN_LAST];
 	hda_nid_t dig_out_pin;
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 1ada1b0..32401bd 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -23,6 +23,8 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include "hda_codec.h"
 #include "hda_local.h"
@@ -60,7 +62,7 @@
 	/* PCM information */
 	struct hda_pcm pcm_rec[2];	/* used in alc_build_pcms() */
 
-	struct semaphore amp_mutex;	/* PCM volume/mute control mutex */
+	struct mutex amp_mutex;	/* PCM volume/mute control mutex */
 	unsigned int spdif_route;
 
 	/* dynamic controls, init_verbs and input_mux */
@@ -308,7 +310,7 @@
 	struct ad198x_spec *spec = codec->spec;
 	int i;
 
-	ad198x_init(codec);
+	codec->patch_ops.init(codec);
 	for (i = 0; i < spec->num_mixers; i++)
 		snd_hda_resume_ctls(codec, spec->mixers[i]);
 	if (spec->multiout.dig_out_nid)
@@ -331,6 +333,61 @@
 
 
 /*
+ * EAPD control
+ * the private value = nid | (invert << 8)
+ */
+static int ad198x_eapd_info(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_info *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 ad198x_eapd_get(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct ad198x_spec *spec = codec->spec;
+	int invert = (kcontrol->private_value >> 8) & 1;
+	if (invert)
+		ucontrol->value.integer.value[0] = ! spec->cur_eapd;
+	else
+		ucontrol->value.integer.value[0] = spec->cur_eapd;
+	return 0;
+}
+
+static int ad198x_eapd_put(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct ad198x_spec *spec = codec->spec;
+	int invert = (kcontrol->private_value >> 8) & 1;
+	hda_nid_t nid = kcontrol->private_value & 0xff;
+	unsigned int eapd;
+	eapd = ucontrol->value.integer.value[0];
+	if (invert)
+		eapd = !eapd;
+	if (eapd == spec->cur_eapd && ! codec->in_resume)
+		return 0;
+	spec->cur_eapd = eapd;
+	snd_hda_codec_write(codec, nid,
+			    0, AC_VERB_SET_EAPD_BTLENABLE,
+			    eapd ? 0x02 : 0x00);
+	return 1;
+}
+
+static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_info *uinfo);
+static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol);
+static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol);
+
+
+/*
  * AD1986A specific
  */
 
@@ -344,6 +401,7 @@
 	AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC
 };
 static hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC };
+static hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 };
 
 static struct hda_input_mux ad1986a_capture_source = {
 	.num_items = 7,
@@ -371,9 +429,9 @@
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct ad198x_spec *ad = codec->spec;
 
-	down(&ad->amp_mutex);
+	mutex_lock(&ad->amp_mutex);
 	snd_hda_mixer_amp_volume_get(kcontrol, ucontrol);
-	up(&ad->amp_mutex);
+	mutex_unlock(&ad->amp_mutex);
 	return 0;
 }
 
@@ -383,13 +441,13 @@
 	struct ad198x_spec *ad = codec->spec;
 	int i, change = 0;
 
-	down(&ad->amp_mutex);
+	mutex_lock(&ad->amp_mutex);
 	for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) {
 		kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT);
 		change |= snd_hda_mixer_amp_volume_put(kcontrol, ucontrol);
 	}
 	kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT);
-	up(&ad->amp_mutex);
+	mutex_unlock(&ad->amp_mutex);
 	return change;
 }
 
@@ -400,9 +458,9 @@
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct ad198x_spec *ad = codec->spec;
 
-	down(&ad->amp_mutex);
+	mutex_lock(&ad->amp_mutex);
 	snd_hda_mixer_amp_switch_get(kcontrol, ucontrol);
-	up(&ad->amp_mutex);
+	mutex_unlock(&ad->amp_mutex);
 	return 0;
 }
 
@@ -412,13 +470,13 @@
 	struct ad198x_spec *ad = codec->spec;
 	int i, change = 0;
 
-	down(&ad->amp_mutex);
+	mutex_lock(&ad->amp_mutex);
 	for (i = 0; i < ARRAY_SIZE(ad1986a_dac_nids); i++) {
 		kcontrol->private_value = HDA_COMPOSE_AMP_VAL(ad1986a_dac_nids[i], 3, 0, HDA_OUTPUT);
 		change |= snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
 	}
 	kcontrol->private_value = HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT);
-	up(&ad->amp_mutex);
+	mutex_unlock(&ad->amp_mutex);
 	return change;
 }
 
@@ -477,6 +535,143 @@
 	{ } /* end */
 };
 
+/* additional mixers for 3stack mode */
+static struct snd_kcontrol_new ad1986a_3st_mixers[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Channel Mode",
+		.info = ad198x_ch_mode_info,
+		.get = ad198x_ch_mode_get,
+		.put = ad198x_ch_mode_put,
+	},
+	{ } /* end */
+};
+
+/* laptop model - 2ch only */
+static hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC };
+
+static struct snd_kcontrol_new ad1986a_laptop_mixers[] = {
+	HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Master Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Master Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+	/* HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT),
+	   HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT), */
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
+	/* HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x18, 0x0, HDA_OUTPUT),
+	   HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x18, 0x0, HDA_OUTPUT),
+	   HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
+	   HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), */
+	HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Capture Source",
+		.info = ad198x_mux_enum_info,
+		.get = ad198x_mux_enum_get,
+		.put = ad198x_mux_enum_put,
+	},
+	{ } /* end */
+};
+
+/* laptop-eapd model - 2ch only */
+
+/* master controls both pins 0x1a and 0x1b */
+static int ad1986a_laptop_master_vol_put(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	long *valp = ucontrol->value.integer.value;
+	int change;
+
+	change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0,
+					  0x7f, valp[0] & 0x7f);
+	change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0,
+					   0x7f, valp[1] & 0x7f);
+	snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0,
+				 0x7f, valp[0] & 0x7f);
+	snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0,
+				 0x7f, valp[1] & 0x7f);
+	return change;
+}
+
+static int ad1986a_laptop_master_sw_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	long *valp = ucontrol->value.integer.value;
+	int change;
+
+	change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0,
+					  0x80, valp[0] ? 0 : 0x80);
+	change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0,
+					   0x80, valp[1] ? 0 : 0x80);
+	snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0,
+				 0x80, valp[0] ? 0 : 0x80);
+	snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0,
+				 0x80, valp[1] ? 0 : 0x80);
+	return change;
+}
+
+static struct hda_input_mux ad1986a_laptop_eapd_capture_source = {
+	.num_items = 3,
+	.items = {
+		{ "Mic", 0x0 },
+		{ "Internal Mic", 0x4 },
+		{ "Mix", 0x5 },
+	},
+};
+
+static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Volume",
+		.info = snd_hda_mixer_amp_volume_info,
+		.get = snd_hda_mixer_amp_volume_get,
+		.put = ad1986a_laptop_master_vol_put,
+		.private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Switch",
+		.info = snd_hda_mixer_amp_switch_info,
+		.get = snd_hda_mixer_amp_switch_get,
+		.put = ad1986a_laptop_master_sw_put,
+		.private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
+	},
+	HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Capture Source",
+		.info = ad198x_mux_enum_info,
+		.get = ad198x_mux_enum_get,
+		.put = ad198x_mux_enum_put,
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "External Amplifier",
+		.info = ad198x_eapd_info,
+		.get = ad198x_eapd_get,
+		.put = ad198x_eapd_put,
+		.private_value = 0x1b | (1 << 8), /* port-D, inversed */
+	},
+	{ } /* end */
+};
+
 /*
  * initialization verbs
  */
@@ -535,16 +730,89 @@
 	{ } /* end */
 };
 
+/* additional verbs for 3-stack model */
+static struct hda_verb ad1986a_3st_init_verbs[] = {
+ 	/* Mic and line-in selectors */
+	{0x0f, AC_VERB_SET_CONNECT_SEL, 0x2},
+	{0x10, AC_VERB_SET_CONNECT_SEL, 0x1},
+ 	{ } /* end */
+};
+
+static struct hda_verb ad1986a_ch2_init[] = {
+	/* Surround out -> Line In */
+	{ 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+	{ 0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+	/* CLFE -> Mic in */
+	{ 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+	{ 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+	{ } /* end */
+};
+
+static struct hda_verb ad1986a_ch4_init[] = {
+	/* Surround out -> Surround */
+	{ 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+	{ 0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+	/* CLFE -> Mic in */
+	{ 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+	{ 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+	{ } /* end */
+};
+
+static struct hda_verb ad1986a_ch6_init[] = {
+	/* Surround out -> Surround out */
+	{ 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+	{ 0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+	/* CLFE -> CLFE */
+	{ 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
+	{ 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+	{ } /* end */
+};
+
+static struct hda_channel_mode ad1986a_modes[3] = {
+	{ 2, ad1986a_ch2_init },
+	{ 4, ad1986a_ch4_init },
+	{ 6, ad1986a_ch6_init },
+};
+
+/* eapd initialization */
+static struct hda_verb ad1986a_eapd_init_verbs[] = {
+	{0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00},
+	{}
+};
+
+/* models */
+enum { AD1986A_6STACK, AD1986A_3STACK, AD1986A_LAPTOP, AD1986A_LAPTOP_EAPD };
+
+static struct hda_board_config ad1986a_cfg_tbl[] = {
+	{ .modelname = "6stack",	.config = AD1986A_6STACK },
+	{ .modelname = "3stack",	.config = AD1986A_3STACK },
+	{ .pci_subvendor = 0x10de, .pci_subdevice = 0xcb84,
+	  .config = AD1986A_3STACK }, /* ASUS A8N-VM CSM */
+	{ .modelname = "laptop",	.config = AD1986A_LAPTOP },
+	{ .pci_subvendor = 0x144d, .pci_subdevice = 0xc01e,
+	  .config = AD1986A_LAPTOP }, /* FSC V2060 */
+	{ .pci_subvendor = 0x17c0, .pci_subdevice = 0x2017,
+	  .config = AD1986A_LAPTOP }, /* Samsung M50 */
+	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x818f,
+	  .config = AD1986A_LAPTOP }, /* ASUS P5GV-MX */
+	{ .modelname = "laptop-eapd",	.config = AD1986A_LAPTOP_EAPD },
+	{ .pci_subvendor = 0x144d, .pci_subdevice = 0xc024,
+	  .config = AD1986A_LAPTOP_EAPD }, /* Samsung R65-T2300 Charis */
+	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1213,
+	  .config = AD1986A_LAPTOP_EAPD }, /* ASUS A6J */
+	{}
+};
 
 static int patch_ad1986a(struct hda_codec *codec)
 {
 	struct ad198x_spec *spec;
+	int board_config;
 
 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (spec == NULL)
 		return -ENOMEM;
 
-	init_MUTEX(&spec->amp_mutex);
+	mutex_init(&spec->amp_mutex);
 	codec->spec = spec;
 
 	spec->multiout.max_channels = 6;
@@ -553,7 +821,7 @@
 	spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT;
 	spec->num_adc_nids = 1;
 	spec->adc_nids = ad1986a_adc_nids;
-	spec->capsrc_nids = ad1986a_adc_nids;
+	spec->capsrc_nids = ad1986a_capsrc_nids;
 	spec->input_mux = &ad1986a_capture_source;
 	spec->num_mixers = 1;
 	spec->mixers[0] = ad1986a_mixers;
@@ -562,6 +830,35 @@
 
 	codec->patch_ops = ad198x_patch_ops;
 
+	/* override some parameters */
+	board_config = snd_hda_check_board_config(codec, ad1986a_cfg_tbl);
+	switch (board_config) {
+	case AD1986A_3STACK:
+		spec->num_mixers = 2;
+		spec->mixers[1] = ad1986a_3st_mixers;
+		spec->num_init_verbs = 2;
+		spec->init_verbs[1] = ad1986a_3st_init_verbs;
+		spec->channel_mode = ad1986a_modes;
+		spec->num_channel_mode = ARRAY_SIZE(ad1986a_modes);
+		break;
+	case AD1986A_LAPTOP:
+		spec->mixers[0] = ad1986a_laptop_mixers;
+		spec->multiout.max_channels = 2;
+		spec->multiout.num_dacs = 1;
+		spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
+		break;
+	case AD1986A_LAPTOP_EAPD:
+		spec->mixers[0] = ad1986a_laptop_eapd_mixers;
+		spec->num_init_verbs = 2;
+		spec->init_verbs[1] = ad1986a_eapd_init_verbs;
+		spec->multiout.max_channels = 2;
+		spec->multiout.num_dacs = 1;
+		spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
+		spec->multiout.dig_out_nid = 0;
+		spec->input_mux = &ad1986a_laptop_eapd_capture_source;
+		break;
+	}
+
 	return 0;
 }
 
@@ -575,6 +872,7 @@
 
 static hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC };
 static hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC };
+static hda_nid_t ad1983_capsrc_nids[1] = { 0x15 };
 
 static struct hda_input_mux ad1983_capture_source = {
 	.num_items = 4,
@@ -708,7 +1006,7 @@
 	if (spec == NULL)
 		return -ENOMEM;
 
-	init_MUTEX(&spec->amp_mutex);
+	mutex_init(&spec->amp_mutex);
 	codec->spec = spec;
 
 	spec->multiout.max_channels = 2;
@@ -717,7 +1015,7 @@
 	spec->multiout.dig_out_nid = AD1983_SPDIF_OUT;
 	spec->num_adc_nids = 1;
 	spec->adc_nids = ad1983_adc_nids;
-	spec->capsrc_nids = ad1983_adc_nids;
+	spec->capsrc_nids = ad1983_capsrc_nids;
 	spec->input_mux = &ad1983_capture_source;
 	spec->num_mixers = 1;
 	spec->mixers[0] = ad1983_mixers;
@@ -741,6 +1039,7 @@
 
 static hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC };
 static hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC };
+static hda_nid_t ad1981_capsrc_nids[1] = { 0x15 };
 
 /* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */
 static struct hda_input_mux ad1981_capture_source = {
@@ -846,15 +1145,200 @@
 	{ } /* end */
 };
 
+/*
+ * Patch for HP nx6320
+ *
+ * nx6320 uses EAPD in the reserve way - EAPD-on means the internal
+ * speaker output enabled _and_ mute-LED off.
+ */
+
+#define AD1981_HP_EVENT		0x37
+#define AD1981_MIC_EVENT	0x38
+
+static struct hda_verb ad1981_hp_init_verbs[] = {
+	{0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, /* default off */
+	/* pin sensing on HP and Mic jacks */
+	{0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
+	{0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT},
+	{}
+};
+
+/* turn on/off EAPD (+ mute HP) as a master switch */
+static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct ad198x_spec *spec = codec->spec;
+
+	if (! ad198x_eapd_put(kcontrol, ucontrol))
+		return 0;
+
+	/* toggle HP mute appropriately */
+	snd_hda_codec_amp_update(codec, 0x06, 0, HDA_OUTPUT, 0,
+				 0x80, spec->cur_eapd ? 0 : 0x80);
+	snd_hda_codec_amp_update(codec, 0x06, 1, HDA_OUTPUT, 0,
+				 0x80, spec->cur_eapd ? 0 : 0x80);
+	return 1;
+}
+
+/* bind volumes of both NID 0x05 and 0x06 */
+static int ad1981_hp_master_vol_put(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	long *valp = ucontrol->value.integer.value;
+	int change;
+
+	change = snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0,
+					  0x7f, valp[0] & 0x7f);
+	change |= snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0,
+					   0x7f, valp[1] & 0x7f);
+	snd_hda_codec_amp_update(codec, 0x06, 0, HDA_OUTPUT, 0,
+				 0x7f, valp[0] & 0x7f);
+	snd_hda_codec_amp_update(codec, 0x06, 1, HDA_OUTPUT, 0,
+				 0x7f, valp[1] & 0x7f);
+	return change;
+}
+
+/* mute internal speaker if HP is plugged */
+static void ad1981_hp_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+
+	present = snd_hda_codec_read(codec, 0x06, 0,
+				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0,
+				 0x80, present ? 0x80 : 0);
+	snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0,
+				 0x80, present ? 0x80 : 0);
+}
+
+/* toggle input of built-in and mic jack appropriately */
+static void ad1981_hp_automic(struct hda_codec *codec)
+{
+	static struct hda_verb mic_jack_on[] = {
+		{0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+		{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+		{}
+	};
+	static struct hda_verb mic_jack_off[] = {
+		{0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
+		{0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+		{}
+	};
+	unsigned int present;
+
+	present = snd_hda_codec_read(codec, 0x08, 0,
+			    	 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	if (present)
+		snd_hda_sequence_write(codec, mic_jack_on);
+	else
+		snd_hda_sequence_write(codec, mic_jack_off);
+}
+
+/* unsolicited event for HP jack sensing */
+static void ad1981_hp_unsol_event(struct hda_codec *codec,
+				  unsigned int res)
+{
+	res >>= 26;
+	switch (res) {
+	case AD1981_HP_EVENT:
+		ad1981_hp_automute(codec);
+		break;
+	case AD1981_MIC_EVENT:
+		ad1981_hp_automic(codec);
+		break;
+	}
+}
+
+static struct hda_input_mux ad1981_hp_capture_source = {
+	.num_items = 3,
+	.items = {
+		{ "Mic", 0x0 },
+		{ "Docking-Station", 0x1 },
+		{ "Mix", 0x2 },
+	},
+};
+
+static struct snd_kcontrol_new ad1981_hp_mixers[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Volume",
+		.info = snd_hda_mixer_amp_volume_info,
+		.get = snd_hda_mixer_amp_volume_get,
+		.put = ad1981_hp_master_vol_put,
+		.private_value = HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Switch",
+		.info = ad198x_eapd_info,
+		.get = ad198x_eapd_get,
+		.put = ad1981_hp_master_sw_put,
+		.private_value = 0x05,
+	},
+	HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
+#if 0
+	/* FIXME: analog mic/line loopback doesn't work with my tests...
+	 *        (although recording is OK)
+	 */
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Docking-Station Playback Volume", 0x13, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Docking-Station Playback Switch", 0x13, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
+	/* FIXME: does this laptop have analog CD connection? */
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
+#endif
+	HDA_CODEC_VOLUME("Mic Boost", 0x08, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Internal Mic Boost", 0x18, 0x0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Capture Source",
+		.info = ad198x_mux_enum_info,
+		.get = ad198x_mux_enum_get,
+		.put = ad198x_mux_enum_put,
+	},
+	{ } /* end */
+};
+
+/* initialize jack-sensing, too */
+static int ad1981_hp_init(struct hda_codec *codec)
+{
+	ad198x_init(codec);
+	ad1981_hp_automute(codec);
+	ad1981_hp_automic(codec);
+	return 0;
+}
+
+/* models */
+enum { AD1981_BASIC, AD1981_HP };
+
+static struct hda_board_config ad1981_cfg_tbl[] = {
+	{ .modelname = "hp", .config = AD1981_HP },
+	{ .pci_subvendor = 0x103c, .pci_subdevice = 0x30aa,
+	  .config = AD1981_HP }, /* HP nx6320 */
+	{ .pci_subvendor = 0x103c, .pci_subdevice = 0x309f,
+	  .config = AD1981_HP }, /* HP nx9420 AngelFire */
+	{ .modelname = "basic", .config = AD1981_BASIC },
+	{}
+};
+
 static int patch_ad1981(struct hda_codec *codec)
 {
 	struct ad198x_spec *spec;
+	int board_config;
 
 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (spec == NULL)
 		return -ENOMEM;
 
-	init_MUTEX(&spec->amp_mutex);
+	mutex_init(&spec->amp_mutex);
 	codec->spec = spec;
 
 	spec->multiout.max_channels = 2;
@@ -863,7 +1347,7 @@
 	spec->multiout.dig_out_nid = AD1981_SPDIF_OUT;
 	spec->num_adc_nids = 1;
 	spec->adc_nids = ad1981_adc_nids;
-	spec->capsrc_nids = ad1981_adc_nids;
+	spec->capsrc_nids = ad1981_capsrc_nids;
 	spec->input_mux = &ad1981_capture_source;
 	spec->num_mixers = 1;
 	spec->mixers[0] = ad1981_mixers;
@@ -873,6 +1357,21 @@
 
 	codec->patch_ops = ad198x_patch_ops;
 
+	/* override some parameters */
+	board_config = snd_hda_check_board_config(codec, ad1981_cfg_tbl);
+	switch (board_config) {
+	case AD1981_HP:
+		spec->mixers[0] = ad1981_hp_mixers;
+		spec->num_init_verbs = 2;
+		spec->init_verbs[1] = ad1981_hp_init_verbs;
+		spec->multiout.dig_out_nid = 0;
+		spec->input_mux = &ad1981_hp_capture_source;
+
+		codec->patch_ops.init = ad1981_hp_init;
+		codec->patch_ops.unsol_event = ad1981_hp_unsol_event;
+		break;
+	}
+
 	return 0;
 }
 
@@ -1060,44 +1559,6 @@
 				   spec->num_channel_mode, &spec->multiout.max_channels);
 }
 
-/*
- * EAPD control
- */
-static int ad1988_eapd_info(struct snd_kcontrol *kcontrol,
-			    struct snd_ctl_elem_info *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 ad1988_eapd_get(struct snd_kcontrol *kcontrol,
-			   struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct ad198x_spec *spec = codec->spec;
-	ucontrol->value.enumerated.item[0] = ! spec->cur_eapd;
-	return 0;
-}
-
-static int ad1988_eapd_put(struct snd_kcontrol *kcontrol,
-			   struct snd_ctl_elem_value *ucontrol)
-{
-	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct ad198x_spec *spec = codec->spec;
-	unsigned int eapd;
-	eapd = ! ucontrol->value.enumerated.item[0];
-	if (eapd == spec->cur_eapd && ! codec->in_resume)
-		return 0;
-	spec->cur_eapd = eapd;
-	snd_hda_codec_write(codec, 0x12 /* port-D */,
-			    0, AC_VERB_SET_EAPD_BTLENABLE,
-			    eapd ? 0x02 : 0x00);
-	return 0;
-}
-
 /* 6-stack mode */
 static struct snd_kcontrol_new ad1988_6stack_mixers1[] = {
 	HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
@@ -1220,9 +1681,10 @@
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "External Amplifier",
-		.info = ad1988_eapd_info,
-		.get = ad1988_eapd_get,
-		.put = ad1988_eapd_put,
+		.info = ad198x_eapd_info,
+		.get = ad198x_eapd_get,
+		.put = ad198x_eapd_put,
+		.private_value = 0x12 | (1 << 8), /* port-D, inversed */
 	},
 
 	{ } /* end */
@@ -1795,14 +2257,11 @@
 
 	idx = ad1988_pin_idx(pin);
 	nid = ad1988_idx_to_dac(codec, idx);
-	if (! spec->multiout.dac_nids[0]) {
-		/* use this as the primary output */
-		spec->multiout.dac_nids[0] = nid;
-		if (! spec->multiout.num_dacs)
-			spec->multiout.num_dacs = 1;
-	} else 
-		/* specify the DAC as the extra output */
+	/* specify the DAC as the extra output */
+	if (! spec->multiout.hp_nid)
 		spec->multiout.hp_nid = nid;
+	else
+		spec->multiout.extra_out_nid[0] = nid;
 	/* control HP volume/switch on the output mixer amp */
 	sprintf(name, "%s Playback Volume", pfx);
 	if ((err = add_control(spec, AD_CTL_WIDGET_VOL, name,
@@ -1921,7 +2380,7 @@
 	struct ad198x_spec *spec = codec->spec;
 	hda_nid_t pin;
 
-	pin = spec->autocfg.speaker_pin;
+	pin = spec->autocfg.speaker_pins[0];
 	if (pin) /* connect to front */
 		ad1988_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
 	pin = spec->autocfg.hp_pin;
@@ -1970,13 +2429,13 @@
 		return err;
 	if ((err = ad1988_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
 		return err;
-	if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin &&
-	    ! spec->autocfg.hp_pin)
+	if (! spec->autocfg.line_outs)
 		return 0; /* can't find valid BIOS pin config */
 	if ((err = ad1988_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
-	    (err = ad1988_auto_create_extra_out(codec, spec->autocfg.speaker_pin,
+	    (err = ad1988_auto_create_extra_out(codec,
+						spec->autocfg.speaker_pins[0],
 						"Speaker")) < 0 ||
-	    (err = ad1988_auto_create_extra_out(codec, spec->autocfg.speaker_pin,
+	    (err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pin,
 						"Headphone")) < 0 ||
 	    (err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
 		return err;
@@ -2032,7 +2491,7 @@
 	if (spec == NULL)
 		return -ENOMEM;
 
-	init_MUTEX(&spec->amp_mutex);
+	mutex_init(&spec->amp_mutex);
 	codec->spec = spec;
 
 	if (codec->revision_id == AD1988A_REV2)
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index b767552..4c6c9ec 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -6,6 +6,7 @@
  * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
  *                    PeiSen Hou <pshou@realtek.com.tw>
  *                    Takashi Iwai <tiwai@suse.de>
+ *                    Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
  *
  *  This driver is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -50,6 +51,7 @@
 	ALC880_UNIWILL_DIG,
 	ALC880_CLEVO,
 	ALC880_TCL_S700,
+	ALC880_LG,
 #ifdef CONFIG_SND_DEBUG
 	ALC880_TEST,
 #endif
@@ -63,6 +65,10 @@
 	ALC260_HP,
 	ALC260_HP_3013,
 	ALC260_FUJITSU_S702X,
+	ALC260_ACER,
+#ifdef CONFIG_SND_DEBUG
+	ALC260_TEST,
+#endif
 	ALC260_AUTO,
 	ALC260_MODEL_LAST /* last tag */
 };
@@ -70,6 +76,7 @@
 /* ALC262 models */
 enum {
 	ALC262_BASIC,
+	ALC262_FUJITSU,
 	ALC262_AUTO,
 	ALC262_MODEL_LAST /* last tag */
 };
@@ -132,7 +139,7 @@
 	int num_channel_mode;
 
 	/* PCM information */
-	struct hda_pcm pcm_rec[2];	/* used in alc_build_pcms() */
+	struct hda_pcm pcm_rec[3];	/* used in alc_build_pcms() */
 
 	/* dynamic controls, init_verbs and input_mux */
 	struct auto_pin_cfg autocfg;
@@ -140,6 +147,14 @@
 	struct snd_kcontrol_new *kctl_alloc;
 	struct hda_input_mux private_imux;
 	hda_nid_t private_dac_nids[5];
+
+	/* hooks */
+	void (*init_hook)(struct hda_codec *codec);
+	void (*unsol_event)(struct hda_codec *codec, unsigned int res);
+
+	/* for pin sensing */
+	unsigned int sense_updated: 1;
+	unsigned int jack_present: 1;
 };
 
 /*
@@ -158,6 +173,8 @@
 	unsigned int num_channel_mode;
 	const struct hda_channel_mode *channel_mode;
 	const struct hda_input_mux *input_mux;
+	void (*unsol_event)(struct hda_codec *, unsigned int);
+	void (*init_hook)(struct hda_codec *);
 };
 
 
@@ -218,56 +235,231 @@
 				   spec->num_channel_mode, &spec->multiout.max_channels);
 }
 
-
 /*
- * Control of pin widget settings via the mixer.  Only boolean settings are
- * supported, so VrefEn can't be controlled using these functions as they
- * stand.
+ * Control the mode of pin widget settings via the mixer.  "pc" is used
+ * instead of "%" to avoid consequences of accidently treating the % as 
+ * being part of a format specifier.  Maximum allowed length of a value is
+ * 63 characters plus NULL terminator.
+ *
+ * Note: some retasking pin complexes seem to ignore requests for input
+ * states other than HiZ (eg: PIN_VREFxx) and revert to HiZ if any of these
+ * are requested.  Therefore order this list so that this behaviour will not
+ * cause problems when mixer clients move through the enum sequentially.
+ * NIDs 0x0f and 0x10 have been observed to have this behaviour.
  */
-static int alc_pinctl_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+static char *alc_pin_mode_names[] = {
+	"Mic 50pc bias", "Mic 80pc bias",
+	"Line in", "Line out", "Headphone out",
+};
+static unsigned char alc_pin_mode_values[] = {
+	PIN_VREF50, PIN_VREF80, PIN_IN, PIN_OUT, PIN_HP,
+};
+/* The control can present all 5 options, or it can limit the options based
+ * in the pin being assumed to be exclusively an input or an output pin.
+ */
+#define ALC_PIN_DIR_IN    0x00
+#define ALC_PIN_DIR_OUT   0x01
+#define ALC_PIN_DIR_INOUT 0x02
+
+/* Info about the pin modes supported by the three different pin directions. 
+ * For each direction the minimum and maximum values are given.
+ */
+static signed char alc_pin_mode_dir_info[3][2] = {
+	{ 0, 2 },    /* ALC_PIN_DIR_IN */
+	{ 3, 4 },    /* ALC_PIN_DIR_OUT */
+	{ 0, 4 },    /* ALC_PIN_DIR_INOUT */
+};
+#define alc_pin_mode_min(_dir) (alc_pin_mode_dir_info[_dir][0])
+#define alc_pin_mode_max(_dir) (alc_pin_mode_dir_info[_dir][1])
+#define alc_pin_mode_n_items(_dir) \
+	(alc_pin_mode_max(_dir)-alc_pin_mode_min(_dir)+1)
+
+static int alc_pin_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
+	unsigned int item_num = uinfo->value.enumerated.item;
+	unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = alc_pin_mode_n_items(dir);
+
+	if (item_num<alc_pin_mode_min(dir) || item_num>alc_pin_mode_max(dir))
+		item_num = alc_pin_mode_min(dir);
+	strcpy(uinfo->value.enumerated.name, alc_pin_mode_names[item_num]);
+	return 0;
+}
+
+static int alc_pin_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+	unsigned int i;
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	hda_nid_t nid = kcontrol->private_value & 0xffff;
+	unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
+	long *valp = ucontrol->value.integer.value;
+	unsigned int pinctl = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_PIN_WIDGET_CONTROL,0x00);
+
+	/* Find enumerated value for current pinctl setting */
+	i = alc_pin_mode_min(dir);
+	while (alc_pin_mode_values[i]!=pinctl && i<=alc_pin_mode_max(dir))
+		i++;
+	*valp = i<=alc_pin_mode_max(dir)?i:alc_pin_mode_min(dir);
+	return 0;
+}
+
+static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+	signed int change;
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	hda_nid_t nid = kcontrol->private_value & 0xffff;
+	unsigned char dir = (kcontrol->private_value >> 16) & 0xff;
+	long val = *ucontrol->value.integer.value;
+	unsigned int pinctl = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_PIN_WIDGET_CONTROL,0x00);
+
+	if (val<alc_pin_mode_min(dir) || val>alc_pin_mode_max(dir)) 
+		val = alc_pin_mode_min(dir);
+
+	change = pinctl != alc_pin_mode_values[val];
+	if (change) {
+		/* Set pin mode to that requested */
+		snd_hda_codec_write(codec,nid,0,AC_VERB_SET_PIN_WIDGET_CONTROL,
+			alc_pin_mode_values[val]);
+
+		/* Also enable the retasking pin's input/output as required 
+		 * for the requested pin mode.  Enum values of 2 or less are
+		 * input modes.
+		 *
+		 * Dynamically switching the input/output buffers probably
+		 * reduces noise slightly, particularly on input.  However,
+		 * havingboth input and output buffers enabled
+		 * simultaneously doesn't seem to be problematic.
+		 */
+		if (val <= 2) {
+			snd_hda_codec_write(codec,nid,0,AC_VERB_SET_AMP_GAIN_MUTE,
+				AMP_OUT_MUTE);
+			snd_hda_codec_write(codec,nid,0,AC_VERB_SET_AMP_GAIN_MUTE,
+				AMP_IN_UNMUTE(0));
+		} else {
+			snd_hda_codec_write(codec,nid,0,AC_VERB_SET_AMP_GAIN_MUTE,
+				AMP_IN_MUTE(0));
+			snd_hda_codec_write(codec,nid,0,AC_VERB_SET_AMP_GAIN_MUTE,
+				AMP_OUT_UNMUTE);
+		}
+	}
+	return change;
+}
+
+#define ALC_PIN_MODE(xname, nid, dir) \
+	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0,  \
+	  .info = alc_pin_mode_info, \
+	  .get = alc_pin_mode_get, \
+	  .put = alc_pin_mode_put, \
+	  .private_value = nid | (dir<<16) }
+
+/* A switch control for ALC260 GPIO pins.  Multiple GPIOs can be ganged
+ * together using a mask with more than one bit set.  This control is
+ * currently used only by the ALC260 test model.  At this stage they are not
+ * needed for any "production" models.
+ */
+#ifdef CONFIG_SND_DEBUG
+static int alc_gpio_data_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *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 alc_pinctl_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+}                                
+static int alc_gpio_data_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	hda_nid_t nid = kcontrol->private_value & 0xffff;
-	long mask = (kcontrol->private_value >> 16) & 0xff;
+	unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
 	long *valp = ucontrol->value.integer.value;
+	unsigned int val = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_GPIO_DATA,0x00);
 
-	*valp = 0;
-	if (snd_hda_codec_read(codec,nid,0,AC_VERB_GET_PIN_WIDGET_CONTROL,0x00) & mask)
-		*valp = 1;
+	*valp = (val & mask) != 0;
 	return 0;
 }
+static int alc_gpio_data_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+	signed int change;
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	hda_nid_t nid = kcontrol->private_value & 0xffff;
+	unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
+	long val = *ucontrol->value.integer.value;
+	unsigned int gpio_data = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_GPIO_DATA,0x00);
 
-static int alc_pinctl_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+	/* Set/unset the masked GPIO bit(s) as needed */
+	change = (val==0?0:mask) != (gpio_data & mask);
+	if (val==0)
+		gpio_data &= ~mask;
+	else
+		gpio_data |= mask;
+	snd_hda_codec_write(codec,nid,0,AC_VERB_SET_GPIO_DATA,gpio_data);
+
+	return change;
+}
+#define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \
+	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0,  \
+	  .info = alc_gpio_data_info, \
+	  .get = alc_gpio_data_get, \
+	  .put = alc_gpio_data_put, \
+	  .private_value = nid | (mask<<16) }
+#endif   /* CONFIG_SND_DEBUG */
+
+/* A switch control to allow the enabling of the digital IO pins on the
+ * ALC260.  This is incredibly simplistic; the intention of this control is
+ * to provide something in the test model allowing digital outputs to be
+ * identified if present.  If models are found which can utilise these
+ * outputs a more complete mixer control can be devised for those models if
+ * necessary.
+ */
+#ifdef CONFIG_SND_DEBUG
+static int alc_spdif_ctrl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *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 alc_spdif_ctrl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	hda_nid_t nid = kcontrol->private_value & 0xffff;
-	long mask = (kcontrol->private_value >> 16) & 0xff;
+	unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
 	long *valp = ucontrol->value.integer.value;
-	unsigned int pinctl = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_PIN_WIDGET_CONTROL,0x00);
-	int change = ((pinctl & mask)!=0) != *valp;
+	unsigned int val = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_DIGI_CONVERT,0x00);
 
-	if (change)
-		snd_hda_codec_write(codec,nid,0,AC_VERB_SET_PIN_WIDGET_CONTROL,
-			*valp?(pinctl|mask):(pinctl&~mask));
+	*valp = (val & mask) != 0;
+	return 0;
+}
+static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+	signed int change;
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	hda_nid_t nid = kcontrol->private_value & 0xffff;
+	unsigned char mask = (kcontrol->private_value >> 16) & 0xff;
+	long val = *ucontrol->value.integer.value;
+	unsigned int ctrl_data = snd_hda_codec_read(codec,nid,0,AC_VERB_GET_DIGI_CONVERT,0x00);
+
+	/* Set/unset the masked control bit(s) as needed */
+	change = (val==0?0:mask) != (ctrl_data & mask);
+	if (val==0)
+		ctrl_data &= ~mask;
+	else
+		ctrl_data |= mask;
+	snd_hda_codec_write(codec,nid,0,AC_VERB_SET_DIGI_CONVERT_1,ctrl_data);
+
 	return change;
 }
-
-#define ALC_PINCTL_SWITCH(xname, nid, mask) \
+#define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \
 	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0,  \
-	  .info = alc_pinctl_switch_info, \
-	  .get = alc_pinctl_switch_get, \
-	  .put = alc_pinctl_switch_put, \
-	  .private_value = (nid) | (mask<<16) }
-
+	  .info = alc_spdif_ctrl_info, \
+	  .get = alc_spdif_ctrl_get, \
+	  .put = alc_spdif_ctrl_put, \
+	  .private_value = nid | (mask<<16) }
+#endif   /* CONFIG_SND_DEBUG */
 
 /*
  * set up from the preset table
@@ -296,6 +488,9 @@
 	spec->num_adc_nids = preset->num_adc_nids;
 	spec->adc_nids = preset->adc_nids;
 	spec->dig_in_nid = preset->dig_in_nid;
+
+	spec->unsol_event = preset->unsol_event;
+	spec->init_hook = preset->init_hook;
 }
 
 /*
@@ -1098,6 +1293,141 @@
 };
 
 /*
+ * LG m1 express dual
+ *
+ * Pin assignment:
+ *   Rear Line-In/Out (blue): 0x14
+ *   Build-in Mic-In: 0x15
+ *   Speaker-out: 0x17
+ *   HP-Out (green): 0x1b
+ *   Mic-In/Out (red): 0x19
+ *   SPDIF-Out: 0x1e
+ */
+
+/* To make 5.1 output working (green=Front, blue=Surr, red=CLFE) */
+static hda_nid_t alc880_lg_dac_nids[3] = {
+	0x05, 0x02, 0x03
+};
+
+/* seems analog CD is not working */
+static struct hda_input_mux alc880_lg_capture_source = {
+	.num_items = 3,
+	.items = {
+		{ "Mic", 0x1 },
+		{ "Line", 0x5 },
+		{ "Internal Mic", 0x6 },
+	},
+};
+
+/* 2,4,6 channel modes */
+static struct hda_verb alc880_lg_ch2_init[] = {
+	/* set line-in and mic-in to input */
+	{ 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+	{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+	{ }
+};
+
+static struct hda_verb alc880_lg_ch4_init[] = {
+	/* set line-in to out and mic-in to input */
+	{ 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
+	{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+	{ }
+};
+
+static struct hda_verb alc880_lg_ch6_init[] = {
+	/* set line-in and mic-in to output */
+	{ 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
+	{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
+	{ }
+};
+
+static struct hda_channel_mode alc880_lg_ch_modes[3] = {
+	{ 2, alc880_lg_ch2_init },
+	{ 4, alc880_lg_ch4_init },
+	{ 6, alc880_lg_ch6_init },
+};
+
+static struct snd_kcontrol_new alc880_lg_mixer[] = {
+	/* FIXME: it's not really "master" but front channels */
+	HDA_CODEC_VOLUME("Master Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Master Playback Switch", 0x0f, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Surround Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Surround Playback Switch", 0x0c, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
+	HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
+	HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x06, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x06, HDA_INPUT),
+	HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x07, HDA_INPUT),
+	HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x07, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Channel Mode",
+		.info = alc_ch_mode_info,
+		.get = alc_ch_mode_get,
+		.put = alc_ch_mode_put,
+	},
+	{ } /* end */
+};
+
+static struct hda_verb alc880_lg_init_verbs[] = {
+	/* set capture source to mic-in */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+	/* mute all amp mixer inputs */
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5)},
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(6)},
+	{0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(7)},
+	/* line-in to input */
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	/* built-in mic */
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	/* speaker-out */
+	{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	/* mic-in to input */
+	{0x11, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+	{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	/* HP-out */
+	{0x13, AC_VERB_SET_CONNECT_SEL, 0x03},
+	{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	/* jack sense */
+	{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1},
+	{ }
+};
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc880_lg_automute(struct hda_codec *codec)
+{
+	unsigned int present;
+
+	present = snd_hda_codec_read(codec, 0x1b, 0,
+				     AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+	snd_hda_codec_amp_update(codec, 0x17, 0, HDA_OUTPUT, 0,
+				 0x80, present ? 0x80 : 0);
+	snd_hda_codec_amp_update(codec, 0x17, 1, HDA_OUTPUT, 0,
+				 0x80, present ? 0x80 : 0);
+}
+
+static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+	/* Looks like the unsol event is incompatible with the standard
+	 * definition.  4bit tag is placed at 28 bit!
+	 */
+	if ((res >> 28) == 0x01)
+		alc880_lg_automute(codec);
+}
+
+/*
+ * Common callbacks
  */
 
 static int alc_init(struct hda_codec *codec)
@@ -1107,9 +1437,21 @@
 
 	for (i = 0; i < spec->num_init_verbs; i++)
 		snd_hda_sequence_write(codec, spec->init_verbs[i]);
+
+	if (spec->init_hook)
+		spec->init_hook(codec);
+
 	return 0;
 }
 
+static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+	struct alc_spec *spec = codec->spec;
+
+	if (spec->unsol_event)
+		spec->unsol_event(codec, res);
+}
+
 #ifdef CONFIG_PM
 /*
  * resume
@@ -1250,6 +1592,13 @@
 	/* NID is set in alc_build_pcms */
 };
 
+/* Used by alc_build_pcms to flag that a PCM has no playback stream */
+static struct hda_pcm_stream alc_pcm_null_playback = {
+	.substreams = 0,
+	.channels_min = 0,
+	.channels_max = 0,
+};
+
 static int alc_build_pcms(struct hda_codec *codec)
 {
 	struct alc_spec *spec = codec->spec;
@@ -1280,6 +1629,23 @@
 		}
 	}
 
+	/* If the use of more than one ADC is requested for the current
+	 * model, configure a second analog capture-only PCM.
+	 */
+	if (spec->num_adc_nids > 1) {
+		codec->num_pcms++;
+		info++;
+		info->name = spec->stream_name_analog;
+		/* No playback stream for second PCM */
+		info->stream[SNDRV_PCM_STREAM_PLAYBACK] = alc_pcm_null_playback;
+		info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
+		if (spec->stream_analog_capture) {
+			snd_assert(spec->adc_nids, return -EINVAL);
+			info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture);
+			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[1];
+		}
+	}
+
 	if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
 		codec->num_pcms++;
 		info++;
@@ -1322,6 +1688,7 @@
 	.build_pcms = alc_build_pcms,
 	.init = alc_init,
 	.free = alc_free,
+	.unsol_event = alc_unsol_event,
 #ifdef CONFIG_PM
 	.resume = alc_resume,
 #endif
@@ -1340,13 +1707,15 @@
 };
 
 static struct hda_input_mux alc880_test_capture_source = {
-	.num_items = 5,
+	.num_items = 7,
 	.items = {
 		{ "In-1", 0x0 },
 		{ "In-2", 0x1 },
 		{ "In-3", 0x2 },
 		{ "In-4", 0x3 },
 		{ "CD", 0x4 },
+		{ "Front", 0x5 },
+		{ "Surround", 0x6 },
 	},
 };
 
@@ -1653,6 +2022,8 @@
 	{ .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 = 0xa0a0, .pci_subdevice = 0x0560,
+	  .config = ALC880_5ST_DIG }, /* Aopen i915GMm-HFS */
 	/* { .pci_subvendor = 0x1019, .pci_subdevice = 0xa884, .config = ALC880_5ST_DIG }, */ /* conflict with 6stack */
 	{ .pci_subvendor = 0x1695, .pci_subdevice = 0x400d, .config = ALC880_5ST_DIG },
 	/* note subvendor = 0 below */
@@ -1680,6 +2051,7 @@
 	{ .pci_subvendor = 0x1025, .pci_subdevice = 0x0078, .config = ALC880_6ST_DIG },
 	{ .pci_subvendor = 0x1025, .pci_subdevice = 0x0087, .config = ALC880_6ST_DIG },
 	{ .pci_subvendor = 0x1297, .pci_subdevice = 0xc790, .config = ALC880_6ST_DIG }, /* Shuttle ST20G5 */
+	{ .pci_subvendor = 0x1509, .pci_subdevice = 0x925d, .config = ALC880_6ST_DIG }, /* FIC P4M-915GD1 */
 
 	{ .modelname = "asus", .config = ALC880_ASUS },
 	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1964, .config = ALC880_ASUS_DIG },
@@ -1693,6 +2065,7 @@
 	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1123, .config = ALC880_ASUS_DIG },
 	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x1143, .config = ALC880_ASUS },
 	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x10b3, .config = ALC880_ASUS_W1V },
+	{ .pci_subvendor = 0x1043, .pci_subdevice = 0x8181, .config = ALC880_ASUS_DIG }, /* ASUS P4GPL-X */
 	{ .pci_subvendor = 0x1558, .pci_subdevice = 0x5401, .config = ALC880_ASUS_DIG2 },
 
 	{ .modelname = "uniwill", .config = ALC880_UNIWILL_DIG },
@@ -1702,6 +2075,9 @@
 	{ .pci_subvendor = 0x1734, .pci_subdevice = 0x107c, .config = ALC880_F1734 },
 	{ .pci_subvendor = 0x1584, .pci_subdevice = 0x9054, .config = ALC880_F1734 },
 
+	{ .modelname = "lg", .config = ALC880_LG },
+	{ .pci_subvendor = 0x1854, .pci_subdevice = 0x003b, .config = ALC880_LG },
+
 #ifdef CONFIG_SND_DEBUG
 	{ .modelname = "test", .config = ALC880_TEST },
 #endif
@@ -1879,6 +2255,19 @@
 		.channel_mode = alc880_threestack_modes,
 		.input_mux = &alc880_capture_source,
 	},
+	[ALC880_LG] = {
+		.mixers = { alc880_lg_mixer },
+		.init_verbs = { alc880_volume_init_verbs,
+				alc880_lg_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc880_lg_dac_nids),
+		.dac_nids = alc880_lg_dac_nids,
+		.dig_out_nid = ALC880_DIGOUT_NID,
+		.num_channel_mode = ARRAY_SIZE(alc880_lg_ch_modes),
+		.channel_mode = alc880_lg_ch_modes,
+		.input_mux = &alc880_lg_capture_source,
+		.unsol_event = alc880_lg_unsol_event,
+		.init_hook = alc880_lg_automute,
+	},
 #ifdef CONFIG_SND_DEBUG
 	[ALC880_TEST] = {
 		.mixers = { alc880_test_mixer },
@@ -2043,14 +2432,11 @@
 
 	if (alc880_is_fixed_pin(pin)) {
 		nid = alc880_idx_to_dac(alc880_fixed_pin_idx(pin));
-		if (! spec->multiout.dac_nids[0]) {
-			/* use this as the primary output */
-			spec->multiout.dac_nids[0] = nid;
-			if (! spec->multiout.num_dacs)
-				spec->multiout.num_dacs = 1;
-		} else 
-			/* specify the DAC as the extra output */
+		/* specify the DAC as the extra output */
+		if (! spec->multiout.hp_nid)
 			spec->multiout.hp_nid = nid;
+		else
+			spec->multiout.extra_out_nid[0] = nid;
 		/* control HP volume/switch on the output mixer amp */
 		nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin));
 		sprintf(name, "%s Playback Volume", pfx);
@@ -2063,12 +2449,6 @@
 			return err;
 	} else if (alc880_is_multi_pin(pin)) {
 		/* set manual connection */
-		if (! spec->multiout.dac_nids[0]) {
-			/* use this as the primary output */
-			spec->multiout.dac_nids[0] = alc880_idx_to_dac(alc880_multi_pin_idx(pin));
-			if (! spec->multiout.num_dacs)
-				spec->multiout.num_dacs = 1;
-		}
 		/* we have only a switch on HP-out PIN */
 		sprintf(name, "%s Playback Switch", pfx);
 		if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
@@ -2152,7 +2532,7 @@
 	struct alc_spec *spec = codec->spec;
 	hda_nid_t pin;
 
-	pin = spec->autocfg.speaker_pin;
+	pin = spec->autocfg.speaker_pins[0];
 	if (pin) /* connect to front */
 		alc880_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
 	pin = spec->autocfg.hp_pin;
@@ -2188,15 +2568,15 @@
 	if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 						alc880_ignore)) < 0)
 		return err;
-	if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin &&
-	    ! spec->autocfg.hp_pin)
+	if (! spec->autocfg.line_outs)
 		return 0; /* can't find valid BIOS pin config */
 
 	if ((err = alc880_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 ||
 	    (err = alc880_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
-	    (err = alc880_auto_create_extra_out(spec, spec->autocfg.speaker_pin,
+	    (err = alc880_auto_create_extra_out(spec,
+						spec->autocfg.speaker_pins[0],
 						"Speaker")) < 0 ||
-	    (err = alc880_auto_create_extra_out(spec, spec->autocfg.speaker_pin,
+	    (err = alc880_auto_create_extra_out(spec, spec->autocfg.hp_pin,
 						"Headphone")) < 0 ||
 	    (err = alc880_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
 		return err;
@@ -2218,14 +2598,12 @@
 	return 1;
 }
 
-/* init callback for auto-configuration model -- overriding the default init */
-static int alc880_auto_init(struct hda_codec *codec)
+/* additional initialization for auto-configuration model */
+static void alc880_auto_init(struct hda_codec *codec)
 {
-	alc_init(codec);
 	alc880_auto_init_multi_out(codec);
 	alc880_auto_init_extra_out(codec);
 	alc880_auto_init_analog_input(codec);
-	return 0;
 }
 
 /*
@@ -2292,7 +2670,7 @@
 
 	codec->patch_ops = alc_patch_ops;
 	if (board_config == ALC880_AUTO)
-		codec->patch_ops.init = alc880_auto_init;
+		spec->init_hook = alc880_auto_init;
 
 	return 0;
 }
@@ -2322,6 +2700,14 @@
 	0x05, 0x04
 };
 
+/* NIDs used when simultaneous access to both ADCs makes sense.  Note that
+ * alc260_capture_mixer assumes ADC0 (nid 0x04) is the first ADC.
+ */
+static hda_nid_t alc260_dual_adc_nids[2] = {
+	/* ADC0, ADC1 */
+	0x04, 0x05
+};
+
 #define ALC260_DIGOUT_NID	0x03
 #define ALC260_DIGIN_NID	0x06
 
@@ -2335,14 +2721,28 @@
 	},
 };
 
-/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack
- * and the internal CD lines.
+/* On Fujitsu S702x laptops capture only makes sense from Mic/LineIn jack,
+ * headphone jack and the internal CD lines.
  */
 static struct hda_input_mux alc260_fujitsu_capture_source = {
-	.num_items = 2,
+	.num_items = 3,
 	.items = {
 		{ "Mic/Line", 0x0 },
 		{ "CD", 0x4 },
+		{ "Headphone", 0x2 },
+	},
+};
+
+/* Acer TravelMate(/Extensa/Aspire) notebooks have similar configutation to
+ * the Fujitsu S702x, but jacks are marked differently. We won't allow
+ * retasking the Headphone jack, so it won't be available here.
+ */
+static struct hda_input_mux alc260_acer_capture_source = {
+	.num_items = 3,
+	.items = {
+		{ "Mic", 0x0 },
+		{ "Line", 0x2 },
+		{ "CD", 0x4 },
 	},
 };
 
@@ -2363,6 +2763,7 @@
  * HP: base_output + input + capture_alt
  * HP_3013: hp_3013 + input + capture
  * fujitsu: fujitsu + capture
+ * acer: acer + capture
  */
 
 static struct snd_kcontrol_new alc260_base_output_mixer[] = {
@@ -2408,11 +2809,12 @@
 static struct snd_kcontrol_new alc260_fujitsu_mixer[] = {
 	HDA_CODEC_VOLUME("Headphone Playback Volume", 0x08, 0x0, HDA_OUTPUT),
 	HDA_BIND_MUTE("Headphone Playback Switch", 0x08, 2, HDA_INPUT),
-	ALC_PINCTL_SWITCH("Headphone Amp Switch", 0x14, PIN_HP_AMP),
+	ALC_PIN_MODE("Headphone Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
 	HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
 	HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
 	HDA_CODEC_VOLUME("Mic/Line Playback Volume", 0x07, 0x0, HDA_INPUT),
 	HDA_CODEC_MUTE("Mic/Line Playback Switch", 0x07, 0x0, HDA_INPUT),
+	ALC_PIN_MODE("Mic/Line Jack Mode", 0x12, ALC_PIN_DIR_IN),
 	HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
 	HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
 	HDA_CODEC_VOLUME("Internal Speaker Playback Volume", 0x09, 0x0, HDA_OUTPUT),
@@ -2420,6 +2822,22 @@
 	{ } /* end */
 };
 
+static struct snd_kcontrol_new alc260_acer_mixer[] = {
+	HDA_CODEC_VOLUME("Master Playback Volume", 0x08, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("Master Playback Switch", 0x08, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x07, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x07, 0x0, HDA_INPUT),
+	ALC_PIN_MODE("Mic Jack Mode", 0x12, ALC_PIN_DIR_IN),
+	HDA_CODEC_VOLUME("Line Playback Volume", 0x07, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("Line Playback Switch", 0x07, 0x02, HDA_INPUT),
+	ALC_PIN_MODE("Line Jack Mode", 0x14, ALC_PIN_DIR_INOUT),
+	HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
+	HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
+	{ } /* end */
+};
+
 /* capture mixer elements */
 static struct snd_kcontrol_new alc260_capture_mixer[] = {
 	HDA_CODEC_VOLUME("Capture Volume", 0x04, 0x0, HDA_INPUT),
@@ -2629,52 +3047,327 @@
 	{0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
 	/* Headphone/Line-out jack connects to Line1 pin; make it an output */
 	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
-        /* Mic/Line-in jack is connected to mic1 pin, so make it an input */
-        {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
-        /* Ensure all other unused pins are disabled and muted.
-	 * Note: trying to set widget 0x15 to anything blocks all audio
-	 * output for some reason, so just leave that at the default.
-	 */
-        {0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-        {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	/* Mic/Line-in jack is connected to mic1 pin, so make it an input */
+	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	/* Ensure all other unused pins are disabled and muted. */
+	{0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-        {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-        {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-        /* Disable digital (SPDIF) pins */
-        {0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
-        {0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
+	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
 
-        /* Start with mixer outputs muted */
-        {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-        {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
-        {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+	/* Disable digital (SPDIF) pins */
+	{0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
+	{0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
 
-        /* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
-        {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-        /* Unmute Line1 pin widget amp left and right (no equiv mixer ctrl) */
-        {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
-	/* Unmute pin widget used for Line-in (no equiv mixer ctrl) */
-        {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	/* Ensure Line1 pin widget takes its input from the OUT1 sum bus 
+	 * when acting as an output.
+	 */
+	{0x0d, AC_VERB_SET_CONNECT_SEL, 0},
 
-        /* Mute capture amp left and right */
-        {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
-        /* Set ADC connection select to line in (on mic1 pin) */
-        {0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
+	/* Start with output sum widgets muted and their output gains at min */
+	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
 
-        /* Mute all inputs to mixer widget (even unconnected ones) */
-        {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
-        {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
-        {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
-        {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
-        {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
-        {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
-        {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
-        {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
+	/* Unmute HP pin widget amp left and right (no equiv mixer ctrl) */
+	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	/* Unmute Line1 pin widget output buffer since it starts as an output.
+	 * If the pin mode is changed by the user the pin mode control will
+	 * take care of enabling the pin's input/output buffers as needed.
+	 * Therefore there's no need to enable the input buffer at this
+	 * stage.
+	 */
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	/* Unmute input buffer of pin widget used for Line-in (no equiv 
+	 * mixer ctrl)
+	 */
+	{0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+	/* Mute capture amp left and right */
+	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	/* Set ADC connection select to match default mixer setting - line 
+	 * in (on mic1 pin)
+	 */
+	{0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+	/* Do the same for the second ADC: mute capture input amp and
+	 * set ADC connection to line in (on mic1 pin)
+	 */
+	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+	/* Mute all inputs to mixer widget (even unconnected ones) */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
 
 	{ }
 };
 
+/* Initialisation sequence for ALC260 as configured in Acer TravelMate and
+ * similar laptops (adapted from Fujitsu init verbs).
+ */
+static struct hda_verb alc260_acer_init_verbs[] = {
+	/* On TravelMate laptops, GPIO 0 enables the internal speaker and
+	 * the headphone jack.  Turn this on and rely on the standard mute
+	 * methods whenever the user wants to turn these outputs off.
+	 */
+	{0x01, AC_VERB_SET_GPIO_MASK, 0x01},
+	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
+	{0x01, AC_VERB_SET_GPIO_DATA, 0x01},
+	/* Internal speaker/Headphone jack is connected to Line-out pin */
+	{0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	/* Internal microphone/Mic jack is connected to Mic1 pin */
+	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50},
+	/* Line In jack is connected to Line1 pin */
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+	/* Ensure all other unused pins are disabled and muted. */
+	{0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	/* Disable digital (SPDIF) pins */
+	{0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
+	{0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
+
+	/* Ensure Mic1 and Line1 pin widgets take input from the OUT1 sum 
+	 * bus when acting as outputs.
+	 */
+	{0x0b, AC_VERB_SET_CONNECT_SEL, 0},
+	{0x0d, AC_VERB_SET_CONNECT_SEL, 0},
+
+	/* Start with output sum widgets muted and their output gains at min */
+	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+	/* Unmute Line-out pin widget amp left and right (no equiv mixer ctrl) */
+	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	/* Unmute Mic1 and Line1 pin widget input buffers since they start as
+	 * inputs. If the pin mode is changed by the user the pin mode control
+	 * will take care of enabling the pin's input/output buffers as needed.
+	 * Therefore there's no need to enable the input buffer at this
+	 * stage.
+	 */
+	{0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+	/* Mute capture amp left and right */
+	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	/* Set ADC connection select to match default mixer setting - mic
+	 * (on mic1 pin)
+	 */
+	{0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+	/* Do similar with the second ADC: mute capture input amp and
+	 * set ADC connection to line (on line1 pin)
+	 */
+	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x05, AC_VERB_SET_CONNECT_SEL, 0x02},
+
+	/* Mute all inputs to mixer widget (even unconnected ones) */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
+
+	{ }
+};
+
+/* Test configuration for debugging, modelled after the ALC880 test
+ * configuration.
+ */
+#ifdef CONFIG_SND_DEBUG
+static hda_nid_t alc260_test_dac_nids[1] = {
+	0x02,
+};
+static hda_nid_t alc260_test_adc_nids[2] = {
+	0x04, 0x05,
+};
+/* This is a bit messy since the two input muxes in the ALC260 have slight
+ * variations in their signal assignments.  The ideal way to deal with this
+ * is to extend alc_spec.input_mux to allow a different input MUX for each
+ * ADC.  For the purposes of the test model it's sufficient to just list
+ * both options for affected signal indices.  The separate input mux
+ * functionality only needs to be considered if a model comes along which
+ * actually uses signals 0x5, 0x6 and 0x7 for something which makes sense to
+ * record.
+ */
+static struct hda_input_mux alc260_test_capture_source = {
+	.num_items = 8,
+	.items = {
+		{ "MIC1 pin", 0x0 },
+		{ "MIC2 pin", 0x1 },
+		{ "LINE1 pin", 0x2 },
+		{ "LINE2 pin", 0x3 },
+		{ "CD pin", 0x4 },
+		{ "LINE-OUT pin (cap1), Mixer (cap2)", 0x5 },
+		{ "HP-OUT pin (cap1), LINE-OUT pin (cap2)", 0x6 },
+		{ "HP-OUT pin (cap2 only)", 0x7 },
+        },
+};
+static struct snd_kcontrol_new alc260_test_mixer[] = {
+	/* Output driver widgets */
+	HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE_MONO("Mono Playback Switch", 0x0a, 1, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("LOUT2 Playback Volume", 0x09, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("LOUT2 Playback Switch", 0x09, 2, HDA_INPUT),
+	HDA_CODEC_VOLUME("LOUT1 Playback Volume", 0x08, 0x0, HDA_OUTPUT),
+	HDA_BIND_MUTE("LOUT1 Playback Switch", 0x08, 2, HDA_INPUT),
+
+	/* Modes for retasking pin widgets */
+	ALC_PIN_MODE("HP-OUT pin mode", 0x10, ALC_PIN_DIR_INOUT),
+	ALC_PIN_MODE("LINE-OUT pin mode", 0x0f, ALC_PIN_DIR_INOUT),
+	ALC_PIN_MODE("LINE2 pin mode", 0x15, ALC_PIN_DIR_INOUT),
+	ALC_PIN_MODE("LINE1 pin mode", 0x14, ALC_PIN_DIR_INOUT),
+	ALC_PIN_MODE("MIC2 pin mode", 0x13, ALC_PIN_DIR_INOUT),
+	ALC_PIN_MODE("MIC1 pin mode", 0x12, ALC_PIN_DIR_INOUT),
+
+	/* Loopback mixer controls */
+	HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x07, 0x00, HDA_INPUT),
+	HDA_CODEC_MUTE("MIC1 Playback Switch", 0x07, 0x00, HDA_INPUT),
+	HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x07, 0x01, HDA_INPUT),
+	HDA_CODEC_MUTE("MIC2 Playback Switch", 0x07, 0x01, HDA_INPUT),
+	HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x07, 0x02, HDA_INPUT),
+	HDA_CODEC_MUTE("LINE1 Playback Switch", 0x07, 0x02, HDA_INPUT),
+	HDA_CODEC_VOLUME("LINE2 Playback Volume", 0x07, 0x03, HDA_INPUT),
+	HDA_CODEC_MUTE("LINE2 Playback Switch", 0x07, 0x03, HDA_INPUT),
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x07, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x07, 0x04, HDA_INPUT),
+	HDA_CODEC_VOLUME("Beep Playback Volume", 0x07, 0x05, HDA_INPUT),
+	HDA_CODEC_MUTE("Beep Playback Switch", 0x07, 0x05, HDA_INPUT),
+	HDA_CODEC_VOLUME("LINE-OUT loopback Playback Volume", 0x07, 0x06, HDA_INPUT),
+	HDA_CODEC_MUTE("LINE-OUT loopback Playback Switch", 0x07, 0x06, HDA_INPUT),
+	HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x07, 0x7, HDA_INPUT),
+	HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x07, 0x7, HDA_INPUT),
+
+	/* Controls for GPIO pins, assuming they are configured as outputs */
+	ALC_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01),
+	ALC_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02),
+	ALC_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04),
+	ALC_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08),
+
+	/* Switches to allow the digital IO pins to be enabled.  The datasheet
+	 * is ambigious as to which NID is which; testing on laptops which
+	 * make this output available should provide clarification. 
+	 */
+	ALC_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x03, 0x01),
+	ALC_SPDIF_CTRL_SWITCH("SPDIF Capture Switch", 0x06, 0x01),
+
+	{ } /* end */
+};
+static struct hda_verb alc260_test_init_verbs[] = {
+	/* Enable all GPIOs as outputs with an initial value of 0 */
+	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f},
+	{0x01, AC_VERB_SET_GPIO_DATA, 0x00},
+	{0x01, AC_VERB_SET_GPIO_MASK, 0x0f},
+
+	/* Enable retasking pins as output, initially without power amp */
+	{0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+	{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+
+	/* Disable digital (SPDIF) pins initially, but users can enable
+	 * them via a mixer switch.  In the case of SPDIF-out, this initverb
+	 * payload also sets the generation to 0, output to be in "consumer"
+	 * PCM format, copyright asserted, no pre-emphasis and no validity
+	 * control.
+	 */
+	{0x03, AC_VERB_SET_DIGI_CONVERT_1, 0},
+	{0x06, AC_VERB_SET_DIGI_CONVERT_1, 0},
+
+	/* Ensure mic1, mic2, line1 and line2 pin widgets take input from the 
+	 * OUT1 sum bus when acting as an output.
+	 */
+	{0x0b, AC_VERB_SET_CONNECT_SEL, 0},
+	{0x0c, AC_VERB_SET_CONNECT_SEL, 0},
+	{0x0d, AC_VERB_SET_CONNECT_SEL, 0},
+	{0x0e, AC_VERB_SET_CONNECT_SEL, 0},
+
+	/* Start with output sum widgets muted and their output gains at min */
+	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+	{0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+
+	/* Unmute retasking pin widget output buffers since the default
+	 * state appears to be output.  As the pin mode is changed by the
+	 * user the pin mode control will take care of enabling the pin's
+	 * input/output buffers as needed.
+	 */
+	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	{0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+	/* Also unmute the mono-out pin widget */
+	{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+	/* Mute capture amp left and right */
+	{0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	/* Set ADC connection select to match default mixer setting (mic1
+	 * pin)
+	 */
+	{0x04, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+	/* Do the same for the second ADC: mute capture input amp and
+	 * set ADC connection to mic1 pin
+	 */
+	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+	{0x05, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+	/* Mute all inputs to mixer widget (even unconnected ones) */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
+
+	{ }
+};
+#endif
+
 static struct hda_pcm_stream alc260_pcm_analog_playback = {
 	.substreams = 1,
 	.channels_min = 2,
@@ -2744,7 +3437,7 @@
 			return err;
 	}
 
-	nid = cfg->speaker_pin;
+	nid = cfg->speaker_pins[0];
 	if (nid) {
 		err = alc260_add_playback_controls(spec, nid, "Speaker");
 		if (err < 0)
@@ -2817,7 +3510,7 @@
 	if (nid)
 		alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
 	
-	nid = spec->autocfg.speaker_pin;
+	nid = spec->autocfg.speaker_pins[0];
 	if (nid)
 		alc260_auto_set_output_and_unmute(codec, nid, PIN_OUT, 0);
 
@@ -2932,13 +3625,11 @@
 	return 1;
 }
 
-/* init callback for auto-configuration model -- overriding the default init */
-static int alc260_auto_init(struct hda_codec *codec)
+/* additional initialization for auto-configuration model */
+static void alc260_auto_init(struct hda_codec *codec)
 {
-	alc_init(codec);
 	alc260_auto_init_multi_out(codec);
 	alc260_auto_init_analog_input(codec);
-	return 0;
 }
 
 /*
@@ -2948,6 +3639,8 @@
 	{ .modelname = "basic", .config = ALC260_BASIC },
 	{ .pci_subvendor = 0x104d, .pci_subdevice = 0x81bb,
 	  .config = ALC260_BASIC }, /* Sony VAIO */
+	{ .pci_subvendor = 0x152d, .pci_subdevice = 0x0729,
+	  .config = ALC260_BASIC }, /* CTL Travel Master U553W */
 	{ .modelname = "hp", .config = ALC260_HP },
 	{ .pci_subvendor = 0x103c, .pci_subdevice = 0x3010, .config = ALC260_HP },
 	{ .pci_subvendor = 0x103c, .pci_subdevice = 0x3011, .config = ALC260_HP },
@@ -2958,6 +3651,11 @@
 	{ .pci_subvendor = 0x103c, .pci_subdevice = 0x3016, .config = ALC260_HP },
 	{ .modelname = "fujitsu", .config = ALC260_FUJITSU_S702X },
 	{ .pci_subvendor = 0x10cf, .pci_subdevice = 0x1326, .config = ALC260_FUJITSU_S702X },
+	{ .modelname = "acer", .config = ALC260_ACER },
+	{ .pci_subvendor = 0x1025, .pci_subdevice = 0x008f, .config = ALC260_ACER },
+#ifdef CONFIG_SND_DEBUG
+	{ .modelname = "test", .config = ALC260_TEST },
+#endif
 	{ .modelname = "auto", .config = ALC260_AUTO },
 	{}
 };
@@ -3009,12 +3707,38 @@
 		.init_verbs = { alc260_fujitsu_init_verbs },
 		.num_dacs = ARRAY_SIZE(alc260_dac_nids),
 		.dac_nids = alc260_dac_nids,
-		.num_adc_nids = ARRAY_SIZE(alc260_adc_nids),
-		.adc_nids = alc260_adc_nids,
+		.num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
+		.adc_nids = alc260_dual_adc_nids,
 		.num_channel_mode = ARRAY_SIZE(alc260_modes),
 		.channel_mode = alc260_modes,
 		.input_mux = &alc260_fujitsu_capture_source,
 	},
+	[ALC260_ACER] = {
+		.mixers = { alc260_acer_mixer,
+			    alc260_capture_mixer },
+		.init_verbs = { alc260_acer_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc260_dac_nids),
+		.dac_nids = alc260_dac_nids,
+		.num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids),
+		.adc_nids = alc260_dual_adc_nids,
+		.num_channel_mode = ARRAY_SIZE(alc260_modes),
+		.channel_mode = alc260_modes,
+		.input_mux = &alc260_acer_capture_source,
+	},
+#ifdef CONFIG_SND_DEBUG
+	[ALC260_TEST] = {
+		.mixers = { alc260_test_mixer,
+			    alc260_capture_mixer },
+		.init_verbs = { alc260_test_init_verbs },
+		.num_dacs = ARRAY_SIZE(alc260_test_dac_nids),
+		.dac_nids = alc260_test_dac_nids,
+		.num_adc_nids = ARRAY_SIZE(alc260_test_adc_nids),
+		.adc_nids = alc260_test_adc_nids,
+		.num_channel_mode = ARRAY_SIZE(alc260_modes),
+		.channel_mode = alc260_modes,
+		.input_mux = &alc260_test_capture_source,
+	},
+#endif
 };
 
 static int patch_alc260(struct hda_codec *codec)
@@ -3059,7 +3783,7 @@
 
 	codec->patch_ops = alc_patch_ops;
 	if (board_config == ALC260_AUTO)
-		codec->patch_ops.init = alc260_auto_init;
+		spec->init_hook = alc260_auto_init;
 
 	return 0;
 }
@@ -3534,14 +4258,12 @@
 	return err;
 }
 
-/* init callback for auto-configuration model -- overriding the default init */
-static int alc882_auto_init(struct hda_codec *codec)
+/* additional initialization for auto-configuration model */
+static void alc882_auto_init(struct hda_codec *codec)
 {
-	alc_init(codec);
 	alc882_auto_init_multi_out(codec);
 	alc882_auto_init_hp_out(codec);
 	alc882_auto_init_analog_input(codec);
-	return 0;
 }
 
 /*
@@ -3608,7 +4330,7 @@
 
 	codec->patch_ops = alc_patch_ops;
 	if (board_config == ALC882_AUTO)
-		codec->patch_ops.init = alc882_auto_init;
+		spec->init_hook = alc882_auto_init;
 
 	return 0;
 }
@@ -3644,19 +4366,9 @@
 	HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
 	HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
 	HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x16, 2, 0x0, HDA_OUTPUT),
-	HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
-	HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
-	{
-		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-		.name = "Capture Source",
-		.count = 1,
-		.info = alc882_mux_enum_info,
-		.get = alc882_mux_enum_get,
-		.put = alc882_mux_enum_put,
-	},
 	{ } /* end */
-};			
-	
+};
+
 #define alc262_capture_mixer		alc882_capture_mixer
 #define alc262_capture_alt_mixer	alc882_capture_alt_mixer
 
@@ -3739,6 +4451,129 @@
 	{ }
 };
 
+/*
+ * fujitsu model
+ *  0x14 = headphone/spdif-out, 0x15 = internal speaker
+ */
+
+#define ALC_HP_EVENT	0x37
+
+static struct hda_verb alc262_fujitsu_unsol_verbs[] = {
+	{0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC_HP_EVENT},
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+	{}
+};
+
+static struct hda_input_mux alc262_fujitsu_capture_source = {
+	.num_items = 2,
+	.items = {
+		{ "Mic", 0x0 },
+		{ "CD", 0x4 },
+	},
+};
+
+/* mute/unmute internal speaker according to the hp jack and mute state */
+static void alc262_fujitsu_automute(struct hda_codec *codec, int force)
+{
+	struct alc_spec *spec = codec->spec;
+	unsigned int mute;
+
+	if (force || ! spec->sense_updated) {
+		unsigned int present;
+		/* need to execute and sync at first */
+		snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0);
+		present = snd_hda_codec_read(codec, 0x14, 0,
+				    	 AC_VERB_GET_PIN_SENSE, 0);
+		spec->jack_present = (present & 0x80000000) != 0;
+		spec->sense_updated = 1;
+	}
+	if (spec->jack_present) {
+		/* mute internal speaker */
+		snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
+					 0x80, 0x80);
+		snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
+					 0x80, 0x80);
+	} else {
+		/* unmute internal speaker if necessary */
+		mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0);
+		snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0,
+					 0x80, mute & 0x80);
+		mute = snd_hda_codec_amp_read(codec, 0x14, 1, HDA_OUTPUT, 0);
+		snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0,
+					 0x80, mute & 0x80);
+	}
+}
+
+/* unsolicited event for HP jack sensing */
+static void alc262_fujitsu_unsol_event(struct hda_codec *codec,
+				       unsigned int res)
+{
+	if ((res >> 26) != ALC_HP_EVENT)
+		return;
+	alc262_fujitsu_automute(codec, 1);
+}
+
+/* bind volumes of both NID 0x0c and 0x0d */
+static int alc262_fujitsu_master_vol_put(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	long *valp = ucontrol->value.integer.value;
+	int change;
+
+	change = snd_hda_codec_amp_update(codec, 0x0c, 0, HDA_OUTPUT, 0,
+					  0x7f, valp[0] & 0x7f);
+	change |= snd_hda_codec_amp_update(codec, 0x0c, 1, HDA_OUTPUT, 0,
+					   0x7f, valp[1] & 0x7f);
+	snd_hda_codec_amp_update(codec, 0x0d, 0, HDA_OUTPUT, 0,
+				 0x7f, valp[0] & 0x7f);
+	snd_hda_codec_amp_update(codec, 0x0d, 1, HDA_OUTPUT, 0,
+				 0x7f, valp[1] & 0x7f);
+	return change;
+}
+
+/* bind hp and internal speaker mute (with plug check) */
+static int alc262_fujitsu_master_sw_put(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	long *valp = ucontrol->value.integer.value;
+	int change;
+
+	change = snd_hda_codec_amp_update(codec, 0x14, 0, HDA_OUTPUT, 0,
+					  0x80, valp[0] ? 0 : 0x80);
+	change |= snd_hda_codec_amp_update(codec, 0x14, 1, HDA_OUTPUT, 0,
+					   0x80, valp[1] ? 0 : 0x80);
+	if (change || codec->in_resume)
+		alc262_fujitsu_automute(codec, codec->in_resume);
+	return change;
+}
+
+static struct snd_kcontrol_new alc262_fujitsu_mixer[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Volume",
+		.info = snd_hda_mixer_amp_volume_info,
+		.get = snd_hda_mixer_amp_volume_get,
+		.put = alc262_fujitsu_master_vol_put,
+		.private_value = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT),
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Switch",
+		.info = snd_hda_mixer_amp_switch_info,
+		.get = snd_hda_mixer_amp_switch_get,
+		.put = alc262_fujitsu_master_sw_put,
+		.private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT),
+	},
+	HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+	HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+	HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+	{ } /* end */
+};
+
 /* add playback controls from the parsed DAC table */
 static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg)
 {
@@ -3759,7 +4594,7 @@
 			return err;
 	}
 
-	nid = cfg->speaker_pin;
+	nid = cfg->speaker_pins[0];
 	if (nid) {
 		if (nid == 0x16) {
 			if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Speaker Playback Volume",
@@ -3769,10 +4604,6 @@
 					       HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0)
 				return err;
 		} else {
-			if (! cfg->line_out_pins[0])
-				if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Speaker Playback Volume",
-					       HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT))) < 0)
-					return err;
 			if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Speaker Playback Switch",
 					       HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
 				return err;
@@ -3789,10 +4620,6 @@
 					       HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT))) < 0)
 				return err;
 		} else {
-			if (! cfg->line_out_pins[0])
-				if ((err = add_control(spec, ALC_CTL_WIDGET_VOL, "Headphone Playback Volume",
-					       HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT))) < 0)
-					return err;
 			if ((err = add_control(spec, ALC_CTL_WIDGET_MUTE, "Headphone Playback Switch",
 					       HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT))) < 0)
 				return err;
@@ -3886,8 +4713,7 @@
 	if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 						alc262_ignore)) < 0)
 		return err;
-	if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin &&
-	    ! spec->autocfg.hp_pin)
+	if (! spec->autocfg.line_outs)
 		return 0; /* can't find valid BIOS pin config */
 	if ((err = alc262_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
 	    (err = alc262_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
@@ -3915,13 +4741,11 @@
 
 
 /* init callback for auto-configuration model -- overriding the default init */
-static int alc262_auto_init(struct hda_codec *codec)
+static void alc262_auto_init(struct hda_codec *codec)
 {
-	alc_init(codec);
 	alc262_auto_init_multi_out(codec);
 	alc262_auto_init_hp_out(codec);
 	alc262_auto_init_analog_input(codec);
-	return 0;
 }
 
 /*
@@ -3929,6 +4753,8 @@
  */
 static struct hda_board_config alc262_cfg_tbl[] = {
 	{ .modelname = "basic", .config = ALC262_BASIC },
+	{ .modelname = "fujitsu", .config = ALC262_FUJITSU },
+	{ .pci_subvendor = 0x10cf, .pci_subdevice = 0x1397, .config = ALC262_FUJITSU },
 	{ .modelname = "auto", .config = ALC262_AUTO },
 	{}
 };
@@ -3944,6 +4770,18 @@
 		.channel_mode = alc262_modes,
 		.input_mux = &alc262_capture_source,
 	},
+	[ALC262_FUJITSU] = {
+		.mixers = { alc262_fujitsu_mixer },
+		.init_verbs = { alc262_init_verbs, alc262_fujitsu_unsol_verbs },
+		.num_dacs = ARRAY_SIZE(alc262_dac_nids),
+		.dac_nids = alc262_dac_nids,
+		.hp_nid = 0x03,
+		.dig_out_nid = ALC262_DIGOUT_NID,
+		.num_channel_mode = ARRAY_SIZE(alc262_modes),
+		.channel_mode = alc262_modes,
+		.input_mux = &alc262_fujitsu_capture_source,
+		.unsol_event = alc262_fujitsu_unsol_event,
+	},
 };
 
 static int patch_alc262(struct hda_codec *codec)
@@ -4017,8 +4855,8 @@
 
 	codec->patch_ops = alc_patch_ops;
 	if (board_config == ALC262_AUTO)
-		codec->patch_ops.init = alc262_auto_init;
-	
+		spec->init_hook = alc262_auto_init;
+		
 	return 0;
 }
 
@@ -4549,8 +5387,7 @@
 	if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
 						alc861_ignore)) < 0)
 		return err;
-	if (! spec->autocfg.line_outs && ! spec->autocfg.speaker_pin &&
-	    ! spec->autocfg.hp_pin)
+	if (! spec->autocfg.line_outs)
 		return 0; /* can't find valid BIOS pin config */
 
 	if ((err = alc861_auto_fill_dac_nids(spec, &spec->autocfg)) < 0 ||
@@ -4579,15 +5416,12 @@
 	return 1;
 }
 
-/* init callback for auto-configuration model -- overriding the default init */
-static int alc861_auto_init(struct hda_codec *codec)
+/* additional initialization for auto-configuration model */
+static void alc861_auto_init(struct hda_codec *codec)
 {
-	alc_init(codec);
 	alc861_auto_init_multi_out(codec);
 	alc861_auto_init_hp_out(codec);
 	alc861_auto_init_analog_input(codec);
-
-	return 0;
 }
 
 
@@ -4685,7 +5519,7 @@
 
 	codec->patch_ops = alc_patch_ops;
 	if (board_config == ALC861_AUTO)
-		codec->patch_ops.init = alc861_auto_init;
+		spec->init_hook = alc861_auto_init;
 		
 	return 0;
 }
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 35c2823..b56ca40 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -51,6 +51,7 @@
 	unsigned int line_switch: 1;
 	unsigned int mic_switch: 1;
 	unsigned int alt_switch: 1;
+	unsigned int hp_detect: 1;
 
 	/* playback */
 	struct hda_multi_out multiout;
@@ -303,6 +304,12 @@
 	  .pci_subdevice = 0x0101,
 	  .config = STAC_D945GTP3 },	/* Intel D945GTP - 3 Stack */
 	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
+	  .pci_subdevice = 0x0202,
+	  .config = STAC_D945GTP3 },	/* Intel D945GNT - 3 Stack, 9221 A1 */
+	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
+	  .pci_subdevice = 0x0b0b,
+	  .config = STAC_D945GTP3 },	/* Intel D945PSN - 3 Stack, 9221 A1 */
+	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
 	  .pci_subdevice = 0x0404,
 	  .config = STAC_D945GTP5 },	/* Intel D945GTP - 5 Stack */
 	{ .pci_subvendor = PCI_VENDOR_ID_INTEL,
@@ -691,13 +698,7 @@
 					AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
 	}
 
-	if (cfg->line_outs)
-		spec->multiout.num_dacs = cfg->line_outs;
-	else if (cfg->hp_pin) {
-		spec->multiout.dac_nids[0] = snd_hda_codec_read(codec, cfg->hp_pin, 0,
-					AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
-		spec->multiout.num_dacs = 1;
-	}
+	spec->multiout.num_dacs = cfg->line_outs;
 
 	return 0;
 }
@@ -766,11 +767,13 @@
 		return 0;
 
 	wid_caps = get_wcaps(codec, pin);
-	if (wid_caps & AC_WCAP_UNSOL_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);
+		spec->hp_detect = 1;
+	}
 
 	nid = snd_hda_codec_read(codec, pin, 0, AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
 	for (i = 0; i < cfg->line_outs; i++) {
@@ -804,9 +807,6 @@
 	for (i = 0; i < AUTO_PIN_LAST; i++) {
 		int index = -1;
 		if (cfg->input_pins[i]) {
-			/* Enable active pin widget as an input */
-			stac92xx_auto_set_pinctl(codec, cfg->input_pins[i], AC_PINCTL_IN_EN);
-
 			imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
 
 			for (j=0; j<spec->num_muxes; j++) {
@@ -855,10 +855,8 @@
 
 	if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
 		return err;
-	if (! spec->autocfg.line_outs && ! spec->autocfg.hp_pin)
+	if (! spec->autocfg.line_outs)
 		return 0; /* can't find valid pin config */
-	stac92xx_auto_init_multi_out(codec);
-	stac92xx_auto_init_hp_out(codec);
 	if ((err = stac92xx_add_dyn_out_pins(codec, &spec->autocfg)) < 0)
 		return err;
 	if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
@@ -873,14 +871,10 @@
 	if (spec->multiout.max_channels > 2)
 		spec->surr_switch = 1;
 
-	if (spec->autocfg.dig_out_pin) {
+	if (spec->autocfg.dig_out_pin)
 		spec->multiout.dig_out_nid = dig_out;
-		stac92xx_auto_set_pinctl(codec, spec->autocfg.dig_out_pin, AC_PINCTL_OUT_EN);
-	}
-	if (spec->autocfg.dig_in_pin) {
+	if (spec->autocfg.dig_in_pin)
 		spec->dig_in_nid = dig_in;
-		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;
@@ -890,6 +884,29 @@
 	return 1;
 }
 
+/* add playback controls for HP output */
+static int stac9200_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;
+	unsigned int wid_caps;
+
+	if (! pin)
+		return 0;
+
+	wid_caps = get_wcaps(codec, pin);
+	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);
+		spec->hp_detect = 1;
+	}
+
+	return 0;
+}
+
 static int stac9200_parse_auto_config(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec = codec->spec;
@@ -901,14 +918,13 @@
 	if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
 		return err;
 
-	if (spec->autocfg.dig_out_pin) {
+	if ((err = stac9200_auto_create_hp_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) {
+	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;
@@ -921,9 +937,31 @@
 static int stac92xx_init(struct hda_codec *codec)
 {
 	struct sigmatel_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+	int i;
 
 	snd_hda_sequence_write(codec, spec->init);
 
+	/* set up pins */
+	if (spec->hp_detect) {
+		/* fake event to set up pins */
+		codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
+	} else {
+		stac92xx_auto_init_multi_out(codec);
+		stac92xx_auto_init_hp_out(codec);
+	}
+	for (i = 0; i < AUTO_PIN_LAST; i++) {
+		if (cfg->input_pins[i])
+			stac92xx_auto_set_pinctl(codec, cfg->input_pins[i],
+						 AC_PINCTL_IN_EN);
+	}
+	if (cfg->dig_out_pin)
+		stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin,
+					 AC_PINCTL_OUT_EN);
+	if (cfg->dig_in_pin)
+		stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin,
+					 AC_PINCTL_IN_EN);
+
 	return 0;
 }
 
@@ -1142,6 +1180,166 @@
 }
 
 /*
+ * STAC 7661(?) hack
+ */
+
+/* static config for Sony VAIO FE550G */
+static hda_nid_t vaio_dacs[] = { 0x2 };
+#define VAIO_HP_DAC	0x5
+static hda_nid_t vaio_adcs[] = { 0x8 /*,0x6*/ };
+static hda_nid_t vaio_mux_nids[] = { 0x15 };
+
+static struct hda_input_mux vaio_mux = {
+	.num_items = 2,
+	.items = {
+		/* { "HP", 0x0 },
+		   { "Unknown", 0x1 }, */
+		{ "Mic", 0x2 },
+		{ "PCM", 0x3 },
+	}
+};
+
+static struct hda_verb vaio_init[] = {
+	{0x0a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, /* HP <- 0x2 */
+	{0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, /* Speaker <- 0x5 */
+	{0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
+	{0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
+	{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
+	{0x15, AC_VERB_SET_CONNECT_SEL, 0x2}, /* mic-sel: 0a,0d,14,02 */
+	{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
+	{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
+	{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
+	{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, /* CD-in -> 0x6 */
+	{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
+	{}
+};
+
+/* bind volumes of both NID 0x02 and 0x05 */
+static int vaio_master_vol_put(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	long *valp = ucontrol->value.integer.value;
+	int change;
+
+	change = snd_hda_codec_amp_update(codec, 0x02, 0, HDA_OUTPUT, 0,
+					  0x7f, valp[0] & 0x7f);
+	change |= snd_hda_codec_amp_update(codec, 0x02, 1, HDA_OUTPUT, 0,
+					   0x7f, valp[1] & 0x7f);
+	snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0,
+				 0x7f, valp[0] & 0x7f);
+	snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0,
+				 0x7f, valp[1] & 0x7f);
+	return change;
+}
+
+/* bind volumes of both NID 0x02 and 0x05 */
+static int vaio_master_sw_put(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	long *valp = ucontrol->value.integer.value;
+	int change;
+
+	change = snd_hda_codec_amp_update(codec, 0x02, 0, HDA_OUTPUT, 0,
+					  0x80, valp[0] & 0x80);
+	change |= snd_hda_codec_amp_update(codec, 0x02, 1, HDA_OUTPUT, 0,
+					   0x80, valp[1] & 0x80);
+	snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0,
+				 0x80, valp[0] & 0x80);
+	snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0,
+				 0x80, valp[1] & 0x80);
+	return change;
+}
+
+static struct snd_kcontrol_new vaio_mixer[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Volume",
+		.info = snd_hda_mixer_amp_volume_info,
+		.get = snd_hda_mixer_amp_volume_get,
+		.put = vaio_master_vol_put,
+		.private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Switch",
+		.info = snd_hda_mixer_amp_switch_info,
+		.get = snd_hda_mixer_amp_switch_get,
+		.put = vaio_master_sw_put,
+		.private_value = HDA_COMPOSE_AMP_VAL(0x02, 3, 0, HDA_OUTPUT),
+	},
+	/* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
+	HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_INPUT),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Capture Source",
+		.count = 1,
+		.info = stac92xx_mux_enum_info,
+		.get = stac92xx_mux_enum_get,
+		.put = stac92xx_mux_enum_put,
+	},
+	{}
+};
+
+static struct hda_codec_ops stac7661_patch_ops = {
+	.build_controls = stac92xx_build_controls,
+	.build_pcms = stac92xx_build_pcms,
+	.init = stac92xx_init,
+	.free = stac92xx_free,
+#ifdef CONFIG_PM
+	.resume = stac92xx_resume,
+#endif
+};
+
+enum { STAC7661_VAIO };
+
+static struct hda_board_config stac7661_cfg_tbl[] = {
+	{ .modelname = "vaio", .config = STAC7661_VAIO },
+	{ .pci_subvendor = 0x104d, .pci_subdevice = 0x81e6,
+	  .config = STAC7661_VAIO },
+	{ .pci_subvendor = 0x104d, .pci_subdevice = 0x81ef,
+	  .config = STAC7661_VAIO },
+	{}
+};
+
+static int patch_stac7661(struct hda_codec *codec)
+{
+	struct sigmatel_spec *spec;
+	int board_config;
+
+	board_config = snd_hda_check_board_config(codec, stac7661_cfg_tbl);
+	if (board_config < 0)
+		/* unknown config, let generic-parser do its job... */
+		return snd_hda_parse_generic_codec(codec);
+	
+	spec  = kzalloc(sizeof(*spec), GFP_KERNEL);
+	if (spec == NULL)
+		return -ENOMEM;
+
+	codec->spec = spec;
+	switch (board_config) {
+	case STAC7661_VAIO:
+		spec->mixer = vaio_mixer;
+		spec->init = vaio_init;
+		spec->multiout.max_channels = 2;
+		spec->multiout.num_dacs = ARRAY_SIZE(vaio_dacs);
+		spec->multiout.dac_nids = vaio_dacs;
+		spec->multiout.hp_nid = VAIO_HP_DAC;
+		spec->num_adcs = ARRAY_SIZE(vaio_adcs);
+		spec->adc_nids = vaio_adcs;
+		spec->input_mux = &vaio_mux;
+		spec->mux_nids = vaio_mux_nids;
+		break;
+	}
+
+	codec->patch_ops = stac7661_patch_ops;
+	return 0;
+}
+
+
+/*
  * patch entries
  */
 struct hda_codec_preset snd_hda_preset_sigmatel[] = {
@@ -1162,5 +1360,6 @@
  	{ .id = 0x83847627, .name = "STAC9271D", .patch = patch_stac927x },
  	{ .id = 0x83847628, .name = "STAC9274X5NH", .patch = patch_stac927x },
  	{ .id = 0x83847629, .name = "STAC9274D5NH", .patch = patch_stac927x },
+ 	{ .id = 0x83847661, .name = "STAC7661", .patch = patch_stac7661 },
 	{} /* terminator */
 };
diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c
index 8809812..7e6608b 100644
--- a/sound/pci/ice1712/aureon.c
+++ b/sound/pci/ice1712/aureon.c
@@ -53,6 +53,8 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 
 #include "ice1712.h"
@@ -210,14 +212,14 @@
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	unsigned short vol;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 
 	vol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F);
 	ucontrol->value.integer.value[0] = 0x1F - (vol & 0x1F);
 	if (kcontrol->private_value & AUREON_AC97_STEREO)
 		ucontrol->value.integer.value[1] = 0x1F - ((vol >> 8) & 0x1F);
 
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -252,11 +254,11 @@
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 
 	ucontrol->value.integer.value[0] = aureon_ac97_read(ice, kcontrol->private_value & 0x7F) & 0x8000 ? 0 : 1;
 
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -288,11 +290,11 @@
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 
 	ucontrol->value.integer.value[0] = aureon_ac97_read(ice, AC97_MIC) & 0x0020 ? 0 : 1;
 
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -322,36 +324,48 @@
 {
 	unsigned int tmp;
 	int i;
+	unsigned int mosi, clk;
 
 	tmp = snd_ice1712_gpio_read(ice);
 
-	snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RW|AUREON_SPI_MOSI|AUREON_SPI_CLK|
-					 AUREON_WM_CS|AUREON_CS8415_CS));
-	tmp |= AUREON_WM_RW;
+	if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT) {
+		snd_ice1712_gpio_set_mask(ice, ~(PRODIGY_SPI_MOSI|PRODIGY_SPI_CLK|PRODIGY_WM_CS));
+		mosi = PRODIGY_SPI_MOSI;
+		clk = PRODIGY_SPI_CLK;
+	}
+	else {
+		snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RW|AUREON_SPI_MOSI|AUREON_SPI_CLK|
+						 AUREON_WM_CS|AUREON_CS8415_CS));
+		mosi = AUREON_SPI_MOSI;
+		clk = AUREON_SPI_CLK;
+		
+		tmp |= AUREON_WM_RW;
+	}
+	
 	tmp &= ~cs;
 	snd_ice1712_gpio_write(ice, tmp);
 	udelay(1);
 
 	for (i = bits - 1; i >= 0; i--) {
-		tmp &= ~AUREON_SPI_CLK;
+		tmp &= ~clk;
 		snd_ice1712_gpio_write(ice, tmp);
 		udelay(1);
 		if (data & (1 << i))
-			tmp |= AUREON_SPI_MOSI;
+			tmp |= mosi;
 		else
-			tmp &= ~AUREON_SPI_MOSI;
+			tmp &= ~mosi;
 		snd_ice1712_gpio_write(ice, tmp);
 		udelay(1);
-		tmp |= AUREON_SPI_CLK;
+		tmp |= clk;
 		snd_ice1712_gpio_write(ice, tmp);
 		udelay(1);
 	}
 
-	tmp &= ~AUREON_SPI_CLK;
+	tmp &= ~clk;
 	tmp |= cs;
 	snd_ice1712_gpio_write(ice, tmp);
 	udelay(1);
-	tmp |= AUREON_SPI_CLK;
+	tmp |= clk;
 	snd_ice1712_gpio_write(ice, tmp);
 	udelay(1);
 }
@@ -440,7 +454,9 @@
  */
 static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val)
 {
-	aureon_spi_write(ice, AUREON_WM_CS, (reg << 9) | (val & 0x1ff), 16);
+	aureon_spi_write(ice,
+			(ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT ? PRODIGY_WM_CS : AUREON_WM_CS),
+			(reg << 9) | (val & 0x1ff), 16);
 }
 
 /*
@@ -474,11 +490,11 @@
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 
 	ucontrol->value.integer.value[0] = (wm_get(ice, WM_OUT_MUX1) >> 1) & 0x01;
 
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -543,9 +559,9 @@
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 0 : 1;
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -768,11 +784,11 @@
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	unsigned short val;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
 	val = val > PCM_MIN ? (val - PCM_MIN) : 0;
 	ucontrol->value.integer.value[0] = val;
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -813,12 +829,12 @@
 	unsigned short val;
 	int i;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	for (i = 0; i < 2; i++) {
 		val = wm_get(ice, WM_ADC_GAIN + i);
 		ucontrol->value.integer.value[i] = ~val>>5 & 0x1;
 	}
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -860,13 +876,13 @@
 	int i, idx;
 	unsigned short vol;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	for (i = 0; i < 2; i++) {
 		idx = WM_ADC_GAIN + i;
 		vol = wm_get(ice, idx) & 0x1f;
 		ucontrol->value.integer.value[i] = vol;
 	}
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -937,11 +953,11 @@
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	unsigned short val;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	val = wm_get(ice, WM_ADC_MUX);
-	ucontrol->value.integer.value[0] = val & 7;
-	ucontrol->value.integer.value[1] = (val >> 4) & 7;
-	up(&ice->gpio_mutex);
+	ucontrol->value.enumerated.item[0] = val & 7;
+	ucontrol->value.enumerated.item[1] = (val >> 4) & 7;
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -954,8 +970,8 @@
 	snd_ice1712_save_gpio_status(ice);
 	oval = wm_get(ice, WM_ADC_MUX);
 	nval = oval & ~0x77;
-	nval |= ucontrol->value.integer.value[0] & 7;
-	nval |= (ucontrol->value.integer.value[1] & 7) << 4;
+	nval |= ucontrol->value.enumerated.item[0] & 7;
+	nval |= (ucontrol->value.enumerated.item[1] & 7) << 4;
 	change = (oval != nval);
 	if (change)
 		wm_put(ice, WM_ADC_MUX, nval);
@@ -995,7 +1011,7 @@
 
 	//snd_ice1712_save_gpio_status(ice);
 	//val = aureon_cs8415_get(ice, CS8415_CTRL2);
-	ucontrol->value.integer.value[0] = ice->spec.aureon.cs8415_mux;
+	ucontrol->value.enumerated.item[0] = ice->spec.aureon.cs8415_mux;
 	//snd_ice1712_restore_gpio_status(ice);
 	return 0;
 }
@@ -1009,12 +1025,12 @@
 	snd_ice1712_save_gpio_status(ice);
 	oval = aureon_cs8415_get(ice, CS8415_CTRL2);
 	nval = oval & ~0x07;
-	nval |= ucontrol->value.integer.value[0] & 7;
+	nval |= ucontrol->value.enumerated.item[0] & 7;
 	change = (oval != nval);
 	if (change)
 		aureon_cs8415_put(ice, CS8415_CTRL2, nval);
 	snd_ice1712_restore_gpio_status(ice);
-	ice->spec.aureon.cs8415_mux = ucontrol->value.integer.value[0];
+	ice->spec.aureon.cs8415_mux = ucontrol->value.enumerated.item[0];
 	return change;
 }
 
@@ -1659,7 +1675,7 @@
 				return err;
 		}
 	}
-	else {
+	else if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) {
 		for (i = 0; i < ARRAY_SIZE(ac97_controls); i++) {
 			err = snd_ctl_add(ice->card, snd_ctl_new1(&ac97_controls[i], ice));
 			if (err < 0)
@@ -1667,7 +1683,7 @@
 		}
 	}
 
-	{
+	if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) {
 		unsigned char id;
 		snd_ice1712_save_gpio_status(ice);
 		id = aureon_cs8415_get(ice, CS8415_ID);
@@ -1822,7 +1838,8 @@
 	udelay(1);
 
 	/* initialize WM8770 codec */
-	if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71)
+	if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71 ||
+		ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT)
 		p = wm_inits_prodigy;
 	else
 		p = wm_inits_aureon;
@@ -1830,11 +1847,13 @@
 		wm_put(ice, p[0], p[1]);
 
 	/* initialize CS8415A codec */
-	for (p = cs_inits; *p != (unsigned short)-1; p++)
-		aureon_spi_write(ice, AUREON_CS8415_CS, *p | 0x200000, 24);
-	ice->spec.aureon.cs8415_mux = 1;
+	if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) {
+		for (p = cs_inits; *p != (unsigned short)-1; p++)
+			aureon_spi_write(ice, AUREON_CS8415_CS, *p | 0x200000, 24);
+		ice->spec.aureon.cs8415_mux = 1;
 
-	aureon_set_headphone_amp(ice, 1);
+		aureon_set_headphone_amp(ice, 1);
+	}
 
 	snd_ice1712_restore_gpio_status(ice);
 	
@@ -1902,6 +1921,23 @@
 	0x00,	/* GPIO_STATE2 */
 };
 
+static unsigned char prodigy71lt_eeprom[] __devinitdata = {
+	0x0b,	/* SYSCINF: clock 512, spdif-in/ADC, 4DACs */
+	0x80,	/* ACLINK: I2S */
+	0xfc,	/* I2S: vol, 96k, 24bit, 192k */
+	0xc3,	/* SPDUF: out-en, out-int */
+	0x00,	/* GPIO_DIR */
+	0x07,	/* GPIO_DIR1 */
+	0x00,	/* GPIO_DIR2 */
+	0xff,	/* GPIO_MASK */
+	0xf8,	/* GPIO_MASK1 */
+	0xff,	/* GPIO_MASK2 */
+	0x00,	/* GPIO_STATE */
+	0x00,	/* GPIO_STATE1 */
+	0x00,	/* GPIO_STATE2 */
+};
+	
+
 /* entry point */
 struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = {
 	{
@@ -1944,5 +1980,15 @@
 		.eeprom_data = prodigy71_eeprom,
 		.driver = "Prodigy71", /* should be identical with Aureon71 */
 	},
+	{
+		.subvendor = VT1724_SUBDEVICE_PRODIGY71LT,
+		.name = "Audiotrak Prodigy 7.1 LT",
+		.model = "prodigy71lt",
+		.chip_init = aureon_init,
+		.build_controls = aureon_add_controls,
+		.eeprom_size = sizeof(prodigy71lt_eeprom),
+		.eeprom_data = prodigy71lt_eeprom,
+		.driver = "Prodigy71LT",
+	},
 	{ } /* terminator */
 };
diff --git a/sound/pci/ice1712/aureon.h b/sound/pci/ice1712/aureon.h
index 95d515f..98a6752 100644
--- a/sound/pci/ice1712/aureon.h
+++ b/sound/pci/ice1712/aureon.h
@@ -27,12 +27,14 @@
 #define  AUREON_DEVICE_DESC 	       "{Terratec,Aureon 5.1 Sky},"\
 				       "{Terratec,Aureon 7.1 Space},"\
 				       "{Terratec,Aureon 7.1 Universe}," \
-					"{AudioTrak,Prodigy 7.1},"
+					"{AudioTrak,Prodigy 7.1}," \
+					"{AudioTrak,Prodigy 7.1 LT},"
 
 #define VT1724_SUBDEVICE_AUREON51_SKY	0x3b154711	/* Aureon 5.1 Sky */
 #define VT1724_SUBDEVICE_AUREON71_SPACE	0x3b154511	/* Aureon 7.1 Space */
 #define VT1724_SUBDEVICE_AUREON71_UNIVERSE	0x3b155311	/* Aureon 7.1 Universe */
 #define VT1724_SUBDEVICE_PRODIGY71	0x33495345	/* PRODIGY 7.1 */
+#define VT1724_SUBDEVICE_PRODIGY71LT	0x32315441	/* PRODIGY 7.1 LT */
 
 extern struct snd_ice1712_card_info  snd_vt1724_aureon_cards[];
 
@@ -53,4 +55,8 @@
 #define AUREON_AC97_DATA_HIGH	(1 << 8)
 #define AUREON_AC97_DATA_MASK	0xFF
 
+#define PRODIGY_WM_CS		(1 << 8)
+#define PRODIGY_SPI_MOSI	(1 << 10)
+#define PRODIGY_SPI_CLK		(1 << 9)
+
 #endif /* __SOUND_AUREON_H */
diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c
index 9a51d34..af65980 100644
--- a/sound/pci/ice1712/delta.c
+++ b/sound/pci/ice1712/delta.c
@@ -28,6 +28,8 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/cs8427.h>
 #include <sound/asoundef.h>
@@ -130,13 +132,13 @@
 	int res = count;
 	unsigned char tmp;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	tmp = ap_cs8427_codec_select(ice);
 	ap_cs8427_write_byte(ice, (device->addr << 1) | 0, tmp); /* address + write mode */
 	while (count-- > 0)
 		ap_cs8427_write_byte(ice, *bytes++, tmp);
 	ap_cs8427_codec_deassert(ice, tmp);
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return res;
 }
 
@@ -147,13 +149,13 @@
 	int res = count;
 	unsigned char tmp;
 	
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	tmp = ap_cs8427_codec_select(ice);
 	ap_cs8427_write_byte(ice, (device->addr << 1) | 1, tmp); /* address + read mode */
 	while (count-- > 0)
 		*bytes++ = ap_cs8427_read_byte(ice, tmp);
 	ap_cs8427_codec_deassert(ice, tmp);
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return res;
 }
 
@@ -180,7 +182,7 @@
 	/* send byte to transmitter */
 	mask1 = ICE1712_DELTA_SPDIF_OUT_STAT_CLOCK;
 	mask2 = ICE1712_DELTA_SPDIF_OUT_STAT_DATA;
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
 	for (idx = 7; idx >= 0; idx--) {
 		tmp &= ~(mask1 | mask2);
@@ -194,7 +196,7 @@
 	}
 	tmp &= ~mask1;
 	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 }
 
 
@@ -296,14 +298,14 @@
 	if (rate == 0)	/* no hint - S/PDIF input is master, simply return */
 		return;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
 	tmp2 = tmp & ~ICE1712_DELTA_DFS;
 	if (rate > 48000)
 		tmp2 |= ICE1712_DELTA_DFS;
 	if (tmp != tmp2)
 		snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp2);
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 }
 
 /*
@@ -318,9 +320,9 @@
 		return;
 
 	/* check before reset ak4524 to avoid unnecessary clicks */
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA);
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	tmp2 = tmp & ~ICE1712_DELTA_DFS; 
 	if (rate > 48000)
 		tmp2 |= ICE1712_DELTA_DFS;
@@ -329,12 +331,12 @@
 
 	/* do it again */
 	snd_akm4xxx_reset(ak, 1);
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA) & ~ICE1712_DELTA_DFS;
 	if (rate > 48000)
 		tmp |= ICE1712_DELTA_DFS;
 	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	snd_akm4xxx_reset(ak, 0);
 }
 
@@ -391,6 +393,37 @@
 	snd_ice1712_delta_cs8403_spdif_write(ice, tmp);
 }
 
+static int snd_ice1712_delta1010lt_wordclock_status_info(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_info *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_ice1712_delta1010lt_wordclock_status_get(struct snd_kcontrol *kcontrol,
+			 struct snd_ctl_elem_value *ucontrol)
+{
+	char reg = 0x10; // cs8427 receiver error register
+	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+
+	if (snd_i2c_sendbytes(ice->cs8427, &reg, 1) != 1)
+		snd_printk(KERN_ERR "unable to send register 0x%x byte to CS8427\n", reg);
+	snd_i2c_readbytes(ice->cs8427, &reg, 1);
+	ucontrol->value.integer.value[0] = (reg ? 1 : 0);
+	return 0;
+}
+
+static struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_status __devinitdata =
+{
+	.access =	(SNDRV_CTL_ELEM_ACCESS_READ),
+	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name =         "Word Clock Status",
+	.info =		snd_ice1712_delta1010lt_wordclock_status_info,
+	.get =		snd_ice1712_delta1010lt_wordclock_status_get,
+};
 
 /*
  * initialize the chips on M-Audio cards
@@ -620,7 +653,7 @@
 static struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_select __devinitdata =
 ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Sync", 0, ICE1712_DELTA_WORD_CLOCK_SELECT, 1, 0);
 static struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_select __devinitdata =
-ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Sync", 0, ICE1712_DELTA_1010LT_WORDCLOCK, 1, 0);
+ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Sync", 0, ICE1712_DELTA_1010LT_WORDCLOCK, 0, 0);
 static struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_status __devinitdata =
 ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Status", 0, ICE1712_DELTA_WORD_CLOCK_STATUS, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE);
 static struct snd_kcontrol_new snd_ice1712_deltadio2496_spdif_in_select __devinitdata =
@@ -653,6 +686,9 @@
 		err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_delta1010lt_wordclock_select, ice));
 		if (err < 0)
 			return err;
+		err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_delta1010lt_wordclock_status, ice));
+		if (err < 0)
+			return err;
 		break;
 	}
 
diff --git a/sound/pci/ice1712/hoontech.c b/sound/pci/ice1712/hoontech.c
index 3f2f918..3f27d04 100644
--- a/sound/pci/ice1712/hoontech.c
+++ b/sound/pci/ice1712/hoontech.c
@@ -27,6 +27,8 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 
 #include "ice1712.h"
@@ -48,31 +50,31 @@
 
 static void __devinit snd_ice1712_stdsp24_darear(struct snd_ice1712 *ice, int activate)
 {
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	ICE1712_STDSP24_0_DAREAR(ice->spec.hoontech.boxbits, activate);
 	snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[0]);
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 }
 
 static void __devinit snd_ice1712_stdsp24_mute(struct snd_ice1712 *ice, int activate)
 {
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	ICE1712_STDSP24_3_MUTE(ice->spec.hoontech.boxbits, activate);
 	snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]);
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 }
 
 static void __devinit snd_ice1712_stdsp24_insel(struct snd_ice1712 *ice, int activate)
 {
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	ICE1712_STDSP24_3_INSEL(ice->spec.hoontech.boxbits, activate);
 	snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]);
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 }
 
 static void __devinit snd_ice1712_stdsp24_box_channel(struct snd_ice1712 *ice, int box, int chn, int activate)
 {
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 
 	/* select box */
 	ICE1712_STDSP24_0_BOX(ice->spec.hoontech.boxbits, box);
@@ -115,12 +117,12 @@
 	ICE1712_STDSP24_2_MIDI1(ice->spec.hoontech.boxbits, 0);
 	snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]);
 
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 }
 
 static void __devinit snd_ice1712_stdsp24_box_midi(struct snd_ice1712 *ice, int box, int master)
 {
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 
 	/* select box */
 	ICE1712_STDSP24_0_BOX(ice->spec.hoontech.boxbits, box);
@@ -141,15 +143,15 @@
 	ICE1712_STDSP24_2_MIDIIN(ice->spec.hoontech.boxbits, 1);
 	snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[2]);
 
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 }
 
 static void __devinit snd_ice1712_stdsp24_midi2(struct snd_ice1712 *ice, int activate)
 {
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	ICE1712_STDSP24_3_MIDI2(ice->spec.hoontech.boxbits, activate);
 	snd_ice1712_stdsp24_gpio_write(ice, ice->spec.hoontech.boxbits[3]);
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 }
 
 static int __devinit snd_ice1712_hoontech_init(struct snd_ice1712 *ice)
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index ef6f185..672e198 100644
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -53,8 +53,10 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/slab.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/cs8427.h>
 #include <sound/info.h>
@@ -82,10 +84,11 @@
 
 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 */
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */
 static char *model[SNDRV_CARDS];
-static int omni[SNDRV_CARDS];	/* Delta44 & 66 Omni I/O support */
+static int omni[SNDRV_CARDS];				/* Delta44 & 66 Omni I/O support */
 static int cs8427_timeout[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 500}; /* CS8427 S/PDIF transciever reset timeout value in msec */
+static int dxr_enable[SNDRV_CARDS];			/* DXR enable for DMX6FIRE */
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for ICE1712 soundcard.");
@@ -99,6 +102,8 @@
 MODULE_PARM_DESC(cs8427_timeout, "Define reset timeout for cs8427 chip in msec resolution.");
 module_param_array(model, charp, NULL, 0444);
 MODULE_PARM_DESC(model, "Use the given board model.");
+module_param_array(dxr_enable, int, NULL, 0444);
+MODULE_PARM_DESC(dxr_enable, "Enable DXR support for Terratec DMX6FIRE.");
 
 
 static struct pci_device_id snd_ice1712_ids[] = {
@@ -316,7 +321,6 @@
 	inb(ICEREG(ice, DATA)); /* dummy read for pci-posting */
 }
 
-
 /*
  *
  * CS8427 interface
@@ -396,6 +400,20 @@
 	return 0;
 }
 
+static void snd_ice1712_set_input_clock_source(struct snd_ice1712 *ice, int spdif_is_master)
+{
+        /* change CS8427 clock source too */
+        if (ice->cs8427)
+                snd_ice1712_cs8427_set_input_clock(ice, spdif_is_master);
+	/* notify ak4524 chip as well */
+	if (spdif_is_master) {
+		unsigned int i;
+		for (i = 0; i < ice->akm_codecs; i++) {
+			if (ice->akm[i].ops.set_rate_val)
+				ice->akm[i].ops.set_rate_val(&ice->akm[i], 0);
+		}
+	}
+}
 
 /*
  *  Interrupt handler
@@ -1567,6 +1585,9 @@
 	snd_iprintf(buffer, "  CAPTURE          : 0x%08x\n", inl(ICEMT(ice, ROUTE_CAPTURE)));
 	snd_iprintf(buffer, "  SPDOUT           : 0x%04x\n", (unsigned)inw(ICEMT(ice, ROUTE_SPDOUT)));
 	snd_iprintf(buffer, "  RATE             : 0x%02x\n", (unsigned)inb(ICEMT(ice, RATE)));
+	snd_iprintf(buffer, "  GPIO_DATA        : 0x%02x\n", (unsigned)snd_ice1712_get_gpio_data(ice));
+        snd_iprintf(buffer, "  GPIO_WRITE_MASK  : 0x%02x\n", (unsigned)snd_ice1712_read(ice, ICE1712_IREG_GPIO_WRITE_MASK));
+	snd_iprintf(buffer, "  GPIO_DIRECTION   : 0x%02x\n", (unsigned)snd_ice1712_read(ice, ICE1712_IREG_GPIO_DIRECTION));
 }
 
 static void __devinit snd_ice1712_proc_init(struct snd_ice1712 * ice)
@@ -1856,20 +1877,8 @@
 	spin_unlock_irq(&ice->reg_lock);
 
 	if ((oval & ICE1712_SPDIF_MASTER) !=
-	    (inb(ICEMT(ice, RATE)) & ICE1712_SPDIF_MASTER)) {
-		/* change CS8427 clock source too */
-		if (ice->cs8427) {
-			snd_ice1712_cs8427_set_input_clock(ice, is_spdif_master(ice));
-		}
-		/* notify ak4524 chip as well */
-		if (is_spdif_master(ice)) {
-			unsigned int i;
-			for (i = 0; i < ice->akm_codecs; i++) {
-				if (ice->akm[i].ops.set_rate_val)
-					ice->akm[i].ops.set_rate_val(&ice->akm[i], 0);
-			}
-		}
-	}
+	    (inb(ICEMT(ice, RATE)) & ICE1712_SPDIF_MASTER))
+	        snd_ice1712_set_input_clock_source(ice, is_spdif_master(ice));
 
 	return change;
 }
@@ -2388,7 +2397,13 @@
 	udelay(200);
 	outb(ICE1712_NATIVE, ICEREG(ice, CONTROL));
 	udelay(200);
-	pci_write_config_byte(ice->pci, 0x60, ice->eeprom.data[ICE_EEP1_CODEC]);
+	if (ice->eeprom.subvendor == ICE1712_SUBDEVICE_DMX6FIRE && !ice->dxr_enable) {
+                /* Limit active ADCs and DACs to 6;  */
+                /* Note: DXR extension not supported */
+		pci_write_config_byte(ice->pci, 0x60, 0x0a);
+	} else {
+		pci_write_config_byte(ice->pci, 0x60, ice->eeprom.data[ICE_EEP1_CODEC]);
+	}
 	pci_write_config_byte(ice->pci, 0x61, ice->eeprom.data[ICE_EEP1_ACLINK]);
 	pci_write_config_byte(ice->pci, 0x62, ice->eeprom.data[ICE_EEP1_I2SID]);
 	pci_write_config_byte(ice->pci, 0x63, ice->eeprom.data[ICE_EEP1_SPDIF]);
@@ -2524,6 +2539,7 @@
 					const char *modelname,
 					int omni,
 					int cs8427_timeout,
+					int dxr_enable,
 					struct snd_ice1712 ** r_ice1712)
 {
 	struct snd_ice1712 *ice;
@@ -2538,8 +2554,8 @@
 	if ((err = pci_enable_device(pci)) < 0)
 		return err;
 	/* check, if we can restrict PCI DMA transfers to 28 bits */
-	if (pci_set_dma_mask(pci, 0x0fffffff) < 0 ||
-	    pci_set_consistent_dma_mask(pci, 0x0fffffff) < 0) {
+	if (pci_set_dma_mask(pci, DMA_28BIT_MASK) < 0 ||
+	    pci_set_consistent_dma_mask(pci, DMA_28BIT_MASK) < 0) {
 		snd_printk(KERN_ERR "architecture does not support 28bit PCI busmaster DMA\n");
 		pci_disable_device(pci);
 		return -ENXIO;
@@ -2556,10 +2572,11 @@
 	else if (cs8427_timeout > 1000)
 		cs8427_timeout = 1000;
 	ice->cs8427_timeout = cs8427_timeout;
+	ice->dxr_enable = dxr_enable;
 	spin_lock_init(&ice->reg_lock);
-	init_MUTEX(&ice->gpio_mutex);
-	init_MUTEX(&ice->i2c_mutex);
-	init_MUTEX(&ice->open_mutex);
+	mutex_init(&ice->gpio_mutex);
+	mutex_init(&ice->i2c_mutex);
+	mutex_init(&ice->open_mutex);
 	ice->gpio.set_mask = snd_ice1712_set_gpio_mask;
 	ice->gpio.set_dir = snd_ice1712_set_gpio_dir;
 	ice->gpio.set_data = snd_ice1712_set_gpio_data;
@@ -2658,7 +2675,8 @@
 	strcpy(card->shortname, "ICEnsemble ICE1712");
 	
 	if ((err = snd_ice1712_create(card, pci, model[dev], omni[dev],
-				      cs8427_timeout[dev], &ice)) < 0) {
+				      cs8427_timeout[dev], dxr_enable[dev],
+				      &ice)) < 0) {
 		snd_card_free(card);
 		return err;
 	}
@@ -2735,6 +2753,8 @@
 			}
 	}
 
+	snd_ice1712_set_input_clock_source(ice, 0);
+
 	sprintf(card->longname, "%s at 0x%lx, irq %i",
 		card->shortname, ice->port, ice->irq);
 
diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h
index ce96b3b..f9b22d4 100644
--- a/sound/pci/ice1712/ice1712.h
+++ b/sound/pci/ice1712/ice1712.h
@@ -325,6 +325,7 @@
 
 	unsigned int pro_volumes[20];
 	unsigned int omni: 1;		/* Delta Omni I/O */
+	unsigned int dxr_enable: 1;	/* Terratec DXR enable for DMX6FIRE */
 	unsigned int vt1724: 1;
 	unsigned int vt1720: 1;
 	unsigned int has_spdif: 1;	/* VT1720/4 - has SPDIF I/O */
@@ -334,7 +335,7 @@
 	unsigned int num_total_adcs;	/* total ADCs */
 	unsigned int cur_rate;		/* current rate */
 
-	struct semaphore open_mutex;
+	struct mutex open_mutex;
 	struct snd_pcm_substream *pcm_reserved[4];
 	struct snd_pcm_hw_constraint_list *hw_rates; /* card-specific rate constraints */
 
@@ -342,7 +343,7 @@
 	struct snd_akm4xxx *akm;
 	struct snd_ice1712_spdif spdif;
 
-	struct semaphore i2c_mutex;	/* I2C mutex for ICE1724 registers */
+	struct mutex i2c_mutex;	/* I2C mutex for ICE1724 registers */
 	struct snd_i2c_bus *i2c;		/* I2C bus */
 	struct snd_i2c_device *cs8427;	/* CS8427 I2C device */
 	unsigned int cs8427_timeout;	/* CS8427 reset timeout in HZ/100 */
@@ -360,7 +361,7 @@
 		void (*set_pro_rate)(struct snd_ice1712 *ice, unsigned int rate);
 		void (*i2s_mclk_changed)(struct snd_ice1712 *ice);
 	} gpio;
-	struct semaphore gpio_mutex;
+	struct mutex gpio_mutex;
 
 	/* other board-specific data */
 	union {
@@ -423,7 +424,7 @@
  */
 static inline void snd_ice1712_save_gpio_status(struct snd_ice1712 *ice)
 {
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	ice->gpio.saved[0] = ice->gpio.direction;
 	ice->gpio.saved[1] = ice->gpio.write_mask;
 }
@@ -434,7 +435,7 @@
 	ice->gpio.set_mask(ice, ice->gpio.saved[1]);
 	ice->gpio.direction = ice->gpio.saved[0];
 	ice->gpio.write_mask = ice->gpio.saved[1];
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 }
 
 /* for bit controls */
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index 71f08c0..fce616c 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -30,6 +30,7 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/mpu401.h>
@@ -487,7 +488,7 @@
 	int i, chs;
 
 	chs = params_channels(hw_params);
-	down(&ice->open_mutex);
+	mutex_lock(&ice->open_mutex);
 	/* mark surround channels */
 	if (substream == ice->playback_pro_substream) {
 		/* PDMA0 can be multi-channel up to 8 */
@@ -495,7 +496,7 @@
 		for (i = 0; i < chs; i++) {
 			if (ice->pcm_reserved[i] &&
 			    ice->pcm_reserved[i] != substream) {
-				up(&ice->open_mutex);
+				mutex_unlock(&ice->open_mutex);
 				return -EBUSY;
 			}
 			ice->pcm_reserved[i] = substream;
@@ -510,7 +511,7 @@
 			if (ice->playback_con_substream_ds[i] == substream) {
 				if (ice->pcm_reserved[i] &&
 				    ice->pcm_reserved[i] != substream) {
-					up(&ice->open_mutex);
+					mutex_unlock(&ice->open_mutex);
 					return -EBUSY;
 				}
 				ice->pcm_reserved[i] = substream;
@@ -518,7 +519,7 @@
 			}
 		}
 	}
-	up(&ice->open_mutex);
+	mutex_unlock(&ice->open_mutex);
 	snd_vt1724_set_pro_rate(ice, params_rate(hw_params), 0);
 	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
 }
@@ -528,12 +529,12 @@
 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
 	int i;
 
-	down(&ice->open_mutex);
+	mutex_lock(&ice->open_mutex);
 	/* unmark surround channels */
 	for (i = 0; i < 3; i++)
 		if (ice->pcm_reserved[i] == substream)
 			ice->pcm_reserved[i] = NULL;
-	up(&ice->open_mutex);
+	mutex_unlock(&ice->open_mutex);
 	return snd_pcm_lib_free_pages(substream);
 }
 
@@ -778,7 +779,7 @@
 	snd_pcm_set_sync(substream);
 	snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
 	set_rate_constraints(ice, substream);
-	down(&ice->open_mutex);
+	mutex_lock(&ice->open_mutex);
 	/* calculate the currently available channels */
 	for (chs = 0; chs < 3; chs++) {
 		if (ice->pcm_reserved[chs])
@@ -788,7 +789,7 @@
 	runtime->hw.channels_max = chs;
 	if (chs > 2) /* channels must be even */
 		snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 2);
-	up(&ice->open_mutex);
+	mutex_unlock(&ice->open_mutex);
 	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
 				   VT1724_BUFFER_ALIGN);
 	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
@@ -1128,13 +1129,13 @@
 	struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 
-	down(&ice->open_mutex);
+	mutex_lock(&ice->open_mutex);
 	/* already used by PDMA0? */
 	if (ice->pcm_reserved[substream->number]) {
-		up(&ice->open_mutex);
+		mutex_unlock(&ice->open_mutex);
 		return -EBUSY; /* FIXME: should handle blocking mode properly */
 	}
-	up(&ice->open_mutex);
+	mutex_unlock(&ice->open_mutex);
 	runtime->private_data = &vt1724_playback_dma_regs[substream->number];
 	ice->playback_con_substream_ds[substream->number] = substream;
 	runtime->hw = snd_vt1724_2ch_stereo;
@@ -1978,12 +1979,12 @@
 {
 	unsigned char val;
 
-	down(&ice->i2c_mutex);
+	mutex_lock(&ice->i2c_mutex);
 	outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR));
 	outb(dev & ~VT1724_I2C_WRITE, ICEREG1724(ice, I2C_DEV_ADDR));
 	wait_i2c_busy(ice);
 	val = inb(ICEREG1724(ice, I2C_DATA));
-	up(&ice->i2c_mutex);
+	mutex_unlock(&ice->i2c_mutex);
 	//printk("i2c_read: [0x%x,0x%x] = 0x%x\n", dev, addr, val);
 	return val;
 }
@@ -1991,14 +1992,14 @@
 void snd_vt1724_write_i2c(struct snd_ice1712 *ice,
 			  unsigned char dev, unsigned char addr, unsigned char data)
 {
-	down(&ice->i2c_mutex);
+	mutex_lock(&ice->i2c_mutex);
 	wait_i2c_busy(ice);
 	//printk("i2c_write: [0x%x,0x%x] = 0x%x\n", dev, addr, data);
 	outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR));
 	outb(data, ICEREG1724(ice, I2C_DATA));
 	outb(dev | VT1724_I2C_WRITE, ICEREG1724(ice, I2C_DEV_ADDR));
 	wait_i2c_busy(ice);
-	up(&ice->i2c_mutex);
+	mutex_unlock(&ice->i2c_mutex);
 }
 
 static int __devinit snd_vt1724_read_eeprom(struct snd_ice1712 *ice,
@@ -2229,9 +2230,9 @@
 	}
 	ice->vt1724 = 1;
 	spin_lock_init(&ice->reg_lock);
-	init_MUTEX(&ice->gpio_mutex);
-	init_MUTEX(&ice->open_mutex);
-	init_MUTEX(&ice->i2c_mutex);
+	mutex_init(&ice->gpio_mutex);
+	mutex_init(&ice->open_mutex);
+	mutex_init(&ice->i2c_mutex);
 	ice->gpio.set_mask = snd_vt1724_set_gpio_mask;
 	ice->gpio.set_dir = snd_vt1724_set_gpio_dir;
 	ice->gpio.set_data = snd_vt1724_set_gpio_data;
diff --git a/sound/pci/ice1712/phase.c b/sound/pci/ice1712/phase.c
index ec37578..502da1c 100644
--- a/sound/pci/ice1712/phase.c
+++ b/sound/pci/ice1712/phase.c
@@ -39,6 +39,8 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 
 #include "ice1712.h"
@@ -273,9 +275,9 @@
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 0 : 1;
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -584,11 +586,11 @@
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	unsigned short val;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
 	val = val > PCM_MIN ? (val - PCM_MIN) : 0;
 	ucontrol->value.integer.value[0] = val;
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c
index 0dccd77..d23fb3f 100644
--- a/sound/pci/ice1712/pontis.c
+++ b/sound/pci/ice1712/pontis.c
@@ -27,6 +27,8 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/info.h>
 
@@ -124,13 +126,13 @@
 	unsigned short val;
 	int i;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	for (i = 0; i < 2; i++) {
 		val = wm_get(ice, WM_DAC_ATTEN_L + i) & 0xff;
 		val = val > DAC_MIN ? (val - DAC_MIN) : 0;
 		ucontrol->value.integer.value[i] = val;
 	}
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -140,7 +142,7 @@
 	unsigned short oval, nval;
 	int i, idx, change = 0;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	for (i = 0; i < 2; i++) {
 		nval = ucontrol->value.integer.value[i];
 		nval = (nval ? (nval + DAC_MIN) : 0) & 0xff;
@@ -152,7 +154,7 @@
 			change = 1;
 		}
 	}
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return change;
 }
 
@@ -179,13 +181,13 @@
 	unsigned short val;
 	int i;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	for (i = 0; i < 2; i++) {
 		val = wm_get(ice, WM_ADC_ATTEN_L + i) & 0xff;
 		val = val > ADC_MIN ? (val - ADC_MIN) : 0;
 		ucontrol->value.integer.value[i] = val;
 	}
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -195,7 +197,7 @@
 	unsigned short ovol, nvol;
 	int i, idx, change = 0;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	for (i = 0; i < 2; i++) {
 		nvol = ucontrol->value.integer.value[i];
 		nvol = nvol ? (nvol + ADC_MIN) : 0;
@@ -206,7 +208,7 @@
 			change = 1;
 		}
 	}
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return change;
 }
 
@@ -227,9 +229,9 @@
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	int bit = kcontrol->private_value;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	ucontrol->value.integer.value[0] = (wm_get(ice, WM_ADC_MUX) & (1 << bit)) ? 1 : 0;
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -240,7 +242,7 @@
 	unsigned short oval, nval;
 	int change;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	nval = oval = wm_get(ice, WM_ADC_MUX);
 	if (ucontrol->value.integer.value[0])
 		nval |= (1 << bit);
@@ -250,7 +252,7 @@
 	if (change) {
 		wm_put(ice, WM_ADC_MUX, nval);
 	}
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -270,9 +272,9 @@
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	ucontrol->value.integer.value[0] = (wm_get(ice, WM_OUT_MUX) & 0x04) ? 1 : 0;
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -282,7 +284,7 @@
 	unsigned short val, oval;
 	int change = 0;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	val = oval = wm_get(ice, WM_OUT_MUX);
 	if (ucontrol->value.integer.value[0])
 		val |= 0x04;
@@ -292,7 +294,7 @@
 		wm_put(ice, WM_OUT_MUX, val);
 		change = 1;
 	}
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return change;
 }
 
@@ -312,9 +314,9 @@
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL1) & 0xf0) != 0x90;
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -324,7 +326,7 @@
 	unsigned short val, oval;
 	int change = 0;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	oval = wm_get(ice, WM_DAC_CTRL1);
 	val = oval & 0x0f;
 	if (ucontrol->value.integer.value[0])
@@ -336,7 +338,7 @@
 		wm_put_nocache(ice, WM_DAC_CTRL1, val);
 		change = 1;
 	}
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return change;
 }
 
@@ -449,9 +451,9 @@
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	ucontrol->value.enumerated.item[0] = ice->gpio.saved[0];
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -461,14 +463,14 @@
 	unsigned char val;
 	int change = 0;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	if (ucontrol->value.enumerated.item[0] != ice->gpio.saved[0]) {
 		ice->gpio.saved[0] = ucontrol->value.enumerated.item[0] & 3;
 		val = 0x80 | (ice->gpio.saved[0] << 3);
 		spi_write(ice, CS_DEV, 0x04, val);
 		change = 1;
 	}
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -488,10 +490,10 @@
 static int pontis_gpio_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	/* 4-7 reserved */
 	ucontrol->value.integer.value[0] = (~ice->gpio.write_mask & 0xffff) | 0x00f0;
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 	
@@ -500,22 +502,22 @@
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	unsigned int val;
 	int changed;
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	/* 4-7 reserved */
 	val = (~ucontrol->value.integer.value[0] & 0xffff) | 0x00f0;
 	changed = val != ice->gpio.write_mask;
 	ice->gpio.write_mask = val;
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return changed;
 }
 
 static int pontis_gpio_dir_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	/* 4-7 reserved */
 	ucontrol->value.integer.value[0] = ice->gpio.direction & 0xff0f;
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 	
@@ -524,23 +526,23 @@
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	unsigned int val;
 	int changed;
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	/* 4-7 reserved */
 	val = ucontrol->value.integer.value[0] & 0xff0f;
 	changed = (val != ice->gpio.direction);
 	ice->gpio.direction = val;
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return changed;
 }
 
 static int pontis_gpio_data_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
 	snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask);
 	ucontrol->value.integer.value[0] = snd_ice1712_gpio_read(ice) & 0xffff;
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return 0;
 }
 
@@ -549,7 +551,7 @@
 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
 	unsigned int val, nval;
 	int changed = 0;
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
 	snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask);
 	val = snd_ice1712_gpio_read(ice) & 0xffff;
@@ -558,7 +560,7 @@
 		snd_ice1712_gpio_write(ice, nval);
 		changed = 1;
 	}
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 	return changed;
 }
 
@@ -651,14 +653,14 @@
 	struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
 	char line[64];
 	unsigned int reg, val;
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	while (!snd_info_get_line(buffer, line, sizeof(line))) {
 		if (sscanf(line, "%x %x", &reg, &val) != 2)
 			continue;
 		if (reg <= 0x17 && val <= 0xffff)
 			wm_put(ice, reg, val);
 	}
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 }
 
 static void wm_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
@@ -666,12 +668,12 @@
 	struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
 	int reg, val;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	for (reg = 0; reg <= 0x17; reg++) {
 		val = wm_get(ice, reg);
 		snd_iprintf(buffer, "%02x = %04x\n", reg, val);
 	}
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 }
 
 static void wm_proc_init(struct snd_ice1712 *ice)
@@ -690,14 +692,14 @@
 	struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data;
 	int reg, val;
 
-	down(&ice->gpio_mutex);
+	mutex_lock(&ice->gpio_mutex);
 	for (reg = 0; reg <= 0x26; reg++) {
 		val = spi_read(ice, CS_DEV, reg);
 		snd_iprintf(buffer, "%02x = %02x\n", reg, val);
 	}
 	val = spi_read(ice, CS_DEV, 0x7f);
 	snd_iprintf(buffer, "%02x = %02x\n", 0x7f, val);
-	up(&ice->gpio_mutex);
+	mutex_unlock(&ice->gpio_mutex);
 }
 
 static void cs_proc_init(struct snd_ice1712 *ice)
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index 174237f..ebbf2cf 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -178,6 +178,8 @@
 #define   ICH_SAMPLE_CAP	0x00c00000	/* ICH4: sample capability bits (RO) */
 #define   ICH_SAMPLE_16_20	0x00400000	/* ICH4: 16- and 20-bit samples */
 #define   ICH_MULTICHAN_CAP	0x00300000	/* ICH4: multi-channel capability bits (RO) */
+#define   ICH_SIS_TRI		0x00080000	/* SIS: tertiary resume irq */
+#define   ICH_SIS_TCR		0x00040000	/* SIS: tertiary codec ready */
 #define   ICH_MD3		0x00020000	/* modem power down semaphore */
 #define   ICH_AD3		0x00010000	/* audio power down semaphore */
 #define   ICH_RCS		0x00008000	/* read completion status */
@@ -398,6 +400,10 @@
 	struct snd_ac97_bus *ac97_bus;
 	struct snd_ac97 *ac97[3];
 	unsigned int ac97_sdin[3];
+	unsigned int max_codecs, ncodecs;
+	unsigned int *codec_bit;
+	unsigned int codec_isr_bits;
+	unsigned int codec_ready_bits;
 
 	spinlock_t reg_lock;
 	
@@ -516,18 +522,6 @@
  * access to AC97 codec via normal i/o (for ICH and SIS7012)
  */
 
-/* return the GLOB_STA bit for the corresponding codec */
-static unsigned int get_ich_codec_bit(struct intel8x0 *chip, unsigned int codec)
-{
-	static unsigned int codec_bit[3] = {
-		ICH_PCR, ICH_SCR, ICH_TCR
-	};
-	snd_assert(codec < 3, return ICH_PCR);
-	if (chip->device_type == DEVICE_INTEL_ICH4)
-		codec = chip->ac97_sdin[codec];
-	return codec_bit[codec];
-}
-
 static int snd_intel8x0_codec_semaphore(struct intel8x0 *chip, unsigned int codec)
 {
 	int time;
@@ -537,9 +531,9 @@
 	if (chip->in_sdin_init) {
 		/* we don't know the ready bit assignment at the moment */
 		/* so we check any */
-		codec = ICH_PCR | ICH_SCR | ICH_TCR;
+		codec = chip->codec_isr_bits;
 	} else {
-		codec = get_ich_codec_bit(chip, codec);
+		codec = chip->codec_bit[chip->ac97_sdin[codec]];
 	}
 
 	/* codec ready ? */
@@ -596,7 +590,7 @@
 		if ((tmp = igetdword(chip, ICHREG(GLOB_STA))) & ICH_RCS) {
 			/* reset RCS and preserve other R/WC bits */
 			iputdword(chip, ICHREG(GLOB_STA), tmp &
-				  ~(ICH_SRI|ICH_PRI|ICH_TRI|ICH_GSCI));
+				  ~(chip->codec_ready_bits | ICH_GSCI));
 			if (! chip->in_ac97_init)
 				snd_printk(KERN_ERR "codec_read %d: read timeout for register 0x%x\n", ac97->num, reg);
 			res = 0xffff;
@@ -605,7 +599,8 @@
 	return res;
 }
 
-static void snd_intel8x0_codec_read_test(struct intel8x0 *chip, unsigned int codec)
+static void __devinit snd_intel8x0_codec_read_test(struct intel8x0 *chip,
+						   unsigned int codec)
 {
 	unsigned int tmp;
 
@@ -614,7 +609,7 @@
 		if ((tmp = igetdword(chip, ICHREG(GLOB_STA))) & ICH_RCS) {
 			/* reset RCS and preserve other R/WC bits */
 			iputdword(chip, ICHREG(GLOB_STA), tmp &
-				  ~(ICH_SRI|ICH_PRI|ICH_TRI|ICH_GSCI));
+				  ~(chip->codec_ready_bits | ICH_GSCI));
 		}
 	}
 }
@@ -2078,23 +2073,24 @@
 	if (chip->device_type != DEVICE_ALI) {
 		glob_sta = igetdword(chip, ICHREG(GLOB_STA));
 		ops = &standard_bus_ops;
-		if (chip->device_type == DEVICE_INTEL_ICH4) {
-			codecs = 0;
-			if (glob_sta & ICH_PCR)
-				codecs++;
-			if (glob_sta & ICH_SCR)
-				codecs++;
-			if (glob_sta & ICH_TCR)
-				codecs++;
-			chip->in_sdin_init = 1;
-			for (i = 0; i < codecs; i++) {
-				snd_intel8x0_codec_read_test(chip, i);
-				chip->ac97_sdin[i] = igetbyte(chip, ICHREG(SDM)) & ICH_LDI_MASK;
-			}
-			chip->in_sdin_init = 0;
-		} else {
-			codecs = glob_sta & ICH_SCR ? 2 : 1;
+		chip->in_sdin_init = 1;
+		codecs = 0;
+		for (i = 0; i < chip->max_codecs; i++) {
+			if (! (glob_sta & chip->codec_bit[i]))
+				continue;
+			if (chip->device_type == DEVICE_INTEL_ICH4) {
+				snd_intel8x0_codec_read_test(chip, codecs);
+				chip->ac97_sdin[codecs] =
+					igetbyte(chip, ICHREG(SDM)) & ICH_LDI_MASK;
+				snd_assert(chip->ac97_sdin[codecs] < 3,
+					   chip->ac97_sdin[codecs] = 0);
+			} else
+				chip->ac97_sdin[codecs] = i;
+			codecs++;
 		}
+		chip->in_sdin_init = 0;
+		if (! codecs)
+			codecs = 1;
 	} else {
 		ops = &ali_bus_ops;
 		codecs = 1;
@@ -2120,6 +2116,7 @@
 	else
 		pbus->dra = 1;
 	chip->ac97_bus = pbus;
+	chip->ncodecs = codecs;
 
 	ac97.pci = chip->pci;
 	for (i = 0; i < codecs; i++) {
@@ -2264,7 +2261,7 @@
 		end_time = jiffies + HZ;
 		do {
 			status = igetdword(chip, ICHREG(GLOB_STA)) &
-				(ICH_PCR | ICH_SCR | ICH_TCR);
+				chip->codec_isr_bits;
 			if (status)
 				break;
 			schedule_timeout_uninterruptible(1);
@@ -2276,32 +2273,27 @@
 			return -EIO;
 		}
 
-		if (chip->device_type == DEVICE_INTEL_ICH4)
-			/* ICH4 can have three codecs */
-			nstatus = ICH_PCR | ICH_SCR | ICH_TCR;
-		else
-			/* others up to two codecs */
-			nstatus = ICH_PCR | ICH_SCR;
-
 		/* wait for other codecs ready status. */
 		end_time = jiffies + HZ / 4;
-		while (status != nstatus && time_after_eq(end_time, jiffies)) {
+		while (status != chip->codec_isr_bits &&
+		       time_after_eq(end_time, jiffies)) {
 			schedule_timeout_uninterruptible(1);
-			status |= igetdword(chip, ICHREG(GLOB_STA)) & nstatus;
+			status |= igetdword(chip, ICHREG(GLOB_STA)) &
+				chip->codec_isr_bits;
 		}
 
 	} else {
 		/* resume phase */
 		int i;
 		status = 0;
-		for (i = 0; i < 3; i++)
+		for (i = 0; i < chip->ncodecs; i++)
 			if (chip->ac97[i])
-				status |= get_ich_codec_bit(chip, i);
+				status |= chip->codec_bit[chip->ac97_sdin[i]];
 		/* wait until all the probed codecs are ready */
 		end_time = jiffies + HZ;
 		do {
 			nstatus = igetdword(chip, ICHREG(GLOB_STA)) &
-				(ICH_PCR | ICH_SCR | ICH_TCR);
+				chip->codec_isr_bits;
 			if (status == nstatus)
 				break;
 			schedule_timeout_uninterruptible(1);
@@ -2359,7 +2351,7 @@
 
 static int snd_intel8x0_chip_init(struct intel8x0 *chip, int probing)
 {
-	unsigned int i;
+	unsigned int i, timeout;
 	int err;
 	
 	if (chip->device_type != DEVICE_ALI) {
@@ -2377,6 +2369,15 @@
 	/* reset channels */
 	for (i = 0; i < chip->bdbars_count; i++)
 		iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, ICH_RESETREGS);
+	for (i = 0; i < chip->bdbars_count; i++) {
+	        timeout = 100000;
+	        while (--timeout != 0) {
+        		if ((igetbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset) & ICH_RESETREGS) == 0)
+        		        break;
+                }
+                if (timeout == 0)
+                        printk(KERN_ERR "intel8x0: reset of registers failed?\n");
+        }
 	/* initialize Buffer Descriptor Lists */
 	for (i = 0; i < chip->bdbars_count; i++)
 		iputdword(chip, ICH_REG_OFF_BDBAR + chip->ichd[i].reg_offset,
@@ -2447,7 +2448,7 @@
 			}
 		}
 	}
-	for (i = 0; i < 3; i++)
+	for (i = 0; i < chip->ncodecs; i++)
 		snd_ac97_suspend(chip->ac97[i]);
 	if (chip->device_type == DEVICE_INTEL_ICH4)
 		chip->sdm_saved = igetbyte(chip, ICHREG(SDM));
@@ -2488,7 +2489,7 @@
 	if (chip->fix_nocache)
 		fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 1);
 
-	for (i = 0; i < 3; i++)
+	for (i = 0; i < chip->ncodecs; i++)
 		snd_ac97_resume(chip->ac97[i]);
 
 	/* refill nocache */
@@ -2619,12 +2620,20 @@
 	snd_iprintf(buffer, "Global status         : 0x%08x\n", tmp);
 	if (chip->device_type == DEVICE_INTEL_ICH4)
 		snd_iprintf(buffer, "SDM                   : 0x%08x\n", igetdword(chip, ICHREG(SDM)));
-	snd_iprintf(buffer, "AC'97 codecs ready    :%s%s%s%s\n",
-			tmp & ICH_PCR ? " primary" : "",
-			tmp & ICH_SCR ? " secondary" : "",
-			tmp & ICH_TCR ? " tertiary" : "",
-			(tmp & (ICH_PCR | ICH_SCR | ICH_TCR)) == 0 ? " none" : "");
-	if (chip->device_type == DEVICE_INTEL_ICH4)
+	snd_iprintf(buffer, "AC'97 codecs ready    :");
+	if (tmp & chip->codec_isr_bits) {
+		int i;
+		static const char *codecs[3] = {
+			"primary", "secondary", "tertiary"
+		};
+		for (i = 0; i < chip->max_codecs; i++)
+			if (tmp & chip->codec_bit[i])
+				snd_iprintf(buffer, " %s", codecs[i]);
+	} else
+		snd_iprintf(buffer, " none");
+	snd_iprintf(buffer, "\n");
+	if (chip->device_type == DEVICE_INTEL_ICH4 ||
+	    chip->device_type == DEVICE_SIS)
 		snd_iprintf(buffer, "AC'97 codecs SDIN     : %i %i %i\n",
 			chip->ac97_sdin[0],
 			chip->ac97_sdin[1],
@@ -2653,6 +2662,13 @@
 	unsigned int offset;
 };
 
+static unsigned int ich_codec_bits[3] = {
+	ICH_PCR, ICH_SCR, ICH_TCR
+};
+static unsigned int sis_codec_bits[3] = {
+	ICH_PCR, ICH_SCR, ICH_SIS_TCR
+};
+
 static int __devinit snd_intel8x0_create(struct snd_card *card,
 					 struct pci_dev *pci,
 					 unsigned long device_type,
@@ -2835,6 +2851,29 @@
 	pci_set_master(pci);
 	synchronize_irq(chip->irq);
 
+	switch(chip->device_type) {
+	case DEVICE_INTEL_ICH4:
+		/* ICH4 can have three codecs */
+		chip->max_codecs = 3;
+		chip->codec_bit = ich_codec_bits;
+		chip->codec_ready_bits = ICH_PRI | ICH_SRI | ICH_TRI;
+		break;
+	case DEVICE_SIS:
+		/* recent SIS7012 can have three codecs */
+		chip->max_codecs = 3;
+		chip->codec_bit = sis_codec_bits;
+		chip->codec_ready_bits = ICH_PRI | ICH_SRI | ICH_SIS_TRI;
+		break;
+	default:
+		/* others up to two codecs */
+		chip->max_codecs = 2;
+		chip->codec_bit = ich_codec_bits;
+		chip->codec_ready_bits = ICH_PRI | ICH_SRI;
+		break;
+	}
+	for (i = 0; i < chip->max_codecs; i++)
+		chip->codec_isr_bits |= chip->codec_bit[i];
+
 	if ((err = snd_intel8x0_chip_init(chip, 1)) < 0) {
 		snd_intel8x0_free(chip);
 		return err;
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
index 4eddb51..4721c09 100644
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 #include <linux/wait.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
 
 #include <sound/core.h>
 #include <sound/info.h>
@@ -325,7 +326,7 @@
         int irq;
 
         spinlock_t    lock;
-	struct semaphore open_mutex;
+	struct mutex open_mutex;
 
 	struct timer_list timer;	/* timer callback for checking ack of stop request */
 	int stop_pending_cnt;		/* counter for stop pending check */
@@ -667,13 +668,13 @@
 {
 	K1212_DEBUG_PRINTK("K1212_DEBUG: OpenCard [%s] %d\n",
 			   stateName[korg1212->cardState], korg1212->opencnt);
-	down(&korg1212->open_mutex);
+	mutex_lock(&korg1212->open_mutex);
         if (korg1212->opencnt++ == 0) {
 		snd_korg1212_TurnOffIdleMonitor(korg1212);
 		snd_korg1212_setCardState(korg1212, K1212_STATE_OPEN);
 	}
 
-	up(&korg1212->open_mutex);
+	mutex_unlock(&korg1212->open_mutex);
         return 1;
 }
 
@@ -682,9 +683,9 @@
 	K1212_DEBUG_PRINTK("K1212_DEBUG: CloseCard [%s] %d\n",
 			   stateName[korg1212->cardState], korg1212->opencnt);
 
-	down(&korg1212->open_mutex);
+	mutex_lock(&korg1212->open_mutex);
 	if (--(korg1212->opencnt)) {
-		up(&korg1212->open_mutex);
+		mutex_unlock(&korg1212->open_mutex);
 		return 0;
 	}
 
@@ -695,7 +696,7 @@
 			K1212_DEBUG_PRINTK("K1212_DEBUG: CloseCard - RC = %d [%s]\n",
 					   rc, stateName[korg1212->cardState]);
 		if (rc != K1212_CMDRET_Success) {
-			up(&korg1212->open_mutex);
+			mutex_unlock(&korg1212->open_mutex);
                         return 0;
 		}
         } else if (korg1212->cardState > K1212_STATE_SETUP) {
@@ -707,7 +708,7 @@
                 snd_korg1212_setCardState(korg1212, K1212_STATE_READY);
 	}
 
-	up(&korg1212->open_mutex);
+	mutex_unlock(&korg1212->open_mutex);
         return 0;
 }
 
@@ -2179,7 +2180,7 @@
 
         init_waitqueue_head(&korg1212->wait);
         spin_lock_init(&korg1212->lock);
-	init_MUTEX(&korg1212->open_mutex);
+	mutex_init(&korg1212->open_mutex);
 	init_timer(&korg1212->timer);
 	korg1212->timer.function = snd_korg1212_timer_func;
 	korg1212->timer.data = (unsigned long)korg1212;
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index d3ef0cc..8bc0849 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -37,6 +37,7 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/moduleparam.h>
@@ -2657,8 +2658,8 @@
 		return -EIO;
 
 	/* check, if we can restrict PCI DMA transfers to 28 bits */
-	if (pci_set_dma_mask(pci, 0x0fffffff) < 0 ||
-	    pci_set_consistent_dma_mask(pci, 0x0fffffff) < 0) {
+	if (pci_set_dma_mask(pci, DMA_28BIT_MASK) < 0 ||
+	    pci_set_consistent_dma_mask(pci, DMA_28BIT_MASK) < 0) {
 		snd_printk(KERN_ERR "architecture does not support 28bit PCI busmaster DMA\n");
 		pci_disable_device(pci);
 		return -ENXIO;
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
index b218e1d..43ee3b2 100644
--- a/sound/pci/mixart/mixart.c
+++ b/sound/pci/mixart/mixart.c
@@ -25,7 +25,9 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/initval.h>
 #include <sound/info.h>
@@ -589,7 +591,7 @@
 	/*  set up format for the stream */
 	format = params_format(hw);
 
-	down(&mgr->setup_mutex);
+	mutex_lock(&mgr->setup_mutex);
 
 	/* update the stream levels */
 	if( stream->pcm_number <= MIXART_PCM_DIGITAL ) {
@@ -628,7 +630,7 @@
 				bufferinfo[i].available_length,
 				subs->number);
 	}
-	up(&mgr->setup_mutex);
+	mutex_unlock(&mgr->setup_mutex);
 
 	return err;
 }
@@ -700,7 +702,7 @@
 	int err = 0;
 	int pcm_number;
 
-	down(&mgr->setup_mutex);
+	mutex_lock(&mgr->setup_mutex);
 
 	if ( pcm == chip->pcm ) {
 		pcm_number = MIXART_PCM_ANALOG;
@@ -758,7 +760,7 @@
 	}
 
  _exit_open:
-	up(&mgr->setup_mutex);
+	mutex_unlock(&mgr->setup_mutex);
 
 	return err;
 }
@@ -775,7 +777,7 @@
 	int err = 0;
 	int pcm_number;
 
-	down(&mgr->setup_mutex);
+	mutex_lock(&mgr->setup_mutex);
 
 	if ( pcm == chip->pcm ) {
 		pcm_number = MIXART_PCM_ANALOG;
@@ -836,7 +838,7 @@
 	}
 
  _exit_open:
-	up(&mgr->setup_mutex);
+	mutex_unlock(&mgr->setup_mutex);
 
 	return err;
 }
@@ -849,7 +851,7 @@
 	struct mixart_mgr *mgr = chip->mgr;
 	struct mixart_stream *stream = subs->runtime->private_data;
 
-	down(&mgr->setup_mutex);
+	mutex_lock(&mgr->setup_mutex);
 
 	snd_printdd("snd_mixart_close C%d/P%d/Sub%d\n", chip->chip_idx, stream->pcm_number, subs->number);
 
@@ -868,7 +870,7 @@
 	stream->status    = MIXART_STREAM_STATUS_FREE;
 	stream->substream = NULL;
 
-	up(&mgr->setup_mutex);
+	mutex_unlock(&mgr->setup_mutex);
 	return 0;
 }
 
@@ -1288,7 +1290,7 @@
 	pci_set_master(pci);
 
 	/* check if we can restrict PCI DMA transfers to 32 bits */
-	if (pci_set_dma_mask(pci, 0xffffffff) < 0) {
+	if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0) {
 		snd_printk(KERN_ERR "architecture does not support 32bit PCI busmaster DMA\n");
 		pci_disable_device(pci);
 		return -ENXIO;
@@ -1335,12 +1337,12 @@
 	mgr->msg_fifo_writeptr = 0;
 
 	spin_lock_init(&mgr->msg_lock);
-	init_MUTEX(&mgr->msg_mutex);
+	mutex_init(&mgr->msg_mutex);
 	init_waitqueue_head(&mgr->msg_sleep);
 	atomic_set(&mgr->msg_processed, 0);
 
 	/* init setup mutex*/
-	init_MUTEX(&mgr->setup_mutex);
+	mutex_init(&mgr->setup_mutex);
 
 	/* init message taslket */
 	tasklet_init(&mgr->msg_taskq, snd_mixart_msg_tasklet, (unsigned long) mgr);
diff --git a/sound/pci/mixart/mixart.h b/sound/pci/mixart/mixart.h
index 3e84863..561634d 100644
--- a/sound/pci/mixart/mixart.h
+++ b/sound/pci/mixart/mixart.h
@@ -24,6 +24,7 @@
 #define __SOUND_MIXART_H
 
 #include <linux/interrupt.h>
+#include <linux/mutex.h>
 #include <sound/pcm.h>
 
 #define MIXART_DRIVER_VERSION	0x000100	/* 0.1.0 */
@@ -92,9 +93,9 @@
 
 	spinlock_t lock;              /* interrupt spinlock */
 	spinlock_t msg_lock;          /* mailbox spinlock */
-	struct semaphore msg_mutex;   /* mutex for blocking_requests */
+	struct mutex msg_mutex;   /* mutex for blocking_requests */
 
-	struct semaphore setup_mutex; /* mutex used in hw_params, open and close */
+	struct mutex setup_mutex; /* mutex used in hw_params, open and close */
 
 	/* hardware interface */
 	unsigned int dsp_loaded;      /* bit flags of loaded dsp indices */
@@ -107,7 +108,7 @@
 	int sample_rate;
 	int ref_count_rate;
 
-	struct semaphore mixer_mutex; /* mutex for mixer */
+	struct mutex mixer_mutex; /* mutex for mixer */
 
 };
 
diff --git a/sound/pci/mixart/mixart_core.c b/sound/pci/mixart/mixart_core.c
index 07c707d..406ac3a 100644
--- a/sound/pci/mixart/mixart_core.c
+++ b/sound/pci/mixart/mixart_core.c
@@ -22,6 +22,8 @@
 
 #include <sound/driver.h>
 #include <linux/interrupt.h>
+#include <linux/mutex.h>
+
 #include <asm/io.h>
 #include <sound/core.h>
 #include "mixart.h"
@@ -239,7 +241,7 @@
 	wait_queue_t wait;
 	long timeout;
 
-	down(&mgr->msg_mutex);
+	mutex_lock(&mgr->msg_mutex);
 
 	init_waitqueue_entry(&wait, current);
 
@@ -248,7 +250,7 @@
 	err = send_msg(mgr, request, max_resp_size, 1, &msg_frame);  /* send and mark the answer pending */
 	if (err) {
 		spin_unlock_irq(&mgr->msg_lock);
-		up(&mgr->msg_mutex);
+		mutex_unlock(&mgr->msg_mutex);
 		return err;
 	}
 
@@ -260,7 +262,7 @@
 
 	if (! timeout) {
 		/* error - no ack */
-		up(&mgr->msg_mutex);
+		mutex_unlock(&mgr->msg_mutex);
 		snd_printk(KERN_ERR "error: no reponse on msg %x\n", msg_frame);
 		return -EIO;
 	}
@@ -276,7 +278,7 @@
 	if( request->message_id != resp.message_id )
 		snd_printk(KERN_ERR "REPONSE ERROR!\n");
 
-	up(&mgr->msg_mutex);
+	mutex_unlock(&mgr->msg_mutex);
 	return err;
 }
 
@@ -292,7 +294,7 @@
 	snd_assert((notif_event & MSG_TYPE_MASK) == MSG_TYPE_NOTIFY, return -EINVAL);
 	snd_assert((notif_event & MSG_CANCEL_NOTIFY_MASK) == 0, return -EINVAL);
 
-	down(&mgr->msg_mutex);
+	mutex_lock(&mgr->msg_mutex);
 
 	init_waitqueue_entry(&wait, current);
 
@@ -301,7 +303,7 @@
 	err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 1, &notif_event);  /* send and mark the notification event pending */
 	if(err) {
 		spin_unlock_irq(&mgr->msg_lock);
-		up(&mgr->msg_mutex);
+		mutex_unlock(&mgr->msg_mutex);
 		return err;
 	}
 
@@ -313,12 +315,12 @@
 
 	if (! timeout) {
 		/* error - no ack */
-		up(&mgr->msg_mutex);
+		mutex_unlock(&mgr->msg_mutex);
 		snd_printk(KERN_ERR "error: notification %x not received\n", notif_event);
 		return -EIO;
 	}
 
-	up(&mgr->msg_mutex);
+	mutex_unlock(&mgr->msg_mutex);
 	return 0;
 }
 
diff --git a/sound/pci/mixart/mixart_mixer.c b/sound/pci/mixart/mixart_mixer.c
index 36a7e9d..ed47b73 100644
--- a/sound/pci/mixart/mixart_mixer.c
+++ b/sound/pci/mixart/mixart_mixer.c
@@ -24,6 +24,8 @@
 #include <linux/time.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include "mixart.h"
 #include "mixart_core.h"
@@ -353,7 +355,7 @@
 static int mixart_analog_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_mixart *chip = snd_kcontrol_chip(kcontrol);
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	if(kcontrol->private_value == 0) {	/* playback */
 		ucontrol->value.integer.value[0] = chip->analog_playback_volume[0];
 		ucontrol->value.integer.value[1] = chip->analog_playback_volume[1];
@@ -361,7 +363,7 @@
 		ucontrol->value.integer.value[0] = chip->analog_capture_volume[0];
 		ucontrol->value.integer.value[1] = chip->analog_capture_volume[1];
 	}
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return 0;
 }
 
@@ -371,7 +373,7 @@
 	int changed = 0;
 	int is_capture, i;
 
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	is_capture = (kcontrol->private_value != 0);
 	for(i=0; i<2; i++) {
 		int  new_volume = ucontrol->value.integer.value[i];
@@ -382,7 +384,7 @@
 		}
 	}
 	if(changed)	mixart_update_analog_audio_level(chip, is_capture);
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return changed;
 }
 
@@ -408,10 +410,10 @@
 {
 	struct snd_mixart *chip = snd_kcontrol_chip(kcontrol);
 
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	ucontrol->value.integer.value[0] = chip->analog_playback_active[0];
 	ucontrol->value.integer.value[1] = chip->analog_playback_active[1];
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return 0;
 }
 
@@ -419,7 +421,7 @@
 {
 	struct snd_mixart *chip = snd_kcontrol_chip(kcontrol);
 	int i, changed = 0;
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	for(i=0; i<2; i++) {
 		if(chip->analog_playback_active[i] != ucontrol->value.integer.value[i]) {
 			chip->analog_playback_active[i] = ucontrol->value.integer.value[i];
@@ -427,7 +429,7 @@
 		}
 	}
 	if(changed)	mixart_update_analog_audio_level(chip, 0); /* update playback levels */
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return changed;
 }
 
@@ -817,7 +819,7 @@
 	int *stored_volume;
 	int is_capture = kcontrol->private_value & MIXART_VOL_REC_MASK;
 	int is_aes = kcontrol->private_value & MIXART_VOL_AES_MASK;
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	if(is_capture) {
 		if(is_aes)	stored_volume = chip->digital_capture_volume[1];	/* AES capture */
 		else		stored_volume = chip->digital_capture_volume[0];	/* analog capture */
@@ -828,7 +830,7 @@
 	}
 	ucontrol->value.integer.value[0] = stored_volume[0];
 	ucontrol->value.integer.value[1] = stored_volume[1];
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return 0;
 }
 
@@ -841,7 +843,7 @@
 	int is_aes = kcontrol->private_value & MIXART_VOL_AES_MASK;
 	int* stored_volume;
 	int i;
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	if(is_capture) {
 		if(is_aes)	stored_volume = chip->digital_capture_volume[1];	/* AES capture */
 		else		stored_volume = chip->digital_capture_volume[0];	/* analog capture */
@@ -860,7 +862,7 @@
 		if(is_capture)	mixart_update_capture_stream_level(chip, is_aes);
 		else		mixart_update_playback_stream_level(chip, is_aes, idx);
 	}
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return changed;
 }
 
@@ -880,12 +882,12 @@
 	struct snd_mixart *chip = snd_kcontrol_chip(kcontrol);
 	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
 	snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); 
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	if(kcontrol->private_value & MIXART_VOL_AES_MASK)	/* AES playback */
 		idx += MIXART_PLAYBACK_STREAMS;
 	ucontrol->value.integer.value[0] = chip->digital_playback_active[idx][0];
 	ucontrol->value.integer.value[1] = chip->digital_playback_active[idx][1];
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return 0;
 }
 
@@ -897,7 +899,7 @@
 	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
 	int i, j;
 	snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); 
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	j = idx;
 	if(is_aes)	j += MIXART_PLAYBACK_STREAMS;
 	for(i=0; i<2; i++) {
@@ -907,7 +909,7 @@
 		}
 	}
 	if(changed)	mixart_update_playback_stream_level(chip, is_aes, idx);
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return changed;
 }
 
@@ -956,10 +958,10 @@
 static int mixart_monitor_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_mixart *chip = snd_kcontrol_chip(kcontrol);
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	ucontrol->value.integer.value[0] = chip->monitoring_volume[0];
 	ucontrol->value.integer.value[1] = chip->monitoring_volume[1];
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return 0;
 }
 
@@ -968,7 +970,7 @@
 	struct snd_mixart *chip = snd_kcontrol_chip(kcontrol);
 	int changed = 0;
 	int i;
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	for(i=0; i<2; i++) {
 		if(chip->monitoring_volume[i] != ucontrol->value.integer.value[i]) {
 			chip->monitoring_volume[i] = ucontrol->value.integer.value[i];
@@ -976,7 +978,7 @@
 			changed = 1;
 		}
 	}
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return changed;
 }
 
@@ -995,10 +997,10 @@
 static int mixart_monitor_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_mixart *chip = snd_kcontrol_chip(kcontrol);
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	ucontrol->value.integer.value[0] = chip->monitoring_active[0];
 	ucontrol->value.integer.value[1] = chip->monitoring_active[1];
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return 0;
 }
 
@@ -1007,7 +1009,7 @@
 	struct snd_mixart *chip = snd_kcontrol_chip(kcontrol);
 	int changed = 0;
 	int i;
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	for(i=0; i<2; i++) {
 		if(chip->monitoring_active[i] != ucontrol->value.integer.value[i]) {
 			chip->monitoring_active[i] = ucontrol->value.integer.value[i];
@@ -1029,7 +1031,7 @@
 		}
 	}
 
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return (changed != 0);
 }
 
@@ -1059,7 +1061,7 @@
 	struct snd_mixart *chip;
 	int err, i;
 
-	init_MUTEX(&mgr->mixer_mutex); /* can be in another place */
+	mutex_init(&mgr->mixer_mutex); /* can be in another place */
 
 	for(i=0; i<mgr->num_cards; i++) {
 		struct snd_kcontrol_new temp;
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
index 0d0ff54..cc297ab 100644
--- a/sound/pci/nm256/nm256.c
+++ b/sound/pci/nm256/nm256.c
@@ -32,6 +32,8 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/control.h>
@@ -226,6 +228,7 @@
 	unsigned int use_cache: 1;	/* use one big coef. table */
 	unsigned int reset_workaround: 1; /* Workaround for some laptops to avoid freeze */
 	unsigned int reset_workaround_2: 1; /* Extended workaround for some other laptops to avoid freeze */
+	unsigned int in_resume: 1;
 
 	int mixer_base;			/* register offset of ac97 mixer */
 	int mixer_status_offset;	/* offset of mixer status reg. */
@@ -235,11 +238,12 @@
 	int irq_acks;
 	irqreturn_t (*interrupt)(int, void *, struct pt_regs *);
 	int badintrcount;		/* counter to check bogus interrupts */
-	struct semaphore irq_mutex;
+	struct mutex irq_mutex;
 
 	struct nm256_stream streams[2];
 
 	struct snd_ac97 *ac97;
+	unsigned short *ac97_regs; /* register caches, only for valid regs */
 
 	struct snd_pcm *pcm;
 
@@ -459,32 +463,32 @@
 /* acquire interrupt */
 static int snd_nm256_acquire_irq(struct nm256 *chip)
 {
-	down(&chip->irq_mutex);
+	mutex_lock(&chip->irq_mutex);
 	if (chip->irq < 0) {
 		if (request_irq(chip->pci->irq, chip->interrupt, SA_INTERRUPT|SA_SHIRQ,
 				chip->card->driver, chip)) {
 			snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->pci->irq);
-			up(&chip->irq_mutex);
+			mutex_unlock(&chip->irq_mutex);
 			return -EBUSY;
 		}
 		chip->irq = chip->pci->irq;
 	}
 	chip->irq_acks++;
-	up(&chip->irq_mutex);
+	mutex_unlock(&chip->irq_mutex);
 	return 0;
 }
 
 /* release interrupt */
 static void snd_nm256_release_irq(struct nm256 *chip)
 {
-	down(&chip->irq_mutex);
+	mutex_lock(&chip->irq_mutex);
 	if (chip->irq_acks > 0)
 		chip->irq_acks--;
 	if (chip->irq_acks == 0 && chip->irq >= 0) {
 		free_irq(chip->irq, chip);
 		chip->irq = -1;
 	}
-	up(&chip->irq_mutex);
+	mutex_unlock(&chip->irq_mutex);
 }
 
 /*
@@ -1151,23 +1155,63 @@
 	return 0;
 }
 
+/* 
+ * Initial register values to be written to the AC97 mixer.
+ * While most of these are identical to the reset values, we do this
+ * so that we have most of the register contents cached--this avoids
+ * reading from the mixer directly (which seems to be problematic,
+ * probably due to ignorance).
+ */
+
+struct initialValues {
+	unsigned short reg;
+	unsigned short value;
+};
+
+static struct initialValues nm256_ac97_init_val[] =
+{
+	{ AC97_MASTER, 		0x8000 },
+	{ AC97_HEADPHONE,	0x8000 },
+	{ AC97_MASTER_MONO,	0x8000 },
+	{ AC97_PC_BEEP,		0x8000 },
+	{ AC97_PHONE,		0x8008 },
+	{ AC97_MIC,		0x8000 },
+	{ AC97_LINE,		0x8808 },
+	{ AC97_CD,		0x8808 },
+	{ AC97_VIDEO,		0x8808 },
+	{ AC97_AUX,		0x8808 },
+	{ AC97_PCM,		0x8808 },
+	{ AC97_REC_SEL,		0x0000 },
+	{ AC97_REC_GAIN,	0x0B0B },
+	{ AC97_GENERAL_PURPOSE,	0x0000 },
+	{ AC97_3D_CONTROL,	0x8000 }, 
+	{ AC97_VENDOR_ID1, 	0x8384 },
+	{ AC97_VENDOR_ID2,	0x7609 },
+};
+
+static int nm256_ac97_idx(unsigned short reg)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(nm256_ac97_init_val); i++)
+		if (nm256_ac97_init_val[i].reg == reg)
+			return i;
+	return -1;
+}
+
 /*
+ * some nm256 easily crash when reading from mixer registers
+ * thus we're treating it as a write-only mixer and cache the
+ * written values
  */
 static unsigned short
 snd_nm256_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
 {
 	struct nm256 *chip = ac97->private_data;
-	int res;
+	int idx = nm256_ac97_idx(reg);
 
-	if (reg >= 128)
+	if (idx < 0)
 		return 0;
-
-	if (! snd_nm256_ac97_ready(chip))
-		return 0;
-	res = snd_nm256_readw(chip, chip->mixer_base + reg);
-	/* Magic delay.  Bleah yucky.  */
-	msleep(1);
-	return res;
+	return chip->ac97_regs[idx];
 }
 
 /* 
@@ -1178,8 +1222,12 @@
 {
 	struct nm256 *chip = ac97->private_data;
 	int tries = 2;
+	int idx = nm256_ac97_idx(reg);
 	u32 base;
 
+	if (idx < 0)
+		return;
+
 	base = chip->mixer_base;
 
 	snd_nm256_ac97_ready(chip);
@@ -1188,12 +1236,32 @@
 	while (tries-- > 0) {
 		snd_nm256_writew(chip, base + reg, val);
 		msleep(1);  /* a little delay here seems better.. */
-		if (snd_nm256_ac97_ready(chip))
+		if (snd_nm256_ac97_ready(chip)) {
+			/* successful write: set cache */
+			chip->ac97_regs[idx] = val;
 			return;
+		}
 	}
 	snd_printd("nm256: ac97 codec not ready..\n");
 }
 
+/* static resolution table */
+static struct snd_ac97_res_table nm256_res_table[] = {
+	{ AC97_MASTER, 0x1f1f },
+	{ AC97_HEADPHONE, 0x1f1f },
+	{ AC97_MASTER_MONO, 0x001f },
+	{ AC97_PC_BEEP, 0x001f },
+	{ AC97_PHONE, 0x001f },
+	{ AC97_MIC, 0x001f },
+	{ AC97_LINE, 0x1f1f },
+	{ AC97_CD, 0x1f1f },
+	{ AC97_VIDEO, 0x1f1f },
+	{ AC97_AUX, 0x1f1f },
+	{ AC97_PCM, 0x1f1f },
+	{ AC97_REC_GAIN, 0x0f0f },
+	{ } /* terminator */
+};
+
 /* initialize the ac97 into a known state */
 static void
 snd_nm256_ac97_reset(struct snd_ac97 *ac97)
@@ -1211,6 +1279,16 @@
 		snd_nm256_writeb(chip, 0x6cc, 0x80);
 		snd_nm256_writeb(chip, 0x6cc, 0x0);
 	}
+	if (! chip->in_resume) {
+		int i;
+		for (i = 0; i < ARRAY_SIZE(nm256_ac97_init_val); i++) {
+			/* preload the cache, so as to avoid even a single
+			 * read of the mixer regs
+			 */
+			snd_nm256_ac97_write(ac97, nm256_ac97_init_val[i].reg,
+					     nm256_ac97_init_val[i].value);
+		}
+	}
 }
 
 /* create an ac97 mixer interface */
@@ -1219,32 +1297,25 @@
 {
 	struct snd_ac97_bus *pbus;
 	struct snd_ac97_template ac97;
-	int i, err;
+	int err;
 	static struct snd_ac97_bus_ops ops = {
 		.reset = snd_nm256_ac97_reset,
 		.write = snd_nm256_ac97_write,
 		.read = snd_nm256_ac97_read,
 	};
-	/* looks like nm256 hangs up when unexpected registers are touched... */
-	static int mixer_regs[] = {
-		AC97_MASTER, AC97_HEADPHONE, AC97_MASTER_MONO,
-		AC97_PC_BEEP, AC97_PHONE, AC97_MIC, AC97_LINE, AC97_CD,
-		AC97_VIDEO, AC97_AUX, AC97_PCM, AC97_REC_SEL,
-		AC97_REC_GAIN, AC97_GENERAL_PURPOSE, AC97_3D_CONTROL,
-		/*AC97_EXTENDED_ID,*/
-		AC97_VENDOR_ID1, AC97_VENDOR_ID2,
-		-1
-	};
+
+	chip->ac97_regs = kcalloc(sizeof(short),
+				  ARRAY_SIZE(nm256_ac97_init_val), GFP_KERNEL);
+	if (! chip->ac97_regs)
+		return -ENOMEM;
 
 	if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &pbus)) < 0)
 		return err;
 
 	memset(&ac97, 0, sizeof(ac97));
 	ac97.scaps = AC97_SCAP_AUDIO; /* we support audio! */
-	ac97.limited_regs = 1;
-	for (i = 0; mixer_regs[i] >= 0; i++)
-		set_bit(mixer_regs[i], ac97.reg_accessed);
 	ac97.private_data = chip;
+	ac97.res_table = nm256_res_table;
 	pbus->no_vra = 1;
 	err = snd_ac97_mixer(pbus, &ac97, &chip->ac97);
 	if (err < 0)
@@ -1329,6 +1400,7 @@
 	int i;
 
 	/* Perform a full reset on the hardware */
+	chip->in_resume = 1;
 	pci_restore_state(pci);
 	pci_enable_device(pci);
 	snd_nm256_init_chip(chip);
@@ -1346,6 +1418,7 @@
 	}
 
 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
+	chip->in_resume = 0;
 	return 0;
 }
 #endif /* CONFIG_PM */
@@ -1370,6 +1443,7 @@
 		free_irq(chip->irq, chip);
 
 	pci_disable_device(chip->pci);
+	kfree(chip->ac97_regs);
 	kfree(chip);
 	return 0;
 }
@@ -1407,7 +1481,7 @@
 	chip->use_cache = use_cache;
 	spin_lock_init(&chip->reg_lock);
 	chip->irq = -1;
-	init_MUTEX(&chip->irq_mutex);
+	mutex_init(&chip->irq_mutex);
 
 	/* store buffer sizes in bytes */
 	chip->streams[SNDRV_PCM_STREAM_PLAYBACK].bufsize = playback_bufsize * 1024;
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c
index b2cba75..f679779 100644
--- a/sound/pci/pcxhr/pcxhr.c
+++ b/sound/pci/pcxhr/pcxhr.c
@@ -26,8 +26,11 @@
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/delay.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/initval.h>
 #include <sound/info.h>
@@ -518,7 +521,7 @@
 	struct timeval my_tv1, my_tv2;
 	do_gettimeofday(&my_tv1);
 #endif
-	down(&mgr->setup_mutex);
+	mutex_lock(&mgr->setup_mutex);
 
 	/* check the pipes concerned and build pipe_array */
 	for (i = 0; i < mgr->num_cards; i++) {
@@ -537,7 +540,7 @@
 		}
 	}
 	if (capture_mask == 0 && playback_mask == 0) {
-		up(&mgr->setup_mutex);
+		mutex_unlock(&mgr->setup_mutex);
 		snd_printk(KERN_ERR "pcxhr_trigger_tasklet : no pipes\n");
 		return;
 	}
@@ -548,7 +551,7 @@
 	/* synchronous stop of all the pipes concerned */
 	err = pcxhr_set_pipe_state(mgr,  playback_mask, capture_mask, 0);
 	if (err) {
-		up(&mgr->setup_mutex);
+		mutex_unlock(&mgr->setup_mutex);
 		snd_printk(KERN_ERR "pcxhr_trigger_tasklet : error stop pipes (P%x C%x)\n",
 			   playback_mask, capture_mask);
 		return;
@@ -592,7 +595,7 @@
 	/* synchronous start of all the pipes concerned */
 	err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 1);
 	if (err) {
-		up(&mgr->setup_mutex);
+		mutex_unlock(&mgr->setup_mutex);
 		snd_printk(KERN_ERR "pcxhr_trigger_tasklet : error start pipes (P%x C%x)\n",
 			   playback_mask, capture_mask);
 		return;
@@ -619,7 +622,7 @@
 	}
 	spin_unlock_irqrestore(&mgr->lock, flags);
 
-	up(&mgr->setup_mutex);
+	mutex_unlock(&mgr->setup_mutex);
 
 #ifdef CONFIG_SND_DEBUG_DETECT
 	do_gettimeofday(&my_tv2);
@@ -728,7 +731,7 @@
 	}
 	*/
 
-	down(&mgr->setup_mutex);
+	mutex_lock(&mgr->setup_mutex);
 
 	do {
 		/* if the stream was stopped before, format and buffer were reset */
@@ -755,7 +758,7 @@
 		}
 	} while(0);	/* do only once (so we can use break instead of goto) */
 
-	up(&mgr->setup_mutex);
+	mutex_unlock(&mgr->setup_mutex);
 
 	return err;
 }
@@ -780,7 +783,7 @@
 	/*  set up format for the stream */
 	format = params_format(hw);
 
-	down(&mgr->setup_mutex);
+	mutex_lock(&mgr->setup_mutex);
 
 	stream->channels = channels;
 	stream->format = format;
@@ -789,7 +792,7 @@
 	/*
 	err = pcxhr_set_format(stream);
 	if(err) {
-		up(&mgr->setup_mutex);
+		mutex_unlock(&mgr->setup_mutex);
 		return err;
 	}
 	*/
@@ -801,7 +804,7 @@
 		err = pcxhr_update_r_buffer(stream);
 	}
 	*/
-	up(&mgr->setup_mutex);
+	mutex_unlock(&mgr->setup_mutex);
 
 	return err;
 }
@@ -847,7 +850,7 @@
 	struct pcxhr_stream    *stream;
 	int                 is_capture;
 
-	down(&mgr->setup_mutex);
+	mutex_lock(&mgr->setup_mutex);
 
 	/* copy the struct snd_pcm_hardware struct */
 	runtime->hw = pcxhr_caps;
@@ -871,7 +874,7 @@
 		/* streams in use */
 		snd_printk(KERN_ERR "pcxhr_open chip%d subs%d in use\n",
 			   chip->chip_idx, subs->number);
-		up(&mgr->setup_mutex);
+		mutex_unlock(&mgr->setup_mutex);
 		return -EBUSY;
 	}
 
@@ -887,7 +890,7 @@
 						     &external_rate) ||
 			    external_rate == 0) {
 				/* cannot detect the external clock rate */
-				up(&mgr->setup_mutex);
+				mutex_unlock(&mgr->setup_mutex);
 				return -EBUSY;
 			}
 			runtime->hw.rate_min = runtime->hw.rate_max = external_rate;
@@ -905,7 +908,7 @@
 
 	mgr->ref_count_rate++;
 
-	up(&mgr->setup_mutex);
+	mutex_unlock(&mgr->setup_mutex);
 	return 0;
 }
 
@@ -916,7 +919,7 @@
 	struct pcxhr_mgr *mgr = chip->mgr;
 	struct pcxhr_stream *stream = subs->runtime->private_data;
 
-	down(&mgr->setup_mutex);
+	mutex_lock(&mgr->setup_mutex);
 
 	snd_printdd("pcxhr_close chip%d subs%d\n", chip->chip_idx, subs->number);
 
@@ -929,7 +932,7 @@
 	stream->status    = PCXHR_STREAM_STATUS_FREE;
 	stream->substream = NULL;
 
-	up(&mgr->setup_mutex);
+	mutex_unlock(&mgr->setup_mutex);
 
 	return 0;
 }
@@ -1215,7 +1218,7 @@
 	pci_set_master(pci);
 
 	/* check if we can restrict PCI DMA transfers to 32 bits */
-	if (pci_set_dma_mask(pci, 0xffffffff) < 0) {
+	if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0) {
 		snd_printk(KERN_ERR "architecture does not support 32bit PCI busmaster DMA\n");
 		pci_disable_device(pci);
 		return -ENXIO;
@@ -1264,7 +1267,7 @@
 	spin_lock_init(&mgr->msg_lock);
 
 	/* init setup mutex*/
-	init_MUTEX(&mgr->setup_mutex);
+	mutex_init(&mgr->setup_mutex);
 
 	/* init taslket */
 	tasklet_init(&mgr->msg_taskq, pcxhr_msg_tasklet, (unsigned long) mgr);
diff --git a/sound/pci/pcxhr/pcxhr.h b/sound/pci/pcxhr/pcxhr.h
index 049f2b3..6520647 100644
--- a/sound/pci/pcxhr/pcxhr.h
+++ b/sound/pci/pcxhr/pcxhr.h
@@ -24,6 +24,7 @@
 #define __SOUND_PCXHR_H
 
 #include <linux/interrupt.h>
+#include <linux/mutex.h>
 #include <sound/pcm.h>
 
 #define PCXHR_DRIVER_VERSION		0x000804	/* 0.8.4 */
@@ -76,8 +77,8 @@
 	spinlock_t lock;		/* interrupt spinlock */
 	spinlock_t msg_lock;		/* message spinlock */
 
-	struct semaphore setup_mutex;	/* mutex used in hw_params, open and close */
-	struct semaphore mixer_mutex;	/* mutex for mixer */
+	struct mutex setup_mutex;	/* mutex used in hw_params, open and close */
+	struct mutex mixer_mutex;	/* mutex for mixer */
 
 	/* hardware interface */
 	unsigned int dsp_loaded;	/* bit flags of loaded dsp indices */
diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c
index fa0d27e..fdc652c 100644
--- a/sound/pci/pcxhr/pcxhr_core.c
+++ b/sound/pci/pcxhr/pcxhr_core.c
@@ -1176,7 +1176,7 @@
 		mgr->dsp_time_last = dsp_time_new;
 
 		if (timer_toggle == mgr->timer_toggle)
-			snd_printk(KERN_ERR "ERROR TIMER TOGGLE\n");
+			snd_printdd("ERROR TIMER TOGGLE\n");
 		mgr->timer_toggle = timer_toggle;
 
 		reg &= ~PCXHR_IRQ_TIMER;
diff --git a/sound/pci/pcxhr/pcxhr_mixer.c b/sound/pci/pcxhr/pcxhr_mixer.c
index 760e733..94e63a1 100644
--- a/sound/pci/pcxhr/pcxhr_mixer.c
+++ b/sound/pci/pcxhr/pcxhr_mixer.c
@@ -25,6 +25,7 @@
 #include <linux/time.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include "pcxhr.h"
 #include "pcxhr_hwdep.h"
@@ -92,7 +93,7 @@
 				struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	if (kcontrol->private_value == 0) {	/* playback */
 		ucontrol->value.integer.value[0] = chip->analog_playback_volume[0];
 		ucontrol->value.integer.value[1] = chip->analog_playback_volume[1];
@@ -100,7 +101,7 @@
 		ucontrol->value.integer.value[0] = chip->analog_capture_volume[0];
 		ucontrol->value.integer.value[1] = chip->analog_capture_volume[1];
 	}
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return 0;
 }
 
@@ -111,7 +112,7 @@
 	int changed = 0;
 	int is_capture, i;
 
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	is_capture = (kcontrol->private_value != 0);
 	for (i = 0; i < 2; i++) {
 		int  new_volume = ucontrol->value.integer.value[i];
@@ -123,7 +124,7 @@
 			pcxhr_update_analog_audio_level(chip, is_capture, i);
 		}
 	}
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return changed;
 }
 
@@ -150,10 +151,10 @@
 {
 	struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
 
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	ucontrol->value.integer.value[0] = chip->analog_playback_active[0];
 	ucontrol->value.integer.value[1] = chip->analog_playback_active[1];
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return 0;
 }
 
@@ -162,7 +163,7 @@
 {
 	struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
 	int i, changed = 0;
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	for(i = 0; i < 2; i++) {
 		if (chip->analog_playback_active[i] != ucontrol->value.integer.value[i]) {
 			chip->analog_playback_active[i] = ucontrol->value.integer.value[i];
@@ -170,7 +171,7 @@
 			pcxhr_update_analog_audio_level(chip, 0, i);	/* update playback levels */
 		}
 	}
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return changed;
 }
 
@@ -299,14 +300,14 @@
 	int *stored_volume;
 	int is_capture = kcontrol->private_value;
 
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	if (is_capture)
 		stored_volume = chip->digital_capture_volume;		/* digital capture */
 	else
 		stored_volume = chip->digital_playback_volume[idx];	/* digital playback */
 	ucontrol->value.integer.value[0] = stored_volume[0];
 	ucontrol->value.integer.value[1] = stored_volume[1];
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return 0;
 }
 
@@ -320,7 +321,7 @@
 	int *stored_volume;
 	int i;
 
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	if (is_capture)
 		stored_volume = chip->digital_capture_volume;		/* digital capture */
 	else
@@ -335,7 +336,7 @@
 	}
 	if (! is_capture && changed)
 		pcxhr_update_playback_stream_level(chip, idx);	/* update playback volume */
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return changed;
 }
 
@@ -356,10 +357,10 @@
 	struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
 	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
 
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	ucontrol->value.integer.value[0] = chip->digital_playback_active[idx][0];
 	ucontrol->value.integer.value[1] = chip->digital_playback_active[idx][1];
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return 0;
 }
 
@@ -370,7 +371,7 @@
 	int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */
 	int i, j;
 
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	j = idx;
 	for (i = 0; i < 2; i++) {
 		if (chip->digital_playback_active[j][i] != ucontrol->value.integer.value[i]) {
@@ -380,7 +381,7 @@
 	}
 	if (changed)
 		pcxhr_update_playback_stream_level(chip, idx);
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return changed;
 }
 
@@ -402,10 +403,10 @@
 				 struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	ucontrol->value.integer.value[0] = chip->monitoring_volume[0];
 	ucontrol->value.integer.value[1] = chip->monitoring_volume[1];
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return 0;
 }
 
@@ -416,7 +417,7 @@
 	int changed = 0;
 	int i;
 
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	for (i = 0; i < 2; i++) {
 		if (chip->monitoring_volume[i] != ucontrol->value.integer.value[i]) {
 			chip->monitoring_volume[i] = ucontrol->value.integer.value[i];
@@ -426,7 +427,7 @@
 			changed = 1;
 		}
 	}
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return changed;
 }
 
@@ -446,10 +447,10 @@
 				struct snd_ctl_elem_value *ucontrol)
 {
 	struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	ucontrol->value.integer.value[0] = chip->monitoring_active[0];
 	ucontrol->value.integer.value[1] = chip->monitoring_active[1];
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return 0;
 }
 
@@ -460,7 +461,7 @@
 	int changed = 0;
 	int i;
 
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	for (i = 0; i < 2; i++) {
 		if (chip->monitoring_active[i] != ucontrol->value.integer.value[i]) {
 			chip->monitoring_active[i] = ucontrol->value.integer.value[i];
@@ -474,7 +475,7 @@
 		/* update right monitoring volume and mute */
 		pcxhr_update_audio_pipe_level(chip, 0, 1);
 
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return (changed != 0);
 }
 
@@ -571,13 +572,13 @@
 	struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol);
 	int ret = 0;
 
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	if (chip->audio_capture_source != ucontrol->value.enumerated.item[0]) {
 		chip->audio_capture_source = ucontrol->value.enumerated.item[0];
 		pcxhr_set_audio_source(chip);
 		ret = 1;
 	}
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return ret;
 }
 
@@ -636,9 +637,9 @@
 	struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol);
 	int rate, ret = 0;
 
-	down(&mgr->mixer_mutex);
+	mutex_lock(&mgr->mixer_mutex);
 	if (mgr->use_clock_type != ucontrol->value.enumerated.item[0]) {
-		down(&mgr->setup_mutex);
+		mutex_lock(&mgr->setup_mutex);
 		mgr->use_clock_type = ucontrol->value.enumerated.item[0];
 		if (mgr->use_clock_type)
 			pcxhr_get_external_clock(mgr, mgr->use_clock_type, &rate);
@@ -649,10 +650,10 @@
 			if (mgr->sample_rate)
 				mgr->sample_rate = rate;
 		}
-		up(&mgr->setup_mutex);
+		mutex_unlock(&mgr->setup_mutex);
 		ret = 1;	/* return 1 even if the set was not done. ok ? */
 	}
-	up(&mgr->mixer_mutex);
+	mutex_unlock(&mgr->mixer_mutex);
 	return ret;
 }
 
@@ -685,7 +686,7 @@
 	struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol);
 	int i, err, rate;
 
-	down(&mgr->mixer_mutex);
+	mutex_lock(&mgr->mixer_mutex);
 	for(i = 0; i < 3 + mgr->capture_chips; i++) {
 		if (i == PCXHR_CLOCK_TYPE_INTERNAL)
 			rate = mgr->sample_rate_real;
@@ -696,7 +697,7 @@
 		}
 		ucontrol->value.integer.value[i] = rate;
 	}
-	up(&mgr->mixer_mutex);
+	mutex_unlock(&mgr->mixer_mutex);
 	return 0;
 }
 
@@ -765,7 +766,7 @@
 	unsigned char aes_bits;
 	int i, err;
 
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	for(i = 0; i < 5; i++) {
 		if (kcontrol->private_value == 0)	/* playback */
 			aes_bits = chip->aes_bits[i];
@@ -776,7 +777,7 @@
 		}
 		ucontrol->value.iec958.status[i] = aes_bits;
 	}
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
         return 0;
 }
 
@@ -828,14 +829,14 @@
 	int i, changed = 0;
 
 	/* playback */
-	down(&chip->mgr->mixer_mutex);
+	mutex_lock(&chip->mgr->mixer_mutex);
 	for (i = 0; i < 5; i++) {
 		if (ucontrol->value.iec958.status[i] != chip->aes_bits[i]) {
 			pcxhr_iec958_update_byte(chip, i, ucontrol->value.iec958.status[i]);
 			changed = 1;
 		}
 	}
-	up(&chip->mgr->mixer_mutex);
+	mutex_unlock(&chip->mgr->mixer_mutex);
 	return changed;
 }
 
@@ -916,7 +917,7 @@
 	struct snd_pcxhr *chip;
 	int err, i;
 
-	init_MUTEX(&mgr->mixer_mutex); /* can be in another place */
+	mutex_init(&mgr->mixer_mutex); /* can be in another place */
 
 	for (i = 0; i < mgr->num_cards; i++) {
 		struct snd_kcontrol_new temp;
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index 103b4d7..980b9cd 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -474,7 +474,7 @@
 static inline int hdspm_read_in_gain(struct hdspm * hdspm, unsigned int chan,
 				     unsigned int in)
 {
-	if (chan > HDSPM_MIXER_CHANNELS || in > HDSPM_MIXER_CHANNELS)
+	if (chan >= HDSPM_MIXER_CHANNELS || in >= HDSPM_MIXER_CHANNELS)
 		return 0;
 
 	return hdspm->mixer->ch[chan].in[in];
@@ -483,7 +483,7 @@
 static inline int hdspm_read_pb_gain(struct hdspm * hdspm, unsigned int chan,
 				     unsigned int pb)
 {
-	if (chan > HDSPM_MIXER_CHANNELS || pb > HDSPM_MIXER_CHANNELS)
+	if (chan >= HDSPM_MIXER_CHANNELS || pb >= HDSPM_MIXER_CHANNELS)
 		return 0;
 	return hdspm->mixer->ch[chan].pb[pb];
 }
diff --git a/sound/pci/trident/trident_memory.c b/sound/pci/trident/trident_memory.c
index cf09ea9..46c6982 100644
--- a/sound/pci/trident/trident_memory.c
+++ b/sound/pci/trident/trident_memory.c
@@ -27,6 +27,8 @@
 #include <asm/io.h>
 #include <linux/pci.h>
 #include <linux/time.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/trident.h>
 
@@ -201,16 +203,16 @@
 
 	
 
-	down(&hdr->block_mutex);
+	mutex_lock(&hdr->block_mutex);
 	blk = search_empty(hdr, runtime->dma_bytes);
 	if (blk == NULL) {
-		up(&hdr->block_mutex);
+		mutex_unlock(&hdr->block_mutex);
 		return NULL;
 	}
 	if (lastpg(blk) - firstpg(blk) >= sgbuf->pages) {
 		snd_printk(KERN_ERR "page calculation doesn't match: allocated pages = %d, trident = %d/%d\n", sgbuf->pages, firstpg(blk), lastpg(blk));
 		__snd_util_mem_free(hdr, blk);
-		up(&hdr->block_mutex);
+		mutex_unlock(&hdr->block_mutex);
 		return NULL;
 	}
 			   
@@ -221,12 +223,12 @@
 		unsigned long ptr = (unsigned long)sgbuf->table[idx].buf;
 		if (! is_valid_page(addr)) {
 			__snd_util_mem_free(hdr, blk);
-			up(&hdr->block_mutex);
+			mutex_unlock(&hdr->block_mutex);
 			return NULL;
 		}
 		set_tlb_bus(trident, page, ptr, addr);
 	}
-	up(&hdr->block_mutex);
+	mutex_unlock(&hdr->block_mutex);
 	return blk;
 }
 
@@ -248,10 +250,10 @@
 	hdr = trident->tlb.memhdr;
 	snd_assert(hdr != NULL, return NULL);
 
-	down(&hdr->block_mutex);
+	mutex_lock(&hdr->block_mutex);
 	blk = search_empty(hdr, runtime->dma_bytes);
 	if (blk == NULL) {
-		up(&hdr->block_mutex);
+		mutex_unlock(&hdr->block_mutex);
 		return NULL;
 	}
 			   
@@ -262,12 +264,12 @@
 	     ptr += SNDRV_TRIDENT_PAGE_SIZE, addr += SNDRV_TRIDENT_PAGE_SIZE) {
 		if (! is_valid_page(addr)) {
 			__snd_util_mem_free(hdr, blk);
-			up(&hdr->block_mutex);
+			mutex_unlock(&hdr->block_mutex);
 			return NULL;
 		}
 		set_tlb_bus(trident, page, ptr, addr);
 	}
-	up(&hdr->block_mutex);
+	mutex_unlock(&hdr->block_mutex);
 	return blk;
 }
 
@@ -300,13 +302,13 @@
 	snd_assert(blk != NULL, return -EINVAL);
 
 	hdr = trident->tlb.memhdr;
-	down(&hdr->block_mutex);
+	mutex_lock(&hdr->block_mutex);
 	/* reset TLB entries */
 	for (page = firstpg(blk); page <= lastpg(blk); page++)
 		set_silent_tlb(trident, page);
 	/* free memory block */
 	__snd_util_mem_free(hdr, blk);
-	up(&hdr->block_mutex);
+	mutex_unlock(&hdr->block_mutex);
 	return 0;
 }
 
@@ -332,18 +334,18 @@
 	struct snd_util_memblk *blk;
 	struct snd_util_memhdr *hdr = hw->tlb.memhdr; 
 
-	down(&hdr->block_mutex);
+	mutex_lock(&hdr->block_mutex);
 	blk = __snd_util_mem_alloc(hdr, size);
 	if (blk == NULL) {
-		up(&hdr->block_mutex);
+		mutex_unlock(&hdr->block_mutex);
 		return NULL;
 	}
 	if (synth_alloc_pages(hw, blk)) {
 		__snd_util_mem_free(hdr, blk);
-		up(&hdr->block_mutex);
+		mutex_unlock(&hdr->block_mutex);
 		return NULL;
 	}
-	up(&hdr->block_mutex);
+	mutex_unlock(&hdr->block_mutex);
 	return blk;
 }
 
@@ -356,10 +358,10 @@
 {
 	struct snd_util_memhdr *hdr = hw->tlb.memhdr; 
 
-	down(&hdr->block_mutex);
+	mutex_lock(&hdr->block_mutex);
 	synth_free_pages(hw, blk);
 	 __snd_util_mem_free(hdr, blk);
-	up(&hdr->block_mutex);
+	mutex_unlock(&hdr->block_mutex);
 	return 0;
 }
 
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index 4237413..1957d29 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -2375,8 +2375,10 @@
 		{ .subvendor = 0x1695, .subdevice = 0x3005, .action = VIA_DXS_ENABLE }, /* EPoX EP-8K9A */
 		{ .subvendor = 0x1695, .subdevice = 0x300e, .action = VIA_DXS_SRC }, /* EPoX 9HEAI */
 		{ .subvendor = 0x16f3, .subdevice = 0x6405, .action = VIA_DXS_SRC }, /* Jetway K8M8MS */
+		{ .subvendor = 0x1734, .subdevice = 0x1078, .action = VIA_DXS_SRC }, /* FSC Amilo L7300 */
 		{ .subvendor = 0x1734, .subdevice = 0x1093, .action = VIA_DXS_SRC }, /* FSC */
 		{ .subvendor = 0x1849, .subdevice = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */
+		{ .subvendor = 0x1849, .subdevice = 0x9739, .action = VIA_DXS_SRC }, /* ASRock mobo(?) */
 		{ .subvendor = 0x1849, .subdevice = 0x9761, .action = VIA_DXS_SRC }, /* ASRock mobo(?) */
 		{ .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 */
diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c
index c705af4..9b6d345 100644
--- a/sound/pci/vx222/vx222_ops.c
+++ b/sound/pci/vx222/vx222_ops.c
@@ -24,6 +24,8 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/firmware.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/control.h>
 #include <asm/io.h>
@@ -861,10 +863,10 @@
 {
 	struct vx_core *_chip = snd_kcontrol_chip(kcontrol);
 	struct snd_vx222 *chip = (struct snd_vx222 *)_chip;
-	down(&_chip->mixer_mutex);
+	mutex_lock(&_chip->mixer_mutex);
 	ucontrol->value.integer.value[0] = chip->input_level[0];
 	ucontrol->value.integer.value[1] = chip->input_level[1];
-	up(&_chip->mixer_mutex);
+	mutex_unlock(&_chip->mixer_mutex);
 	return 0;
 }
 
@@ -872,16 +874,16 @@
 {
 	struct vx_core *_chip = snd_kcontrol_chip(kcontrol);
 	struct snd_vx222 *chip = (struct snd_vx222 *)_chip;
-	down(&_chip->mixer_mutex);
+	mutex_lock(&_chip->mixer_mutex);
 	if (chip->input_level[0] != ucontrol->value.integer.value[0] ||
 	    chip->input_level[1] != ucontrol->value.integer.value[1]) {
 		chip->input_level[0] = ucontrol->value.integer.value[0];
 		chip->input_level[1] = ucontrol->value.integer.value[1];
 		vx2_set_input_level(chip);
-		up(&_chip->mixer_mutex);
+		mutex_unlock(&_chip->mixer_mutex);
 		return 1;
 	}
-	up(&_chip->mixer_mutex);
+	mutex_unlock(&_chip->mixer_mutex);
 	return 0;
 }
 
@@ -907,14 +909,14 @@
 {
 	struct vx_core *_chip = snd_kcontrol_chip(kcontrol);
 	struct snd_vx222 *chip = (struct snd_vx222 *)_chip;
-	down(&_chip->mixer_mutex);
+	mutex_lock(&_chip->mixer_mutex);
 	if (chip->mic_level != ucontrol->value.integer.value[0]) {
 		chip->mic_level = ucontrol->value.integer.value[0];
 		vx2_set_input_level(chip);
-		up(&_chip->mixer_mutex);
+		mutex_unlock(&_chip->mixer_mutex);
 		return 1;
 	}
-	up(&_chip->mixer_mutex);
+	mutex_unlock(&_chip->mixer_mutex);
 	return 0;
 }
 
diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c
index dab9b83..db57ce9 100644
--- a/sound/pci/ymfpci/ymfpci.c
+++ b/sound/pci/ymfpci/ymfpci.c
@@ -49,6 +49,7 @@
 static long joystick_port[SNDRV_CARDS];
 #endif
 static int rear_switch[SNDRV_CARDS];
+static int rear_swap[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 1 };
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for the Yamaha DS-1 PCI soundcard.");
@@ -66,6 +67,8 @@
 #endif
 module_param_array(rear_switch, bool, NULL, 0444);
 MODULE_PARM_DESC(rear_switch, "Enable shared rear/line-in switch");
+module_param_array(rear_swap, bool, NULL, 0444);
+MODULE_PARM_DESC(rear_swap, "Swap rear channels (must be enabled for correct IEC958 (S/PDIF)) output");
 
 static struct pci_device_id snd_ymfpci_ids[] = {
         { 0x1073, 0x0004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* YMF724 */
@@ -295,7 +298,7 @@
 		snd_card_free(card);
 		return err;
 	}
-	if ((err = snd_ymfpci_mixer(chip, rear_switch[dev])) < 0) {
+	if ((err = snd_ymfpci_mixer(chip, rear_switch[dev], rear_swap[dev])) < 0) {
 		snd_card_free(card);
 		return err;
 	}
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
index a1aa74b..8ac5ab5 100644
--- a/sound/pci/ymfpci/ymfpci_main.c
+++ b/sound/pci/ymfpci/ymfpci_main.c
@@ -536,15 +536,30 @@
 			}
 		}
 		if (ypcm->output_rear) {
-			if (use_left) {
-				bank->eff2_gain =
-				bank->eff2_gain_end = vol_left;
-			}
-			if (use_right) {
-				bank->eff3_gain =
-				bank->eff3_gain_end = vol_right;
-			}
-		}
+		        if (!ypcm->swap_rear) {
+        			if (use_left) {
+        				bank->eff2_gain =
+        				bank->eff2_gain_end = vol_left;
+        			}
+        			if (use_right) {
+        				bank->eff3_gain =
+        				bank->eff3_gain_end = vol_right;
+        			}
+		        } else {
+        			/* The SPDIF out channels seem to be swapped, so we have
+        			 * to swap them here, too.  The rear analog out channels
+        			 * will be wrong, but otherwise AC3 would not work.
+        			 */
+        			if (use_left) {
+        				bank->eff3_gain =
+        				bank->eff3_gain_end = vol_left;
+        			}
+        			if (use_right) {
+        				bank->eff2_gain =
+        				bank->eff2_gain_end = vol_right;
+        			}
+        		}
+                }
 	}
 }
 
@@ -894,6 +909,7 @@
 	ypcm = runtime->private_data;
 	ypcm->output_front = 1;
 	ypcm->output_rear = chip->mode_dup4ch ? 1 : 0;
+	ypcm->swap_rear = chip->rear_swap;
 	spin_lock_irq(&chip->reg_lock);
 	if (ypcm->output_rear) {
 		ymfpci_open_extension(chip);
@@ -1734,7 +1750,7 @@
 	chip->ac97 = NULL;
 }
 
-int __devinit snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch)
+int __devinit snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch, int rear_swap)
 {
 	struct snd_ac97_template ac97;
 	struct snd_kcontrol *kctl;
@@ -1746,6 +1762,7 @@
 		.read = snd_ymfpci_codec_read,
 	};
 
+	chip->rear_swap = rear_swap;
 	if ((err = snd_ac97_bus(chip->card, 0, &ops, chip, &chip->ac97_bus)) < 0)
 		return err;
 	chip->ac97_bus->private_free = snd_ymfpci_mixer_free_ac97_bus;
@@ -2293,6 +2310,7 @@
 		return -EIO;
 	}
 
+	chip->rear_swap = 1;
 	if ((err = snd_ymfpci_ac3_init(chip)) < 0) {
 		snd_ymfpci_free(chip);
 		return err;
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c
index 962e6d52..7f2a4de 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c
@@ -66,10 +66,9 @@
 static int snd_pcm_free_vmalloc_buffer(struct snd_pcm_substream *subs)
 {
 	struct snd_pcm_runtime *runtime = subs->runtime;
-	if (runtime->dma_area) {
-		vfree(runtime->dma_area);
-		runtime->dma_area = NULL;
-	}
+
+	vfree(runtime->dma_area);
+	runtime->dma_area = NULL;
 	return 0;
 }
 
diff --git a/sound/pcmcia/vx/vxp_mixer.c b/sound/pcmcia/vx/vxp_mixer.c
index 9450149..e237f6c 100644
--- a/sound/pcmcia/vx/vxp_mixer.c
+++ b/sound/pcmcia/vx/vxp_mixer.c
@@ -52,14 +52,14 @@
 {
 	struct vx_core *_chip = snd_kcontrol_chip(kcontrol);
 	struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip;
-	down(&_chip->mixer_mutex);
+	mutex_lock(&_chip->mixer_mutex);
 	if (chip->mic_level != ucontrol->value.integer.value[0]) {
 		vx_set_mic_level(_chip, ucontrol->value.integer.value[0]);
 		chip->mic_level = ucontrol->value.integer.value[0];
-		up(&_chip->mixer_mutex);
+		mutex_unlock(&_chip->mixer_mutex);
 		return 1;
 	}
-	up(&_chip->mixer_mutex);
+	mutex_unlock(&_chip->mixer_mutex);
 	return 0;
 }
 
@@ -95,14 +95,14 @@
 {
 	struct vx_core *_chip = snd_kcontrol_chip(kcontrol);
 	struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip;
-	down(&_chip->mixer_mutex);
+	mutex_lock(&_chip->mixer_mutex);
 	if (chip->mic_level != ucontrol->value.integer.value[0]) {
 		vx_set_mic_boost(_chip, ucontrol->value.integer.value[0]);
 		chip->mic_level = ucontrol->value.integer.value[0];
-		up(&_chip->mixer_mutex);
+		mutex_unlock(&_chip->mixer_mutex);
 		return 1;
 	}
-	up(&_chip->mixer_mutex);
+	mutex_unlock(&_chip->mixer_mutex);
 	return 0;
 }
 
diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c
index fd65439..53a148b 100644
--- a/sound/sparc/cs4231.c
+++ b/sound/sparc/cs4231.c
@@ -115,8 +115,8 @@
 	unsigned char		image[32];	/* registers image */
 	int			mce_bit;
 	int			calibrate_mute;
-	struct semaphore	mce_mutex;
-	struct semaphore	open_mutex;
+	struct mutex		mce_mutex;
+	struct mutex		open_mutex;
 
 	union {
 #ifdef SBUS_SUPPORT
@@ -775,7 +775,7 @@
 {
 	unsigned long flags;
 
-	down(&chip->mce_mutex);
+	mutex_lock(&chip->mce_mutex);
 	snd_cs4231_calibrate_mute(chip, 1);
 
 	snd_cs4231_mce_up(chip);
@@ -790,7 +790,7 @@
 	snd_cs4231_mce_down(chip);
 
 	snd_cs4231_calibrate_mute(chip, 0);
-	up(&chip->mce_mutex);
+	mutex_unlock(&chip->mce_mutex);
 }
 
 static void snd_cs4231_capture_format(struct snd_cs4231 *chip, struct snd_pcm_hw_params *params,
@@ -798,7 +798,7 @@
 {
 	unsigned long flags;
 
-	down(&chip->mce_mutex);
+	mutex_lock(&chip->mce_mutex);
 	snd_cs4231_calibrate_mute(chip, 1);
 
 	snd_cs4231_mce_up(chip);
@@ -819,7 +819,7 @@
 	snd_cs4231_mce_down(chip);
 
 	snd_cs4231_calibrate_mute(chip, 0);
-	up(&chip->mce_mutex);
+	mutex_unlock(&chip->mce_mutex);
 }
 
 /*
@@ -933,14 +933,14 @@
 {
 	unsigned long flags;
 
-	down(&chip->open_mutex);
+	mutex_lock(&chip->open_mutex);
 	if ((chip->mode & mode)) {
-		up(&chip->open_mutex);
+		mutex_unlock(&chip->open_mutex);
 		return -EAGAIN;
 	}
 	if (chip->mode & CS4231_MODE_OPEN) {
 		chip->mode |= mode;
-		up(&chip->open_mutex);
+		mutex_unlock(&chip->open_mutex);
 		return 0;
 	}
 	/* ok. now enable and ack CODEC IRQ */
@@ -960,7 +960,7 @@
 	spin_unlock_irqrestore(&chip->lock, flags);
 
 	chip->mode = mode;
-	up(&chip->open_mutex);
+	mutex_unlock(&chip->open_mutex);
 	return 0;
 }
 
@@ -968,10 +968,10 @@
 {
 	unsigned long flags;
 
-	down(&chip->open_mutex);
+	mutex_lock(&chip->open_mutex);
 	chip->mode &= ~mode;
 	if (chip->mode & CS4231_MODE_OPEN) {
-		up(&chip->open_mutex);
+		mutex_unlock(&chip->open_mutex);
 		return;
 	}
 	snd_cs4231_calibrate_mute(chip, 1);
@@ -1008,7 +1008,7 @@
 	snd_cs4231_calibrate_mute(chip, 0);
 
 	chip->mode = 0;
-	up(&chip->open_mutex);
+	mutex_unlock(&chip->open_mutex);
 }
 
 /*
@@ -1969,8 +1969,8 @@
 	spin_lock_init(&chip->lock);
 	spin_lock_init(&chip->c_dma.sbus_info.lock);
 	spin_lock_init(&chip->p_dma.sbus_info.lock);
-	init_MUTEX(&chip->mce_mutex);
-	init_MUTEX(&chip->open_mutex);
+	mutex_init(&chip->mce_mutex);
+	mutex_init(&chip->open_mutex);
 	chip->card = card;
 	chip->dev_u.sdev = sdev;
 	chip->regs_size = sdev->reg_addrs[0].reg_size;
@@ -2157,8 +2157,8 @@
 	spin_lock_init(&chip->lock);
 	spin_lock_init(&chip->c_dma.ebus_info.lock);
 	spin_lock_init(&chip->p_dma.ebus_info.lock);
-	init_MUTEX(&chip->mce_mutex);
-	init_MUTEX(&chip->open_mutex);
+	mutex_init(&chip->mce_mutex);
+	mutex_init(&chip->open_mutex);
 	chip->flags |= CS4231_FLAG_EBUS;
 	chip->card = card;
 	chip->dev_u.pdev = edev->bus->self;
diff --git a/sound/synth/emux/emux.c b/sound/synth/emux/emux.c
index 7c8e328..fc733bb 100644
--- a/sound/synth/emux/emux.c
+++ b/sound/synth/emux/emux.c
@@ -45,7 +45,7 @@
 		return -ENOMEM;
 
 	spin_lock_init(&emu->voice_lock);
-	init_MUTEX(&emu->register_mutex);
+	mutex_init(&emu->register_mutex);
 
 	emu->client = -1;
 #ifdef CONFIG_SND_SEQUENCER_OSS
diff --git a/sound/synth/emux/emux_oss.c b/sound/synth/emux/emux_oss.c
index dfbfcfb..3436816 100644
--- a/sound/synth/emux/emux_oss.c
+++ b/sound/synth/emux/emux_oss.c
@@ -117,10 +117,10 @@
 	emu = closure;
 	snd_assert(arg != NULL && emu != NULL, return -ENXIO);
 
-	down(&emu->register_mutex);
+	mutex_lock(&emu->register_mutex);
 
 	if (!snd_emux_inc_count(emu)) {
-		up(&emu->register_mutex);
+		mutex_unlock(&emu->register_mutex);
 		return -EFAULT;
 	}
 
@@ -134,7 +134,7 @@
 	if (p == NULL) {
 		snd_printk("can't create port\n");
 		snd_emux_dec_count(emu);
-		up(&emu->register_mutex);
+		mutex_unlock(&emu->register_mutex);
 		return -ENOMEM;
 	}
 
@@ -148,7 +148,7 @@
 
 	snd_emux_reset_port(p);
 
-	up(&emu->register_mutex);
+	mutex_unlock(&emu->register_mutex);
 	return 0;
 }
 
@@ -191,13 +191,13 @@
 	emu = p->emu;
 	snd_assert(emu != NULL, return -ENXIO);
 
-	down(&emu->register_mutex);
+	mutex_lock(&emu->register_mutex);
 	snd_emux_sounds_off_all(p);
 	snd_soundfont_close_check(emu->sflist, SF_CLIENT_NO(p->chset.port));
 	snd_seq_event_port_detach(p->chset.client, p->chset.port);
 	snd_emux_dec_count(emu);
 
-	up(&emu->register_mutex);
+	mutex_unlock(&emu->register_mutex);
 	return 0;
 }
 
diff --git a/sound/synth/emux/emux_proc.c b/sound/synth/emux/emux_proc.c
index a70a179..1ba68ce 100644
--- a/sound/synth/emux/emux_proc.c
+++ b/sound/synth/emux/emux_proc.c
@@ -37,7 +37,7 @@
 	int i;
 
 	emu = entry->private_data;
-	down(&emu->register_mutex);
+	mutex_lock(&emu->register_mutex);
 	if (emu->name)
 		snd_iprintf(buf, "Device: %s\n", emu->name);
 	snd_iprintf(buf, "Ports: %d\n", emu->num_ports);
@@ -56,13 +56,13 @@
 		snd_iprintf(buf, "Memory Size: 0\n");
 	}
 	if (emu->sflist) {
-		down(&emu->sflist->presets_mutex);
+		mutex_lock(&emu->sflist->presets_mutex);
 		snd_iprintf(buf, "SoundFonts: %d\n", emu->sflist->fonts_size);
 		snd_iprintf(buf, "Instruments: %d\n", emu->sflist->zone_counter);
 		snd_iprintf(buf, "Samples: %d\n", emu->sflist->sample_counter);
 		snd_iprintf(buf, "Locked Instruments: %d\n", emu->sflist->zone_locked);
 		snd_iprintf(buf, "Locked Samples: %d\n", emu->sflist->sample_locked);
-		up(&emu->sflist->presets_mutex);
+		mutex_unlock(&emu->sflist->presets_mutex);
 	}
 #if 0  /* debug */
 	if (emu->voices[0].state != SNDRV_EMUX_ST_OFF && emu->voices[0].ch >= 0) {
@@ -103,7 +103,7 @@
 		snd_iprintf(buf, "sample_mode=%x, rate=%x\n", vp->reg.sample_mode, vp->reg.rate_offset);
 	}
 #endif
-	up(&emu->register_mutex);
+	mutex_unlock(&emu->register_mutex);
 }
 
 
diff --git a/sound/synth/emux/emux_seq.c b/sound/synth/emux/emux_seq.c
index 1a973d7..8f00f07 100644
--- a/sound/synth/emux/emux_seq.c
+++ b/sound/synth/emux/emux_seq.c
@@ -123,12 +123,12 @@
 	if (emu->voices)
 		snd_emux_terminate_all(emu);
 		
-	down(&emu->register_mutex);
+	mutex_lock(&emu->register_mutex);
 	if (emu->client >= 0) {
 		snd_seq_delete_kernel_client(emu->client);
 		emu->client = -1;
 	}
-	up(&emu->register_mutex);
+	mutex_unlock(&emu->register_mutex);
 }
 
 
@@ -311,10 +311,10 @@
 	emu = p->emu;
 	snd_assert(emu != NULL, return -EINVAL);
 
-	down(&emu->register_mutex);
+	mutex_lock(&emu->register_mutex);
 	snd_emux_init_port(p);
 	snd_emux_inc_count(emu);
-	up(&emu->register_mutex);
+	mutex_unlock(&emu->register_mutex);
 	return 0;
 }
 
@@ -332,10 +332,10 @@
 	emu = p->emu;
 	snd_assert(emu != NULL, return -EINVAL);
 
-	down(&emu->register_mutex);
+	mutex_lock(&emu->register_mutex);
 	snd_emux_sounds_off_all(p);
 	snd_emux_dec_count(emu);
-	up(&emu->register_mutex);
+	mutex_unlock(&emu->register_mutex);
 	return 0;
 }
 
diff --git a/sound/synth/emux/soundfont.c b/sound/synth/emux/soundfont.c
index 4c5754d..32c2716 100644
--- a/sound/synth/emux/soundfont.c
+++ b/sound/synth/emux/soundfont.c
@@ -79,7 +79,7 @@
 lock_preset(struct snd_sf_list *sflist)
 {
 	unsigned long flags;
-	down(&sflist->presets_mutex);
+	mutex_lock(&sflist->presets_mutex);
 	spin_lock_irqsave(&sflist->lock, flags);
 	sflist->presets_locked = 1;
 	spin_unlock_irqrestore(&sflist->lock, flags);
@@ -96,7 +96,7 @@
 	spin_lock_irqsave(&sflist->lock, flags);
 	sflist->presets_locked = 0;
 	spin_unlock_irqrestore(&sflist->lock, flags);
-	up(&sflist->presets_mutex);
+	mutex_unlock(&sflist->presets_mutex);
 }
 
 
@@ -1390,7 +1390,7 @@
 	if ((sflist = kzalloc(sizeof(*sflist), GFP_KERNEL)) == NULL)
 		return NULL;
 
-	init_MUTEX(&sflist->presets_mutex);
+	mutex_init(&sflist->presets_mutex);
 	spin_lock_init(&sflist->lock);
 	sflist->memhdr = hdr;
 
diff --git a/sound/synth/util_mem.c b/sound/synth/util_mem.c
index 217e8e5..1d9b11f 100644
--- a/sound/synth/util_mem.c
+++ b/sound/synth/util_mem.c
@@ -18,6 +18,7 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
+#include <linux/mutex.h>
 #include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -42,7 +43,7 @@
 	if (hdr == NULL)
 		return NULL;
 	hdr->size = memsize;
-	init_MUTEX(&hdr->block_mutex);
+	mutex_init(&hdr->block_mutex);
 	INIT_LIST_HEAD(&hdr->block);
 
 	return hdr;
@@ -136,9 +137,9 @@
 snd_util_mem_alloc(struct snd_util_memhdr *hdr, int size)
 {
 	struct snd_util_memblk *blk;
-	down(&hdr->block_mutex);
+	mutex_lock(&hdr->block_mutex);
 	blk = __snd_util_mem_alloc(hdr, size);
-	up(&hdr->block_mutex);
+	mutex_unlock(&hdr->block_mutex);
 	return blk;
 }
 
@@ -163,9 +164,9 @@
 {
 	snd_assert(hdr && blk, return -EINVAL);
 
-	down(&hdr->block_mutex);
+	mutex_lock(&hdr->block_mutex);
 	__snd_util_mem_free(hdr, blk);
-	up(&hdr->block_mutex);
+	mutex_unlock(&hdr->block_mutex);
 	return 0;
 }
 
@@ -175,9 +176,9 @@
 int snd_util_mem_avail(struct snd_util_memhdr *hdr)
 {
 	unsigned int size;
-	down(&hdr->block_mutex);
+	mutex_lock(&hdr->block_mutex);
 	size = hdr->size - hdr->used;
-	up(&hdr->block_mutex);
+	mutex_unlock(&hdr->block_mutex);
 	return size;
 }
 
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index d501338..4e614ac 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -47,6 +47,7 @@
 #include <linux/usb.h>
 #include <linux/vmalloc.h>
 #include <linux/moduleparam.h>
+#include <linux/mutex.h>
 #include <sound/core.h>
 #include <sound/info.h>
 #include <sound/pcm.h>
@@ -69,6 +70,7 @@
 static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Product ID for this card */
 static int nrpacks = 4;		/* max. number of packets per urb */
 static int async_unlink = 1;
+static int device_setup[SNDRV_CARDS]; /* device parameter for this card*/
 
 module_param_array(index, int, NULL, 0444);
 MODULE_PARM_DESC(index, "Index value for the USB audio adapter.");
@@ -84,6 +86,8 @@
 MODULE_PARM_DESC(nrpacks, "Max. number of packets per URB.");
 module_param(async_unlink, bool, 0444);
 MODULE_PARM_DESC(async_unlink, "Use async unlink mode.");
+module_param_array(device_setup, int, NULL, 0444);
+MODULE_PARM_DESC(device_setup, "Specific device setup (if needed).");
 
 
 /*
@@ -202,7 +206,7 @@
  * the all interfaces on the same card as one sound device.
  */
 
-static DECLARE_MUTEX(register_mutex);
+static DEFINE_MUTEX(register_mutex);
 static struct snd_usb_audio *usb_chip[SNDRV_CARDS];
 
 
@@ -475,6 +479,18 @@
 	return 0;
 }
 
+/* determine the number of frames in the next packet */
+static int snd_usb_audio_next_packet_size(struct snd_usb_substream *subs)
+{
+	if (subs->fill_max)
+		return subs->maxframesize;
+	else {
+		subs->phase = (subs->phase & 0xffff)
+			+ (subs->freqm << subs->datainterval);
+		return min(subs->phase >> 16, subs->maxframesize);
+	}
+}
+
 /*
  * Prepare urb for streaming before playback starts.
  *
@@ -492,16 +508,7 @@
 	urb->dev = ctx->subs->dev;
 	urb->number_of_packets = subs->packs_per_ms;
 	for (i = 0; i < subs->packs_per_ms; ++i) {
-		/* calculate the size of a packet */
-		if (subs->fill_max)
-			counts = subs->maxframesize; /* fixed */
-		else {
-			subs->phase = (subs->phase & 0xffff)
-				+ (subs->freqm << subs->datainterval);
-			counts = subs->phase >> 16;
-			if (counts > subs->maxframesize)
-				counts = subs->maxframesize;
-		}
+		counts = snd_usb_audio_next_packet_size(subs);
 		urb->iso_frame_desc[i].offset = offs * stride;
 		urb->iso_frame_desc[i].length = counts * stride;
 		offs += counts;
@@ -538,16 +545,7 @@
 	urb->number_of_packets = 0;
 	spin_lock_irqsave(&subs->lock, flags);
 	for (i = 0; i < ctx->packets; i++) {
-		/* calculate the size of a packet */
-		if (subs->fill_max)
-			counts = subs->maxframesize; /* fixed */
-		else {
-			subs->phase = (subs->phase & 0xffff)
-				+ (subs->freqm << subs->datainterval);
-			counts = subs->phase >> 16;
-			if (counts > subs->maxframesize)
-				counts = subs->maxframesize;
-		}
+		counts = snd_usb_audio_next_packet_size(subs);
 		/* set up descriptor */
 		urb->iso_frame_desc[i].offset = offs * stride;
 		urb->iso_frame_desc[i].length = counts * stride;
@@ -725,10 +723,9 @@
 static int snd_pcm_free_vmalloc_buffer(struct snd_pcm_substream *subs)
 {
 	struct snd_pcm_runtime *runtime = subs->runtime;
-	if (runtime->dma_area) {
-		vfree(runtime->dma_area);
-		runtime->dma_area = NULL;
-	}
+
+	vfree(runtime->dma_area);
+	runtime->dma_area = NULL;
 	return 0;
 }
 
@@ -779,6 +776,35 @@
 }
 
 
+static const char *usb_error_string(int err)
+{
+	switch (err) {
+	case -ENODEV:
+		return "no device";
+	case -ENOENT:
+		return "endpoint not enabled";
+	case -EPIPE:
+		return "endpoint stalled";
+	case -ENOSPC:
+		return "not enough bandwidth";
+	case -ESHUTDOWN:
+		return "device disabled";
+	case -EHOSTUNREACH:
+		return "device suspended";
+#ifndef CONFIG_USB_EHCI_SPLIT_ISO
+	case -ENOSYS:
+		return "enable CONFIG_USB_EHCI_SPLIT_ISO to play through a hub";
+#endif
+	case -EINVAL:
+	case -EAGAIN:
+	case -EFBIG:
+	case -EMSGSIZE:
+		return "internal error";
+	default:
+		return "unknown error";
+	}
+}
+
 /*
  * set up and start data/sync urbs
  */
@@ -811,16 +837,22 @@
 	subs->unlink_mask = 0;
 	subs->running = 1;
 	for (i = 0; i < subs->nurbs; i++) {
-		if ((err = usb_submit_urb(subs->dataurb[i].urb, GFP_ATOMIC)) < 0) {
-			snd_printk(KERN_ERR "cannot submit datapipe for urb %d, err = %d\n", i, err);
+		err = usb_submit_urb(subs->dataurb[i].urb, GFP_ATOMIC);
+		if (err < 0) {
+			snd_printk(KERN_ERR "cannot submit datapipe "
+				   "for urb %d, error %d: %s\n",
+				   i, err, usb_error_string(err));
 			goto __error;
 		}
 		set_bit(i, &subs->active_mask);
 	}
 	if (subs->syncpipe) {
 		for (i = 0; i < SYNC_URBS; i++) {
-			if ((err = usb_submit_urb(subs->syncurb[i].urb, GFP_ATOMIC)) < 0) {
-				snd_printk(KERN_ERR "cannot submit syncpipe for urb %d, err = %d\n", i, err);
+			err = usb_submit_urb(subs->syncurb[i].urb, GFP_ATOMIC);
+			if (err < 0) {
+				snd_printk(KERN_ERR "cannot submit syncpipe "
+					   "for urb %d, error %d: %s\n",
+					   i, err, usb_error_string(err));
 				goto __error;
 			}
 			set_bit(i + 16, &subs->active_mask);
@@ -1390,8 +1422,8 @@
 	channels = params_channels(hw_params);
 	fmt = find_format(subs, format, rate, channels);
 	if (! fmt) {
-		snd_printd(KERN_DEBUG "cannot set format: format = %s, rate = %d, channels = %d\n",
-			   snd_pcm_format_name(format), rate, channels);
+		snd_printd(KERN_DEBUG "cannot set format: format = 0x%x, rate = %d, channels = %d\n",
+			   format, rate, channels);
 		return -EINVAL;
 	}
 
@@ -2017,6 +2049,8 @@
 };
 
 
+#if defined(CONFIG_PROCFS) && defined(CONFIG_SND_VERBOSE_PROCFS)
+
 /*
  * proc interface for list the supported pcm formats
  */
@@ -2032,7 +2066,7 @@
 		fp = list_entry(p, struct audioformat, list);
 		snd_iprintf(buffer, "  Interface %d\n", fp->iface);
 		snd_iprintf(buffer, "    Altset %d\n", fp->altsetting);
-		snd_iprintf(buffer, "    Format: %s\n", snd_pcm_format_name(fp->format));
+		snd_iprintf(buffer, "    Format: 0x%x\n", fp->format);
 		snd_iprintf(buffer, "    Channels: %d\n", fp->channels);
 		snd_iprintf(buffer, "    Endpoint: %d %s (%s)\n",
 			    fp->endpoint & USB_ENDPOINT_NUMBER_MASK,
@@ -2107,6 +2141,13 @@
 		snd_info_set_text_ops(entry, stream, 1024, proc_pcm_format_read);
 }
 
+#else
+
+static inline void proc_pcm_format_add(struct snd_usb_stream *stream)
+{
+}
+
+#endif
 
 /*
  * initialize the substream instance.
@@ -2509,6 +2550,8 @@
 	return 0;
 }
 
+static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip,
+					 int iface, int altno);
 static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
 {
 	struct usb_device *dev;
@@ -2543,6 +2586,12 @@
 		stream = (get_endpoint(alts, 0)->bEndpointAddress & USB_DIR_IN) ?
 			SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
 		altno = altsd->bAlternateSetting;
+	
+		/* audiophile usb: skip altsets incompatible with device_setup
+		 */
+		if (chip->usb_id == USB_ID(0x0763, 0x2003) && 
+		    audiophile_skip_setting_quirk(chip, iface_no, altno))
+			continue;
 
 		/* get audio formats */
 		fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, AS_GENERAL);
@@ -2637,7 +2686,7 @@
 			continue;
 		}
 
-		snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint 0x%x\n", dev->devnum, iface_no, i, fp->endpoint);
+		snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint 0x%x\n", dev->devnum, iface_no, altno, fp->endpoint);
 		err = add_audio_endpoint(chip, stream, fp);
 		if (err < 0) {
 			kfree(fp->rate_table);
@@ -3045,6 +3094,45 @@
 	return 0;
 }
 
+/*
+ * Setup quirks
+ */
+#define AUDIOPHILE_SET			0x01 /* if set, parse device_setup */
+#define AUDIOPHILE_SET_DTS              0x02 /* if set, enable DTS Digital Output */
+#define AUDIOPHILE_SET_96K              0x04 /* 48-96KHz rate if set, 8-48KHz otherwise */
+#define AUDIOPHILE_SET_24B		0x08 /* 24bits sample if set, 16bits otherwise */
+#define AUDIOPHILE_SET_DI		0x10 /* if set, enable Digital Input */
+#define AUDIOPHILE_SET_MASK		0x1F /* bit mask for setup value */
+#define AUDIOPHILE_SET_24B_48K_DI	0x19 /* value for 24bits+48KHz+Digital Input */
+#define AUDIOPHILE_SET_24B_48K_NOTDI	0x09 /* value for 24bits+48KHz+No Digital Input */
+#define AUDIOPHILE_SET_16B_48K_DI	0x11 /* value for 16bits+48KHz+Digital Input */
+#define AUDIOPHILE_SET_16B_48K_NOTDI	0x01 /* value for 16bits+48KHz+No Digital Input */
+
+static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip,
+					 int iface, int altno)
+{
+	if (device_setup[chip->index] & AUDIOPHILE_SET) {
+		if ((device_setup[chip->index] & AUDIOPHILE_SET_DTS)
+		    && altno != 6)
+			return 1; /* skip this altsetting */
+		if ((device_setup[chip->index] & AUDIOPHILE_SET_96K)
+		    && altno != 1)
+			return 1; /* skip this altsetting */
+		if ((device_setup[chip->index] & AUDIOPHILE_SET_MASK) ==
+		    AUDIOPHILE_SET_24B_48K_DI && altno != 2)
+			return 1; /* skip this altsetting */
+		if ((device_setup[chip->index] & AUDIOPHILE_SET_MASK) ==
+		    AUDIOPHILE_SET_24B_48K_NOTDI && altno != 3)
+			return 1; /* skip this altsetting */
+		if ((device_setup[chip->index] & AUDIOPHILE_SET_MASK) ==
+		    AUDIOPHILE_SET_16B_48K_DI && altno != 4)
+			return 1; /* skip this altsetting */
+		if ((device_setup[chip->index] & AUDIOPHILE_SET_MASK) ==
+		    AUDIOPHILE_SET_16B_48K_NOTDI && altno != 5)
+			return 1; /* skip this altsetting */
+	}	
+	return 0; /* keep this altsetting */
+}
 
 /*
  * audio-interface quirks
@@ -3070,7 +3158,7 @@
 		[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_MIDI_CME] = snd_usb_create_midi_interface,
 		[QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk,
 		[QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,
 		[QUIRK_AUDIO_EDIROL_UA700_UA25] = create_ua700_ua25_quirk,
@@ -3282,7 +3370,7 @@
 
 	/* check whether it's already registered */
 	chip = NULL;
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	for (i = 0; i < SNDRV_CARDS; i++) {
 		if (usb_chip[i] && usb_chip[i]->dev == dev) {
 			if (usb_chip[i]->shutdown) {
@@ -3335,13 +3423,13 @@
 
 	usb_chip[chip->index] = chip;
 	chip->num_interfaces++;
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
 	return chip;
 
  __error:
 	if (chip && !chip->num_interfaces)
 		snd_card_free(chip->card);
-	up(&register_mutex);
+	mutex_unlock(&register_mutex);
  __err_val:
 	return NULL;
 }
@@ -3361,7 +3449,7 @@
 
 	chip = ptr;
 	card = chip->card;
-	down(&register_mutex);
+	mutex_lock(&register_mutex);
 	chip->shutdown = 1;
 	chip->num_interfaces--;
 	if (chip->num_interfaces <= 0) {
@@ -3379,10 +3467,10 @@
 			snd_usb_mixer_disconnect(p);
 		}
 		usb_chip[chip->index] = NULL;
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 		snd_card_free(card);
 	} else {
-		up(&register_mutex);
+		mutex_unlock(&register_mutex);
 	}
 }
 
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index ecd724b..8873352 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -161,7 +161,7 @@
 	QUIRK_MIDI_NOVATION,
 	QUIRK_MIDI_RAW,
 	QUIRK_MIDI_EMAGIC,
-	QUIRK_MIDI_MIDITECH,
+	QUIRK_MIDI_CME,
 	QUIRK_AUDIO_STANDARD_INTERFACE,
 	QUIRK_AUDIO_FIXED_ENDPOINT,
 	QUIRK_AUDIO_EDIROL_UA700_UA25,
@@ -209,7 +209,7 @@
 /* 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 */
+/* for QUIRK_MIDI_CME, data is NULL */
 
 /*
  */
diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c
index f15b021..2b9d940 100644
--- a/sound/usb/usbmidi.c
+++ b/sound/usb/usbmidi.c
@@ -871,10 +871,10 @@
 
 static unsigned int snd_usbmidi_count_bits(unsigned int x)
 {
-	unsigned int bits = 0;
+	unsigned int bits;
 
-	for (; x; x >>= 1)
-		bits += x & 1;
+	for (bits = 0; x; ++bits)
+		x &= x - 1;
 	return bits;
 }
 
@@ -1082,6 +1082,8 @@
 	{ USB_ID(0x0582, 0x004d), 0, "%s MIDI" },
 	{ USB_ID(0x0582, 0x004d), 1, "%s 1" },
 	{ USB_ID(0x0582, 0x004d), 2, "%s 2" },
+	/* Edirol UM-3EX */
+	{ USB_ID(0x0582, 0x009a), 3, "%s Control" },
 	/* M-Audio MidiSport 8x8 */
 	{ USB_ID(0x0763, 0x1031), 8, "%s Control" },
 	{ USB_ID(0x0763, 0x1033), 8, "%s Control" },
@@ -1574,7 +1576,7 @@
 		       sizeof(struct snd_usb_midi_endpoint_info));
 		err = snd_usbmidi_detect_endpoints(umidi, &endpoints[0], 1);
 		break;
-	case QUIRK_MIDI_MIDITECH:
+	case QUIRK_MIDI_CME:
 		err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
 		break;
 	default:
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c
index 678dac2..8d08b34 100644
--- a/sound/usb/usbmixer.c
+++ b/sound/usb/usbmixer.c
@@ -434,7 +434,6 @@
 		kctl->id.index++;
 	if ((err = snd_ctl_add(state->chip->card, kctl)) < 0) {
 		snd_printd(KERN_ERR "cannot add control (err = %d)\n", err);
-		snd_ctl_free_one(kctl);
 		return err;
 	}
 	cval->elem_id = &kctl->id;
@@ -1469,6 +1468,7 @@
 	kctl = snd_ctl_new1(&mixer_selectunit_ctl, cval);
 	if (! kctl) {
 		snd_printk(KERN_ERR "cannot malloc kcontrol\n");
+		kfree(namelist);
 		kfree(cval);
 		return -ENOMEM;
 	}
diff --git a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c
index c126443..37accb6 100644
--- a/sound/usb/usbmixer_maps.c
+++ b/sound/usb/usbmixer_maps.c
@@ -195,6 +195,22 @@
 	{ 0 } /* terminator */
 };
 
+static struct usbmix_name_map maya44_map[] = {
+	/* 1: IT line */
+	{ 2, "Line Playback" }, /* FU */
+	/* 3: IT line */
+	{ 4, "Line Playback" }, /* FU */
+	/* 5: IT pcm playback */
+	/* 6: MU */
+	{ 7, "Master Playback" }, /* FU */
+	/* 8: OT speaker */
+	/* 9: IT line */
+	{ 10, "Line Capture" }, /* FU */
+	/* 11: MU */
+	/* 12: OT pcm capture */
+	{ }
+};
+
 /* Section "justlink_map" below added by James Courtier-Dutton <James@superbug.demon.co.uk>
  * sourced from Maplin Electronics (http://www.maplin.co.uk), part number A56AK
  * Part has 2 connectors that act as a single output. (TOSLINK Optical for digital out, and 3.5mm Jack for Analogue out.)
@@ -253,6 +269,10 @@
 		.ignore_ctl_error = 1,
 	},
 	{
+		.id = USB_ID(0x0a92, 0x0091),
+		.map = maya44_map,
+	},
+	{
 		.id = USB_ID(0x0c45, 0x1158),
 		.map = justlink_map,
 	},
diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h
index 6190ada..0992a09 100644
--- a/sound/usb/usbquirks.h
+++ b/sound/usb/usbquirks.h
@@ -82,6 +82,7 @@
 YAMAHA_DEVICE(0x1013, "PF-500"),
 YAMAHA_DEVICE(0x1014, "S90"),
 YAMAHA_DEVICE(0x1015, "MOTIF-R"),
+YAMAHA_DEVICE(0x1016, "MDP-5"),
 YAMAHA_DEVICE(0x1017, "CVP-204"),
 YAMAHA_DEVICE(0x1018, "CVP-206"),
 YAMAHA_DEVICE(0x1019, "CVP-208"),
@@ -90,6 +91,7 @@
 YAMAHA_DEVICE(0x101c, "PSR-2100"),
 YAMAHA_DEVICE(0x101d, "CLP-175"),
 YAMAHA_DEVICE(0x101e, "PSR-K1"),
+YAMAHA_DEVICE(0x101f, "EZ-J24"),
 YAMAHA_DEVICE(0x1020, "EZ-250i"),
 YAMAHA_DEVICE(0x1021, "MOTIF ES 6"),
 YAMAHA_DEVICE(0x1022, "MOTIF ES 7"),
@@ -294,7 +296,8 @@
 	}
 },
 {
-	/* a later revision uses ID 0x0099 */
+	/* Has ID 0x0099 when not in "Advanced Driver" mode.
+	 * The UM-2EX has only one input, but we cannot detect this. */
 	USB_DEVICE(0x0582, 0x0005),
 	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
 		.vendor_name = "EDIROL",
@@ -385,7 +388,7 @@
 	}
 },
 {
-	/* a later revision uses ID 0x009d */
+	/* has ID 0x009d when not in "Advanced Driver" mode */
 	USB_DEVICE(0x0582, 0x0009),
 	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
 		.vendor_name = "EDIROL",
@@ -1090,6 +1093,53 @@
 		}
 	}
 },
+	/* TODO: add Edirol UA-101 support */
+{
+	/* has ID 0x0081 when not in "Advanced Driver" mode */
+	USB_DEVICE(0x0582, 0x0080),
+	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+		.vendor_name = "Roland",
+		.product_name = "G-70",
+		.ifnum = 0,
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const struct snd_usb_midi_endpoint_info) {
+			.out_cables = 0x0001,
+			.in_cables  = 0x0001
+		}
+	}
+},
+	/* TODO: add Roland V-SYNTH XT support */
+	/* TODO: add BOSS GT-PRO support */
+{
+	/* has ID 0x008c when not in "Advanced Driver" mode */
+	USB_DEVICE(0x0582, 0x008b),
+	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+		.vendor_name = "EDIROL",
+		.product_name = "PC-50",
+		.ifnum = 0,
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const struct snd_usb_midi_endpoint_info) {
+			.out_cables = 0x0001,
+			.in_cables  = 0x0001
+		}
+	}
+},
+	/* TODO: add Edirol PC-80 support */
+	/* TODO: add Edirol UA-1EX support */
+{
+	USB_DEVICE(0x0582, 0x009a),
+	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+		.vendor_name = "EDIROL",
+		.product_name = "UM-3EX",
+		.ifnum = 0,
+		.type = QUIRK_MIDI_FIXED_ENDPOINT,
+		.data = & (const struct snd_usb_midi_endpoint_info) {
+			.out_cables = 0x000f,
+			.in_cables  = 0x000f
+		}
+	}
+},
+	/* TODO: add Edirol MD-P1 support */
 
 /* Guillemot devices */
 {
@@ -1111,15 +1161,6 @@
 		}
 	}
 },
-	/* TODO: add Edirol UA-101 support */
-	/* TODO: add Roland G-70 support */
-	/* TODO: add Roland V-SYNTH XT support */
-	/* TODO: add BOSS GT-PRO support */
-	/* TODO: add Edirol PC-50 support */
-	/* TODO: add Edirol PC-80 support */
-	/* TODO: add Edirol UA-1EX support */
-	/* TODO: add Edirol UM-3 support */
-	/* TODO: add Edirol MD-P1 support */
 
 /* Midiman/M-Audio devices */
 {
@@ -1367,6 +1408,27 @@
 	}
 },
 
+/* Casio devices */
+{
+	USB_DEVICE(0x07cf, 0x6801),
+	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+		.vendor_name = "Casio",
+		.product_name = "PL-40R",
+		.ifnum = 0,
+		.type = QUIRK_MIDI_YAMAHA
+	}
+},
+{
+	/* this ID is used by several devices without a product ID */
+	USB_DEVICE(0x07cf, 0x6802),
+	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+		.vendor_name = "Casio",
+		.product_name = "Keyboard",
+		.ifnum = 0,
+		.type = QUIRK_MIDI_YAMAHA
+	}
+},
+
 /* Mark of the Unicorn devices */
 {
 	/* thanks to Robert A. Lerche <ral 'at' msbit.com> */
@@ -1468,6 +1530,15 @@
 		.type = QUIRK_MIDI_STANDARD_INTERFACE
 	}
 },
+{
+	USB_DEVICE(0x0ccd, 0x0035),
+	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+		.vendor_name = "Miditech",
+		.product_name = "Play'n Roll",
+		.ifnum = 0,
+		.type = QUIRK_MIDI_CME
+	}
+},
 
 /* Novation EMS devices */
 {
@@ -1498,22 +1569,24 @@
 	}
 },
 
+/* Miditech devices */
 {
 	USB_DEVICE(0x4752, 0x0011),
 	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
 		.vendor_name = "Miditech",
 		.product_name = "Midistart-2",
 		.ifnum = 0,
-		.type = QUIRK_MIDI_MIDITECH
+		.type = QUIRK_MIDI_CME
 	}
 },
+
+/* Central Music devices */
 {
+	/* this ID used by both Miditech MidiStudio-2 and CME UF-x */
 	USB_DEVICE(0x7104, 0x2202),
 	.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
-		.vendor_name = "Miditech",
-		.product_name = "MidiStudio-2",
 		.ifnum = 0,
-		.type = QUIRK_MIDI_MIDITECH
+		.type = QUIRK_MIDI_CME
 	}
 },
 
diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c
index e0abb56..cfec38d 100644
--- a/sound/usb/usx2y/usbusx2y.c
+++ b/sound/usb/usx2y/usbusx2y.c
@@ -351,7 +351,7 @@
 	usX2Y(card)->chip.dev = device;
 	usX2Y(card)->chip.card = card;
 	init_waitqueue_head(&usX2Y(card)->prepare_wait_queue);
-	init_MUTEX (&usX2Y(card)->prepare_mutex);
+	mutex_init(&usX2Y(card)->prepare_mutex);
 	INIT_LIST_HEAD(&usX2Y(card)->chip.midi_list);
 	strcpy(card->driver, "USB "NAME_ALLCAPS"");
 	sprintf(card->shortname, "TASCAM "NAME_ALLCAPS"");
diff --git a/sound/usb/usx2y/usbusx2y.h b/sound/usb/usx2y/usbusx2y.h
index 435c1fe..456b5fd 100644
--- a/sound/usb/usx2y/usbusx2y.h
+++ b/sound/usb/usx2y/usbusx2y.h
@@ -34,7 +34,7 @@
 	unsigned int		rate,
 				format;
 	int			chip_status;
-	struct semaphore	prepare_mutex;
+	struct mutex		prepare_mutex;
 	struct us428ctls_sharedmem	*us428ctls_sharedmem;
 	int			wait_iso_frame;
 	wait_queue_head_t	us428ctls_wait_queue_head;
diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
index a6bbc7a..f6bd0de 100644
--- a/sound/usb/usx2y/usbusx2yaudio.c
+++ b/sound/usb/usx2y/usbusx2yaudio.c
@@ -811,7 +811,7 @@
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_usX2Y_substream *subs = runtime->private_data;
-	down(&subs->usX2Y->prepare_mutex);
+	mutex_lock(&subs->usX2Y->prepare_mutex);
 	snd_printdd("snd_usX2Y_hw_free(%p)\n", substream);
 
 	if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
@@ -832,7 +832,7 @@
 			usX2Y_urbs_release(subs);
 		}
 	}
-	up(&subs->usX2Y->prepare_mutex);
+	mutex_unlock(&subs->usX2Y->prepare_mutex);
 	return snd_pcm_lib_free_pages(substream);
 }
 /*
@@ -849,7 +849,7 @@
 	int err = 0;
 	snd_printdd("snd_usX2Y_pcm_prepare(%p)\n", substream);
 
-	down(&usX2Y->prepare_mutex);
+	mutex_lock(&usX2Y->prepare_mutex);
 	usX2Y_subs_prepare(subs);
 // Start hardware streams
 // SyncStream first....
@@ -869,7 +869,7 @@
 		err = usX2Y_urbs_start(subs);
 
  up_prepare_mutex:
-	up(&usX2Y->prepare_mutex);
+	mutex_unlock(&usX2Y->prepare_mutex);
 	return err;
 }
 
diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c
index 796a7dce..3158550 100644
--- a/sound/usb/usx2y/usx2yhwdeppcm.c
+++ b/sound/usb/usx2y/usx2yhwdeppcm.c
@@ -366,7 +366,7 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_usX2Y_substream *subs = runtime->private_data,
 		*cap_subs2 = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
-	down(&subs->usX2Y->prepare_mutex);
+	mutex_lock(&subs->usX2Y->prepare_mutex);
 	snd_printdd("snd_usX2Y_usbpcm_hw_free(%p)\n", substream);
 
 	if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
@@ -395,7 +395,7 @@
 				usX2Y_usbpcm_urbs_release(cap_subs2);
 		}
 	}
-	up(&subs->usX2Y->prepare_mutex);
+	mutex_unlock(&subs->usX2Y->prepare_mutex);
 	return snd_pcm_lib_free_pages(substream);
 }
 
@@ -503,7 +503,7 @@
 		memset(usX2Y->hwdep_pcm_shm, 0, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
 	}
 
-	down(&usX2Y->prepare_mutex);
+	mutex_lock(&usX2Y->prepare_mutex);
 	usX2Y_subs_prepare(subs);
 // Start hardware streams
 // SyncStream first....
@@ -544,7 +544,7 @@
 		usX2Y->hwdep_pcm_shm->capture_iso_start = -1;
 
  up_prepare_mutex:
-	up(&usX2Y->prepare_mutex);
+	mutex_unlock(&usX2Y->prepare_mutex);
 	return err;
 }
 
@@ -621,7 +621,7 @@
 		if (dev->type != SNDRV_DEV_PCM)
 			continue;
 		pcm = dev->device_data;
-		down(&pcm->open_mutex);
+		mutex_lock(&pcm->open_mutex);
 	}
 	list_for_each(list, &card->devices) {
 		int s;
@@ -650,7 +650,7 @@
 		if (dev->type != SNDRV_DEV_PCM)
 			continue;
 		pcm = dev->device_data;
-		up(&pcm->open_mutex);
+		mutex_unlock(&pcm->open_mutex);
 	}
 }