Browse Source

Merge tag 'sound-4.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound

Pull sound updates from Takashi Iwai:
 "There have been little changes in ALSA core stuff, but ASoC core still
  kept rolling for the continued restructuring. The rest are lots of
  small driver-specific changes and some minor API updates. Here are
  highlights:

  General:
  - Appropriate fall-through annotations everywhere
  - Some code cleanup in memalloc code, handling non-cacahed pages more
    commonly in the helper
  - Deployment of SNDRV_PCM_INFO_SYNC_APPLPTR flag consistently

  Drivers:
  - More HD-audio CA0132 codec improvement for supporting other Creative
    boards
  - Plumbing legacy HD-audio codecs as ASoC BE on Intel SST; this will
    give move support of existing HD-audio devices with DSP
  - A few device-specific HD-audio quirks as usual
  - New quirk for RME CC devices and correction for B&W PX for USB-audio
  - FireWire: code refactoring including devres usages

  ASoC Core:
  - Continued componentization works; it's almost done!
  - A bunch of new for_each_foo macros
  - Cleanups and fixes in DAPM code

  ASoC Drivers:
  - MCLK support for several different devices, including CS42L51, STM32
    SAI, and MAX98373
  - Support for Allwinner A64 CODEC analog, Intel boards with DA7219 and
    MAX98927, Meson AXG PDM inputs, Nuvoton NAU8822, Renesas R8A7744 and
    TI PCM3060"

* tag 'sound-4.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (299 commits)
  ASoC: stm32: sai: fix master clock naming
  ASoC: stm32: add clock dependency for sai
  ALSA: hda/ca0132 - Actually fix microphone issue
  ASoC: sun4i-i2s: move code from startup/shutdown hooks into pm_runtime hooks
  ASoC: wm2000: Remove wm2000_read helper function
  ASoC: cs42l51: fix mclk support
  ASoC: wm_adsp: Log addresses as 8 digits in wm_adsp_buffer_populate
  ASoC: wm_adsp: Rename memory fields in wm_adsp_buffer
  ASoC: cs42l51: add mclk support
  ASoC: stm32: sai: set sai as mclk clock provider
  ASoC: dt-bindings: add mclk support to cs42l51
  ASoC: dt-bindings: add mclk provider support to stm32 sai
  ASoC: soc-core: fix trivial checkpatch issues
  ASoC: dapm: Add support for hw_free on CODEC to CODEC links
  ASoC: Intel: kbl_da7219_max98927: minor white space clean up
  ALSA: i2c/cs8427: Fix int to char conversion
  ALSA: doc: Brush up the old writing-an-alsa-driver
  ASoC: rsnd: tidyup SSICR::SWSP for TDM
  ASoC: rsnd: enable TDM settings for SSI parent
  ASoC: pcm3168a: add hw constraint for capture channel
  ...
Linus Torvalds 6 years ago
parent
commit
3acbd2de6b
100 changed files with 2669 additions and 1142 deletions
  1. 54 0
      Documentation/devicetree/bindings/sound/adi,adau1977.txt
  2. 24 0
      Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt
  3. 17 0
      Documentation/devicetree/bindings/sound/cs42l51.txt
  4. 23 0
      Documentation/devicetree/bindings/sound/maxim,max98088.txt
  5. 23 0
      Documentation/devicetree/bindings/sound/mikroe,mikroe-proto.txt
  6. 16 0
      Documentation/devicetree/bindings/sound/nau8822.txt
  7. 17 0
      Documentation/devicetree/bindings/sound/pcm3060.txt
  8. 9 9
      Documentation/devicetree/bindings/sound/qcom,q6afe.txt
  9. 4 1
      Documentation/devicetree/bindings/sound/renesas,rsnd.txt
  10. 9 0
      Documentation/devicetree/bindings/sound/st,sta32x.txt
  11. 7 0
      Documentation/devicetree/bindings/sound/st,stm32-sai.txt
  12. 2 0
      Documentation/devicetree/bindings/sound/sun4i-i2s.txt
  13. 12 0
      Documentation/devicetree/bindings/sound/sun50i-codec-analog.txt
  14. 1 1
      Documentation/devicetree/bindings/sound/ts3a227e.txt
  15. 17 0
      Documentation/devicetree/bindings/sound/wm8782.txt
  16. 0 1
      Documentation/devicetree/bindings/trivial-devices.txt
  17. 1 0
      Documentation/devicetree/bindings/vendor-prefixes.txt
  18. 2 0
      Documentation/sound/hd-audio/models.rst
  19. 149 158
      Documentation/sound/kernel-api/writing-an-alsa-driver.rst
  20. 7 0
      MAINTAINERS
  21. 0 0
      include/sound/hda_codec.h
  22. 3 0
      include/sound/memalloc.h
  23. 1 0
      include/sound/rawmidi.h
  24. 18 9
      include/sound/simple_card_utils.h
  25. 6 0
      include/sound/soc-acpi-intel-match.h
  26. 0 9
      include/sound/soc-dapm.h
  27. 10 0
      include/sound/soc-dpcm.h
  28. 44 1
      include/sound/soc.h
  29. 1 1
      include/uapi/sound/asound.h
  30. 8 7
      sound/aoa/soundbus/i2sbus/core.c
  31. 0 1
      sound/arm/Kconfig
  32. 25 16
      sound/core/memalloc.c
  33. 2 2
      sound/core/oss/pcm_plugin.c
  34. 14 7
      sound/core/pcm_lib.c
  35. 22 0
      sound/core/rawmidi.c
  36. 1 1
      sound/core/seq/oss/seq_oss_timer.c
  37. 19 3
      sound/core/seq/seq_system.c
  38. 1 3
      sound/core/seq/seq_virmidi.c
  39. 13 2
      sound/core/sgbuf.c
  40. 2 0
      sound/firewire/Kconfig
  41. 71 7
      sound/firewire/amdtp-stream.c
  42. 16 42
      sound/firewire/bebob/bebob.c
  43. 3 2
      sound/firewire/bebob/bebob_maudio.c
  44. 10 31
      sound/firewire/dice/dice.c
  45. 13 22
      sound/firewire/digi00x/digi00x.c
  46. 12 24
      sound/firewire/fireface/ff.c
  47. 20 49
      sound/firewire/fireworks/fireworks.c
  48. 10 8
      sound/firewire/isight.c
  49. 13 34
      sound/firewire/motu/motu.c
  50. 3 2
      sound/firewire/oxfw/oxfw-scs1x.c
  51. 3 2
      sound/firewire/oxfw/oxfw-spkr.c
  52. 8 5
      sound/firewire/oxfw/oxfw-stream.c
  53. 12 51
      sound/firewire/oxfw/oxfw.c
  54. 12 28
      sound/firewire/tascam/tascam.c
  55. 14 8
      sound/hda/ext/hdac_ext_controller.c
  56. 1 1
      sound/i2c/cs8427.c
  57. 4 2
      sound/isa/opti9xx/opti92x-ad1848.c
  58. 5 5
      sound/isa/sb/sb8_main.c
  59. 5 8
      sound/mips/hal2.c
  60. 1 1
      sound/pci/asihpi/hpios.c
  61. 3 3
      sound/pci/atiixp.c
  62. 6 0
      sound/pci/au88x0/au88x0_core.c
  63. 4 2
      sound/pci/cs46xx/cs46xx_lib.c
  64. 2 1
      sound/pci/emu10k1/emupcm.c
  65. 1 1
      sound/pci/hda/hda_auto_parser.c
  66. 1 1
      sound/pci/hda/hda_beep.h
  67. 13 1
      sound/pci/hda/hda_bind.c
  68. 1 1
      sound/pci/hda/hda_codec.c
  69. 9 27
      sound/pci/hda/hda_controller.c
  70. 7 13
      sound/pci/hda/hda_controller.h
  71. 1 1
      sound/pci/hda/hda_eld.c
  72. 1 1
      sound/pci/hda/hda_generic.c
  73. 1 1
      sound/pci/hda/hda_hwdep.c
  74. 17 95
      sound/pci/hda/hda_intel.c
  75. 1 1
      sound/pci/hda/hda_jack.c
  76. 1 1
      sound/pci/hda/hda_proc.c
  77. 1 1
      sound/pci/hda/hda_sysfs.c
  78. 2 18
      sound/pci/hda/hda_tegra.c
  79. 1 1
      sound/pci/hda/patch_analog.c
  80. 1 1
      sound/pci/hda/patch_ca0110.c
  81. 1412 263
      sound/pci/hda/patch_ca0132.c
  82. 1 1
      sound/pci/hda/patch_cirrus.c
  83. 1 1
      sound/pci/hda/patch_cmedia.c
  84. 2 1
      sound/pci/hda/patch_conexant.c
  85. 1 1
      sound/pci/hda/patch_hdmi.c
  86. 28 1
      sound/pci/hda/patch_realtek.c
  87. 1 1
      sound/pci/hda/patch_si3054.c
  88. 21 1
      sound/pci/hda/patch_sigmatel.c
  89. 1 1
      sound/pci/hda/patch_via.c
  90. 16 81
      sound/pci/intel8x0.c
  91. 10 10
      sound/pci/intel8x0m.c
  92. 8 14
      sound/pci/rme32.c
  93. 1 1
      sound/pci/rme9652/hdspm.c
  94. 68 9
      sound/soc/amd/acp-da7219-max98357a.c
  95. 20 10
      sound/soc/amd/acp-pcm-dma.c
  96. 2 1
      sound/soc/amd/acp.h
  97. 12 0
      sound/soc/atmel/Kconfig
  98. 2 0
      sound/soc/atmel/Makefile
  99. 3 10
      sound/soc/atmel/atmel_ssc_dai.c
  100. 165 0
      sound/soc/atmel/mikroe-proto.c

+ 54 - 0
Documentation/devicetree/bindings/sound/adi,adau1977.txt

@@ -0,0 +1,54 @@
+Analog Devices ADAU1977/ADAU1978/ADAU1979
+
+Datasheets:
+http://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1977.pdf
+http://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1978.pdf
+http://www.analog.com/media/en/technical-documentation/data-sheets/ADAU1979.pdf
+
+This driver supports both the I2C and SPI bus.
+
+Required properties:
+ - compatible: Should contain one of the following:
+               "adi,adau1977"
+               "adi,adau1978"
+               "adi,adau1979"
+
+ - AVDD-supply: analog power supply for the device, please consult
+                Documentation/devicetree/bindings/regulator/regulator.txt
+
+Optional properties:
+ - reset-gpio:  the reset pin for the chip, for more details consult
+                Documentation/devicetree/bindings/gpio/gpio.txt
+
+ - DVDD-supply: supply voltage for the digital core, please consult
+                Documentation/devicetree/bindings/regulator/regulator.txt
+
+For required properties on SPI, please consult
+Documentation/devicetree/bindings/spi/spi-bus.txt
+
+Required properties on I2C:
+
+ - reg:         The i2c address. Value depends on the state of ADDR0
+                and ADDR1, as wired in hardware.
+
+Examples:
+
+	adau1977_spi: adau1977@0 {
+		compatible = "adi,adau1977";
+		spi-max-frequency = <600000>;
+
+		AVDD-supply = <&regulator>;
+		DVDD-supply = <&regulator_digital>;
+
+		reset_gpio = <&gpio 10 GPIO_ACTIVE_LOW>;
+	};
+
+	adau1977_i2c: adau1977@11 {
+		compatible = "adi,adau1977";
+		reg = <0x11>;
+
+		AVDD-supply = <&regulator>;
+		DVDD-supply = <&regulator_digital>;
+
+		reset_gpio = <&gpio 10 GPIO_ACTIVE_LOW>;
+	};

+ 24 - 0
Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt

@@ -0,0 +1,24 @@
+* Amlogic Audio PDM input
+
+Required properties:
+- compatible: 'amlogic,axg-pdm'
+- reg: physical base address of the controller and length of memory
+       mapped region.
+- clocks: list of clock phandle, one for each entry clock-names.
+- clock-names: should contain the following:
+  * "pclk"   : peripheral clock.
+  * "dclk"   : pdm digital clock
+  * "sysclk" : dsp system clock
+- #sound-dai-cells: must be 0.
+
+Example of PDM on the A113 SoC:
+
+pdm: audio-controller@ff632000 {
+	compatible = "amlogic,axg-pdm";
+	reg = <0x0 0xff632000 0x0 0x34>;
+	#sound-dai-cells = <0>;
+	clocks = <&clkc_audio AUD_CLKID_PDM>,
+		 <&clkc_audio AUD_CLKID_PDM_DCLK>,
+		 <&clkc_audio AUD_CLKID_PDM_SYSCLK>;
+	clock-names = "pclk", "dclk", "sysclk";
+};

+ 17 - 0
Documentation/devicetree/bindings/sound/cs42l51.txt

@@ -0,0 +1,17 @@
+CS42L51 audio CODEC
+
+Optional properties:
+
+  - clocks : a list of phandles + clock-specifiers, one for each entry in
+    clock-names
+
+  - clock-names : must contain "MCLK"
+
+Example:
+
+cs42l51: cs42l51@4a {
+	compatible = "cirrus,cs42l51";
+	reg = <0x4a>;
+	clocks = <&mclk_prov>;
+	clock-names = "MCLK";
+};

+ 23 - 0
Documentation/devicetree/bindings/sound/maxim,max98088.txt

@@ -0,0 +1,23 @@
+MAX98088 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+- compatible: "maxim,max98088" or "maxim,max98089".
+- reg: The I2C address of the device.
+
+Optional properties:
+
+- clocks: the clock provider of MCLK, see ../clock/clock-bindings.txt section
+  "consumer" for more information.
+- clock-names: must be set to "mclk"
+
+Example:
+
+max98089: codec@10 {
+	compatible = "maxim,max98089";
+	reg = <0x10>;
+	clocks = <&clks IMX6QDL_CLK_CKO2>;
+	clock-names = "mclk";
+};

+ 23 - 0
Documentation/devicetree/bindings/sound/mikroe,mikroe-proto.txt

@@ -0,0 +1,23 @@
+Mikroe-PROTO audio board
+
+Required properties:
+  - compatible: "mikroe,mikroe-proto"
+  - dai-format: Must be "i2s".
+  - i2s-controller: The phandle of the I2S controller.
+  - audio-codec: The phandle of the WM8731 audio codec.
+Optional properties:
+  - model: The user-visible name of this sound complex.
+  - bitclock-master: Indicates dai-link bit clock master; for details see simple-card.txt (1).
+  - frame-master: Indicates dai-link frame master; for details see simple-card.txt (1).
+
+(1) : There must be the same master for both bit and frame clocks.
+
+Example:
+	sound {
+		compatible = "mikroe,mikroe-proto";
+		model = "wm8731 @ sama5d2_xplained";
+		i2s-controller = <&i2s0>;
+		audio-codec = <&wm8731>;
+		dai-format = "i2s";
+        };
+};

+ 16 - 0
Documentation/devicetree/bindings/sound/nau8822.txt

@@ -0,0 +1,16 @@
+NAU8822 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+  - compatible : "nuvoton,nau8822"
+
+  - reg : the I2C address of the device.
+
+Example:
+
+codec: nau8822@1a {
+	compatible = "nuvoton,nau8822";
+	reg = <0x1a>;
+};

+ 17 - 0
Documentation/devicetree/bindings/sound/pcm3060.txt

@@ -0,0 +1,17 @@
+PCM3060 audio CODEC
+
+This driver supports both I2C and SPI.
+
+Required properties:
+
+- compatible: "ti,pcm3060"
+
+- reg : the I2C address of the device for I2C, the chip select
+        number for SPI.
+
+Examples:
+
+	pcm3060: pcm3060@46 {
+		 compatible = "ti,pcm3060";
+		 reg = <0x46>;
+	};

+ 9 - 9
Documentation/devicetree/bindings/sound/qcom,q6afe.txt

@@ -49,7 +49,7 @@ configuration of each dai. Must contain the following properties.
 	Usage: required for mi2s interface
 	Usage: required for mi2s interface
 	Value type: <prop-encoded-array>
 	Value type: <prop-encoded-array>
 	Definition: Must be list of serial data lines used by this dai.
 	Definition: Must be list of serial data lines used by this dai.
-	should be one or more of the 1-4 sd lines.
+	should be one or more of the 0-3 sd lines.
 
 
  - qcom,tdm-sync-mode:
  - qcom,tdm-sync-mode:
 	Usage: required for tdm interface
 	Usage: required for tdm interface
@@ -137,42 +137,42 @@ q6afe@4 {
 
 
 		prim-mi2s-rx@16 {
 		prim-mi2s-rx@16 {
 			reg = <16>;
 			reg = <16>;
-			qcom,sd-lines = <1 3>;
+			qcom,sd-lines = <0 2>;
 		};
 		};
 
 
 		prim-mi2s-tx@17 {
 		prim-mi2s-tx@17 {
 			reg = <17>;
 			reg = <17>;
-			qcom,sd-lines = <2>;
+			qcom,sd-lines = <1>;
 		};
 		};
 
 
 		sec-mi2s-rx@18 {
 		sec-mi2s-rx@18 {
 			reg = <18>;
 			reg = <18>;
-			qcom,sd-lines = <1 4>;
+			qcom,sd-lines = <0 3>;
 		};
 		};
 
 
 		sec-mi2s-tx@19 {
 		sec-mi2s-tx@19 {
 			reg = <19>;
 			reg = <19>;
-			qcom,sd-lines = <2>;
+			qcom,sd-lines = <1>;
 		};
 		};
 
 
 		tert-mi2s-rx@20 {
 		tert-mi2s-rx@20 {
 			reg = <20>;
 			reg = <20>;
-			qcom,sd-lines = <2 4>;
+			qcom,sd-lines = <1 3>;
 		};
 		};
 
 
 		tert-mi2s-tx@21 {
 		tert-mi2s-tx@21 {
 			reg = <21>;
 			reg = <21>;
-			qcom,sd-lines = <1>;
+			qcom,sd-lines = <0>;
 		};
 		};
 
 
 		quat-mi2s-rx@22 {
 		quat-mi2s-rx@22 {
 			reg = <22>;
 			reg = <22>;
-			qcom,sd-lines = <1>;
+			qcom,sd-lines = <0>;
 		};
 		};
 
 
 		quat-mi2s-tx@23 {
 		quat-mi2s-tx@23 {
 			reg = <23>;
 			reg = <23>;
-			qcom,sd-lines = <2>;
+			qcom,sd-lines = <1>;
 		};
 		};
 	};
 	};
 };
 };

+ 4 - 1
Documentation/devicetree/bindings/sound/renesas,rsnd.txt

@@ -340,10 +340,12 @@ Required properties:
 - compatible			: "renesas,rcar_sound-<soctype>", fallbacks
 - compatible			: "renesas,rcar_sound-<soctype>", fallbacks
 				  "renesas,rcar_sound-gen1" if generation1, and
 				  "renesas,rcar_sound-gen1" if generation1, and
 				  "renesas,rcar_sound-gen2" if generation2 (or RZ/G1)
 				  "renesas,rcar_sound-gen2" if generation2 (or RZ/G1)
-				  "renesas,rcar_sound-gen3" if generation3
+				  "renesas,rcar_sound-gen3" if generation3 (or RZ/G2)
 				  Examples with soctypes are:
 				  Examples with soctypes are:
 				    - "renesas,rcar_sound-r8a7743" (RZ/G1M)
 				    - "renesas,rcar_sound-r8a7743" (RZ/G1M)
+				    - "renesas,rcar_sound-r8a7744" (RZ/G1N)
 				    - "renesas,rcar_sound-r8a7745" (RZ/G1E)
 				    - "renesas,rcar_sound-r8a7745" (RZ/G1E)
+				    - "renesas,rcar_sound-r8a774a1" (RZ/G2M)
 				    - "renesas,rcar_sound-r8a7778" (R-Car M1A)
 				    - "renesas,rcar_sound-r8a7778" (R-Car M1A)
 				    - "renesas,rcar_sound-r8a7779" (R-Car H1)
 				    - "renesas,rcar_sound-r8a7779" (R-Car H1)
 				    - "renesas,rcar_sound-r8a7790" (R-Car H2)
 				    - "renesas,rcar_sound-r8a7790" (R-Car H2)
@@ -353,6 +355,7 @@ Required properties:
 				    - "renesas,rcar_sound-r8a7795" (R-Car H3)
 				    - "renesas,rcar_sound-r8a7795" (R-Car H3)
 				    - "renesas,rcar_sound-r8a7796" (R-Car M3-W)
 				    - "renesas,rcar_sound-r8a7796" (R-Car M3-W)
 				    - "renesas,rcar_sound-r8a77965" (R-Car M3-N)
 				    - "renesas,rcar_sound-r8a77965" (R-Car M3-N)
+				    - "renesas,rcar_sound-r8a77990" (R-Car E3)
 - reg				: Should contain the register physical address.
 - reg				: Should contain the register physical address.
 				  required register is
 				  required register is
 				   SRU/ADG/SSI      if generation1
 				   SRU/ADG/SSI      if generation1

+ 9 - 0
Documentation/devicetree/bindings/sound/st,sta32x.txt

@@ -19,6 +19,10 @@ Required properties:
 
 
 Optional properties:
 Optional properties:
 
 
+  - clocks, clock-names: Clock specifier for XTI input clock.
+	If specified, the clock will be enabled when the codec is probed,
+	and disabled when it is removed. The 'clock-names' must be set to 'xti'.
+
   -  st,output-conf: number, Selects the output configuration:
   -  st,output-conf: number, Selects the output configuration:
 	0: 2-channel (full-bridge) power, 2-channel data-out
 	0: 2-channel (full-bridge) power, 2-channel data-out
 	1: 2 (half-bridge). 1 (full-bridge) on-board power
 	1: 2 (half-bridge). 1 (full-bridge) on-board power
@@ -39,6 +43,9 @@ Optional properties:
   -  st,thermal-warning-recover:
   -  st,thermal-warning-recover:
 	If present, thermal warning recovery is enabled.
 	If present, thermal warning recovery is enabled.
 
 
+  - st,fault-detect-recovery:
+	If present, fault detect recovery is enabled.
+
   -  st,thermal-warning-adjustment:
   -  st,thermal-warning-adjustment:
 	If present, thermal warning adjustment is enabled.
 	If present, thermal warning adjustment is enabled.
 
 
@@ -76,6 +83,8 @@ Example:
 codec: sta32x@38 {
 codec: sta32x@38 {
 	compatible = "st,sta32x";
 	compatible = "st,sta32x";
 	reg = <0x1c>;
 	reg = <0x1c>;
+	clocks = <&clock>;
+	clock-names = "xti";
 	reset-gpios = <&gpio1 19 0>;
 	reset-gpios = <&gpio1 19 0>;
 	power-down-gpios = <&gpio1 16 0>;
 	power-down-gpios = <&gpio1 16 0>;
 	st,output-conf = /bits/ 8  <0x3>;	// set output to 2-channel
 	st,output-conf = /bits/ 8  <0x3>;	// set output to 2-channel

+ 7 - 0
Documentation/devicetree/bindings/sound/st,stm32-sai.txt

@@ -31,7 +31,11 @@ SAI subnodes required properties:
   - reg: Base address and size of SAI sub-block register set.
   - reg: Base address and size of SAI sub-block register set.
   - clocks: Must contain one phandle and clock specifier pair
   - clocks: Must contain one phandle and clock specifier pair
 	for sai_ck which feeds the internal clock generator.
 	for sai_ck which feeds the internal clock generator.
+	If the SAI shares a master clock, with another SAI set as MCLK
+	clock provider, SAI provider phandle must be specified here.
   - clock-names: Must contain "sai_ck".
   - clock-names: Must contain "sai_ck".
+	Must also contain "MCLK", if SAI shares a master clock,
+	with a SAI set as MCLK clock provider.
   - dmas: see Documentation/devicetree/bindings/dma/stm32-dma.txt
   - dmas: see Documentation/devicetree/bindings/dma/stm32-dma.txt
   - dma-names: identifier string for each DMA request line
   - dma-names: identifier string for each DMA request line
 	"tx": if sai sub-block is configured as playback DAI
 	"tx": if sai sub-block is configured as playback DAI
@@ -51,6 +55,9 @@ SAI subnodes Optional properties:
 	configured according to protocol defined in related DAI link node,
 	configured according to protocol defined in related DAI link node,
 	such as i2s, left justified, right justified, dsp and pdm protocols.
 	such as i2s, left justified, right justified, dsp and pdm protocols.
 	Note: ac97 protocol is not supported by SAI driver
 	Note: ac97 protocol is not supported by SAI driver
+   - #clock-cells: should be 0. This property must be present if the SAI device
+	is a master clock provider, according to clocks bindings, described in
+	Documentation/devicetree/bindings/clock/clock-bindings.txt.
 
 
 The device node should contain one 'port' child node with one child 'endpoint'
 The device node should contain one 'port' child node with one child 'endpoint'
 node, according to the bindings defined in Documentation/devicetree/bindings/
 node, according to the bindings defined in Documentation/devicetree/bindings/

+ 2 - 0
Documentation/devicetree/bindings/sound/sun4i-i2s.txt

@@ -10,6 +10,7 @@ Required properties:
    - "allwinner,sun6i-a31-i2s"
    - "allwinner,sun6i-a31-i2s"
    - "allwinner,sun8i-a83t-i2s"
    - "allwinner,sun8i-a83t-i2s"
    - "allwinner,sun8i-h3-i2s"
    - "allwinner,sun8i-h3-i2s"
+   - "allwinner,sun50i-a64-codec-i2s"
 - reg: physical base address of the controller and length of memory mapped
 - reg: physical base address of the controller and length of memory mapped
   region.
   region.
 - interrupts: should contain the I2S interrupt.
 - interrupts: should contain the I2S interrupt.
@@ -26,6 +27,7 @@ Required properties for the following compatibles:
 	- "allwinner,sun6i-a31-i2s"
 	- "allwinner,sun6i-a31-i2s"
 	- "allwinner,sun8i-a83t-i2s"
 	- "allwinner,sun8i-a83t-i2s"
 	- "allwinner,sun8i-h3-i2s"
 	- "allwinner,sun8i-h3-i2s"
+	- "allwinner,sun50i-a64-codec-i2s"
 - resets: phandle to the reset line for this codec
 - resets: phandle to the reset line for this codec
 
 
 Example:
 Example:

+ 12 - 0
Documentation/devicetree/bindings/sound/sun50i-codec-analog.txt

@@ -0,0 +1,12 @@
+* Allwinner A64 Codec Analog Controls
+
+Required properties:
+- compatible: must be one of the following compatibles:
+		- "allwinner,sun50i-a64-codec-analog"
+- reg: must contain the registers location and length
+
+Example:
+	codec_analog: codec-analog@1f015c0 {
+		compatible = "allwinner,sun50i-a64-codec-analog";
+		reg = <0x01f015c0 0x4>;
+	};

+ 1 - 1
Documentation/devicetree/bindings/sound/ts3a227e.txt

@@ -14,7 +14,7 @@ Required properties:
 
 
 Optional properies:
 Optional properies:
  - ti,micbias:   Intended MICBIAS voltage (datasheet section 9.6.7).
  - ti,micbias:   Intended MICBIAS voltage (datasheet section 9.6.7).
-      Select 0/1/2/3/4/5/6/7 to specify MACBIAS voltage
+      Select 0/1/2/3/4/5/6/7 to specify MICBIAS voltage
       2.1V/2.2V/2.3V/2.4V/2.5V/2.6V/2.7V/2.8V
       2.1V/2.2V/2.3V/2.4V/2.5V/2.6V/2.7V/2.8V
       Default value is "1" (2.2V).
       Default value is "1" (2.2V).
 
 

+ 17 - 0
Documentation/devicetree/bindings/sound/wm8782.txt

@@ -0,0 +1,17 @@
+WM8782 stereo ADC
+
+This device does not have any control interface or reset pins.
+
+Required properties:
+
+ - compatible  : "wlf,wm8782"
+ - Vdda-supply : phandle to a regulator for the analog power supply (2.7V - 5.5V)
+ - Vdd-supply  : phandle to a regulator for the digital power supply (2.7V - 3.6V)
+
+Example:
+
+wm8782: stereo-adc {
+	compatible = "wlf,wm8782";
+	Vdda-supply = <&vdda_supply>;
+	Vdd-supply = <&vdd_supply>;
+};

+ 0 - 1
Documentation/devicetree/bindings/trivial-devices.txt

@@ -35,7 +35,6 @@ at,24c08		i2c serial eeprom  (24cxx)
 atmel,at97sc3204t	i2c trusted platform module (TPM)
 atmel,at97sc3204t	i2c trusted platform module (TPM)
 capella,cm32181		CM32181: Ambient Light Sensor
 capella,cm32181		CM32181: Ambient Light Sensor
 capella,cm3232		CM3232: Ambient Light Sensor
 capella,cm3232		CM3232: Ambient Light Sensor
-cirrus,cs42l51		Cirrus Logic CS42L51 audio codec
 dallas,ds1374		I2C, 32-Bit Binary Counter Watchdog RTC with Trickle Charger and Reset Input/Output
 dallas,ds1374		I2C, 32-Bit Binary Counter Watchdog RTC with Trickle Charger and Reset Input/Output
 dallas,ds1631		High-Precision Digital Thermometer
 dallas,ds1631		High-Precision Digital Thermometer
 dallas,ds1672		Dallas DS1672 Real-time Clock
 dallas,ds1672		Dallas DS1672 Real-time Clock

+ 1 - 0
Documentation/devicetree/bindings/vendor-prefixes.txt

@@ -235,6 +235,7 @@ micrel	Micrel Inc.
 microchip	Microchip Technology Inc.
 microchip	Microchip Technology Inc.
 microcrystal	Micro Crystal AG
 microcrystal	Micro Crystal AG
 micron	Micron Technology Inc.
 micron	Micron Technology Inc.
+mikroe		MikroElektronika d.o.o.
 minix	MINIX Technology Ltd.
 minix	MINIX Technology Ltd.
 miramems	MiraMEMS Sensing Technology Co., Ltd.
 miramems	MiraMEMS Sensing Technology Co., Ltd.
 mitsubishi	Mitsubishi Electric Corporation
 mitsubishi	Mitsubishi Electric Corporation

+ 2 - 0
Documentation/sound/hd-audio/models.rst

@@ -309,6 +309,8 @@ asus-nx50
     ASUS Nx50 fixups
     ASUS Nx50 fixups
 asus-nx51
 asus-nx51
     ASUS Nx51 fixups
     ASUS Nx51 fixups
+asus-g751
+    ASUS G751 fixups
 alc891-headset
 alc891-headset
     Headset mode support on ALC891
     Headset mode support on ALC891
 alc891-headset-multi
 alc891-headset-multi

+ 149 - 158
Documentation/sound/kernel-api/writing-an-alsa-driver.rst

@@ -3,8 +3,6 @@ Writing an ALSA Driver
 ======================
 ======================
 
 
 :Author: Takashi Iwai <tiwai@suse.de>
 :Author: Takashi Iwai <tiwai@suse.de>
-:Date:   Oct 15, 2007
-:Edition: 0.3.7
 
 
 Preface
 Preface
 =======
 =======
@@ -21,11 +19,6 @@ explain the general topic of linux kernel coding and doesn't cover
 low-level driver implementation details. It only describes the standard
 low-level driver implementation details. It only describes the standard
 way to write a PCI sound driver on ALSA.
 way to write a PCI sound driver on ALSA.
 
 
-If you are already familiar with the older ALSA ver.0.5.x API, you can
-check the drivers such as ``sound/pci/es1938.c`` or
-``sound/pci/maestro3.c`` which have also almost the same code-base in
-the ALSA 0.5.x tree, so you can compare the differences.
-
 This document is still a draft version. Any feedback and corrections,
 This document is still a draft version. Any feedback and corrections,
 please!!
 please!!
 
 
@@ -35,24 +28,7 @@ File Tree Structure
 General
 General
 -------
 -------
 
 
-The ALSA drivers are provided in two ways.
-
-One is the trees provided as a tarball or via cvs from the ALSA's ftp
-site, and another is the 2.6 (or later) Linux kernel tree. To
-synchronize both, the ALSA driver tree is split into two different
-trees: alsa-kernel and alsa-driver. The former contains purely the
-source code for the Linux 2.6 (or later) tree. This tree is designed
-only for compilation on 2.6 or later environment. The latter,
-alsa-driver, contains many subtle files for compiling ALSA drivers
-outside of the Linux kernel tree, wrapper functions for older 2.2 and
-2.4 kernels, to adapt the latest kernel API, and additional drivers
-which are still in development or in tests. The drivers in alsa-driver
-tree will be moved to alsa-kernel (and eventually to the 2.6 kernel
-tree) when they are finished and confirmed to work fine.
-
-The file tree structure of ALSA driver is depicted below. Both
-alsa-kernel and alsa-driver have almost the same file structure, except
-for “core” directory. It's named as “acore” in alsa-driver tree.
+The file tree structure of ALSA driver is depicted below.
 
 
 ::
 ::
 
 
@@ -61,14 +37,11 @@ for “core” directory. It's named as “acore” in alsa-driver tree.
                             /oss
                             /oss
                             /seq
                             /seq
                                     /oss
                                     /oss
-                                    /instr
-                    /ioctl32
                     /include
                     /include
                     /drivers
                     /drivers
                             /mpu401
                             /mpu401
                             /opl3
                             /opl3
                     /i2c
                     /i2c
-                            /l3
                     /synth
                     /synth
                             /emux
                             /emux
                     /pci
                     /pci
@@ -80,6 +53,7 @@ for “core” directory. It's named as “acore” in alsa-driver tree.
                     /sparc
                     /sparc
                     /usb
                     /usb
                     /pcmcia /(cards)
                     /pcmcia /(cards)
+                    /soc
                     /oss
                     /oss
 
 
 
 
@@ -99,13 +73,6 @@ directory. The rawmidi OSS emulation is included in the ALSA rawmidi
 code since it's quite small. The sequencer code is stored in
 code since it's quite small. The sequencer code is stored in
 ``core/seq/oss`` directory (see `below <#core-seq-oss>`__).
 ``core/seq/oss`` directory (see `below <#core-seq-oss>`__).
 
 
-core/ioctl32
-~~~~~~~~~~~~
-
-This directory contains the 32bit-ioctl wrappers for 64bit architectures
-such like x86-64, ppc64 and sparc64. For 32bit and alpha architectures,
-these are not compiled.
-
 core/seq
 core/seq
 ~~~~~~~~
 ~~~~~~~~
 
 
@@ -119,11 +86,6 @@ core/seq/oss
 
 
 This contains the OSS sequencer emulation codes.
 This contains the OSS sequencer emulation codes.
 
 
-core/seq/instr
-~~~~~~~~~~~~~~
-
-This directory contains the modules for the sequencer instrument layer.
-
 include directory
 include directory
 -----------------
 -----------------
 
 
@@ -161,11 +123,6 @@ Although there is a standard i2c layer on Linux, ALSA has its own i2c
 code for some cards, because the soundcard needs only a simple operation
 code for some cards, because the soundcard needs only a simple operation
 and the standard i2c API is too complicated for such a purpose.
 and the standard i2c API is too complicated for such a purpose.
 
 
-i2c/l3
-~~~~~~
-
-This is a sub-directory for ARM L3 i2c.
-
 synth directory
 synth directory
 ---------------
 ---------------
 
 
@@ -209,11 +166,19 @@ The PCMCIA, especially PCCard drivers will go here. CardBus drivers will
 be in the pci directory, because their API is identical to that of
 be in the pci directory, because their API is identical to that of
 standard PCI cards.
 standard PCI cards.
 
 
+soc directory
+-------------
+
+This directory contains the codes for ASoC (ALSA System on Chip)
+layer including ASoC core, codec and machine drivers.
+
 oss directory
 oss directory
 -------------
 -------------
 
 
-The OSS/Lite source files are stored here in Linux 2.6 (or later) tree.
-In the ALSA driver tarball, this directory is empty, of course :)
+Here contains OSS/Lite codes.
+All codes have been deprecated except for dmasound on m68k as of
+writing this.
+
 
 
 Basic Flow for PCI Drivers
 Basic Flow for PCI Drivers
 ==========================
 ==========================
@@ -352,10 +317,8 @@ to details explained in the following section.
 
 
               /* (3) */
               /* (3) */
               err = snd_mychip_create(card, pci, &chip);
               err = snd_mychip_create(card, pci, &chip);
-              if (err < 0) {
-                      snd_card_free(card);
-                      return err;
-              }
+              if (err < 0)
+                      goto error;
 
 
               /* (4) */
               /* (4) */
               strcpy(card->driver, "My Chip");
               strcpy(card->driver, "My Chip");
@@ -368,22 +331,23 @@ to details explained in the following section.
 
 
               /* (6) */
               /* (6) */
               err = snd_card_register(card);
               err = snd_card_register(card);
-              if (err < 0) {
-                      snd_card_free(card);
-                      return err;
-              }
+              if (err < 0)
+                      goto error;
 
 
               /* (7) */
               /* (7) */
               pci_set_drvdata(pci, card);
               pci_set_drvdata(pci, card);
               dev++;
               dev++;
               return 0;
               return 0;
+
+      error:
+              snd_card_free(card);
+	      return err;
       }
       }
 
 
       /* destructor -- see the "Destructor" sub-section */
       /* destructor -- see the "Destructor" sub-section */
       static void snd_mychip_remove(struct pci_dev *pci)
       static void snd_mychip_remove(struct pci_dev *pci)
       {
       {
               snd_card_free(pci_get_drvdata(pci));
               snd_card_free(pci_get_drvdata(pci));
-              pci_set_drvdata(pci, NULL);
       }
       }
 
 
 
 
@@ -445,14 +409,26 @@ In this part, the PCI resources are allocated.
   struct mychip *chip;
   struct mychip *chip;
   ....
   ....
   err = snd_mychip_create(card, pci, &chip);
   err = snd_mychip_create(card, pci, &chip);
-  if (err < 0) {
-          snd_card_free(card);
-          return err;
-  }
+  if (err < 0)
+          goto error;
 
 
 The details will be explained in the section `PCI Resource
 The details will be explained in the section `PCI Resource
 Management`_.
 Management`_.
 
 
+When something goes wrong, the probe function needs to deal with the
+error.  In this example, we have a single error handling path placed
+at the end of the function.
+
+::
+
+  error:
+          snd_card_free(card);
+	  return err;
+
+Since each component can be properly freed, the single
+:c:func:`snd_card_free()` call should suffice in most cases.
+
+
 4) Set the driver ID and name strings.
 4) Set the driver ID and name strings.
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 
@@ -486,10 +462,8 @@ too.
 ::
 ::
 
 
   err = snd_card_register(card);
   err = snd_card_register(card);
-  if (err < 0) {
-          snd_card_free(card);
-          return err;
-  }
+  if (err < 0)
+          goto error;
 
 
 Will be explained in the section `Management of Cards and
 Will be explained in the section `Management of Cards and
 Components`_, too.
 Components`_, too.
@@ -513,14 +487,13 @@ The destructor, remove callback, simply releases the card instance. Then
 the ALSA middle layer will release all the attached components
 the ALSA middle layer will release all the attached components
 automatically.
 automatically.
 
 
-It would be typically like the following:
+It would be typically just :c:func:`calling snd_card_free()`:
 
 
 ::
 ::
 
 
   static void snd_mychip_remove(struct pci_dev *pci)
   static void snd_mychip_remove(struct pci_dev *pci)
   {
   {
           snd_card_free(pci_get_drvdata(pci));
           snd_card_free(pci_get_drvdata(pci));
-          pci_set_drvdata(pci, NULL);
   }
   }
 
 
 
 
@@ -546,7 +519,7 @@ in the source file. If the code is split into several files, the files
 without module options don't need them.
 without module options don't need them.
 
 
 In addition to these headers, you'll need ``<linux/interrupt.h>`` for
 In addition to these headers, you'll need ``<linux/interrupt.h>`` for
-interrupt handling, and ``<asm/io.h>`` for I/O access. If you use the
+interrupt handling, and ``<linux/io.h>`` for I/O access. If you use the
 :c:func:`mdelay()` or :c:func:`udelay()` functions, you'll need
 :c:func:`mdelay()` or :c:func:`udelay()` functions, you'll need
 to include ``<linux/delay.h>`` too.
 to include ``<linux/delay.h>`` too.
 
 
@@ -720,6 +693,13 @@ function, which will call the real destructor.
 
 
 where :c:func:`snd_mychip_free()` is the real destructor.
 where :c:func:`snd_mychip_free()` is the real destructor.
 
 
+The demerit of this method is the obviously more amount of codes.
+The merit is, however, you can trigger the own callback at registering
+and disconnecting the card via setting in snd_device_ops.
+About the registering and disconnecting the card, see the subsections
+below.
+
+
 Registration and Release
 Registration and Release
 ------------------------
 ------------------------
 
 
@@ -905,10 +885,8 @@ Resource Allocation
 -------------------
 -------------------
 
 
 The allocation of I/O ports and irqs is done via standard kernel
 The allocation of I/O ports and irqs is done via standard kernel
-functions. Unlike ALSA ver.0.5.x., there are no helpers for that. And
-these resources must be released in the destructor function (see below).
-Also, on ALSA 0.9.x, you don't need to allocate (pseudo-)DMA for PCI
-like in ALSA 0.5.x.
+functions.  These resources must be released in the destructor
+function (see below).
 
 
 Now assume that the PCI device has an I/O port with 8 bytes and an
 Now assume that the PCI device has an I/O port with 8 bytes and an
 interrupt. Then :c:type:`struct mychip <mychip>` will have the
 interrupt. Then :c:type:`struct mychip <mychip>` will have the
@@ -1064,7 +1042,8 @@ and the allocation would be like below:
 
 
 ::
 ::
 
 
-  if ((err = pci_request_regions(pci, "My Chip")) < 0) {
+  err = pci_request_regions(pci, "My Chip");
+  if (err < 0) {
           kfree(chip);
           kfree(chip);
           return err;
           return err;
   }
   }
@@ -1086,6 +1065,21 @@ and the corresponding destructor would be:
           ....
           ....
   }
   }
 
 
+Of course, a modern way with :c:func:`pci_iomap()` will make things a
+bit easier, too.
+
+::
+
+  err = pci_request_regions(pci, "My Chip");
+  if (err < 0) {
+          kfree(chip);
+          return err;
+  }
+  chip->iobase_virt = pci_iomap(pci, 0, 0);
+
+which is paired with :c:func:`pci_iounmap()` at destructor.
+
+
 PCI Entries
 PCI Entries
 -----------
 -----------
 
 
@@ -1154,13 +1148,6 @@ And at last, the module entries:
 Note that these module entries are tagged with ``__init`` and ``__exit``
 Note that these module entries are tagged with ``__init`` and ``__exit``
 prefixes.
 prefixes.
 
 
-Oh, one thing was forgotten. If you have no exported symbols, you need
-to declare it in 2.2 or 2.4 kernels (it's not necessary in 2.6 kernels).
-
-::
-
-  EXPORT_NO_SYMBOLS;
-
 That's all!
 That's all!
 
 
 PCM Interface
 PCM Interface
@@ -2113,6 +2100,16 @@ non-contiguous buffers. The mmap calls this callback to get the page
 address. Some examples will be explained in the later section `Buffer
 address. Some examples will be explained in the later section `Buffer
 and Memory Management`_, too.
 and Memory Management`_, too.
 
 
+mmap calllback
+~~~~~~~~~~~~~~
+
+This is another optional callback for controlling mmap behavior.
+Once when defined, PCM core calls this callback when a page is
+memory-mapped instead of dealing via the standard helper.
+If you need special handling (due to some architecture or
+device-specific issues), implement everything here as you like.
+
+
 PCM Interrupt Handler
 PCM Interrupt Handler
 ---------------------
 ---------------------
 
 
@@ -2370,6 +2367,27 @@ to define the inverse rule:
                       hw_rule_format_by_channels, NULL,
                       hw_rule_format_by_channels, NULL,
                       SNDRV_PCM_HW_PARAM_CHANNELS, -1);
                       SNDRV_PCM_HW_PARAM_CHANNELS, -1);
 
 
+One typical usage of the hw constraints is to align the buffer size
+with the period size.  As default, ALSA PCM core doesn't enforce the
+buffer size to be aligned with the period size.  For example, it'd be
+possible to have a combination like 256 period bytes with 999 buffer
+bytes.
+
+Many device chips, however, require the buffer to be a multiple of
+periods.  In such a case, call
+:c:func:`snd_pcm_hw_constraint_integer()` for
+``SNDRV_PCM_HW_PARAM_PERIODS``.
+
+::
+
+  snd_pcm_hw_constraint_integer(substream->runtime,
+                                SNDRV_PCM_HW_PARAM_PERIODS);
+
+This assures that the number of periods is integer, hence the buffer
+size is aligned with the period size.
+
+The hw constraint is a very much powerful mechanism to define the
+preferred PCM configuration, and there are relevant helpers.
 I won't give more details here, rather I would like to say, “Luke, use
 I won't give more details here, rather I would like to say, “Luke, use
 the source.”
 the source.”
 
 
@@ -3712,7 +3730,14 @@ example, for an intermediate buffer. Since the allocated pages are not
 contiguous, you need to set the ``page`` callback to obtain the physical
 contiguous, you need to set the ``page`` callback to obtain the physical
 address at every offset.
 address at every offset.
 
 
-The implementation of ``page`` callback would be like this:
+The easiest way to achieve it would be to use
+:c:func:`snd_pcm_lib_alloc_vmalloc_buffer()` for allocating the buffer
+via :c:func:`vmalloc()`, and set :c:func:`snd_pcm_sgbuf_ops_page()` to
+the ``page`` callback.  At release, you need to call
+:c:func:`snd_pcm_lib_free_vmalloc_buffer()`.
+
+If you want to implementation the ``page`` manually, it would be like
+this:
 
 
 ::
 ::
 
 
@@ -3848,7 +3873,9 @@ Power Management
 
 
 If the chip is supposed to work with suspend/resume functions, you need
 If the chip is supposed to work with suspend/resume functions, you need
 to add power-management code to the driver. The additional code for
 to add power-management code to the driver. The additional code for
-power-management should be ifdef-ed with ``CONFIG_PM``.
+power-management should be ifdef-ed with ``CONFIG_PM``, or annotated
+with __maybe_unused attribute; otherwise the compiler will complain
+you.
 
 
 If the driver *fully* supports suspend/resume that is, the device can be
 If the driver *fully* supports suspend/resume that is, the device can be
 properly resumed to its state when suspend was called, you can set the
 properly resumed to its state when suspend was called, you can set the
@@ -3879,18 +3906,16 @@ the case of PCI drivers, the callbacks look like below:
 
 
 ::
 ::
 
 
-  #ifdef CONFIG_PM
-  static int snd_my_suspend(struct pci_dev *pci, pm_message_t state)
+  static int __maybe_unused snd_my_suspend(struct device *dev)
   {
   {
           .... /* do things for suspend */
           .... /* do things for suspend */
           return 0;
           return 0;
   }
   }
-  static int snd_my_resume(struct pci_dev *pci)
+  static int __maybe_unused snd_my_resume(struct device *dev)
   {
   {
           .... /* do things for suspend */
           .... /* do things for suspend */
           return 0;
           return 0;
   }
   }
-  #endif
 
 
 The scheme of the real suspend job is as follows.
 The scheme of the real suspend job is as follows.
 
 
@@ -3909,18 +3934,14 @@ The scheme of the real suspend job is as follows.
 
 
 6. Stop the hardware if necessary.
 6. Stop the hardware if necessary.
 
 
-7. Disable the PCI device by calling
-   :c:func:`pci_disable_device()`. Then, call
-   :c:func:`pci_save_state()` at last.
-
 A typical code would be like:
 A typical code would be like:
 
 
 ::
 ::
 
 
-  static int mychip_suspend(struct pci_dev *pci, pm_message_t state)
+  static int __maybe_unused mychip_suspend(struct device *dev)
   {
   {
           /* (1) */
           /* (1) */
-          struct snd_card *card = pci_get_drvdata(pci);
+          struct snd_card *card = dev_get_drvdata(dev);
           struct mychip *chip = card->private_data;
           struct mychip *chip = card->private_data;
           /* (2) */
           /* (2) */
           snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
           snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
@@ -3932,9 +3953,6 @@ A typical code would be like:
           snd_mychip_save_registers(chip);
           snd_mychip_save_registers(chip);
           /* (6) */
           /* (6) */
           snd_mychip_stop_hardware(chip);
           snd_mychip_stop_hardware(chip);
-          /* (7) */
-          pci_disable_device(pci);
-          pci_save_state(pci);
           return 0;
           return 0;
   }
   }
 
 
@@ -3943,44 +3961,35 @@ The scheme of the real resume job is as follows.
 
 
 1. Retrieve the card and the chip data.
 1. Retrieve the card and the chip data.
 
 
-2. Set up PCI. First, call :c:func:`pci_restore_state()`. Then
-   enable the pci device again by calling
-   :c:func:`pci_enable_device()`. Call
-   :c:func:`pci_set_master()` if necessary, too.
+2. Re-initialize the chip.
 
 
-3. Re-initialize the chip.
+3. Restore the saved registers if necessary.
 
 
-4. Restore the saved registers if necessary.
+4. Resume the mixer, e.g. calling :c:func:`snd_ac97_resume()`.
 
 
-5. Resume the mixer, e.g. calling :c:func:`snd_ac97_resume()`.
+5. Restart the hardware (if any).
 
 
-6. Restart the hardware (if any).
-
-7. Call :c:func:`snd_power_change_state()` with
+6. Call :c:func:`snd_power_change_state()` with
    ``SNDRV_CTL_POWER_D0`` to notify the processes.
    ``SNDRV_CTL_POWER_D0`` to notify the processes.
 
 
 A typical code would be like:
 A typical code would be like:
 
 
 ::
 ::
 
 
-  static int mychip_resume(struct pci_dev *pci)
+  static int __maybe_unused mychip_resume(struct pci_dev *pci)
   {
   {
           /* (1) */
           /* (1) */
-          struct snd_card *card = pci_get_drvdata(pci);
+          struct snd_card *card = dev_get_drvdata(dev);
           struct mychip *chip = card->private_data;
           struct mychip *chip = card->private_data;
           /* (2) */
           /* (2) */
-          pci_restore_state(pci);
-          pci_enable_device(pci);
-          pci_set_master(pci);
-          /* (3) */
           snd_mychip_reinit_chip(chip);
           snd_mychip_reinit_chip(chip);
-          /* (4) */
+          /* (3) */
           snd_mychip_restore_registers(chip);
           snd_mychip_restore_registers(chip);
-          /* (5) */
+          /* (4) */
           snd_ac97_resume(chip->ac97);
           snd_ac97_resume(chip->ac97);
-          /* (6) */
+          /* (5) */
           snd_mychip_restart_chip(chip);
           snd_mychip_restart_chip(chip);
-          /* (7) */
+          /* (6) */
           snd_power_change_state(card, SNDRV_CTL_POWER_D0);
           snd_power_change_state(card, SNDRV_CTL_POWER_D0);
           return 0;
           return 0;
   }
   }
@@ -4046,15 +4055,14 @@ And next, set suspend/resume callbacks to the pci_driver.
 
 
 ::
 ::
 
 
+  static SIMPLE_DEV_PM_OPS(snd_my_pm_ops, mychip_suspend, mychip_resume);
+
   static struct pci_driver driver = {
   static struct pci_driver driver = {
           .name = KBUILD_MODNAME,
           .name = KBUILD_MODNAME,
           .id_table = snd_my_ids,
           .id_table = snd_my_ids,
           .probe = snd_my_probe,
           .probe = snd_my_probe,
           .remove = snd_my_remove,
           .remove = snd_my_remove,
-  #ifdef CONFIG_PM
-          .suspend = snd_my_suspend,
-          .resume = snd_my_resume,
-  #endif
+          .driver.pm = &snd_my_pm_ops,
   };
   };
 
 
 Module Parameters
 Module Parameters
@@ -4078,7 +4086,7 @@ variables, instead. ``enable`` option is not always necessary in this
 case, but it would be better to have a dummy option for compatibility.
 case, but it would be better to have a dummy option for compatibility.
 
 
 The module parameters must be declared with the standard
 The module parameters must be declared with the standard
-``module_param()()``, ``module_param_array()()`` and
+``module_param()``, ``module_param_array()`` and
 :c:func:`MODULE_PARM_DESC()` macros.
 :c:func:`MODULE_PARM_DESC()` macros.
 
 
 The typical coding would be like below:
 The typical coding would be like below:
@@ -4094,15 +4102,14 @@ The typical coding would be like below:
   module_param_array(enable, bool, NULL, 0444);
   module_param_array(enable, bool, NULL, 0444);
   MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
   MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
 
 
-Also, don't forget to define the module description, classes, license
-and devices. Especially, the recent modprobe requires to define the
+Also, don't forget to define the module description and the license.
+Especially, the recent modprobe requires to define the
 module license as GPL, etc., otherwise the system is shown as “tainted”.
 module license as GPL, etc., otherwise the system is shown as “tainted”.
 
 
 ::
 ::
 
 
-  MODULE_DESCRIPTION("My Chip");
+  MODULE_DESCRIPTION("Sound driver for My Chip");
   MODULE_LICENSE("GPL");
   MODULE_LICENSE("GPL");
-  MODULE_SUPPORTED_DEVICE("{{Vendor,My Chip Name}}");
 
 
 
 
 How To Put Your Driver Into ALSA Tree
 How To Put Your Driver Into ALSA Tree
@@ -4117,21 +4124,17 @@ a question now: how to put my own driver into the ALSA driver tree? Here
 
 
 Suppose that you create a new PCI driver for the card “xyz”. The card
 Suppose that you create a new PCI driver for the card “xyz”. The card
 module name would be snd-xyz. The new driver is usually put into the
 module name would be snd-xyz. The new driver is usually put into the
-alsa-driver tree, ``alsa-driver/pci`` directory in the case of PCI
-cards. Then the driver is evaluated, audited and tested by developers
-and users. After a certain time, the driver will go to the alsa-kernel
-tree (to the corresponding directory, such as ``alsa-kernel/pci``) and
-eventually will be integrated into the Linux 2.6 tree (the directory
-would be ``linux/sound/pci``).
+alsa-driver tree, ``sound/pci`` directory in the case of PCI
+cards.
 
 
 In the following sections, the driver code is supposed to be put into
 In the following sections, the driver code is supposed to be put into
-alsa-driver tree. The two cases are covered: a driver consisting of a
+Linux kernel tree. The two cases are covered: a driver consisting of a
 single source file and one consisting of several source files.
 single source file and one consisting of several source files.
 
 
 Driver with A Single Source File
 Driver with A Single Source File
 --------------------------------
 --------------------------------
 
 
-1. Modify alsa-driver/pci/Makefile
+1. Modify sound/pci/Makefile
 
 
    Suppose you have a file xyz.c. Add the following two lines
    Suppose you have a file xyz.c. Add the following two lines
 
 
@@ -4160,52 +4163,43 @@ Driver with A Single Source File
 
 
    For the details of Kconfig script, refer to the kbuild documentation.
    For the details of Kconfig script, refer to the kbuild documentation.
 
 
-3. Run cvscompile script to re-generate the configure script and build
-   the whole stuff again.
-
 Drivers with Several Source Files
 Drivers with Several Source Files
 ---------------------------------
 ---------------------------------
 
 
 Suppose that the driver snd-xyz have several source files. They are
 Suppose that the driver snd-xyz have several source files. They are
-located in the new subdirectory, pci/xyz.
+located in the new subdirectory, sound/pci/xyz.
 
 
-1. Add a new directory (``xyz``) in ``alsa-driver/pci/Makefile`` as
-   below
+1. Add a new directory (``sound/pci/xyz``) in ``sound/pci/Makefile``
+   as below
 
 
 ::
 ::
 
 
-  obj-$(CONFIG_SND) += xyz/
+  obj-$(CONFIG_SND) += sound/pci/xyz/
 
 
 
 
-2. Under the directory ``xyz``, create a Makefile
+2. Under the directory ``sound/pci/xyz``, create a Makefile
 
 
 ::
 ::
 
 
-         ifndef SND_TOPDIR
-         SND_TOPDIR=../..
-         endif
-
-         include $(SND_TOPDIR)/toplevel.config
-         include $(SND_TOPDIR)/Makefile.conf
-
          snd-xyz-objs := xyz.o abc.o def.o
          snd-xyz-objs := xyz.o abc.o def.o
-
          obj-$(CONFIG_SND_XYZ) += snd-xyz.o
          obj-$(CONFIG_SND_XYZ) += snd-xyz.o
 
 
-         include $(SND_TOPDIR)/Rules.make
-
 3. Create the Kconfig entry
 3. Create the Kconfig entry
 
 
    This procedure is as same as in the last section.
    This procedure is as same as in the last section.
 
 
-4. Run cvscompile script to re-generate the configure script and build
-   the whole stuff again.
 
 
 Useful Functions
 Useful Functions
 ================
 ================
 
 
 :c:func:`snd_printk()` and friends
 :c:func:`snd_printk()` and friends
----------------------------------------
+----------------------------------
+
+.. note:: This subsection describes a few helper functions for
+   decorating a bit more on the standard :c:func:`printk()` & co.
+   However, in general, the use of such helpers is no longer recommended.
+   If possible, try to stick with the standard functions like
+   :c:func:`dev_err()` or :c:func:`pr_err()`.
 
 
 ALSA provides a verbose version of the :c:func:`printk()` function.
 ALSA provides a verbose version of the :c:func:`printk()` function.
 If a kernel config ``CONFIG_SND_VERBOSE_PRINTK`` is set, this function
 If a kernel config ``CONFIG_SND_VERBOSE_PRINTK`` is set, this function
@@ -4221,13 +4215,10 @@ just like :c:func:`snd_printk()`. If the ALSA is compiled without
 the debugging flag, it's ignored.
 the debugging flag, it's ignored.
 
 
 :c:func:`snd_printdd()` is compiled in only when
 :c:func:`snd_printdd()` is compiled in only when
-``CONFIG_SND_DEBUG_VERBOSE`` is set. Please note that
-``CONFIG_SND_DEBUG_VERBOSE`` is not set as default even if you configure
-the alsa-driver with ``--with-debug=full`` option. You need to give
-explicitly ``--with-debug=detect`` option instead.
+``CONFIG_SND_DEBUG_VERBOSE`` is set.
 
 
 :c:func:`snd_BUG()`
 :c:func:`snd_BUG()`
-------------------------
+-------------------
 
 
 It shows the ``BUG?`` message and stack trace as well as
 It shows the ``BUG?`` message and stack trace as well as
 :c:func:`snd_BUG_ON()` at the point. It's useful to show that a
 :c:func:`snd_BUG_ON()` at the point. It's useful to show that a
@@ -4236,7 +4227,7 @@ fatal error happens there.
 When no debug flag is set, this macro is ignored.
 When no debug flag is set, this macro is ignored.
 
 
 :c:func:`snd_BUG_ON()`
 :c:func:`snd_BUG_ON()`
-----------------------------
+----------------------
 
 
 :c:func:`snd_BUG_ON()` macro is similar with
 :c:func:`snd_BUG_ON()` macro is similar with
 :c:func:`WARN_ON()` macro. For example, snd_BUG_ON(!pointer); or
 :c:func:`WARN_ON()` macro. For example, snd_BUG_ON(!pointer); or

+ 7 - 0
MAINTAINERS

@@ -14759,6 +14759,13 @@ L:	netdev@vger.kernel.org
 S:	Maintained
 S:	Maintained
 F:	drivers/net/ethernet/ti/netcp*
 F:	drivers/net/ethernet/ti/netcp*
 
 
+TI PCM3060 ASoC CODEC DRIVER
+M:	Kirill Marinushkin <kmarinushkin@birdec.tech>
+L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
+S:	Maintained
+F:	Documentation/devicetree/bindings/sound/pcm3060.txt
+F:	sound/soc/codecs/pcm3060*
+
 TI TAS571X FAMILY ASoC CODEC DRIVER
 TI TAS571X FAMILY ASoC CODEC DRIVER
 M:	Kevin Cernekee <cernekee@chromium.org>
 M:	Kevin Cernekee <cernekee@chromium.org>
 L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
 L:	alsa-devel@alsa-project.org (moderated for non-subscribers)

+ 0 - 0
sound/pci/hda/hda_codec.h → include/sound/hda_codec.h


+ 3 - 0
include/sound/memalloc.h

@@ -47,10 +47,13 @@ struct snd_dma_device {
 #define SNDRV_DMA_TYPE_UNKNOWN		0	/* not defined */
 #define SNDRV_DMA_TYPE_UNKNOWN		0	/* not defined */
 #define SNDRV_DMA_TYPE_CONTINUOUS	1	/* continuous no-DMA memory */
 #define SNDRV_DMA_TYPE_CONTINUOUS	1	/* continuous no-DMA memory */
 #define SNDRV_DMA_TYPE_DEV		2	/* generic device continuous */
 #define SNDRV_DMA_TYPE_DEV		2	/* generic device continuous */
+#define SNDRV_DMA_TYPE_DEV_UC		5	/* continuous non-cahced */
 #ifdef CONFIG_SND_DMA_SGBUF
 #ifdef CONFIG_SND_DMA_SGBUF
 #define SNDRV_DMA_TYPE_DEV_SG		3	/* generic device SG-buffer */
 #define SNDRV_DMA_TYPE_DEV_SG		3	/* generic device SG-buffer */
+#define SNDRV_DMA_TYPE_DEV_UC_SG	6	/* SG non-cached */
 #else
 #else
 #define SNDRV_DMA_TYPE_DEV_SG	SNDRV_DMA_TYPE_DEV /* no SG-buf support */
 #define SNDRV_DMA_TYPE_DEV_SG	SNDRV_DMA_TYPE_DEV /* no SG-buf support */
+#define SNDRV_DMA_TYPE_DEV_UC_SG	SNDRV_DMA_TYPE_DEV_UC
 #endif
 #endif
 #ifdef CONFIG_GENERIC_ALLOCATOR
 #ifdef CONFIG_GENERIC_ALLOCATOR
 #define SNDRV_DMA_TYPE_DEV_IRAM		4	/* generic device iram-buffer */
 #define SNDRV_DMA_TYPE_DEV_IRAM		4	/* generic device iram-buffer */

+ 1 - 0
include/sound/rawmidi.h

@@ -171,6 +171,7 @@ int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream,
 			      unsigned char *buffer, int count);
 			      unsigned char *buffer, int count);
 int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream,
 int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream,
 			       int count);
 			       int count);
+int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream);
 
 
 /* main midi functions */
 /* main midi functions */
 
 

+ 18 - 9
include/sound/simple_card_utils.h

@@ -51,29 +51,35 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
 
 
 #define asoc_simple_card_parse_clk_cpu(dev, node, dai_link, simple_dai)		\
 #define asoc_simple_card_parse_clk_cpu(dev, node, dai_link, simple_dai)		\
 	asoc_simple_card_parse_clk(dev, node, dai_link->cpu_of_node, simple_dai, \
 	asoc_simple_card_parse_clk(dev, node, dai_link->cpu_of_node, simple_dai, \
-				   dai_link->cpu_dai_name)
+				   dai_link->cpu_dai_name, NULL)
 #define asoc_simple_card_parse_clk_codec(dev, node, dai_link, simple_dai)	\
 #define asoc_simple_card_parse_clk_codec(dev, node, dai_link, simple_dai)	\
 	asoc_simple_card_parse_clk(dev, node, dai_link->codec_of_node, simple_dai,\
 	asoc_simple_card_parse_clk(dev, node, dai_link->codec_of_node, simple_dai,\
-				   dai_link->codec_dai_name)
+				   dai_link->codec_dai_name, dai_link->codecs)
 int asoc_simple_card_parse_clk(struct device *dev,
 int asoc_simple_card_parse_clk(struct device *dev,
 			       struct device_node *node,
 			       struct device_node *node,
 			       struct device_node *dai_of_node,
 			       struct device_node *dai_of_node,
 			       struct asoc_simple_dai *simple_dai,
 			       struct asoc_simple_dai *simple_dai,
-			       const char *name);
+			       const char *dai_name,
+			       struct snd_soc_dai_link_component *dlc);
 int asoc_simple_card_clk_enable(struct asoc_simple_dai *dai);
 int asoc_simple_card_clk_enable(struct asoc_simple_dai *dai);
 void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai);
 void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai);
 
 
 #define asoc_simple_card_parse_cpu(node, dai_link,				\
 #define asoc_simple_card_parse_cpu(node, dai_link,				\
 				   list_name, cells_name, is_single_link)	\
 				   list_name, cells_name, is_single_link)	\
-	asoc_simple_card_parse_dai(node, &dai_link->cpu_of_node,		\
+	asoc_simple_card_parse_dai(node, NULL,					\
+		&dai_link->cpu_of_node,						\
 		&dai_link->cpu_dai_name, list_name, cells_name, is_single_link)
 		&dai_link->cpu_dai_name, list_name, cells_name, is_single_link)
 #define asoc_simple_card_parse_codec(node, dai_link, list_name, cells_name)	\
 #define asoc_simple_card_parse_codec(node, dai_link, list_name, cells_name)	\
-	asoc_simple_card_parse_dai(node, &dai_link->codec_of_node,		\
-		&dai_link->codec_dai_name, list_name, cells_name, NULL)
+	asoc_simple_card_parse_dai(node, dai_link->codecs,			\
+				   &dai_link->codec_of_node,			\
+				   &dai_link->codec_dai_name,			\
+				   list_name, cells_name, NULL)
 #define asoc_simple_card_parse_platform(node, dai_link, list_name, cells_name)	\
 #define asoc_simple_card_parse_platform(node, dai_link, list_name, cells_name)	\
-	asoc_simple_card_parse_dai(node, &dai_link->platform_of_node,		\
+	asoc_simple_card_parse_dai(node, dai_link->platform,					\
+		&dai_link->platform_of_node,					\
 		NULL, list_name, cells_name, NULL)
 		NULL, list_name, cells_name, NULL)
 int asoc_simple_card_parse_dai(struct device_node *node,
 int asoc_simple_card_parse_dai(struct device_node *node,
+				  struct snd_soc_dai_link_component *dlc,
 				  struct device_node **endpoint_np,
 				  struct device_node **endpoint_np,
 				  const char **dai_name,
 				  const char **dai_name,
 				  const char *list_name,
 				  const char *list_name,
@@ -81,12 +87,15 @@ int asoc_simple_card_parse_dai(struct device_node *node,
 				  int *is_single_links);
 				  int *is_single_links);
 
 
 #define asoc_simple_card_parse_graph_cpu(ep, dai_link)			\
 #define asoc_simple_card_parse_graph_cpu(ep, dai_link)			\
-	asoc_simple_card_parse_graph_dai(ep, &dai_link->cpu_of_node,	\
+	asoc_simple_card_parse_graph_dai(ep, NULL,			\
+					 &dai_link->cpu_of_node,	\
 					 &dai_link->cpu_dai_name)
 					 &dai_link->cpu_dai_name)
 #define asoc_simple_card_parse_graph_codec(ep, dai_link)		\
 #define asoc_simple_card_parse_graph_codec(ep, dai_link)		\
-	asoc_simple_card_parse_graph_dai(ep, &dai_link->codec_of_node,	\
+	asoc_simple_card_parse_graph_dai(ep, dai_link->codecs,		\
+					 &dai_link->codec_of_node,	\
 					 &dai_link->codec_dai_name)
 					 &dai_link->codec_dai_name)
 int asoc_simple_card_parse_graph_dai(struct device_node *ep,
 int asoc_simple_card_parse_graph_dai(struct device_node *ep,
+				     struct snd_soc_dai_link_component *dlc,
 				     struct device_node **endpoint_np,
 				     struct device_node **endpoint_np,
 				     const char **dai_name);
 				     const char **dai_name);
 
 

+ 6 - 0
include/sound/soc-acpi-intel-match.h

@@ -25,4 +25,10 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_bxt_machines[];
 extern struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[];
 extern struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[];
 extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[];
 extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[];
 
 
+/*
+ * generic table used for HDA codec-based platforms, possibly with
+ * additional ACPI-enumerated codecs
+ */
+extern struct snd_soc_acpi_mach snd_soc_acpi_intel_hda_machines[];
+
 #endif
 #endif

+ 0 - 9
include/sound/soc-dapm.h

@@ -406,12 +406,6 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
 				 struct snd_soc_dai *dai);
 				 struct snd_soc_dai *dai);
 int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card);
 int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card);
 void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card);
 void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card);
-int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
-			 struct snd_soc_pcm_runtime *rtd,
-			 const struct snd_soc_pcm_stream *params,
-			 unsigned int num_params,
-			 struct snd_soc_dapm_widget *source,
-			 struct snd_soc_dapm_widget *sink);
 
 
 /* dapm path setup */
 /* dapm path setup */
 int snd_soc_dapm_new_widgets(struct snd_soc_card *card);
 int snd_soc_dapm_new_widgets(struct snd_soc_card *card);
@@ -590,9 +584,6 @@ struct snd_soc_dapm_widget {
 	void *priv;				/* widget specific data */
 	void *priv;				/* widget specific data */
 	struct regulator *regulator;		/* attached regulator */
 	struct regulator *regulator;		/* attached regulator */
 	struct pinctrl *pinctrl;		/* attached pinctrl */
 	struct pinctrl *pinctrl;		/* attached pinctrl */
-	const struct snd_soc_pcm_stream *params; /* params for dai links */
-	unsigned int num_params; /* number of params for dai links */
-	unsigned int params_select; /* currently selected param for dai link */
 
 
 	/* dapm control */
 	/* dapm control */
 	int reg;				/* negative reg = no direct dapm */
 	int reg;				/* negative reg = no direct dapm */

+ 10 - 0
include/sound/soc-dpcm.h

@@ -103,6 +103,16 @@ struct snd_soc_dpcm_runtime {
 	int trigger_pending; /* trigger cmd + 1 if pending, 0 if not */
 	int trigger_pending; /* trigger cmd + 1 if pending, 0 if not */
 };
 };
 
 
+#define for_each_dpcm_fe(be, stream, dpcm)				\
+	list_for_each_entry(dpcm, &(be)->dpcm[stream].fe_clients, list_fe)
+
+#define for_each_dpcm_be(fe, stream, dpcm)				\
+	list_for_each_entry(dpcm, &(fe)->dpcm[stream].be_clients, list_be)
+#define for_each_dpcm_be_safe(fe, stream, dpcm, _dpcm)			\
+	list_for_each_entry_safe(dpcm, _dpcm, &(fe)->dpcm[stream].be_clients, list_be)
+#define for_each_dpcm_be_rollback(fe, stream, dpcm)			\
+	list_for_each_entry_continue_reverse(dpcm, &(fe)->dpcm[stream].be_clients, list_be)
+
 /* can this BE stop and free */
 /* can this BE stop and free */
 int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
 int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
 		struct snd_soc_pcm_runtime *be, int stream);
 		struct snd_soc_pcm_runtime *be, int stream);

+ 44 - 1
include/sound/soc.h

@@ -372,6 +372,11 @@
 #define SND_SOC_COMP_ORDER_LATE		1
 #define SND_SOC_COMP_ORDER_LATE		1
 #define SND_SOC_COMP_ORDER_LAST		2
 #define SND_SOC_COMP_ORDER_LAST		2
 
 
+#define for_each_comp_order(order)		\
+	for (order  = SND_SOC_COMP_ORDER_FIRST;	\
+	     order <= SND_SOC_COMP_ORDER_LAST;	\
+	     order++)
+
 /*
 /*
  * Bias levels
  * Bias levels
  *
  *
@@ -859,6 +864,11 @@ struct snd_soc_component {
 #endif
 #endif
 };
 };
 
 
+#define for_each_component_dais(component, dai)\
+	list_for_each_entry(dai, &(component)->dai_list, list)
+#define for_each_component_dais_safe(component, dai, _dai)\
+	list_for_each_entry_safe(dai, _dai, &(component)->dai_list, list)
+
 struct snd_soc_rtdcom_list {
 struct snd_soc_rtdcom_list {
 	struct snd_soc_component *component;
 	struct snd_soc_component *component;
 	struct list_head list; /* rtd::component_list */
 	struct list_head list; /* rtd::component_list */
@@ -915,6 +925,8 @@ struct snd_soc_dai_link {
 	 */
 	 */
 	const char *platform_name;
 	const char *platform_name;
 	struct device_node *platform_of_node;
 	struct device_node *platform_of_node;
+	struct snd_soc_dai_link_component *platform;
+
 	int id;	/* optional ID for machine driver link identification */
 	int id;	/* optional ID for machine driver link identification */
 
 
 	const struct snd_soc_pcm_stream *params;
 	const struct snd_soc_pcm_stream *params;
@@ -976,6 +988,10 @@ struct snd_soc_dai_link {
 	struct list_head list; /* DAI link list of the soc card */
 	struct list_head list; /* DAI link list of the soc card */
 	struct snd_soc_dobj dobj; /* For topology */
 	struct snd_soc_dobj dobj; /* For topology */
 };
 };
+#define for_each_link_codecs(link, i, codec)				\
+	for ((i) = 0;							\
+	     ((i) < link->num_codecs) && ((codec) = &link->codecs[i]);	\
+	     (i)++)
 
 
 struct snd_soc_codec_conf {
 struct snd_soc_codec_conf {
 	/*
 	/*
@@ -1054,7 +1070,6 @@ struct snd_soc_card {
 	struct snd_soc_dai_link *dai_link;  /* predefined links only */
 	struct snd_soc_dai_link *dai_link;  /* predefined links only */
 	int num_links;  /* predefined links only */
 	int num_links;  /* predefined links only */
 	struct list_head dai_link_list; /* all links */
 	struct list_head dai_link_list; /* all links */
-	int num_dai_links;
 
 
 	struct list_head rtd_list;
 	struct list_head rtd_list;
 	int num_rtd;
 	int num_rtd;
@@ -1092,6 +1107,7 @@ struct snd_soc_card {
 
 
 	/* lists of probed devices belonging to this card */
 	/* lists of probed devices belonging to this card */
 	struct list_head component_dev_list;
 	struct list_head component_dev_list;
+	struct list_head list;
 
 
 	struct list_head widgets;
 	struct list_head widgets;
 	struct list_head paths;
 	struct list_head paths;
@@ -1114,6 +1130,23 @@ struct snd_soc_card {
 
 
 	void *drvdata;
 	void *drvdata;
 };
 };
+#define for_each_card_prelinks(card, i, link)				\
+	for ((i) = 0;							\
+	     ((i) < (card)->num_links) && ((link) = &(card)->dai_link[i]); \
+	     (i)++)
+
+#define for_each_card_links(card, link)				\
+	list_for_each_entry(dai_link, &(card)->dai_link_list, list)
+#define for_each_card_links_safe(card, link, _link)			\
+	list_for_each_entry_safe(link, _link, &(card)->dai_link_list, list)
+
+#define for_each_card_rtds(card, rtd)			\
+	list_for_each_entry(rtd, &(card)->rtd_list, list)
+#define for_each_card_rtds_safe(card, rtd, _rtd)	\
+	list_for_each_entry_safe(rtd, _rtd, &(card)->rtd_list, list)
+
+#define for_each_card_components(card, component)			\
+	list_for_each_entry(component, &(card)->component_dev_list, card_list)
 
 
 /* SoC machine DAI configuration, glues a codec and cpu DAI together */
 /* SoC machine DAI configuration, glues a codec and cpu DAI together */
 struct snd_soc_pcm_runtime {
 struct snd_soc_pcm_runtime {
@@ -1124,6 +1157,8 @@ struct snd_soc_pcm_runtime {
 	enum snd_soc_pcm_subclass pcm_subclass;
 	enum snd_soc_pcm_subclass pcm_subclass;
 	struct snd_pcm_ops ops;
 	struct snd_pcm_ops ops;
 
 
+	unsigned int params_select; /* currently selected param for dai link */
+
 	/* Dynamic PCM BE runtime data */
 	/* Dynamic PCM BE runtime data */
 	struct snd_soc_dpcm_runtime dpcm[2];
 	struct snd_soc_dpcm_runtime dpcm[2];
 	int fe_compr;
 	int fe_compr;
@@ -1152,6 +1187,13 @@ struct snd_soc_pcm_runtime {
 	unsigned int dev_registered:1;
 	unsigned int dev_registered:1;
 	unsigned int pop_wait:1;
 	unsigned int pop_wait:1;
 };
 };
+#define for_each_rtd_codec_dai(rtd, i, dai)\
+	for ((i) = 0;						       \
+	     ((i) < rtd->num_codecs) && ((dai) = rtd->codec_dais[i]); \
+	     (i)++)
+#define for_each_rtd_codec_dai_rollback(rtd, i, dai)		\
+	for (; ((i--) >= 0) && ((dai) = rtd->codec_dais[i]);)
+
 
 
 /* mixer control */
 /* mixer control */
 struct soc_mixer_control {
 struct soc_mixer_control {
@@ -1359,6 +1401,7 @@ static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card)
 	INIT_LIST_HEAD(&card->dapm_list);
 	INIT_LIST_HEAD(&card->dapm_list);
 	INIT_LIST_HEAD(&card->aux_comp_list);
 	INIT_LIST_HEAD(&card->aux_comp_list);
 	INIT_LIST_HEAD(&card->component_dev_list);
 	INIT_LIST_HEAD(&card->component_dev_list);
+	INIT_LIST_HEAD(&card->list);
 }
 }
 
 
 static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc)
 static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc)

+ 1 - 1
include/uapi/sound/asound.h

@@ -752,7 +752,7 @@ struct snd_timer_info {
 #define SNDRV_TIMER_PSFLG_EARLY_EVENT	(1<<2)	/* write early event to the poll queue */
 #define SNDRV_TIMER_PSFLG_EARLY_EVENT	(1<<2)	/* write early event to the poll queue */
 
 
 struct snd_timer_params {
 struct snd_timer_params {
-	unsigned int flags;		/* flags - SNDRV_MIXER_PSFLG_* */
+	unsigned int flags;		/* flags - SNDRV_TIMER_PSFLG_* */
 	unsigned int ticks;		/* requested resolution in ticks */
 	unsigned int ticks;		/* requested resolution in ticks */
 	unsigned int queue_size;	/* total size of queue (32-1024) */
 	unsigned int queue_size;	/* total size of queue (32-1024) */
 	unsigned int reserved0;		/* reserved, was: failure locations */
 	unsigned int reserved0;		/* reserved, was: failure locations */

+ 8 - 7
sound/aoa/soundbus/i2sbus/core.c

@@ -157,18 +157,19 @@ static int i2sbus_add_dev(struct macio_dev *macio,
 	struct device_node *child = NULL, *sound = NULL;
 	struct device_node *child = NULL, *sound = NULL;
 	struct resource *r;
 	struct resource *r;
 	int i, layout = 0, rlen, ok = force;
 	int i, layout = 0, rlen, ok = force;
-	static const char *rnames[] = { "i2sbus: %s (control)",
-					"i2sbus: %s (tx)",
-					"i2sbus: %s (rx)" };
+	char node_name[6];
+	static const char *rnames[] = { "i2sbus: %pOFn (control)",
+					"i2sbus: %pOFn (tx)",
+					"i2sbus: %pOFn (rx)" };
 	static irq_handler_t ints[] = {
 	static irq_handler_t ints[] = {
 		i2sbus_bus_intr,
 		i2sbus_bus_intr,
 		i2sbus_tx_intr,
 		i2sbus_tx_intr,
 		i2sbus_rx_intr
 		i2sbus_rx_intr
 	};
 	};
 
 
-	if (strlen(np->name) != 5)
+	if (snprintf(node_name, sizeof(node_name), "%pOFn", np) != 5)
 		return 0;
 		return 0;
-	if (strncmp(np->name, "i2s-", 4))
+	if (strncmp(node_name, "i2s-", 4))
 		return 0;
 		return 0;
 
 
 	dev = kzalloc(sizeof(struct i2sbus_dev), GFP_KERNEL);
 	dev = kzalloc(sizeof(struct i2sbus_dev), GFP_KERNEL);
@@ -228,13 +229,13 @@ static int i2sbus_add_dev(struct macio_dev *macio,
 	dev->sound.pcmid = -1;
 	dev->sound.pcmid = -1;
 	dev->macio = macio;
 	dev->macio = macio;
 	dev->control = control;
 	dev->control = control;
-	dev->bus_number = np->name[4] - 'a';
+	dev->bus_number = node_name[4] - 'a';
 	INIT_LIST_HEAD(&dev->sound.codec_list);
 	INIT_LIST_HEAD(&dev->sound.codec_list);
 
 
 	for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) {
 	for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) {
 		dev->interrupts[i] = -1;
 		dev->interrupts[i] = -1;
 		snprintf(dev->rnames[i], sizeof(dev->rnames[i]),
 		snprintf(dev->rnames[i], sizeof(dev->rnames[i]),
-			 rnames[i], np->name);
+			 rnames[i], np);
 	}
 	}
 	for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) {
 	for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++) {
 		int irq = irq_of_parse_and_map(np, i);
 		int irq = irq_of_parse_and_map(np, i);

+ 0 - 1
sound/arm/Kconfig

@@ -31,7 +31,6 @@ endif	# SND_ARM
 
 
 config SND_PXA2XX_LIB
 config SND_PXA2XX_LIB
 	tristate
 	tristate
-	select SND_AC97_CODEC if SND_PXA2XX_LIB_AC97
 	select SND_DMAENGINE_PCM
 	select SND_DMAENGINE_PCM
 
 
 config SND_PXA2XX_LIB_AC97
 config SND_PXA2XX_LIB_AC97

+ 25 - 16
sound/core/memalloc.c

@@ -25,6 +25,9 @@
 #include <linux/mm.h>
 #include <linux/mm.h>
 #include <linux/dma-mapping.h>
 #include <linux/dma-mapping.h>
 #include <linux/genalloc.h>
 #include <linux/genalloc.h>
+#ifdef CONFIG_X86
+#include <asm/set_memory.h>
+#endif
 #include <sound/memalloc.h>
 #include <sound/memalloc.h>
 
 
 /*
 /*
@@ -82,31 +85,32 @@ EXPORT_SYMBOL(snd_free_pages);
 
 
 #ifdef CONFIG_HAS_DMA
 #ifdef CONFIG_HAS_DMA
 /* allocate the coherent DMA pages */
 /* allocate the coherent DMA pages */
-static void *snd_malloc_dev_pages(struct device *dev, size_t size, dma_addr_t *dma)
+static void snd_malloc_dev_pages(struct snd_dma_buffer *dmab, size_t size)
 {
 {
-	int pg;
 	gfp_t gfp_flags;
 	gfp_t gfp_flags;
 
 
-	if (WARN_ON(!dma))
-		return NULL;
-	pg = get_order(size);
 	gfp_flags = GFP_KERNEL
 	gfp_flags = GFP_KERNEL
 		| __GFP_COMP	/* compound page lets parts be mapped */
 		| __GFP_COMP	/* compound page lets parts be mapped */
 		| __GFP_NORETRY /* don't trigger OOM-killer */
 		| __GFP_NORETRY /* don't trigger OOM-killer */
 		| __GFP_NOWARN; /* no stack trace print - this call is non-critical */
 		| __GFP_NOWARN; /* no stack trace print - this call is non-critical */
-	return dma_alloc_coherent(dev, PAGE_SIZE << pg, dma, gfp_flags);
+	dmab->area = dma_alloc_coherent(dmab->dev.dev, size, &dmab->addr,
+					gfp_flags);
+#ifdef CONFIG_X86
+	if (dmab->area && dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC)
+		set_memory_wc((unsigned long)dmab->area,
+			      PAGE_ALIGN(size) >> PAGE_SHIFT);
+#endif
 }
 }
 
 
 /* free the coherent DMA pages */
 /* free the coherent DMA pages */
-static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr,
-			       dma_addr_t dma)
+static void snd_free_dev_pages(struct snd_dma_buffer *dmab)
 {
 {
-	int pg;
-
-	if (ptr == NULL)
-		return;
-	pg = get_order(size);
-	dma_free_coherent(dev, PAGE_SIZE << pg, ptr, dma);
+#ifdef CONFIG_X86
+	if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC)
+		set_memory_wb((unsigned long)dmab->area,
+			      PAGE_ALIGN(dmab->bytes) >> PAGE_SHIFT);
+#endif
+	dma_free_coherent(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr);
 }
 }
 
 
 #ifdef CONFIG_GENERIC_ALLOCATOR
 #ifdef CONFIG_GENERIC_ALLOCATOR
@@ -199,12 +203,15 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,
 		 */
 		 */
 		dmab->dev.type = SNDRV_DMA_TYPE_DEV;
 		dmab->dev.type = SNDRV_DMA_TYPE_DEV;
 #endif /* CONFIG_GENERIC_ALLOCATOR */
 #endif /* CONFIG_GENERIC_ALLOCATOR */
+		/* fall through */
 	case SNDRV_DMA_TYPE_DEV:
 	case SNDRV_DMA_TYPE_DEV:
-		dmab->area = snd_malloc_dev_pages(device, size, &dmab->addr);
+	case SNDRV_DMA_TYPE_DEV_UC:
+		snd_malloc_dev_pages(dmab, size);
 		break;
 		break;
 #endif
 #endif
 #ifdef CONFIG_SND_DMA_SGBUF
 #ifdef CONFIG_SND_DMA_SGBUF
 	case SNDRV_DMA_TYPE_DEV_SG:
 	case SNDRV_DMA_TYPE_DEV_SG:
+	case SNDRV_DMA_TYPE_DEV_UC_SG:
 		snd_malloc_sgbuf_pages(device, size, dmab, NULL);
 		snd_malloc_sgbuf_pages(device, size, dmab, NULL);
 		break;
 		break;
 #endif
 #endif
@@ -275,11 +282,13 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab)
 		break;
 		break;
 #endif /* CONFIG_GENERIC_ALLOCATOR */
 #endif /* CONFIG_GENERIC_ALLOCATOR */
 	case SNDRV_DMA_TYPE_DEV:
 	case SNDRV_DMA_TYPE_DEV:
-		snd_free_dev_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr);
+	case SNDRV_DMA_TYPE_DEV_UC:
+		snd_free_dev_pages(dmab);
 		break;
 		break;
 #endif
 #endif
 #ifdef CONFIG_SND_DMA_SGBUF
 #ifdef CONFIG_SND_DMA_SGBUF
 	case SNDRV_DMA_TYPE_DEV_SG:
 	case SNDRV_DMA_TYPE_DEV_SG:
+	case SNDRV_DMA_TYPE_DEV_UC_SG:
 		snd_free_sgbuf_pages(dmab);
 		snd_free_sgbuf_pages(dmab);
 		break;
 		break;
 #endif
 #endif

+ 2 - 2
sound/core/oss/pcm_plugin.c

@@ -111,7 +111,7 @@ int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames)
 		while (plugin->next) {
 		while (plugin->next) {
 			if (plugin->dst_frames)
 			if (plugin->dst_frames)
 				frames = plugin->dst_frames(plugin, frames);
 				frames = plugin->dst_frames(plugin, frames);
-			if (snd_BUG_ON(frames <= 0))
+			if (snd_BUG_ON((snd_pcm_sframes_t)frames <= 0))
 				return -ENXIO;
 				return -ENXIO;
 			plugin = plugin->next;
 			plugin = plugin->next;
 			err = snd_pcm_plugin_alloc(plugin, frames);
 			err = snd_pcm_plugin_alloc(plugin, frames);
@@ -123,7 +123,7 @@ int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames)
 		while (plugin->prev) {
 		while (plugin->prev) {
 			if (plugin->src_frames)
 			if (plugin->src_frames)
 				frames = plugin->src_frames(plugin, frames);
 				frames = plugin->src_frames(plugin, frames);
-			if (snd_BUG_ON(frames <= 0))
+			if (snd_BUG_ON((snd_pcm_sframes_t)frames <= 0))
 				return -ENXIO;
 				return -ENXIO;
 			plugin = plugin->prev;
 			plugin = plugin->prev;
 			err = snd_pcm_plugin_alloc(plugin, frames);
 			err = snd_pcm_plugin_alloc(plugin, frames);

+ 14 - 7
sound/core/pcm_lib.c

@@ -2172,18 +2172,25 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream,
 	if (err < 0)
 	if (err < 0)
 		goto _end_unlock;
 		goto _end_unlock;
 
 
+	runtime->twake = runtime->control->avail_min ? : 1;
+	if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
+		snd_pcm_update_hw_ptr(substream);
+
 	if (!is_playback &&
 	if (!is_playback &&
-	    runtime->status->state == SNDRV_PCM_STATE_PREPARED &&
-	    size >= runtime->start_threshold) {
-		err = snd_pcm_start(substream);
-		if (err < 0)
+	    runtime->status->state == SNDRV_PCM_STATE_PREPARED) {
+		if (size >= runtime->start_threshold) {
+			err = snd_pcm_start(substream);
+			if (err < 0)
+				goto _end_unlock;
+		} else {
+			/* nothing to do */
+			err = 0;
 			goto _end_unlock;
 			goto _end_unlock;
+		}
 	}
 	}
 
 
-	runtime->twake = runtime->control->avail_min ? : 1;
-	if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
-		snd_pcm_update_hw_ptr(substream);
 	avail = snd_pcm_avail(substream);
 	avail = snd_pcm_avail(substream);
+
 	while (size > 0) {
 	while (size > 0) {
 		snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
 		snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
 		snd_pcm_uframes_t cont;
 		snd_pcm_uframes_t cont;

+ 22 - 0
sound/core/rawmidi.c

@@ -1236,6 +1236,28 @@ int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream,
 }
 }
 EXPORT_SYMBOL(snd_rawmidi_transmit);
 EXPORT_SYMBOL(snd_rawmidi_transmit);
 
 
+/**
+ * snd_rawmidi_proceed - Discard the all pending bytes and proceed
+ * @substream: rawmidi substream
+ *
+ * Return: the number of discarded bytes
+ */
+int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream)
+{
+	struct snd_rawmidi_runtime *runtime = substream->runtime;
+	unsigned long flags;
+	int count = 0;
+
+	spin_lock_irqsave(&runtime->lock, flags);
+	if (runtime->avail < runtime->buffer_size) {
+		count = runtime->buffer_size - runtime->avail;
+		__snd_rawmidi_transmit_ack(substream, count);
+	}
+	spin_unlock_irqrestore(&runtime->lock, flags);
+	return count;
+}
+EXPORT_SYMBOL(snd_rawmidi_proceed);
+
 static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream,
 static long snd_rawmidi_kernel_write1(struct snd_rawmidi_substream *substream,
 				      const unsigned char __user *userbuf,
 				      const unsigned char __user *userbuf,
 				      const unsigned char *kernelbuf,
 				      const unsigned char *kernelbuf,

+ 1 - 1
sound/core/seq/oss/seq_oss_timer.c

@@ -92,7 +92,7 @@ snd_seq_oss_process_timer_event(struct seq_oss_timer *rec, union evrec *ev)
 		case TMR_WAIT_REL:
 		case TMR_WAIT_REL:
 			parm += rec->cur_tick;
 			parm += rec->cur_tick;
 			rec->realtime = 0;
 			rec->realtime = 0;
-			/* fall through and continue to next */
+			/* fall through */
 		case TMR_WAIT_ABS:
 		case TMR_WAIT_ABS:
 			if (parm == 0) {
 			if (parm == 0) {
 				rec->realtime = 1;
 				rec->realtime = 1;

+ 19 - 3
sound/core/seq/seq_system.c

@@ -123,6 +123,7 @@ int __init snd_seq_system_client_init(void)
 {
 {
 	struct snd_seq_port_callback pcallbacks;
 	struct snd_seq_port_callback pcallbacks;
 	struct snd_seq_port_info *port;
 	struct snd_seq_port_info *port;
+	int err;
 
 
 	port = kzalloc(sizeof(*port), GFP_KERNEL);
 	port = kzalloc(sizeof(*port), GFP_KERNEL);
 	if (!port)
 	if (!port)
@@ -134,6 +135,10 @@ int __init snd_seq_system_client_init(void)
 
 
 	/* register client */
 	/* register client */
 	sysclient = snd_seq_create_kernel_client(NULL, 0, "System");
 	sysclient = snd_seq_create_kernel_client(NULL, 0, "System");
+	if (sysclient < 0) {
+		kfree(port);
+		return sysclient;
+	}
 
 
 	/* register timer */
 	/* register timer */
 	strcpy(port->name, "Timer");
 	strcpy(port->name, "Timer");
@@ -144,7 +149,10 @@ int __init snd_seq_system_client_init(void)
 	port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
 	port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
 	port->addr.client = sysclient;
 	port->addr.client = sysclient;
 	port->addr.port = SNDRV_SEQ_PORT_SYSTEM_TIMER;
 	port->addr.port = SNDRV_SEQ_PORT_SYSTEM_TIMER;
-	snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, port);
+	err = snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT,
+					port);
+	if (err < 0)
+		goto error_port;
 
 
 	/* register announcement port */
 	/* register announcement port */
 	strcpy(port->name, "Announce");
 	strcpy(port->name, "Announce");
@@ -154,16 +162,24 @@ int __init snd_seq_system_client_init(void)
 	port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
 	port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
 	port->addr.client = sysclient;
 	port->addr.client = sysclient;
 	port->addr.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
 	port->addr.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
-	snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, port);
+	err = snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT,
+					port);
+	if (err < 0)
+		goto error_port;
 	announce_port = port->addr.port;
 	announce_port = port->addr.port;
 
 
 	kfree(port);
 	kfree(port);
 	return 0;
 	return 0;
+
+ error_port:
+	snd_seq_system_client_done();
+	kfree(port);
+	return err;
 }
 }
 
 
 
 
 /* unregister our internal client */
 /* unregister our internal client */
-void __exit snd_seq_system_client_done(void)
+void snd_seq_system_client_done(void)
 {
 {
 	int oldsysclient = sysclient;
 	int oldsysclient = sysclient;
 
 

+ 1 - 3
sound/core/seq/seq_virmidi.c

@@ -149,9 +149,7 @@ static void snd_vmidi_output_work(struct work_struct *work)
 	/* discard the outputs in dispatch mode unless subscribed */
 	/* discard the outputs in dispatch mode unless subscribed */
 	if (vmidi->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH &&
 	if (vmidi->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH &&
 	    !(vmidi->rdev->flags & SNDRV_VIRMIDI_SUBSCRIBE)) {
 	    !(vmidi->rdev->flags & SNDRV_VIRMIDI_SUBSCRIBE)) {
-		char buf[32];
-		while (snd_rawmidi_transmit(substream, buf, sizeof(buf)) > 0)
-			; /* ignored */
+		snd_rawmidi_proceed(substream);
 		return;
 		return;
 	}
 	}
 
 

+ 13 - 2
sound/core/sgbuf.c

@@ -23,6 +23,7 @@
 #include <linux/mm.h>
 #include <linux/mm.h>
 #include <linux/vmalloc.h>
 #include <linux/vmalloc.h>
 #include <linux/export.h>
 #include <linux/export.h>
+#include <asm/pgtable.h>
 #include <sound/memalloc.h>
 #include <sound/memalloc.h>
 
 
 
 
@@ -43,6 +44,8 @@ int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab)
 	dmab->area = NULL;
 	dmab->area = NULL;
 
 
 	tmpb.dev.type = SNDRV_DMA_TYPE_DEV;
 	tmpb.dev.type = SNDRV_DMA_TYPE_DEV;
+	if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC_SG)
+		tmpb.dev.type = SNDRV_DMA_TYPE_DEV_UC;
 	tmpb.dev.dev = sgbuf->dev;
 	tmpb.dev.dev = sgbuf->dev;
 	for (i = 0; i < sgbuf->pages; i++) {
 	for (i = 0; i < sgbuf->pages; i++) {
 		if (!(sgbuf->table[i].addr & ~PAGE_MASK))
 		if (!(sgbuf->table[i].addr & ~PAGE_MASK))
@@ -72,12 +75,20 @@ void *snd_malloc_sgbuf_pages(struct device *device,
 	struct snd_dma_buffer tmpb;
 	struct snd_dma_buffer tmpb;
 	struct snd_sg_page *table;
 	struct snd_sg_page *table;
 	struct page **pgtable;
 	struct page **pgtable;
+	int type = SNDRV_DMA_TYPE_DEV;
+	pgprot_t prot = PAGE_KERNEL;
 
 
 	dmab->area = NULL;
 	dmab->area = NULL;
 	dmab->addr = 0;
 	dmab->addr = 0;
 	dmab->private_data = sgbuf = kzalloc(sizeof(*sgbuf), GFP_KERNEL);
 	dmab->private_data = sgbuf = kzalloc(sizeof(*sgbuf), GFP_KERNEL);
 	if (! sgbuf)
 	if (! sgbuf)
 		return NULL;
 		return NULL;
+	if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC_SG) {
+		type = SNDRV_DMA_TYPE_DEV_UC;
+#ifdef pgprot_noncached
+		prot = pgprot_noncached(PAGE_KERNEL);
+#endif
+	}
 	sgbuf->dev = device;
 	sgbuf->dev = device;
 	pages = snd_sgbuf_aligned_pages(size);
 	pages = snd_sgbuf_aligned_pages(size);
 	sgbuf->tblsize = sgbuf_align_table(pages);
 	sgbuf->tblsize = sgbuf_align_table(pages);
@@ -98,7 +109,7 @@ void *snd_malloc_sgbuf_pages(struct device *device,
 		if (chunk > maxpages)
 		if (chunk > maxpages)
 			chunk = maxpages;
 			chunk = maxpages;
 		chunk <<= PAGE_SHIFT;
 		chunk <<= PAGE_SHIFT;
-		if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, device,
+		if (snd_dma_alloc_pages_fallback(type, device,
 						 chunk, &tmpb) < 0) {
 						 chunk, &tmpb) < 0) {
 			if (!sgbuf->pages)
 			if (!sgbuf->pages)
 				goto _failed;
 				goto _failed;
@@ -125,7 +136,7 @@ void *snd_malloc_sgbuf_pages(struct device *device,
 	}
 	}
 
 
 	sgbuf->size = size;
 	sgbuf->size = size;
-	dmab->area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP, PAGE_KERNEL);
+	dmab->area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP, prot);
 	if (! dmab->area)
 	if (! dmab->area)
 		goto _failed;
 		goto _failed;
 	if (res_size)
 	if (res_size)

+ 2 - 0
sound/firewire/Kconfig

@@ -147,7 +147,9 @@ config SND_FIREWIRE_MOTU
 	help
 	help
 	 Say Y here to enable support for FireWire devices which MOTU produced:
 	 Say Y here to enable support for FireWire devices which MOTU produced:
 	  * 828mk2
 	  * 828mk2
+	  * Traveler
 	  * 828mk3
 	  * 828mk3
+	  * Audio Express
 
 
 	 To compile this driver as a module, choose M here: the module
 	 To compile this driver as a module, choose M here: the module
 	 will be called snd-firewire-motu.
 	 will be called snd-firewire-motu.

+ 71 - 7
sound/firewire/amdtp-stream.c

@@ -140,6 +140,59 @@ const unsigned int amdtp_rate_table[CIP_SFC_COUNT] = {
 };
 };
 EXPORT_SYMBOL(amdtp_rate_table);
 EXPORT_SYMBOL(amdtp_rate_table);
 
 
+static int apply_constraint_to_size(struct snd_pcm_hw_params *params,
+				    struct snd_pcm_hw_rule *rule)
+{
+	struct snd_interval *s = hw_param_interval(params, rule->var);
+	const struct snd_interval *r =
+		hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
+	struct snd_interval t = {
+		.min = s->min, .max = s->max, .integer = 1,
+	};
+	int i;
+
+	for (i = 0; i < CIP_SFC_COUNT; ++i) {
+		unsigned int rate = amdtp_rate_table[i];
+		unsigned int step = amdtp_syt_intervals[i];
+
+		if (!snd_interval_test(r, rate))
+			continue;
+
+		t.min = roundup(t.min, step);
+		t.max = rounddown(t.max, step);
+	}
+
+	if (snd_interval_checkempty(&t))
+		return -EINVAL;
+
+	return snd_interval_refine(s, &t);
+}
+
+static int apply_constraint_to_rate(struct snd_pcm_hw_params *params,
+				    struct snd_pcm_hw_rule *rule)
+{
+	struct snd_interval *r =
+			hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+	const struct snd_interval *s = hw_param_interval_c(params, rule->deps[0]);
+	struct snd_interval t = {
+		.min = UINT_MAX, .max = 0, .integer = 1,
+	};
+	int i;
+
+	for (i = 0; i < CIP_SFC_COUNT; ++i) {
+		unsigned int step = amdtp_syt_intervals[i];
+		unsigned int rate = amdtp_rate_table[i];
+
+		if (s->min % step || s->max % step)
+			continue;
+
+		t.min = min(t.min, rate);
+		t.max = max(t.max, rate);
+	}
+
+	return snd_interval_refine(r, &t);
+}
+
 /**
 /**
  * amdtp_stream_add_pcm_hw_constraints - add hw constraints for PCM substream
  * amdtp_stream_add_pcm_hw_constraints - add hw constraints for PCM substream
  * @s:		the AMDTP stream, which must be initialized.
  * @s:		the AMDTP stream, which must be initialized.
@@ -194,16 +247,27 @@ int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s,
 	 * number equals to SYT_INTERVAL. So the number is 8, 16 or 32,
 	 * number equals to SYT_INTERVAL. So the number is 8, 16 or 32,
 	 * depending on its sampling rate. For accurate period interrupt, it's
 	 * depending on its sampling rate. For accurate period interrupt, it's
 	 * preferrable to align period/buffer sizes to current SYT_INTERVAL.
 	 * preferrable to align period/buffer sizes to current SYT_INTERVAL.
-	 *
-	 * TODO: These constraints can be improved with proper rules.
-	 * Currently apply LCM of SYT_INTERVALs.
 	 */
 	 */
-	err = snd_pcm_hw_constraint_step(runtime, 0,
-					 SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 32);
+	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
+				  apply_constraint_to_size, NULL,
+				  SNDRV_PCM_HW_PARAM_RATE, -1);
+	if (err < 0)
+		goto end;
+	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+				  apply_constraint_to_rate, NULL,
+				  SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1);
+	if (err < 0)
+		goto end;
+	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+				  apply_constraint_to_size, NULL,
+				  SNDRV_PCM_HW_PARAM_RATE, -1);
+	if (err < 0)
+		goto end;
+	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+				  apply_constraint_to_rate, NULL,
+				  SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1);
 	if (err < 0)
 	if (err < 0)
 		goto end;
 		goto end;
-	err = snd_pcm_hw_constraint_step(runtime, 0,
-					 SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 32);
 end:
 end:
 	return err;
 	return err;
 }
 }

+ 16 - 42
sound/firewire/bebob/bebob.c

@@ -126,23 +126,6 @@ end:
 	return err;
 	return err;
 }
 }
 
 
-static void bebob_free(struct snd_bebob *bebob)
-{
-	snd_bebob_stream_destroy_duplex(bebob);
-	fw_unit_put(bebob->unit);
-
-	kfree(bebob->maudio_special_quirk);
-
-	mutex_destroy(&bebob->mutex);
-	kfree(bebob);
-}
-
-/*
- * This module releases the FireWire unit data after all ALSA character devices
- * are released by applications. This is for releasing stream data or finishing
- * transactions safely. Thus at returning from .remove(), this module still keep
- * references for the unit.
- */
 static void
 static void
 bebob_card_free(struct snd_card *card)
 bebob_card_free(struct snd_card *card)
 {
 {
@@ -152,7 +135,7 @@ bebob_card_free(struct snd_card *card)
 	clear_bit(bebob->card_index, devices_used);
 	clear_bit(bebob->card_index, devices_used);
 	mutex_unlock(&devices_mutex);
 	mutex_unlock(&devices_mutex);
 
 
-	bebob_free(card->private_data);
+	snd_bebob_stream_destroy_duplex(bebob);
 }
 }
 
 
 static const struct snd_bebob_spec *
 static const struct snd_bebob_spec *
@@ -192,7 +175,6 @@ do_registration(struct work_struct *work)
 		return;
 		return;
 
 
 	mutex_lock(&devices_mutex);
 	mutex_lock(&devices_mutex);
-
 	for (card_index = 0; card_index < SNDRV_CARDS; card_index++) {
 	for (card_index = 0; card_index < SNDRV_CARDS; card_index++) {
 		if (!test_bit(card_index, devices_used) && enable[card_index])
 		if (!test_bit(card_index, devices_used) && enable[card_index])
 			break;
 			break;
@@ -208,6 +190,11 @@ do_registration(struct work_struct *work)
 		mutex_unlock(&devices_mutex);
 		mutex_unlock(&devices_mutex);
 		return;
 		return;
 	}
 	}
+	set_bit(card_index, devices_used);
+	mutex_unlock(&devices_mutex);
+
+	bebob->card->private_free = bebob_card_free;
+	bebob->card->private_data = bebob;
 
 
 	err = name_device(bebob);
 	err = name_device(bebob);
 	if (err < 0)
 	if (err < 0)
@@ -248,23 +235,10 @@ do_registration(struct work_struct *work)
 	if (err < 0)
 	if (err < 0)
 		goto error;
 		goto error;
 
 
-	set_bit(card_index, devices_used);
-	mutex_unlock(&devices_mutex);
-
-	/*
-	 * After registered, bebob instance can be released corresponding to
-	 * releasing the sound card instance.
-	 */
-	bebob->card->private_free = bebob_card_free;
-	bebob->card->private_data = bebob;
 	bebob->registered = true;
 	bebob->registered = true;
 
 
 	return;
 	return;
 error:
 error:
-	mutex_unlock(&devices_mutex);
-	snd_bebob_stream_destroy_duplex(bebob);
-	kfree(bebob->maudio_special_quirk);
-	bebob->maudio_special_quirk = NULL;
 	snd_card_free(bebob->card);
 	snd_card_free(bebob->card);
 	dev_info(&bebob->unit->device,
 	dev_info(&bebob->unit->device,
 		 "Sound card registration failed: %d\n", err);
 		 "Sound card registration failed: %d\n", err);
@@ -295,15 +269,15 @@ bebob_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry)
 	}
 	}
 
 
 	/* Allocate this independent of sound card instance. */
 	/* Allocate this independent of sound card instance. */
-	bebob = kzalloc(sizeof(struct snd_bebob), GFP_KERNEL);
-	if (bebob == NULL)
+	bebob = devm_kzalloc(&unit->device, sizeof(struct snd_bebob),
+			     GFP_KERNEL);
+	if (!bebob)
 		return -ENOMEM;
 		return -ENOMEM;
-
 	bebob->unit = fw_unit_get(unit);
 	bebob->unit = fw_unit_get(unit);
-	bebob->entry = entry;
-	bebob->spec = spec;
 	dev_set_drvdata(&unit->device, bebob);
 	dev_set_drvdata(&unit->device, bebob);
 
 
+	bebob->entry = entry;
+	bebob->spec = spec;
 	mutex_init(&bebob->mutex);
 	mutex_init(&bebob->mutex);
 	spin_lock_init(&bebob->lock);
 	spin_lock_init(&bebob->lock);
 	init_waitqueue_head(&bebob->hwdep_wait);
 	init_waitqueue_head(&bebob->hwdep_wait);
@@ -379,12 +353,12 @@ static void bebob_remove(struct fw_unit *unit)
 	cancel_delayed_work_sync(&bebob->dwork);
 	cancel_delayed_work_sync(&bebob->dwork);
 
 
 	if (bebob->registered) {
 	if (bebob->registered) {
-		/* No need to wait for releasing card object in this context. */
-		snd_card_free_when_closed(bebob->card);
-	} else {
-		/* Don't forget this case. */
-		bebob_free(bebob);
+		// Block till all of ALSA character devices are released.
+		snd_card_free(bebob->card);
 	}
 	}
+
+	mutex_destroy(&bebob->mutex);
+	fw_unit_put(bebob->unit);
 }
 }
 
 
 static const struct snd_bebob_rate_spec normal_rate_spec = {
 static const struct snd_bebob_rate_spec normal_rate_spec = {

+ 3 - 2
sound/firewire/bebob/bebob_maudio.c

@@ -261,8 +261,9 @@ snd_bebob_maudio_special_discover(struct snd_bebob *bebob, bool is1814)
 	struct special_params *params;
 	struct special_params *params;
 	int err;
 	int err;
 
 
-	params = kzalloc(sizeof(struct special_params), GFP_KERNEL);
-	if (params == NULL)
+	params = devm_kzalloc(&bebob->card->card_dev,
+			      sizeof(struct special_params), GFP_KERNEL);
+	if (!params)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
 	mutex_lock(&bebob->mutex);
 	mutex_lock(&bebob->mutex);

+ 10 - 31
sound/firewire/dice/dice.c

@@ -122,25 +122,12 @@ static void dice_card_strings(struct snd_dice *dice)
 	strcpy(card->mixername, "DICE");
 	strcpy(card->mixername, "DICE");
 }
 }
 
 
-static void dice_free(struct snd_dice *dice)
+static void dice_card_free(struct snd_card *card)
 {
 {
+	struct snd_dice *dice = card->private_data;
+
 	snd_dice_stream_destroy_duplex(dice);
 	snd_dice_stream_destroy_duplex(dice);
 	snd_dice_transaction_destroy(dice);
 	snd_dice_transaction_destroy(dice);
-	fw_unit_put(dice->unit);
-
-	mutex_destroy(&dice->mutex);
-	kfree(dice);
-}
-
-/*
- * This module releases the FireWire unit data after all ALSA character devices
- * are released by applications. This is for releasing stream data or finishing
- * transactions safely. Thus at returning from .remove(), this module still keep
- * references for the unit.
- */
-static void dice_card_free(struct snd_card *card)
-{
-	dice_free(card->private_data);
 }
 }
 
 
 static void do_registration(struct work_struct *work)
 static void do_registration(struct work_struct *work)
@@ -155,6 +142,8 @@ static void do_registration(struct work_struct *work)
 			   &dice->card);
 			   &dice->card);
 	if (err < 0)
 	if (err < 0)
 		return;
 		return;
+	dice->card->private_free = dice_card_free;
+	dice->card->private_data = dice;
 
 
 	err = snd_dice_transaction_init(dice);
 	err = snd_dice_transaction_init(dice);
 	if (err < 0)
 	if (err < 0)
@@ -192,19 +181,10 @@ static void do_registration(struct work_struct *work)
 	if (err < 0)
 	if (err < 0)
 		goto error;
 		goto error;
 
 
-	/*
-	 * After registered, dice instance can be released corresponding to
-	 * releasing the sound card instance.
-	 */
-	dice->card->private_free = dice_card_free;
-	dice->card->private_data = dice;
 	dice->registered = true;
 	dice->registered = true;
 
 
 	return;
 	return;
 error:
 error:
-	snd_dice_stream_destroy_duplex(dice);
-	snd_dice_transaction_destroy(dice);
-	snd_dice_stream_destroy_duplex(dice);
 	snd_card_free(dice->card);
 	snd_card_free(dice->card);
 	dev_info(&dice->unit->device,
 	dev_info(&dice->unit->device,
 		 "Sound card registration failed: %d\n", err);
 		 "Sound card registration failed: %d\n", err);
@@ -223,10 +203,9 @@ static int dice_probe(struct fw_unit *unit,
 	}
 	}
 
 
 	/* Allocate this independent of sound card instance. */
 	/* Allocate this independent of sound card instance. */
-	dice = kzalloc(sizeof(struct snd_dice), GFP_KERNEL);
-	if (dice == NULL)
+	dice = devm_kzalloc(&unit->device, sizeof(struct snd_dice), GFP_KERNEL);
+	if (!dice)
 		return -ENOMEM;
 		return -ENOMEM;
-
 	dice->unit = fw_unit_get(unit);
 	dice->unit = fw_unit_get(unit);
 	dev_set_drvdata(&unit->device, dice);
 	dev_set_drvdata(&unit->device, dice);
 
 
@@ -263,10 +242,10 @@ static void dice_remove(struct fw_unit *unit)
 	if (dice->registered) {
 	if (dice->registered) {
 		/* No need to wait for releasing card object in this context. */
 		/* No need to wait for releasing card object in this context. */
 		snd_card_free_when_closed(dice->card);
 		snd_card_free_when_closed(dice->card);
-	} else {
-		/* Don't forget this case. */
-		dice_free(dice);
 	}
 	}
+
+	mutex_destroy(&dice->mutex);
+	fw_unit_put(dice->unit);
 }
 }
 
 
 static void dice_bus_reset(struct fw_unit *unit)
 static void dice_bus_reset(struct fw_unit *unit)

+ 13 - 22
sound/firewire/digi00x/digi00x.c

@@ -41,20 +41,12 @@ static int name_card(struct snd_dg00x *dg00x)
 	return 0;
 	return 0;
 }
 }
 
 
-static void dg00x_free(struct snd_dg00x *dg00x)
+static void dg00x_card_free(struct snd_card *card)
 {
 {
+	struct snd_dg00x *dg00x = card->private_data;
+
 	snd_dg00x_stream_destroy_duplex(dg00x);
 	snd_dg00x_stream_destroy_duplex(dg00x);
 	snd_dg00x_transaction_unregister(dg00x);
 	snd_dg00x_transaction_unregister(dg00x);
-
-	fw_unit_put(dg00x->unit);
-
-	mutex_destroy(&dg00x->mutex);
-	kfree(dg00x);
-}
-
-static void dg00x_card_free(struct snd_card *card)
-{
-	dg00x_free(card->private_data);
 }
 }
 
 
 static void do_registration(struct work_struct *work)
 static void do_registration(struct work_struct *work)
@@ -70,6 +62,8 @@ static void do_registration(struct work_struct *work)
 			   &dg00x->card);
 			   &dg00x->card);
 	if (err < 0)
 	if (err < 0)
 		return;
 		return;
+	dg00x->card->private_free = dg00x_card_free;
+	dg00x->card->private_data = dg00x;
 
 
 	err = name_card(dg00x);
 	err = name_card(dg00x);
 	if (err < 0)
 	if (err < 0)
@@ -101,14 +95,10 @@ static void do_registration(struct work_struct *work)
 	if (err < 0)
 	if (err < 0)
 		goto error;
 		goto error;
 
 
-	dg00x->card->private_free = dg00x_card_free;
-	dg00x->card->private_data = dg00x;
 	dg00x->registered = true;
 	dg00x->registered = true;
 
 
 	return;
 	return;
 error:
 error:
-	snd_dg00x_transaction_unregister(dg00x);
-	snd_dg00x_stream_destroy_duplex(dg00x);
 	snd_card_free(dg00x->card);
 	snd_card_free(dg00x->card);
 	dev_info(&dg00x->unit->device,
 	dev_info(&dg00x->unit->device,
 		 "Sound card registration failed: %d\n", err);
 		 "Sound card registration failed: %d\n", err);
@@ -120,8 +110,9 @@ static int snd_dg00x_probe(struct fw_unit *unit,
 	struct snd_dg00x *dg00x;
 	struct snd_dg00x *dg00x;
 
 
 	/* Allocate this independent of sound card instance. */
 	/* Allocate this independent of sound card instance. */
-	dg00x = kzalloc(sizeof(struct snd_dg00x), GFP_KERNEL);
-	if (dg00x == NULL)
+	dg00x = devm_kzalloc(&unit->device, sizeof(struct snd_dg00x),
+			     GFP_KERNEL);
+	if (!dg00x)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
 	dg00x->unit = fw_unit_get(unit);
 	dg00x->unit = fw_unit_get(unit);
@@ -173,12 +164,12 @@ static void snd_dg00x_remove(struct fw_unit *unit)
 	cancel_delayed_work_sync(&dg00x->dwork);
 	cancel_delayed_work_sync(&dg00x->dwork);
 
 
 	if (dg00x->registered) {
 	if (dg00x->registered) {
-		/* No need to wait for releasing card object in this context. */
-		snd_card_free_when_closed(dg00x->card);
-	} else {
-		/* Don't forget this case. */
-		dg00x_free(dg00x);
+		// Block till all of ALSA character devices are released.
+		snd_card_free(dg00x->card);
 	}
 	}
+
+	mutex_destroy(&dg00x->mutex);
+	fw_unit_put(dg00x->unit);
 }
 }
 
 
 static const struct ieee1394_device_id snd_dg00x_id_table[] = {
 static const struct ieee1394_device_id snd_dg00x_id_table[] = {

+ 12 - 24
sound/firewire/fireface/ff.c

@@ -27,20 +27,12 @@ static void name_card(struct snd_ff *ff)
 		 dev_name(&ff->unit->device), 100 << fw_dev->max_speed);
 		 dev_name(&ff->unit->device), 100 << fw_dev->max_speed);
 }
 }
 
 
-static void ff_free(struct snd_ff *ff)
+static void ff_card_free(struct snd_card *card)
 {
 {
+	struct snd_ff *ff = card->private_data;
+
 	snd_ff_stream_destroy_duplex(ff);
 	snd_ff_stream_destroy_duplex(ff);
 	snd_ff_transaction_unregister(ff);
 	snd_ff_transaction_unregister(ff);
-
-	fw_unit_put(ff->unit);
-
-	mutex_destroy(&ff->mutex);
-	kfree(ff);
-}
-
-static void ff_card_free(struct snd_card *card)
-{
-	ff_free(card->private_data);
 }
 }
 
 
 static void do_registration(struct work_struct *work)
 static void do_registration(struct work_struct *work)
@@ -55,6 +47,8 @@ static void do_registration(struct work_struct *work)
 			   &ff->card);
 			   &ff->card);
 	if (err < 0)
 	if (err < 0)
 		return;
 		return;
+	ff->card->private_free = ff_card_free;
+	ff->card->private_data = ff;
 
 
 	err = snd_ff_transaction_register(ff);
 	err = snd_ff_transaction_register(ff);
 	if (err < 0)
 	if (err < 0)
@@ -84,14 +78,10 @@ static void do_registration(struct work_struct *work)
 	if (err < 0)
 	if (err < 0)
 		goto error;
 		goto error;
 
 
-	ff->card->private_free = ff_card_free;
-	ff->card->private_data = ff;
 	ff->registered = true;
 	ff->registered = true;
 
 
 	return;
 	return;
 error:
 error:
-	snd_ff_transaction_unregister(ff);
-	snd_ff_stream_destroy_duplex(ff);
 	snd_card_free(ff->card);
 	snd_card_free(ff->card);
 	dev_info(&ff->unit->device,
 	dev_info(&ff->unit->device,
 		 "Sound card registration failed: %d\n", err);
 		 "Sound card registration failed: %d\n", err);
@@ -102,11 +92,9 @@ static int snd_ff_probe(struct fw_unit *unit,
 {
 {
 	struct snd_ff *ff;
 	struct snd_ff *ff;
 
 
-	ff = kzalloc(sizeof(struct snd_ff), GFP_KERNEL);
-	if (ff == NULL)
+	ff = devm_kzalloc(&unit->device, sizeof(struct snd_ff), GFP_KERNEL);
+	if (!ff)
 		return -ENOMEM;
 		return -ENOMEM;
-
-	/* initialize myself */
 	ff->unit = fw_unit_get(unit);
 	ff->unit = fw_unit_get(unit);
 	dev_set_drvdata(&unit->device, ff);
 	dev_set_drvdata(&unit->device, ff);
 
 
@@ -149,12 +137,12 @@ static void snd_ff_remove(struct fw_unit *unit)
 	cancel_work_sync(&ff->dwork.work);
 	cancel_work_sync(&ff->dwork.work);
 
 
 	if (ff->registered) {
 	if (ff->registered) {
-		/* No need to wait for releasing card object in this context. */
-		snd_card_free_when_closed(ff->card);
-	} else {
-		/* Don't forget this case. */
-		ff_free(ff);
+		// Block till all of ALSA character devices are released.
+		snd_card_free(ff->card);
 	}
 	}
+
+	mutex_destroy(&ff->mutex);
+	fw_unit_put(ff->unit);
 }
 }
 
 
 static const struct snd_ff_spec spec_ff400 = {
 static const struct snd_ff_spec spec_ff400 = {

+ 20 - 49
sound/firewire/fireworks/fireworks.c

@@ -184,36 +184,17 @@ end:
 	return err;
 	return err;
 }
 }
 
 
-static void efw_free(struct snd_efw *efw)
-{
-	snd_efw_stream_destroy_duplex(efw);
-	snd_efw_transaction_remove_instance(efw);
-	fw_unit_put(efw->unit);
-
-	kfree(efw->resp_buf);
-
-	mutex_destroy(&efw->mutex);
-	kfree(efw);
-}
-
-/*
- * This module releases the FireWire unit data after all ALSA character devices
- * are released by applications. This is for releasing stream data or finishing
- * transactions safely. Thus at returning from .remove(), this module still keep
- * references for the unit.
- */
 static void
 static void
 efw_card_free(struct snd_card *card)
 efw_card_free(struct snd_card *card)
 {
 {
 	struct snd_efw *efw = card->private_data;
 	struct snd_efw *efw = card->private_data;
 
 
-	if (efw->card_index >= 0) {
-		mutex_lock(&devices_mutex);
-		clear_bit(efw->card_index, devices_used);
-		mutex_unlock(&devices_mutex);
-	}
+	mutex_lock(&devices_mutex);
+	clear_bit(efw->card_index, devices_used);
+	mutex_unlock(&devices_mutex);
 
 
-	efw_free(card->private_data);
+	snd_efw_stream_destroy_duplex(efw);
+	snd_efw_transaction_remove_instance(efw);
 }
 }
 
 
 static void
 static void
@@ -226,9 +207,8 @@ do_registration(struct work_struct *work)
 	if (efw->registered)
 	if (efw->registered)
 		return;
 		return;
 
 
-	mutex_lock(&devices_mutex);
-
 	/* check registered cards */
 	/* check registered cards */
+	mutex_lock(&devices_mutex);
 	for (card_index = 0; card_index < SNDRV_CARDS; ++card_index) {
 	for (card_index = 0; card_index < SNDRV_CARDS; ++card_index) {
 		if (!test_bit(card_index, devices_used) && enable[card_index])
 		if (!test_bit(card_index, devices_used) && enable[card_index])
 			break;
 			break;
@@ -244,12 +224,18 @@ do_registration(struct work_struct *work)
 		mutex_unlock(&devices_mutex);
 		mutex_unlock(&devices_mutex);
 		return;
 		return;
 	}
 	}
+	set_bit(card_index, devices_used);
+	mutex_unlock(&devices_mutex);
+
+	efw->card->private_free = efw_card_free;
+	efw->card->private_data = efw;
 
 
 	/* prepare response buffer */
 	/* prepare response buffer */
 	snd_efw_resp_buf_size = clamp(snd_efw_resp_buf_size,
 	snd_efw_resp_buf_size = clamp(snd_efw_resp_buf_size,
 				      SND_EFW_RESPONSE_MAXIMUM_BYTES, 4096U);
 				      SND_EFW_RESPONSE_MAXIMUM_BYTES, 4096U);
-	efw->resp_buf = kzalloc(snd_efw_resp_buf_size, GFP_KERNEL);
-	if (efw->resp_buf == NULL) {
+	efw->resp_buf = devm_kzalloc(&efw->card->card_dev,
+				     snd_efw_resp_buf_size, GFP_KERNEL);
+	if (!efw->resp_buf) {
 		err = -ENOMEM;
 		err = -ENOMEM;
 		goto error;
 		goto error;
 	}
 	}
@@ -284,25 +270,11 @@ do_registration(struct work_struct *work)
 	if (err < 0)
 	if (err < 0)
 		goto error;
 		goto error;
 
 
-	set_bit(card_index, devices_used);
-	mutex_unlock(&devices_mutex);
-
-	/*
-	 * After registered, efw instance can be released corresponding to
-	 * releasing the sound card instance.
-	 */
-	efw->card->private_free = efw_card_free;
-	efw->card->private_data = efw;
 	efw->registered = true;
 	efw->registered = true;
 
 
 	return;
 	return;
 error:
 error:
-	mutex_unlock(&devices_mutex);
-	snd_efw_transaction_remove_instance(efw);
-	snd_efw_stream_destroy_duplex(efw);
 	snd_card_free(efw->card);
 	snd_card_free(efw->card);
-	kfree(efw->resp_buf);
-	efw->resp_buf = NULL;
 	dev_info(&efw->unit->device,
 	dev_info(&efw->unit->device,
 		 "Sound card registration failed: %d\n", err);
 		 "Sound card registration failed: %d\n", err);
 }
 }
@@ -312,10 +284,9 @@ efw_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry)
 {
 {
 	struct snd_efw *efw;
 	struct snd_efw *efw;
 
 
-	efw = kzalloc(sizeof(struct snd_efw), GFP_KERNEL);
+	efw = devm_kzalloc(&unit->device, sizeof(struct snd_efw), GFP_KERNEL);
 	if (efw == NULL)
 	if (efw == NULL)
 		return -ENOMEM;
 		return -ENOMEM;
-
 	efw->unit = fw_unit_get(unit);
 	efw->unit = fw_unit_get(unit);
 	dev_set_drvdata(&unit->device, efw);
 	dev_set_drvdata(&unit->device, efw);
 
 
@@ -363,12 +334,12 @@ static void efw_remove(struct fw_unit *unit)
 	cancel_delayed_work_sync(&efw->dwork);
 	cancel_delayed_work_sync(&efw->dwork);
 
 
 	if (efw->registered) {
 	if (efw->registered) {
-		/* No need to wait for releasing card object in this context. */
-		snd_card_free_when_closed(efw->card);
-	} else {
-		/* Don't forget this case. */
-		efw_free(efw);
+		// Block till all of ALSA character devices are released.
+		snd_card_free(efw->card);
 	}
 	}
+
+	mutex_destroy(&efw->mutex);
+	fw_unit_put(efw->unit);
 }
 }
 
 
 static const struct ieee1394_device_id efw_id_table[] = {
 static const struct ieee1394_device_id efw_id_table[] = {

+ 10 - 8
sound/firewire/isight.c

@@ -602,8 +602,6 @@ static void isight_card_free(struct snd_card *card)
 	struct isight *isight = card->private_data;
 	struct isight *isight = card->private_data;
 
 
 	fw_iso_resources_destroy(&isight->resources);
 	fw_iso_resources_destroy(&isight->resources);
-	fw_unit_put(isight->unit);
-	mutex_destroy(&isight->mutex);
 }
 }
 
 
 static u64 get_unit_base(struct fw_unit *unit)
 static u64 get_unit_base(struct fw_unit *unit)
@@ -640,7 +638,7 @@ static int isight_probe(struct fw_unit *unit,
 	if (!isight->audio_base) {
 	if (!isight->audio_base) {
 		dev_err(&unit->device, "audio unit base not found\n");
 		dev_err(&unit->device, "audio unit base not found\n");
 		err = -ENXIO;
 		err = -ENXIO;
-		goto err_unit;
+		goto error;
 	}
 	}
 	fw_iso_resources_init(&isight->resources, unit);
 	fw_iso_resources_init(&isight->resources, unit);
 
 
@@ -669,12 +667,12 @@ static int isight_probe(struct fw_unit *unit,
 	dev_set_drvdata(&unit->device, isight);
 	dev_set_drvdata(&unit->device, isight);
 
 
 	return 0;
 	return 0;
-
-err_unit:
-	fw_unit_put(isight->unit);
-	mutex_destroy(&isight->mutex);
 error:
 error:
 	snd_card_free(card);
 	snd_card_free(card);
+
+	mutex_destroy(&isight->mutex);
+	fw_unit_put(isight->unit);
+
 	return err;
 	return err;
 }
 }
 
 
@@ -703,7 +701,11 @@ static void isight_remove(struct fw_unit *unit)
 	isight_stop_streaming(isight);
 	isight_stop_streaming(isight);
 	mutex_unlock(&isight->mutex);
 	mutex_unlock(&isight->mutex);
 
 
-	snd_card_free_when_closed(isight->card);
+	// Block till all of ALSA character devices are released.
+	snd_card_free(isight->card);
+
+	mutex_destroy(&isight->mutex);
+	fw_unit_put(isight->unit);
 }
 }
 
 
 static const struct ieee1394_device_id isight_id_table[] = {
 static const struct ieee1394_device_id isight_id_table[] = {

+ 13 - 34
sound/firewire/motu/motu.c

@@ -52,26 +52,12 @@ static void name_card(struct snd_motu *motu)
 		 dev_name(&motu->unit->device), 100 << fw_dev->max_speed);
 		 dev_name(&motu->unit->device), 100 << fw_dev->max_speed);
 }
 }
 
 
-static void motu_free(struct snd_motu *motu)
+static void motu_card_free(struct snd_card *card)
 {
 {
-	snd_motu_transaction_unregister(motu);
+	struct snd_motu *motu = card->private_data;
 
 
+	snd_motu_transaction_unregister(motu);
 	snd_motu_stream_destroy_duplex(motu);
 	snd_motu_stream_destroy_duplex(motu);
-	fw_unit_put(motu->unit);
-
-	mutex_destroy(&motu->mutex);
-	kfree(motu);
-}
-
-/*
- * This module releases the FireWire unit data after all ALSA character devices
- * are released by applications. This is for releasing stream data or finishing
- * transactions safely. Thus at returning from .remove(), this module still keep
- * references for the unit.
- */
-static void motu_card_free(struct snd_card *card)
-{
-	motu_free(card->private_data);
 }
 }
 
 
 static void do_registration(struct work_struct *work)
 static void do_registration(struct work_struct *work)
@@ -86,6 +72,8 @@ static void do_registration(struct work_struct *work)
 			   &motu->card);
 			   &motu->card);
 	if (err < 0)
 	if (err < 0)
 		return;
 		return;
+	motu->card->private_free = motu_card_free;
+	motu->card->private_data = motu;
 
 
 	name_card(motu);
 	name_card(motu);
 
 
@@ -120,18 +108,10 @@ static void do_registration(struct work_struct *work)
 	if (err < 0)
 	if (err < 0)
 		goto error;
 		goto error;
 
 
-	/*
-	 * After registered, motu instance can be released corresponding to
-	 * releasing the sound card instance.
-	 */
-	motu->card->private_free = motu_card_free;
-	motu->card->private_data = motu;
 	motu->registered = true;
 	motu->registered = true;
 
 
 	return;
 	return;
 error:
 error:
-	snd_motu_transaction_unregister(motu);
-	snd_motu_stream_destroy_duplex(motu);
 	snd_card_free(motu->card);
 	snd_card_free(motu->card);
 	dev_info(&motu->unit->device,
 	dev_info(&motu->unit->device,
 		 "Sound card registration failed: %d\n", err);
 		 "Sound card registration failed: %d\n", err);
@@ -143,14 +123,13 @@ static int motu_probe(struct fw_unit *unit,
 	struct snd_motu *motu;
 	struct snd_motu *motu;
 
 
 	/* Allocate this independently of sound card instance. */
 	/* Allocate this independently of sound card instance. */
-	motu = kzalloc(sizeof(struct snd_motu), GFP_KERNEL);
-	if (motu == NULL)
+	motu = devm_kzalloc(&unit->device, sizeof(struct snd_motu), GFP_KERNEL);
+	if (!motu)
 		return -ENOMEM;
 		return -ENOMEM;
-
-	motu->spec = (const struct snd_motu_spec *)entry->driver_data;
 	motu->unit = fw_unit_get(unit);
 	motu->unit = fw_unit_get(unit);
 	dev_set_drvdata(&unit->device, motu);
 	dev_set_drvdata(&unit->device, motu);
 
 
+	motu->spec = (const struct snd_motu_spec *)entry->driver_data;
 	mutex_init(&motu->mutex);
 	mutex_init(&motu->mutex);
 	spin_lock_init(&motu->lock);
 	spin_lock_init(&motu->lock);
 	init_waitqueue_head(&motu->hwdep_wait);
 	init_waitqueue_head(&motu->hwdep_wait);
@@ -174,12 +153,12 @@ static void motu_remove(struct fw_unit *unit)
 	cancel_delayed_work_sync(&motu->dwork);
 	cancel_delayed_work_sync(&motu->dwork);
 
 
 	if (motu->registered) {
 	if (motu->registered) {
-		/* No need to wait for releasing card object in this context. */
-		snd_card_free_when_closed(motu->card);
-	} else {
-		/* Don't forget this case. */
-		motu_free(motu);
+		// Block till all of ALSA character devices are released.
+		snd_card_free(motu->card);
 	}
 	}
+
+	mutex_destroy(&motu->mutex);
+	fw_unit_put(motu->unit);
 }
 }
 
 
 static void motu_bus_update(struct fw_unit *unit)
 static void motu_bus_update(struct fw_unit *unit)

+ 3 - 2
sound/firewire/oxfw/oxfw-scs1x.c

@@ -372,8 +372,9 @@ int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw)
 	struct fw_scs1x *scs;
 	struct fw_scs1x *scs;
 	int err;
 	int err;
 
 
-	scs = kzalloc(sizeof(struct fw_scs1x), GFP_KERNEL);
-	if (scs == NULL)
+	scs = devm_kzalloc(&oxfw->card->card_dev, sizeof(struct fw_scs1x),
+			   GFP_KERNEL);
+	if (!scs)
 		return -ENOMEM;
 		return -ENOMEM;
 	scs->fw_dev = fw_parent_device(oxfw->unit);
 	scs->fw_dev = fw_parent_device(oxfw->unit);
 	oxfw->spec = scs;
 	oxfw->spec = scs;

+ 3 - 2
sound/firewire/oxfw/oxfw-spkr.c

@@ -270,8 +270,9 @@ int snd_oxfw_add_spkr(struct snd_oxfw *oxfw, bool is_lacie)
 	unsigned int i, first_ch;
 	unsigned int i, first_ch;
 	int err;
 	int err;
 
 
-	spkr = kzalloc(sizeof(struct fw_spkr), GFP_KERNEL);
-	if (spkr == NULL)
+	spkr = devm_kzalloc(&oxfw->card->card_dev, sizeof(struct fw_spkr),
+			    GFP_KERNEL);
+	if (!spkr)
 		return -ENOMEM;
 		return -ENOMEM;
 	oxfw->spec = spkr;
 	oxfw->spec = spkr;
 
 

+ 8 - 5
sound/firewire/oxfw/oxfw-stream.c

@@ -517,8 +517,9 @@ assume_stream_formats(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir,
 	if (err < 0)
 	if (err < 0)
 		goto end;
 		goto end;
 
 
-	formats[eid] = kmemdup(buf, *len, GFP_KERNEL);
-	if (formats[eid] == NULL) {
+	formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, *len,
+				    GFP_KERNEL);
+	if (!formats[eid]) {
 		err = -ENOMEM;
 		err = -ENOMEM;
 		goto end;
 		goto end;
 	}
 	}
@@ -535,7 +536,8 @@ assume_stream_formats(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir,
 			continue;
 			continue;
 
 
 		eid++;
 		eid++;
-		formats[eid] = kmemdup(buf, *len, GFP_KERNEL);
+		formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, *len,
+					    GFP_KERNEL);
 		if (formats[eid] == NULL) {
 		if (formats[eid] == NULL) {
 			err = -ENOMEM;
 			err = -ENOMEM;
 			goto end;
 			goto end;
@@ -597,8 +599,9 @@ static int fill_stream_formats(struct snd_oxfw *oxfw,
 		if (err < 0)
 		if (err < 0)
 			break;
 			break;
 
 
-		formats[eid] = kmemdup(buf, len, GFP_KERNEL);
-		if (formats[eid] == NULL) {
+		formats[eid] = devm_kmemdup(&oxfw->card->card_dev, buf, len,
+					    GFP_KERNEL);
+		if (!formats[eid]) {
 			err = -ENOMEM;
 			err = -ENOMEM;
 			break;
 			break;
 		}
 		}

+ 12 - 51
sound/firewire/oxfw/oxfw.c

@@ -113,35 +113,13 @@ end:
 	return err;
 	return err;
 }
 }
 
 
-static void oxfw_free(struct snd_oxfw *oxfw)
+static void oxfw_card_free(struct snd_card *card)
 {
 {
-	unsigned int i;
+	struct snd_oxfw *oxfw = card->private_data;
 
 
 	snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream);
 	snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream);
 	if (oxfw->has_output)
 	if (oxfw->has_output)
 		snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream);
 		snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream);
-
-	fw_unit_put(oxfw->unit);
-
-	for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
-		kfree(oxfw->tx_stream_formats[i]);
-		kfree(oxfw->rx_stream_formats[i]);
-	}
-
-	kfree(oxfw->spec);
-	mutex_destroy(&oxfw->mutex);
-	kfree(oxfw);
-}
-
-/*
- * This module releases the FireWire unit data after all ALSA character devices
- * are released by applications. This is for releasing stream data or finishing
- * transactions safely. Thus at returning from .remove(), this module still keep
- * references for the unit.
- */
-static void oxfw_card_free(struct snd_card *card)
-{
-	oxfw_free(card->private_data);
 }
 }
 
 
 static int detect_quirks(struct snd_oxfw *oxfw)
 static int detect_quirks(struct snd_oxfw *oxfw)
@@ -208,7 +186,6 @@ static int detect_quirks(struct snd_oxfw *oxfw)
 static void do_registration(struct work_struct *work)
 static void do_registration(struct work_struct *work)
 {
 {
 	struct snd_oxfw *oxfw = container_of(work, struct snd_oxfw, dwork.work);
 	struct snd_oxfw *oxfw = container_of(work, struct snd_oxfw, dwork.work);
-	int i;
 	int err;
 	int err;
 
 
 	if (oxfw->registered)
 	if (oxfw->registered)
@@ -218,6 +195,8 @@ static void do_registration(struct work_struct *work)
 			   &oxfw->card);
 			   &oxfw->card);
 	if (err < 0)
 	if (err < 0)
 		return;
 		return;
+	oxfw->card->private_free = oxfw_card_free;
+	oxfw->card->private_data = oxfw;
 
 
 	err = name_card(oxfw);
 	err = name_card(oxfw);
 	if (err < 0)
 	if (err < 0)
@@ -258,28 +237,11 @@ static void do_registration(struct work_struct *work)
 	if (err < 0)
 	if (err < 0)
 		goto error;
 		goto error;
 
 
-	/*
-	 * After registered, oxfw instance can be released corresponding to
-	 * releasing the sound card instance.
-	 */
-	oxfw->card->private_free = oxfw_card_free;
-	oxfw->card->private_data = oxfw;
 	oxfw->registered = true;
 	oxfw->registered = true;
 
 
 	return;
 	return;
 error:
 error:
-	snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream);
-	if (oxfw->has_output)
-		snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream);
-	for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; ++i) {
-		kfree(oxfw->tx_stream_formats[i]);
-		oxfw->tx_stream_formats[i] = NULL;
-		kfree(oxfw->rx_stream_formats[i]);
-		oxfw->rx_stream_formats[i] = NULL;
-	}
 	snd_card_free(oxfw->card);
 	snd_card_free(oxfw->card);
-	kfree(oxfw->spec);
-	oxfw->spec = NULL;
 	dev_info(&oxfw->unit->device,
 	dev_info(&oxfw->unit->device,
 		 "Sound card registration failed: %d\n", err);
 		 "Sound card registration failed: %d\n", err);
 }
 }
@@ -293,14 +255,13 @@ static int oxfw_probe(struct fw_unit *unit,
 		return -ENODEV;
 		return -ENODEV;
 
 
 	/* Allocate this independent of sound card instance. */
 	/* Allocate this independent of sound card instance. */
-	oxfw = kzalloc(sizeof(struct snd_oxfw), GFP_KERNEL);
-	if (oxfw == NULL)
+	oxfw = devm_kzalloc(&unit->device, sizeof(struct snd_oxfw), GFP_KERNEL);
+	if (!oxfw)
 		return -ENOMEM;
 		return -ENOMEM;
-
-	oxfw->entry = entry;
 	oxfw->unit = fw_unit_get(unit);
 	oxfw->unit = fw_unit_get(unit);
 	dev_set_drvdata(&unit->device, oxfw);
 	dev_set_drvdata(&unit->device, oxfw);
 
 
+	oxfw->entry = entry;
 	mutex_init(&oxfw->mutex);
 	mutex_init(&oxfw->mutex);
 	spin_lock_init(&oxfw->lock);
 	spin_lock_init(&oxfw->lock);
 	init_waitqueue_head(&oxfw->hwdep_wait);
 	init_waitqueue_head(&oxfw->hwdep_wait);
@@ -347,12 +308,12 @@ static void oxfw_remove(struct fw_unit *unit)
 	cancel_delayed_work_sync(&oxfw->dwork);
 	cancel_delayed_work_sync(&oxfw->dwork);
 
 
 	if (oxfw->registered) {
 	if (oxfw->registered) {
-		/* No need to wait for releasing card object in this context. */
-		snd_card_free_when_closed(oxfw->card);
-	} else {
-		/* Don't forget this case. */
-		oxfw_free(oxfw);
+		// Block till all of ALSA character devices are released.
+		snd_card_free(oxfw->card);
 	}
 	}
+
+	mutex_destroy(&oxfw->mutex);
+	fw_unit_put(oxfw->unit);
 }
 }
 
 
 static const struct compat_info griffin_firewave = {
 static const struct compat_info griffin_firewave = {

+ 12 - 28
sound/firewire/tascam/tascam.c

@@ -85,20 +85,12 @@ static int identify_model(struct snd_tscm *tscm)
 	return 0;
 	return 0;
 }
 }
 
 
-static void tscm_free(struct snd_tscm *tscm)
+static void tscm_card_free(struct snd_card *card)
 {
 {
+	struct snd_tscm *tscm = card->private_data;
+
 	snd_tscm_transaction_unregister(tscm);
 	snd_tscm_transaction_unregister(tscm);
 	snd_tscm_stream_destroy_duplex(tscm);
 	snd_tscm_stream_destroy_duplex(tscm);
-
-	fw_unit_put(tscm->unit);
-
-	mutex_destroy(&tscm->mutex);
-	kfree(tscm);
-}
-
-static void tscm_card_free(struct snd_card *card)
-{
-	tscm_free(card->private_data);
 }
 }
 
 
 static void do_registration(struct work_struct *work)
 static void do_registration(struct work_struct *work)
@@ -110,6 +102,8 @@ static void do_registration(struct work_struct *work)
 			   &tscm->card);
 			   &tscm->card);
 	if (err < 0)
 	if (err < 0)
 		return;
 		return;
+	tscm->card->private_free = tscm_card_free;
+	tscm->card->private_data = tscm;
 
 
 	err = identify_model(tscm);
 	err = identify_model(tscm);
 	if (err < 0)
 	if (err < 0)
@@ -141,18 +135,10 @@ static void do_registration(struct work_struct *work)
 	if (err < 0)
 	if (err < 0)
 		goto error;
 		goto error;
 
 
-	/*
-	 * After registered, tscm instance can be released corresponding to
-	 * releasing the sound card instance.
-	 */
-	tscm->card->private_free = tscm_card_free;
-	tscm->card->private_data = tscm;
 	tscm->registered = true;
 	tscm->registered = true;
 
 
 	return;
 	return;
 error:
 error:
-	snd_tscm_transaction_unregister(tscm);
-	snd_tscm_stream_destroy_duplex(tscm);
 	snd_card_free(tscm->card);
 	snd_card_free(tscm->card);
 	dev_info(&tscm->unit->device,
 	dev_info(&tscm->unit->device,
 		 "Sound card registration failed: %d\n", err);
 		 "Sound card registration failed: %d\n", err);
@@ -164,11 +150,9 @@ static int snd_tscm_probe(struct fw_unit *unit,
 	struct snd_tscm *tscm;
 	struct snd_tscm *tscm;
 
 
 	/* Allocate this independent of sound card instance. */
 	/* Allocate this independent of sound card instance. */
-	tscm = kzalloc(sizeof(struct snd_tscm), GFP_KERNEL);
-	if (tscm == NULL)
+	tscm = devm_kzalloc(&unit->device, sizeof(struct snd_tscm), GFP_KERNEL);
+	if (!tscm)
 		return -ENOMEM;
 		return -ENOMEM;
-
-	/* initialize myself */
 	tscm->unit = fw_unit_get(unit);
 	tscm->unit = fw_unit_get(unit);
 	dev_set_drvdata(&unit->device, tscm);
 	dev_set_drvdata(&unit->device, tscm);
 
 
@@ -216,12 +200,12 @@ static void snd_tscm_remove(struct fw_unit *unit)
 	cancel_delayed_work_sync(&tscm->dwork);
 	cancel_delayed_work_sync(&tscm->dwork);
 
 
 	if (tscm->registered) {
 	if (tscm->registered) {
-		/* No need to wait for releasing card object in this context. */
-		snd_card_free_when_closed(tscm->card);
-	} else {
-		/* Don't forget this case. */
-		tscm_free(tscm);
+		// Block till all of ALSA character devices are released.
+		snd_card_free(tscm->card);
 	}
 	}
+
+	mutex_destroy(&tscm->mutex);
+	fw_unit_put(tscm->unit);
 }
 }
 
 
 static const struct ieee1394_device_id snd_tscm_id_table[] = {
 static const struct ieee1394_device_id snd_tscm_id_table[] = {

+ 14 - 8
sound/hda/ext/hdac_ext_controller.c

@@ -48,9 +48,11 @@ void snd_hdac_ext_bus_ppcap_enable(struct hdac_bus *bus, bool enable)
 	}
 	}
 
 
 	if (enable)
 	if (enable)
-		snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_GPROCEN);
+		snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL,
+				 AZX_PPCTL_GPROCEN, AZX_PPCTL_GPROCEN);
 	else
 	else
-		snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_GPROCEN, 0);
+		snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL,
+				 AZX_PPCTL_GPROCEN, 0);
 }
 }
 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_enable);
 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_enable);
 
 
@@ -68,9 +70,11 @@ void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_bus *bus, bool enable)
 	}
 	}
 
 
 	if (enable)
 	if (enable)
-		snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, 0, AZX_PPCTL_PIE);
+		snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL,
+				 AZX_PPCTL_PIE, AZX_PPCTL_PIE);
 	else
 	else
-		snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL, AZX_PPCTL_PIE, 0);
+		snd_hdac_updatel(bus->ppcap, AZX_REG_PP_PPCTL,
+				 AZX_PPCTL_PIE, 0);
 }
 }
 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_int_enable);
 EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_ppcap_int_enable);
 
 
@@ -194,7 +198,8 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable)
  */
  */
 int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link)
 int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link)
 {
 {
-	snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL, 0, AZX_MLCTL_SPA);
+	snd_hdac_updatel(link->ml_addr, AZX_REG_ML_LCTL,
+			 AZX_MLCTL_SPA, AZX_MLCTL_SPA);
 
 
 	return check_hdac_link_power_active(link, true);
 	return check_hdac_link_power_active(link, true);
 }
 }
@@ -222,8 +227,8 @@ int snd_hdac_ext_bus_link_power_up_all(struct hdac_bus *bus)
 	int ret;
 	int ret;
 
 
 	list_for_each_entry(hlink, &bus->hlink_list, list) {
 	list_for_each_entry(hlink, &bus->hlink_list, list) {
-		snd_hdac_updatel(hlink->ml_addr,
-				AZX_REG_ML_LCTL, 0, AZX_MLCTL_SPA);
+		snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL,
+				 AZX_MLCTL_SPA, AZX_MLCTL_SPA);
 		ret = check_hdac_link_power_active(hlink, true);
 		ret = check_hdac_link_power_active(hlink, true);
 		if (ret < 0)
 		if (ret < 0)
 			return ret;
 			return ret;
@@ -243,7 +248,8 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_bus *bus)
 	int ret;
 	int ret;
 
 
 	list_for_each_entry(hlink, &bus->hlink_list, list) {
 	list_for_each_entry(hlink, &bus->hlink_list, list) {
-		snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, AZX_MLCTL_SPA, 0);
+		snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL,
+				 AZX_MLCTL_SPA, 0);
 		ret = check_hdac_link_power_active(hlink, false);
 		ret = check_hdac_link_power_active(hlink, false);
 		if (ret < 0)
 		if (ret < 0)
 			return ret;
 			return ret;

+ 1 - 1
sound/i2c/cs8427.c

@@ -118,7 +118,7 @@ static int snd_cs8427_send_corudata(struct snd_i2c_device *device,
 	struct cs8427 *chip = device->private_data;
 	struct cs8427 *chip = device->private_data;
 	char *hw_data = udata ?
 	char *hw_data = udata ?
 		chip->playback.hw_udata : chip->playback.hw_status;
 		chip->playback.hw_udata : chip->playback.hw_status;
-	char data[32];
+	unsigned char data[32];
 	int err, idx;
 	int err, idx;
 
 
 	if (!memcmp(hw_data, ndata, count))
 	if (!memcmp(hw_data, ndata, count))

+ 4 - 2
sound/isa/opti9xx/opti92x-ad1848.c

@@ -389,7 +389,8 @@ static int snd_opti9xx_configure(struct snd_opti9xx *chip,
 	case OPTi9XX_HW_82C931:
 	case OPTi9XX_HW_82C931:
 		/* disable 3D sound (set GPIO1 as output, low) */
 		/* disable 3D sound (set GPIO1 as output, low) */
 		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(20), 0x04, 0x0c);
 		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(20), 0x04, 0x0c);
-	case OPTi9XX_HW_82C933: /* FALL THROUGH */
+		/* fall through */
+	case OPTi9XX_HW_82C933:
 		/*
 		/*
 		 * The BTC 1817DW has QS1000 wavetable which is connected
 		 * The BTC 1817DW has QS1000 wavetable which is connected
 		 * to the serial digital input of the OPTI931.
 		 * to the serial digital input of the OPTI931.
@@ -400,7 +401,8 @@ static int snd_opti9xx_configure(struct snd_opti9xx *chip,
 		 * or digital input signal.
 		 * or digital input signal.
 		 */
 		 */
 		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(26), 0x01, 0x01);
 		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(26), 0x01, 0x01);
-	case OPTi9XX_HW_82C930: /* FALL THROUGH */
+		/* fall through */
+	case OPTi9XX_HW_82C930:
 		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x03);
 		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x03);
 		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(3), 0x00, 0xff);
 		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(3), 0x00, 0xff);
 		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(4), 0x10 |
 		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(4), 0x10 |

+ 5 - 5
sound/isa/sb/sb8_main.c

@@ -130,13 +130,13 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream)
 			chip->playback_format = SB_DSP_HI_OUTPUT_AUTO;
 			chip->playback_format = SB_DSP_HI_OUTPUT_AUTO;
 			break;
 			break;
 		}
 		}
-		/* fallthru */
+		/* fall through */
 	case SB_HW_201:
 	case SB_HW_201:
 		if (rate > 23000) {
 		if (rate > 23000) {
 			chip->playback_format = SB_DSP_HI_OUTPUT_AUTO;
 			chip->playback_format = SB_DSP_HI_OUTPUT_AUTO;
 			break;
 			break;
 		}
 		}
-		/* fallthru */
+		/* fall through */
 	case SB_HW_20:
 	case SB_HW_20:
 		chip->playback_format = SB_DSP_LO_OUTPUT_AUTO;
 		chip->playback_format = SB_DSP_LO_OUTPUT_AUTO;
 		break;
 		break;
@@ -287,7 +287,7 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream)
 			chip->capture_format = SB_DSP_HI_INPUT_AUTO;
 			chip->capture_format = SB_DSP_HI_INPUT_AUTO;
 			break;
 			break;
 		}
 		}
-		/* fallthru */
+		/* fall through */
 	case SB_HW_20:
 	case SB_HW_20:
 		chip->capture_format = SB_DSP_LO_INPUT_AUTO;
 		chip->capture_format = SB_DSP_LO_INPUT_AUTO;
 		break;
 		break;
@@ -387,7 +387,7 @@ irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip)
 	case SB_MODE_PLAYBACK_16:	/* ok.. playback is active */
 	case SB_MODE_PLAYBACK_16:	/* ok.. playback is active */
 		if (chip->hardware != SB_HW_JAZZ16)
 		if (chip->hardware != SB_HW_JAZZ16)
 			break;
 			break;
-		/* fallthru */
+		/* fall through */
 	case SB_MODE_PLAYBACK_8:
 	case SB_MODE_PLAYBACK_8:
 		substream = chip->playback_substream;
 		substream = chip->playback_substream;
 		if (chip->playback_format == SB_DSP_OUTPUT)
 		if (chip->playback_format == SB_DSP_OUTPUT)
@@ -397,7 +397,7 @@ irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip)
 	case SB_MODE_CAPTURE_16:
 	case SB_MODE_CAPTURE_16:
 		if (chip->hardware != SB_HW_JAZZ16)
 		if (chip->hardware != SB_HW_JAZZ16)
 			break;
 			break;
-		/* fallthru */
+		/* fall through */
 	case SB_MODE_CAPTURE_8:
 	case SB_MODE_CAPTURE_8:
 		substream = chip->capture_substream;
 		substream = chip->capture_substream;
 		if (chip->capture_format == SB_DSP_INPUT)
 		if (chip->capture_format == SB_DSP_INPUT)

+ 5 - 8
sound/mips/hal2.c

@@ -500,7 +500,8 @@ static const struct snd_pcm_hardware hal2_pcm_hw = {
 	.info = (SNDRV_PCM_INFO_MMAP |
 	.info = (SNDRV_PCM_INFO_MMAP |
 		 SNDRV_PCM_INFO_MMAP_VALID |
 		 SNDRV_PCM_INFO_MMAP_VALID |
 		 SNDRV_PCM_INFO_INTERLEAVED |
 		 SNDRV_PCM_INFO_INTERLEAVED |
-		 SNDRV_PCM_INFO_BLOCK_TRANSFER),
+		 SNDRV_PCM_INFO_BLOCK_TRANSFER |
+		 SNDRV_PCM_INFO_SYNC_APPLPTR),
 	.formats =          SNDRV_PCM_FMTBIT_S16_BE,
 	.formats =          SNDRV_PCM_FMTBIT_S16_BE,
 	.rates =            SNDRV_PCM_RATE_8000_48000,
 	.rates =            SNDRV_PCM_RATE_8000_48000,
 	.rate_min =         8000,
 	.rate_min =         8000,
@@ -563,6 +564,8 @@ static int hal2_playback_prepare(struct snd_pcm_substream *substream)
 	dac->sample_rate = hal2_compute_rate(dac, runtime->rate);
 	dac->sample_rate = hal2_compute_rate(dac, runtime->rate);
 	memset(&dac->pcm_indirect, 0, sizeof(dac->pcm_indirect));
 	memset(&dac->pcm_indirect, 0, sizeof(dac->pcm_indirect));
 	dac->pcm_indirect.hw_buffer_size = H2_BUF_SIZE;
 	dac->pcm_indirect.hw_buffer_size = H2_BUF_SIZE;
+	dac->pcm_indirect.hw_queue_size = H2_BUF_SIZE / 2;
+	dac->pcm_indirect.hw_io = dac->buffer_dma;
 	dac->pcm_indirect.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream);
 	dac->pcm_indirect.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream);
 	dac->substream = substream;
 	dac->substream = substream;
 	hal2_setup_dac(hal2);
 	hal2_setup_dac(hal2);
@@ -575,9 +578,6 @@ static int hal2_playback_trigger(struct snd_pcm_substream *substream, int cmd)
 
 
 	switch (cmd) {
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_START:
-		hal2->dac.pcm_indirect.hw_io = hal2->dac.buffer_dma;
-		hal2->dac.pcm_indirect.hw_data = 0;
-		substream->ops->ack(substream);
 		hal2_start_dac(hal2);
 		hal2_start_dac(hal2);
 		break;
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_STOP:
@@ -615,7 +615,6 @@ static int hal2_playback_ack(struct snd_pcm_substream *substream)
 	struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
 	struct snd_hal2 *hal2 = snd_pcm_substream_chip(substream);
 	struct hal2_codec *dac = &hal2->dac;
 	struct hal2_codec *dac = &hal2->dac;
 
 
-	dac->pcm_indirect.hw_queue_size = H2_BUF_SIZE / 2;
 	return snd_pcm_indirect_playback_transfer(substream,
 	return snd_pcm_indirect_playback_transfer(substream,
 						  &dac->pcm_indirect,
 						  &dac->pcm_indirect,
 						  hal2_playback_transfer);
 						  hal2_playback_transfer);
@@ -655,6 +654,7 @@ static int hal2_capture_prepare(struct snd_pcm_substream *substream)
 	memset(&adc->pcm_indirect, 0, sizeof(adc->pcm_indirect));
 	memset(&adc->pcm_indirect, 0, sizeof(adc->pcm_indirect));
 	adc->pcm_indirect.hw_buffer_size = H2_BUF_SIZE;
 	adc->pcm_indirect.hw_buffer_size = H2_BUF_SIZE;
 	adc->pcm_indirect.hw_queue_size = H2_BUF_SIZE / 2;
 	adc->pcm_indirect.hw_queue_size = H2_BUF_SIZE / 2;
+	adc->pcm_indirect.hw_io = adc->buffer_dma;
 	adc->pcm_indirect.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream);
 	adc->pcm_indirect.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream);
 	adc->substream = substream;
 	adc->substream = substream;
 	hal2_setup_adc(hal2);
 	hal2_setup_adc(hal2);
@@ -667,9 +667,6 @@ static int hal2_capture_trigger(struct snd_pcm_substream *substream, int cmd)
 
 
 	switch (cmd) {
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_START:
-		hal2->adc.pcm_indirect.hw_io = hal2->adc.buffer_dma;
-		hal2->adc.pcm_indirect.hw_data = 0;
-		printk(KERN_DEBUG "buffer_dma %x\n", hal2->adc.buffer_dma);
 		hal2_start_adc(hal2);
 		hal2_start_adc(hal2);
 		break;
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_STOP:

+ 1 - 1
sound/pci/asihpi/hpios.c

@@ -49,7 +49,7 @@ u16 hpios_locked_mem_alloc(struct consistent_dma_area *p_mem_area, u32 size,
 	/*?? any benefit in using managed dmam_alloc_coherent? */
 	/*?? any benefit in using managed dmam_alloc_coherent? */
 	p_mem_area->vaddr =
 	p_mem_area->vaddr =
 		dma_alloc_coherent(&pdev->dev, size, &p_mem_area->dma_handle,
 		dma_alloc_coherent(&pdev->dev, size, &p_mem_area->dma_handle,
-		GFP_DMA32 | GFP_KERNEL);
+		GFP_KERNEL);
 
 
 	if (p_mem_area->vaddr) {
 	if (p_mem_area->vaddr) {
 		HPI_DEBUG_LOG(DEBUG, "allocated %d bytes, dma 0x%x vma %p\n",
 		HPI_DEBUG_LOG(DEBUG, "allocated %d bytes, dma 0x%x vma %p\n",

+ 3 - 3
sound/pci/atiixp.c

@@ -903,15 +903,15 @@ static int snd_atiixp_playback_prepare(struct snd_pcm_substream *substream)
 	case 8:
 	case 8:
 		data |= ATI_REG_OUT_DMA_SLOT_BIT(10) |
 		data |= ATI_REG_OUT_DMA_SLOT_BIT(10) |
 			ATI_REG_OUT_DMA_SLOT_BIT(11);
 			ATI_REG_OUT_DMA_SLOT_BIT(11);
-		/* fallthru */
+		/* fall through */
 	case 6:
 	case 6:
 		data |= ATI_REG_OUT_DMA_SLOT_BIT(7) |
 		data |= ATI_REG_OUT_DMA_SLOT_BIT(7) |
 			ATI_REG_OUT_DMA_SLOT_BIT(8);
 			ATI_REG_OUT_DMA_SLOT_BIT(8);
-		/* fallthru */
+		/* fall through */
 	case 4:
 	case 4:
 		data |= ATI_REG_OUT_DMA_SLOT_BIT(6) |
 		data |= ATI_REG_OUT_DMA_SLOT_BIT(6) |
 			ATI_REG_OUT_DMA_SLOT_BIT(9);
 			ATI_REG_OUT_DMA_SLOT_BIT(9);
-		/* fallthru */
+		/* fall through */
 	default:
 	default:
 		data |= ATI_REG_OUT_DMA_SLOT_BIT(3) |
 		data |= ATI_REG_OUT_DMA_SLOT_BIT(3) |
 			ATI_REG_OUT_DMA_SLOT_BIT(4);
 			ATI_REG_OUT_DMA_SLOT_BIT(4);

+ 6 - 0
sound/pci/au88x0/au88x0_core.c

@@ -1115,6 +1115,7 @@ vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma,
 		hwwrite(vortex->mmio,
 		hwwrite(vortex->mmio,
 			VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0xc,
 			VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0xc,
 			snd_pcm_sgbuf_get_addr(dma->substream, psize * 3));
 			snd_pcm_sgbuf_get_addr(dma->substream, psize * 3));
+		/* fall through */
 		/* 3 pages */
 		/* 3 pages */
 	case 3:
 	case 3:
 		dma->cfg0 |= 0x12000000;
 		dma->cfg0 |= 0x12000000;
@@ -1122,12 +1123,14 @@ vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma,
 		hwwrite(vortex->mmio,
 		hwwrite(vortex->mmio,
 			VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0x8,
 			VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0x8,
 			snd_pcm_sgbuf_get_addr(dma->substream, psize * 2));
 			snd_pcm_sgbuf_get_addr(dma->substream, psize * 2));
+		/* fall through */
 		/* 2 pages */
 		/* 2 pages */
 	case 2:
 	case 2:
 		dma->cfg0 |= 0x88000000 | 0x44000000 | 0x10000000 | (psize - 1);
 		dma->cfg0 |= 0x88000000 | 0x44000000 | 0x10000000 | (psize - 1);
 		hwwrite(vortex->mmio,
 		hwwrite(vortex->mmio,
 			VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0x4,
 			VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0x4,
 			snd_pcm_sgbuf_get_addr(dma->substream, psize));
 			snd_pcm_sgbuf_get_addr(dma->substream, psize));
+		/* fall through */
 		/* 1 page */
 		/* 1 page */
 	case 1:
 	case 1:
 		dma->cfg0 |= 0x80000000 | 0x40000000 | ((psize - 1) << 0xc);
 		dma->cfg0 |= 0x80000000 | 0x40000000 | ((psize - 1) << 0xc);
@@ -1390,17 +1393,20 @@ vortex_wtdma_setbuffers(vortex_t * vortex, int wtdma,
 		dma->cfg1 |= 0x88000000 | 0x44000000 | 0x30000000 | (psize-1);
 		dma->cfg1 |= 0x88000000 | 0x44000000 | 0x30000000 | (psize-1);
 		hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4) + 0xc,
 		hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4) + 0xc,
 			snd_pcm_sgbuf_get_addr(dma->substream, psize * 3));
 			snd_pcm_sgbuf_get_addr(dma->substream, psize * 3));
+		/* fall through */
 		/* 3 pages */
 		/* 3 pages */
 	case 3:
 	case 3:
 		dma->cfg0 |= 0x12000000;
 		dma->cfg0 |= 0x12000000;
 		dma->cfg1 |= 0x80000000 | 0x40000000 | ((psize-1) << 0xc);
 		dma->cfg1 |= 0x80000000 | 0x40000000 | ((psize-1) << 0xc);
 		hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4)  + 0x8,
 		hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4)  + 0x8,
 			snd_pcm_sgbuf_get_addr(dma->substream, psize * 2));
 			snd_pcm_sgbuf_get_addr(dma->substream, psize * 2));
+		/* fall through */
 		/* 2 pages */
 		/* 2 pages */
 	case 2:
 	case 2:
 		dma->cfg0 |= 0x88000000 | 0x44000000 | 0x10000000 | (psize-1);
 		dma->cfg0 |= 0x88000000 | 0x44000000 | 0x10000000 | (psize-1);
 		hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4) + 0x4,
 		hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4) + 0x4,
 			snd_pcm_sgbuf_get_addr(dma->substream, psize));
 			snd_pcm_sgbuf_get_addr(dma->substream, psize));
+		/* fall through */
 		/* 1 page */
 		/* 1 page */
 	case 1:
 	case 1:
 		dma->cfg0 |= 0x80000000 | 0x40000000 | ((psize-1) << 0xc);
 		dma->cfg0 |= 0x80000000 | 0x40000000 | ((psize-1) << 0xc);

+ 4 - 2
sound/pci/cs46xx/cs46xx_lib.c

@@ -1443,7 +1443,8 @@ static const struct snd_pcm_hardware snd_cs46xx_playback =
 	.info =			(SNDRV_PCM_INFO_MMAP |
 	.info =			(SNDRV_PCM_INFO_MMAP |
 				 SNDRV_PCM_INFO_INTERLEAVED | 
 				 SNDRV_PCM_INFO_INTERLEAVED | 
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER /*|*/
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER /*|*/
-				 /*SNDRV_PCM_INFO_RESUME*/),
+				 /*SNDRV_PCM_INFO_RESUME*/ |
+				 SNDRV_PCM_INFO_SYNC_APPLPTR),
 	.formats =		(SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |
 	.formats =		(SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 |
 				 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
 				 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
 				 SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE),
 				 SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE),
@@ -1465,7 +1466,8 @@ static const struct snd_pcm_hardware snd_cs46xx_capture =
 	.info =			(SNDRV_PCM_INFO_MMAP |
 	.info =			(SNDRV_PCM_INFO_MMAP |
 				 SNDRV_PCM_INFO_INTERLEAVED |
 				 SNDRV_PCM_INFO_INTERLEAVED |
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER /*|*/
 				 SNDRV_PCM_INFO_BLOCK_TRANSFER /*|*/
-				 /*SNDRV_PCM_INFO_RESUME*/),
+				 /*SNDRV_PCM_INFO_RESUME*/ |
+				 SNDRV_PCM_INFO_SYNC_APPLPTR),
 	.formats =		SNDRV_PCM_FMTBIT_S16_LE,
 	.formats =		SNDRV_PCM_FMTBIT_S16_LE,
 	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
 	.rates =		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
 	.rate_min =		5500,
 	.rate_min =		5500,

+ 2 - 1
sound/pci/emu10k1/emupcm.c

@@ -1753,7 +1753,8 @@ static const struct snd_pcm_hardware snd_emu10k1_fx8010_playback =
 {
 {
 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 				 SNDRV_PCM_INFO_RESUME |
 				 SNDRV_PCM_INFO_RESUME |
-				 /* SNDRV_PCM_INFO_MMAP_VALID | */ SNDRV_PCM_INFO_PAUSE),
+				 /* SNDRV_PCM_INFO_MMAP_VALID | */ SNDRV_PCM_INFO_PAUSE |
+				 SNDRV_PCM_INFO_SYNC_APPLPTR),
 	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
 	.formats =		SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
 	.rates =		SNDRV_PCM_RATE_48000,
 	.rates =		SNDRV_PCM_RATE_48000,
 	.rate_min =		48000,
 	.rate_min =		48000,

+ 1 - 1
sound/pci/hda/hda_auto_parser.c

@@ -13,7 +13,7 @@
 #include <linux/export.h>
 #include <linux/export.h>
 #include <linux/sort.h>
 #include <linux/sort.h>
 #include <sound/core.h>
 #include <sound/core.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
 #include "hda_local.h"
 #include "hda_local.h"
 #include "hda_auto_parser.h"
 #include "hda_auto_parser.h"
 
 

+ 1 - 1
sound/pci/hda/hda_beep.h

@@ -9,7 +9,7 @@
 #ifndef __SOUND_HDA_BEEP_H
 #ifndef __SOUND_HDA_BEEP_H
 #define __SOUND_HDA_BEEP_H
 #define __SOUND_HDA_BEEP_H
 
 
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
 
 
 #define HDA_BEEP_MODE_OFF	0
 #define HDA_BEEP_MODE_OFF	0
 #define HDA_BEEP_MODE_ON	1
 #define HDA_BEEP_MODE_ON	1

+ 13 - 1
sound/pci/hda/hda_bind.c

@@ -11,7 +11,7 @@
 #include <linux/pm.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
 #include <linux/pm_runtime.h>
 #include <sound/core.h>
 #include <sound/core.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
 #include "hda_local.h"
 #include "hda_local.h"
 
 
 /*
 /*
@@ -81,6 +81,12 @@ static int hda_codec_driver_probe(struct device *dev)
 	hda_codec_patch_t patch;
 	hda_codec_patch_t patch;
 	int err;
 	int err;
 
 
+	if (codec->bus->core.ext_ops) {
+		if (WARN_ON(!codec->bus->core.ext_ops->hdev_attach))
+			return -EINVAL;
+		return codec->bus->core.ext_ops->hdev_attach(&codec->core);
+	}
+
 	if (WARN_ON(!codec->preset))
 	if (WARN_ON(!codec->preset))
 		return -EINVAL;
 		return -EINVAL;
 
 
@@ -134,6 +140,12 @@ static int hda_codec_driver_remove(struct device *dev)
 {
 {
 	struct hda_codec *codec = dev_to_hda_codec(dev);
 	struct hda_codec *codec = dev_to_hda_codec(dev);
 
 
+	if (codec->bus->core.ext_ops) {
+		if (WARN_ON(!codec->bus->core.ext_ops->hdev_detach))
+			return -EINVAL;
+		return codec->bus->core.ext_ops->hdev_detach(&codec->core);
+	}
+
 	if (codec->patch_ops.free)
 	if (codec->patch_ops.free)
 		codec->patch_ops.free(codec);
 		codec->patch_ops.free(codec);
 	snd_hda_codec_cleanup_for_unbind(codec);
 	snd_hda_codec_cleanup_for_unbind(codec);

+ 1 - 1
sound/pci/hda/hda_codec.c

@@ -27,7 +27,7 @@
 #include <linux/pm.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
 #include <linux/pm_runtime.h>
 #include <sound/core.h>
 #include <sound/core.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
 #include <sound/asoundef.h>
 #include <sound/asoundef.h>
 #include <sound/tlv.h>
 #include <sound/tlv.h>
 #include <sound/initval.h>
 #include <sound/initval.h>

+ 9 - 27
sound/pci/hda/hda_controller.c

@@ -130,8 +130,9 @@ static int azx_pcm_hw_params(struct snd_pcm_substream *substream,
 	azx_dev->core.bufsize = 0;
 	azx_dev->core.bufsize = 0;
 	azx_dev->core.period_bytes = 0;
 	azx_dev->core.period_bytes = 0;
 	azx_dev->core.format_val = 0;
 	azx_dev->core.format_val = 0;
-	ret = chip->ops->substream_alloc_pages(chip, substream,
-					  params_buffer_bytes(hw_params));
+	ret = snd_pcm_lib_malloc_pages(substream,
+				       params_buffer_bytes(hw_params));
+
 unlock:
 unlock:
 	dsp_unlock(azx_dev);
 	dsp_unlock(azx_dev);
 	return ret;
 	return ret;
@@ -141,7 +142,6 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
 {
 {
 	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
 	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
 	struct azx_dev *azx_dev = get_azx_dev(substream);
 	struct azx_dev *azx_dev = get_azx_dev(substream);
-	struct azx *chip = apcm->chip;
 	struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
 	struct hda_pcm_stream *hinfo = to_hda_pcm_stream(substream);
 	int err;
 	int err;
 
 
@@ -152,7 +152,7 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
 
 
 	snd_hda_codec_cleanup(apcm->codec, hinfo, substream);
 	snd_hda_codec_cleanup(apcm->codec, hinfo, substream);
 
 
-	err = chip->ops->substream_free_pages(chip, substream);
+	err = snd_pcm_lib_free_pages(substream);
 	azx_stream(azx_dev)->prepared = 0;
 	azx_stream(azx_dev)->prepared = 0;
 	dsp_unlock(azx_dev);
 	dsp_unlock(azx_dev);
 	return err;
 	return err;
@@ -732,6 +732,7 @@ int snd_hda_attach_pcm_stream(struct hda_bus *_bus, struct hda_codec *codec,
 	int pcm_dev = cpcm->device;
 	int pcm_dev = cpcm->device;
 	unsigned int size;
 	unsigned int size;
 	int s, err;
 	int s, err;
+	int type = SNDRV_DMA_TYPE_DEV_SG;
 
 
 	list_for_each_entry(apcm, &chip->pcm_list, list) {
 	list_for_each_entry(apcm, &chip->pcm_list, list) {
 		if (apcm->pcm->device == pcm_dev) {
 		if (apcm->pcm->device == pcm_dev) {
@@ -770,7 +771,9 @@ int snd_hda_attach_pcm_stream(struct hda_bus *_bus, struct hda_codec *codec,
 	size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024;
 	size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024;
 	if (size > MAX_PREALLOC_SIZE)
 	if (size > MAX_PREALLOC_SIZE)
 		size = MAX_PREALLOC_SIZE;
 		size = MAX_PREALLOC_SIZE;
-	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
+	if (chip->uc_buffer)
+		type = SNDRV_DMA_TYPE_DEV_UC_SG;
+	snd_pcm_lib_preallocate_pages_for_all(pcm, type,
 					      chip->card->dev,
 					      chip->card->dev,
 					      size, MAX_PREALLOC_SIZE);
 					      size, MAX_PREALLOC_SIZE);
 	return 0;
 	return 0;
@@ -1220,27 +1223,6 @@ void snd_hda_bus_reset(struct hda_bus *bus)
 	bus->in_reset = 0;
 	bus->in_reset = 0;
 }
 }
 
 
-static int get_jackpoll_interval(struct azx *chip)
-{
-	int i;
-	unsigned int j;
-
-	if (!chip->jackpoll_ms)
-		return 0;
-
-	i = chip->jackpoll_ms[chip->dev_index];
-	if (i == 0)
-		return 0;
-	if (i < 50 || i > 60000)
-		j = 0;
-	else
-		j = msecs_to_jiffies(i);
-	if (j == 0)
-		dev_warn(chip->card->dev,
-			 "jackpoll_ms value out of range: %d\n", i);
-	return j;
-}
-
 /* HD-audio bus initialization */
 /* HD-audio bus initialization */
 int azx_bus_init(struct azx *chip, const char *model,
 int azx_bus_init(struct azx *chip, const char *model,
 		 const struct hdac_io_ops *io_ops)
 		 const struct hdac_io_ops *io_ops)
@@ -1323,7 +1305,7 @@ int azx_probe_codecs(struct azx *chip, unsigned int max_slots)
 			err = snd_hda_codec_new(&chip->bus, chip->card, c, &codec);
 			err = snd_hda_codec_new(&chip->bus, chip->card, c, &codec);
 			if (err < 0)
 			if (err < 0)
 				continue;
 				continue;
-			codec->jackpoll_interval = get_jackpoll_interval(chip);
+			codec->jackpoll_interval = chip->jackpoll_interval;
 			codec->beep_mode = chip->beep_mode;
 			codec->beep_mode = chip->beep_mode;
 			codecs++;
 			codecs++;
 		}
 		}

+ 7 - 13
sound/pci/hda/hda_controller.h

@@ -20,7 +20,7 @@
 #include <sound/core.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm.h>
 #include <sound/initval.h>
 #include <sound/initval.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
 #include <sound/hda_register.h>
 #include <sound/hda_register.h>
 
 
 #define AZX_MAX_CODECS		HDA_MAX_CODECS
 #define AZX_MAX_CODECS		HDA_MAX_CODECS
@@ -76,7 +76,6 @@ struct azx_dev {
 	 *  when link position is not greater than FIFO size
 	 *  when link position is not greater than FIFO size
 	 */
 	 */
 	unsigned int insufficient:1;
 	unsigned int insufficient:1;
-	unsigned int wc_marked:1;
 };
 };
 
 
 #define azx_stream(dev)		(&(dev)->core)
 #define azx_stream(dev)		(&(dev)->core)
@@ -88,11 +87,6 @@ struct azx;
 struct hda_controller_ops {
 struct hda_controller_ops {
 	/* Disable msi if supported, PCI only */
 	/* Disable msi if supported, PCI only */
 	int (*disable_msi_reset_irq)(struct azx *);
 	int (*disable_msi_reset_irq)(struct azx *);
-	int (*substream_alloc_pages)(struct azx *chip,
-				     struct snd_pcm_substream *substream,
-				     size_t size);
-	int (*substream_free_pages)(struct azx *chip,
-				    struct snd_pcm_substream *substream);
 	void (*pcm_mmap_prepare)(struct snd_pcm_substream *substream,
 	void (*pcm_mmap_prepare)(struct snd_pcm_substream *substream,
 				 struct vm_area_struct *area);
 				 struct vm_area_struct *area);
 	/* Check if current position is acceptable */
 	/* Check if current position is acceptable */
@@ -127,7 +121,7 @@ struct azx {
 	int capture_streams;
 	int capture_streams;
 	int capture_index_offset;
 	int capture_index_offset;
 	int num_streams;
 	int num_streams;
-	const int *jackpoll_ms; /* per-card jack poll interval */
+	int jackpoll_interval; /* jack poll interval in jiffies */
 
 
 	/* Register interaction. */
 	/* Register interaction. */
 	const struct hda_controller_ops *ops;
 	const struct hda_controller_ops *ops;
@@ -160,6 +154,7 @@ struct azx {
 	unsigned int msi:1;
 	unsigned int msi:1;
 	unsigned int probing:1; /* codec probing phase */
 	unsigned int probing:1; /* codec probing phase */
 	unsigned int snoop:1;
 	unsigned int snoop:1;
+	unsigned int uc_buffer:1; /* non-cached pages for stream buffers */
 	unsigned int align_buffer_size:1;
 	unsigned int align_buffer_size:1;
 	unsigned int region_requested:1;
 	unsigned int region_requested:1;
 	unsigned int disabled:1; /* disabled by vga_switcheroo */
 	unsigned int disabled:1; /* disabled by vga_switcheroo */
@@ -175,11 +170,10 @@ struct azx {
 #define azx_bus(chip)	(&(chip)->bus.core)
 #define azx_bus(chip)	(&(chip)->bus.core)
 #define bus_to_azx(_bus)	container_of(_bus, struct azx, bus.core)
 #define bus_to_azx(_bus)	container_of(_bus, struct azx, bus.core)
 
 
-#ifdef CONFIG_X86
-#define azx_snoop(chip)		((chip)->snoop)
-#else
-#define azx_snoop(chip)		true
-#endif
+static inline bool azx_snoop(struct azx *chip)
+{
+	return !IS_ENABLED(CONFIG_X86) || chip->snoop;
+}
 
 
 /*
 /*
  * macros for easy use
  * macros for easy use

+ 1 - 1
sound/pci/hda/hda_eld.c

@@ -27,7 +27,7 @@
 #include <sound/core.h>
 #include <sound/core.h>
 #include <asm/unaligned.h>
 #include <asm/unaligned.h>
 #include <sound/hda_chmap.h>
 #include <sound/hda_chmap.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
 #include "hda_local.h"
 #include "hda_local.h"
 
 
 enum eld_versions {
 enum eld_versions {

+ 1 - 1
sound/pci/hda/hda_generic.c

@@ -32,7 +32,7 @@
 #include <sound/core.h>
 #include <sound/core.h>
 #include <sound/jack.h>
 #include <sound/jack.h>
 #include <sound/tlv.h>
 #include <sound/tlv.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
 #include "hda_local.h"
 #include "hda_local.h"
 #include "hda_auto_parser.h"
 #include "hda_auto_parser.h"
 #include "hda_jack.h"
 #include "hda_jack.h"

+ 1 - 1
sound/pci/hda/hda_hwdep.c

@@ -23,7 +23,7 @@
 #include <linux/compat.h>
 #include <linux/compat.h>
 #include <linux/nospec.h>
 #include <linux/nospec.h>
 #include <sound/core.h>
 #include <sound/core.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
 #include "hda_local.h"
 #include "hda_local.h"
 #include <sound/hda_hwdep.h>
 #include <sound/hda_hwdep.h>
 #include <sound/minors.h>
 #include <sound/minors.h>

+ 17 - 95
sound/pci/hda/hda_intel.c

@@ -63,7 +63,7 @@
 #include <linux/vgaarb.h>
 #include <linux/vgaarb.h>
 #include <linux/vga_switcheroo.h>
 #include <linux/vga_switcheroo.h>
 #include <linux/firmware.h>
 #include <linux/firmware.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
 #include "hda_controller.h"
 #include "hda_controller.h"
 #include "hda_intel.h"
 #include "hda_intel.h"
 
 
@@ -399,61 +399,6 @@ static char *driver_short_names[] = {
 	[AZX_DRIVER_GENERIC] = "HD-Audio Generic",
 	[AZX_DRIVER_GENERIC] = "HD-Audio Generic",
 };
 };
 
 
-#ifdef CONFIG_X86
-static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on)
-{
-	int pages;
-
-	if (azx_snoop(chip))
-		return;
-	if (!dmab || !dmab->area || !dmab->bytes)
-		return;
-
-#ifdef CONFIG_SND_DMA_SGBUF
-	if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_SG) {
-		struct snd_sg_buf *sgbuf = dmab->private_data;
-		if (chip->driver_type == AZX_DRIVER_CMEDIA)
-			return; /* deal with only CORB/RIRB buffers */
-		if (on)
-			set_pages_array_wc(sgbuf->page_table, sgbuf->pages);
-		else
-			set_pages_array_wb(sgbuf->page_table, sgbuf->pages);
-		return;
-	}
-#endif
-
-	pages = (dmab->bytes + PAGE_SIZE - 1) >> PAGE_SHIFT;
-	if (on)
-		set_memory_wc((unsigned long)dmab->area, pages);
-	else
-		set_memory_wb((unsigned long)dmab->area, pages);
-}
-
-static inline void mark_pages_wc(struct azx *chip, struct snd_dma_buffer *buf,
-				 bool on)
-{
-	__mark_pages_wc(chip, buf, on);
-}
-static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev,
-				   struct snd_pcm_substream *substream, bool on)
-{
-	if (azx_dev->wc_marked != on) {
-		__mark_pages_wc(chip, snd_pcm_get_dma_buf(substream), on);
-		azx_dev->wc_marked = on;
-	}
-}
-#else
-/* NOP for other archs */
-static inline void mark_pages_wc(struct azx *chip, struct snd_dma_buffer *buf,
-				 bool on)
-{
-}
-static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev,
-				   struct snd_pcm_substream *substream, bool on)
-{
-}
-#endif
-
 static int azx_acquire_irq(struct azx *chip, int do_disconnect);
 static int azx_acquire_irq(struct azx *chip, int do_disconnect);
 static void set_default_power_save(struct azx *chip);
 static void set_default_power_save(struct azx *chip);
 
 
@@ -1678,6 +1623,7 @@ static void azx_check_snoop_available(struct azx *chip)
 		dev_info(chip->card->dev, "Force to %s mode by module option\n",
 		dev_info(chip->card->dev, "Force to %s mode by module option\n",
 			 snoop ? "snoop" : "non-snoop");
 			 snoop ? "snoop" : "non-snoop");
 		chip->snoop = snoop;
 		chip->snoop = snoop;
+		chip->uc_buffer = !snoop;
 		return;
 		return;
 	}
 	}
 
 
@@ -1698,8 +1644,12 @@ static void azx_check_snoop_available(struct azx *chip)
 		snoop = false;
 		snoop = false;
 
 
 	chip->snoop = snoop;
 	chip->snoop = snoop;
-	if (!snoop)
+	if (!snoop) {
 		dev_info(chip->card->dev, "Force to non-snoop mode\n");
 		dev_info(chip->card->dev, "Force to non-snoop mode\n");
+		/* C-Media requires non-cached pages only for CORB/RIRB */
+		if (chip->driver_type != AZX_DRIVER_CMEDIA)
+			chip->uc_buffer = true;
+	}
 }
 }
 
 
 static void azx_probe_work(struct work_struct *work)
 static void azx_probe_work(struct work_struct *work)
@@ -1767,7 +1717,8 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
 	chip->driver_type = driver_caps & 0xff;
 	chip->driver_type = driver_caps & 0xff;
 	check_msi(chip);
 	check_msi(chip);
 	chip->dev_index = dev;
 	chip->dev_index = dev;
-	chip->jackpoll_ms = jackpoll_ms;
+	if (jackpoll_ms[dev] >= 50 && jackpoll_ms[dev] <= 60000)
+		chip->jackpoll_interval = msecs_to_jiffies(jackpoll_ms[dev]);
 	INIT_LIST_HEAD(&chip->pcm_list);
 	INIT_LIST_HEAD(&chip->pcm_list);
 	INIT_WORK(&hda->irq_pending_work, azx_irq_pending_work);
 	INIT_WORK(&hda->irq_pending_work, azx_irq_pending_work);
 	INIT_LIST_HEAD(&hda->list);
 	INIT_LIST_HEAD(&hda->list);
@@ -2090,55 +2041,24 @@ static int dma_alloc_pages(struct hdac_bus *bus,
 			   struct snd_dma_buffer *buf)
 			   struct snd_dma_buffer *buf)
 {
 {
 	struct azx *chip = bus_to_azx(bus);
 	struct azx *chip = bus_to_azx(bus);
-	int err;
 
 
-	err = snd_dma_alloc_pages(type,
-				  bus->dev,
-				  size, buf);
-	if (err < 0)
-		return err;
-	mark_pages_wc(chip, buf, true);
-	return 0;
+	if (!azx_snoop(chip) && type == SNDRV_DMA_TYPE_DEV)
+		type = SNDRV_DMA_TYPE_DEV_UC;
+	return snd_dma_alloc_pages(type, bus->dev, size, buf);
 }
 }
 
 
 static void dma_free_pages(struct hdac_bus *bus, struct snd_dma_buffer *buf)
 static void dma_free_pages(struct hdac_bus *bus, struct snd_dma_buffer *buf)
 {
 {
-	struct azx *chip = bus_to_azx(bus);
-
-	mark_pages_wc(chip, buf, false);
 	snd_dma_free_pages(buf);
 	snd_dma_free_pages(buf);
 }
 }
 
 
-static int substream_alloc_pages(struct azx *chip,
-				 struct snd_pcm_substream *substream,
-				 size_t size)
-{
-	struct azx_dev *azx_dev = get_azx_dev(substream);
-	int ret;
-
-	mark_runtime_wc(chip, azx_dev, substream, false);
-	ret = snd_pcm_lib_malloc_pages(substream, size);
-	if (ret < 0)
-		return ret;
-	mark_runtime_wc(chip, azx_dev, substream, true);
-	return 0;
-}
-
-static int substream_free_pages(struct azx *chip,
-				struct snd_pcm_substream *substream)
-{
-	struct azx_dev *azx_dev = get_azx_dev(substream);
-	mark_runtime_wc(chip, azx_dev, substream, false);
-	return snd_pcm_lib_free_pages(substream);
-}
-
 static void pcm_mmap_prepare(struct snd_pcm_substream *substream,
 static void pcm_mmap_prepare(struct snd_pcm_substream *substream,
 			     struct vm_area_struct *area)
 			     struct vm_area_struct *area)
 {
 {
 #ifdef CONFIG_X86
 #ifdef CONFIG_X86
 	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
 	struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
 	struct azx *chip = apcm->chip;
 	struct azx *chip = apcm->chip;
-	if (!azx_snoop(chip) && chip->driver_type != AZX_DRIVER_CMEDIA)
+	if (chip->uc_buffer)
 		area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
 		area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
 #endif
 #endif
 }
 }
@@ -2156,8 +2076,6 @@ static const struct hdac_io_ops pci_hda_io_ops = {
 
 
 static const struct hda_controller_ops pci_hda_ops = {
 static const struct hda_controller_ops pci_hda_ops = {
 	.disable_msi_reset_irq = disable_msi_reset_irq,
 	.disable_msi_reset_irq = disable_msi_reset_irq,
-	.substream_alloc_pages = substream_alloc_pages,
-	.substream_free_pages = substream_free_pages,
 	.pcm_mmap_prepare = pcm_mmap_prepare,
 	.pcm_mmap_prepare = pcm_mmap_prepare,
 	.position_check = azx_position_check,
 	.position_check = azx_position_check,
 	.link_power = azx_intel_link_power,
 	.link_power = azx_intel_link_power,
@@ -2257,8 +2175,12 @@ static struct snd_pci_quirk power_save_blacklist[] = {
 	/* https://bugzilla.redhat.com/show_bug.cgi?id=1581607 */
 	/* https://bugzilla.redhat.com/show_bug.cgi?id=1581607 */
 	SND_PCI_QUIRK(0x1558, 0x3501, "Clevo W35xSS_370SS", 0),
 	SND_PCI_QUIRK(0x1558, 0x3501, "Clevo W35xSS_370SS", 0),
 	/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
 	/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
+	SND_PCI_QUIRK(0x1028, 0x0497, "Dell Precision T3600", 0),
+	/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
 	/* Note the P55A-UD3 and Z87-D3HP share the subsys id for the HDA dev */
 	/* Note the P55A-UD3 and Z87-D3HP share the subsys id for the HDA dev */
 	SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P55A-UD3 / Z87-D3HP", 0),
 	SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P55A-UD3 / Z87-D3HP", 0),
+	/* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
+	SND_PCI_QUIRK(0x8086, 0x2040, "Intel DZ77BH-55K", 0),
 	/* https://bugzilla.kernel.org/show_bug.cgi?id=199607 */
 	/* https://bugzilla.kernel.org/show_bug.cgi?id=199607 */
 	SND_PCI_QUIRK(0x8086, 0x2057, "Intel NUC5i7RYB", 0),
 	SND_PCI_QUIRK(0x8086, 0x2057, "Intel NUC5i7RYB", 0),
 	/* https://bugzilla.redhat.com/show_bug.cgi?id=1520902 */
 	/* https://bugzilla.redhat.com/show_bug.cgi?id=1520902 */

+ 1 - 1
sound/pci/hda/hda_jack.c

@@ -15,7 +15,7 @@
 #include <sound/core.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/control.h>
 #include <sound/jack.h>
 #include <sound/jack.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
 #include "hda_local.h"
 #include "hda_local.h"
 #include "hda_auto_parser.h"
 #include "hda_auto_parser.h"
 #include "hda_jack.h"
 #include "hda_jack.h"

+ 1 - 1
sound/pci/hda/hda_proc.c

@@ -25,7 +25,7 @@
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/core.h>
 #include <linux/module.h>
 #include <linux/module.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
 #include "hda_local.h"
 #include "hda_local.h"
 
 
 static int dump_coef = -1;
 static int dump_coef = -1;

+ 1 - 1
sound/pci/hda/hda_sysfs.c

@@ -14,7 +14,7 @@
 #include <linux/string.h>
 #include <linux/string.h>
 #include <linux/export.h>
 #include <linux/export.h>
 #include <sound/core.h>
 #include <sound/core.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
 #include "hda_local.h"
 #include "hda_local.h"
 #include <sound/hda_hwdep.h>
 #include <sound/hda_hwdep.h>
 #include <sound/minors.h>
 #include <sound/minors.h>

+ 2 - 18
sound/pci/hda/hda_tegra.c

@@ -35,7 +35,7 @@
 #include <sound/core.h>
 #include <sound/core.h>
 #include <sound/initval.h>
 #include <sound/initval.h>
 
 
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
 #include "hda_controller.h"
 #include "hda_controller.h"
 
 
 /* Defines for Nvidia Tegra HDA support */
 /* Defines for Nvidia Tegra HDA support */
@@ -99,19 +99,6 @@ static void dma_free_pages(struct hdac_bus *bus, struct snd_dma_buffer *buf)
 	snd_dma_free_pages(buf);
 	snd_dma_free_pages(buf);
 }
 }
 
 
-static int substream_alloc_pages(struct azx *chip,
-				 struct snd_pcm_substream *substream,
-				 size_t size)
-{
-	return snd_pcm_lib_malloc_pages(substream, size);
-}
-
-static int substream_free_pages(struct azx *chip,
-				struct snd_pcm_substream *substream)
-{
-	return snd_pcm_lib_free_pages(substream);
-}
-
 /*
 /*
  * Register access ops. Tegra HDA register access is DWORD only.
  * Register access ops. Tegra HDA register access is DWORD only.
  */
  */
@@ -180,10 +167,7 @@ static const struct hdac_io_ops hda_tegra_io_ops = {
 	.dma_free_pages = dma_free_pages,
 	.dma_free_pages = dma_free_pages,
 };
 };
 
 
-static const struct hda_controller_ops hda_tegra_ops = {
-	.substream_alloc_pages = substream_alloc_pages,
-	.substream_free_pages = substream_free_pages,
-};
+static const struct hda_controller_ops hda_tegra_ops; /* nothing special */
 
 
 static void hda_tegra_init(struct hda_tegra *hda)
 static void hda_tegra_init(struct hda_tegra *hda)
 {
 {

+ 1 - 1
sound/pci/hda/patch_analog.c

@@ -24,7 +24,7 @@
 #include <linux/module.h>
 #include <linux/module.h>
 
 
 #include <sound/core.h>
 #include <sound/core.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
 #include "hda_local.h"
 #include "hda_local.h"
 #include "hda_auto_parser.h"
 #include "hda_auto_parser.h"
 #include "hda_beep.h"
 #include "hda_beep.h"

+ 1 - 1
sound/pci/hda/patch_ca0110.c

@@ -22,7 +22,7 @@
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <sound/core.h>
 #include <sound/core.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
 #include "hda_local.h"
 #include "hda_local.h"
 #include "hda_auto_parser.h"
 #include "hda_auto_parser.h"
 #include "hda_jack.h"
 #include "hda_jack.h"

+ 1412 - 263
sound/pci/hda/patch_ca0132.c

@@ -31,8 +31,9 @@
 #include <linux/types.h>
 #include <linux/types.h>
 #include <linux/io.h>
 #include <linux/io.h>
 #include <linux/pci.h>
 #include <linux/pci.h>
+#include <asm/io.h>
 #include <sound/core.h>
 #include <sound/core.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
 #include "hda_local.h"
 #include "hda_local.h"
 #include "hda_auto_parser.h"
 #include "hda_auto_parser.h"
 #include "hda_jack.h"
 #include "hda_jack.h"
@@ -81,12 +82,12 @@
 #define SCP_GET    1
 #define SCP_GET    1
 
 
 #define EFX_FILE   "ctefx.bin"
 #define EFX_FILE   "ctefx.bin"
-#define SBZ_EFX_FILE   "ctefx-sbz.bin"
+#define DESKTOP_EFX_FILE   "ctefx-desktop.bin"
 #define R3DI_EFX_FILE  "ctefx-r3di.bin"
 #define R3DI_EFX_FILE  "ctefx-r3di.bin"
 
 
 #ifdef CONFIG_SND_HDA_CODEC_CA0132_DSP
 #ifdef CONFIG_SND_HDA_CODEC_CA0132_DSP
 MODULE_FIRMWARE(EFX_FILE);
 MODULE_FIRMWARE(EFX_FILE);
-MODULE_FIRMWARE(SBZ_EFX_FILE);
+MODULE_FIRMWARE(DESKTOP_EFX_FILE);
 MODULE_FIRMWARE(R3DI_EFX_FILE);
 MODULE_FIRMWARE(R3DI_EFX_FILE);
 #endif
 #endif
 
 
@@ -152,7 +153,10 @@ enum {
 	XBASS_XOVER,
 	XBASS_XOVER,
 	EQ_PRESET_ENUM,
 	EQ_PRESET_ENUM,
 	SMART_VOLUME_ENUM,
 	SMART_VOLUME_ENUM,
-	MIC_BOOST_ENUM
+	MIC_BOOST_ENUM,
+	AE5_HEADPHONE_GAIN_ENUM,
+	AE5_SOUND_FILTER_ENUM,
+	ZXR_HEADPHONE_GAIN
 #define EFFECTS_COUNT  (EFFECT_END_NID - EFFECT_START_NID)
 #define EFFECTS_COUNT  (EFFECT_END_NID - EFFECT_START_NID)
 };
 };
 
 
@@ -666,6 +670,65 @@ static const struct ct_dsp_volume_ctl ca0132_alt_vol_ctls[] = {
 	}
 	}
 };
 };
 
 
+/* Values for ca0113_mmio_command_set for selecting output. */
+#define AE5_CA0113_OUT_SET_COMMANDS 6
+struct ae5_ca0113_output_set {
+	unsigned int group[AE5_CA0113_OUT_SET_COMMANDS];
+	unsigned int target[AE5_CA0113_OUT_SET_COMMANDS];
+	unsigned int vals[AE5_CA0113_OUT_SET_COMMANDS];
+};
+
+static const struct ae5_ca0113_output_set ae5_ca0113_output_presets[] = {
+	{ .group =  { 0x30, 0x30, 0x48, 0x48, 0x48, 0x30 },
+	  .target = { 0x2e, 0x30, 0x0d, 0x17, 0x19, 0x32 },
+	  .vals =   { 0x00, 0x00, 0x40, 0x00, 0x00, 0x3f }
+	},
+	{ .group =  { 0x30, 0x30, 0x48, 0x48, 0x48, 0x30 },
+	  .target = { 0x2e, 0x30, 0x0d, 0x17, 0x19, 0x32 },
+	  .vals =   { 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00 }
+	},
+	{ .group =  { 0x30, 0x30, 0x48, 0x48, 0x48, 0x30 },
+	  .target = { 0x2e, 0x30, 0x0d, 0x17, 0x19, 0x32 },
+	  .vals =   { 0x00, 0x00, 0x40, 0x00, 0x00, 0x3f }
+	}
+};
+
+/* ae5 ca0113 command sequences to set headphone gain levels. */
+#define AE5_HEADPHONE_GAIN_PRESET_MAX_COMMANDS 4
+struct ae5_headphone_gain_set {
+	char *name;
+	unsigned int vals[AE5_HEADPHONE_GAIN_PRESET_MAX_COMMANDS];
+};
+
+static const struct ae5_headphone_gain_set ae5_headphone_gain_presets[] = {
+	{ .name = "Low (16-31",
+	  .vals = { 0xff, 0x2c, 0xf5, 0x32 }
+	},
+	{ .name = "Medium (32-149",
+	  .vals = { 0x38, 0xa8, 0x3e, 0x4c }
+	},
+	{ .name = "High (150-600",
+	  .vals = { 0xff, 0xff, 0xff, 0x7f }
+	}
+};
+
+struct ae5_filter_set {
+	char *name;
+	unsigned int val;
+};
+
+static const struct ae5_filter_set ae5_filter_presets[] = {
+	{ .name = "Slow Roll Off",
+	  .val = 0xa0
+	},
+	{ .name = "Minimum Phase",
+	  .val = 0xc0
+	},
+	{ .name = "Fast Roll Off",
+	  .val = 0x80
+	}
+};
+
 enum hda_cmd_vendor_io {
 enum hda_cmd_vendor_io {
 	/* for DspIO node */
 	/* for DspIO node */
 	VENDOR_DSPIO_SCP_WRITE_DATA_LOW      = 0x000,
 	VENDOR_DSPIO_SCP_WRITE_DATA_LOW      = 0x000,
@@ -685,6 +748,9 @@ enum hda_cmd_vendor_io {
 	VENDOR_CHIPIO_DATA_LOW               = 0x300,
 	VENDOR_CHIPIO_DATA_LOW               = 0x300,
 	VENDOR_CHIPIO_DATA_HIGH              = 0x400,
 	VENDOR_CHIPIO_DATA_HIGH              = 0x400,
 
 
+	VENDOR_CHIPIO_8051_WRITE_DIRECT      = 0x500,
+	VENDOR_CHIPIO_8051_READ_DIRECT       = 0xD00,
+
 	VENDOR_CHIPIO_GET_PARAMETER          = 0xF00,
 	VENDOR_CHIPIO_GET_PARAMETER          = 0xF00,
 	VENDOR_CHIPIO_STATUS                 = 0xF01,
 	VENDOR_CHIPIO_STATUS                 = 0xF01,
 	VENDOR_CHIPIO_HIC_POST_READ          = 0x702,
 	VENDOR_CHIPIO_HIC_POST_READ          = 0x702,
@@ -692,6 +758,9 @@ enum hda_cmd_vendor_io {
 
 
 	VENDOR_CHIPIO_8051_DATA_WRITE        = 0x707,
 	VENDOR_CHIPIO_8051_DATA_WRITE        = 0x707,
 	VENDOR_CHIPIO_8051_DATA_READ         = 0xF07,
 	VENDOR_CHIPIO_8051_DATA_READ         = 0xF07,
+	VENDOR_CHIPIO_8051_PMEM_READ         = 0xF08,
+	VENDOR_CHIPIO_8051_IRAM_WRITE        = 0x709,
+	VENDOR_CHIPIO_8051_IRAM_READ         = 0xF09,
 
 
 	VENDOR_CHIPIO_CT_EXTENSIONS_ENABLE   = 0x70A,
 	VENDOR_CHIPIO_CT_EXTENSIONS_ENABLE   = 0x70A,
 	VENDOR_CHIPIO_CT_EXTENSIONS_GET      = 0xF0A,
 	VENDOR_CHIPIO_CT_EXTENSIONS_GET      = 0xF0A,
@@ -798,6 +867,12 @@ enum control_param_id {
 	 * impedance is selected*/
 	 * impedance is selected*/
 	CONTROL_PARAM_PORTD_160OHM_GAIN        = 10,
 	CONTROL_PARAM_PORTD_160OHM_GAIN        = 10,
 
 
+	/*
+	 * This control param name was found in the 8051 memory, and makes
+	 * sense given the fact the AE-5 uses it and has the ASI flag set.
+	 */
+	CONTROL_PARAM_ASI                      = 23,
+
 	/* Stream Control */
 	/* Stream Control */
 
 
 	/* Select stream with the given ID */
 	/* Select stream with the given ID */
@@ -955,7 +1030,11 @@ struct ca0132_spec {
 	long eq_preset_val;
 	long eq_preset_val;
 	unsigned int tlv[4];
 	unsigned int tlv[4];
 	struct hda_vmaster_mute_hook vmaster_mute;
 	struct hda_vmaster_mute_hook vmaster_mute;
-
+	/* AE-5 Control values */
+	unsigned char ae5_headphone_gain_val;
+	unsigned char ae5_filter_val;
+	/* ZxR Control Values */
+	unsigned char zxr_gain_set;
 
 
 	struct hda_codec *codec;
 	struct hda_codec *codec;
 	struct delayed_work unsol_hp_work;
 	struct delayed_work unsol_hp_work;
@@ -995,8 +1074,11 @@ enum {
 	QUIRK_ALIENWARE,
 	QUIRK_ALIENWARE,
 	QUIRK_ALIENWARE_M17XR4,
 	QUIRK_ALIENWARE_M17XR4,
 	QUIRK_SBZ,
 	QUIRK_SBZ,
+	QUIRK_ZXR,
+	QUIRK_ZXR_DBPRO,
 	QUIRK_R3DI,
 	QUIRK_R3DI,
 	QUIRK_R3D,
 	QUIRK_R3D,
+	QUIRK_AE5,
 };
 };
 
 
 static const struct hda_pintbl alienware_pincfgs[] = {
 static const struct hda_pintbl alienware_pincfgs[] = {
@@ -1028,6 +1110,21 @@ static const struct hda_pintbl sbz_pincfgs[] = {
 	{}
 	{}
 };
 };
 
 
+/* Sound Blaster ZxR pin configs taken from Windows Driver */
+static const struct hda_pintbl zxr_pincfgs[] = {
+	{ 0x0b, 0x01047110 }, /* Port G -- Lineout FRONT L/R */
+	{ 0x0c, 0x414510f0 }, /* SPDIF Out 1 - Disabled*/
+	{ 0x0d, 0x014510f0 }, /* Digital Out */
+	{ 0x0e, 0x41c520f0 }, /* SPDIF In - Disabled*/
+	{ 0x0f, 0x0122711f }, /* Port A -- BackPanel HP */
+	{ 0x10, 0x01017111 }, /* Port D -- Center/LFE */
+	{ 0x11, 0x01017114 }, /* Port B -- LineMicIn2 / Rear L/R */
+	{ 0x12, 0x01a271f0 }, /* Port C -- LineIn1 */
+	{ 0x13, 0x908700f0 }, /* What U Hear In*/
+	{ 0x18, 0x50d000f0 }, /* N/A */
+	{}
+};
+
 /* Recon3D pin configs taken from Windows Driver */
 /* Recon3D pin configs taken from Windows Driver */
 static const struct hda_pintbl r3d_pincfgs[] = {
 static const struct hda_pintbl r3d_pincfgs[] = {
 	{ 0x0b, 0x01014110 }, /* Port G -- Lineout FRONT L/R */
 	{ 0x0b, 0x01014110 }, /* Port G -- Lineout FRONT L/R */
@@ -1043,6 +1140,21 @@ static const struct hda_pintbl r3d_pincfgs[] = {
 	{}
 	{}
 };
 };
 
 
+/* Sound Blaster AE-5 pin configs taken from Windows Driver */
+static const struct hda_pintbl ae5_pincfgs[] = {
+	{ 0x0b, 0x01017010 }, /* Port G -- Lineout FRONT L/R */
+	{ 0x0c, 0x014510f0 }, /* SPDIF Out 1 */
+	{ 0x0d, 0x014510f0 }, /* Digital Out */
+	{ 0x0e, 0x01c510f0 }, /* SPDIF In */
+	{ 0x0f, 0x01017114 }, /* Port A -- Rear L/R. */
+	{ 0x10, 0x01017012 }, /* Port D -- Center/LFE or FP Hp */
+	{ 0x11, 0x01a170ff }, /* Port B -- LineMicIn2 / Rear Headphone */
+	{ 0x12, 0x01a170f0 }, /* Port C -- LineIn1 */
+	{ 0x13, 0x908700f0 }, /* What U Hear In*/
+	{ 0x18, 0x50d000f0 }, /* N/A */
+	{}
+};
+
 /* Recon3D integrated pin configs taken from Windows Driver */
 /* Recon3D integrated pin configs taken from Windows Driver */
 static const struct hda_pintbl r3di_pincfgs[] = {
 static const struct hda_pintbl r3di_pincfgs[] = {
 	{ 0x0b, 0x01014110 }, /* Port G -- Lineout FRONT L/R */
 	{ 0x0b, 0x01014110 }, /* Port G -- Lineout FRONT L/R */
@@ -1069,6 +1181,7 @@ static const struct snd_pci_quirk ca0132_quirks[] = {
 	SND_PCI_QUIRK(0x1458, 0xA026, "Gigabyte G1.Sniper Z97", QUIRK_R3DI),
 	SND_PCI_QUIRK(0x1458, 0xA026, "Gigabyte G1.Sniper Z97", QUIRK_R3DI),
 	SND_PCI_QUIRK(0x1458, 0xA036, "Gigabyte GA-Z170X-Gaming 7", QUIRK_R3DI),
 	SND_PCI_QUIRK(0x1458, 0xA036, "Gigabyte GA-Z170X-Gaming 7", QUIRK_R3DI),
 	SND_PCI_QUIRK(0x1102, 0x0013, "Recon3D", QUIRK_R3D),
 	SND_PCI_QUIRK(0x1102, 0x0013, "Recon3D", QUIRK_R3D),
+	SND_PCI_QUIRK(0x1102, 0x0051, "Sound Blaster AE-5", QUIRK_AE5),
 	{}
 	{}
 };
 };
 
 
@@ -1453,6 +1566,20 @@ static void chipio_set_conn_rate(struct hda_codec *codec,
 				 rate);
 				 rate);
 }
 }
 
 
+/*
+ * Writes to the 8051's internal address space directly instead of indirectly,
+ * giving access to the special function registers located at addresses
+ * 0x80-0xFF.
+ */
+static void chipio_8051_write_direct(struct hda_codec *codec,
+		unsigned int addr, unsigned int data)
+{
+	unsigned int verb;
+
+	verb = VENDOR_CHIPIO_8051_WRITE_DIRECT | data;
+	snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, verb, addr);
+}
+
 /*
 /*
  * Enable clocks.
  * Enable clocks.
  */
  */
@@ -3088,7 +3215,9 @@ static bool dspload_wait_loaded(struct hda_codec *codec)
 }
 }
 
 
 /*
 /*
- * Setup GPIO for the other variants of Core3D.
+ * ca0113 related functions. The ca0113 acts as the HDA bus for the pci-e
+ * based cards, and has a second mmio region, region2, that's used for special
+ * commands.
  */
  */
 
 
 /*
 /*
@@ -3096,8 +3225,11 @@ static bool dspload_wait_loaded(struct hda_codec *codec)
  * the mmio address 0x320 is used to set GPIO pins. The format for the data
  * the mmio address 0x320 is used to set GPIO pins. The format for the data
  * The first eight bits are just the number of the pin. So far, I've only seen
  * The first eight bits are just the number of the pin. So far, I've only seen
  * this number go to 7.
  * this number go to 7.
+ * AE-5 note: The AE-5 seems to use pins 2 and 3 to somehow set the color value
+ * of the on-card LED. It seems to use pin 2 for data, then toggles 3 to on and
+ * then off to send that bit.
  */
  */
-static void ca0132_mmio_gpio_set(struct hda_codec *codec, unsigned int gpio_pin,
+static void ca0113_mmio_gpio_set(struct hda_codec *codec, unsigned int gpio_pin,
 		bool enable)
 		bool enable)
 {
 {
 	struct ca0132_spec *spec = codec->spec;
 	struct ca0132_spec *spec = codec->spec;
@@ -3109,6 +3241,89 @@ static void ca0132_mmio_gpio_set(struct hda_codec *codec, unsigned int gpio_pin,
 	writew(gpio_data, spec->mem_base + 0x320);
 	writew(gpio_data, spec->mem_base + 0x320);
 }
 }
 
 
+/*
+ * Special pci region2 commands that are only used by the AE-5. They follow
+ * a set format, and require reads at certain points to seemingly 'clear'
+ * the response data. My first tests didn't do these reads, and would cause
+ * the card to get locked up until the memory was read. These commands
+ * seem to work with three distinct values that I've taken to calling group,
+ * target-id, and value.
+ */
+static void ca0113_mmio_command_set(struct hda_codec *codec, unsigned int group,
+		unsigned int target, unsigned int value)
+{
+	struct ca0132_spec *spec = codec->spec;
+	unsigned int write_val;
+
+	writel(0x0000007e, spec->mem_base + 0x210);
+	readl(spec->mem_base + 0x210);
+	writel(0x0000005a, spec->mem_base + 0x210);
+	readl(spec->mem_base + 0x210);
+	readl(spec->mem_base + 0x210);
+
+	writel(0x00800005, spec->mem_base + 0x20c);
+	writel(group, spec->mem_base + 0x804);
+
+	writel(0x00800005, spec->mem_base + 0x20c);
+	write_val = (target & 0xff);
+	write_val |= (value << 8);
+
+
+	writel(write_val, spec->mem_base + 0x204);
+	/*
+	 * Need delay here or else it goes too fast and works inconsistently.
+	 */
+	msleep(20);
+
+	readl(spec->mem_base + 0x860);
+	readl(spec->mem_base + 0x854);
+	readl(spec->mem_base + 0x840);
+
+	writel(0x00800004, spec->mem_base + 0x20c);
+	writel(0x00000000, spec->mem_base + 0x210);
+	readl(spec->mem_base + 0x210);
+	readl(spec->mem_base + 0x210);
+}
+
+/*
+ * This second type of command is used for setting the sound filter type.
+ */
+static void ca0113_mmio_command_set_type2(struct hda_codec *codec,
+		unsigned int group, unsigned int target, unsigned int value)
+{
+	struct ca0132_spec *spec = codec->spec;
+	unsigned int write_val;
+
+	writel(0x0000007e, spec->mem_base + 0x210);
+	readl(spec->mem_base + 0x210);
+	writel(0x0000005a, spec->mem_base + 0x210);
+	readl(spec->mem_base + 0x210);
+	readl(spec->mem_base + 0x210);
+
+	writel(0x00800003, spec->mem_base + 0x20c);
+	writel(group, spec->mem_base + 0x804);
+
+	writel(0x00800005, spec->mem_base + 0x20c);
+	write_val = (target & 0xff);
+	write_val |= (value << 8);
+
+
+	writel(write_val, spec->mem_base + 0x204);
+	msleep(20);
+	readl(spec->mem_base + 0x860);
+	readl(spec->mem_base + 0x854);
+	readl(spec->mem_base + 0x840);
+
+	writel(0x00800004, spec->mem_base + 0x20c);
+	writel(0x00000000, spec->mem_base + 0x210);
+	readl(spec->mem_base + 0x210);
+	readl(spec->mem_base + 0x210);
+}
+
+/*
+ * Setup GPIO for the other variants of Core3D.
+ */
+
 /*
 /*
  * Sets up the GPIO pins so that they are discoverable. If this isn't done,
  * Sets up the GPIO pins so that they are discoverable. If this isn't done,
  * the card shows as having no GPIO pins.
  * the card shows as having no GPIO pins.
@@ -3119,6 +3334,7 @@ static void ca0132_gpio_init(struct hda_codec *codec)
 
 
 	switch (spec->quirk) {
 	switch (spec->quirk) {
 	case QUIRK_SBZ:
 	case QUIRK_SBZ:
+	case QUIRK_AE5:
 		snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00);
 		snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00);
 		snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x53);
 		snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x53);
 		snd_hda_codec_write(codec, 0x01, 0, 0x790, 0x23);
 		snd_hda_codec_write(codec, 0x01, 0, 0x790, 0x23);
@@ -3928,6 +4144,138 @@ exit:
 	return err < 0 ? err : 0;
 	return err < 0 ? err : 0;
 }
 }
 
 
+static int ae5_headphone_gain_set(struct hda_codec *codec, long val);
+static int zxr_headphone_gain_set(struct hda_codec *codec, long val);
+static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val);
+
+static void ae5_mmio_select_out(struct hda_codec *codec)
+{
+	struct ca0132_spec *spec = codec->spec;
+	unsigned int i;
+
+	for (i = 0; i < AE5_CA0113_OUT_SET_COMMANDS; i++)
+		ca0113_mmio_command_set(codec,
+			ae5_ca0113_output_presets[spec->cur_out_type].group[i],
+			ae5_ca0113_output_presets[spec->cur_out_type].target[i],
+			ae5_ca0113_output_presets[spec->cur_out_type].vals[i]);
+}
+
+/*
+ * These are the commands needed to setup output on each of the different card
+ * types.
+ */
+static void ca0132_alt_select_out_quirk_handler(struct hda_codec *codec)
+{
+	struct ca0132_spec *spec = codec->spec;
+	unsigned int tmp;
+
+	switch (spec->cur_out_type) {
+	case SPEAKER_OUT:
+		switch (spec->quirk) {
+		case QUIRK_SBZ:
+			ca0113_mmio_gpio_set(codec, 7, false);
+			ca0113_mmio_gpio_set(codec, 4, true);
+			ca0113_mmio_gpio_set(codec, 1, true);
+			chipio_set_control_param(codec, 0x0d, 0x18);
+			break;
+		case QUIRK_ZXR:
+			ca0113_mmio_gpio_set(codec, 2, true);
+			ca0113_mmio_gpio_set(codec, 3, true);
+			ca0113_mmio_gpio_set(codec, 5, false);
+			zxr_headphone_gain_set(codec, 0);
+			chipio_set_control_param(codec, 0x0d, 0x24);
+			break;
+		case QUIRK_R3DI:
+			chipio_set_control_param(codec, 0x0d, 0x24);
+			r3di_gpio_out_set(codec, R3DI_LINE_OUT);
+			break;
+		case QUIRK_R3D:
+			chipio_set_control_param(codec, 0x0d, 0x24);
+			ca0113_mmio_gpio_set(codec, 1, true);
+			break;
+		case QUIRK_AE5:
+			ae5_mmio_select_out(codec);
+			ae5_headphone_gain_set(codec, 2);
+			tmp = FLOAT_ZERO;
+			dspio_set_uint_param(codec, 0x96, 0x29, tmp);
+			dspio_set_uint_param(codec, 0x96, 0x2a, tmp);
+			chipio_set_control_param(codec, 0x0d, 0xa4);
+			chipio_write(codec, 0x18b03c, 0x00000012);
+			break;
+		}
+		break;
+	case HEADPHONE_OUT:
+		switch (spec->quirk) {
+		case QUIRK_SBZ:
+			ca0113_mmio_gpio_set(codec, 7, true);
+			ca0113_mmio_gpio_set(codec, 4, true);
+			ca0113_mmio_gpio_set(codec, 1, false);
+			chipio_set_control_param(codec, 0x0d, 0x12);
+			break;
+		case QUIRK_ZXR:
+			ca0113_mmio_gpio_set(codec, 2, false);
+			ca0113_mmio_gpio_set(codec, 3, false);
+			ca0113_mmio_gpio_set(codec, 5, true);
+			zxr_headphone_gain_set(codec, spec->zxr_gain_set);
+			chipio_set_control_param(codec, 0x0d, 0x21);
+			break;
+		case QUIRK_R3DI:
+			chipio_set_control_param(codec, 0x0d, 0x21);
+			r3di_gpio_out_set(codec, R3DI_HEADPHONE_OUT);
+			break;
+		case QUIRK_R3D:
+			chipio_set_control_param(codec, 0x0d, 0x21);
+			ca0113_mmio_gpio_set(codec, 0x1, false);
+			break;
+		case QUIRK_AE5:
+			ae5_mmio_select_out(codec);
+			ae5_headphone_gain_set(codec,
+					spec->ae5_headphone_gain_val);
+			tmp = FLOAT_ONE;
+			dspio_set_uint_param(codec, 0x96, 0x29, tmp);
+			dspio_set_uint_param(codec, 0x96, 0x2a, tmp);
+			chipio_set_control_param(codec, 0x0d, 0xa1);
+			chipio_write(codec, 0x18b03c, 0x00000012);
+			break;
+		}
+		break;
+	case SURROUND_OUT:
+		switch (spec->quirk) {
+		case QUIRK_SBZ:
+			ca0113_mmio_gpio_set(codec, 7, false);
+			ca0113_mmio_gpio_set(codec, 4, true);
+			ca0113_mmio_gpio_set(codec, 1, true);
+			chipio_set_control_param(codec, 0x0d, 0x18);
+			break;
+		case QUIRK_ZXR:
+			ca0113_mmio_gpio_set(codec, 2, true);
+			ca0113_mmio_gpio_set(codec, 3, true);
+			ca0113_mmio_gpio_set(codec, 5, false);
+			zxr_headphone_gain_set(codec, 0);
+			chipio_set_control_param(codec, 0x0d, 0x24);
+			break;
+		case QUIRK_R3DI:
+			chipio_set_control_param(codec, 0x0d, 0x24);
+			r3di_gpio_out_set(codec, R3DI_LINE_OUT);
+			break;
+		case QUIRK_R3D:
+			ca0113_mmio_gpio_set(codec, 1, true);
+			chipio_set_control_param(codec, 0x0d, 0x24);
+			break;
+		case QUIRK_AE5:
+			ae5_mmio_select_out(codec);
+			ae5_headphone_gain_set(codec, 2);
+			tmp = FLOAT_ZERO;
+			dspio_set_uint_param(codec, 0x96, 0x29, tmp);
+			dspio_set_uint_param(codec, 0x96, 0x2a, tmp);
+			chipio_set_control_param(codec, 0x0d, 0xa4);
+			chipio_write(codec, 0x18b03c, 0x00000012);
+			break;
+		}
+		break;
+	}
+}
+
 /*
 /*
  * This function behaves similarly to the ca0132_select_out funciton above,
  * This function behaves similarly to the ca0132_select_out funciton above,
  * except with a few differences. It adds the ability to select the current
  * except with a few differences. It adds the ability to select the current
@@ -3978,26 +4326,11 @@ static int ca0132_alt_select_out(struct hda_codec *codec)
 	if (err < 0)
 	if (err < 0)
 		goto exit;
 		goto exit;
 
 
+	ca0132_alt_select_out_quirk_handler(codec);
+
 	switch (spec->cur_out_type) {
 	switch (spec->cur_out_type) {
 	case SPEAKER_OUT:
 	case SPEAKER_OUT:
 		codec_dbg(codec, "%s speaker\n", __func__);
 		codec_dbg(codec, "%s speaker\n", __func__);
-		/*speaker out config*/
-		switch (spec->quirk) {
-		case QUIRK_SBZ:
-			ca0132_mmio_gpio_set(codec, 7, false);
-			ca0132_mmio_gpio_set(codec, 4, true);
-			ca0132_mmio_gpio_set(codec, 1, true);
-			chipio_set_control_param(codec, 0x0D, 0x18);
-			break;
-		case QUIRK_R3DI:
-			chipio_set_control_param(codec, 0x0D, 0x24);
-			r3di_gpio_out_set(codec, R3DI_LINE_OUT);
-			break;
-		case QUIRK_R3D:
-			chipio_set_control_param(codec, 0x0D, 0x24);
-			ca0132_mmio_gpio_set(codec, 1, true);
-			break;
-		}
 
 
 		/* disable headphone node */
 		/* disable headphone node */
 		pin_ctl = snd_hda_codec_read(codec, spec->out_pins[1], 0,
 		pin_ctl = snd_hda_codec_read(codec, spec->out_pins[1], 0,
@@ -4021,23 +4354,6 @@ static int ca0132_alt_select_out(struct hda_codec *codec)
 		break;
 		break;
 	case HEADPHONE_OUT:
 	case HEADPHONE_OUT:
 		codec_dbg(codec, "%s hp\n", __func__);
 		codec_dbg(codec, "%s hp\n", __func__);
-		/* Headphone out config*/
-		switch (spec->quirk) {
-		case QUIRK_SBZ:
-			ca0132_mmio_gpio_set(codec, 7, true);
-			ca0132_mmio_gpio_set(codec, 4, true);
-			ca0132_mmio_gpio_set(codec, 1, false);
-			chipio_set_control_param(codec, 0x0D, 0x12);
-			break;
-		case QUIRK_R3DI:
-			chipio_set_control_param(codec, 0x0D, 0x21);
-			r3di_gpio_out_set(codec, R3DI_HEADPHONE_OUT);
-			break;
-		case QUIRK_R3D:
-			chipio_set_control_param(codec, 0x0D, 0x21);
-			ca0132_mmio_gpio_set(codec, 0x1, false);
-			break;
-		}
 
 
 		snd_hda_codec_write(codec, spec->out_pins[0], 0,
 		snd_hda_codec_write(codec, spec->out_pins[0], 0,
 			AC_VERB_SET_EAPD_BTLENABLE, 0x00);
 			AC_VERB_SET_EAPD_BTLENABLE, 0x00);
@@ -4067,23 +4383,7 @@ static int ca0132_alt_select_out(struct hda_codec *codec)
 		break;
 		break;
 	case SURROUND_OUT:
 	case SURROUND_OUT:
 		codec_dbg(codec, "%s surround\n", __func__);
 		codec_dbg(codec, "%s surround\n", __func__);
-		/* Surround out config*/
-		switch (spec->quirk) {
-		case QUIRK_SBZ:
-			ca0132_mmio_gpio_set(codec, 7, false);
-			ca0132_mmio_gpio_set(codec, 4, true);
-			ca0132_mmio_gpio_set(codec, 1, true);
-			chipio_set_control_param(codec, 0x0D, 0x18);
-			break;
-		case QUIRK_R3DI:
-			chipio_set_control_param(codec, 0x0D, 0x24);
-			r3di_gpio_out_set(codec, R3DI_LINE_OUT);
-			break;
-		case QUIRK_R3D:
-			ca0132_mmio_gpio_set(codec, 1, true);
-			chipio_set_control_param(codec, 0x0D, 0x24);
-			break;
-		}
+
 		/* enable line out node */
 		/* enable line out node */
 		pin_ctl = snd_hda_codec_read(codec, spec->out_pins[0], 0,
 		pin_ctl = snd_hda_codec_read(codec, spec->out_pins[0], 0,
 				AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
 				AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
@@ -4108,14 +4408,21 @@ static int ca0132_alt_select_out(struct hda_codec *codec)
 		snd_hda_set_pin_ctl(codec, spec->out_pins[3],
 		snd_hda_set_pin_ctl(codec, spec->out_pins[3],
 				    pin_ctl | PIN_OUT);
 				    pin_ctl | PIN_OUT);
 
 
-		if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID])
-			dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_ONE);
-		else
-			dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_EIGHT);
+		dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_EIGHT);
 		break;
 		break;
 	}
 	}
+	/*
+	 * Surround always sets it's scp command to req 0x04 to FLOAT_EIGHT.
+	 * With this set though, X_BASS cannot be enabled. So, if we have OutFX
+	 * enabled, we need to make sure X_BASS is off, otherwise everything
+	 * sounds all muffled. Running ca0132_effects_set with X_BASS as the
+	 * effect should sort this out.
+	 */
+	if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID])
+		ca0132_effects_set(codec, X_BASS,
+			spec->effects_switch[X_BASS - EFFECT_START_NID]);
 
 
-	/* run through the output dsp commands for line-out */
+	/* run through the output dsp commands for the selected output. */
 	for (i = 0; i < alt_out_presets[spec->cur_out_type].commands; i++) {
 	for (i = 0; i < alt_out_presets[spec->cur_out_type].commands; i++) {
 		err = dspio_set_uint_param(codec,
 		err = dspio_set_uint_param(codec,
 		alt_out_presets[spec->cur_out_type].mids[i],
 		alt_out_presets[spec->cur_out_type].mids[i],
@@ -4152,7 +4459,6 @@ static void ca0132_unsol_hp_delayed(struct work_struct *work)
 
 
 static void ca0132_set_dmic(struct hda_codec *codec, int enable);
 static void ca0132_set_dmic(struct hda_codec *codec, int enable);
 static int ca0132_mic_boost_set(struct hda_codec *codec, long val);
 static int ca0132_mic_boost_set(struct hda_codec *codec, long val);
-static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val);
 static void resume_mic1(struct hda_codec *codec, unsigned int oldval);
 static void resume_mic1(struct hda_codec *codec, unsigned int oldval);
 static int stop_mic1(struct hda_codec *codec);
 static int stop_mic1(struct hda_codec *codec);
 static int ca0132_cvoice_switch_set(struct hda_codec *codec);
 static int ca0132_cvoice_switch_set(struct hda_codec *codec);
@@ -4341,13 +4647,20 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
 		switch (spec->quirk) {
 		switch (spec->quirk) {
 		case QUIRK_SBZ:
 		case QUIRK_SBZ:
 		case QUIRK_R3D:
 		case QUIRK_R3D:
-			ca0132_mmio_gpio_set(codec, 0, false);
+			ca0113_mmio_gpio_set(codec, 0, false);
+			tmp = FLOAT_THREE;
+			break;
+		case QUIRK_ZXR:
 			tmp = FLOAT_THREE;
 			tmp = FLOAT_THREE;
 			break;
 			break;
 		case QUIRK_R3DI:
 		case QUIRK_R3DI:
 			r3di_gpio_mic_set(codec, R3DI_REAR_MIC);
 			r3di_gpio_mic_set(codec, R3DI_REAR_MIC);
 			tmp = FLOAT_ONE;
 			tmp = FLOAT_ONE;
 			break;
 			break;
+		case QUIRK_AE5:
+			ca0113_mmio_command_set(codec, 0x48, 0x28, 0x00);
+			tmp = FLOAT_THREE;
+			break;
 		default:
 		default:
 			tmp = FLOAT_ONE;
 			tmp = FLOAT_ONE;
 			break;
 			break;
@@ -4362,10 +4675,19 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
 
 
 		chipio_set_stream_control(codec, 0x03, 1);
 		chipio_set_stream_control(codec, 0x03, 1);
 		chipio_set_stream_control(codec, 0x04, 1);
 		chipio_set_stream_control(codec, 0x04, 1);
-
-		if (spec->quirk == QUIRK_SBZ) {
+		switch (spec->quirk) {
+		case QUIRK_SBZ:
 			chipio_write(codec, 0x18B098, 0x0000000C);
 			chipio_write(codec, 0x18B098, 0x0000000C);
 			chipio_write(codec, 0x18B09C, 0x0000000C);
 			chipio_write(codec, 0x18B09C, 0x0000000C);
+			break;
+		case QUIRK_ZXR:
+			chipio_write(codec, 0x18B098, 0x0000000C);
+			chipio_write(codec, 0x18B09C, 0x000000CC);
+			break;
+		case QUIRK_AE5:
+			chipio_write(codec, 0x18B098, 0x0000000C);
+			chipio_write(codec, 0x18B09C, 0x0000004C);
+			break;
 		}
 		}
 		ca0132_alt_mic_boost_set(codec, spec->mic_boost_enum_val);
 		ca0132_alt_mic_boost_set(codec, spec->mic_boost_enum_val);
 		break;
 		break;
@@ -4374,11 +4696,14 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
 		switch (spec->quirk) {
 		switch (spec->quirk) {
 		case QUIRK_SBZ:
 		case QUIRK_SBZ:
 		case QUIRK_R3D:
 		case QUIRK_R3D:
-			ca0132_mmio_gpio_set(codec, 0, false);
+			ca0113_mmio_gpio_set(codec, 0, false);
 			break;
 			break;
 		case QUIRK_R3DI:
 		case QUIRK_R3DI:
 			r3di_gpio_mic_set(codec, R3DI_REAR_MIC);
 			r3di_gpio_mic_set(codec, R3DI_REAR_MIC);
 			break;
 			break;
+		case QUIRK_AE5:
+			ca0113_mmio_command_set(codec, 0x48, 0x28, 0x00);
+			break;
 		}
 		}
 
 
 		chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
 		chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
@@ -4389,11 +4714,13 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
 		tmp = FLOAT_ZERO;
 		tmp = FLOAT_ZERO;
 		dspio_set_uint_param(codec, 0x80, 0x00, tmp);
 		dspio_set_uint_param(codec, 0x80, 0x00, tmp);
 
 
-		if (spec->quirk == QUIRK_SBZ) {
+		switch (spec->quirk) {
+		case QUIRK_SBZ:
+		case QUIRK_AE5:
 			chipio_write(codec, 0x18B098, 0x00000000);
 			chipio_write(codec, 0x18B098, 0x00000000);
 			chipio_write(codec, 0x18B09C, 0x00000000);
 			chipio_write(codec, 0x18B09C, 0x00000000);
+			break;
 		}
 		}
-
 		chipio_set_stream_control(codec, 0x03, 1);
 		chipio_set_stream_control(codec, 0x03, 1);
 		chipio_set_stream_control(codec, 0x04, 1);
 		chipio_set_stream_control(codec, 0x04, 1);
 		break;
 		break;
@@ -4401,14 +4728,18 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
 		switch (spec->quirk) {
 		switch (spec->quirk) {
 		case QUIRK_SBZ:
 		case QUIRK_SBZ:
 		case QUIRK_R3D:
 		case QUIRK_R3D:
-			ca0132_mmio_gpio_set(codec, 0, true);
-			ca0132_mmio_gpio_set(codec, 5, false);
+			ca0113_mmio_gpio_set(codec, 0, true);
+			ca0113_mmio_gpio_set(codec, 5, false);
 			tmp = FLOAT_THREE;
 			tmp = FLOAT_THREE;
 			break;
 			break;
 		case QUIRK_R3DI:
 		case QUIRK_R3DI:
 			r3di_gpio_mic_set(codec, R3DI_FRONT_MIC);
 			r3di_gpio_mic_set(codec, R3DI_FRONT_MIC);
 			tmp = FLOAT_ONE;
 			tmp = FLOAT_ONE;
 			break;
 			break;
+		case QUIRK_AE5:
+			ca0113_mmio_command_set(codec, 0x48, 0x28, 0x3f);
+			tmp = FLOAT_THREE;
+			break;
 		default:
 		default:
 			tmp = FLOAT_ONE;
 			tmp = FLOAT_ONE;
 			break;
 			break;
@@ -4424,9 +4755,15 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
 		chipio_set_stream_control(codec, 0x03, 1);
 		chipio_set_stream_control(codec, 0x03, 1);
 		chipio_set_stream_control(codec, 0x04, 1);
 		chipio_set_stream_control(codec, 0x04, 1);
 
 
-		if (spec->quirk == QUIRK_SBZ) {
+		switch (spec->quirk) {
+		case QUIRK_SBZ:
 			chipio_write(codec, 0x18B098, 0x0000000C);
 			chipio_write(codec, 0x18B098, 0x0000000C);
 			chipio_write(codec, 0x18B09C, 0x000000CC);
 			chipio_write(codec, 0x18B09C, 0x000000CC);
+			break;
+		case QUIRK_AE5:
+			chipio_write(codec, 0x18B098, 0x0000000C);
+			chipio_write(codec, 0x18B09C, 0x0000004C);
+			break;
 		}
 		}
 		ca0132_alt_mic_boost_set(codec, spec->mic_boost_enum_val);
 		ca0132_alt_mic_boost_set(codec, spec->mic_boost_enum_val);
 		break;
 		break;
@@ -4435,7 +4772,6 @@ static int ca0132_alt_select_in(struct hda_codec *codec)
 
 
 	snd_hda_power_down_pm(codec);
 	snd_hda_power_down_pm(codec);
 	return 0;
 	return 0;
-
 }
 }
 
 
 /*
 /*
@@ -4507,6 +4843,8 @@ static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val)
 		/* if PE if off, turn off out effects. */
 		/* if PE if off, turn off out effects. */
 		if (!spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID])
 		if (!spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID])
 			val = 0;
 			val = 0;
+		if (spec->cur_out_type == SURROUND_OUT && nid == X_BASS)
+			val = 0;
 	}
 	}
 
 
 	/* for in effect, qualify with CrystalVoice */
 	/* for in effect, qualify with CrystalVoice */
@@ -4520,7 +4858,7 @@ static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val)
 			val = 0;
 			val = 0;
 
 
 		/* If Voice Focus on SBZ, set to two channel. */
 		/* If Voice Focus on SBZ, set to two channel. */
-		if ((nid == VOICE_FOCUS) && (spec->quirk == QUIRK_SBZ)
+		if ((nid == VOICE_FOCUS) && (spec->use_pci_mmio)
 				&& (spec->cur_mic_type != REAR_LINE_IN)) {
 				&& (spec->cur_mic_type != REAR_LINE_IN)) {
 			if (spec->effects_switch[CRYSTAL_VOICE -
 			if (spec->effects_switch[CRYSTAL_VOICE -
 						 EFFECT_START_NID]) {
 						 EFFECT_START_NID]) {
@@ -4539,7 +4877,7 @@ static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val)
 		 * For SBZ noise reduction, there's an extra command
 		 * For SBZ noise reduction, there's an extra command
 		 * to module ID 0x47. No clue why.
 		 * to module ID 0x47. No clue why.
 		 */
 		 */
-		if ((nid == NOISE_REDUCTION) && (spec->quirk == QUIRK_SBZ)
+		if ((nid == NOISE_REDUCTION) && (spec->use_pci_mmio)
 				&& (spec->cur_mic_type != REAR_LINE_IN)) {
 				&& (spec->cur_mic_type != REAR_LINE_IN)) {
 			if (spec->effects_switch[CRYSTAL_VOICE -
 			if (spec->effects_switch[CRYSTAL_VOICE -
 						 EFFECT_START_NID]) {
 						 EFFECT_START_NID]) {
@@ -4678,6 +5016,27 @@ static int ca0132_alt_mic_boost_set(struct hda_codec *codec, long val)
 	return ret;
 	return ret;
 }
 }
 
 
+static int ae5_headphone_gain_set(struct hda_codec *codec, long val)
+{
+	unsigned int i;
+
+	for (i = 0; i < 4; i++)
+		ca0113_mmio_command_set(codec, 0x48, 0x11 + i,
+				ae5_headphone_gain_presets[val].vals[i]);
+	return 0;
+}
+
+/*
+ * gpio pin 1 is a relay that switches on/off, apparently setting the headphone
+ * amplifier to handle a 600 ohm load.
+ */
+static int zxr_headphone_gain_set(struct hda_codec *codec, long val)
+{
+	ca0113_mmio_gpio_set(codec, 1, val);
+
+	return 0;
+}
+
 static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol,
 static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 				struct snd_ctl_elem_value *ucontrol)
 {
 {
@@ -4942,66 +5301,172 @@ static int ca0132_alt_mic_boost_put(struct snd_kcontrol *kcontrol,
 	return 1;
 	return 1;
 }
 }
 
 
-
 /*
 /*
- * Input Select Control for alternative ca0132 codecs. This exists because
- * front microphone has no auto-detect, and we need a way to set the rear
- * as line-in
+ * Sound BlasterX AE-5 Headphone Gain Controls.
  */
  */
-static int ca0132_alt_input_source_info(struct snd_kcontrol *kcontrol,
+#define AE5_HEADPHONE_GAIN_MAX 3
+static int ae5_headphone_gain_info(struct snd_kcontrol *kcontrol,
 				 struct snd_ctl_elem_info *uinfo)
 				 struct snd_ctl_elem_info *uinfo)
 {
 {
+	char *sfx = " Ohms)";
+	char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->count = 1;
 	uinfo->count = 1;
-	uinfo->value.enumerated.items = IN_SRC_NUM_OF_INPUTS;
-	if (uinfo->value.enumerated.item >= IN_SRC_NUM_OF_INPUTS)
-		uinfo->value.enumerated.item = IN_SRC_NUM_OF_INPUTS - 1;
-	strcpy(uinfo->value.enumerated.name,
-			in_src_str[uinfo->value.enumerated.item]);
+	uinfo->value.enumerated.items = AE5_HEADPHONE_GAIN_MAX;
+	if (uinfo->value.enumerated.item >= AE5_HEADPHONE_GAIN_MAX)
+		uinfo->value.enumerated.item = AE5_HEADPHONE_GAIN_MAX - 1;
+	sprintf(namestr, "%s %s",
+		ae5_headphone_gain_presets[uinfo->value.enumerated.item].name,
+		sfx);
+	strcpy(uinfo->value.enumerated.name, namestr);
 	return 0;
 	return 0;
 }
 }
 
 
-static int ca0132_alt_input_source_get(struct snd_kcontrol *kcontrol,
+static int ae5_headphone_gain_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 				struct snd_ctl_elem_value *ucontrol)
 {
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct ca0132_spec *spec = codec->spec;
 	struct ca0132_spec *spec = codec->spec;
 
 
-	ucontrol->value.enumerated.item[0] = spec->in_enum_val;
+	ucontrol->value.enumerated.item[0] = spec->ae5_headphone_gain_val;
 	return 0;
 	return 0;
 }
 }
 
 
-static int ca0132_alt_input_source_put(struct snd_kcontrol *kcontrol,
+static int ae5_headphone_gain_put(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 				struct snd_ctl_elem_value *ucontrol)
 {
 {
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 	struct ca0132_spec *spec = codec->spec;
 	struct ca0132_spec *spec = codec->spec;
 	int sel = ucontrol->value.enumerated.item[0];
 	int sel = ucontrol->value.enumerated.item[0];
-	unsigned int items = IN_SRC_NUM_OF_INPUTS;
+	unsigned int items = AE5_HEADPHONE_GAIN_MAX;
 
 
 	if (sel >= items)
 	if (sel >= items)
 		return 0;
 		return 0;
 
 
-	codec_dbg(codec, "ca0132_alt_input_select: sel=%d, preset=%s\n",
-		    sel, in_src_str[sel]);
+	codec_dbg(codec, "ae5_headphone_gain: boost=%d\n",
+		    sel);
 
 
-	spec->in_enum_val = sel;
+	spec->ae5_headphone_gain_val = sel;
 
 
-	ca0132_alt_select_in(codec);
+	if (spec->out_enum_val == HEADPHONE_OUT)
+		ae5_headphone_gain_set(codec, spec->ae5_headphone_gain_val);
 
 
 	return 1;
 	return 1;
 }
 }
 
 
-/* Sound Blaster Z Output Select Control */
-static int ca0132_alt_output_select_get_info(struct snd_kcontrol *kcontrol,
+/*
+ * Sound BlasterX AE-5 sound filter enumerated control.
+ */
+#define AE5_SOUND_FILTER_MAX 3
+
+static int ae5_sound_filter_info(struct snd_kcontrol *kcontrol,
 				 struct snd_ctl_elem_info *uinfo)
 				 struct snd_ctl_elem_info *uinfo)
 {
 {
+	char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
 	uinfo->count = 1;
 	uinfo->count = 1;
-	uinfo->value.enumerated.items = NUM_OF_OUTPUTS;
-	if (uinfo->value.enumerated.item >= NUM_OF_OUTPUTS)
-		uinfo->value.enumerated.item = NUM_OF_OUTPUTS - 1;
-	strcpy(uinfo->value.enumerated.name,
+	uinfo->value.enumerated.items = AE5_SOUND_FILTER_MAX;
+	if (uinfo->value.enumerated.item >= AE5_SOUND_FILTER_MAX)
+		uinfo->value.enumerated.item = AE5_SOUND_FILTER_MAX - 1;
+	sprintf(namestr, "%s",
+			ae5_filter_presets[uinfo->value.enumerated.item].name);
+	strcpy(uinfo->value.enumerated.name, namestr);
+	return 0;
+}
+
+static int ae5_sound_filter_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct ca0132_spec *spec = codec->spec;
+
+	ucontrol->value.enumerated.item[0] = spec->ae5_filter_val;
+	return 0;
+}
+
+static int ae5_sound_filter_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct ca0132_spec *spec = codec->spec;
+	int sel = ucontrol->value.enumerated.item[0];
+	unsigned int items = AE5_SOUND_FILTER_MAX;
+
+	if (sel >= items)
+		return 0;
+
+	codec_dbg(codec, "ae5_sound_filter: %s\n",
+			ae5_filter_presets[sel].name);
+
+	spec->ae5_filter_val = sel;
+
+	ca0113_mmio_command_set_type2(codec, 0x48, 0x07,
+			ae5_filter_presets[sel].val);
+
+	return 1;
+}
+
+/*
+ * Input Select Control for alternative ca0132 codecs. This exists because
+ * front microphone has no auto-detect, and we need a way to set the rear
+ * as line-in
+ */
+static int ca0132_alt_input_source_info(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = IN_SRC_NUM_OF_INPUTS;
+	if (uinfo->value.enumerated.item >= IN_SRC_NUM_OF_INPUTS)
+		uinfo->value.enumerated.item = IN_SRC_NUM_OF_INPUTS - 1;
+	strcpy(uinfo->value.enumerated.name,
+			in_src_str[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int ca0132_alt_input_source_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct ca0132_spec *spec = codec->spec;
+
+	ucontrol->value.enumerated.item[0] = spec->in_enum_val;
+	return 0;
+}
+
+static int ca0132_alt_input_source_put(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct ca0132_spec *spec = codec->spec;
+	int sel = ucontrol->value.enumerated.item[0];
+	unsigned int items = IN_SRC_NUM_OF_INPUTS;
+
+	if (sel >= items)
+		return 0;
+
+	codec_dbg(codec, "ca0132_alt_input_select: sel=%d, preset=%s\n",
+		    sel, in_src_str[sel]);
+
+	spec->in_enum_val = sel;
+
+	ca0132_alt_select_in(codec);
+
+	return 1;
+}
+
+/* Sound Blaster Z Output Select Control */
+static int ca0132_alt_output_select_get_info(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = NUM_OF_OUTPUTS;
+	if (uinfo->value.enumerated.item >= NUM_OF_OUTPUTS)
+		uinfo->value.enumerated.item = NUM_OF_OUTPUTS - 1;
+	strcpy(uinfo->value.enumerated.name,
 			alt_out_presets[uinfo->value.enumerated.item].name);
 			alt_out_presets[uinfo->value.enumerated.item].name);
 	return 0;
 	return 0;
 }
 }
@@ -5330,6 +5795,16 @@ static int ca0132_switch_put(struct snd_kcontrol *kcontrol,
 		goto exit;
 		goto exit;
 	}
 	}
 
 
+	if (nid == ZXR_HEADPHONE_GAIN) {
+		spec->zxr_gain_set = *valp;
+		if (spec->cur_out_type == HEADPHONE_OUT)
+			changed = zxr_headphone_gain_set(codec, *valp);
+		else
+			changed = 0;
+
+		goto exit;
+	}
+
 exit:
 exit:
 	snd_hda_power_down(codec);
 	snd_hda_power_down(codec);
 	return changed;
 	return changed;
@@ -5704,6 +6179,50 @@ static int ca0132_alt_add_mic_boost_enum(struct hda_codec *codec)
 
 
 }
 }
 
 
+/*
+ * Add headphone gain enumerated control for the AE-5. This switches between
+ * three modes, low, medium, and high. When non-headphone outputs are selected,
+ * it is automatically set to high. This is the same behavior as Windows.
+ */
+static int ae5_add_headphone_gain_enum(struct hda_codec *codec)
+{
+	struct snd_kcontrol_new knew =
+		HDA_CODEC_MUTE_MONO("AE-5: Headphone Gain",
+				    AE5_HEADPHONE_GAIN_ENUM, 1, 0, HDA_OUTPUT);
+	knew.info = ae5_headphone_gain_info;
+	knew.get = ae5_headphone_gain_get;
+	knew.put = ae5_headphone_gain_put;
+	return snd_hda_ctl_add(codec, AE5_HEADPHONE_GAIN_ENUM,
+				snd_ctl_new1(&knew, codec));
+}
+
+/*
+ * Add sound filter enumerated control for the AE-5. This adds three different
+ * settings: Slow Roll Off, Minimum Phase, and Fast Roll Off. From what I've
+ * read into it, it changes the DAC's interpolation filter.
+ */
+static int ae5_add_sound_filter_enum(struct hda_codec *codec)
+{
+	struct snd_kcontrol_new knew =
+		HDA_CODEC_MUTE_MONO("AE-5: Sound Filter",
+				    AE5_SOUND_FILTER_ENUM, 1, 0, HDA_OUTPUT);
+	knew.info = ae5_sound_filter_info;
+	knew.get = ae5_sound_filter_get;
+	knew.put = ae5_sound_filter_put;
+	return snd_hda_ctl_add(codec, AE5_SOUND_FILTER_ENUM,
+				snd_ctl_new1(&knew, codec));
+}
+
+static int zxr_add_headphone_gain_switch(struct hda_codec *codec)
+{
+	struct snd_kcontrol_new knew =
+		CA0132_CODEC_MUTE_MONO("ZxR: 600 Ohm Gain",
+				    ZXR_HEADPHONE_GAIN, 1, HDA_OUTPUT);
+
+	return snd_hda_ctl_add(codec, ZXR_HEADPHONE_GAIN,
+				snd_ctl_new1(&knew, codec));
+}
+
 /*
 /*
  * Need to create slave controls for the alternate codecs that have surround
  * Need to create slave controls for the alternate codecs that have surround
  * capabilities.
  * capabilities.
@@ -5847,7 +6366,8 @@ static int ca0132_build_controls(struct hda_codec *codec)
 					    NULL, ca0132_alt_slave_pfxs,
 					    NULL, ca0132_alt_slave_pfxs,
 					    "Playback Switch",
 					    "Playback Switch",
 					    true, &spec->vmaster_mute.sw_kctl);
 					    true, &spec->vmaster_mute.sw_kctl);
-
+		if (err < 0)
+			return err;
 	}
 	}
 
 
 	/* Add in and out effects controls.
 	/* Add in and out effects controls.
@@ -5855,8 +6375,8 @@ static int ca0132_build_controls(struct hda_codec *codec)
 	 */
 	 */
 	num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT;
 	num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT;
 	for (i = 0; i < num_fx; i++) {
 	for (i = 0; i < num_fx; i++) {
-		/* SBZ and R3D break if Echo Cancellation is used. */
-		if (spec->quirk == QUIRK_SBZ || spec->quirk == QUIRK_R3D) {
+		/* Desktop cards break if Echo Cancellation is used. */
+		if (spec->use_pci_mmio) {
 			if (i == (ECHO_CANCELLATION - IN_EFFECT_START_NID +
 			if (i == (ECHO_CANCELLATION - IN_EFFECT_START_NID +
 						OUT_EFFECTS_COUNT))
 						OUT_EFFECTS_COUNT))
 				continue;
 				continue;
@@ -5874,8 +6394,14 @@ static int ca0132_build_controls(struct hda_codec *codec)
 	 * prefix, and change PlayEnhancement and CrystalVoice to match.
 	 * prefix, and change PlayEnhancement and CrystalVoice to match.
 	 */
 	 */
 	if (spec->use_alt_controls) {
 	if (spec->use_alt_controls) {
-		ca0132_alt_add_svm_enum(codec);
-		add_ca0132_alt_eq_presets(codec);
+		err = ca0132_alt_add_svm_enum(codec);
+		if (err < 0)
+			return err;
+
+		err = add_ca0132_alt_eq_presets(codec);
+		if (err < 0)
+			return err;
+
 		err = add_fx_switch(codec, PLAY_ENHANCEMENT,
 		err = add_fx_switch(codec, PLAY_ENHANCEMENT,
 					"Enable OutFX", 0);
 					"Enable OutFX", 0);
 		if (err < 0)
 		if (err < 0)
@@ -5912,7 +6438,9 @@ static int ca0132_build_controls(struct hda_codec *codec)
 		if (err < 0)
 		if (err < 0)
 			return err;
 			return err;
 	}
 	}
-	add_voicefx(codec);
+	err = add_voicefx(codec);
+	if (err < 0)
+		return err;
 
 
 	/*
 	/*
 	 * If the codec uses alt_functions, you need the enumerated controls
 	 * If the codec uses alt_functions, you need the enumerated controls
@@ -5920,9 +6448,36 @@ static int ca0132_build_controls(struct hda_codec *codec)
 	 * setting control.
 	 * setting control.
 	 */
 	 */
 	if (spec->use_alt_functions) {
 	if (spec->use_alt_functions) {
-		ca0132_alt_add_output_enum(codec);
-		ca0132_alt_add_input_enum(codec);
-		ca0132_alt_add_mic_boost_enum(codec);
+		err = ca0132_alt_add_output_enum(codec);
+		if (err < 0)
+			return err;
+		err = ca0132_alt_add_mic_boost_enum(codec);
+		if (err < 0)
+			return err;
+		/*
+		 * ZxR only has microphone input, there is no front panel
+		 * header on the card, and aux-in is handled by the DBPro board.
+		 */
+		if (spec->quirk != QUIRK_ZXR) {
+			err = ca0132_alt_add_input_enum(codec);
+			if (err < 0)
+				return err;
+		}
+	}
+
+	if (spec->quirk == QUIRK_AE5) {
+		err = ae5_add_headphone_gain_enum(codec);
+		if (err < 0)
+			return err;
+		err = ae5_add_sound_filter_enum(codec);
+		if (err < 0)
+			return err;
+	}
+
+	if (spec->quirk == QUIRK_ZXR) {
+		err = zxr_add_headphone_gain_switch(codec);
+		if (err < 0)
+			return err;
 	}
 	}
 #ifdef ENABLE_TUNING_CONTROLS
 #ifdef ENABLE_TUNING_CONTROLS
 	add_tuning_ctls(codec);
 	add_tuning_ctls(codec);
@@ -5955,6 +6510,27 @@ static int ca0132_build_controls(struct hda_codec *codec)
 	return 0;
 	return 0;
 }
 }
 
 
+static int dbpro_build_controls(struct hda_codec *codec)
+{
+	struct ca0132_spec *spec = codec->spec;
+	int err = 0;
+
+	if (spec->dig_out) {
+		err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out,
+				spec->dig_out);
+		if (err < 0)
+			return err;
+	}
+
+	if (spec->dig_in) {
+		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
 /*
 /*
  * PCM
  * PCM
  */
  */
@@ -6058,6 +6634,40 @@ static int ca0132_build_pcms(struct hda_codec *codec)
 	return 0;
 	return 0;
 }
 }
 
 
+static int dbpro_build_pcms(struct hda_codec *codec)
+{
+	struct ca0132_spec *spec = codec->spec;
+	struct hda_pcm *info;
+
+	info = snd_hda_codec_pcm_new(codec, "CA0132 Alt Analog");
+	if (!info)
+		return -ENOMEM;
+	info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture;
+	info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1;
+	info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0];
+
+
+	if (!spec->dig_out && !spec->dig_in)
+		return 0;
+
+	info = snd_hda_codec_pcm_new(codec, "CA0132 Digital");
+	if (!info)
+		return -ENOMEM;
+	info->pcm_type = HDA_PCM_TYPE_SPDIF;
+	if (spec->dig_out) {
+		info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
+			ca0132_pcm_digital_playback;
+		info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dig_out;
+	}
+	if (spec->dig_in) {
+		info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+			ca0132_pcm_digital_capture;
+		info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in;
+	}
+
+	return 0;
+}
+
 static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
 static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
 {
 {
 	if (pin) {
 	if (pin) {
@@ -6238,69 +6848,48 @@ static void ca0132_refresh_widget_caps(struct hda_codec *codec)
 }
 }
 
 
 /*
 /*
- * Recon3D r3d_setup_defaults sub functions.
+ * Creates a dummy stream to bind the output to. This seems to have to be done
+ * after changing the main outputs source and destination streams.
  */
  */
-
-static void r3d_dsp_scp_startup(struct hda_codec *codec)
+static void ca0132_alt_create_dummy_stream(struct hda_codec *codec)
 {
 {
-	unsigned int tmp;
-
-	tmp = 0x00000000;
-	dspio_set_uint_param_no_source(codec, 0x80, 0x0A, tmp);
-
-	tmp = 0x00000001;
-	dspio_set_uint_param_no_source(codec, 0x80, 0x0B, tmp);
-
-	tmp = 0x00000004;
-	dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
-
-	tmp = 0x00000005;
-	dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
-
-	tmp = 0x00000000;
-	dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
-
-}
+	struct ca0132_spec *spec = codec->spec;
+	unsigned int stream_format;
 
 
-static void r3d_dsp_initial_mic_setup(struct hda_codec *codec)
-{
-	unsigned int tmp;
+	stream_format = snd_hdac_calc_stream_format(48000, 2,
+			SNDRV_PCM_FORMAT_S32_LE, 32, 0);
 
 
-	/* Mic 1 Setup */
-	chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
-	chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
-	/* This ConnPointID is unique to Recon3Di. Haven't seen it elsewhere */
-	chipio_set_conn_rate(codec, 0x0F, SR_96_000);
-	tmp = FLOAT_ONE;
-	dspio_set_uint_param(codec, 0x80, 0x00, tmp);
+	snd_hda_codec_setup_stream(codec, spec->dacs[0], spec->dsp_stream_id,
+					0, stream_format);
 
 
-	/* Mic 2 Setup, even though it isn't connected on SBZ */
-	chipio_set_conn_rate(codec, MEM_CONNID_MICIN2, SR_96_000);
-	chipio_set_conn_rate(codec, MEM_CONNID_MICOUT2, SR_96_000);
-	chipio_set_conn_rate(codec, 0x0F, SR_96_000);
-	tmp = FLOAT_ZERO;
-	dspio_set_uint_param(codec, 0x80, 0x01, tmp);
+	snd_hda_codec_cleanup_stream(codec, spec->dacs[0]);
 }
 }
 
 
 /*
 /*
- * Initialize Sound Blaster Z analog microphones.
+ * Initialize mic for non-chromebook ca0132 implementations.
  */
  */
-static void sbz_init_analog_mics(struct hda_codec *codec)
+static void ca0132_alt_init_analog_mics(struct hda_codec *codec)
 {
 {
+	struct ca0132_spec *spec = codec->spec;
 	unsigned int tmp;
 	unsigned int tmp;
 
 
 	/* Mic 1 Setup */
 	/* Mic 1 Setup */
 	chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
 	chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
 	chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
 	chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
-	tmp = FLOAT_THREE;
+	if (spec->quirk == QUIRK_R3DI) {
+		chipio_set_conn_rate(codec, 0x0F, SR_96_000);
+		tmp = FLOAT_ONE;
+	} else
+		tmp = FLOAT_THREE;
 	dspio_set_uint_param(codec, 0x80, 0x00, tmp);
 	dspio_set_uint_param(codec, 0x80, 0x00, tmp);
 
 
-	/* Mic 2 Setup, even though it isn't connected on SBZ */
+	/* Mic 2 setup (not present on desktop cards) */
 	chipio_set_conn_rate(codec, MEM_CONNID_MICIN2, SR_96_000);
 	chipio_set_conn_rate(codec, MEM_CONNID_MICIN2, SR_96_000);
 	chipio_set_conn_rate(codec, MEM_CONNID_MICOUT2, SR_96_000);
 	chipio_set_conn_rate(codec, MEM_CONNID_MICOUT2, SR_96_000);
+	if (spec->quirk == QUIRK_R3DI)
+		chipio_set_conn_rate(codec, 0x0F, SR_96_000);
 	tmp = FLOAT_ZERO;
 	tmp = FLOAT_ZERO;
 	dspio_set_uint_param(codec, 0x80, 0x01, tmp);
 	dspio_set_uint_param(codec, 0x80, 0x01, tmp);
-
 }
 }
 
 
 /*
 /*
@@ -6333,7 +6922,6 @@ static void sbz_connect_streams(struct hda_codec *codec)
 	codec_dbg(codec, "Connect Streams exited, mutex released.\n");
 	codec_dbg(codec, "Connect Streams exited, mutex released.\n");
 
 
 	mutex_unlock(&spec->chipio_mutex);
 	mutex_unlock(&spec->chipio_mutex);
-
 }
 }
 
 
 /*
 /*
@@ -6360,19 +6948,29 @@ static void sbz_chipio_startup_data(struct hda_codec *codec)
 	chipio_set_stream_channels(codec, 0x0C, 6);
 	chipio_set_stream_channels(codec, 0x0C, 6);
 	chipio_set_stream_control(codec, 0x0C, 1);
 	chipio_set_stream_control(codec, 0x0C, 1);
 	/* No clue what these control */
 	/* No clue what these control */
-	chipio_write_no_mutex(codec, 0x190030, 0x0001e0c0);
-	chipio_write_no_mutex(codec, 0x190034, 0x0001e1c1);
-	chipio_write_no_mutex(codec, 0x190038, 0x0001e4c2);
-	chipio_write_no_mutex(codec, 0x19003c, 0x0001e5c3);
-	chipio_write_no_mutex(codec, 0x190040, 0x0001e2c4);
-	chipio_write_no_mutex(codec, 0x190044, 0x0001e3c5);
-	chipio_write_no_mutex(codec, 0x190048, 0x0001e8c6);
-	chipio_write_no_mutex(codec, 0x19004c, 0x0001e9c7);
-	chipio_write_no_mutex(codec, 0x190050, 0x0001ecc8);
-	chipio_write_no_mutex(codec, 0x190054, 0x0001edc9);
-	chipio_write_no_mutex(codec, 0x190058, 0x0001eaca);
-	chipio_write_no_mutex(codec, 0x19005c, 0x0001ebcb);
-
+	if (spec->quirk == QUIRK_SBZ) {
+		chipio_write_no_mutex(codec, 0x190030, 0x0001e0c0);
+		chipio_write_no_mutex(codec, 0x190034, 0x0001e1c1);
+		chipio_write_no_mutex(codec, 0x190038, 0x0001e4c2);
+		chipio_write_no_mutex(codec, 0x19003c, 0x0001e5c3);
+		chipio_write_no_mutex(codec, 0x190040, 0x0001e2c4);
+		chipio_write_no_mutex(codec, 0x190044, 0x0001e3c5);
+		chipio_write_no_mutex(codec, 0x190048, 0x0001e8c6);
+		chipio_write_no_mutex(codec, 0x19004c, 0x0001e9c7);
+		chipio_write_no_mutex(codec, 0x190050, 0x0001ecc8);
+		chipio_write_no_mutex(codec, 0x190054, 0x0001edc9);
+		chipio_write_no_mutex(codec, 0x190058, 0x0001eaca);
+		chipio_write_no_mutex(codec, 0x19005c, 0x0001ebcb);
+	} else if (spec->quirk == QUIRK_ZXR) {
+		chipio_write_no_mutex(codec, 0x190038, 0x000140c2);
+		chipio_write_no_mutex(codec, 0x19003c, 0x000141c3);
+		chipio_write_no_mutex(codec, 0x190040, 0x000150c4);
+		chipio_write_no_mutex(codec, 0x190044, 0x000151c5);
+		chipio_write_no_mutex(codec, 0x190050, 0x000142c8);
+		chipio_write_no_mutex(codec, 0x190054, 0x000143c9);
+		chipio_write_no_mutex(codec, 0x190058, 0x000152ca);
+		chipio_write_no_mutex(codec, 0x19005c, 0x000153cb);
+	}
 	chipio_write_no_mutex(codec, 0x19042c, 0x00000001);
 	chipio_write_no_mutex(codec, 0x19042c, 0x00000001);
 
 
 	codec_dbg(codec, "Startup Data exited, mutex released.\n");
 	codec_dbg(codec, "Startup Data exited, mutex released.\n");
@@ -6380,35 +6978,56 @@ static void sbz_chipio_startup_data(struct hda_codec *codec)
 }
 }
 
 
 /*
 /*
- * Sound Blaster Z uses these after DSP is loaded. Weird SCP commands
- * without a 0x20 source like normal.
+ * Custom DSP SCP commands where the src value is 0x00 instead of 0x20. This is
+ * done after the DSP is loaded.
  */
  */
-static void sbz_dsp_scp_startup(struct hda_codec *codec)
+static void ca0132_alt_dsp_scp_startup(struct hda_codec *codec)
 {
 {
-	unsigned int tmp;
-
-	tmp = 0x00000003;
-	dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
-
-	tmp = 0x00000000;
-	dspio_set_uint_param_no_source(codec, 0x80, 0x0A, tmp);
-
-	tmp = 0x00000001;
-	dspio_set_uint_param_no_source(codec, 0x80, 0x0B, tmp);
-
-	tmp = 0x00000004;
-	dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
-
-	tmp = 0x00000005;
-	dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
-
-	tmp = 0x00000000;
-	dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
+	struct ca0132_spec *spec = codec->spec;
+	unsigned int tmp, i;
 
 
+	/*
+	 * Gotta run these twice, or else mic works inconsistently. Not clear
+	 * why this is, but multiple tests have confirmed it.
+	 */
+	for (i = 0; i < 2; i++) {
+		switch (spec->quirk) {
+		case QUIRK_SBZ:
+		case QUIRK_AE5:
+			tmp = 0x00000003;
+			dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
+			tmp = 0x00000000;
+			dspio_set_uint_param_no_source(codec, 0x80, 0x0A, tmp);
+			tmp = 0x00000001;
+			dspio_set_uint_param_no_source(codec, 0x80, 0x0B, tmp);
+			tmp = 0x00000004;
+			dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
+			tmp = 0x00000005;
+			dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
+			tmp = 0x00000000;
+			dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
+			break;
+		case QUIRK_R3D:
+		case QUIRK_R3DI:
+			tmp = 0x00000000;
+			dspio_set_uint_param_no_source(codec, 0x80, 0x0A, tmp);
+			tmp = 0x00000001;
+			dspio_set_uint_param_no_source(codec, 0x80, 0x0B, tmp);
+			tmp = 0x00000004;
+			dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
+			tmp = 0x00000005;
+			dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
+			tmp = 0x00000000;
+			dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp);
+			break;
+		}
+		msleep(100);
+	}
 }
 }
 
 
-static void sbz_dsp_initial_mic_setup(struct hda_codec *codec)
+static void ca0132_alt_dsp_initial_mic_setup(struct hda_codec *codec)
 {
 {
+	struct ca0132_spec *spec = codec->spec;
 	unsigned int tmp;
 	unsigned int tmp;
 
 
 	chipio_set_stream_control(codec, 0x03, 0);
 	chipio_set_stream_control(codec, 0x03, 0);
@@ -6423,17 +7042,170 @@ static void sbz_dsp_initial_mic_setup(struct hda_codec *codec)
 	chipio_set_stream_control(codec, 0x03, 1);
 	chipio_set_stream_control(codec, 0x03, 1);
 	chipio_set_stream_control(codec, 0x04, 1);
 	chipio_set_stream_control(codec, 0x04, 1);
 
 
-	chipio_write(codec, 0x18b098, 0x0000000c);
-	chipio_write(codec, 0x18b09C, 0x0000000c);
+	switch (spec->quirk) {
+	case QUIRK_SBZ:
+		chipio_write(codec, 0x18b098, 0x0000000c);
+		chipio_write(codec, 0x18b09C, 0x0000000c);
+		break;
+	case QUIRK_AE5:
+		chipio_write(codec, 0x18b098, 0x0000000c);
+		chipio_write(codec, 0x18b09c, 0x0000004c);
+		break;
+	}
 }
 }
 
 
-/*
- * Setup default parameters for DSP
- */
-static void ca0132_setup_defaults(struct hda_codec *codec)
+static void ae5_post_dsp_register_set(struct hda_codec *codec)
 {
 {
 	struct ca0132_spec *spec = codec->spec;
 	struct ca0132_spec *spec = codec->spec;
-	unsigned int tmp;
+
+	chipio_8051_write_direct(codec, 0x93, 0x10);
+	snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+			    VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x44);
+	snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+			    VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc2);
+
+	writeb(0xff, spec->mem_base + 0x304);
+	writeb(0xff, spec->mem_base + 0x304);
+	writeb(0xff, spec->mem_base + 0x304);
+	writeb(0xff, spec->mem_base + 0x304);
+	writeb(0x00, spec->mem_base + 0x100);
+	writeb(0xff, spec->mem_base + 0x304);
+	writeb(0x00, spec->mem_base + 0x100);
+	writeb(0xff, spec->mem_base + 0x304);
+	writeb(0x00, spec->mem_base + 0x100);
+	writeb(0xff, spec->mem_base + 0x304);
+	writeb(0x00, spec->mem_base + 0x100);
+	writeb(0xff, spec->mem_base + 0x304);
+
+	ca0113_mmio_command_set(codec, 0x30, 0x2b, 0x3f);
+	ca0113_mmio_command_set(codec, 0x30, 0x2d, 0x3f);
+	ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83);
+}
+
+static void ae5_post_dsp_param_setup(struct hda_codec *codec)
+{
+	/*
+	 * Param3 in the 8051's memory is represented by the ascii string 'mch'
+	 * which seems to be 'multichannel'. This is also mentioned in the
+	 * AE-5's registry values in Windows.
+	 */
+	chipio_set_control_param(codec, 3, 0);
+	/*
+	 * I believe ASI is 'audio serial interface' and that it's used to
+	 * change colors on the external LED strip connected to the AE-5.
+	 */
+	chipio_set_control_flag(codec, CONTROL_FLAG_ASI_96KHZ, 1);
+
+	snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x724, 0x83);
+	chipio_set_control_param(codec, CONTROL_PARAM_ASI, 0);
+
+	snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+			    VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x92);
+	snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+			    VENDOR_CHIPIO_8051_ADDRESS_HIGH, 0xfa);
+	snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+			    VENDOR_CHIPIO_8051_DATA_WRITE, 0x22);
+}
+
+static void ae5_post_dsp_pll_setup(struct hda_codec *codec)
+{
+	snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+			    VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x41);
+	snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+			    VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc8);
+
+	snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+			    VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x45);
+	snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+			    VENDOR_CHIPIO_PLL_PMU_WRITE, 0xcc);
+
+	snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+			    VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x40);
+	snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+			    VENDOR_CHIPIO_PLL_PMU_WRITE, 0xcb);
+
+	snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+			    VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x43);
+	snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+			    VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc7);
+
+	snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+			    VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x51);
+	snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+			    VENDOR_CHIPIO_PLL_PMU_WRITE, 0x8d);
+}
+
+static void ae5_post_dsp_stream_setup(struct hda_codec *codec)
+{
+	struct ca0132_spec *spec = codec->spec;
+
+	mutex_lock(&spec->chipio_mutex);
+
+	snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x725, 0x81);
+
+	chipio_set_conn_rate_no_mutex(codec, 0x70, SR_96_000);
+
+	chipio_set_stream_channels(codec, 0x0C, 6);
+	chipio_set_stream_control(codec, 0x0C, 1);
+
+	chipio_set_stream_source_dest(codec, 0x5, 0x43, 0x0);
+
+	chipio_set_stream_source_dest(codec, 0x18, 0x9, 0xd0);
+	chipio_set_conn_rate_no_mutex(codec, 0xd0, SR_96_000);
+	chipio_set_stream_channels(codec, 0x18, 6);
+	chipio_set_stream_control(codec, 0x18, 1);
+
+	chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_ASI, 4);
+
+	snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+			    VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x43);
+	snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+			    VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc7);
+
+	ca0113_mmio_command_set(codec, 0x48, 0x01, 0x80);
+
+	mutex_unlock(&spec->chipio_mutex);
+}
+
+static void ae5_post_dsp_startup_data(struct hda_codec *codec)
+{
+	struct ca0132_spec *spec = codec->spec;
+
+	mutex_lock(&spec->chipio_mutex);
+
+	chipio_write_no_mutex(codec, 0x189000, 0x0001f101);
+	chipio_write_no_mutex(codec, 0x189004, 0x0001f101);
+	chipio_write_no_mutex(codec, 0x189024, 0x00014004);
+	chipio_write_no_mutex(codec, 0x189028, 0x0002000f);
+
+	ca0113_mmio_command_set(codec, 0x48, 0x0a, 0x05);
+	chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_ASI, 7);
+	ca0113_mmio_command_set(codec, 0x48, 0x0b, 0x12);
+	ca0113_mmio_command_set(codec, 0x48, 0x04, 0x00);
+	ca0113_mmio_command_set(codec, 0x48, 0x06, 0x48);
+	ca0113_mmio_command_set(codec, 0x48, 0x0a, 0x05);
+	ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83);
+	ca0113_mmio_command_set(codec, 0x48, 0x0f, 0x00);
+	ca0113_mmio_command_set(codec, 0x48, 0x10, 0x00);
+	ca0113_mmio_gpio_set(codec, 0, true);
+	ca0113_mmio_gpio_set(codec, 1, true);
+	ca0113_mmio_command_set(codec, 0x48, 0x07, 0x80);
+
+	chipio_write_no_mutex(codec, 0x18b03c, 0x00000012);
+
+	ca0113_mmio_command_set(codec, 0x48, 0x0f, 0x00);
+	ca0113_mmio_command_set(codec, 0x48, 0x10, 0x00);
+
+	mutex_unlock(&spec->chipio_mutex);
+}
+
+/*
+ * Setup default parameters for DSP
+ */
+static void ca0132_setup_defaults(struct hda_codec *codec)
+{
+	struct ca0132_spec *spec = codec->spec;
+	unsigned int tmp;
 	int num_fx;
 	int num_fx;
 	int idx, i;
 	int idx, i;
 
 
@@ -6485,9 +7257,8 @@ static void r3d_setup_defaults(struct hda_codec *codec)
 	if (spec->dsp_state != DSP_DOWNLOADED)
 	if (spec->dsp_state != DSP_DOWNLOADED)
 		return;
 		return;
 
 
-	r3d_dsp_scp_startup(codec);
-
-	r3d_dsp_initial_mic_setup(codec);
+	ca0132_alt_dsp_scp_startup(codec);
+	ca0132_alt_init_analog_mics(codec);
 
 
 	/*remove DSP headroom*/
 	/*remove DSP headroom*/
 	tmp = FLOAT_ZERO;
 	tmp = FLOAT_ZERO;
@@ -6523,19 +7294,16 @@ static void r3d_setup_defaults(struct hda_codec *codec)
 static void sbz_setup_defaults(struct hda_codec *codec)
 static void sbz_setup_defaults(struct hda_codec *codec)
 {
 {
 	struct ca0132_spec *spec = codec->spec;
 	struct ca0132_spec *spec = codec->spec;
-	unsigned int tmp, stream_format;
+	unsigned int tmp;
 	int num_fx;
 	int num_fx;
 	int idx, i;
 	int idx, i;
 
 
 	if (spec->dsp_state != DSP_DOWNLOADED)
 	if (spec->dsp_state != DSP_DOWNLOADED)
 		return;
 		return;
 
 
-	sbz_dsp_scp_startup(codec);
-
-	sbz_init_analog_mics(codec);
-
+	ca0132_alt_dsp_scp_startup(codec);
+	ca0132_alt_init_analog_mics(codec);
 	sbz_connect_streams(codec);
 	sbz_connect_streams(codec);
-
 	sbz_chipio_startup_data(codec);
 	sbz_chipio_startup_data(codec);
 
 
 	chipio_set_stream_control(codec, 0x03, 1);
 	chipio_set_stream_control(codec, 0x03, 1);
@@ -6561,8 +7329,7 @@ static void sbz_setup_defaults(struct hda_codec *codec)
 	/* Set speaker source? */
 	/* Set speaker source? */
 	dspio_set_uint_param(codec, 0x32, 0x00, tmp);
 	dspio_set_uint_param(codec, 0x32, 0x00, tmp);
 
 
-	sbz_dsp_initial_mic_setup(codec);
-
+	ca0132_alt_dsp_initial_mic_setup(codec);
 
 
 	/* out, in effects + voicefx */
 	/* out, in effects + voicefx */
 	num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT + 1;
 	num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT + 1;
@@ -6575,23 +7342,74 @@ static void sbz_setup_defaults(struct hda_codec *codec)
 		}
 		}
 	}
 	}
 
 
-	/*
-	 * Have to make a stream to bind the sound output to, otherwise
-	 * you'll get dead audio. Before I did this, it would bind to an
-	 * audio input, and would never work
-	 */
-	stream_format = snd_hdac_calc_stream_format(48000, 2,
-			SNDRV_PCM_FORMAT_S32_LE, 32, 0);
+	ca0132_alt_create_dummy_stream(codec);
+}
 
 
-	snd_hda_codec_setup_stream(codec, spec->dacs[0], spec->dsp_stream_id,
-					0, stream_format);
+/*
+ * Setup default parameters for the Sound BlasterX AE-5 DSP.
+ */
+static void ae5_setup_defaults(struct hda_codec *codec)
+{
+	struct ca0132_spec *spec = codec->spec;
+	unsigned int tmp;
+	int num_fx;
+	int idx, i;
 
 
-	snd_hda_codec_cleanup_stream(codec, spec->dacs[0]);
+	if (spec->dsp_state != DSP_DOWNLOADED)
+		return;
 
 
-	snd_hda_codec_setup_stream(codec, spec->dacs[0], spec->dsp_stream_id,
-					0, stream_format);
+	ca0132_alt_dsp_scp_startup(codec);
+	ca0132_alt_init_analog_mics(codec);
+	chipio_set_stream_control(codec, 0x03, 1);
+	chipio_set_stream_control(codec, 0x04, 1);
 
 
-	snd_hda_codec_cleanup_stream(codec, spec->dacs[0]);
+	/* New, unknown SCP req's */
+	tmp = FLOAT_ZERO;
+	dspio_set_uint_param(codec, 0x96, 0x29, tmp);
+	dspio_set_uint_param(codec, 0x96, 0x2a, tmp);
+	dspio_set_uint_param(codec, 0x80, 0x0d, tmp);
+	dspio_set_uint_param(codec, 0x80, 0x0e, tmp);
+
+	ca0113_mmio_command_set(codec, 0x30, 0x2e, 0x3f);
+	ca0113_mmio_gpio_set(codec, 0, false);
+	ca0113_mmio_command_set(codec, 0x30, 0x28, 0x00);
+
+	/* Internal loopback off */
+	tmp = FLOAT_ONE;
+	dspio_set_uint_param(codec, 0x37, 0x08, tmp);
+	dspio_set_uint_param(codec, 0x37, 0x10, tmp);
+
+	/*remove DSP headroom*/
+	tmp = FLOAT_ZERO;
+	dspio_set_uint_param(codec, 0x96, 0x3C, tmp);
+
+	/* set WUH source */
+	tmp = FLOAT_TWO;
+	dspio_set_uint_param(codec, 0x31, 0x00, tmp);
+	chipio_set_conn_rate(codec, MEM_CONNID_WUH, SR_48_000);
+
+	/* Set speaker source? */
+	dspio_set_uint_param(codec, 0x32, 0x00, tmp);
+
+	ca0132_alt_dsp_initial_mic_setup(codec);
+	ae5_post_dsp_register_set(codec);
+	ae5_post_dsp_param_setup(codec);
+	ae5_post_dsp_pll_setup(codec);
+	ae5_post_dsp_stream_setup(codec);
+	ae5_post_dsp_startup_data(codec);
+
+	/* out, in effects + voicefx */
+	num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT + 1;
+	for (idx = 0; idx < num_fx; idx++) {
+		for (i = 0; i <= ca0132_effects[idx].params; i++) {
+			dspio_set_uint_param(codec,
+					ca0132_effects[idx].mid,
+					ca0132_effects[idx].reqs[i],
+					ca0132_effects[idx].def_vals[i]);
+		}
+	}
+
+	ca0132_alt_create_dummy_stream(codec);
 }
 }
 
 
 /*
 /*
@@ -6673,12 +7491,14 @@ static bool ca0132_download_dsp_images(struct hda_codec *codec)
 	 */
 	 */
 	switch (spec->quirk) {
 	switch (spec->quirk) {
 	case QUIRK_SBZ:
 	case QUIRK_SBZ:
-		if (request_firmware(&fw_entry, SBZ_EFX_FILE,
+	case QUIRK_R3D:
+	case QUIRK_AE5:
+		if (request_firmware(&fw_entry, DESKTOP_EFX_FILE,
 					codec->card->dev) != 0) {
 					codec->card->dev) != 0) {
-			codec_dbg(codec, "SBZ alt firmware not detected. ");
+			codec_dbg(codec, "Desktop firmware not found.");
 			spec->alt_firmware_present = false;
 			spec->alt_firmware_present = false;
 		} else {
 		} else {
-			codec_dbg(codec, "Sound Blaster Z firmware selected.");
+			codec_dbg(codec, "Desktop firmware selected.");
 			spec->alt_firmware_present = true;
 			spec->alt_firmware_present = true;
 		}
 		}
 		break;
 		break;
@@ -6921,6 +7741,14 @@ static void ca0132_init_chip(struct hda_codec *codec)
 	spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID] = 1;
 	spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID] = 1;
 	spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID] = 0;
 	spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID] = 0;
 
 
+	/*
+	 * The ZxR doesn't have a front panel header, and it's line-in is on
+	 * the daughter board. So, there is no input enum control, and we need
+	 * to make sure that spec->in_enum_val is set properly.
+	 */
+	if (spec->quirk == QUIRK_ZXR)
+		spec->in_enum_val = REAR_MIC;
+
 #ifdef ENABLE_TUNING_CONTROLS
 #ifdef ENABLE_TUNING_CONTROLS
 	ca0132_init_tuning_defaults(codec);
 	ca0132_init_tuning_defaults(codec);
 #endif
 #endif
@@ -6948,11 +7776,11 @@ static void sbz_region2_exit(struct hda_codec *codec)
 	for (i = 0; i < 8; i++)
 	for (i = 0; i < 8; i++)
 		writeb(0xb3, spec->mem_base + 0x304);
 		writeb(0xb3, spec->mem_base + 0x304);
 
 
-	ca0132_mmio_gpio_set(codec, 0, false);
-	ca0132_mmio_gpio_set(codec, 1, false);
-	ca0132_mmio_gpio_set(codec, 4, true);
-	ca0132_mmio_gpio_set(codec, 5, false);
-	ca0132_mmio_gpio_set(codec, 7, false);
+	ca0113_mmio_gpio_set(codec, 0, false);
+	ca0113_mmio_gpio_set(codec, 1, false);
+	ca0113_mmio_gpio_set(codec, 4, true);
+	ca0113_mmio_gpio_set(codec, 5, false);
+	ca0113_mmio_gpio_set(codec, 7, false);
 }
 }
 
 
 static void sbz_set_pin_ctl_default(struct hda_codec *codec)
 static void sbz_set_pin_ctl_default(struct hda_codec *codec)
@@ -6995,6 +7823,16 @@ static void sbz_gpio_shutdown_commands(struct hda_codec *codec, int dir,
 				AC_VERB_SET_GPIO_DATA, data);
 				AC_VERB_SET_GPIO_DATA, data);
 }
 }
 
 
+static void zxr_dbpro_power_state_shutdown(struct hda_codec *codec)
+{
+	hda_nid_t pins[7] = {0x05, 0x0c, 0x09, 0x0e, 0x08, 0x11, 0x01};
+	unsigned int i;
+
+	for (i = 0; i < 7; i++)
+		snd_hda_codec_write(codec, pins[i], 0,
+				AC_VERB_SET_POWER_STATE, 0x03);
+}
+
 static void sbz_exit_chip(struct hda_codec *codec)
 static void sbz_exit_chip(struct hda_codec *codec)
 {
 {
 	chipio_set_stream_control(codec, 0x03, 0);
 	chipio_set_stream_control(codec, 0x03, 0);
@@ -7037,6 +7875,61 @@ static void r3d_exit_chip(struct hda_codec *codec)
 	snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x5b);
 	snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x5b);
 }
 }
 
 
+static void ae5_exit_chip(struct hda_codec *codec)
+{
+	chipio_set_stream_control(codec, 0x03, 0);
+	chipio_set_stream_control(codec, 0x04, 0);
+
+	ca0113_mmio_command_set(codec, 0x30, 0x32, 0x3f);
+	ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83);
+	ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83);
+	ca0113_mmio_command_set(codec, 0x30, 0x30, 0x00);
+	ca0113_mmio_command_set(codec, 0x30, 0x2b, 0x00);
+	ca0113_mmio_command_set(codec, 0x30, 0x2d, 0x00);
+	ca0113_mmio_gpio_set(codec, 0, false);
+	ca0113_mmio_gpio_set(codec, 1, false);
+
+	snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00);
+	snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x53);
+
+	chipio_set_control_param(codec, CONTROL_PARAM_ASI, 0);
+
+	chipio_set_stream_control(codec, 0x18, 0);
+	chipio_set_stream_control(codec, 0x0c, 0);
+
+	snd_hda_codec_write(codec, 0x01, 0, 0x724, 0x83);
+}
+
+static void zxr_exit_chip(struct hda_codec *codec)
+{
+	chipio_set_stream_control(codec, 0x03, 0);
+	chipio_set_stream_control(codec, 0x04, 0);
+	chipio_set_stream_control(codec, 0x14, 0);
+	chipio_set_stream_control(codec, 0x0C, 0);
+
+	chipio_set_conn_rate(codec, 0x41, SR_192_000);
+	chipio_set_conn_rate(codec, 0x91, SR_192_000);
+
+	chipio_write(codec, 0x18a020, 0x00000083);
+
+	snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00);
+	snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x53);
+
+	ca0132_clear_unsolicited(codec);
+	sbz_set_pin_ctl_default(codec);
+	snd_hda_codec_write(codec, 0x0B, 0, AC_VERB_SET_EAPD_BTLENABLE, 0x00);
+
+	ca0113_mmio_gpio_set(codec, 5, false);
+	ca0113_mmio_gpio_set(codec, 2, false);
+	ca0113_mmio_gpio_set(codec, 3, false);
+	ca0113_mmio_gpio_set(codec, 0, false);
+	ca0113_mmio_gpio_set(codec, 4, true);
+	ca0113_mmio_gpio_set(codec, 0, true);
+	ca0113_mmio_gpio_set(codec, 5, true);
+	ca0113_mmio_gpio_set(codec, 2, false);
+	ca0113_mmio_gpio_set(codec, 3, false);
+}
+
 static void ca0132_exit_chip(struct hda_codec *codec)
 static void ca0132_exit_chip(struct hda_codec *codec)
 {
 {
 	/* put any chip cleanup stuffs here. */
 	/* put any chip cleanup stuffs here. */
@@ -7140,11 +8033,6 @@ static void sbz_pre_dsp_setup(struct hda_codec *codec)
 	writel(0x00820680, spec->mem_base + 0x01C);
 	writel(0x00820680, spec->mem_base + 0x01C);
 	writel(0x00820680, spec->mem_base + 0x01C);
 	writel(0x00820680, spec->mem_base + 0x01C);
 
 
-	snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfc);
-	snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfd);
-	snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfe);
-	snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xff);
-
 	chipio_write(codec, 0x18b0a4, 0x000000c2);
 	chipio_write(codec, 0x18b0a4, 0x000000c2);
 
 
 	snd_hda_codec_write(codec, 0x11, 0,
 	snd_hda_codec_write(codec, 0x11, 0,
@@ -7153,12 +8041,6 @@ static void sbz_pre_dsp_setup(struct hda_codec *codec)
 
 
 static void r3d_pre_dsp_setup(struct hda_codec *codec)
 static void r3d_pre_dsp_setup(struct hda_codec *codec)
 {
 {
-
-	snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfc);
-	snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfd);
-	snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfe);
-	snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xff);
-
 	chipio_write(codec, 0x18b0a4, 0x000000c2);
 	chipio_write(codec, 0x18b0a4, 0x000000c2);
 
 
 	snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
 	snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
@@ -7205,23 +8087,116 @@ static void ca0132_mmio_init(struct hda_codec *codec)
 {
 {
 	struct ca0132_spec *spec = codec->spec;
 	struct ca0132_spec *spec = codec->spec;
 
 
-	writel(0x00000000, spec->mem_base + 0x400);
-	writel(0x00000000, spec->mem_base + 0x408);
-	writel(0x00000000, spec->mem_base + 0x40C);
-	writel(0x00880680, spec->mem_base + 0x01C);
-	writel(0x00000083, spec->mem_base + 0xC0C);
+	if (spec->quirk == QUIRK_AE5)
+		writel(0x00000001, spec->mem_base + 0x400);
+	else
+		writel(0x00000000, spec->mem_base + 0x400);
+
+	if (spec->quirk == QUIRK_AE5)
+		writel(0x00000001, spec->mem_base + 0x408);
+	else
+		writel(0x00000000, spec->mem_base + 0x408);
+
+	if (spec->quirk == QUIRK_AE5)
+		writel(0x00000001, spec->mem_base + 0x40c);
+	else
+		writel(0x00000000, spec->mem_base + 0x40C);
+
+	if (spec->quirk == QUIRK_ZXR)
+		writel(0x00880640, spec->mem_base + 0x01C);
+	else
+		writel(0x00880680, spec->mem_base + 0x01C);
+
+	if (spec->quirk == QUIRK_AE5)
+		writel(0x00000080, spec->mem_base + 0xC0C);
+	else
+		writel(0x00000083, spec->mem_base + 0xC0C);
+
 	writel(0x00000030, spec->mem_base + 0xC00);
 	writel(0x00000030, spec->mem_base + 0xC00);
 	writel(0x00000000, spec->mem_base + 0xC04);
 	writel(0x00000000, spec->mem_base + 0xC04);
+
+	if (spec->quirk == QUIRK_AE5)
+		writel(0x00000000, spec->mem_base + 0xC0C);
+	else
+		writel(0x00000003, spec->mem_base + 0xC0C);
+
 	writel(0x00000003, spec->mem_base + 0xC0C);
 	writel(0x00000003, spec->mem_base + 0xC0C);
 	writel(0x00000003, spec->mem_base + 0xC0C);
 	writel(0x00000003, spec->mem_base + 0xC0C);
 	writel(0x00000003, spec->mem_base + 0xC0C);
 	writel(0x00000003, spec->mem_base + 0xC0C);
-	writel(0x00000003, spec->mem_base + 0xC0C);
-	writel(0x000000C1, spec->mem_base + 0xC08);
+
+	if (spec->quirk == QUIRK_AE5)
+		writel(0x00000001, spec->mem_base + 0xC08);
+	else
+		writel(0x000000C1, spec->mem_base + 0xC08);
+
 	writel(0x000000F1, spec->mem_base + 0xC08);
 	writel(0x000000F1, spec->mem_base + 0xC08);
 	writel(0x00000001, spec->mem_base + 0xC08);
 	writel(0x00000001, spec->mem_base + 0xC08);
 	writel(0x000000C7, spec->mem_base + 0xC08);
 	writel(0x000000C7, spec->mem_base + 0xC08);
 	writel(0x000000C1, spec->mem_base + 0xC08);
 	writel(0x000000C1, spec->mem_base + 0xC08);
 	writel(0x00000080, spec->mem_base + 0xC04);
 	writel(0x00000080, spec->mem_base + 0xC04);
+
+	if (spec->quirk == QUIRK_AE5) {
+		writel(0x00000000, spec->mem_base + 0x42c);
+		writel(0x00000000, spec->mem_base + 0x46c);
+		writel(0x00000000, spec->mem_base + 0x4ac);
+		writel(0x00000000, spec->mem_base + 0x4ec);
+		writel(0x00000000, spec->mem_base + 0x43c);
+		writel(0x00000000, spec->mem_base + 0x47c);
+		writel(0x00000000, spec->mem_base + 0x4bc);
+		writel(0x00000000, spec->mem_base + 0x4fc);
+		writel(0x00000600, spec->mem_base + 0x100);
+		writel(0x00000014, spec->mem_base + 0x410);
+		writel(0x0000060f, spec->mem_base + 0x100);
+		writel(0x0000070f, spec->mem_base + 0x100);
+		writel(0x00000aff, spec->mem_base + 0x830);
+		writel(0x00000000, spec->mem_base + 0x86c);
+		writel(0x0000006b, spec->mem_base + 0x800);
+		writel(0x00000001, spec->mem_base + 0x86c);
+		writel(0x0000006b, spec->mem_base + 0x800);
+		writel(0x00000057, spec->mem_base + 0x804);
+		writel(0x00800000, spec->mem_base + 0x20c);
+	}
+}
+
+/*
+ * This function writes to some SFR's, does some region2 writes, and then
+ * eventually resets the codec with the 0x7ff verb. Not quite sure why it does
+ * what it does.
+ */
+static void ae5_register_set(struct hda_codec *codec)
+{
+	struct ca0132_spec *spec = codec->spec;
+
+	chipio_8051_write_direct(codec, 0x93, 0x10);
+	snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+			    VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x44);
+	snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+			    VENDOR_CHIPIO_PLL_PMU_WRITE, 0xc2);
+
+	writeb(0x0f, spec->mem_base + 0x304);
+	writeb(0x0f, spec->mem_base + 0x304);
+	writeb(0x0f, spec->mem_base + 0x304);
+	writeb(0x0f, spec->mem_base + 0x304);
+	writeb(0x0e, spec->mem_base + 0x100);
+	writeb(0x1f, spec->mem_base + 0x304);
+	writeb(0x0c, spec->mem_base + 0x100);
+	writeb(0x3f, spec->mem_base + 0x304);
+	writeb(0x08, spec->mem_base + 0x100);
+	writeb(0x7f, spec->mem_base + 0x304);
+	writeb(0x00, spec->mem_base + 0x100);
+	writeb(0xff, spec->mem_base + 0x304);
+
+	ca0113_mmio_command_set(codec, 0x30, 0x2d, 0x3f);
+
+	chipio_8051_write_direct(codec, 0x90, 0x00);
+	chipio_8051_write_direct(codec, 0x90, 0x10);
+
+	ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83);
+
+	chipio_write(codec, 0x18b0a4, 0x000000c2);
+
+	snd_hda_codec_write(codec, 0x01, 0, 0x7ff, 0x00);
+	snd_hda_codec_write(codec, 0x01, 0, 0x7ff, 0x00);
 }
 }
 
 
 /*
 /*
@@ -7257,6 +8232,21 @@ static void ca0132_alt_init(struct hda_codec *codec)
 		snd_hda_sequence_write(codec, spec->chip_init_verbs);
 		snd_hda_sequence_write(codec, spec->chip_init_verbs);
 		snd_hda_sequence_write(codec, spec->desktop_init_verbs);
 		snd_hda_sequence_write(codec, spec->desktop_init_verbs);
 		break;
 		break;
+	case QUIRK_AE5:
+		ca0132_gpio_init(codec);
+		snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+				VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x49);
+		snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+				VENDOR_CHIPIO_PLL_PMU_WRITE, 0x88);
+		chipio_write(codec, 0x18b030, 0x00000020);
+		snd_hda_sequence_write(codec, spec->chip_init_verbs);
+		snd_hda_sequence_write(codec, spec->desktop_init_verbs);
+		ca0113_mmio_command_set(codec, 0x30, 0x32, 0x3f);
+		break;
+	case QUIRK_ZXR:
+		snd_hda_sequence_write(codec, spec->chip_init_verbs);
+		snd_hda_sequence_write(codec, spec->desktop_init_verbs);
+		break;
 	}
 	}
 }
 }
 
 
@@ -7298,6 +8288,9 @@ static int ca0132_init(struct hda_codec *codec)
 
 
 	snd_hda_power_up_pm(codec);
 	snd_hda_power_up_pm(codec);
 
 
+	if (spec->quirk == QUIRK_AE5)
+		ae5_register_set(codec);
+
 	ca0132_init_unsol(codec);
 	ca0132_init_unsol(codec);
 	ca0132_init_params(codec);
 	ca0132_init_params(codec);
 	ca0132_init_flags(codec);
 	ca0132_init_flags(codec);
@@ -7317,8 +8310,12 @@ static int ca0132_init(struct hda_codec *codec)
 		r3d_setup_defaults(codec);
 		r3d_setup_defaults(codec);
 		break;
 		break;
 	case QUIRK_SBZ:
 	case QUIRK_SBZ:
+	case QUIRK_ZXR:
 		sbz_setup_defaults(codec);
 		sbz_setup_defaults(codec);
 		break;
 		break;
+	case QUIRK_AE5:
+		ae5_setup_defaults(codec);
+		break;
 	default:
 	default:
 		ca0132_setup_defaults(codec);
 		ca0132_setup_defaults(codec);
 		ca0132_init_analog_mic2(codec);
 		ca0132_init_analog_mic2(codec);
@@ -7372,6 +8369,21 @@ static int ca0132_init(struct hda_codec *codec)
 	return 0;
 	return 0;
 }
 }
 
 
+static int dbpro_init(struct hda_codec *codec)
+{
+	struct ca0132_spec *spec = codec->spec;
+	struct auto_pin_cfg *cfg = &spec->autocfg;
+	unsigned int i;
+
+	init_output(codec, cfg->dig_out_pins[0], spec->dig_out);
+	init_input(codec, cfg->dig_in_pin, spec->dig_in);
+
+	for (i = 0; i < spec->num_inputs; i++)
+		init_input(codec, spec->input_pins[i], spec->adcs[i]);
+
+	return 0;
+}
+
 static void ca0132_free(struct hda_codec *codec)
 static void ca0132_free(struct hda_codec *codec)
 {
 {
 	struct ca0132_spec *spec = codec->spec;
 	struct ca0132_spec *spec = codec->spec;
@@ -7382,9 +8394,15 @@ static void ca0132_free(struct hda_codec *codec)
 	case QUIRK_SBZ:
 	case QUIRK_SBZ:
 		sbz_exit_chip(codec);
 		sbz_exit_chip(codec);
 		break;
 		break;
+	case QUIRK_ZXR:
+		zxr_exit_chip(codec);
+		break;
 	case QUIRK_R3D:
 	case QUIRK_R3D:
 		r3d_exit_chip(codec);
 		r3d_exit_chip(codec);
 		break;
 		break;
+	case QUIRK_AE5:
+		ae5_exit_chip(codec);
+		break;
 	case QUIRK_R3DI:
 	case QUIRK_R3DI:
 		r3di_gpio_shutdown(codec);
 		r3di_gpio_shutdown(codec);
 		break;
 		break;
@@ -7400,6 +8418,16 @@ static void ca0132_free(struct hda_codec *codec)
 	kfree(codec->spec);
 	kfree(codec->spec);
 }
 }
 
 
+static void dbpro_free(struct hda_codec *codec)
+{
+	struct ca0132_spec *spec = codec->spec;
+
+	zxr_dbpro_power_state_shutdown(codec);
+
+	kfree(spec->spec_init_verbs);
+	kfree(codec->spec);
+}
+
 static void ca0132_reboot_notify(struct hda_codec *codec)
 static void ca0132_reboot_notify(struct hda_codec *codec)
 {
 {
 	codec->patch_ops.free(codec);
 	codec->patch_ops.free(codec);
@@ -7414,6 +8442,13 @@ static const struct hda_codec_ops ca0132_patch_ops = {
 	.reboot_notify = ca0132_reboot_notify,
 	.reboot_notify = ca0132_reboot_notify,
 };
 };
 
 
+static const struct hda_codec_ops dbpro_patch_ops = {
+	.build_controls = dbpro_build_controls,
+	.build_pcms = dbpro_build_pcms,
+	.init = dbpro_init,
+	.free = dbpro_free,
+};
+
 static void ca0132_config(struct hda_codec *codec)
 static void ca0132_config(struct hda_codec *codec)
 {
 {
 	struct ca0132_spec *spec = codec->spec;
 	struct ca0132_spec *spec = codec->spec;
@@ -7432,9 +8467,33 @@ static void ca0132_config(struct hda_codec *codec)
 
 
 	switch (spec->quirk) {
 	switch (spec->quirk) {
 	case QUIRK_ALIENWARE:
 	case QUIRK_ALIENWARE:
-		codec_dbg(codec, "ca0132_config: QUIRK_ALIENWARE applied.\n");
+		codec_dbg(codec, "%s: QUIRK_ALIENWARE applied.\n", __func__);
 		snd_hda_apply_pincfgs(codec, alienware_pincfgs);
 		snd_hda_apply_pincfgs(codec, alienware_pincfgs);
+		break;
+	case QUIRK_SBZ:
+		codec_dbg(codec, "%s: QUIRK_SBZ applied.\n", __func__);
+		snd_hda_apply_pincfgs(codec, sbz_pincfgs);
+		break;
+	case QUIRK_ZXR:
+		codec_dbg(codec, "%s: QUIRK_ZXR applied.\n", __func__);
+		snd_hda_apply_pincfgs(codec, zxr_pincfgs);
+		break;
+	case QUIRK_R3D:
+		codec_dbg(codec, "%s: QUIRK_R3D applied.\n", __func__);
+		snd_hda_apply_pincfgs(codec, r3d_pincfgs);
+		break;
+	case QUIRK_R3DI:
+		codec_dbg(codec, "%s: QUIRK_R3DI applied.\n", __func__);
+		snd_hda_apply_pincfgs(codec, r3di_pincfgs);
+		break;
+	case QUIRK_AE5:
+		codec_dbg(codec, "%s: QUIRK_AE5 applied.\n", __func__);
+		snd_hda_apply_pincfgs(codec, r3di_pincfgs);
+		break;
+	}
 
 
+	switch (spec->quirk) {
+	case QUIRK_ALIENWARE:
 		spec->num_outputs = 2;
 		spec->num_outputs = 2;
 		spec->out_pins[0] = 0x0b; /* speaker out */
 		spec->out_pins[0] = 0x0b; /* speaker out */
 		spec->out_pins[1] = 0x0f;
 		spec->out_pins[1] = 0x0f;
@@ -7454,15 +8513,6 @@ static void ca0132_config(struct hda_codec *codec)
 		break;
 		break;
 	case QUIRK_SBZ:
 	case QUIRK_SBZ:
 	case QUIRK_R3D:
 	case QUIRK_R3D:
-		if (spec->quirk == QUIRK_SBZ) {
-			codec_dbg(codec, "%s: QUIRK_SBZ applied.\n", __func__);
-			snd_hda_apply_pincfgs(codec, sbz_pincfgs);
-		}
-		if (spec->quirk == QUIRK_R3D) {
-			codec_dbg(codec, "%s: QUIRK_R3D applied.\n", __func__);
-			snd_hda_apply_pincfgs(codec, r3d_pincfgs);
-		}
-
 		spec->num_outputs = 2;
 		spec->num_outputs = 2;
 		spec->out_pins[0] = 0x0B; /* Line out */
 		spec->out_pins[0] = 0x0B; /* Line out */
 		spec->out_pins[1] = 0x0F; /* Rear headphone out */
 		spec->out_pins[1] = 0x0F; /* Rear headphone out */
@@ -7487,10 +8537,62 @@ static void ca0132_config(struct hda_codec *codec)
 		spec->multiout.dig_out_nid = spec->dig_out;
 		spec->multiout.dig_out_nid = spec->dig_out;
 		spec->dig_in = 0x09;
 		spec->dig_in = 0x09;
 		break;
 		break;
-	case QUIRK_R3DI:
-		codec_dbg(codec, "%s: QUIRK_R3DI applied.\n", __func__);
-		snd_hda_apply_pincfgs(codec, r3di_pincfgs);
+	case QUIRK_ZXR:
+		spec->num_outputs = 2;
+		spec->out_pins[0] = 0x0B; /* Line out */
+		spec->out_pins[1] = 0x0F; /* Rear headphone out */
+		spec->out_pins[2] = 0x10; /* Center/LFE */
+		spec->out_pins[3] = 0x11; /* Rear surround */
+		spec->shared_out_nid = 0x2;
+		spec->unsol_tag_hp = spec->out_pins[1];
+		spec->unsol_tag_front_hp = spec->out_pins[2];
 
 
+		spec->adcs[0] = 0x7; /* Rear Mic / Line-in */
+		spec->adcs[1] = 0x8; /* Not connected, no front mic */
+		spec->adcs[2] = 0xa; /* what u hear */
+
+		spec->num_inputs = 2;
+		spec->input_pins[0] = 0x12; /* Rear Mic / Line-in */
+		spec->input_pins[1] = 0x13; /* What U Hear */
+		spec->shared_mic_nid = 0x7;
+		spec->unsol_tag_amic1 = spec->input_pins[0];
+		break;
+	case QUIRK_ZXR_DBPRO:
+		spec->adcs[0] = 0x8; /* ZxR DBPro Aux In */
+
+		spec->num_inputs = 1;
+		spec->input_pins[0] = 0x11; /* RCA Line-in */
+
+		spec->dig_out = 0x05;
+		spec->multiout.dig_out_nid = spec->dig_out;
+
+		spec->dig_in = 0x09;
+		break;
+	case QUIRK_AE5:
+		spec->num_outputs = 2;
+		spec->out_pins[0] = 0x0B; /* Line out */
+		spec->out_pins[1] = 0x11; /* Rear headphone out */
+		spec->out_pins[2] = 0x10; /* Front Headphone / Center/LFE*/
+		spec->out_pins[3] = 0x0F; /* Rear surround */
+		spec->shared_out_nid = 0x2;
+		spec->unsol_tag_hp = spec->out_pins[1];
+		spec->unsol_tag_front_hp = spec->out_pins[2];
+
+		spec->adcs[0] = 0x7; /* Rear Mic / Line-in */
+		spec->adcs[1] = 0x8; /* Front Mic, but only if no DSP */
+		spec->adcs[2] = 0xa; /* what u hear */
+
+		spec->num_inputs = 2;
+		spec->input_pins[0] = 0x12; /* Rear Mic / Line-in */
+		spec->input_pins[1] = 0x13; /* What U Hear */
+		spec->shared_mic_nid = 0x7;
+		spec->unsol_tag_amic1 = spec->input_pins[0];
+
+		/* SPDIF I/O */
+		spec->dig_out = 0x05;
+		spec->multiout.dig_out_nid = spec->dig_out;
+		break;
+	case QUIRK_R3DI:
 		spec->num_outputs = 2;
 		spec->num_outputs = 2;
 		spec->out_pins[0] = 0x0B; /* Line out */
 		spec->out_pins[0] = 0x0B; /* Line out */
 		spec->out_pins[1] = 0x0F; /* Rear headphone out */
 		spec->out_pins[1] = 0x0F; /* Rear headphone out */
@@ -7547,7 +8649,11 @@ static int ca0132_prepare_verbs(struct hda_codec *codec)
 	struct ca0132_spec *spec = codec->spec;
 	struct ca0132_spec *spec = codec->spec;
 
 
 	spec->chip_init_verbs = ca0132_init_verbs0;
 	spec->chip_init_verbs = ca0132_init_verbs0;
-	if (spec->quirk == QUIRK_SBZ || spec->quirk == QUIRK_R3D)
+	/*
+	 * Since desktop cards use pci_mmio, this can be used to determine
+	 * whether or not to use these verbs instead of a separate bool.
+	 */
+	if (spec->use_pci_mmio)
 		spec->desktop_init_verbs = ca0132_init_verbs1;
 		spec->desktop_init_verbs = ca0132_init_verbs1;
 	spec->spec_init_verbs = kcalloc(NUM_SPEC_VERBS,
 	spec->spec_init_verbs = kcalloc(NUM_SPEC_VERBS,
 					sizeof(struct hda_verb),
 					sizeof(struct hda_verb),
@@ -7579,6 +8685,29 @@ static int ca0132_prepare_verbs(struct hda_codec *codec)
 	return 0;
 	return 0;
 }
 }
 
 
+/*
+ * The Sound Blaster ZxR shares the same PCI subsystem ID as some regular
+ * Sound Blaster Z cards. However, they have different HDA codec subsystem
+ * ID's. So, we check for the ZxR's subsystem ID, as well as the DBPro
+ * daughter boards ID.
+ */
+static void sbz_detect_quirk(struct hda_codec *codec)
+{
+	struct ca0132_spec *spec = codec->spec;
+
+	switch (codec->core.subsystem_id) {
+	case 0x11020033:
+		spec->quirk = QUIRK_ZXR;
+		break;
+	case 0x1102003f:
+		spec->quirk = QUIRK_ZXR_DBPRO;
+		break;
+	default:
+		spec->quirk = QUIRK_SBZ;
+		break;
+	}
+}
+
 static int patch_ca0132(struct hda_codec *codec)
 static int patch_ca0132(struct hda_codec *codec)
 {
 {
 	struct ca0132_spec *spec;
 	struct ca0132_spec *spec;
@@ -7593,10 +8722,6 @@ static int patch_ca0132(struct hda_codec *codec)
 	codec->spec = spec;
 	codec->spec = spec;
 	spec->codec = codec;
 	spec->codec = codec;
 
 
-	codec->patch_ops = ca0132_patch_ops;
-	codec->pcm_format_first = 1;
-	codec->no_sticky_stream = 1;
-
 	/* Detect codec quirk */
 	/* Detect codec quirk */
 	quirk = snd_pci_quirk_lookup(codec->bus->pci, ca0132_quirks);
 	quirk = snd_pci_quirk_lookup(codec->bus->pci, ca0132_quirks);
 	if (quirk)
 	if (quirk)
@@ -7604,6 +8729,18 @@ static int patch_ca0132(struct hda_codec *codec)
 	else
 	else
 		spec->quirk = QUIRK_NONE;
 		spec->quirk = QUIRK_NONE;
 
 
+	if (spec->quirk == QUIRK_SBZ)
+		sbz_detect_quirk(codec);
+
+	if (spec->quirk == QUIRK_ZXR_DBPRO)
+		codec->patch_ops = dbpro_patch_ops;
+	else
+		codec->patch_ops = ca0132_patch_ops;
+
+	codec->pcm_format_first = 1;
+	codec->no_sticky_stream = 1;
+
+
 	spec->dsp_state = DSP_DOWNLOAD_INIT;
 	spec->dsp_state = DSP_DOWNLOAD_INIT;
 	spec->num_mixers = 1;
 	spec->num_mixers = 1;
 
 
@@ -7613,6 +8750,12 @@ static int patch_ca0132(struct hda_codec *codec)
 		spec->mixers[0] = desktop_mixer;
 		spec->mixers[0] = desktop_mixer;
 		snd_hda_codec_set_name(codec, "Sound Blaster Z");
 		snd_hda_codec_set_name(codec, "Sound Blaster Z");
 		break;
 		break;
+	case QUIRK_ZXR:
+		spec->mixers[0] = desktop_mixer;
+		snd_hda_codec_set_name(codec, "Sound Blaster ZxR");
+		break;
+	case QUIRK_ZXR_DBPRO:
+		break;
 	case QUIRK_R3D:
 	case QUIRK_R3D:
 		spec->mixers[0] = desktop_mixer;
 		spec->mixers[0] = desktop_mixer;
 		snd_hda_codec_set_name(codec, "Recon3D");
 		snd_hda_codec_set_name(codec, "Recon3D");
@@ -7621,6 +8764,10 @@ static int patch_ca0132(struct hda_codec *codec)
 		spec->mixers[0] = r3di_mixer;
 		spec->mixers[0] = r3di_mixer;
 		snd_hda_codec_set_name(codec, "Recon3Di");
 		snd_hda_codec_set_name(codec, "Recon3Di");
 		break;
 		break;
+	case QUIRK_AE5:
+		spec->mixers[0] = desktop_mixer;
+		snd_hda_codec_set_name(codec, "Sound BlasterX AE-5");
+		break;
 	default:
 	default:
 		spec->mixers[0] = ca0132_mixer;
 		spec->mixers[0] = ca0132_mixer;
 		break;
 		break;
@@ -7630,6 +8777,8 @@ static int patch_ca0132(struct hda_codec *codec)
 	switch (spec->quirk) {
 	switch (spec->quirk) {
 	case QUIRK_SBZ:
 	case QUIRK_SBZ:
 	case QUIRK_R3D:
 	case QUIRK_R3D:
+	case QUIRK_AE5:
+	case QUIRK_ZXR:
 		spec->use_alt_controls = true;
 		spec->use_alt_controls = true;
 		spec->use_alt_functions = true;
 		spec->use_alt_functions = true;
 		spec->use_pci_mmio = true;
 		spec->use_pci_mmio = true;

+ 1 - 1
sound/pci/hda/patch_cirrus.c

@@ -23,7 +23,7 @@
 #include <linux/module.h>
 #include <linux/module.h>
 #include <sound/core.h>
 #include <sound/core.h>
 #include <sound/tlv.h>
 #include <sound/tlv.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
 #include "hda_local.h"
 #include "hda_local.h"
 #include "hda_auto_parser.h"
 #include "hda_auto_parser.h"
 #include "hda_jack.h"
 #include "hda_jack.h"

+ 1 - 1
sound/pci/hda/patch_cmedia.c

@@ -25,7 +25,7 @@
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <sound/core.h>
 #include <sound/core.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
 #include "hda_local.h"
 #include "hda_local.h"
 #include "hda_auto_parser.h"
 #include "hda_auto_parser.h"
 #include "hda_jack.h"
 #include "hda_jack.h"

+ 2 - 1
sound/pci/hda/patch_conexant.c

@@ -27,7 +27,7 @@
 #include <sound/core.h>
 #include <sound/core.h>
 #include <sound/jack.h>
 #include <sound/jack.h>
 
 
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
 #include "hda_local.h"
 #include "hda_local.h"
 #include "hda_auto_parser.h"
 #include "hda_auto_parser.h"
 #include "hda_beep.h"
 #include "hda_beep.h"
@@ -943,6 +943,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
 	SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT_PINCFG_LENOVO_TP410),
 	SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT_PINCFG_LENOVO_TP410),
 	SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT_PINCFG_LENOVO_TP410),
 	SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT_PINCFG_LENOVO_TP410),
 	SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo IdeaPad Z560", CXT_FIXUP_MUTE_LED_EAPD),
 	SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo IdeaPad Z560", CXT_FIXUP_MUTE_LED_EAPD),
+	SND_PCI_QUIRK(0x17aa, 0x3905, "Lenovo G50-30", CXT_FIXUP_STEREO_DMIC),
 	SND_PCI_QUIRK(0x17aa, 0x390b, "Lenovo G50-80", CXT_FIXUP_STEREO_DMIC),
 	SND_PCI_QUIRK(0x17aa, 0x390b, "Lenovo G50-80", CXT_FIXUP_STEREO_DMIC),
 	SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
 	SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
 	SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC),
 	SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC),

+ 1 - 1
sound/pci/hda/patch_hdmi.c

@@ -41,7 +41,7 @@
 #include <sound/hdaudio.h>
 #include <sound/hdaudio.h>
 #include <sound/hda_i915.h>
 #include <sound/hda_i915.h>
 #include <sound/hda_chmap.h>
 #include <sound/hda_chmap.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
 #include "hda_local.h"
 #include "hda_local.h"
 #include "hda_jack.h"
 #include "hda_jack.h"
 
 

+ 28 - 1
sound/pci/hda/patch_realtek.c

@@ -32,7 +32,7 @@
 #include <linux/input.h>
 #include <linux/input.h>
 #include <sound/core.h>
 #include <sound/core.h>
 #include <sound/jack.h>
 #include <sound/jack.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
 #include "hda_local.h"
 #include "hda_local.h"
 #include "hda_auto_parser.h"
 #include "hda_auto_parser.h"
 #include "hda_jack.h"
 #include "hda_jack.h"
@@ -6841,6 +6841,12 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
 		{0x1a, 0x02a11040},
 		{0x1a, 0x02a11040},
 		{0x1b, 0x01014020},
 		{0x1b, 0x01014020},
 		{0x21, 0x0221101f}),
 		{0x21, 0x0221101f}),
+	SND_HDA_PIN_QUIRK(0x10ec0235, 0x17aa, "Lenovo", ALC294_FIXUP_LENOVO_MIC_LOCATION,
+		{0x14, 0x90170110},
+		{0x19, 0x02a11030},
+		{0x1a, 0x02a11040},
+		{0x1b, 0x01011020},
+		{0x21, 0x0221101f}),
 	SND_HDA_PIN_QUIRK(0x10ec0235, 0x17aa, "Lenovo", ALC294_FIXUP_LENOVO_MIC_LOCATION,
 	SND_HDA_PIN_QUIRK(0x10ec0235, 0x17aa, "Lenovo", ALC294_FIXUP_LENOVO_MIC_LOCATION,
 		{0x14, 0x90170110},
 		{0x14, 0x90170110},
 		{0x19, 0x02a11020},
 		{0x19, 0x02a11020},
@@ -7738,6 +7744,8 @@ enum {
 	ALC662_FIXUP_ASUS_Nx50,
 	ALC662_FIXUP_ASUS_Nx50,
 	ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
 	ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
 	ALC668_FIXUP_ASUS_Nx51,
 	ALC668_FIXUP_ASUS_Nx51,
+	ALC668_FIXUP_MIC_COEF,
+	ALC668_FIXUP_ASUS_G751,
 	ALC891_FIXUP_HEADSET_MODE,
 	ALC891_FIXUP_HEADSET_MODE,
 	ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
 	ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
 	ALC662_FIXUP_ACER_VERITON,
 	ALC662_FIXUP_ACER_VERITON,
@@ -8007,6 +8015,23 @@ static const struct hda_fixup alc662_fixups[] = {
 		.chained = true,
 		.chained = true,
 		.chain_id = ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
 		.chain_id = ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
 	},
 	},
+	[ALC668_FIXUP_MIC_COEF] = {
+		.type = HDA_FIXUP_VERBS,
+		.v.verbs = (const struct hda_verb[]) {
+			{ 0x20, AC_VERB_SET_COEF_INDEX, 0xc3 },
+			{ 0x20, AC_VERB_SET_PROC_COEF, 0x4000 },
+			{}
+		},
+	},
+	[ALC668_FIXUP_ASUS_G751] = {
+		.type = HDA_FIXUP_PINS,
+		.v.pins = (const struct hda_pintbl[]) {
+			{ 0x16, 0x0421101f }, /* HP */
+			{}
+		},
+		.chained = true,
+		.chain_id = ALC668_FIXUP_MIC_COEF
+	},
 	[ALC891_FIXUP_HEADSET_MODE] = {
 	[ALC891_FIXUP_HEADSET_MODE] = {
 		.type = HDA_FIXUP_FUNC,
 		.type = HDA_FIXUP_FUNC,
 		.v.func = alc_fixup_headset_mode,
 		.v.func = alc_fixup_headset_mode,
@@ -8080,6 +8105,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50),
 	SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50),
 	SND_PCI_QUIRK(0x1043, 0x13df, "Asus N550JX", ALC662_FIXUP_BASS_1A),
 	SND_PCI_QUIRK(0x1043, 0x13df, "Asus N550JX", ALC662_FIXUP_BASS_1A),
 	SND_PCI_QUIRK(0x1043, 0x129d, "Asus N750", ALC662_FIXUP_ASUS_Nx50),
 	SND_PCI_QUIRK(0x1043, 0x129d, "Asus N750", ALC662_FIXUP_ASUS_Nx50),
+	SND_PCI_QUIRK(0x1043, 0x12ff, "ASUS G751", ALC668_FIXUP_ASUS_G751),
 	SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
 	SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
 	SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16),
 	SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16),
 	SND_PCI_QUIRK(0x1043, 0x177d, "ASUS N551", ALC668_FIXUP_ASUS_Nx51),
 	SND_PCI_QUIRK(0x1043, 0x177d, "ASUS N551", ALC668_FIXUP_ASUS_Nx51),
@@ -8184,6 +8210,7 @@ static const struct hda_model_fixup alc662_fixup_models[] = {
 	{.id = ALC668_FIXUP_DELL_XPS13, .name = "dell-xps13"},
 	{.id = ALC668_FIXUP_DELL_XPS13, .name = "dell-xps13"},
 	{.id = ALC662_FIXUP_ASUS_Nx50, .name = "asus-nx50"},
 	{.id = ALC662_FIXUP_ASUS_Nx50, .name = "asus-nx50"},
 	{.id = ALC668_FIXUP_ASUS_Nx51, .name = "asus-nx51"},
 	{.id = ALC668_FIXUP_ASUS_Nx51, .name = "asus-nx51"},
+	{.id = ALC668_FIXUP_ASUS_G751, .name = "asus-g751"},
 	{.id = ALC891_FIXUP_HEADSET_MODE, .name = "alc891-headset"},
 	{.id = ALC891_FIXUP_HEADSET_MODE, .name = "alc891-headset"},
 	{.id = ALC891_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc891-headset-multi"},
 	{.id = ALC891_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc891-headset-multi"},
 	{.id = ALC662_FIXUP_ACER_VERITON, .name = "acer-veriton"},
 	{.id = ALC662_FIXUP_ACER_VERITON, .name = "acer-veriton"},

+ 1 - 1
sound/pci/hda/patch_si3054.c

@@ -27,7 +27,7 @@
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <sound/core.h>
 #include <sound/core.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
 #include "hda_local.h"
 #include "hda_local.h"
 
 
 /* si3054 verbs */
 /* si3054 verbs */

+ 21 - 1
sound/pci/hda/patch_sigmatel.c

@@ -32,7 +32,7 @@
 #include <linux/module.h>
 #include <linux/module.h>
 #include <sound/core.h>
 #include <sound/core.h>
 #include <sound/jack.h>
 #include <sound/jack.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
 #include "hda_local.h"
 #include "hda_local.h"
 #include "hda_auto_parser.h"
 #include "hda_auto_parser.h"
 #include "hda_beep.h"
 #include "hda_beep.h"
@@ -77,6 +77,7 @@ enum {
 	STAC_DELL_M6_BOTH,
 	STAC_DELL_M6_BOTH,
 	STAC_DELL_EQ,
 	STAC_DELL_EQ,
 	STAC_ALIENWARE_M17X,
 	STAC_ALIENWARE_M17X,
+	STAC_ELO_VUPOINT_15MX,
 	STAC_92HD89XX_HP_FRONT_JACK,
 	STAC_92HD89XX_HP_FRONT_JACK,
 	STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK,
 	STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK,
 	STAC_92HD73XX_ASUS_MOBO,
 	STAC_92HD73XX_ASUS_MOBO,
@@ -1879,6 +1880,18 @@ static void stac92hd73xx_fixup_no_jd(struct hda_codec *codec,
 		codec->no_jack_detect = 1;
 		codec->no_jack_detect = 1;
 }
 }
 
 
+
+static void stac92hd73xx_disable_automute(struct hda_codec *codec,
+				     const struct hda_fixup *fix, int action)
+{
+	struct sigmatel_spec *spec = codec->spec;
+
+	if (action != HDA_FIXUP_ACT_PRE_PROBE)
+		return;
+
+	spec->gen.suppress_auto_mute = 1;
+}
+
 static const struct hda_fixup stac92hd73xx_fixups[] = {
 static const struct hda_fixup stac92hd73xx_fixups[] = {
 	[STAC_92HD73XX_REF] = {
 	[STAC_92HD73XX_REF] = {
 		.type = HDA_FIXUP_FUNC,
 		.type = HDA_FIXUP_FUNC,
@@ -1904,6 +1917,10 @@ static const struct hda_fixup stac92hd73xx_fixups[] = {
 		.type = HDA_FIXUP_FUNC,
 		.type = HDA_FIXUP_FUNC,
 		.v.func = stac92hd73xx_fixup_alienware_m17x,
 		.v.func = stac92hd73xx_fixup_alienware_m17x,
 	},
 	},
+	[STAC_ELO_VUPOINT_15MX] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = stac92hd73xx_disable_automute,
+	},
 	[STAC_92HD73XX_INTEL] = {
 	[STAC_92HD73XX_INTEL] = {
 		.type = HDA_FIXUP_PINS,
 		.type = HDA_FIXUP_PINS,
 		.v.pins = intel_dg45id_pin_configs,
 		.v.pins = intel_dg45id_pin_configs,
@@ -1942,6 +1959,7 @@ static const struct hda_model_fixup stac92hd73xx_models[] = {
 	{ .id = STAC_DELL_M6_BOTH, .name = "dell-m6" },
 	{ .id = STAC_DELL_M6_BOTH, .name = "dell-m6" },
 	{ .id = STAC_DELL_EQ, .name = "dell-eq" },
 	{ .id = STAC_DELL_EQ, .name = "dell-eq" },
 	{ .id = STAC_ALIENWARE_M17X, .name = "alienware" },
 	{ .id = STAC_ALIENWARE_M17X, .name = "alienware" },
+	{ .id = STAC_ELO_VUPOINT_15MX, .name = "elo-vupoint-15mx" },
 	{ .id = STAC_92HD73XX_ASUS_MOBO, .name = "asus-mobo" },
 	{ .id = STAC_92HD73XX_ASUS_MOBO, .name = "asus-mobo" },
 	{}
 	{}
 };
 };
@@ -1991,6 +2009,8 @@ static const struct snd_pci_quirk stac92hd73xx_fixup_tbl[] = {
 		      "Alienware M17x", STAC_ALIENWARE_M17X),
 		      "Alienware M17x", STAC_ALIENWARE_M17X),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0490,
 	SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0490,
 		      "Alienware M17x R3", STAC_DELL_EQ),
 		      "Alienware M17x R3", STAC_DELL_EQ),
+	SND_PCI_QUIRK(0x1059, 0x1011,
+		      "ELO VuPoint 15MX", STAC_ELO_VUPOINT_15MX),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1927,
 	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1927,
 				"HP Z1 G2", STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK),
 				"HP Z1 G2", STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK),
 	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2b17,
 	SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2b17,

+ 1 - 1
sound/pci/hda/patch_via.c

@@ -52,7 +52,7 @@
 #include <linux/module.h>
 #include <linux/module.h>
 #include <sound/core.h>
 #include <sound/core.h>
 #include <sound/asoundef.h>
 #include <sound/asoundef.h>
-#include "hda_codec.h"
+#include <sound/hda_codec.h>
 #include "hda_local.h"
 #include "hda_local.h"
 #include "hda_auto_parser.h"
 #include "hda_auto_parser.h"
 #include "hda_jack.h"
 #include "hda_jack.h"

+ 16 - 81
sound/pci/intel8x0.c

@@ -38,11 +38,6 @@
 #include <sound/ac97_codec.h>
 #include <sound/ac97_codec.h>
 #include <sound/info.h>
 #include <sound/info.h>
 #include <sound/initval.h>
 #include <sound/initval.h>
-/* for 440MX workaround */
-#include <asm/pgtable.h>
-#ifdef CONFIG_X86
-#include <asm/set_memory.h>
-#endif
 
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("Intel 82801AA,82901AB,i810,i820,i830,i840,i845,MX440; SiS 7012; Ali 5455");
 MODULE_DESCRIPTION("Intel 82801AA,82901AB,i810,i820,i830,i840,i845,MX440; SiS 7012; Ali 5455");
@@ -374,7 +369,6 @@ struct ichdev {
 	unsigned int ali_slot;			/* ALI DMA slot */
 	unsigned int ali_slot;			/* ALI DMA slot */
 	struct ac97_pcm *pcm;
 	struct ac97_pcm *pcm;
 	int pcm_open_flag;
 	int pcm_open_flag;
-	unsigned int page_attr_changed: 1;
 	unsigned int suspended: 1;
 	unsigned int suspended: 1;
 };
 };
 
 
@@ -724,25 +718,6 @@ static void snd_intel8x0_setup_periods(struct intel8x0 *chip, struct ichdev *ich
 	iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI);
 	iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI);
 }
 }
 
 
-#ifdef __i386__
-/*
- * Intel 82443MX running a 100MHz processor system bus has a hardware bug,
- * which aborts PCI busmaster for audio transfer.  A workaround is to set
- * the pages as non-cached.  For details, see the errata in
- *	http://download.intel.com/design/chipsets/specupdt/24505108.pdf
- */
-static void fill_nocache(void *buf, int size, int nocache)
-{
-	size = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
-	if (nocache)
-		set_pages_uc(virt_to_page(buf), size);
-	else
-		set_pages_wb(virt_to_page(buf), size);
-}
-#else
-#define fill_nocache(buf, size, nocache) do { ; } while (0)
-#endif
-
 /*
 /*
  *  Interrupt handler
  *  Interrupt handler
  */
  */
@@ -850,7 +825,7 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd
 	switch (cmd) {
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_RESUME:
 		ichdev->suspended = 0;
 		ichdev->suspended = 0;
-		/* fallthru */
+		/* fall through */
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		val = ICH_IOCE | ICH_STARTBM;
 		val = ICH_IOCE | ICH_STARTBM;
@@ -858,7 +833,7 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd
 		break;
 		break;
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 		ichdev->suspended = 1;
 		ichdev->suspended = 1;
-		/* fallthru */
+		/* fall through */
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_STOP:
 		val = 0;
 		val = 0;
 		break;
 		break;
@@ -892,7 +867,7 @@ static int snd_intel8x0_ali_trigger(struct snd_pcm_substream *substream, int cmd
 	switch (cmd) {
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_RESUME:
 		ichdev->suspended = 0;
 		ichdev->suspended = 0;
-		/* fallthru */
+		/* fall through */
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -909,7 +884,7 @@ static int snd_intel8x0_ali_trigger(struct snd_pcm_substream *substream, int cmd
 		break;
 		break;
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 		ichdev->suspended = 1;
 		ichdev->suspended = 1;
-		/* fallthru */
+		/* fall through */
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		/* pause */
 		/* pause */
@@ -938,23 +913,12 @@ static int snd_intel8x0_hw_params(struct snd_pcm_substream *substream,
 {
 {
 	struct intel8x0 *chip = snd_pcm_substream_chip(substream);
 	struct intel8x0 *chip = snd_pcm_substream_chip(substream);
 	struct ichdev *ichdev = get_ichdev(substream);
 	struct ichdev *ichdev = get_ichdev(substream);
-	struct snd_pcm_runtime *runtime = substream->runtime;
 	int dbl = params_rate(hw_params) > 48000;
 	int dbl = params_rate(hw_params) > 48000;
 	int err;
 	int err;
 
 
-	if (chip->fix_nocache && ichdev->page_attr_changed) {
-		fill_nocache(runtime->dma_area, runtime->dma_bytes, 0); /* clear */
-		ichdev->page_attr_changed = 0;
-	}
 	err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
 	err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
 	if (err < 0)
 	if (err < 0)
 		return err;
 		return err;
-	if (chip->fix_nocache) {
-		if (runtime->dma_area && ! ichdev->page_attr_changed) {
-			fill_nocache(runtime->dma_area, runtime->dma_bytes, 1);
-			ichdev->page_attr_changed = 1;
-		}
-	}
 	if (ichdev->pcm_open_flag) {
 	if (ichdev->pcm_open_flag) {
 		snd_ac97_pcm_close(ichdev->pcm);
 		snd_ac97_pcm_close(ichdev->pcm);
 		ichdev->pcm_open_flag = 0;
 		ichdev->pcm_open_flag = 0;
@@ -974,17 +938,12 @@ static int snd_intel8x0_hw_params(struct snd_pcm_substream *substream,
 
 
 static int snd_intel8x0_hw_free(struct snd_pcm_substream *substream)
 static int snd_intel8x0_hw_free(struct snd_pcm_substream *substream)
 {
 {
-	struct intel8x0 *chip = snd_pcm_substream_chip(substream);
 	struct ichdev *ichdev = get_ichdev(substream);
 	struct ichdev *ichdev = get_ichdev(substream);
 
 
 	if (ichdev->pcm_open_flag) {
 	if (ichdev->pcm_open_flag) {
 		snd_ac97_pcm_close(ichdev->pcm);
 		snd_ac97_pcm_close(ichdev->pcm);
 		ichdev->pcm_open_flag = 0;
 		ichdev->pcm_open_flag = 0;
 	}
 	}
-	if (chip->fix_nocache && ichdev->page_attr_changed) {
-		fill_nocache(substream->runtime->dma_area, substream->runtime->dma_bytes, 0);
-		ichdev->page_attr_changed = 0;
-	}
 	return snd_pcm_lib_free_pages(substream);
 	return snd_pcm_lib_free_pages(substream);
 }
 }
 
 
@@ -1510,6 +1469,9 @@ struct ich_pcm_table {
 	int ac97_idx;
 	int ac97_idx;
 };
 };
 
 
+#define intel8x0_dma_type(chip) \
+	((chip)->fix_nocache ? SNDRV_DMA_TYPE_DEV_UC : SNDRV_DMA_TYPE_DEV)
+
 static int snd_intel8x0_pcm1(struct intel8x0 *chip, int device,
 static int snd_intel8x0_pcm1(struct intel8x0 *chip, int device,
 			     struct ich_pcm_table *rec)
 			     struct ich_pcm_table *rec)
 {
 {
@@ -1540,7 +1502,7 @@ static int snd_intel8x0_pcm1(struct intel8x0 *chip, int device,
 		strcpy(pcm->name, chip->card->shortname);
 		strcpy(pcm->name, chip->card->shortname);
 	chip->pcm[device] = pcm;
 	chip->pcm[device] = pcm;
 
 
-	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+	snd_pcm_lib_preallocate_pages_for_all(pcm, intel8x0_dma_type(chip),
 					      snd_dma_pci_data(chip->pci),
 					      snd_dma_pci_data(chip->pci),
 					      rec->prealloc_size, rec->prealloc_max_size);
 					      rec->prealloc_size, rec->prealloc_max_size);
 
 
@@ -2629,11 +2591,8 @@ static int snd_intel8x0_free(struct intel8x0 *chip)
       __hw_end:
       __hw_end:
 	if (chip->irq >= 0)
 	if (chip->irq >= 0)
 		free_irq(chip->irq, chip);
 		free_irq(chip->irq, chip);
-	if (chip->bdbars.area) {
-		if (chip->fix_nocache)
-			fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 0);
+	if (chip->bdbars.area)
 		snd_dma_free_pages(&chip->bdbars);
 		snd_dma_free_pages(&chip->bdbars);
-	}
 	if (chip->addr)
 	if (chip->addr)
 		pci_iounmap(chip->pci, chip->addr);
 		pci_iounmap(chip->pci, chip->addr);
 	if (chip->bmaddr)
 	if (chip->bmaddr)
@@ -2657,17 +2616,6 @@ static int intel8x0_suspend(struct device *dev)
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
 	for (i = 0; i < chip->pcm_devs; i++)
 	for (i = 0; i < chip->pcm_devs; i++)
 		snd_pcm_suspend_all(chip->pcm[i]);
 		snd_pcm_suspend_all(chip->pcm[i]);
-	/* clear nocache */
-	if (chip->fix_nocache) {
-		for (i = 0; i < chip->bdbars_count; i++) {
-			struct ichdev *ichdev = &chip->ichd[i];
-			if (ichdev->substream && ichdev->page_attr_changed) {
-				struct snd_pcm_runtime *runtime = ichdev->substream->runtime;
-				if (runtime->dma_area)
-					fill_nocache(runtime->dma_area, runtime->dma_bytes, 0);
-			}
-		}
-	}
 	for (i = 0; i < chip->ncodecs; i++)
 	for (i = 0; i < chip->ncodecs; i++)
 		snd_ac97_suspend(chip->ac97[i]);
 		snd_ac97_suspend(chip->ac97[i]);
 	if (chip->device_type == DEVICE_INTEL_ICH4)
 	if (chip->device_type == DEVICE_INTEL_ICH4)
@@ -2708,25 +2656,9 @@ static int intel8x0_resume(struct device *dev)
 			  ICH_PCM_SPDIF_1011);
 			  ICH_PCM_SPDIF_1011);
 	}
 	}
 
 
-	/* refill nocache */
-	if (chip->fix_nocache)
-		fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 1);
-
 	for (i = 0; i < chip->ncodecs; i++)
 	for (i = 0; i < chip->ncodecs; i++)
 		snd_ac97_resume(chip->ac97[i]);
 		snd_ac97_resume(chip->ac97[i]);
 
 
-	/* refill nocache */
-	if (chip->fix_nocache) {
-		for (i = 0; i < chip->bdbars_count; i++) {
-			struct ichdev *ichdev = &chip->ichd[i];
-			if (ichdev->substream && ichdev->page_attr_changed) {
-				struct snd_pcm_runtime *runtime = ichdev->substream->runtime;
-				if (runtime->dma_area)
-					fill_nocache(runtime->dma_area, runtime->dma_bytes, 1);
-			}
-		}
-	}
-
 	/* resume status */
 	/* resume status */
 	for (i = 0; i < chip->bdbars_count; i++) {
 	for (i = 0; i < chip->bdbars_count; i++) {
 		struct ichdev *ichdev = &chip->ichd[i];
 		struct ichdev *ichdev = &chip->ichd[i];
@@ -3057,6 +2989,12 @@ static int snd_intel8x0_create(struct snd_card *card,
 
 
 	chip->inside_vm = snd_intel8x0_inside_vm(pci);
 	chip->inside_vm = snd_intel8x0_inside_vm(pci);
 
 
+	/*
+	 * Intel 82443MX running a 100MHz processor system bus has a hardware
+	 * bug, which aborts PCI busmaster for audio transfer.  A workaround
+	 * is to set the pages as non-cached.  For details, see the errata in
+	 *     http://download.intel.com/design/chipsets/specupdt/24505108.pdf
+	 */
 	if (pci->vendor == PCI_VENDOR_ID_INTEL &&
 	if (pci->vendor == PCI_VENDOR_ID_INTEL &&
 	    pci->device == PCI_DEVICE_ID_INTEL_440MX)
 	    pci->device == PCI_DEVICE_ID_INTEL_440MX)
 		chip->fix_nocache = 1; /* enable workaround */
 		chip->fix_nocache = 1; /* enable workaround */
@@ -3128,7 +3066,7 @@ static int snd_intel8x0_create(struct snd_card *card,
 
 
 	/* allocate buffer descriptor lists */
 	/* allocate buffer descriptor lists */
 	/* the start of each lists must be aligned to 8 bytes */
 	/* the start of each lists must be aligned to 8 bytes */
-	if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
+	if (snd_dma_alloc_pages(intel8x0_dma_type(chip), snd_dma_pci_data(pci),
 				chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2,
 				chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2,
 				&chip->bdbars) < 0) {
 				&chip->bdbars) < 0) {
 		snd_intel8x0_free(chip);
 		snd_intel8x0_free(chip);
@@ -3137,9 +3075,6 @@ static int snd_intel8x0_create(struct snd_card *card,
 	}
 	}
 	/* tables must be aligned to 8 bytes here, but the kernel pages
 	/* tables must be aligned to 8 bytes here, but the kernel pages
 	   are much bigger, so we don't care (on i386) */
 	   are much bigger, so we don't care (on i386) */
-	/* workaround for 440MX */
-	if (chip->fix_nocache)
-		fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 1);
 	int_sta_masks = 0;
 	int_sta_masks = 0;
 	for (i = 0; i < chip->bdbars_count; i++) {
 	for (i = 0; i < chip->bdbars_count; i++) {
 		ichdev = &chip->ichd[i];
 		ichdev = &chip->ichd[i];

+ 10 - 10
sound/pci/intel8x0m.c

@@ -1171,16 +1171,6 @@ static int snd_intel8x0m_create(struct snd_card *card,
 	}
 	}
 
 
  port_inited:
  port_inited:
-	if (request_irq(pci->irq, snd_intel8x0m_interrupt, IRQF_SHARED,
-			KBUILD_MODNAME, chip)) {
-		dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
-		snd_intel8x0m_free(chip);
-		return -EBUSY;
-	}
-	chip->irq = pci->irq;
-	pci_set_master(pci);
-	synchronize_irq(chip->irq);
-
 	/* initialize offsets */
 	/* initialize offsets */
 	chip->bdbars_count = 2;
 	chip->bdbars_count = 2;
 	tbl = intel_regs;
 	tbl = intel_regs;
@@ -1224,11 +1214,21 @@ static int snd_intel8x0m_create(struct snd_card *card,
 	chip->int_sta_reg = ICH_REG_GLOB_STA;
 	chip->int_sta_reg = ICH_REG_GLOB_STA;
 	chip->int_sta_mask = int_sta_masks;
 	chip->int_sta_mask = int_sta_masks;
 
 
+	pci_set_master(pci);
+
 	if ((err = snd_intel8x0m_chip_init(chip, 1)) < 0) {
 	if ((err = snd_intel8x0m_chip_init(chip, 1)) < 0) {
 		snd_intel8x0m_free(chip);
 		snd_intel8x0m_free(chip);
 		return err;
 		return err;
 	}
 	}
 
 
+	if (request_irq(pci->irq, snd_intel8x0m_interrupt, IRQF_SHARED,
+			KBUILD_MODNAME, chip)) {
+		dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
+		snd_intel8x0m_free(chip);
+		return -EBUSY;
+	}
+	chip->irq = pci->irq;
+
 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
 		snd_intel8x0m_free(chip);
 		snd_intel8x0m_free(chip);
 		return err;
 		return err;

+ 8 - 14
sound/pci/rme32.c

@@ -319,7 +319,8 @@ static const struct snd_pcm_hardware snd_rme32_spdif_info = {
 			 SNDRV_PCM_INFO_MMAP_VALID |
 			 SNDRV_PCM_INFO_MMAP_VALID |
 			 SNDRV_PCM_INFO_INTERLEAVED | 
 			 SNDRV_PCM_INFO_INTERLEAVED | 
 			 SNDRV_PCM_INFO_PAUSE |
 			 SNDRV_PCM_INFO_PAUSE |
-			 SNDRV_PCM_INFO_SYNC_START),
+			 SNDRV_PCM_INFO_SYNC_START |
+			 SNDRV_PCM_INFO_SYNC_APPLPTR),
 	.formats =	(SNDRV_PCM_FMTBIT_S16_LE | 
 	.formats =	(SNDRV_PCM_FMTBIT_S16_LE | 
 			 SNDRV_PCM_FMTBIT_S32_LE),
 			 SNDRV_PCM_FMTBIT_S32_LE),
 	.rates =	(SNDRV_PCM_RATE_32000 |
 	.rates =	(SNDRV_PCM_RATE_32000 |
@@ -346,7 +347,8 @@ static const struct snd_pcm_hardware snd_rme32_adat_info =
 			      SNDRV_PCM_INFO_MMAP_VALID |
 			      SNDRV_PCM_INFO_MMAP_VALID |
 			      SNDRV_PCM_INFO_INTERLEAVED |
 			      SNDRV_PCM_INFO_INTERLEAVED |
 			      SNDRV_PCM_INFO_PAUSE |
 			      SNDRV_PCM_INFO_PAUSE |
-			      SNDRV_PCM_INFO_SYNC_START),
+			      SNDRV_PCM_INFO_SYNC_START |
+			      SNDRV_PCM_INFO_SYNC_APPLPTR),
 	.formats=            SNDRV_PCM_FMTBIT_S16_LE,
 	.formats=            SNDRV_PCM_FMTBIT_S16_LE,
 	.rates =             (SNDRV_PCM_RATE_44100 | 
 	.rates =             (SNDRV_PCM_RATE_44100 | 
 			      SNDRV_PCM_RATE_48000),
 			      SNDRV_PCM_RATE_48000),
@@ -370,7 +372,8 @@ static const struct snd_pcm_hardware snd_rme32_spdif_fd_info = {
 			 SNDRV_PCM_INFO_MMAP_VALID |
 			 SNDRV_PCM_INFO_MMAP_VALID |
 			 SNDRV_PCM_INFO_INTERLEAVED | 
 			 SNDRV_PCM_INFO_INTERLEAVED | 
 			 SNDRV_PCM_INFO_PAUSE |
 			 SNDRV_PCM_INFO_PAUSE |
-			 SNDRV_PCM_INFO_SYNC_START),
+			 SNDRV_PCM_INFO_SYNC_START |
+			 SNDRV_PCM_INFO_SYNC_APPLPTR),
 	.formats =	(SNDRV_PCM_FMTBIT_S16_LE | 
 	.formats =	(SNDRV_PCM_FMTBIT_S16_LE | 
 			 SNDRV_PCM_FMTBIT_S32_LE),
 			 SNDRV_PCM_FMTBIT_S32_LE),
 	.rates =	(SNDRV_PCM_RATE_32000 |
 	.rates =	(SNDRV_PCM_RATE_32000 |
@@ -397,7 +400,8 @@ static const struct snd_pcm_hardware snd_rme32_adat_fd_info =
 			      SNDRV_PCM_INFO_MMAP_VALID |
 			      SNDRV_PCM_INFO_MMAP_VALID |
 			      SNDRV_PCM_INFO_INTERLEAVED |
 			      SNDRV_PCM_INFO_INTERLEAVED |
 			      SNDRV_PCM_INFO_PAUSE |
 			      SNDRV_PCM_INFO_PAUSE |
-			      SNDRV_PCM_INFO_SYNC_START),
+			      SNDRV_PCM_INFO_SYNC_START |
+			      SNDRV_PCM_INFO_SYNC_APPLPTR),
 	.formats=            SNDRV_PCM_FMTBIT_S16_LE,
 	.formats=            SNDRV_PCM_FMTBIT_S16_LE,
 	.rates =             (SNDRV_PCM_RATE_44100 | 
 	.rates =             (SNDRV_PCM_RATE_44100 | 
 			      SNDRV_PCM_RATE_48000),
 			      SNDRV_PCM_RATE_48000),
@@ -1104,16 +1108,6 @@ snd_rme32_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 		snd_pcm_trigger_done(s, substream);
 		snd_pcm_trigger_done(s, substream);
 	}
 	}
 	
 	
-	/* prefill playback buffer */
-	if (cmd == SNDRV_PCM_TRIGGER_START && rme32->fullduplex_mode) {
-		snd_pcm_group_for_each_entry(s, substream) {
-			if (s == rme32->playback_substream) {
-				s->ops->ack(s);
-				break;
-			}
-		}
-	}
-
 	switch (cmd) {
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_START:
 		if (rme32->running && ! RME32_ISWORKING(rme32))
 		if (rme32->running && ! RME32_ISWORKING(rme32))

+ 1 - 1
sound/pci/rme9652/hdspm.c

@@ -6534,7 +6534,7 @@ static int snd_hdspm_create_alsa_devices(struct snd_card *card,
 	dev_dbg(card->dev, "Update mixer controls...\n");
 	dev_dbg(card->dev, "Update mixer controls...\n");
 	hdspm_update_simple_mixer_controls(hdspm);
 	hdspm_update_simple_mixer_controls(hdspm);
 
 
-	dev_dbg(card->dev, "Initializeing complete ???\n");
+	dev_dbg(card->dev, "Initializing complete?\n");
 
 
 	err = snd_card_register(card);
 	err = snd_card_register(card);
 	if (err < 0) {
 	if (err < 0) {

+ 68 - 9
sound/soc/amd/acp-da7219-max98357a.c

@@ -42,7 +42,7 @@
 #include "../codecs/da7219.h"
 #include "../codecs/da7219.h"
 #include "../codecs/da7219-aad.h"
 #include "../codecs/da7219-aad.h"
 
 
-#define CZ_PLAT_CLK 25000000
+#define CZ_PLAT_CLK 48000000
 #define DUAL_CHANNEL		2
 #define DUAL_CHANNEL		2
 
 
 static struct snd_soc_jack cz_jack;
 static struct snd_soc_jack cz_jack;
@@ -75,7 +75,7 @@ static int cz_da7219_init(struct snd_soc_pcm_runtime *rtd)
 	da7219_dai_clk = clk_get(component->dev, "da7219-dai-clks");
 	da7219_dai_clk = clk_get(component->dev, "da7219-dai-clks");
 
 
 	ret = snd_soc_card_jack_new(card, "Headset Jack",
 	ret = snd_soc_card_jack_new(card, "Headset Jack",
-				SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
+				SND_JACK_HEADSET | SND_JACK_LINEOUT |
 				SND_JACK_BTN_0 | SND_JACK_BTN_1 |
 				SND_JACK_BTN_0 | SND_JACK_BTN_1 |
 				SND_JACK_BTN_2 | SND_JACK_BTN_3,
 				SND_JACK_BTN_2 | SND_JACK_BTN_3,
 				&cz_jack, NULL, 0);
 				&cz_jack, NULL, 0);
@@ -133,7 +133,7 @@ static const struct snd_pcm_hw_constraint_list constraints_channels = {
 	.mask = 0,
 	.mask = 0,
 };
 };
 
 
-static int cz_da7219_startup(struct snd_pcm_substream *substream)
+static int cz_da7219_play_startup(struct snd_pcm_substream *substream)
 {
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -150,7 +150,28 @@ static int cz_da7219_startup(struct snd_pcm_substream *substream)
 	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
 	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
 				   &constraints_rates);
 				   &constraints_rates);
 
 
-	machine->i2s_instance = I2S_SP_INSTANCE;
+	machine->play_i2s_instance = I2S_SP_INSTANCE;
+	return da7219_clk_enable(substream);
+}
+
+static int cz_da7219_cap_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_card *card = rtd->card;
+	struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
+
+	/*
+	 * On this platform for PCM device we support stereo
+	 */
+
+	runtime->hw.channels_max = DUAL_CHANNEL;
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+				   &constraints_channels);
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+				   &constraints_rates);
+
+	machine->cap_i2s_instance = I2S_SP_INSTANCE;
 	machine->capture_channel = CAP_CHANNEL1;
 	machine->capture_channel = CAP_CHANNEL1;
 	return da7219_clk_enable(substream);
 	return da7219_clk_enable(substream);
 }
 }
@@ -162,11 +183,22 @@ static void cz_da7219_shutdown(struct snd_pcm_substream *substream)
 
 
 static int cz_max_startup(struct snd_pcm_substream *substream)
 static int cz_max_startup(struct snd_pcm_substream *substream)
 {
 {
+	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_card *card = rtd->card;
 	struct snd_soc_card *card = rtd->card;
 	struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
 	struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
 
 
-	machine->i2s_instance = I2S_BT_INSTANCE;
+	/*
+	 * On this platform for PCM device we support stereo
+	 */
+
+	runtime->hw.channels_max = DUAL_CHANNEL;
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+				   &constraints_channels);
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+				   &constraints_rates);
+
+	machine->play_i2s_instance = I2S_BT_INSTANCE;
 	return da7219_clk_enable(substream);
 	return da7219_clk_enable(substream);
 }
 }
 
 
@@ -177,21 +209,43 @@ static void cz_max_shutdown(struct snd_pcm_substream *substream)
 
 
 static int cz_dmic0_startup(struct snd_pcm_substream *substream)
 static int cz_dmic0_startup(struct snd_pcm_substream *substream)
 {
 {
+	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_card *card = rtd->card;
 	struct snd_soc_card *card = rtd->card;
 	struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
 	struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
 
 
-	machine->i2s_instance = I2S_BT_INSTANCE;
+	/*
+	 * On this platform for PCM device we support stereo
+	 */
+
+	runtime->hw.channels_max = DUAL_CHANNEL;
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+				   &constraints_channels);
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+				   &constraints_rates);
+
+	machine->cap_i2s_instance = I2S_BT_INSTANCE;
 	return da7219_clk_enable(substream);
 	return da7219_clk_enable(substream);
 }
 }
 
 
 static int cz_dmic1_startup(struct snd_pcm_substream *substream)
 static int cz_dmic1_startup(struct snd_pcm_substream *substream)
 {
 {
+	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_card *card = rtd->card;
 	struct snd_soc_card *card = rtd->card;
 	struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
 	struct acp_platform_info *machine = snd_soc_card_get_drvdata(card);
 
 
-	machine->i2s_instance = I2S_SP_INSTANCE;
+	/*
+	 * On this platform for PCM device we support stereo
+	 */
+
+	runtime->hw.channels_max = DUAL_CHANNEL;
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+				   &constraints_channels);
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+				   &constraints_rates);
+
+	machine->cap_i2s_instance = I2S_SP_INSTANCE;
 	machine->capture_channel = CAP_CHANNEL0;
 	machine->capture_channel = CAP_CHANNEL0;
 	return da7219_clk_enable(substream);
 	return da7219_clk_enable(substream);
 }
 }
@@ -201,8 +255,13 @@ static void cz_dmic_shutdown(struct snd_pcm_substream *substream)
 	da7219_clk_disable();
 	da7219_clk_disable();
 }
 }
 
 
+static const struct snd_soc_ops cz_da7219_play_ops = {
+	.startup = cz_da7219_play_startup,
+	.shutdown = cz_da7219_shutdown,
+};
+
 static const struct snd_soc_ops cz_da7219_cap_ops = {
 static const struct snd_soc_ops cz_da7219_cap_ops = {
-	.startup = cz_da7219_startup,
+	.startup = cz_da7219_cap_startup,
 	.shutdown = cz_da7219_shutdown,
 	.shutdown = cz_da7219_shutdown,
 };
 };
 
 
@@ -233,7 +292,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = {
 				| SND_SOC_DAIFMT_CBM_CFM,
 				| SND_SOC_DAIFMT_CBM_CFM,
 		.init = cz_da7219_init,
 		.init = cz_da7219_init,
 		.dpcm_playback = 1,
 		.dpcm_playback = 1,
-		.ops = &cz_da7219_cap_ops,
+		.ops = &cz_da7219_play_ops,
 	},
 	},
 	{
 	{
 		.name = "amd-da7219-cap",
 		.name = "amd-da7219-cap",

+ 20 - 10
sound/soc/amd/acp-pcm-dma.c

@@ -867,8 +867,12 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
 		return -EINVAL;
 		return -EINVAL;
 
 
 	if (pinfo) {
 	if (pinfo) {
-		rtd->i2s_instance = pinfo->i2s_instance;
-		rtd->capture_channel = pinfo->capture_channel;
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			rtd->i2s_instance = pinfo->play_i2s_instance;
+		} else {
+			rtd->i2s_instance = pinfo->cap_i2s_instance;
+			rtd->capture_channel = pinfo->capture_channel;
+		}
 	}
 	}
 	if (adata->asic_type == CHIP_STONEY) {
 	if (adata->asic_type == CHIP_STONEY) {
 		val = acp_reg_read(adata->acp_mmio,
 		val = acp_reg_read(adata->acp_mmio,
@@ -1036,16 +1040,22 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream)
 
 
 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
 		period_bytes = frames_to_bytes(runtime, runtime->period_size);
 		period_bytes = frames_to_bytes(runtime, runtime->period_size);
-		dscr = acp_reg_read(rtd->acp_mmio, rtd->dma_curr_dscr);
-		if (dscr == rtd->dma_dscr_idx_1)
-			pos = period_bytes;
-		else
-			pos = 0;
 		bytescount = acp_get_byte_count(rtd);
 		bytescount = acp_get_byte_count(rtd);
-		if (bytescount > rtd->bytescount)
+		if (bytescount >= rtd->bytescount)
 			bytescount -= rtd->bytescount;
 			bytescount -= rtd->bytescount;
-		delay = do_div(bytescount, period_bytes);
-		runtime->delay = bytes_to_frames(runtime, delay);
+		if (bytescount < period_bytes) {
+			pos = 0;
+		} else {
+			dscr = acp_reg_read(rtd->acp_mmio, rtd->dma_curr_dscr);
+			if (dscr == rtd->dma_dscr_idx_1)
+				pos = period_bytes;
+			else
+				pos = 0;
+		}
+		if (bytescount > 0) {
+			delay = do_div(bytescount, period_bytes);
+			runtime->delay = bytes_to_frames(runtime, delay);
+		}
 	} else {
 	} else {
 		buffersize = frames_to_bytes(runtime, runtime->buffer_size);
 		buffersize = frames_to_bytes(runtime, runtime->buffer_size);
 		bytescount = acp_get_byte_count(rtd);
 		bytescount = acp_get_byte_count(rtd);

+ 2 - 1
sound/soc/amd/acp.h

@@ -158,7 +158,8 @@ struct audio_drv_data {
  * and dma driver
  * and dma driver
  */
  */
 struct acp_platform_info {
 struct acp_platform_info {
-	u16 i2s_instance;
+	u16 play_i2s_instance;
+	u16 cap_i2s_instance;
 	u16 capture_channel;
 	u16 capture_channel;
 };
 };
 
 

+ 12 - 0
sound/soc/atmel/Kconfig

@@ -97,4 +97,16 @@ config SND_ATMEL_SOC_I2S
 	help
 	help
 	  Say Y or M if you want to add support for Atmel ASoc driver for boards
 	  Say Y or M if you want to add support for Atmel ASoc driver for boards
 	  using I2S.
 	  using I2S.
+
+config SND_SOC_MIKROE_PROTO
+	tristate "Support for Mikroe-PROTO board"
+	depends on OF
+	depends on SND_SOC_I2C_AND_SPI
+	select SND_SOC_WM8731
+	help
+	  Say Y or M if you want to add support for MikroElektronika PROTO Audio
+	  Board. This board contains the WM8731 codec, which can be configured
+	  using I2C over SDA (MPU Data Input) and SCL (MPU Clock Input) pins.
+	  Both playback and capture are supported.
+
 endif
 endif

+ 2 - 0
sound/soc/atmel/Makefile

@@ -17,6 +17,7 @@ snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o
 snd-atmel-soc-classd-objs := atmel-classd.o
 snd-atmel-soc-classd-objs := atmel-classd.o
 snd-atmel-soc-pdmic-objs := atmel-pdmic.o
 snd-atmel-soc-pdmic-objs := atmel-pdmic.o
 snd-atmel-soc-tse850-pcm5142-objs := tse850-pcm5142.o
 snd-atmel-soc-tse850-pcm5142-objs := tse850-pcm5142.o
+snd-soc-mikroe-proto-objs := mikroe-proto.o
 
 
 obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
 obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
 obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o
 obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o
@@ -24,3 +25,4 @@ obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o
 obj-$(CONFIG_SND_ATMEL_SOC_CLASSD) += snd-atmel-soc-classd.o
 obj-$(CONFIG_SND_ATMEL_SOC_CLASSD) += snd-atmel-soc-classd.o
 obj-$(CONFIG_SND_ATMEL_SOC_PDMIC) += snd-atmel-soc-pdmic.o
 obj-$(CONFIG_SND_ATMEL_SOC_PDMIC) += snd-atmel-soc-pdmic.o
 obj-$(CONFIG_SND_ATMEL_SOC_TSE850_PCM5142) += snd-atmel-soc-tse850-pcm5142.o
 obj-$(CONFIG_SND_ATMEL_SOC_TSE850_PCM5142) += snd-atmel-soc-tse850-pcm5142.o
+obj-$(CONFIG_SND_SOC_MIKROE_PROTO) += snd-soc-mikroe-proto.o

+ 3 - 10
sound/soc/atmel/atmel_ssc_dai.c

@@ -1005,11 +1005,11 @@ static int asoc_ssc_init(struct device *dev)
 	struct ssc_device *ssc = dev_get_drvdata(dev);
 	struct ssc_device *ssc = dev_get_drvdata(dev);
 	int ret;
 	int ret;
 
 
-	ret = snd_soc_register_component(dev, &atmel_ssc_component,
+	ret = devm_snd_soc_register_component(dev, &atmel_ssc_component,
 					 &atmel_ssc_dai, 1);
 					 &atmel_ssc_dai, 1);
 	if (ret) {
 	if (ret) {
 		dev_err(dev, "Could not register DAI: %d\n", ret);
 		dev_err(dev, "Could not register DAI: %d\n", ret);
-		goto err;
+		return ret;
 	}
 	}
 
 
 	if (ssc->pdata->use_dma)
 	if (ssc->pdata->use_dma)
@@ -1019,15 +1019,10 @@ static int asoc_ssc_init(struct device *dev)
 
 
 	if (ret) {
 	if (ret) {
 		dev_err(dev, "Could not register PCM: %d\n", ret);
 		dev_err(dev, "Could not register PCM: %d\n", ret);
-		goto err_unregister_dai;
+		return ret;
 	}
 	}
 
 
 	return 0;
 	return 0;
-
-err_unregister_dai:
-	snd_soc_unregister_component(dev);
-err:
-	return ret;
 }
 }
 
 
 static void asoc_ssc_exit(struct device *dev)
 static void asoc_ssc_exit(struct device *dev)
@@ -1038,8 +1033,6 @@ static void asoc_ssc_exit(struct device *dev)
 		atmel_pcm_dma_platform_unregister(dev);
 		atmel_pcm_dma_platform_unregister(dev);
 	else
 	else
 		atmel_pcm_pdc_platform_unregister(dev);
 		atmel_pcm_pdc_platform_unregister(dev);
-
-	snd_soc_unregister_component(dev);
 }
 }
 
 
 /**
 /**

+ 165 - 0
sound/soc/atmel/mikroe-proto.c

@@ -0,0 +1,165 @@
+/*
+ * ASoC driver for PROTO AudioCODEC (with a WM8731)
+ *
+ * Author:      Florian Meier, <koalo@koalo.de>
+ *	      Copyright 2013
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+
+#include "../codecs/wm8731.h"
+
+#define XTAL_RATE 12288000	/* This is fixed on this board */
+
+static int snd_proto_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_card *card = rtd->card;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+	/* Set proto sysclk */
+	int ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
+					 XTAL_RATE, SND_SOC_CLOCK_IN);
+	if (ret < 0) {
+		dev_err(card->dev, "Failed to set WM8731 SYSCLK: %d\n",
+			ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget snd_proto_widget[] = {
+	SND_SOC_DAPM_MIC("Microphone Jack", NULL),
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+};
+
+static const struct snd_soc_dapm_route snd_proto_route[] = {
+	/* speaker connected to LHPOUT/RHPOUT */
+	{"Headphone Jack", NULL, "LHPOUT"},
+	{"Headphone Jack", NULL, "RHPOUT"},
+
+	/* mic is connected to Mic Jack, with WM8731 Mic Bias */
+	{"MICIN", NULL, "Mic Bias"},
+	{"Mic Bias", NULL, "Microphone Jack"},
+};
+
+/* audio machine driver */
+static struct snd_soc_card snd_proto = {
+	.name		= "snd_mikroe_proto",
+	.owner		= THIS_MODULE,
+	.dapm_widgets	= snd_proto_widget,
+	.num_dapm_widgets = ARRAY_SIZE(snd_proto_widget),
+	.dapm_routes	= snd_proto_route,
+	.num_dapm_routes = ARRAY_SIZE(snd_proto_route),
+};
+
+static int snd_proto_probe(struct platform_device *pdev)
+{
+	struct snd_soc_dai_link *dai;
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *codec_np, *cpu_np;
+	struct device_node *bitclkmaster = NULL;
+	struct device_node *framemaster = NULL;
+	unsigned int dai_fmt;
+	int ret = 0;
+
+	if (!np) {
+		dev_err(&pdev->dev, "No device node supplied\n");
+		return -EINVAL;
+	}
+
+	snd_proto.dev = &pdev->dev;
+	ret = snd_soc_of_parse_card_name(&snd_proto, "model");
+	if (ret)
+		return ret;
+
+	dai = devm_kzalloc(&pdev->dev, sizeof(*dai), GFP_KERNEL);
+	if (!dai)
+		return -ENOMEM;
+
+	snd_proto.dai_link = dai;
+	snd_proto.num_links = 1;
+
+	dai->name = "WM8731";
+	dai->stream_name = "WM8731 HiFi";
+	dai->codec_dai_name = "wm8731-hifi";
+	dai->init = &snd_proto_init;
+
+	codec_np = of_parse_phandle(np, "audio-codec", 0);
+	if (!codec_np) {
+		dev_err(&pdev->dev, "audio-codec node missing\n");
+		return -EINVAL;
+	}
+	dai->codec_of_node = codec_np;
+
+	cpu_np = of_parse_phandle(np, "i2s-controller", 0);
+	if (!cpu_np) {
+		dev_err(&pdev->dev, "i2s-controller missing\n");
+		return -EINVAL;
+	}
+	dai->cpu_of_node = cpu_np;
+	dai->platform_of_node = cpu_np;
+
+	dai_fmt = snd_soc_of_parse_daifmt(np, NULL,
+					  &bitclkmaster, &framemaster);
+	if (bitclkmaster != framemaster) {
+		dev_err(&pdev->dev, "Must be the same bitclock and frame master\n");
+		return -EINVAL;
+	}
+	if (bitclkmaster) {
+		dai_fmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
+		if (codec_np == bitclkmaster)
+			dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
+		else
+			dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
+	}
+	of_node_put(bitclkmaster);
+	of_node_put(framemaster);
+	dai->dai_fmt = dai_fmt;
+
+	of_node_put(codec_np);
+	of_node_put(cpu_np);
+
+	ret = snd_soc_register_card(&snd_proto);
+	if (ret && ret != -EPROBE_DEFER)
+		dev_err(&pdev->dev,
+			"snd_soc_register_card() failed: %d\n", ret);
+
+	return ret;
+}
+
+static int snd_proto_remove(struct platform_device *pdev)
+{
+	return snd_soc_unregister_card(&snd_proto);
+}
+
+static const struct of_device_id snd_proto_of_match[] = {
+	{ .compatible = "mikroe,mikroe-proto", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, snd_proto_of_match);
+
+static struct platform_driver snd_proto_driver = {
+	.driver = {
+		.name   = "snd-mikroe-proto",
+		.of_match_table = snd_proto_of_match,
+	},
+	.probe	  = snd_proto_probe,
+	.remove	 = snd_proto_remove,
+};
+
+module_platform_driver(snd_proto_driver);
+
+MODULE_AUTHOR("Florian Meier");
+MODULE_DESCRIPTION("ASoC Driver for PROTO board (WM8731)");
+MODULE_LICENSE("GPL");

Some files were not shown because too many files changed in this diff