瀏覽代碼

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

Pull sound updates from Takashi Iwai:
 "There have been major modernization with the standard bus: in ALSA
  sequencer core and HD-audio.  Also, HD-audio receives the regmap
  support replacing the in-house cache register cache code.  These
  changes shouldn't impact the existing behavior, but rather
  refactoring.

  In addition, HD-audio got the code split to a core library part and
  the "legacy" driver parts.  This is a preliminary work for adapting
  the upcoming ASoC HD-audio driver, and the whole transition is still
  work in progress, likely finished in 4.1.

  Along with them, there are many updates in ASoC area as usual, too:
  lots of cleanups, Intel code shuffling, etc.

  Here are some highlights:

  ALSA core:
   - PCM: the audio timestamp / wallclock enhancement
   - PCM: fixes in DPCM management
   - Fixes / cleanups of user-space control element management
   - Sequencer: modernization using the standard bus

  HD-audio:
   - Modernization using the standard bus
   - Regmap support
   - Use standard runtime PM for codec power saving
   - Widget-path based power-saving for IDT, VIA and Realtek codecs
   - Reorganized sysfs entries for each codec object
   - More Dell headset support

  ASoC:
   - Move of jack registration to the card level
   - Lots of ASoC cleanups, mainly moving things from the CODEC level to
     the card level
   - Support for DAPM routes specified by both the machine driver and DT
   - Continuing improvements to rcar
   - pcm512x enhacements
   - Intel platforms updates
   - rt5670 updates / fixes
   - New platforms / devices: some non-DSP Qualcomm platforms, Google's
     Storm platform, Maxmim MAX98925 CODECs and the Ingenic JZ4780 SoC

  Misc:
   - ice1724: Improved ESI W192M support
   - emu10k1: Emu 1010 fixes/enhancement"

* tag 'sound-4.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (411 commits)
  ALSA: hda - set GET bit when adding a vendor verb to the codec regmap
  ALSA: hda/realtek - Enable the ALC292 dock fixup on the Thinkpad T450
  ALSA: hda - Fix another race in runtime PM refcounting
  ALSA: hda - Expose codec type sysfs
  ALSA: ctl: fix to handle several elements added by one operation for userspace element
  ASoC: Intel: fix array_size.cocci warnings
  ASoC: n810: Automatically disconnect non-connected pins
  ASoC: n810: Consistently pass the card DAPM context to n810_ext_control()
  ASoC: davinci-evm: Use card DAPM context to access widgets
  ASoC: mop500_ab8500: Use card DAPM context to access widgets
  ASoC: wm1133-ev1: Use card DAPM context to access widgets
  ASoC: atmel: Improve machine driver compile test coverage
  ASoC: atmel: Add dependency to SND_SOC_I2C_AND_SPI where necessary
  ALSA: control: Fix a typo of SNDRV_CTL_ELEM_ACCESS_TLV_* with SNDRV_CTL_TLV_OP_*
  ALSA: usb-audio: Don't attempt to get Microsoft Lifecam Cinema sample rate
  ASoC: rnsd: fix build regression without CONFIG_OF
  ALSA: emu10k1: add toggles for E-mu 1010 optical ports
  ALSA: ctl: fill identical information to return value when adding userspace elements
  ALSA: ctl: fix a bug to return no identical information in info operation for userspace controls
  ALSA: ctl: confirm to return all identical information in 'activate' event
  ...
Linus Torvalds 10 年之前
父節點
當前提交
d0a3997c0c
共有 100 個文件被更改,包括 3750 次插入985 次删除
  1. 1 1
      Documentation/devicetree/bindings/sound/ingenic,jz4740-i2s.txt
  2. 22 0
      Documentation/devicetree/bindings/sound/max98925.txt
  3. 1 0
      Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt
  4. 43 0
      Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt
  5. 111 14
      Documentation/devicetree/bindings/sound/renesas,rsnd.txt
  6. 67 0
      Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt
  7. 23 0
      Documentation/devicetree/bindings/sound/storm.txt
  8. 7 0
      Documentation/devicetree/bindings/sound/wm8804.txt
  9. 5 5
      Documentation/sound/alsa/ControlNames.txt
  10. 5 1
      Documentation/sound/alsa/HD-Audio.txt
  11. 200 0
      Documentation/sound/alsa/timestamping.txt
  12. 8 1
      MAINTAINERS
  13. 1 2
      arch/arm/mach-shmobile/board-armadillo800eva.c
  14. 1 0
      drivers/dma/of-dma.c
  15. 3 1
      include/sound/ac97_codec.h
  16. 2 2
      include/sound/compress_driver.h
  17. 1 1
      include/sound/control.h
  18. 2 1
      include/sound/core.h
  19. 217 0
      include/sound/hda_regmap.h
  20. 247 0
      include/sound/hdaudio.h
  21. 64 2
      include/sound/pcm.h
  22. 7 0
      include/sound/pcm_params.h
  23. 1 0
      include/sound/rt5670.h
  24. 29 17
      include/sound/seq_device.h
  25. 1 5
      include/sound/seq_kernel.h
  26. 0 1
      include/sound/simple_card.h
  27. 3 3
      include/sound/soc-dapm.h
  28. 1 1
      include/sound/soc-dpcm.h
  29. 28 4
      include/sound/soc.h
  30. 1 0
      include/uapi/sound/asequencer.h
  31. 34 5
      include/uapi/sound/asound.h
  32. 1 1
      include/uapi/sound/compress_offload.h
  33. 1 2
      include/uapi/sound/emu10k1.h
  34. 6 0
      include/uapi/sound/hdspm.h
  35. 2 0
      sound/Kconfig
  36. 1 1
      sound/Makefile
  37. 1 1
      sound/aoa/soundbus/i2sbus/core.c
  38. 205 124
      sound/core/control.c
  39. 34 13
      sound/core/device.c
  40. 1 3
      sound/core/hwdep.c
  41. 1 4
      sound/core/init.c
  42. 1 3
      sound/core/oss/mixer_oss.c
  43. 0 1
      sound/core/oss/pcm_oss.c
  44. 44 61
      sound/core/pcm.c
  45. 23 5
      sound/core/pcm_compat.c
  46. 2 2
      sound/core/pcm_dmaengine.c
  47. 59 29
      sound/core/pcm_lib.c
  48. 38 3
      sound/core/pcm_native.c
  49. 2 6
      sound/core/rawmidi.c
  50. 13 9
      sound/core/seq/oss/seq_oss.c
  51. 1 3
      sound/core/seq/oss/seq_oss_init.c
  52. 2 3
      sound/core/seq/oss/seq_oss_midi.c
  53. 4 5
      sound/core/seq/oss/seq_oss_readq.c
  54. 6 6
      sound/core/seq/oss/seq_oss_synth.c
  55. 2 2
      sound/core/seq/oss/seq_oss_synth.h
  56. 1 0
      sound/core/seq/seq_clientmgr.c
  57. 135 436
      sound/core/seq/seq_device.c
  58. 1 5
      sound/core/seq/seq_dummy.c
  59. 1 3
      sound/core/seq/seq_fifo.c
  60. 2 6
      sound/core/seq/seq_memory.c
  61. 14 22
      sound/core/seq/seq_midi.c
  62. 1 3
      sound/core/seq/seq_ports.c
  63. 1 3
      sound/core/seq/seq_prioq.c
  64. 1 3
      sound/core/seq/seq_queue.c
  65. 1 3
      sound/core/seq/seq_timer.c
  66. 5 9
      sound/core/sound.c
  67. 1 3
      sound/core/timer.c
  68. 14 20
      sound/drivers/opl3/opl3_seq.c
  69. 14 19
      sound/drivers/opl4/opl4_seq.c
  70. 4 4
      sound/firewire/amdtp.c
  71. 1 1
      sound/firewire/fireworks/fireworks_transaction.c
  72. 3 0
      sound/hda/Kconfig
  73. 7 0
      sound/hda/Makefile
  74. 49 0
      sound/hda/array.c
  75. 42 0
      sound/hda/hda_bus_type.c
  76. 186 0
      sound/hda/hdac_bus.c
  77. 599 0
      sound/hda/hdac_device.c
  78. 472 0
      sound/hda/hdac_regmap.c
  79. 406 0
      sound/hda/hdac_sysfs.c
  80. 23 0
      sound/hda/local.h
  81. 6 0
      sound/hda/trace.c
  82. 62 0
      sound/hda/trace.h
  83. 2 2
      sound/i2c/other/ak4113.c
  84. 15 20
      sound/isa/sb/emu8000_synth.c
  85. 3 3
      sound/isa/wavefront/wavefront_fx.c
  86. 13 13
      sound/isa/wavefront/wavefront_synth.c
  87. 9 3
      sound/mips/au1x00.c
  88. 3 3
      sound/oss/dev_table.c
  89. 2 2
      sound/oss/opl3.c
  90. 7 12
      sound/oss/sb_ess.c
  91. 3 3
      sound/oss/sb_midi.c
  92. 15 20
      sound/oss/sys_timer.c
  93. 2 2
      sound/oss/v_midi.c
  94. 3 1
      sound/pci/ac97/ac97_codec.c
  95. 27 0
      sound/pci/ac97/ac97_patch.c
  96. 1 1
      sound/pci/ad1889.c
  97. 1 1
      sound/pci/asihpi/asihpi.c
  98. 1 1
      sound/pci/atiixp.c
  99. 4 3
      sound/pci/azt3328.c
  100. 1 1
      sound/pci/cmipci.c

+ 1 - 1
Documentation/devicetree/bindings/sound/ingenic,jz4740-i2s.txt

@@ -1,7 +1,7 @@
 Ingenic JZ4740 I2S controller
 
 Required properties:
-- compatible : "ingenic,jz4740-i2s"
+- compatible : "ingenic,jz4740-i2s" or "ingenic,jz4780-i2s"
 - reg : I2S registers location and length
 - clocks : AIC and I2S PLL clock specifiers.
 - clock-names: "aic" and "i2s"

+ 22 - 0
Documentation/devicetree/bindings/sound/max98925.txt

@@ -0,0 +1,22 @@
+max98925 audio CODEC
+
+This device supports I2C.
+
+Required properties:
+
+  - compatible : "maxim,max98925"
+
+  - vmon-slot-no : slot number used to send voltage information
+
+  - imon-slot-no : slot number used to send current information
+
+  - reg : the I2C address of the device for I2C
+
+Example:
+
+codec: max98925@1a {
+	compatible = "maxim,max98925";
+	vmon-slot-no = <0>;
+	imon-slot-no = <2>;
+	reg = <0x1a>;
+};

+ 1 - 0
Documentation/devicetree/bindings/sound/nvidia,tegra-audio-max98090.txt

@@ -18,6 +18,7 @@ Required properties:
   * Headphones
   * Speakers
   * Mic Jack
+  * Int Mic
 
 - nvidia,i2s-controller : The phandle of the Tegra I2S controller that's
   connected to the CODEC.

+ 43 - 0
Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt

@@ -0,0 +1,43 @@
+* Qualcomm Technologies LPASS CPU DAI
+
+This node models the Qualcomm Technologies Low-Power Audio SubSystem (LPASS).
+
+Required properties:
+
+- compatible		: "qcom,lpass-cpu"
+- clocks		: Must contain an entry for each entry in clock-names.
+- clock-names		: A list which must include the following entries:
+				* "ahbix-clk"
+				* "mi2s-osr-clk"
+				* "mi2s-bit-clk"
+- interrupts		: Must contain an entry for each entry in
+			  interrupt-names.
+- interrupt-names	: A list which must include the following entries:
+				* "lpass-irq-lpaif"
+- pinctrl-N		: One property must exist for each entry in
+			  pinctrl-names.  See ../pinctrl/pinctrl-bindings.txt
+			  for details of the property values.
+- pinctrl-names		: Must contain a "default" entry.
+- reg			: Must contain an address for each entry in reg-names.
+- reg-names		: A list which must include the following entries:
+				* "lpass-lpaif"
+
+Optional properties:
+
+- qcom,adsp		: Phandle for the audio DSP node
+
+Example:
+
+lpass@28100000 {
+	compatible = "qcom,lpass-cpu";
+	clocks = <&lcc AHBIX_CLK>, <&lcc MI2S_OSR_CLK>, <&lcc MI2S_BIT_CLK>;
+	clock-names = "ahbix-clk", "mi2s-osr-clk", "mi2s-bit-clk";
+	interrupts = <0 85 1>;
+	interrupt-names = "lpass-irq-lpaif";
+	pinctrl-names = "default", "idle";
+	pinctrl-0 = <&mi2s_default>;
+	pinctrl-1 = <&mi2s_idle>;
+	reg = <0x28100000 0x10000>;
+	reg-names = "lpass-lpaif";
+	qcom,adsp = <&adsp>;
+};

+ 111 - 14
Documentation/devicetree/bindings/sound/renesas,rsnd.txt

@@ -29,9 +29,17 @@ SSI subnode properties:
 - shared-pin			: if shared clock pin
 - pio-transfer			: use PIO transfer mode
 - no-busif			: BUSIF is not ussed when [mem -> SSI] via DMA case
+- dma				: Should contain Audio DMAC entry
+- dma-names			: SSI  case "rx"  (=playback), "tx"  (=capture)
+				  SSIU case "rxu" (=playback), "txu" (=capture)
 
 SRC subnode properties:
-no properties at this point
+- dma				: Should contain Audio DMAC entry
+- dma-names			: "rx" (=playback), "tx" (=capture)
+
+DVC subnode properties:
+- dma				: Should contain Audio DMAC entry
+- dma-names			: "tx" (=playback/capture)
 
 DAI subnode properties:
 - playback			: list of playback modules
@@ -45,56 +53,145 @@ rcar_sound: rcar_sound@ec500000 {
 	reg =	<0 0xec500000 0 0x1000>, /* SCU */
 		<0 0xec5a0000 0 0x100>,  /* ADG */
 		<0 0xec540000 0 0x1000>, /* SSIU */
-		<0 0xec541000 0 0x1280>; /* SSI */
+		<0 0xec541000 0 0x1280>, /* SSI */
+		<0 0xec740000 0 0x200>;  /* Audio DMAC peri peri*/
+	reg-names = "scu", "adg", "ssiu", "ssi", "audmapp";
+
+	clocks = <&mstp10_clks R8A7790_CLK_SSI_ALL>,
+		<&mstp10_clks R8A7790_CLK_SSI9>, <&mstp10_clks R8A7790_CLK_SSI8>,
+		<&mstp10_clks R8A7790_CLK_SSI7>, <&mstp10_clks R8A7790_CLK_SSI6>,
+		<&mstp10_clks R8A7790_CLK_SSI5>, <&mstp10_clks R8A7790_CLK_SSI4>,
+		<&mstp10_clks R8A7790_CLK_SSI3>, <&mstp10_clks R8A7790_CLK_SSI2>,
+		<&mstp10_clks R8A7790_CLK_SSI1>, <&mstp10_clks R8A7790_CLK_SSI0>,
+		<&mstp10_clks R8A7790_CLK_SCU_SRC9>, <&mstp10_clks R8A7790_CLK_SCU_SRC8>,
+		<&mstp10_clks R8A7790_CLK_SCU_SRC7>, <&mstp10_clks R8A7790_CLK_SCU_SRC6>,
+		<&mstp10_clks R8A7790_CLK_SCU_SRC5>, <&mstp10_clks R8A7790_CLK_SCU_SRC4>,
+		<&mstp10_clks R8A7790_CLK_SCU_SRC3>, <&mstp10_clks R8A7790_CLK_SCU_SRC2>,
+		<&mstp10_clks R8A7790_CLK_SCU_SRC1>, <&mstp10_clks R8A7790_CLK_SCU_SRC0>,
+		<&mstp10_clks R8A7790_CLK_SCU_DVC0>, <&mstp10_clks R8A7790_CLK_SCU_DVC1>,
+		<&audio_clk_a>, <&audio_clk_b>, <&audio_clk_c>, <&m2_clk>;
+	clock-names = "ssi-all",
+			"ssi.9", "ssi.8", "ssi.7", "ssi.6", "ssi.5",
+			"ssi.4", "ssi.3", "ssi.2", "ssi.1", "ssi.0",
+			"src.9", "src.8", "src.7", "src.6", "src.5",
+			"src.4", "src.3", "src.2", "src.1", "src.0",
+			"dvc.0", "dvc.1",
+			"clk_a", "clk_b", "clk_c", "clk_i";
 
 	rcar_sound,dvc {
-		dvc0: dvc@0 { };
-		dvc1: dvc@1 { };
+		dvc0: dvc@0 {
+			dmas = <&audma0 0xbc>;
+			dma-names = "tx";
+		};
+		dvc1: dvc@1 {
+			dmas = <&audma0 0xbe>;
+			dma-names = "tx";
+		};
 	};
 
 	rcar_sound,src {
-		src0: src@0 { };
-		src1: src@1 { };
-		src2: src@2 { };
-		src3: src@3 { };
-		src4: src@4 { };
-		src5: src@5 { };
-		src6: src@6 { };
-		src7: src@7 { };
-		src8: src@8 { };
-		src9: src@9 { };
+		src0: src@0 {
+			interrupts = <0 352 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x85>, <&audma1 0x9a>;
+			dma-names = "rx", "tx";
+		};
+		src1: src@1 {
+			interrupts = <0 353 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x87>, <&audma1 0x9c>;
+			dma-names = "rx", "tx";
+		};
+		src2: src@2 {
+			interrupts = <0 354 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x89>, <&audma1 0x9e>;
+			dma-names = "rx", "tx";
+		};
+		src3: src@3 {
+			interrupts = <0 355 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x8b>, <&audma1 0xa0>;
+			dma-names = "rx", "tx";
+		};
+		src4: src@4 {
+			interrupts = <0 356 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x8d>, <&audma1 0xb0>;
+			dma-names = "rx", "tx";
+		};
+		src5: src@5 {
+			interrupts = <0 357 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x8f>, <&audma1 0xb2>;
+			dma-names = "rx", "tx";
+		};
+		src6: src@6 {
+			interrupts = <0 358 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x91>, <&audma1 0xb4>;
+			dma-names = "rx", "tx";
+		};
+		src7: src@7 {
+			interrupts = <0 359 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x93>, <&audma1 0xb6>;
+			dma-names = "rx", "tx";
+		};
+		src8: src@8 {
+			interrupts = <0 360 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x95>, <&audma1 0xb8>;
+			dma-names = "rx", "tx";
+		};
+		src9: src@9 {
+			interrupts = <0 361 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x97>, <&audma1 0xba>;
+			dma-names = "rx", "tx";
+		};
 	};
 
 	rcar_sound,ssi {
 		ssi0: ssi@0 {
 			interrupts = <0 370 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x01>, <&audma1 0x02>, <&audma0 0x15>, <&audma1 0x16>;
+			dma-names = "rx", "tx", "rxu", "txu";
 		};
 		ssi1: ssi@1 {
 			interrupts = <0 371 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x03>, <&audma1 0x04>, <&audma0 0x49>, <&audma1 0x4a>;
+			dma-names = "rx", "tx", "rxu", "txu";
 		};
 		ssi2: ssi@2 {
 			interrupts = <0 372 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x05>, <&audma1 0x06>, <&audma0 0x63>, <&audma1 0x64>;
+			dma-names = "rx", "tx", "rxu", "txu";
 		};
 		ssi3: ssi@3 {
 			interrupts = <0 373 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x07>, <&audma1 0x08>, <&audma0 0x6f>, <&audma1 0x70>;
+			dma-names = "rx", "tx", "rxu", "txu";
 		};
 		ssi4: ssi@4 {
 			interrupts = <0 374 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x09>, <&audma1 0x0a>, <&audma0 0x71>, <&audma1 0x72>;
+			dma-names = "rx", "tx", "rxu", "txu";
 		};
 		ssi5: ssi@5 {
 			interrupts = <0 375 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x0b>, <&audma1 0x0c>, <&audma0 0x73>, <&audma1 0x74>;
+			dma-names = "rx", "tx", "rxu", "txu";
 		};
 		ssi6: ssi@6 {
 			interrupts = <0 376 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x0d>, <&audma1 0x0e>, <&audma0 0x75>, <&audma1 0x76>;
+			dma-names = "rx", "tx", "rxu", "txu";
 		};
 		ssi7: ssi@7 {
 			interrupts = <0 377 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x0f>, <&audma1 0x10>, <&audma0 0x79>, <&audma1 0x7a>;
+			dma-names = "rx", "tx", "rxu", "txu";
 		};
 		ssi8: ssi@8 {
 			interrupts = <0 378 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x11>, <&audma1 0x12>, <&audma0 0x7b>, <&audma1 0x7c>;
+			dma-names = "rx", "tx", "rxu", "txu";
 		};
 		ssi9: ssi@9 {
 			interrupts = <0 379 IRQ_TYPE_LEVEL_HIGH>;
+			dmas = <&audma0 0x13>, <&audma1 0x14>, <&audma0 0x7d>, <&audma1 0x7e>;
+			dma-names = "rx", "tx", "rxu", "txu";
 		};
 	};
 

+ 67 - 0
Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt

@@ -0,0 +1,67 @@
+Renesas Sampling Rate Convert Sound Card:
+
+Renesas Sampling Rate Convert Sound Card specifies audio DAI connections of SoC <-> codec.
+
+Required properties:
+
+- compatible				: "renesas,rsrc-card,<board>"
+					  Examples with soctypes are:
+					    - "renesas,rsrc-card,lager"
+					    - "renesas,rsrc-card,koelsch"
+Optional properties:
+
+- card_name				: User specified audio sound card name, one string
+					  property.
+- cpu					: CPU   sub-node
+- codec					: CODEC sub-node
+
+Optional subnode properties:
+
+- format				: CPU/CODEC common audio format.
+					  "i2s", "right_j", "left_j" , "dsp_a"
+					  "dsp_b", "ac97", "pdm", "msb", "lsb"
+- frame-master				: Indicates dai-link frame master.
+					  phandle to a cpu or codec subnode.
+- bitclock-master			: Indicates dai-link bit clock master.
+					  phandle to a cpu or codec subnode.
+- bitclock-inversion			: bool property. Add this if the
+					  dai-link uses bit clock inversion.
+- frame-inversion			: bool property. Add this if the
+					  dai-link uses frame clock inversion.
+- convert-rate				: platform specified sampling rate convert
+
+Required CPU/CODEC subnodes properties:
+
+- sound-dai				: phandle and port of CPU/CODEC
+
+Optional CPU/CODEC subnodes properties:
+
+- clocks / system-clock-frequency	: specify subnode's clock if needed.
+					  it can be specified via "clocks" if system has
+					  clock node (= common clock), or "system-clock-frequency"
+					  (if system doens't support common clock)
+					  If a clock is specified, it is
+					  enabled with clk_prepare_enable()
+					  in dai startup() and disabled with
+					  clk_disable_unprepare() in dai
+					  shutdown().
+
+Example
+
+sound {
+	compatible = "renesas,rsrc-card,lager";
+
+	card-name = "rsnd-ak4643";
+	format = "left_j";
+	bitclock-master = <&sndcodec>;
+	frame-master = <&sndcodec>;
+
+	sndcpu: cpu {
+		sound-dai = <&rcar_sound>;
+	};
+
+	sndcodec: codec {
+		sound-dai = <&ak4643>;
+		system-clock-frequency = <11289600>;
+	};
+};

+ 23 - 0
Documentation/devicetree/bindings/sound/storm.txt

@@ -0,0 +1,23 @@
+* Sound complex for Storm boards
+
+Models a soundcard for Storm boards with the Qualcomm Technologies IPQ806x SOC
+connected to a MAX98357A DAC via I2S.
+
+Required properties:
+
+- compatible	: "google,storm-audio"
+- cpu		: Phandle of the CPU DAI
+- codec		: Phandle of the codec DAI
+
+Optional properties:
+
+- qcom,model	: The user-visible name of this sound card.
+
+Example:
+
+sound {
+	compatible = "google,storm-audio";
+	qcom,model = "ipq806x-storm";
+	cpu = <&lpass_cpu>;
+	codec = <&max98357a>;
+};

+ 7 - 0
Documentation/devicetree/bindings/sound/wm8804.txt

@@ -10,6 +10,13 @@ Required properties:
   - reg : the I2C address of the device for I2C, the chip select
           number for SPI.
 
+  - PVDD-supply, DVDD-supply : Power supplies for the device, as covered
+    in Documentation/devicetree/bindings/regulator/regulator.txt
+
+Optional properties:
+
+  - wlf,reset-gpio: A GPIO specifier for the GPIO controlling the reset pin
+
 Example:
 
 codec: wm8804@1a {

+ 5 - 5
Documentation/sound/alsa/ControlNames.txt

@@ -71,11 +71,11 @@ SOURCE:
   HDMI/DP	(either HDMI or DisplayPort)
 
 Exceptions (deprecated):
-  [Digital] Capture Source
-  [Digital] Capture Switch	(aka input gain switch)
-  [Digital] Capture Volume	(aka input gain volume)
-  [Digital] Playback Switch	(aka output gain switch)
-  [Digital] Playback Volume	(aka output gain volume)
+  [Analogue|Digital] Capture Source
+  [Analogue|Digital] Capture Switch	(aka input gain switch)
+  [Analogue|Digital] Capture Volume	(aka input gain volume)
+  [Analogue|Digital] Playback Switch	(aka output gain switch)
+  [Analogue|Digital] Playback Volume	(aka output gain volume)
   Tone Control - Switch
   Tone Control - Bass
   Tone Control - Treble

+ 5 - 1
Documentation/sound/alsa/HD-Audio.txt

@@ -466,7 +466,11 @@ The generic parser supports the following hints:
 - add_jack_modes (bool): add "xxx Jack Mode" enum controls to each
   I/O jack for allowing to change the headphone amp and mic bias VREF
   capabilities
-- power_down_unused (bool): power down the unused widgets
+- power_save_node (bool): advanced power management for each widget,
+  controlling the power sate (D0/D3) of each widget node depending on
+  the actual pin and stream states
+- power_down_unused (bool): power down the unused widgets, a subset of
+  power_save_node, and will be dropped in future
 - add_hp_mic (bool): add the headphone to capture source if possible
 - hp_mic_detect (bool): enable/disable the hp/mic shared input for a
   single built-in mic case; default true

+ 200 - 0
Documentation/sound/alsa/timestamping.txt

@@ -0,0 +1,200 @@
+The ALSA API can provide two different system timestamps:
+
+- Trigger_tstamp is the system time snapshot taken when the .trigger
+callback is invoked. This snapshot is taken by the ALSA core in the
+general case, but specific hardware may have synchronization
+capabilities or conversely may only be able to provide a correct
+estimate with a delay. In the latter two cases, the low-level driver
+is responsible for updating the trigger_tstamp at the most appropriate
+and precise moment. Applications should not rely solely on the first
+trigger_tstamp but update their internal calculations if the driver
+provides a refined estimate with a delay.
+
+- tstamp is the current system timestamp updated during the last
+event or application query.
+The difference (tstamp - trigger_tstamp) defines the elapsed time.
+
+The ALSA API provides reports two basic pieces of information, avail
+and delay, which combined with the trigger and current system
+timestamps allow for applications to keep track of the 'fullness' of
+the ring buffer and the amount of queued samples.
+
+The use of these different pointers and time information depends on
+the application needs:
+
+- 'avail' reports how much can be written in the ring buffer
+- 'delay' reports the time it will take to hear a new sample after all
+queued samples have been played out.
+
+When timestamps are enabled, the avail/delay information is reported
+along with a snapshot of system time. Applications can select from
+CLOCK_REALTIME (NTP corrections including going backwards),
+CLOCK_MONOTONIC (NTP corrections but never going backwards),
+CLOCK_MONOTIC_RAW (without NTP corrections) and change the mode
+dynamically with sw_params
+
+
+The ALSA API also provide an audio_tstamp which reflects the passage
+of time as measured by different components of audio hardware.  In
+ascii-art, this could be represented as follows (for the playback
+case):
+
+
+--------------------------------------------------------------> time
+  ^               ^              ^                ^           ^
+  |               |              |                |           |
+ analog         link            dma              app       FullBuffer
+ time           time           time              time        time
+  |               |              |                |           |
+  |< codec delay >|<--hw delay-->|<queued samples>|<---avail->|
+  |<----------------- delay---------------------->|           |
+			         |<----ring buffer length---->|
+
+The analog time is taken at the last stage of the playback, as close
+as possible to the actual transducer
+
+The link time is taken at the output of the SOC/chipset as the samples
+are pushed on a link. The link time can be directly measured if
+supported in hardware by sample counters or wallclocks (e.g. with
+HDAudio 24MHz or PTP clock for networked solutions) or indirectly
+estimated (e.g. with the frame counter in USB).
+
+The DMA time is measured using counters - typically the least reliable
+of all measurements due to the bursty natured of DMA transfers.
+
+The app time corresponds to the time tracked by an application after
+writing in the ring buffer.
+
+The application can query what the hardware supports, define which
+audio time it wants reported by selecting the relevant settings in
+audio_tstamp_config fields, get an estimate of the timestamp
+accuracy. It can also request the delay-to-analog be included in the
+measurement. Direct access to the link time is very interesting on
+platforms that provide an embedded DSP; measuring directly the link
+time with dedicated hardware, possibly synchronized with system time,
+removes the need to keep track of internal DSP processing times and
+latency.
+
+In case the application requests an audio tstamp that is not supported
+in hardware/low-level driver, the type is overridden as DEFAULT and the
+timestamp will report the DMA time based on the hw_pointer value.
+
+For backwards compatibility with previous implementations that did not
+provide timestamp selection, with a zero-valued COMPAT timestamp type
+the results will default to the HDAudio wall clock for playback
+streams and to the DMA time (hw_ptr) in all other cases.
+
+The audio timestamp accuracy can be returned to user-space, so that
+appropriate decisions are made:
+
+- for dma time (default), the granularity of the transfers can be
+  inferred from the steps between updates and in turn provide
+  information on how much the application pointer can be rewound
+  safely.
+
+- the link time can be used to track long-term drifts between audio
+  and system time using the (tstamp-trigger_tstamp)/audio_tstamp
+  ratio, the precision helps define how much smoothing/low-pass
+  filtering is required. The link time can be either reset on startup
+  or reported as is (the latter being useful to compare progress of
+  different streams - but may require the wallclock to be always
+  running and not wrap-around during idle periods). If supported in
+  hardware, the absolute link time could also be used to define a
+  precise start time (patches WIP)
+
+- including the delay in the audio timestamp may
+  counter-intuitively not increase the precision of timestamps, e.g. if a
+  codec includes variable-latency DSP processing or a chain of
+  hardware components the delay is typically not known with precision.
+
+The accuracy is reported in nanosecond units (using an unsigned 32-bit
+word), which gives a max precision of 4.29s, more than enough for
+audio applications...
+
+Due to the varied nature of timestamping needs, even for a single
+application, the audio_tstamp_config can be changed dynamically. In
+the STATUS ioctl, the parameters are read-only and do not allow for
+any application selection. To work around this limitation without
+impacting legacy applications, a new STATUS_EXT ioctl is introduced
+with read/write parameters. ALSA-lib will be modified to make use of
+STATUS_EXT and effectively deprecate STATUS.
+
+The ALSA API only allows for a single audio timestamp to be reported
+at a time. This is a conscious design decision, reading the audio
+timestamps from hardware registers or from IPC takes time, the more
+timestamps are read the more imprecise the combined measurements
+are. To avoid any interpretation issues, a single (system, audio)
+timestamp is reported. Applications that need different timestamps
+will be required to issue multiple queries and perform an
+interpolation of the results
+
+In some hardware-specific configuration, the system timestamp is
+latched by a low-level audio subsytem, and the information provided
+back to the driver. Due to potential delays in the communication with
+the hardware, there is a risk of misalignment with the avail and delay
+information. To make sure applications are not confused, a
+driver_timestamp field is added in the snd_pcm_status structure; this
+timestamp shows when the information is put together by the driver
+before returning from the STATUS and STATUS_EXT ioctl. in most cases
+this driver_timestamp will be identical to the regular system tstamp.
+
+Examples of typestamping with HDaudio:
+
+1. DMA timestamp, no compensation for DMA+analog delay
+$ ./audio_time  -p --ts_type=1
+playback: systime: 341121338 nsec, audio time 342000000 nsec, 	systime delta -878662
+playback: systime: 426236663 nsec, audio time 427187500 nsec, 	systime delta -950837
+playback: systime: 597080580 nsec, audio time 598000000 nsec, 	systime delta -919420
+playback: systime: 682059782 nsec, audio time 683020833 nsec, 	systime delta -961051
+playback: systime: 852896415 nsec, audio time 853854166 nsec, 	systime delta -957751
+playback: systime: 937903344 nsec, audio time 938854166 nsec, 	systime delta -950822
+
+2. DMA timestamp, compensation for DMA+analog delay
+$ ./audio_time  -p --ts_type=1 -d
+playback: systime: 341053347 nsec, audio time 341062500 nsec, 	systime delta -9153
+playback: systime: 426072447 nsec, audio time 426062500 nsec, 	systime delta 9947
+playback: systime: 596899518 nsec, audio time 596895833 nsec, 	systime delta 3685
+playback: systime: 681915317 nsec, audio time 681916666 nsec, 	systime delta -1349
+playback: systime: 852741306 nsec, audio time 852750000 nsec, 	systime delta -8694
+
+3. link timestamp, compensation for DMA+analog delay
+$ ./audio_time  -p --ts_type=2 -d
+playback: systime: 341060004 nsec, audio time 341062791 nsec, 	systime delta -2787
+playback: systime: 426242074 nsec, audio time 426244875 nsec, 	systime delta -2801
+playback: systime: 597080992 nsec, audio time 597084583 nsec, 	systime delta -3591
+playback: systime: 682084512 nsec, audio time 682088291 nsec, 	systime delta -3779
+playback: systime: 852936229 nsec, audio time 852940916 nsec, 	systime delta -4687
+playback: systime: 938107562 nsec, audio time 938112708 nsec, 	systime delta -5146
+
+Example 1 shows that the timestamp at the DMA level is close to 1ms
+ahead of the actual playback time (as a side time this sort of
+measurement can help define rewind safeguards). Compensating for the
+DMA-link delay in example 2 helps remove the hardware buffering abut
+the information is still very jittery, with up to one sample of
+error. In example 3 where the timestamps are measured with the link
+wallclock, the timestamps show a monotonic behavior and a lower
+dispersion.
+
+Example 3 and 4 are with USB audio class. Example 3 shows a high
+offset between audio time and system time due to buffering. Example 4
+shows how compensating for the delay exposes a 1ms accuracy (due to
+the use of the frame counter by the driver)
+
+Example 3: DMA timestamp, no compensation for delay, delta of ~5ms
+$ ./audio_time -p -Dhw:1 -t1
+playback: systime: 120174019 nsec, audio time 125000000 nsec, 	systime delta -4825981
+playback: systime: 245041136 nsec, audio time 250000000 nsec, 	systime delta -4958864
+playback: systime: 370106088 nsec, audio time 375000000 nsec, 	systime delta -4893912
+playback: systime: 495040065 nsec, audio time 500000000 nsec, 	systime delta -4959935
+playback: systime: 620038179 nsec, audio time 625000000 nsec, 	systime delta -4961821
+playback: systime: 745087741 nsec, audio time 750000000 nsec, 	systime delta -4912259
+playback: systime: 870037336 nsec, audio time 875000000 nsec, 	systime delta -4962664
+
+Example 4: DMA timestamp, compensation for delay, delay of ~1ms
+$ ./audio_time -p -Dhw:1 -t1 -d
+playback: systime: 120190520 nsec, audio time 120000000 nsec, 	systime delta 190520
+playback: systime: 245036740 nsec, audio time 244000000 nsec, 	systime delta 1036740
+playback: systime: 370034081 nsec, audio time 369000000 nsec, 	systime delta 1034081
+playback: systime: 495159907 nsec, audio time 494000000 nsec, 	systime delta 1159907
+playback: systime: 620098824 nsec, audio time 619000000 nsec, 	systime delta 1098824
+playback: systime: 745031847 nsec, audio time 744000000 nsec, 	systime delta 1031847

+ 8 - 1
MAINTAINERS

@@ -1764,7 +1764,7 @@ S:	Supported
 F:	drivers/tty/serial/atmel_serial.c
 
 ATMEL Audio ALSA driver
-M:	Bo Shen <voice.shen@atmel.com>
+M:	Nicolas Ferre <nicolas.ferre@atmel.com>
 L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:	Supported
 F:	sound/soc/atmel
@@ -5301,6 +5301,13 @@ F:	drivers/char/ipmi/
 F:	include/linux/ipmi*
 F:	include/uapi/linux/ipmi*
 
+QCOM AUDIO (ASoC) DRIVERS
+M:	Patrick Lai <plai@codeaurora.org>
+M:	Banajit Goswami <bgoswami@codeaurora.org>
+L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
+S:	Supported
+F:	sound/soc/qcom/
+
 IPS SCSI RAID DRIVER
 M:	Adaptec OEM Raid Solutions <aacraid@adaptec.com>
 L:	linux-scsi@vger.kernel.org

+ 1 - 2
arch/arm/mach-shmobile/board-armadillo800eva.c

@@ -1015,7 +1015,6 @@ static struct asoc_simple_card_info fsi_wm8978_info = {
 	.platform	= "sh_fsi2",
 	.daifmt		= SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM,
 	.cpu_dai = {
-		.fmt	= SND_SOC_DAIFMT_IB_NF,
 		.name	= "fsia-dai",
 	},
 	.codec_dai = {
@@ -1040,9 +1039,9 @@ static struct asoc_simple_card_info fsi2_hdmi_info = {
 	.card		= "FSI2B-HDMI",
 	.codec		= "sh-mobile-hdmi",
 	.platform	= "sh_fsi2",
+	.daifmt		= SND_SOC_DAIFMT_CBS_CFS,
 	.cpu_dai = {
 		.name	= "fsib-dai",
-		.fmt	= SND_SOC_DAIFMT_CBS_CFS,
 	},
 	.codec_dai = {
 		.name = "sh_mobile_hdmi-hifi",

+ 1 - 0
drivers/dma/of-dma.c

@@ -194,6 +194,7 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
 
 	return ERR_PTR(ret_no_channel);
 }
+EXPORT_SYMBOL_GPL(of_dma_request_slave_channel);
 
 /**
  * of_dma_simple_xlate - Simple DMA engine translation function

+ 3 - 1
include/sound/ac97_codec.h

@@ -608,7 +608,9 @@ struct ac97_quirk {
 	int type;		/* quirk type above */
 };
 
-int snd_ac97_tune_hardware(struct snd_ac97 *ac97, struct ac97_quirk *quirk, const char *override);
+int snd_ac97_tune_hardware(struct snd_ac97 *ac97,
+			   const struct ac97_quirk *quirk,
+			   const char *override);
 int snd_ac97_set_rate(struct snd_ac97 *ac97, int reg, unsigned int rate);
 
 /*

+ 2 - 2
include/sound/compress_driver.h

@@ -70,7 +70,7 @@ struct snd_compr_runtime {
  * @device: device pointer
  * @direction: stream direction, playback/recording
  * @metadata_set: metadata set flag, true when set
- * @next_track: has userspace signall next track transistion, true when set
+ * @next_track: has userspace signal next track transition, true when set
  * @private_data: pointer to DSP private data
  */
 struct snd_compr_stream {
@@ -95,7 +95,7 @@ struct snd_compr_stream {
  * and the stream properties
  * @get_params: retrieve the codec parameters, mandatory
  * @set_metadata: Set the metadata values for a stream
- * @get_metadata: retreives the requested metadata values from stream
+ * @get_metadata: retrieves the requested metadata values from stream
  * @trigger: Trigger operations like start, pause, resume, drain, stop.
  * This callback is mandatory
  * @pointer: Retrieve current h/w pointer information. Mandatory

+ 1 - 1
include/sound/control.h

@@ -227,7 +227,7 @@ snd_ctl_add_slave(struct snd_kcontrol *master, struct snd_kcontrol *slave)
  * Add a virtual slave control to the given master.
  * Unlike snd_ctl_add_slave(), the element added via this function
  * is supposed to have volatile values, and get callback is called
- * at each time quried from the master.
+ * at each time queried from the master.
  *
  * When the control peeks the hardware values directly and the value
  * can be changed by other means than the put callback of the element,

+ 2 - 1
include/sound/core.h

@@ -278,7 +278,8 @@ int snd_device_new(struct snd_card *card, enum snd_device_type type,
 		   void *device_data, struct snd_device_ops *ops);
 int snd_device_register(struct snd_card *card, void *device_data);
 int snd_device_register_all(struct snd_card *card);
-int snd_device_disconnect_all(struct snd_card *card);
+void snd_device_disconnect(struct snd_card *card, void *device_data);
+void snd_device_disconnect_all(struct snd_card *card);
 void snd_device_free(struct snd_card *card, void *device_data);
 void snd_device_free_all(struct snd_card *card);
 

+ 217 - 0
include/sound/hda_regmap.h

@@ -0,0 +1,217 @@
+/*
+ * HD-audio regmap helpers
+ */
+
+#ifndef __SOUND_HDA_REGMAP_H
+#define __SOUND_HDA_REGMAP_H
+
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/hdaudio.h>
+
+int snd_hdac_regmap_init(struct hdac_device *codec);
+void snd_hdac_regmap_exit(struct hdac_device *codec);
+int snd_hdac_regmap_add_vendor_verb(struct hdac_device *codec,
+				    unsigned int verb);
+int snd_hdac_regmap_read_raw(struct hdac_device *codec, unsigned int reg,
+			     unsigned int *val);
+int snd_hdac_regmap_write_raw(struct hdac_device *codec, unsigned int reg,
+			      unsigned int val);
+int snd_hdac_regmap_update_raw(struct hdac_device *codec, unsigned int reg,
+			       unsigned int mask, unsigned int val);
+
+/**
+ * snd_hdac_regmap_encode_verb - encode the verb to a pseudo register
+ * @nid: widget NID
+ * @verb: codec verb
+ *
+ * Returns an encoded pseudo register.
+ */
+#define snd_hdac_regmap_encode_verb(nid, verb)		\
+	(((verb) << 8) | 0x80000 | ((unsigned int)(nid) << 20))
+
+/**
+ * snd_hdac_regmap_encode_amp - encode the AMP verb to a pseudo register
+ * @nid: widget NID
+ * @ch: channel (left = 0, right = 1)
+ * @dir: direction (#HDA_INPUT, #HDA_OUTPUT)
+ * @idx: input index value
+ *
+ * Returns an encoded pseudo register.
+ */
+#define snd_hdac_regmap_encode_amp(nid, ch, dir, idx)			\
+	(snd_hdac_regmap_encode_verb(nid, AC_VERB_GET_AMP_GAIN_MUTE) |	\
+	 ((ch) ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT) |			\
+	 ((dir) == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT) | \
+	 (idx))
+
+/**
+ * snd_hdac_regmap_encode_amp_stereo - encode a pseudo register for stereo AMPs
+ * @nid: widget NID
+ * @dir: direction (#HDA_INPUT, #HDA_OUTPUT)
+ * @idx: input index value
+ *
+ * Returns an encoded pseudo register.
+ */
+#define snd_hdac_regmap_encode_amp_stereo(nid, dir, idx)		\
+	(snd_hdac_regmap_encode_verb(nid, AC_VERB_GET_AMP_GAIN_MUTE) |	\
+	 AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT | /* both bits set! */	\
+	 ((dir) == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT) | \
+	 (idx))
+
+/**
+ * snd_hdac_regmap_write - Write a verb with caching
+ * @nid: codec NID
+ * @reg: verb to write
+ * @val: value to write
+ *
+ * For writing an amp value, use snd_hda_regmap_amp_update().
+ */
+static inline int
+snd_hdac_regmap_write(struct hdac_device *codec, hda_nid_t nid,
+		      unsigned int verb, unsigned int val)
+{
+	unsigned int cmd = snd_hdac_regmap_encode_verb(nid, verb);
+
+	return snd_hdac_regmap_write_raw(codec, cmd, val);
+}
+
+/**
+ * snd_hda_regmap_update - Update a verb value with caching
+ * @nid: codec NID
+ * @verb: verb to update
+ * @mask: bit mask to update
+ * @val: value to update
+ *
+ * For updating an amp value, use snd_hda_regmap_amp_update().
+ */
+static inline int
+snd_hdac_regmap_update(struct hdac_device *codec, hda_nid_t nid,
+		       unsigned int verb, unsigned int mask,
+		       unsigned int val)
+{
+	unsigned int cmd = snd_hdac_regmap_encode_verb(nid, verb);
+
+	return snd_hdac_regmap_update_raw(codec, cmd, mask, val);
+}
+
+/**
+ * snd_hda_regmap_read - Read a verb with caching
+ * @nid: codec NID
+ * @verb: verb to read
+ * @val: pointer to store the value
+ *
+ * For reading an amp value, use snd_hda_regmap_get_amp().
+ */
+static inline int
+snd_hdac_regmap_read(struct hdac_device *codec, hda_nid_t nid,
+		     unsigned int verb, unsigned int *val)
+{
+	unsigned int cmd = snd_hdac_regmap_encode_verb(nid, verb);
+
+	return snd_hdac_regmap_read_raw(codec, cmd, val);
+}
+
+/**
+ * snd_hdac_regmap_get_amp - Read AMP value
+ * @codec: HD-audio codec
+ * @nid: NID to read the AMP value
+ * @ch: channel (left=0 or right=1)
+ * @direction: #HDA_INPUT or #HDA_OUTPUT
+ * @index: the index value (only for input direction)
+ * @val: the pointer to store the value
+ *
+ * Read AMP value.  The volume is between 0 to 0x7f, 0x80 = mute bit.
+ * Returns the value or a negative error.
+ */
+static inline int
+snd_hdac_regmap_get_amp(struct hdac_device *codec, hda_nid_t nid,
+			int ch, int dir, int idx)
+{
+	unsigned int cmd = snd_hdac_regmap_encode_amp(nid, ch, dir, idx);
+	int err, val;
+
+	err = snd_hdac_regmap_read_raw(codec, cmd, &val);
+	return err < 0 ? err : val;
+}
+
+/**
+ * snd_hdac_regmap_update_amp - update the AMP value
+ * @codec: HD-audio codec
+ * @nid: NID to read the AMP value
+ * @ch: channel (left=0 or right=1)
+ * @direction: #HDA_INPUT or #HDA_OUTPUT
+ * @idx: the index value (only for input direction)
+ * @mask: bit mask to set
+ * @val: the bits value to set
+ *
+ * Update the AMP value with a bit mask.
+ * Returns 0 if the value is unchanged, 1 if changed, or a negative error.
+ */
+static inline int
+snd_hdac_regmap_update_amp(struct hdac_device *codec, hda_nid_t nid,
+			   int ch, int dir, int idx, int mask, int val)
+{
+	unsigned int cmd = snd_hdac_regmap_encode_amp(nid, ch, dir, idx);
+
+	return snd_hdac_regmap_update_raw(codec, cmd, mask, val);
+}
+
+/**
+ * snd_hdac_regmap_get_amp_stereo - Read stereo AMP values
+ * @codec: HD-audio codec
+ * @nid: NID to read the AMP value
+ * @ch: channel (left=0 or right=1)
+ * @direction: #HDA_INPUT or #HDA_OUTPUT
+ * @index: the index value (only for input direction)
+ * @val: the pointer to store the value
+ *
+ * Read stereo AMP values.  The lower byte is left, the upper byte is right.
+ * Returns the value or a negative error.
+ */
+static inline int
+snd_hdac_regmap_get_amp_stereo(struct hdac_device *codec, hda_nid_t nid,
+			       int dir, int idx)
+{
+	unsigned int cmd = snd_hdac_regmap_encode_amp_stereo(nid, dir, idx);
+	int err, val;
+
+	err = snd_hdac_regmap_read_raw(codec, cmd, &val);
+	return err < 0 ? err : val;
+}
+
+/**
+ * snd_hdac_regmap_update_amp_stereo - update the stereo AMP value
+ * @codec: HD-audio codec
+ * @nid: NID to read the AMP value
+ * @direction: #HDA_INPUT or #HDA_OUTPUT
+ * @idx: the index value (only for input direction)
+ * @mask: bit mask to set
+ * @val: the bits value to set
+ *
+ * Update the stereo AMP value with a bit mask.
+ * The lower byte is left, the upper byte is right.
+ * Returns 0 if the value is unchanged, 1 if changed, or a negative error.
+ */
+static inline int
+snd_hdac_regmap_update_amp_stereo(struct hdac_device *codec, hda_nid_t nid,
+				  int dir, int idx, int mask, int val)
+{
+	unsigned int cmd = snd_hdac_regmap_encode_amp_stereo(nid, dir, idx);
+
+	return snd_hdac_regmap_update_raw(codec, cmd, mask, val);
+}
+
+/**
+ * snd_hdac_regmap_sync_node - sync the widget node attributes
+ * @codec: HD-audio codec
+ * @nid: NID to sync
+ */
+static inline void
+snd_hdac_regmap_sync_node(struct hdac_device *codec, hda_nid_t nid)
+{
+	regcache_mark_dirty(codec->regmap);
+	regcache_sync_region(codec->regmap, nid << 20, ((nid + 1) << 20) - 1);
+}
+
+#endif /* __SOUND_HDA_REGMAP_H */

+ 247 - 0
include/sound/hdaudio.h

@@ -0,0 +1,247 @@
+/*
+ * HD-audio core stuff
+ */
+
+#ifndef __SOUND_HDAUDIO_H
+#define __SOUND_HDAUDIO_H
+
+#include <linux/device.h>
+#include <sound/hda_verbs.h>
+
+/* codec node id */
+typedef u16 hda_nid_t;
+
+struct hdac_bus;
+struct hdac_device;
+struct hdac_driver;
+struct hdac_widget_tree;
+
+/*
+ * exported bus type
+ */
+extern struct bus_type snd_hda_bus_type;
+
+/*
+ * generic arrays
+ */
+struct snd_array {
+	unsigned int used;
+	unsigned int alloced;
+	unsigned int elem_size;
+	unsigned int alloc_align;
+	void *list;
+};
+
+/*
+ * HD-audio codec base device
+ */
+struct hdac_device {
+	struct device dev;
+	int type;
+	struct hdac_bus *bus;
+	unsigned int addr;		/* codec address */
+	struct list_head list;		/* list point for bus codec_list */
+
+	hda_nid_t afg;			/* AFG node id */
+	hda_nid_t mfg;			/* MFG node id */
+
+	/* ids */
+	unsigned int vendor_id;
+	unsigned int subsystem_id;
+	unsigned int revision_id;
+	unsigned int afg_function_id;
+	unsigned int mfg_function_id;
+	unsigned int afg_unsol:1;
+	unsigned int mfg_unsol:1;
+
+	unsigned int power_caps;	/* FG power caps */
+
+	const char *vendor_name;	/* codec vendor name */
+	const char *chip_name;		/* codec chip name */
+
+	/* verb exec op override */
+	int (*exec_verb)(struct hdac_device *dev, unsigned int cmd,
+			 unsigned int flags, unsigned int *res);
+
+	/* widgets */
+	unsigned int num_nodes;
+	hda_nid_t start_nid, end_nid;
+
+	/* misc flags */
+	atomic_t in_pm;		/* suspend/resume being performed */
+
+	/* sysfs */
+	struct hdac_widget_tree *widgets;
+
+	/* regmap */
+	struct regmap *regmap;
+	struct snd_array vendor_verbs;
+	bool lazy_cache:1;	/* don't wake up for writes */
+	bool caps_overwriting:1; /* caps overwrite being in process */
+	bool cache_coef:1;	/* cache COEF read/write too */
+};
+
+/* device/driver type used for matching */
+enum {
+	HDA_DEV_CORE,
+	HDA_DEV_LEGACY,
+};
+
+/* direction */
+enum {
+	HDA_INPUT, HDA_OUTPUT
+};
+
+#define dev_to_hdac_dev(_dev)	container_of(_dev, struct hdac_device, dev)
+
+int snd_hdac_device_init(struct hdac_device *dev, struct hdac_bus *bus,
+			 const char *name, unsigned int addr);
+void snd_hdac_device_exit(struct hdac_device *dev);
+int snd_hdac_device_register(struct hdac_device *codec);
+void snd_hdac_device_unregister(struct hdac_device *codec);
+
+int snd_hdac_refresh_widgets(struct hdac_device *codec);
+
+unsigned int snd_hdac_make_cmd(struct hdac_device *codec, hda_nid_t nid,
+			       unsigned int verb, unsigned int parm);
+int snd_hdac_exec_verb(struct hdac_device *codec, unsigned int cmd,
+		       unsigned int flags, unsigned int *res);
+int snd_hdac_read(struct hdac_device *codec, hda_nid_t nid,
+		  unsigned int verb, unsigned int parm, unsigned int *res);
+int _snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid, int parm,
+			unsigned int *res);
+int snd_hdac_read_parm_uncached(struct hdac_device *codec, hda_nid_t nid,
+				int parm);
+int snd_hdac_override_parm(struct hdac_device *codec, hda_nid_t nid,
+			   unsigned int parm, unsigned int val);
+int snd_hdac_get_connections(struct hdac_device *codec, hda_nid_t nid,
+			     hda_nid_t *conn_list, int max_conns);
+int snd_hdac_get_sub_nodes(struct hdac_device *codec, hda_nid_t nid,
+			   hda_nid_t *start_id);
+
+/**
+ * snd_hdac_read_parm - read a codec parameter
+ * @codec: the codec object
+ * @nid: NID to read a parameter
+ * @parm: parameter to read
+ *
+ * Returns -1 for error.  If you need to distinguish the error more
+ * strictly, use _snd_hdac_read_parm() directly.
+ */
+static inline int snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid,
+				     int parm)
+{
+	unsigned int val;
+
+	return _snd_hdac_read_parm(codec, nid, parm, &val) < 0 ? -1 : val;
+}
+
+#ifdef CONFIG_PM
+void snd_hdac_power_up(struct hdac_device *codec);
+void snd_hdac_power_down(struct hdac_device *codec);
+void snd_hdac_power_up_pm(struct hdac_device *codec);
+void snd_hdac_power_down_pm(struct hdac_device *codec);
+#else
+static inline void snd_hdac_power_up(struct hdac_device *codec) {}
+static inline void snd_hdac_power_down(struct hdac_device *codec) {}
+static inline void snd_hdac_power_up_pm(struct hdac_device *codec) {}
+static inline void snd_hdac_power_down_pm(struct hdac_device *codec) {}
+#endif
+
+/*
+ * HD-audio codec base driver
+ */
+struct hdac_driver {
+	struct device_driver driver;
+	int type;
+	int (*match)(struct hdac_device *dev, struct hdac_driver *drv);
+	void (*unsol_event)(struct hdac_device *dev, unsigned int event);
+};
+
+#define drv_to_hdac_driver(_drv) container_of(_drv, struct hdac_driver, driver)
+
+/*
+ * HD-audio bus base driver
+ */
+struct hdac_bus_ops {
+	/* send a single command */
+	int (*command)(struct hdac_bus *bus, unsigned int cmd);
+	/* get a response from the last command */
+	int (*get_response)(struct hdac_bus *bus, unsigned int addr,
+			    unsigned int *res);
+};
+
+#define HDA_UNSOL_QUEUE_SIZE	64
+
+struct hdac_bus {
+	struct device *dev;
+	const struct hdac_bus_ops *ops;
+
+	/* codec linked list */
+	struct list_head codec_list;
+	unsigned int num_codecs;
+
+	/* link caddr -> codec */
+	struct hdac_device *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1];
+
+	/* unsolicited event queue */
+	u32 unsol_queue[HDA_UNSOL_QUEUE_SIZE * 2]; /* ring buffer */
+	unsigned int unsol_rp, unsol_wp;
+	struct work_struct unsol_work;
+
+	/* bit flags of powered codecs */
+	unsigned long codec_powered;
+
+	/* flags */
+	bool sync_write:1;		/* sync after verb write */
+
+	/* locks */
+	struct mutex cmd_mutex;
+};
+
+int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
+		      const struct hdac_bus_ops *ops);
+void snd_hdac_bus_exit(struct hdac_bus *bus);
+int snd_hdac_bus_exec_verb(struct hdac_bus *bus, unsigned int addr,
+			   unsigned int cmd, unsigned int *res);
+int snd_hdac_bus_exec_verb_unlocked(struct hdac_bus *bus, unsigned int addr,
+				    unsigned int cmd, unsigned int *res);
+void snd_hdac_bus_queue_event(struct hdac_bus *bus, u32 res, u32 res_ex);
+
+int snd_hdac_bus_add_device(struct hdac_bus *bus, struct hdac_device *codec);
+void snd_hdac_bus_remove_device(struct hdac_bus *bus,
+				struct hdac_device *codec);
+
+static inline void snd_hdac_codec_link_up(struct hdac_device *codec)
+{
+	set_bit(codec->addr, &codec->bus->codec_powered);
+}
+
+static inline void snd_hdac_codec_link_down(struct hdac_device *codec)
+{
+	clear_bit(codec->addr, &codec->bus->codec_powered);
+}
+
+/*
+ * generic array helpers
+ */
+void *snd_array_new(struct snd_array *array);
+void snd_array_free(struct snd_array *array);
+static inline void snd_array_init(struct snd_array *array, unsigned int size,
+				  unsigned int align)
+{
+	array->elem_size = size;
+	array->alloc_align = align;
+}
+
+static inline void *snd_array_elem(struct snd_array *array, unsigned int idx)
+{
+	return array->list + idx * array->elem_size;
+}
+
+static inline unsigned int snd_array_index(struct snd_array *array, void *ptr)
+{
+	return (unsigned long)(ptr - array->list) / array->elem_size;
+}
+
+#endif /* __SOUND_HDAUDIO_H */

+ 64 - 2
include/sound/pcm.h

@@ -60,6 +60,9 @@ struct snd_pcm_hardware {
 
 struct snd_pcm_substream;
 
+struct snd_pcm_audio_tstamp_config; /* definitions further down */
+struct snd_pcm_audio_tstamp_report;
+
 struct snd_pcm_ops {
 	int (*open)(struct snd_pcm_substream *substream);
 	int (*close)(struct snd_pcm_substream *substream);
@@ -71,8 +74,10 @@ struct snd_pcm_ops {
 	int (*prepare)(struct snd_pcm_substream *substream);
 	int (*trigger)(struct snd_pcm_substream *substream, int cmd);
 	snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *substream);
-	int (*wall_clock)(struct snd_pcm_substream *substream,
-			  struct timespec *audio_ts);
+	int (*get_time_info)(struct snd_pcm_substream *substream,
+			struct timespec *system_ts, struct timespec *audio_ts,
+			struct snd_pcm_audio_tstamp_config *audio_tstamp_config,
+			struct snd_pcm_audio_tstamp_report *audio_tstamp_report);
 	int (*copy)(struct snd_pcm_substream *substream, int channel,
 		    snd_pcm_uframes_t pos,
 		    void __user *buf, snd_pcm_uframes_t count);
@@ -281,6 +286,58 @@ struct snd_pcm_hw_constraint_ranges {
 
 struct snd_pcm_hwptr_log;
 
+/*
+ * userspace-provided audio timestamp config to kernel,
+ * structure is for internal use only and filled with dedicated unpack routine
+ */
+struct snd_pcm_audio_tstamp_config {
+	/* 5 of max 16 bits used */
+	u32 type_requested:4;
+	u32 report_delay:1; /* add total delay to A/D or D/A */
+};
+
+static inline void snd_pcm_unpack_audio_tstamp_config(__u32 data,
+						struct snd_pcm_audio_tstamp_config *config)
+{
+	config->type_requested = data & 0xF;
+	config->report_delay = (data >> 4) & 1;
+}
+
+/*
+ * kernel-provided audio timestamp report to user-space
+ * structure is for internal use only and read by dedicated pack routine
+ */
+struct snd_pcm_audio_tstamp_report {
+	/* 6 of max 16 bits used for bit-fields */
+
+	/* for backwards compatibility */
+	u32 valid:1;
+
+	/* actual type if hardware could not support requested timestamp */
+	u32 actual_type:4;
+
+	/* accuracy represented in ns units */
+	u32 accuracy_report:1; /* 0 if accuracy unknown, 1 if accuracy field is valid */
+	u32 accuracy; /* up to 4.29s, will be packed in separate field  */
+};
+
+static inline void snd_pcm_pack_audio_tstamp_report(__u32 *data, __u32 *accuracy,
+						const struct snd_pcm_audio_tstamp_report *report)
+{
+	u32 tmp;
+
+	tmp = report->accuracy_report;
+	tmp <<= 4;
+	tmp |= report->actual_type;
+	tmp <<= 1;
+	tmp |= report->valid;
+
+	*data &= 0xffff; /* zero-clear MSBs */
+	*data |= (tmp << 16);
+	*accuracy = report->accuracy;
+}
+
+
 struct snd_pcm_runtime {
 	/* -- Status -- */
 	struct snd_pcm_substream *trigger_master;
@@ -361,6 +418,11 @@ struct snd_pcm_runtime {
 
 	struct snd_dma_buffer *dma_buffer_p;	/* allocated buffer */
 
+	/* -- audio timestamp config -- */
+	struct snd_pcm_audio_tstamp_config audio_tstamp_config;
+	struct snd_pcm_audio_tstamp_report audio_tstamp_report;
+	struct timespec driver_tstamp;
+
 #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
 	/* -- OSS things -- */
 	struct snd_pcm_oss_runtime oss;

+ 7 - 0
include/sound/pcm_params.h

@@ -366,4 +366,11 @@ static inline int params_physical_width(const struct snd_pcm_hw_params *p)
 	return snd_pcm_format_physical_width(params_format(p));
 }
 
+static inline void
+params_set_format(struct snd_pcm_hw_params *p, snd_pcm_format_t fmt)
+{
+	snd_mask_set(hw_param_mask(p, SNDRV_PCM_HW_PARAM_FORMAT),
+		(__force int)fmt);
+}
+
 #endif /* __SOUND_PCM_PARAMS_H */

+ 1 - 0
include/sound/rt5670.h

@@ -14,6 +14,7 @@
 struct rt5670_platform_data {
 	int jd_mode;
 	bool in2_diff;
+	bool dev_gpio;
 
 	bool dmic_en;
 	unsigned int dmic1_data_pin;

+ 29 - 17
include/sound/seq_device.h

@@ -25,29 +25,26 @@
  * registered device information
  */
 
-#define ID_LEN	32
-
-/* status flag */
-#define SNDRV_SEQ_DEVICE_FREE		0
-#define SNDRV_SEQ_DEVICE_REGISTERED	1
-
 struct snd_seq_device {
 	/* device info */
 	struct snd_card *card;	/* sound card */
 	int device;		/* device number */
-	char id[ID_LEN];	/* driver id */
+	const char *id;		/* driver id */
 	char name[80];		/* device name */
 	int argsize;		/* size of the argument */
 	void *driver_data;	/* private data for driver */
-	int status;		/* flag - read only */
 	void *private_data;	/* private data for the caller */
 	void (*private_free)(struct snd_seq_device *device);
-	struct list_head list;	/* link to next device */
+	struct device dev;
 };
 
+#define to_seq_dev(_dev) \
+	container_of(_dev, struct snd_seq_device, dev)
+
+/* sequencer driver */
 
 /* driver operators
- * init_device:
+ * probe:
  *	Initialize the device with given parameters.
  *	Typically,
  *		1. call snd_hwdep_new
@@ -55,25 +52,40 @@ struct snd_seq_device {
  *		3. call snd_hwdep_register
  *		4. store the instance to dev->driver_data pointer.
  *		
- * free_device:
+ * remove:
  *	Release the private data.
  *	Typically, call snd_device_free(dev->card, dev->driver_data)
  */
-struct snd_seq_dev_ops {
-	int (*init_device)(struct snd_seq_device *dev);
-	int (*free_device)(struct snd_seq_device *dev);
+struct snd_seq_driver {
+	struct device_driver driver;
+	char *id;
+	int argsize;
 };
 
+#define to_seq_drv(_drv) \
+	container_of(_drv, struct snd_seq_driver, driver)
+
 /*
  * prototypes
  */
+#ifdef CONFIG_MODULES
 void snd_seq_device_load_drivers(void);
-int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize, struct snd_seq_device **result);
-int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry, int argsize);
-int snd_seq_device_unregister_driver(char *id);
+#else
+#define snd_seq_device_load_drivers()
+#endif
+int snd_seq_device_new(struct snd_card *card, int device, const char *id,
+		       int argsize, struct snd_seq_device **result);
 
 #define SNDRV_SEQ_DEVICE_ARGPTR(dev) (void *)((char *)(dev) + sizeof(struct snd_seq_device))
 
+int __must_check __snd_seq_driver_register(struct snd_seq_driver *drv,
+					   struct module *mod);
+#define snd_seq_driver_register(drv) \
+	__snd_seq_driver_register(drv, THIS_MODULE)
+void snd_seq_driver_unregister(struct snd_seq_driver *drv);
+
+#define module_snd_seq_driver(drv) \
+	module_driver(drv, snd_seq_driver_register, snd_seq_driver_unregister)
 
 /*
  * id strings for generic devices

+ 1 - 5
include/sound/seq_kernel.h

@@ -99,13 +99,9 @@ int snd_seq_event_port_attach(int client, struct snd_seq_port_callback *pcbp,
 int snd_seq_event_port_detach(int client, int port);
 
 #ifdef CONFIG_MODULES
-void snd_seq_autoload_lock(void);
-void snd_seq_autoload_unlock(void);
 void snd_seq_autoload_init(void);
-#define snd_seq_autoload_exit()	snd_seq_autoload_lock()
+void snd_seq_autoload_exit(void);
 #else
-#define snd_seq_autoload_lock()
-#define snd_seq_autoload_unlock()
 #define snd_seq_autoload_init()
 #define snd_seq_autoload_exit()
 #endif

+ 0 - 1
include/sound/simple_card.h

@@ -16,7 +16,6 @@
 
 struct asoc_simple_dai {
 	const char *name;
-	unsigned int fmt;
 	unsigned int sysclk;
 	int slots;
 	int slot_width;

+ 3 - 3
include/sound/soc-dapm.h

@@ -378,6 +378,7 @@ 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);
 int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
 			 const struct snd_soc_pcm_stream *params,
+			 unsigned int num_params,
 			 struct snd_soc_dapm_widget *source,
 			 struct snd_soc_dapm_widget *sink);
 
@@ -440,7 +441,6 @@ void dapm_mark_endpoints_dirty(struct snd_soc_card *card);
 int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
 	struct snd_soc_dapm_widget_list **list);
 
-struct snd_soc_codec *snd_soc_dapm_kcontrol_codec(struct snd_kcontrol *kcontrol);
 struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(
 	struct snd_kcontrol *kcontrol);
 
@@ -531,6 +531,8 @@ struct snd_soc_dapm_widget {
 	void *priv;				/* widget specific data */
 	struct regulator *regulator;		/* attached regulator */
 	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 */
 	int reg;				/* negative reg = no direct dapm */
@@ -586,8 +588,6 @@ struct snd_soc_dapm_update {
 /* DAPM context */
 struct snd_soc_dapm_context {
 	enum snd_soc_bias_level bias_level;
-	enum snd_soc_bias_level suspend_bias_level;
-	struct delayed_work delayed_work;
 	unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
 	/* Go to BIAS_OFF in suspend if the DAPM context is idle */
 	unsigned int suspend_bias_off:1;

+ 1 - 1
include/sound/soc-dpcm.h

@@ -135,7 +135,7 @@ void snd_soc_dpcm_be_set_state(struct snd_soc_pcm_runtime *be, int stream,
 
 /* internal use only */
 int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute);
-int soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd);
+void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd);
 int soc_dpcm_runtime_update(struct snd_soc_card *);
 
 int dpcm_path_get(struct snd_soc_pcm_runtime *fe,

+ 28 - 4
include/sound/soc.h

@@ -450,8 +450,10 @@ int soc_dai_hw_params(struct snd_pcm_substream *substream,
 		      struct snd_soc_dai *dai);
 
 /* Jack reporting */
-int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
-		     struct snd_soc_jack *jack);
+int snd_soc_card_jack_new(struct snd_soc_card *card, const char *id, int type,
+	struct snd_soc_jack *jack, struct snd_soc_jack_pin *pins,
+	unsigned int num_pins);
+
 void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask);
 int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count,
 			  struct snd_soc_jack_pin *pins);
@@ -659,7 +661,7 @@ struct snd_soc_jack_gpio {
 struct snd_soc_jack {
 	struct mutex mutex;
 	struct snd_jack *jack;
-	struct snd_soc_codec *codec;
+	struct snd_soc_card *card;
 	struct list_head pins;
 	int status;
 	struct blocking_notifier_head notifier;
@@ -941,6 +943,7 @@ struct snd_soc_dai_link {
 	int be_id;	/* optional ID for machine driver BE identification */
 
 	const struct snd_soc_pcm_stream *params;
+	unsigned int num_params;
 
 	unsigned int dai_fmt;           /* format to set on init */
 
@@ -954,6 +957,9 @@ struct snd_soc_dai_link {
 	unsigned int symmetric_channels:1;
 	unsigned int symmetric_samplebits:1;
 
+	/* Mark this pcm with non atomic ops */
+	bool nonatomic;
+
 	/* Do not create a PCM for this DAI link (Backend link) */
 	unsigned int no_pcm:1;
 
@@ -1071,11 +1077,16 @@ struct snd_soc_card {
 
 	/*
 	 * Card-specific routes and widgets.
+	 * Note: of_dapm_xxx for Device Tree; Otherwise for driver build-in.
 	 */
 	const struct snd_soc_dapm_widget *dapm_widgets;
 	int num_dapm_widgets;
 	const struct snd_soc_dapm_route *dapm_routes;
 	int num_dapm_routes;
+	const struct snd_soc_dapm_widget *of_dapm_widgets;
+	int num_of_dapm_widgets;
+	const struct snd_soc_dapm_route *of_dapm_routes;
+	int num_of_dapm_routes;
 	bool fully_routed;
 
 	struct work_struct deferred_resume_work;
@@ -1258,6 +1269,19 @@ static inline struct snd_soc_dapm_context *snd_soc_component_get_dapm(
 	return component->dapm_ptr;
 }
 
+/**
+ * snd_soc_dapm_kcontrol_codec() - Returns the codec associated to a kcontrol
+ * @kcontrol: The kcontrol
+ *
+ * This function must only be used on DAPM contexts that are known to be part of
+ * a CODEC (e.g. in a CODEC driver). Otherwise the behavior is undefined.
+ */
+static inline struct snd_soc_codec *snd_soc_dapm_kcontrol_codec(
+	struct snd_kcontrol *kcontrol)
+{
+	return snd_soc_dapm_to_codec(snd_soc_dapm_kcontrol_dapm(kcontrol));
+}
+
 /* codec IO */
 unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg);
 int snd_soc_write(struct snd_soc_codec *codec, unsigned int reg,
@@ -1469,7 +1493,7 @@ static inline struct snd_soc_codec *snd_soc_kcontrol_codec(
 }
 
 /**
- * snd_soc_kcontrol_platform() - Returns the platform that registerd the control
+ * snd_soc_kcontrol_platform() - Returns the platform that registered the control
  * @kcontrol: The control for which to get the platform
  *
  * Note: This function will only work correctly if the control has been

+ 1 - 0
include/uapi/sound/asequencer.h

@@ -22,6 +22,7 @@
 #ifndef _UAPI__SOUND_ASEQUENCER_H
 #define _UAPI__SOUND_ASEQUENCER_H
 
+#include <sound/asound.h>
 
 /** version of the sequencer */
 #define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION (1, 0, 1)

+ 34 - 5
include/uapi/sound/asound.h

@@ -25,6 +25,9 @@
 
 #include <linux/types.h>
 
+#ifndef __KERNEL__
+#include <stdlib.h>
+#endif
 
 /*
  *  protocol version
@@ -140,7 +143,7 @@ struct snd_hwdep_dsp_image {
  *                                                                           *
  *****************************************************************************/
 
-#define SNDRV_PCM_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 12)
+#define SNDRV_PCM_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 13)
 
 typedef unsigned long snd_pcm_uframes_t;
 typedef signed long snd_pcm_sframes_t;
@@ -267,10 +270,17 @@ typedef int __bitwise snd_pcm_subformat_t;
 #define SNDRV_PCM_INFO_JOINT_DUPLEX	0x00200000	/* playback and capture stream are somewhat correlated */
 #define SNDRV_PCM_INFO_SYNC_START	0x00400000	/* pcm support some kind of sync go */
 #define SNDRV_PCM_INFO_NO_PERIOD_WAKEUP	0x00800000	/* period wakeup can be disabled */
-#define SNDRV_PCM_INFO_HAS_WALL_CLOCK   0x01000000      /* has audio wall clock for audio/system time sync */
+#define SNDRV_PCM_INFO_HAS_WALL_CLOCK   0x01000000      /* (Deprecated)has audio wall clock for audio/system time sync */
+#define SNDRV_PCM_INFO_HAS_LINK_ATIME              0x01000000  /* report hardware link audio time, reset on startup */
+#define SNDRV_PCM_INFO_HAS_LINK_ABSOLUTE_ATIME     0x02000000  /* report absolute hardware link audio time, not reset on startup */
+#define SNDRV_PCM_INFO_HAS_LINK_ESTIMATED_ATIME    0x04000000  /* report estimated link audio time */
+#define SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME 0x08000000  /* report synchronized audio/system time */
+
 #define SNDRV_PCM_INFO_DRAIN_TRIGGER	0x40000000		/* internal kernel flag - trigger in drain */
 #define SNDRV_PCM_INFO_FIFO_IN_FRAMES	0x80000000	/* internal kernel flag - FIFO size is in frames */
 
+
+
 typedef int __bitwise snd_pcm_state_t;
 #define	SNDRV_PCM_STATE_OPEN		((__force snd_pcm_state_t) 0) /* stream is open */
 #define	SNDRV_PCM_STATE_SETUP		((__force snd_pcm_state_t) 1) /* stream has a setup */
@@ -408,6 +418,22 @@ struct snd_pcm_channel_info {
 	unsigned int step;		/* samples distance in bits */
 };
 
+enum {
+	/*
+	 *  first definition for backwards compatibility only,
+	 *  maps to wallclock/link time for HDAudio playback and DEFAULT/DMA time for everything else
+	 */
+	SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT = 0,
+
+	/* timestamp definitions */
+	SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT = 1,           /* DMA time, reported as per hw_ptr */
+	SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK = 2,	           /* link time reported by sample or wallclock counter, reset on startup */
+	SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ABSOLUTE = 3,	   /* link time reported by sample or wallclock counter, not reset on startup */
+	SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_ESTIMATED = 4,    /* link time estimated indirectly */
+	SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED = 5, /* link time synchronized with system time */
+	SNDRV_PCM_AUDIO_TSTAMP_TYPE_LAST = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED
+};
+
 struct snd_pcm_status {
 	snd_pcm_state_t state;		/* stream state */
 	struct timespec trigger_tstamp;	/* time when stream was started/stopped/paused */
@@ -419,9 +445,11 @@ struct snd_pcm_status {
 	snd_pcm_uframes_t avail_max;	/* max frames available on hw since last status */
 	snd_pcm_uframes_t overrange;	/* count of ADC (capture) overrange detections from last status */
 	snd_pcm_state_t suspended_state; /* suspended stream state */
-	__u32 reserved_alignment;	/* must be filled with zero */
-	struct timespec audio_tstamp;	/* from sample counter or wall clock */
-	unsigned char reserved[56-sizeof(struct timespec)]; /* must be filled with zero */
+	__u32 audio_tstamp_data;	 /* needed for 64-bit alignment, used for configs/report to/from userspace */
+	struct timespec audio_tstamp;	/* sample counter, wall clock, PHC or on-demand sync'ed */
+	struct timespec driver_tstamp;	/* useful in case reference system tstamp is reported with delay */
+	__u32 audio_tstamp_accuracy;	/* in ns units, only valid if indicated in audio_tstamp_data */
+	unsigned char reserved[52-2*sizeof(struct timespec)]; /* must be filled with zero */
 };
 
 struct snd_pcm_mmap_status {
@@ -534,6 +562,7 @@ enum {
 #define SNDRV_PCM_IOCTL_DELAY		_IOR('A', 0x21, snd_pcm_sframes_t)
 #define SNDRV_PCM_IOCTL_HWSYNC		_IO('A', 0x22)
 #define SNDRV_PCM_IOCTL_SYNC_PTR	_IOWR('A', 0x23, struct snd_pcm_sync_ptr)
+#define SNDRV_PCM_IOCTL_STATUS_EXT	_IOWR('A', 0x24, struct snd_pcm_status)
 #define SNDRV_PCM_IOCTL_CHANNEL_INFO	_IOR('A', 0x32, struct snd_pcm_channel_info)
 #define SNDRV_PCM_IOCTL_PREPARE		_IO('A', 0x40)
 #define SNDRV_PCM_IOCTL_RESET		_IO('A', 0x41)

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

@@ -75,7 +75,7 @@ struct snd_compr_tstamp {
 /**
  * struct snd_compr_avail - avail descriptor
  * @avail: Number of bytes available in ring buffer for writing/reading
- * @tstamp: timestamp infomation
+ * @tstamp: timestamp information
  */
 struct snd_compr_avail {
 	__u64 avail;

+ 1 - 2
include/uapi/sound/emu10k1.h

@@ -23,8 +23,7 @@
 #define _UAPI__SOUND_EMU10K1_H
 
 #include <linux/types.h>
-
-
+#include <sound/asound.h>
 
 /*
  * ---- FX8010 ----

+ 6 - 0
include/uapi/sound/hdspm.h

@@ -20,6 +20,12 @@
  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <stdint.h>
+#endif
+
 /* Maximum channels is 64 even on 56Mode you have 64playbacks to matrix */
 #define HDSPM_MAX_CHANNELS      64
 

+ 2 - 0
sound/Kconfig

@@ -76,6 +76,8 @@ source "sound/isa/Kconfig"
 
 source "sound/pci/Kconfig"
 
+source "sound/hda/Kconfig"
+
 source "sound/ppc/Kconfig"
 
 source "sound/aoa/Kconfig"

+ 1 - 1
sound/Makefile

@@ -6,7 +6,7 @@ obj-$(CONFIG_SOUND_PRIME) += sound_firmware.o
 obj-$(CONFIG_SOUND_PRIME) += oss/
 obj-$(CONFIG_DMASOUND) += oss/
 obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \
-	firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/
+	firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ hda/
 obj-$(CONFIG_SND_AOA) += aoa/
 
 # This one must be compilable even if sound is configured out

+ 1 - 1
sound/aoa/soundbus/i2sbus/core.c

@@ -31,7 +31,7 @@ module_param(force, int, 0444);
 MODULE_PARM_DESC(force, "Force loading i2sbus even when"
 			" no layout-id property is present");
 
-static struct of_device_id i2sbus_match[] = {
+static const struct of_device_id i2sbus_match[] = {
 	{ .name = "i2s" },
 	{ }
 };

+ 205 - 124
sound/core/control.c

@@ -192,36 +192,41 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask,
 EXPORT_SYMBOL(snd_ctl_notify);
 
 /**
- * snd_ctl_new - create a control instance from the template
- * @control: the control template
- * @access: the default control access
+ * snd_ctl_new - create a new control instance with some elements
+ * @kctl: the pointer to store new control instance
+ * @count: the number of elements in this control
+ * @access: the default access flags for elements in this control
+ * @file: given when locking these elements
  *
- * Allocates a new struct snd_kcontrol instance and copies the given template 
- * to the new instance. It does not copy volatile data (access).
+ * Allocates a memory object for a new control instance. The instance has
+ * elements as many as the given number (@count). Each element has given
+ * access permissions (@access). Each element is locked when @file is given.
  *
- * Return: The pointer of the new instance, or %NULL on failure.
+ * Return: 0 on success, error code on failure
  */
-static struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control,
-					unsigned int access)
+static int snd_ctl_new(struct snd_kcontrol **kctl, unsigned int count,
+		       unsigned int access, struct snd_ctl_file *file)
 {
-	struct snd_kcontrol *kctl;
+	unsigned int size;
 	unsigned int idx;
 	
-	if (snd_BUG_ON(!control || !control->count))
-		return NULL;
+	if (count == 0 || count > MAX_CONTROL_COUNT)
+		return -EINVAL;
 
-	if (control->count > MAX_CONTROL_COUNT)
-		return NULL;
+	size  = sizeof(struct snd_kcontrol);
+	size += sizeof(struct snd_kcontrol_volatile) * count;
 
-	kctl = kzalloc(sizeof(*kctl) + sizeof(struct snd_kcontrol_volatile) * control->count, GFP_KERNEL);
-	if (kctl == NULL) {
-		pr_err("ALSA: Cannot allocate control instance\n");
-		return NULL;
+	*kctl = kzalloc(size, GFP_KERNEL);
+	if (!*kctl)
+		return -ENOMEM;
+
+	for (idx = 0; idx < count; idx++) {
+		(*kctl)->vd[idx].access = access;
+		(*kctl)->vd[idx].owner = file;
 	}
-	*kctl = *control;
-	for (idx = 0; idx < kctl->count; idx++)
-		kctl->vd[idx].access = access;
-	return kctl;
+	(*kctl)->count = count;
+
+	return 0;
 }
 
 /**
@@ -238,37 +243,53 @@ static struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control,
 struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
 				  void *private_data)
 {
-	struct snd_kcontrol kctl;
+	struct snd_kcontrol *kctl;
+	unsigned int count;
 	unsigned int access;
+	int err;
 	
 	if (snd_BUG_ON(!ncontrol || !ncontrol->info))
 		return NULL;
-	memset(&kctl, 0, sizeof(kctl));
-	kctl.id.iface = ncontrol->iface;
-	kctl.id.device = ncontrol->device;
-	kctl.id.subdevice = ncontrol->subdevice;
+
+	count = ncontrol->count;
+	if (count == 0)
+		count = 1;
+
+	access = ncontrol->access;
+	if (access == 0)
+		access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+	access &= (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+		   SNDRV_CTL_ELEM_ACCESS_VOLATILE |
+		   SNDRV_CTL_ELEM_ACCESS_INACTIVE |
+		   SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE |
+		   SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND |
+		   SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK);
+
+	err = snd_ctl_new(&kctl, count, access, NULL);
+	if (err < 0)
+		return NULL;
+
+	/* The 'numid' member is decided when calling snd_ctl_add(). */
+	kctl->id.iface = ncontrol->iface;
+	kctl->id.device = ncontrol->device;
+	kctl->id.subdevice = ncontrol->subdevice;
 	if (ncontrol->name) {
-		strlcpy(kctl.id.name, ncontrol->name, sizeof(kctl.id.name));
-		if (strcmp(ncontrol->name, kctl.id.name) != 0)
+		strlcpy(kctl->id.name, ncontrol->name, sizeof(kctl->id.name));
+		if (strcmp(ncontrol->name, kctl->id.name) != 0)
 			pr_warn("ALSA: Control name '%s' truncated to '%s'\n",
-				ncontrol->name, kctl.id.name);
+				ncontrol->name, kctl->id.name);
 	}
-	kctl.id.index = ncontrol->index;
-	kctl.count = ncontrol->count ? ncontrol->count : 1;
-	access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
-		 (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|
-				      SNDRV_CTL_ELEM_ACCESS_VOLATILE|
-				      SNDRV_CTL_ELEM_ACCESS_INACTIVE|
-				      SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE|
-				      SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND|
-				      SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK));
-	kctl.info = ncontrol->info;
-	kctl.get = ncontrol->get;
-	kctl.put = ncontrol->put;
-	kctl.tlv.p = ncontrol->tlv.p;
-	kctl.private_value = ncontrol->private_value;
-	kctl.private_data = private_data;
-	return snd_ctl_new(&kctl, access);
+	kctl->id.index = ncontrol->index;
+
+	kctl->info = ncontrol->info;
+	kctl->get = ncontrol->get;
+	kctl->put = ncontrol->put;
+	kctl->tlv.p = ncontrol->tlv.p;
+
+	kctl->private_value = ncontrol->private_value;
+	kctl->private_data = private_data;
+
+	return kctl;
 }
 EXPORT_SYMBOL(snd_ctl_new1);
 
@@ -557,6 +578,7 @@ error:
  *
  * Finds the control instance with the given id, and activate or
  * inactivate the control together with notification, if changed.
+ * The given ID data is filled with full information.
  *
  * Return: 0 if unchanged, 1 if changed, or a negative error code on failure.
  */
@@ -586,6 +608,7 @@ int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id,
 			goto unlock;
 		vd->access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
 	}
+	snd_ctl_build_ioff(id, kctl, index_offset);
 	ret = 1;
  unlock:
 	up_write(&card->controls_rwsem);
@@ -1006,7 +1029,7 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file,
 struct user_element {
 	struct snd_ctl_elem_info info;
 	struct snd_card *card;
-	void *elem_data;		/* element data */
+	char *elem_data;		/* element data */
 	unsigned long elem_data_size;	/* size of element data in bytes */
 	void *tlv_data;			/* TLV data */
 	unsigned long tlv_data_size;	/* TLV data size */
@@ -1017,8 +1040,12 @@ static int snd_ctl_elem_user_info(struct snd_kcontrol *kcontrol,
 				  struct snd_ctl_elem_info *uinfo)
 {
 	struct user_element *ue = kcontrol->private_data;
+	unsigned int offset;
 
+	offset = snd_ctl_get_ioff(kcontrol, &uinfo->id);
 	*uinfo = ue->info;
+	snd_ctl_build_ioff(&uinfo->id, kcontrol, offset);
+
 	return 0;
 }
 
@@ -1028,10 +1055,13 @@ static int snd_ctl_elem_user_enum_info(struct snd_kcontrol *kcontrol,
 	struct user_element *ue = kcontrol->private_data;
 	const char *names;
 	unsigned int item;
+	unsigned int offset;
 
 	item = uinfo->value.enumerated.item;
 
+	offset = snd_ctl_get_ioff(kcontrol, &uinfo->id);
 	*uinfo = ue->info;
+	snd_ctl_build_ioff(&uinfo->id, kcontrol, offset);
 
 	item = min(item, uinfo->value.enumerated.items - 1);
 	uinfo->value.enumerated.item = item;
@@ -1048,9 +1078,12 @@ static int snd_ctl_elem_user_get(struct snd_kcontrol *kcontrol,
 				 struct snd_ctl_elem_value *ucontrol)
 {
 	struct user_element *ue = kcontrol->private_data;
+	unsigned int size = ue->elem_data_size;
+	char *src = ue->elem_data +
+			snd_ctl_get_ioff(kcontrol, &ucontrol->id) * size;
 
 	mutex_lock(&ue->card->user_ctl_lock);
-	memcpy(&ucontrol->value, ue->elem_data, ue->elem_data_size);
+	memcpy(&ucontrol->value, src, size);
 	mutex_unlock(&ue->card->user_ctl_lock);
 	return 0;
 }
@@ -1060,11 +1093,14 @@ static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol,
 {
 	int change;
 	struct user_element *ue = kcontrol->private_data;
+	unsigned int size = ue->elem_data_size;
+	char *dst = ue->elem_data +
+			snd_ctl_get_ioff(kcontrol, &ucontrol->id) * size;
 
 	mutex_lock(&ue->card->user_ctl_lock);
-	change = memcmp(&ucontrol->value, ue->elem_data, ue->elem_data_size) != 0;
+	change = memcmp(&ucontrol->value, dst, size) != 0;
 	if (change)
-		memcpy(ue->elem_data, &ucontrol->value, ue->elem_data_size);
+		memcpy(dst, &ucontrol->value, size);
 	mutex_unlock(&ue->card->user_ctl_lock);
 	return change;
 }
@@ -1078,7 +1114,7 @@ static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol,
 	int change = 0;
 	void *new_data;
 
-	if (op_flag > 0) {
+	if (op_flag == SNDRV_CTL_TLV_OP_WRITE) {
 		if (size > 1024 * 128)	/* sane value */
 			return -EINVAL;
 
@@ -1161,84 +1197,103 @@ static void snd_ctl_elem_user_free(struct snd_kcontrol *kcontrol)
 static int snd_ctl_elem_add(struct snd_ctl_file *file,
 			    struct snd_ctl_elem_info *info, int replace)
 {
+	/* The capacity of struct snd_ctl_elem_value.value.*/
+	static const unsigned int value_sizes[] = {
+		[SNDRV_CTL_ELEM_TYPE_BOOLEAN]	= sizeof(long),
+		[SNDRV_CTL_ELEM_TYPE_INTEGER]	= sizeof(long),
+		[SNDRV_CTL_ELEM_TYPE_ENUMERATED] = sizeof(unsigned int),
+		[SNDRV_CTL_ELEM_TYPE_BYTES]	= sizeof(unsigned char),
+		[SNDRV_CTL_ELEM_TYPE_IEC958]	= sizeof(struct snd_aes_iec958),
+		[SNDRV_CTL_ELEM_TYPE_INTEGER64] = sizeof(long long),
+	};
+	static const unsigned int max_value_counts[] = {
+		[SNDRV_CTL_ELEM_TYPE_BOOLEAN]	= 128,
+		[SNDRV_CTL_ELEM_TYPE_INTEGER]	= 128,
+		[SNDRV_CTL_ELEM_TYPE_ENUMERATED] = 128,
+		[SNDRV_CTL_ELEM_TYPE_BYTES]	= 512,
+		[SNDRV_CTL_ELEM_TYPE_IEC958]	= 1,
+		[SNDRV_CTL_ELEM_TYPE_INTEGER64] = 64,
+	};
 	struct snd_card *card = file->card;
-	struct snd_kcontrol kctl, *_kctl;
+	struct snd_kcontrol *kctl;
+	unsigned int count;
 	unsigned int access;
 	long private_size;
 	struct user_element *ue;
-	int idx, err;
+	unsigned int offset;
+	int err;
 
-	if (info->count < 1)
-		return -EINVAL;
 	if (!*info->id.name)
 		return -EINVAL;
 	if (strnlen(info->id.name, sizeof(info->id.name)) >= sizeof(info->id.name))
 		return -EINVAL;
-	access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
-		(info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|
-				 SNDRV_CTL_ELEM_ACCESS_INACTIVE|
-				 SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE));
-	info->id.numid = 0;
-	memset(&kctl, 0, sizeof(kctl));
 
+	/* Delete a control to replace them if needed. */
 	if (replace) {
+		info->id.numid = 0;
 		err = snd_ctl_remove_user_ctl(file, &info->id);
 		if (err)
 			return err;
 	}
 
-	if (card->user_ctl_count >= MAX_USER_CONTROLS)
+	/*
+	 * The number of userspace controls are counted control by control,
+	 * not element by element.
+	 */
+	if (card->user_ctl_count + 1 > MAX_USER_CONTROLS)
 		return -ENOMEM;
 
-	memcpy(&kctl.id, &info->id, sizeof(info->id));
-	kctl.count = info->owner ? info->owner : 1;
-	access |= SNDRV_CTL_ELEM_ACCESS_USER;
-	if (info->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED)
-		kctl.info = snd_ctl_elem_user_enum_info;
-	else
-		kctl.info = snd_ctl_elem_user_info;
-	if (access & SNDRV_CTL_ELEM_ACCESS_READ)
-		kctl.get = snd_ctl_elem_user_get;
-	if (access & SNDRV_CTL_ELEM_ACCESS_WRITE)
-		kctl.put = snd_ctl_elem_user_put;
-	if (access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) {
-		kctl.tlv.c = snd_ctl_elem_user_tlv;
+	/* Check the number of elements for this userspace control. */
+	count = info->owner;
+	if (count == 0)
+		count = 1;
+
+	/* Arrange access permissions if needed. */
+	access = info->access;
+	if (access == 0)
+		access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+	access &= (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+		   SNDRV_CTL_ELEM_ACCESS_INACTIVE |
+		   SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE);
+	if (access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)
 		access |= SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
-	}
-	switch (info->type) {
-	case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
-	case SNDRV_CTL_ELEM_TYPE_INTEGER:
-		private_size = sizeof(long);
-		if (info->count > 128)
-			return -EINVAL;
-		break;
-	case SNDRV_CTL_ELEM_TYPE_INTEGER64:
-		private_size = sizeof(long long);
-		if (info->count > 64)
-			return -EINVAL;
-		break;
-	case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
-		private_size = sizeof(unsigned int);
-		if (info->count > 128 || info->value.enumerated.items == 0)
-			return -EINVAL;
-		break;
-	case SNDRV_CTL_ELEM_TYPE_BYTES:
-		private_size = sizeof(unsigned char);
-		if (info->count > 512)
-			return -EINVAL;
-		break;
-	case SNDRV_CTL_ELEM_TYPE_IEC958:
-		private_size = sizeof(struct snd_aes_iec958);
-		if (info->count != 1)
-			return -EINVAL;
-		break;
-	default:
+	access |= SNDRV_CTL_ELEM_ACCESS_USER;
+
+	/*
+	 * Check information and calculate the size of data specific to
+	 * this userspace control.
+	 */
+	if (info->type < SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
+	    info->type > SNDRV_CTL_ELEM_TYPE_INTEGER64)
 		return -EINVAL;
-	}
-	private_size *= info->count;
-	ue = kzalloc(sizeof(struct user_element) + private_size, GFP_KERNEL);
-	if (ue == NULL)
+	if (info->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED &&
+	    info->value.enumerated.items == 0)
+		return -EINVAL;
+	if (info->count < 1 ||
+	    info->count > max_value_counts[info->type])
+		return -EINVAL;
+	private_size = value_sizes[info->type] * info->count;
+
+	/*
+	 * Keep memory object for this userspace control. After passing this
+	 * code block, the instance should be freed by snd_ctl_free_one().
+	 *
+	 * Note that these elements in this control are locked.
+	 */
+	err = snd_ctl_new(&kctl, count, access, file);
+	if (err < 0)
+		return err;
+	memcpy(&kctl->id, &info->id, sizeof(kctl->id));
+	kctl->private_data = kzalloc(sizeof(struct user_element) + private_size * count,
+				     GFP_KERNEL);
+	if (kctl->private_data == NULL) {
+		kfree(kctl);
 		return -ENOMEM;
+	}
+	kctl->private_free = snd_ctl_elem_user_free;
+
+	/* Set private data for this userspace control. */
+	ue = (struct user_element *)kctl->private_data;
 	ue->card = card;
 	ue->info = *info;
 	ue->info.access = 0;
@@ -1247,23 +1302,36 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
 	if (ue->info.type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
 		err = snd_ctl_elem_init_enum_names(ue);
 		if (err < 0) {
-			kfree(ue);
+			snd_ctl_free_one(kctl);
 			return err;
 		}
 	}
-	kctl.private_free = snd_ctl_elem_user_free;
-	_kctl = snd_ctl_new(&kctl, access);
-	if (_kctl == NULL) {
-		kfree(ue->priv_data);
-		kfree(ue);
-		return -ENOMEM;
-	}
-	_kctl->private_data = ue;
-	for (idx = 0; idx < _kctl->count; idx++)
-		_kctl->vd[idx].owner = file;
-	err = snd_ctl_add(card, _kctl);
+
+	/* Set callback functions. */
+	if (info->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED)
+		kctl->info = snd_ctl_elem_user_enum_info;
+	else
+		kctl->info = snd_ctl_elem_user_info;
+	if (access & SNDRV_CTL_ELEM_ACCESS_READ)
+		kctl->get = snd_ctl_elem_user_get;
+	if (access & SNDRV_CTL_ELEM_ACCESS_WRITE)
+		kctl->put = snd_ctl_elem_user_put;
+	if (access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)
+		kctl->tlv.c = snd_ctl_elem_user_tlv;
+
+	/* This function manage to free the instance on failure. */
+	err = snd_ctl_add(card, kctl);
 	if (err < 0)
 		return err;
+	offset = snd_ctl_get_ioff(kctl, &info->id);
+	snd_ctl_build_ioff(&info->id, kctl, offset);
+	/*
+	 * Here we cannot fill any field for the number of elements added by
+	 * this operation because there're no specific fields. The usage of
+	 * 'owner' field for this purpose may cause any bugs to userspace
+	 * applications because the field originally means PID of a process
+	 * which locks the element.
+	 */
 
 	down_write(&card->controls_rwsem);
 	card->user_ctl_count++;
@@ -1276,9 +1344,19 @@ static int snd_ctl_elem_add_user(struct snd_ctl_file *file,
 				 struct snd_ctl_elem_info __user *_info, int replace)
 {
 	struct snd_ctl_elem_info info;
+	int err;
+
 	if (copy_from_user(&info, _info, sizeof(info)))
 		return -EFAULT;
-	return snd_ctl_elem_add(file, &info, replace);
+	err = snd_ctl_elem_add(file, &info, replace);
+	if (err < 0)
+		return err;
+	if (copy_to_user(_info, &info, sizeof(info))) {
+		snd_ctl_remove_user_ctl(file, &info.id);
+		return -EFAULT;
+	}
+
+	return 0;
 }
 
 static int snd_ctl_elem_remove(struct snd_ctl_file *file,
@@ -1338,9 +1416,12 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file,
 		goto __kctl_end;
 	}
 	vd = &kctl->vd[tlv.numid - kctl->id.numid];
-	if ((op_flag == 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) == 0) ||
-	    (op_flag > 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) == 0) ||
-	    (op_flag < 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND) == 0)) {
+	if ((op_flag == SNDRV_CTL_TLV_OP_READ &&
+	     (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) == 0) ||
+	    (op_flag == SNDRV_CTL_TLV_OP_WRITE &&
+	     (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) == 0) ||
+	    (op_flag == SNDRV_CTL_TLV_OP_CMD &&
+	     (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND) == 0)) {
 	    	err = -ENXIO;
 	    	goto __kctl_end;
 	}
@@ -1357,7 +1438,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file,
 			return 0;
 		}
 	} else {
-		if (op_flag) {
+		if (op_flag != SNDRV_CTL_TLV_OP_READ) {
 			err = -ENXIO;
 			goto __kctl_end;
 		}

+ 34 - 13
sound/core/device.c

@@ -50,10 +50,8 @@ int snd_device_new(struct snd_card *card, enum snd_device_type type,
 	if (snd_BUG_ON(!card || !device_data || !ops))
 		return -ENXIO;
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-	if (dev == NULL) {
-		dev_err(card->dev, "Cannot allocate device, type=%d\n", type);
+	if (!dev)
 		return -ENOMEM;
-	}
 	INIT_LIST_HEAD(&dev->list);
 	dev->card = card;
 	dev->type = type;
@@ -73,7 +71,7 @@ int snd_device_new(struct snd_card *card, enum snd_device_type type,
 }
 EXPORT_SYMBOL(snd_device_new);
 
-static int __snd_device_disconnect(struct snd_device *dev)
+static void __snd_device_disconnect(struct snd_device *dev)
 {
 	if (dev->state == SNDRV_DEV_REGISTERED) {
 		if (dev->ops->dev_disconnect &&
@@ -81,7 +79,6 @@ static int __snd_device_disconnect(struct snd_device *dev)
 			dev_err(dev->card->dev, "device disconnect failure\n");
 		dev->state = SNDRV_DEV_DISCONNECTED;
 	}
-	return 0;
 }
 
 static void __snd_device_free(struct snd_device *dev)
@@ -108,6 +105,34 @@ static struct snd_device *look_for_dev(struct snd_card *card, void *device_data)
 	return NULL;
 }
 
+/**
+ * snd_device_disconnect - disconnect the device
+ * @card: the card instance
+ * @device_data: the data pointer to disconnect
+ *
+ * Turns the device into the disconnection state, invoking
+ * dev_disconnect callback, if the device was already registered.
+ *
+ * Usually called from snd_card_disconnect().
+ *
+ * Return: Zero if successful, or a negative error code on failure or if the
+ * device not found.
+ */
+void snd_device_disconnect(struct snd_card *card, void *device_data)
+{
+	struct snd_device *dev;
+
+	if (snd_BUG_ON(!card || !device_data))
+		return;
+	dev = look_for_dev(card, device_data);
+	if (dev)
+		__snd_device_disconnect(dev);
+	else
+		dev_dbg(card->dev, "device disconnect %p (from %pF), not found\n",
+			device_data, __builtin_return_address(0));
+}
+EXPORT_SYMBOL_GPL(snd_device_disconnect);
+
 /**
  * snd_device_free - release the device from the card
  * @card: the card instance
@@ -195,18 +220,14 @@ int snd_device_register_all(struct snd_card *card)
  * disconnect all the devices on the card.
  * called from init.c
  */
-int snd_device_disconnect_all(struct snd_card *card)
+void snd_device_disconnect_all(struct snd_card *card)
 {
 	struct snd_device *dev;
-	int err = 0;
 
 	if (snd_BUG_ON(!card))
-		return -ENXIO;
-	list_for_each_entry_reverse(dev, &card->devices, list) {
-		if (__snd_device_disconnect(dev) < 0)
-			err = -ENXIO;
-	}
-	return err;
+		return;
+	list_for_each_entry_reverse(dev, &card->devices, list)
+		__snd_device_disconnect(dev);
 }
 
 /*

+ 1 - 3
sound/core/hwdep.c

@@ -378,10 +378,8 @@ int snd_hwdep_new(struct snd_card *card, char *id, int device,
 	if (rhwdep)
 		*rhwdep = NULL;
 	hwdep = kzalloc(sizeof(*hwdep), GFP_KERNEL);
-	if (hwdep == NULL) {
-		dev_err(card->dev, "hwdep: cannot allocate\n");
+	if (!hwdep)
 		return -ENOMEM;
-	}
 
 	init_waitqueue_head(&hwdep->open_wait);
 	mutex_init(&hwdep->open_mutex);

+ 1 - 4
sound/core/init.c

@@ -400,7 +400,6 @@ static const struct file_operations snd_shutdown_f_ops =
 int snd_card_disconnect(struct snd_card *card)
 {
 	struct snd_monitor_file *mfile;
-	int err;
 
 	if (!card)
 		return -EINVAL;
@@ -445,9 +444,7 @@ int snd_card_disconnect(struct snd_card *card)
 #endif
 
 	/* notify all devices that we are disconnected */
-	err = snd_device_disconnect_all(card);
-	if (err < 0)
-		dev_err(card->dev, "not all devices for card %i can be disconnected\n", card->number);
+	snd_device_disconnect_all(card);
 
 	snd_info_card_disconnect(card);
 	if (card->registered) {

+ 1 - 3
sound/core/oss/mixer_oss.c

@@ -1212,10 +1212,8 @@ static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
 			/* not changed */
 			goto __unlock;
 		tbl = kmalloc(sizeof(*tbl), GFP_KERNEL);
-		if (! tbl) {
-			pr_err("ALSA: mixer_oss: no memory\n");
+		if (!tbl)
 			goto __unlock;
-		}
 		tbl->oss_id = ch;
 		tbl->name = kstrdup(str, GFP_KERNEL);
 		if (! tbl->name) {

+ 0 - 1
sound/core/oss/pcm_oss.c

@@ -854,7 +854,6 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
 	params = kmalloc(sizeof(*params), GFP_KERNEL);
 	sparams = kmalloc(sizeof(*sparams), GFP_KERNEL);
 	if (!sw_params || !params || !sparams) {
-		pcm_dbg(substream->pcm, "No memory\n");
 		err = -ENOMEM;
 		goto failure;
 	}

+ 44 - 61
sound/core/pcm.c

@@ -49,8 +49,6 @@ static struct snd_pcm *snd_pcm_get(struct snd_card *card, int device)
 	struct snd_pcm *pcm;
 
 	list_for_each_entry(pcm, &snd_pcm_devices, list) {
-		if (pcm->internal)
-			continue;
 		if (pcm->card == card && pcm->device == device)
 			return pcm;
 	}
@@ -62,8 +60,6 @@ static int snd_pcm_next(struct snd_card *card, int device)
 	struct snd_pcm *pcm;
 
 	list_for_each_entry(pcm, &snd_pcm_devices, list) {
-		if (pcm->internal)
-			continue;
 		if (pcm->card == card && pcm->device > device)
 			return pcm->device;
 		else if (pcm->card->number > card->number)
@@ -76,6 +72,9 @@ static int snd_pcm_add(struct snd_pcm *newpcm)
 {
 	struct snd_pcm *pcm;
 
+	if (newpcm->internal)
+		return 0;
+
 	list_for_each_entry(pcm, &snd_pcm_devices, list) {
 		if (pcm->card == newpcm->card && pcm->device == newpcm->device)
 			return -EBUSY;
@@ -344,11 +343,8 @@ static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream,
 		return;
 
 	info = kmalloc(sizeof(*info), GFP_KERNEL);
-	if (! info) {
-		pcm_dbg(substream->pcm,
-			"snd_pcm_proc_info_read: cannot malloc\n");
+	if (!info)
 		return;
-	}
 
 	err = snd_pcm_info(substream, info);
 	if (err < 0) {
@@ -718,10 +714,8 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
 	prev = NULL;
 	for (idx = 0, prev = NULL; idx < substream_count; idx++) {
 		substream = kzalloc(sizeof(*substream), GFP_KERNEL);
-		if (substream == NULL) {
-			pcm_err(pcm, "Cannot allocate PCM substream\n");
+		if (!substream)
 			return -ENOMEM;
-		}
 		substream->pcm = pcm;
 		substream->pstr = pstr;
 		substream->number = idx;
@@ -775,13 +769,14 @@ static int _snd_pcm_new(struct snd_card *card, const char *id, int device,
 	if (rpcm)
 		*rpcm = NULL;
 	pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
-	if (pcm == NULL) {
-		dev_err(card->dev, "Cannot allocate PCM\n");
+	if (!pcm)
 		return -ENOMEM;
-	}
 	pcm->card = card;
 	pcm->device = device;
 	pcm->internal = internal;
+	mutex_init(&pcm->open_mutex);
+	init_waitqueue_head(&pcm->open_wait);
+	INIT_LIST_HEAD(&pcm->list);
 	if (id)
 		strlcpy(pcm->id, id, sizeof(pcm->id));
 	if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count)) < 0) {
@@ -792,8 +787,6 @@ static int _snd_pcm_new(struct snd_card *card, const char *id, int device,
 		snd_pcm_free(pcm);
 		return err;
 	}
-	mutex_init(&pcm->open_mutex);
-	init_waitqueue_head(&pcm->open_wait);
 	if ((err = snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops)) < 0) {
 		snd_pcm_free(pcm);
 		return err;
@@ -888,8 +881,9 @@ static int snd_pcm_free(struct snd_pcm *pcm)
 
 	if (!pcm)
 		return 0;
-	list_for_each_entry(notify, &snd_pcm_notify_list, list) {
-		notify->n_unregister(pcm);
+	if (!pcm->internal) {
+		list_for_each_entry(notify, &snd_pcm_notify_list, list)
+			notify->n_unregister(pcm);
 	}
 	if (pcm->private_free)
 		pcm->private_free(pcm);
@@ -919,6 +913,9 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
 
 	if (snd_BUG_ON(!pcm || !rsubstream))
 		return -ENXIO;
+	if (snd_BUG_ON(stream != SNDRV_PCM_STREAM_PLAYBACK &&
+		       stream != SNDRV_PCM_STREAM_CAPTURE))
+		return -EINVAL;
 	*rsubstream = NULL;
 	pstr = &pcm->streams[stream];
 	if (pstr->substream == NULL || pstr->substream_count == 0)
@@ -927,25 +924,14 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
 	card = pcm->card;
 	prefer_subdevice = snd_ctl_get_preferred_subdevice(card, SND_CTL_SUBDEV_PCM);
 
-	switch (stream) {
-	case SNDRV_PCM_STREAM_PLAYBACK:
-		if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) {
-			for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next) {
-				if (SUBSTREAM_BUSY(substream))
-					return -EAGAIN;
-			}
-		}
-		break;
-	case SNDRV_PCM_STREAM_CAPTURE:
-		if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) {
-			for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) {
-				if (SUBSTREAM_BUSY(substream))
-					return -EAGAIN;
-			}
+	if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) {
+		int opposite = !stream;
+
+		for (substream = pcm->streams[opposite].substream; substream;
+		     substream = substream->next) {
+			if (SUBSTREAM_BUSY(substream))
+				return -EAGAIN;
 		}
-		break;
-	default:
-		return -EINVAL;
 	}
 
 	if (file->f_flags & O_APPEND) {
@@ -968,15 +954,12 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
 		return 0;
 	}
 
-	if (prefer_subdevice >= 0) {
-		for (substream = pstr->substream; substream; substream = substream->next)
-			if (!SUBSTREAM_BUSY(substream) && substream->number == prefer_subdevice)
-				goto __ok;
-	}
-	for (substream = pstr->substream; substream; substream = substream->next)
-		if (!SUBSTREAM_BUSY(substream))
+	for (substream = pstr->substream; substream; substream = substream->next) {
+		if (!SUBSTREAM_BUSY(substream) &&
+		    (prefer_subdevice == -1 ||
+		     substream->number == prefer_subdevice))
 			break;
-      __ok:
+	}
 	if (substream == NULL)
 		return -EAGAIN;
 
@@ -1086,15 +1069,16 @@ static int snd_pcm_dev_register(struct snd_device *device)
 	if (snd_BUG_ON(!device || !device->device_data))
 		return -ENXIO;
 	pcm = device->device_data;
+	if (pcm->internal)
+		return 0;
+
 	mutex_lock(&register_mutex);
 	err = snd_pcm_add(pcm);
-	if (err) {
-		mutex_unlock(&register_mutex);
-		return err;
-	}
+	if (err)
+		goto unlock;
 	for (cidx = 0; cidx < 2; cidx++) {
 		int devtype = -1;
-		if (pcm->streams[cidx].substream == NULL || pcm->internal)
+		if (pcm->streams[cidx].substream == NULL)
 			continue;
 		switch (cidx) {
 		case SNDRV_PCM_STREAM_PLAYBACK:
@@ -1109,9 +1093,8 @@ static int snd_pcm_dev_register(struct snd_device *device)
 					  &snd_pcm_f_ops[cidx], pcm,
 					  &pcm->streams[cidx].dev);
 		if (err < 0) {
-			list_del(&pcm->list);
-			mutex_unlock(&register_mutex);
-			return err;
+			list_del_init(&pcm->list);
+			goto unlock;
 		}
 
 		for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
@@ -1121,8 +1104,9 @@ static int snd_pcm_dev_register(struct snd_device *device)
 	list_for_each_entry(notify, &snd_pcm_notify_list, list)
 		notify->n_register(pcm);
 
+ unlock:
 	mutex_unlock(&register_mutex);
-	return 0;
+	return err;
 }
 
 static int snd_pcm_dev_disconnect(struct snd_device *device)
@@ -1133,13 +1117,10 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
 	int cidx;
 
 	mutex_lock(&register_mutex);
-	if (list_empty(&pcm->list))
-		goto unlock;
-
 	mutex_lock(&pcm->open_mutex);
 	wake_up(&pcm->open_wait);
 	list_del_init(&pcm->list);
-	for (cidx = 0; cidx < 2; cidx++)
+	for (cidx = 0; cidx < 2; cidx++) {
 		for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) {
 			snd_pcm_stream_lock_irq(substream);
 			if (substream->runtime) {
@@ -1149,18 +1130,20 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
 			}
 			snd_pcm_stream_unlock_irq(substream);
 		}
-	list_for_each_entry(notify, &snd_pcm_notify_list, list) {
-		notify->n_disconnect(pcm);
+	}
+	if (!pcm->internal) {
+		list_for_each_entry(notify, &snd_pcm_notify_list, list)
+			notify->n_disconnect(pcm);
 	}
 	for (cidx = 0; cidx < 2; cidx++) {
-		snd_unregister_device(&pcm->streams[cidx].dev);
+		if (!pcm->internal)
+			snd_unregister_device(&pcm->streams[cidx].dev);
 		if (pcm->streams[cidx].chmap_kctl) {
 			snd_ctl_remove(pcm->card, pcm->streams[cidx].chmap_kctl);
 			pcm->streams[cidx].chmap_kctl = NULL;
 		}
 	}
 	mutex_unlock(&pcm->open_mutex);
- unlock:
 	mutex_unlock(&register_mutex);
 	return 0;
 }

+ 23 - 5
sound/core/pcm_compat.c

@@ -194,18 +194,30 @@ struct snd_pcm_status32 {
 	u32 avail_max;
 	u32 overrange;
 	s32 suspended_state;
-	u32 reserved_alignment;
+	u32 audio_tstamp_data;
 	struct compat_timespec audio_tstamp;
-	unsigned char reserved[56-sizeof(struct compat_timespec)];
+	struct compat_timespec driver_tstamp;
+	u32 audio_tstamp_accuracy;
+	unsigned char reserved[52-2*sizeof(struct compat_timespec)];
 } __attribute__((packed));
 
 
 static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream,
-				      struct snd_pcm_status32 __user *src)
+				      struct snd_pcm_status32 __user *src,
+				      bool ext)
 {
 	struct snd_pcm_status status;
 	int err;
 
+	memset(&status, 0, sizeof(status));
+	/*
+	 * with extension, parameters are read/write,
+	 * get audio_tstamp_data from user,
+	 * ignore rest of status structure
+	 */
+	if (ext && get_user(status.audio_tstamp_data,
+				(u32 __user *)(&src->audio_tstamp_data)))
+		return -EFAULT;
 	err = snd_pcm_status(substream, &status);
 	if (err < 0)
 		return err;
@@ -222,7 +234,10 @@ static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream,
 	    put_user(status.avail_max, &src->avail_max) ||
 	    put_user(status.overrange, &src->overrange) ||
 	    put_user(status.suspended_state, &src->suspended_state) ||
-	    compat_put_timespec(&status.audio_tstamp, &src->audio_tstamp))
+	    put_user(status.audio_tstamp_data, &src->audio_tstamp_data) ||
+	    compat_put_timespec(&status.audio_tstamp, &src->audio_tstamp) ||
+	    compat_put_timespec(&status.driver_tstamp, &src->driver_tstamp) ||
+	    put_user(status.audio_tstamp_accuracy, &src->audio_tstamp_accuracy))
 		return -EFAULT;
 
 	return err;
@@ -457,6 +472,7 @@ enum {
 	SNDRV_PCM_IOCTL_HW_PARAMS32 = _IOWR('A', 0x11, struct snd_pcm_hw_params32),
 	SNDRV_PCM_IOCTL_SW_PARAMS32 = _IOWR('A', 0x13, struct snd_pcm_sw_params32),
 	SNDRV_PCM_IOCTL_STATUS32 = _IOR('A', 0x20, struct snd_pcm_status32),
+	SNDRV_PCM_IOCTL_STATUS_EXT32 = _IOWR('A', 0x24, struct snd_pcm_status32),
 	SNDRV_PCM_IOCTL_DELAY32 = _IOR('A', 0x21, s32),
 	SNDRV_PCM_IOCTL_CHANNEL_INFO32 = _IOR('A', 0x32, struct snd_pcm_channel_info32),
 	SNDRV_PCM_IOCTL_REWIND32 = _IOW('A', 0x46, u32),
@@ -517,7 +533,9 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
 	case SNDRV_PCM_IOCTL_SW_PARAMS32:
 		return snd_pcm_ioctl_sw_params_compat(substream, argp);
 	case SNDRV_PCM_IOCTL_STATUS32:
-		return snd_pcm_status_user_compat(substream, argp);
+		return snd_pcm_status_user_compat(substream, argp, false);
+	case SNDRV_PCM_IOCTL_STATUS_EXT32:
+		return snd_pcm_status_user_compat(substream, argp, true);
 	case SNDRV_PCM_IOCTL_SYNC_PTR32:
 		return snd_pcm_ioctl_sync_ptr_compat(substream, argp);
 	case SNDRV_PCM_IOCTL_CHANNEL_INFO32:

+ 2 - 2
sound/core/pcm_dmaengine.c

@@ -289,7 +289,7 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_request_channel);
  *
  * The function should usually be called from the pcm open callback. Note that
  * this function will use private_data field of the substream's runtime. So it
- * is not availabe to your pcm driver implementation.
+ * is not available to your pcm driver implementation.
  */
 int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
 	struct dma_chan *chan)
@@ -328,7 +328,7 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open);
  * This function will request a DMA channel using the passed filter function and
  * data. The function should usually be called from the pcm open callback. Note
  * that this function will use private_data field of the substream's runtime. So
- * it is not availabe to your pcm driver implementation.
+ * it is not available to your pcm driver implementation.
  */
 int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream,
 	dma_filter_fn filter_fn, void *filter_data)

+ 59 - 29
sound/core/pcm_lib.c

@@ -232,6 +232,49 @@ int snd_pcm_update_state(struct snd_pcm_substream *substream,
 	return 0;
 }
 
+static void update_audio_tstamp(struct snd_pcm_substream *substream,
+				struct timespec *curr_tstamp,
+				struct timespec *audio_tstamp)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	u64 audio_frames, audio_nsecs;
+	struct timespec driver_tstamp;
+
+	if (runtime->tstamp_mode != SNDRV_PCM_TSTAMP_ENABLE)
+		return;
+
+	if (!(substream->ops->get_time_info) ||
+		(runtime->audio_tstamp_report.actual_type ==
+			SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT)) {
+
+		/*
+		 * provide audio timestamp derived from pointer position
+		 * add delay only if requested
+		 */
+
+		audio_frames = runtime->hw_ptr_wrap + runtime->status->hw_ptr;
+
+		if (runtime->audio_tstamp_config.report_delay) {
+			if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+				audio_frames -=  runtime->delay;
+			else
+				audio_frames +=  runtime->delay;
+		}
+		audio_nsecs = div_u64(audio_frames * 1000000000LL,
+				runtime->rate);
+		*audio_tstamp = ns_to_timespec(audio_nsecs);
+	}
+	runtime->status->audio_tstamp = *audio_tstamp;
+	runtime->status->tstamp = *curr_tstamp;
+
+	/*
+	 * re-take a driver timestamp to let apps detect if the reference tstamp
+	 * read by low-level hardware was provided with a delay
+	 */
+	snd_pcm_gettime(substream->runtime, (struct timespec *)&driver_tstamp);
+	runtime->driver_tstamp = driver_tstamp;
+}
+
 static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
 				  unsigned int in_interrupt)
 {
@@ -256,11 +299,18 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
 	pos = substream->ops->pointer(substream);
 	curr_jiffies = jiffies;
 	if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
-		snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp);
-
-		if ((runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK) &&
-			(substream->ops->wall_clock))
-			substream->ops->wall_clock(substream, &audio_tstamp);
+		if ((substream->ops->get_time_info) &&
+			(runtime->audio_tstamp_config.type_requested != SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT)) {
+			substream->ops->get_time_info(substream, &curr_tstamp,
+						&audio_tstamp,
+						&runtime->audio_tstamp_config,
+						&runtime->audio_tstamp_report);
+
+			/* re-test in case tstamp type is not supported in hardware and was demoted to DEFAULT */
+			if (runtime->audio_tstamp_report.actual_type == SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT)
+				snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp);
+		} else
+			snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp);
 	}
 
 	if (pos == SNDRV_PCM_POS_XRUN) {
@@ -403,8 +453,10 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
 	}
 
  no_delta_check:
-	if (runtime->status->hw_ptr == new_hw_ptr)
+	if (runtime->status->hw_ptr == new_hw_ptr) {
+		update_audio_tstamp(substream, &curr_tstamp, &audio_tstamp);
 		return 0;
+	}
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
 	    runtime->silence_size > 0)
@@ -426,30 +478,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
 		snd_BUG_ON(crossed_boundary != 1);
 		runtime->hw_ptr_wrap += runtime->boundary;
 	}
-	if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
-		runtime->status->tstamp = curr_tstamp;
 
-		if (!(runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK)) {
-			/*
-			 * no wall clock available, provide audio timestamp
-			 * derived from pointer position+delay
-			 */
-			u64 audio_frames, audio_nsecs;
-
-			if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-				audio_frames = runtime->hw_ptr_wrap
-					+ runtime->status->hw_ptr
-					- runtime->delay;
-			else
-				audio_frames = runtime->hw_ptr_wrap
-					+ runtime->status->hw_ptr
-					+ runtime->delay;
-			audio_nsecs = div_u64(audio_frames * 1000000000LL,
-					runtime->rate);
-			audio_tstamp = ns_to_timespec(audio_nsecs);
-		}
-		runtime->status->audio_tstamp = audio_tstamp;
-	}
+	update_audio_tstamp(substream, &curr_tstamp, &audio_tstamp);
 
 	return snd_pcm_update_state(substream, runtime);
 }

+ 38 - 3
sound/core/pcm_native.c

@@ -707,6 +707,23 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
 	struct snd_pcm_runtime *runtime = substream->runtime;
 
 	snd_pcm_stream_lock_irq(substream);
+
+	snd_pcm_unpack_audio_tstamp_config(status->audio_tstamp_data,
+					&runtime->audio_tstamp_config);
+
+	/* backwards compatible behavior */
+	if (runtime->audio_tstamp_config.type_requested ==
+		SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT) {
+		if (runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK)
+			runtime->audio_tstamp_config.type_requested =
+				SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK;
+		else
+			runtime->audio_tstamp_config.type_requested =
+				SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT;
+		runtime->audio_tstamp_report.valid = 0;
+	} else
+		runtime->audio_tstamp_report.valid = 1;
+
 	status->state = runtime->status->state;
 	status->suspended_state = runtime->status->suspended_state;
 	if (status->state == SNDRV_PCM_STATE_OPEN)
@@ -716,8 +733,15 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
 		snd_pcm_update_hw_ptr(substream);
 		if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
 			status->tstamp = runtime->status->tstamp;
+			status->driver_tstamp = runtime->driver_tstamp;
 			status->audio_tstamp =
 				runtime->status->audio_tstamp;
+			if (runtime->audio_tstamp_report.valid == 1)
+				/* backwards compatibility, no report provided in COMPAT mode */
+				snd_pcm_pack_audio_tstamp_report(&status->audio_tstamp_data,
+								&status->audio_tstamp_accuracy,
+								&runtime->audio_tstamp_report);
+
 			goto _tstamp_end;
 		}
 	} else {
@@ -753,12 +777,21 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
 }
 
 static int snd_pcm_status_user(struct snd_pcm_substream *substream,
-			       struct snd_pcm_status __user * _status)
+			       struct snd_pcm_status __user * _status,
+			       bool ext)
 {
 	struct snd_pcm_status status;
 	int res;
-	
+
 	memset(&status, 0, sizeof(status));
+	/*
+	 * with extension, parameters are read/write,
+	 * get audio_tstamp_data from user,
+	 * ignore rest of status structure
+	 */
+	if (ext && get_user(status.audio_tstamp_data,
+				(u32 __user *)(&_status->audio_tstamp_data)))
+		return -EFAULT;
 	res = snd_pcm_status(substream, &status);
 	if (res < 0)
 		return res;
@@ -2725,7 +2758,9 @@ static int snd_pcm_common_ioctl1(struct file *file,
 	case SNDRV_PCM_IOCTL_SW_PARAMS:
 		return snd_pcm_sw_params_user(substream, arg);
 	case SNDRV_PCM_IOCTL_STATUS:
-		return snd_pcm_status_user(substream, arg);
+		return snd_pcm_status_user(substream, arg, false);
+	case SNDRV_PCM_IOCTL_STATUS_EXT:
+		return snd_pcm_status_user(substream, arg, true);
 	case SNDRV_PCM_IOCTL_CHANNEL_INFO:
 		return snd_pcm_channel_info_user(substream, arg);
 	case SNDRV_PCM_IOCTL_PREPARE:

+ 2 - 6
sound/core/rawmidi.c

@@ -1429,10 +1429,8 @@ static int snd_rawmidi_alloc_substreams(struct snd_rawmidi *rmidi,
 
 	for (idx = 0; idx < count; idx++) {
 		substream = kzalloc(sizeof(*substream), GFP_KERNEL);
-		if (substream == NULL) {
-			rmidi_err(rmidi, "rawmidi: cannot allocate substream\n");
+		if (!substream)
 			return -ENOMEM;
-		}
 		substream->stream = direction;
 		substream->number = idx;
 		substream->rmidi = rmidi;
@@ -1479,10 +1477,8 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device,
 	if (rrawmidi)
 		*rrawmidi = NULL;
 	rmidi = kzalloc(sizeof(*rmidi), GFP_KERNEL);
-	if (rmidi == NULL) {
-		dev_err(card->dev, "rawmidi: cannot allocate\n");
+	if (!rmidi)
 		return -ENOMEM;
-	}
 	rmidi->card = card;
 	rmidi->device = device;
 	mutex_init(&rmidi->open_mutex);

+ 13 - 9
sound/core/seq/oss/seq_oss.c

@@ -65,15 +65,20 @@ static unsigned int odev_poll(struct file *file, poll_table * wait);
  * module interface
  */
 
+static struct snd_seq_driver seq_oss_synth_driver = {
+	.driver = {
+		.name = KBUILD_MODNAME,
+		.probe = snd_seq_oss_synth_probe,
+		.remove = snd_seq_oss_synth_remove,
+	},
+	.id = SNDRV_SEQ_DEV_ID_OSS,
+	.argsize = sizeof(struct snd_seq_oss_reg),
+};
+
 static int __init alsa_seq_oss_init(void)
 {
 	int rc;
-	static struct snd_seq_dev_ops ops = {
-		snd_seq_oss_synth_register,
-		snd_seq_oss_synth_unregister,
-	};
 
-	snd_seq_autoload_lock();
 	if ((rc = register_device()) < 0)
 		goto error;
 	if ((rc = register_proc()) < 0) {
@@ -86,8 +91,8 @@ static int __init alsa_seq_oss_init(void)
 		goto error;
 	}
 
-	if ((rc = snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_OSS, &ops,
-						 sizeof(struct snd_seq_oss_reg))) < 0) {
+	rc = snd_seq_driver_register(&seq_oss_synth_driver);
+	if (rc < 0) {
 		snd_seq_oss_delete_client();
 		unregister_proc();
 		unregister_device();
@@ -98,13 +103,12 @@ static int __init alsa_seq_oss_init(void)
 	snd_seq_oss_synth_init();
 
  error:
-	snd_seq_autoload_unlock();
 	return rc;
 }
 
 static void __exit alsa_seq_oss_exit(void)
 {
-	snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_OSS);
+	snd_seq_driver_unregister(&seq_oss_synth_driver);
 	snd_seq_oss_delete_client();
 	unregister_proc();
 	unregister_device();

+ 1 - 3
sound/core/seq/oss/seq_oss_init.c

@@ -188,10 +188,8 @@ snd_seq_oss_open(struct file *file, int level)
 	struct seq_oss_devinfo *dp;
 
 	dp = kzalloc(sizeof(*dp), GFP_KERNEL);
-	if (!dp) {
-		pr_err("ALSA: seq_oss: can't malloc device info\n");
+	if (!dp)
 		return -ENOMEM;
-	}
 
 	dp->cseq = system_client;
 	dp->port = -1;

+ 2 - 3
sound/core/seq/oss/seq_oss_midi.c

@@ -173,10 +173,9 @@ snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo)
 	/*
 	 * allocate midi info record
 	 */
-	if ((mdev = kzalloc(sizeof(*mdev), GFP_KERNEL)) == NULL) {
-		pr_err("ALSA: seq_oss: can't malloc midi info\n");
+	mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
+	if (!mdev)
 		return -ENOMEM;
-	}
 
 	/* copy the port information */
 	mdev->client = pinfo->addr.client;

+ 4 - 5
sound/core/seq/oss/seq_oss_readq.c

@@ -47,13 +47,12 @@ snd_seq_oss_readq_new(struct seq_oss_devinfo *dp, int maxlen)
 {
 	struct seq_oss_readq *q;
 
-	if ((q = kzalloc(sizeof(*q), GFP_KERNEL)) == NULL) {
-		pr_err("ALSA: seq_oss: can't malloc read queue\n");
+	q = kzalloc(sizeof(*q), GFP_KERNEL);
+	if (!q)
 		return NULL;
-	}
 
-	if ((q->q = kcalloc(maxlen, sizeof(union evrec), GFP_KERNEL)) == NULL) {
-		pr_err("ALSA: seq_oss: can't malloc read queue buffer\n");
+	q->q = kcalloc(maxlen, sizeof(union evrec), GFP_KERNEL);
+	if (!q->q) {
 		kfree(q);
 		return NULL;
 	}

+ 6 - 6
sound/core/seq/oss/seq_oss_synth.c

@@ -98,17 +98,17 @@ snd_seq_oss_synth_init(void)
  * registration of the synth device
  */
 int
-snd_seq_oss_synth_register(struct snd_seq_device *dev)
+snd_seq_oss_synth_probe(struct device *_dev)
 {
+	struct snd_seq_device *dev = to_seq_dev(_dev);
 	int i;
 	struct seq_oss_synth *rec;
 	struct snd_seq_oss_reg *reg = SNDRV_SEQ_DEVICE_ARGPTR(dev);
 	unsigned long flags;
 
-	if ((rec = kzalloc(sizeof(*rec), GFP_KERNEL)) == NULL) {
-		pr_err("ALSA: seq_oss: can't malloc synth info\n");
+	rec = kzalloc(sizeof(*rec), GFP_KERNEL);
+	if (!rec)
 		return -ENOMEM;
-	}
 	rec->seq_device = -1;
 	rec->synth_type = reg->type;
 	rec->synth_subtype = reg->subtype;
@@ -149,8 +149,9 @@ snd_seq_oss_synth_register(struct snd_seq_device *dev)
 
 
 int
-snd_seq_oss_synth_unregister(struct snd_seq_device *dev)
+snd_seq_oss_synth_remove(struct device *_dev)
 {
+	struct snd_seq_device *dev = to_seq_dev(_dev);
 	int index;
 	struct seq_oss_synth *rec = dev->driver_data;
 	unsigned long flags;
@@ -247,7 +248,6 @@ snd_seq_oss_synth_setup(struct seq_oss_devinfo *dp)
 		if (info->nr_voices > 0) {
 			info->ch = kcalloc(info->nr_voices, sizeof(struct seq_oss_chinfo), GFP_KERNEL);
 			if (!info->ch) {
-				pr_err("ALSA: seq_oss: Cannot malloc voices\n");
 				rec->oper.close(&info->arg);
 				module_put(rec->oper.owner);
 				snd_use_lock_free(&rec->use_lock);

+ 2 - 2
sound/core/seq/oss/seq_oss_synth.h

@@ -28,8 +28,8 @@
 #include <sound/seq_device.h>
 
 void snd_seq_oss_synth_init(void);
-int snd_seq_oss_synth_register(struct snd_seq_device *dev);
-int snd_seq_oss_synth_unregister(struct snd_seq_device *dev);
+int snd_seq_oss_synth_probe(struct device *dev);
+int snd_seq_oss_synth_remove(struct device *dev);
 void snd_seq_oss_synth_setup(struct seq_oss_devinfo *dp);
 void snd_seq_oss_synth_setup_midi(struct seq_oss_devinfo *dp);
 void snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp);

+ 1 - 0
sound/core/seq/seq_clientmgr.c

@@ -1879,6 +1879,7 @@ static int snd_seq_ioctl_get_client_pool(struct snd_seq_client *client,
 	if (cptr == NULL)
 		return -ENOENT;
 	memset(&info, 0, sizeof(info));
+	info.client = cptr->number;
 	info.output_pool = cptr->pool->size;
 	info.output_room = cptr->pool->room;
 	info.output_free = info.output_pool;

+ 135 - 436
sound/core/seq/seq_device.c

@@ -36,6 +36,7 @@
  *
  */
 
+#include <linux/device.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <sound/core.h>
@@ -51,140 +52,78 @@ MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
 MODULE_DESCRIPTION("ALSA sequencer device management");
 MODULE_LICENSE("GPL");
 
-/* driver state */
-#define DRIVER_EMPTY		0
-#define DRIVER_LOADED		(1<<0)
-#define DRIVER_REQUESTED	(1<<1)
-#define DRIVER_LOCKED		(1<<2)
-#define DRIVER_REQUESTING	(1<<3)
-
-struct ops_list {
-	char id[ID_LEN];	/* driver id */
-	int driver;		/* driver state */
-	int used;		/* reference counter */
-	int argsize;		/* argument size */
-
-	/* operators */
-	struct snd_seq_dev_ops ops;
-
-	/* registered devices */
-	struct list_head dev_list;	/* list of devices */
-	int num_devices;	/* number of associated devices */
-	int num_init_devices;	/* number of initialized devices */
-	struct mutex reg_mutex;
-
-	struct list_head list;	/* next driver */
-};
+/*
+ * bus definition
+ */
+static int snd_seq_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct snd_seq_device *sdev = to_seq_dev(dev);
+	struct snd_seq_driver *sdrv = to_seq_drv(drv);
 
+	return strcmp(sdrv->id, sdev->id) == 0 &&
+		sdrv->argsize == sdev->argsize;
+}
 
-static LIST_HEAD(opslist);
-static int num_ops;
-static DEFINE_MUTEX(ops_mutex);
-#ifdef CONFIG_PROC_FS
-static struct snd_info_entry *info_entry;
-#endif
+static struct bus_type snd_seq_bus_type = {
+	.name = "snd_seq",
+	.match = snd_seq_bus_match,
+};
 
 /*
- * prototypes
+ * proc interface -- just for compatibility
  */
-static int snd_seq_device_free(struct snd_seq_device *dev);
-static int snd_seq_device_dev_free(struct snd_device *device);
-static int snd_seq_device_dev_register(struct snd_device *device);
-static int snd_seq_device_dev_disconnect(struct snd_device *device);
-
-static int init_device(struct snd_seq_device *dev, struct ops_list *ops);
-static int free_device(struct snd_seq_device *dev, struct ops_list *ops);
-static struct ops_list *find_driver(char *id, int create_if_empty);
-static struct ops_list *create_driver(char *id);
-static void unlock_driver(struct ops_list *ops);
-static void remove_drivers(void);
+#ifdef CONFIG_PROC_FS
+static struct snd_info_entry *info_entry;
 
-/*
- * show all drivers and their status
- */
+static int print_dev_info(struct device *dev, void *data)
+{
+	struct snd_seq_device *sdev = to_seq_dev(dev);
+	struct snd_info_buffer *buffer = data;
+
+	snd_iprintf(buffer, "snd-%s,%s,%d\n", sdev->id,
+		    dev->driver ? "loaded" : "empty",
+		    dev->driver ? 1 : 0);
+	return 0;
+}
 
-#ifdef CONFIG_PROC_FS
 static void snd_seq_device_info(struct snd_info_entry *entry,
 				struct snd_info_buffer *buffer)
 {
-	struct ops_list *ops;
-
-	mutex_lock(&ops_mutex);
-	list_for_each_entry(ops, &opslist, list) {
-		snd_iprintf(buffer, "snd-%s%s%s%s,%d\n",
-				ops->id,
-				ops->driver & DRIVER_LOADED ? ",loaded" : (ops->driver == DRIVER_EMPTY ? ",empty" : ""),
-				ops->driver & DRIVER_REQUESTED ? ",requested" : "",
-				ops->driver & DRIVER_LOCKED ? ",locked" : "",
-				ops->num_devices);
-	}
-	mutex_unlock(&ops_mutex);
+	bus_for_each_dev(&snd_seq_bus_type, NULL, buffer, print_dev_info);
 }
 #endif
- 
+
 /*
  * load all registered drivers (called from seq_clientmgr.c)
  */
 
 #ifdef CONFIG_MODULES
-/* avoid auto-loading during module_init() */
+/* flag to block auto-loading */
 static atomic_t snd_seq_in_init = ATOMIC_INIT(1); /* blocked as default */
-void snd_seq_autoload_lock(void)
-{
-	atomic_inc(&snd_seq_in_init);
-}
 
-void snd_seq_autoload_unlock(void)
+static int request_seq_drv(struct device *dev, void *data)
 {
-	atomic_dec(&snd_seq_in_init);
+	struct snd_seq_device *sdev = to_seq_dev(dev);
+
+	if (!dev->driver)
+		request_module("snd-%s", sdev->id);
+	return 0;
 }
 
-static void autoload_drivers(void)
+static void autoload_drivers(struct work_struct *work)
 {
 	/* avoid reentrance */
-	if (atomic_inc_return(&snd_seq_in_init) == 1) {
-		struct ops_list *ops;
-
-		mutex_lock(&ops_mutex);
-		list_for_each_entry(ops, &opslist, list) {
-			if ((ops->driver & DRIVER_REQUESTING) &&
-			    !(ops->driver & DRIVER_REQUESTED)) {
-				ops->used++;
-				mutex_unlock(&ops_mutex);
-				ops->driver |= DRIVER_REQUESTED;
-				request_module("snd-%s", ops->id);
-				mutex_lock(&ops_mutex);
-				ops->used--;
-			}
-		}
-		mutex_unlock(&ops_mutex);
-	}
+	if (atomic_inc_return(&snd_seq_in_init) == 1)
+		bus_for_each_dev(&snd_seq_bus_type, NULL, NULL,
+				 request_seq_drv);
 	atomic_dec(&snd_seq_in_init);
 }
 
-static void call_autoload(struct work_struct *work)
-{
-	autoload_drivers();
-}
-
-static DECLARE_WORK(autoload_work, call_autoload);
-
-static void try_autoload(struct ops_list *ops)
-{
-	if (!ops->driver) {
-		ops->driver |= DRIVER_REQUESTING;
-		schedule_work(&autoload_work);
-	}
-}
+static DECLARE_WORK(autoload_work, autoload_drivers);
 
 static void queue_autoload_drivers(void)
 {
-	struct ops_list *ops;
-
-	mutex_lock(&ops_mutex);
-	list_for_each_entry(ops, &opslist, list)
-		try_autoload(ops);
-	mutex_unlock(&ops_mutex);
+	schedule_work(&autoload_work);
 }
 
 void snd_seq_autoload_init(void)
@@ -195,384 +134,143 @@ void snd_seq_autoload_init(void)
 	queue_autoload_drivers();
 #endif
 }
-#else
-#define try_autoload(ops) /* NOP */
-#endif
+EXPORT_SYMBOL(snd_seq_autoload_init);
 
-void snd_seq_device_load_drivers(void)
+void snd_seq_autoload_exit(void)
 {
-#ifdef CONFIG_MODULES
-	queue_autoload_drivers();
-	flush_work(&autoload_work);
-#endif
+	atomic_inc(&snd_seq_in_init);
 }
+EXPORT_SYMBOL(snd_seq_autoload_exit);
 
-/*
- * register a sequencer device
- * card = card info
- * device = device number (if any)
- * id = id of driver
- * result = return pointer (NULL allowed if unnecessary)
- */
-int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize,
-		       struct snd_seq_device **result)
+void snd_seq_device_load_drivers(void)
 {
-	struct snd_seq_device *dev;
-	struct ops_list *ops;
-	int err;
-	static struct snd_device_ops dops = {
-		.dev_free = snd_seq_device_dev_free,
-		.dev_register = snd_seq_device_dev_register,
-		.dev_disconnect = snd_seq_device_dev_disconnect,
-	};
-
-	if (result)
-		*result = NULL;
-
-	if (snd_BUG_ON(!id))
-		return -EINVAL;
-
-	ops = find_driver(id, 1);
-	if (ops == NULL)
-		return -ENOMEM;
-
-	dev = kzalloc(sizeof(*dev)*2 + argsize, GFP_KERNEL);
-	if (dev == NULL) {
-		unlock_driver(ops);
-		return -ENOMEM;
-	}
-
-	/* set up device info */
-	dev->card = card;
-	dev->device = device;
-	strlcpy(dev->id, id, sizeof(dev->id));
-	dev->argsize = argsize;
-	dev->status = SNDRV_SEQ_DEVICE_FREE;
-
-	/* add this device to the list */
-	mutex_lock(&ops->reg_mutex);
-	list_add_tail(&dev->list, &ops->dev_list);
-	ops->num_devices++;
-	mutex_unlock(&ops->reg_mutex);
-
-	if ((err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops)) < 0) {
-		snd_seq_device_free(dev);
-		return err;
-	}
-	
-	try_autoload(ops);
-	unlock_driver(ops);
-
-	if (result)
-		*result = dev;
-
-	return 0;
+	queue_autoload_drivers();
+	flush_work(&autoload_work);
 }
+EXPORT_SYMBOL(snd_seq_device_load_drivers);
+#else
+#define queue_autoload_drivers() /* NOP */
+#endif
 
 /*
- * free the existing device
+ * device management
  */
-static int snd_seq_device_free(struct snd_seq_device *dev)
-{
-	struct ops_list *ops;
-
-	if (snd_BUG_ON(!dev))
-		return -EINVAL;
-
-	ops = find_driver(dev->id, 0);
-	if (ops == NULL)
-		return -ENXIO;
-
-	/* remove the device from the list */
-	mutex_lock(&ops->reg_mutex);
-	list_del(&dev->list);
-	ops->num_devices--;
-	mutex_unlock(&ops->reg_mutex);
-
-	free_device(dev, ops);
-	if (dev->private_free)
-		dev->private_free(dev);
-	kfree(dev);
-
-	unlock_driver(ops);
-
-	return 0;
-}
-
 static int snd_seq_device_dev_free(struct snd_device *device)
 {
 	struct snd_seq_device *dev = device->device_data;
-	return snd_seq_device_free(dev);
+
+	put_device(&dev->dev);
+	return 0;
 }
 
-/*
- * register the device
- */
 static int snd_seq_device_dev_register(struct snd_device *device)
 {
 	struct snd_seq_device *dev = device->device_data;
-	struct ops_list *ops;
-
-	ops = find_driver(dev->id, 0);
-	if (ops == NULL)
-		return -ENOENT;
-
-	/* initialize this device if the corresponding driver was
-	 * already loaded
-	 */
-	if (ops->driver & DRIVER_LOADED)
-		init_device(dev, ops);
+	int err;
 
-	unlock_driver(ops);
+	err = device_add(&dev->dev);
+	if (err < 0)
+		return err;
+	if (!dev->dev.driver)
+		queue_autoload_drivers();
 	return 0;
 }
 
-/*
- * disconnect the device
- */
 static int snd_seq_device_dev_disconnect(struct snd_device *device)
 {
 	struct snd_seq_device *dev = device->device_data;
-	struct ops_list *ops;
-
-	ops = find_driver(dev->id, 0);
-	if (ops == NULL)
-		return -ENOENT;
-
-	free_device(dev, ops);
 
-	unlock_driver(ops);
+	device_del(&dev->dev);
 	return 0;
 }
 
-/*
- * register device driver
- * id = driver id
- * entry = driver operators - duplicated to each instance
- */
-int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry,
-				   int argsize)
+static void snd_seq_dev_release(struct device *dev)
 {
-	struct ops_list *ops;
-	struct snd_seq_device *dev;
+	struct snd_seq_device *sdev = to_seq_dev(dev);
 
-	if (id == NULL || entry == NULL ||
-	    entry->init_device == NULL || entry->free_device == NULL)
-		return -EINVAL;
-
-	ops = find_driver(id, 1);
-	if (ops == NULL)
-		return -ENOMEM;
-	if (ops->driver & DRIVER_LOADED) {
-		pr_warn("ALSA: seq: driver_register: driver '%s' already exists\n", id);
-		unlock_driver(ops);
-		return -EBUSY;
-	}
-
-	mutex_lock(&ops->reg_mutex);
-	/* copy driver operators */
-	ops->ops = *entry;
-	ops->driver |= DRIVER_LOADED;
-	ops->argsize = argsize;
-
-	/* initialize existing devices if necessary */
-	list_for_each_entry(dev, &ops->dev_list, list) {
-		init_device(dev, ops);
-	}
-	mutex_unlock(&ops->reg_mutex);
-
-	unlock_driver(ops);
-
-	return 0;
+	if (sdev->private_free)
+		sdev->private_free(sdev);
+	kfree(sdev);
 }
 
-
-/*
- * create driver record
- */
-static struct ops_list * create_driver(char *id)
-{
-	struct ops_list *ops;
-
-	ops = kzalloc(sizeof(*ops), GFP_KERNEL);
-	if (ops == NULL)
-		return ops;
-
-	/* set up driver entry */
-	strlcpy(ops->id, id, sizeof(ops->id));
-	mutex_init(&ops->reg_mutex);
-	/*
-	 * The ->reg_mutex locking rules are per-driver, so we create
-	 * separate per-driver lock classes:
-	 */
-	lockdep_set_class(&ops->reg_mutex, (struct lock_class_key *)id);
-
-	ops->driver = DRIVER_EMPTY;
-	INIT_LIST_HEAD(&ops->dev_list);
-	/* lock this instance */
-	ops->used = 1;
-
-	/* register driver entry */
-	mutex_lock(&ops_mutex);
-	list_add_tail(&ops->list, &opslist);
-	num_ops++;
-	mutex_unlock(&ops_mutex);
-
-	return ops;
-}
-
-
 /*
- * unregister the specified driver
+ * register a sequencer device
+ * card = card info
+ * device = device number (if any)
+ * id = id of driver
+ * result = return pointer (NULL allowed if unnecessary)
  */
-int snd_seq_device_unregister_driver(char *id)
+int snd_seq_device_new(struct snd_card *card, int device, const char *id,
+		       int argsize, struct snd_seq_device **result)
 {
-	struct ops_list *ops;
 	struct snd_seq_device *dev;
+	int err;
+	static struct snd_device_ops dops = {
+		.dev_free = snd_seq_device_dev_free,
+		.dev_register = snd_seq_device_dev_register,
+		.dev_disconnect = snd_seq_device_dev_disconnect,
+	};
 
-	ops = find_driver(id, 0);
-	if (ops == NULL)
-		return -ENXIO;
-	if (! (ops->driver & DRIVER_LOADED) ||
-	    (ops->driver & DRIVER_LOCKED)) {
-		pr_err("ALSA: seq: driver_unregister: cannot unload driver '%s': status=%x\n",
-			   id, ops->driver);
-		unlock_driver(ops);
-		return -EBUSY;
-	}
-
-	/* close and release all devices associated with this driver */
-	mutex_lock(&ops->reg_mutex);
-	ops->driver |= DRIVER_LOCKED; /* do not remove this driver recursively */
-	list_for_each_entry(dev, &ops->dev_list, list) {
-		free_device(dev, ops);
-	}
-
-	ops->driver = 0;
-	if (ops->num_init_devices > 0)
-		pr_err("ALSA: seq: free_driver: init_devices > 0!! (%d)\n",
-			   ops->num_init_devices);
-	mutex_unlock(&ops->reg_mutex);
-
-	unlock_driver(ops);
+	if (result)
+		*result = NULL;
 
-	/* remove empty driver entries */
-	remove_drivers();
+	if (snd_BUG_ON(!id))
+		return -EINVAL;
 
-	return 0;
-}
+	dev = kzalloc(sizeof(*dev) + argsize, GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
 
+	/* set up device info */
+	dev->card = card;
+	dev->device = device;
+	dev->id = id;
+	dev->argsize = argsize;
 
-/*
- * remove empty driver entries
- */
-static void remove_drivers(void)
-{
-	struct list_head *head;
-
-	mutex_lock(&ops_mutex);
-	head = opslist.next;
-	while (head != &opslist) {
-		struct ops_list *ops = list_entry(head, struct ops_list, list);
-		if (! (ops->driver & DRIVER_LOADED) &&
-		    ops->used == 0 && ops->num_devices == 0) {
-			head = head->next;
-			list_del(&ops->list);
-			kfree(ops);
-			num_ops--;
-		} else
-			head = head->next;
-	}
-	mutex_unlock(&ops_mutex);
-}
+	device_initialize(&dev->dev);
+	dev->dev.parent = &card->card_dev;
+	dev->dev.bus = &snd_seq_bus_type;
+	dev->dev.release = snd_seq_dev_release;
+	dev_set_name(&dev->dev, "%s-%d-%d", dev->id, card->number, device);
 
-/*
- * initialize the device - call init_device operator
- */
-static int init_device(struct snd_seq_device *dev, struct ops_list *ops)
-{
-	if (! (ops->driver & DRIVER_LOADED))
-		return 0; /* driver is not loaded yet */
-	if (dev->status != SNDRV_SEQ_DEVICE_FREE)
-		return 0; /* already initialized */
-	if (ops->argsize != dev->argsize) {
-		pr_err("ALSA: seq: incompatible device '%s' for plug-in '%s' (%d %d)\n",
-			   dev->name, ops->id, ops->argsize, dev->argsize);
-		return -EINVAL;
-	}
-	if (ops->ops.init_device(dev) >= 0) {
-		dev->status = SNDRV_SEQ_DEVICE_REGISTERED;
-		ops->num_init_devices++;
-	} else {
-		pr_err("ALSA: seq: init_device failed: %s: %s\n",
-			   dev->name, dev->id);
+	/* add this device to the list */
+	err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops);
+	if (err < 0) {
+		put_device(&dev->dev);
+		return err;
 	}
+	
+	if (result)
+		*result = dev;
 
 	return 0;
 }
+EXPORT_SYMBOL(snd_seq_device_new);
 
 /*
- * release the device - call free_device operator
+ * driver registration
  */
-static int free_device(struct snd_seq_device *dev, struct ops_list *ops)
+int __snd_seq_driver_register(struct snd_seq_driver *drv, struct module *mod)
 {
-	int result;
-
-	if (! (ops->driver & DRIVER_LOADED))
-		return 0; /* driver is not loaded yet */
-	if (dev->status != SNDRV_SEQ_DEVICE_REGISTERED)
-		return 0; /* not registered */
-	if (ops->argsize != dev->argsize) {
-		pr_err("ALSA: seq: incompatible device '%s' for plug-in '%s' (%d %d)\n",
-			   dev->name, ops->id, ops->argsize, dev->argsize);
+	if (WARN_ON(!drv->driver.name || !drv->id))
 		return -EINVAL;
-	}
-	if ((result = ops->ops.free_device(dev)) >= 0 || result == -ENXIO) {
-		dev->status = SNDRV_SEQ_DEVICE_FREE;
-		dev->driver_data = NULL;
-		ops->num_init_devices--;
-	} else {
-		pr_err("ALSA: seq: free_device failed: %s: %s\n",
-			   dev->name, dev->id);
-	}
-
-	return 0;
+	drv->driver.bus = &snd_seq_bus_type;
+	drv->driver.owner = mod;
+	return driver_register(&drv->driver);
 }
+EXPORT_SYMBOL_GPL(__snd_seq_driver_register);
 
-/*
- * find the matching driver with given id
- */
-static struct ops_list * find_driver(char *id, int create_if_empty)
+void snd_seq_driver_unregister(struct snd_seq_driver *drv)
 {
-	struct ops_list *ops;
-
-	mutex_lock(&ops_mutex);
-	list_for_each_entry(ops, &opslist, list) {
-		if (strcmp(ops->id, id) == 0) {
-			ops->used++;
-			mutex_unlock(&ops_mutex);
-			return ops;
-		}
-	}
-	mutex_unlock(&ops_mutex);
-	if (create_if_empty)
-		return create_driver(id);
-	return NULL;
+	driver_unregister(&drv->driver);
 }
-
-static void unlock_driver(struct ops_list *ops)
-{
-	mutex_lock(&ops_mutex);
-	ops->used--;
-	mutex_unlock(&ops_mutex);
-}
-
+EXPORT_SYMBOL_GPL(snd_seq_driver_unregister);
 
 /*
  * module part
  */
 
-static int __init alsa_seq_device_init(void)
+static int __init seq_dev_proc_init(void)
 {
 #ifdef CONFIG_PROC_FS
 	info_entry = snd_info_create_module_entry(THIS_MODULE, "drivers",
@@ -589,28 +287,29 @@ static int __init alsa_seq_device_init(void)
 	return 0;
 }
 
+static int __init alsa_seq_device_init(void)
+{
+	int err;
+
+	err = bus_register(&snd_seq_bus_type);
+	if (err < 0)
+		return err;
+	err = seq_dev_proc_init();
+	if (err < 0)
+		bus_unregister(&snd_seq_bus_type);
+	return err;
+}
+
 static void __exit alsa_seq_device_exit(void)
 {
 #ifdef CONFIG_MODULES
 	cancel_work_sync(&autoload_work);
 #endif
-	remove_drivers();
 #ifdef CONFIG_PROC_FS
 	snd_info_free_entry(info_entry);
 #endif
-	if (num_ops)
-		pr_err("ALSA: seq: drivers not released (%d)\n", num_ops);
+	bus_unregister(&snd_seq_bus_type);
 }
 
-module_init(alsa_seq_device_init)
+subsys_initcall(alsa_seq_device_init)
 module_exit(alsa_seq_device_exit)
-
-EXPORT_SYMBOL(snd_seq_device_load_drivers);
-EXPORT_SYMBOL(snd_seq_device_new);
-EXPORT_SYMBOL(snd_seq_device_register_driver);
-EXPORT_SYMBOL(snd_seq_device_unregister_driver);
-#ifdef CONFIG_MODULES
-EXPORT_SYMBOL(snd_seq_autoload_init);
-EXPORT_SYMBOL(snd_seq_autoload_lock);
-EXPORT_SYMBOL(snd_seq_autoload_unlock);
-#endif

+ 1 - 5
sound/core/seq/seq_dummy.c

@@ -214,11 +214,7 @@ delete_client(void)
 
 static int __init alsa_seq_dummy_init(void)
 {
-	int err;
-	snd_seq_autoload_lock();
-	err = register_client();
-	snd_seq_autoload_unlock();
-	return err;
+	return register_client();
 }
 
 static void __exit alsa_seq_dummy_exit(void)

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

@@ -33,10 +33,8 @@ struct snd_seq_fifo *snd_seq_fifo_new(int poolsize)
 	struct snd_seq_fifo *f;
 
 	f = kzalloc(sizeof(*f), GFP_KERNEL);
-	if (f == NULL) {
-		pr_debug("ALSA: seq: malloc failed for snd_seq_fifo_new() \n");
+	if (!f)
 		return NULL;
-	}
 
 	f->pool = snd_seq_pool_new(poolsize);
 	if (f->pool == NULL) {

+ 2 - 6
sound/core/seq/seq_memory.c

@@ -387,10 +387,8 @@ int snd_seq_pool_init(struct snd_seq_pool *pool)
 		return 0;
 
 	pool->ptr = vmalloc(sizeof(struct snd_seq_event_cell) * pool->size);
-	if (pool->ptr == NULL) {
-		pr_debug("ALSA: seq: malloc for sequencer events failed\n");
+	if (!pool->ptr)
 		return -ENOMEM;
-	}
 
 	/* add new cells to the free cell list */
 	spin_lock_irqsave(&pool->lock, flags);
@@ -463,10 +461,8 @@ struct snd_seq_pool *snd_seq_pool_new(int poolsize)
 
 	/* create pool block */
 	pool = kzalloc(sizeof(*pool), GFP_KERNEL);
-	if (pool == NULL) {
-		pr_debug("ALSA: seq: malloc failed for pool\n");
+	if (!pool)
 		return NULL;
-	}
 	spin_lock_init(&pool->lock);
 	pool->ptr = NULL;
 	pool->free = NULL;

+ 14 - 22
sound/core/seq/seq_midi.c

@@ -273,8 +273,9 @@ static void snd_seq_midisynth_delete(struct seq_midisynth *msynth)
 
 /* register new midi synth port */
 static int
-snd_seq_midisynth_register_port(struct snd_seq_device *dev)
+snd_seq_midisynth_probe(struct device *_dev)
 {
+	struct snd_seq_device *dev = to_seq_dev(_dev);
 	struct seq_midisynth_client *client;
 	struct seq_midisynth *msynth, *ms;
 	struct snd_seq_port_info *port;
@@ -427,8 +428,9 @@ snd_seq_midisynth_register_port(struct snd_seq_device *dev)
 
 /* release midi synth port */
 static int
-snd_seq_midisynth_unregister_port(struct snd_seq_device *dev)
+snd_seq_midisynth_remove(struct device *_dev)
 {
+	struct snd_seq_device *dev = to_seq_dev(_dev);
 	struct seq_midisynth_client *client;
 	struct seq_midisynth *msynth;
 	struct snd_card *card = dev->card;
@@ -457,24 +459,14 @@ snd_seq_midisynth_unregister_port(struct snd_seq_device *dev)
 	return 0;
 }
 
+static struct snd_seq_driver seq_midisynth_driver = {
+	.driver = {
+		.name = KBUILD_MODNAME,
+		.probe = snd_seq_midisynth_probe,
+		.remove = snd_seq_midisynth_remove,
+	},
+	.id = SNDRV_SEQ_DEV_ID_MIDISYNTH,
+	.argsize = 0,
+};
 
-static int __init alsa_seq_midi_init(void)
-{
-	static struct snd_seq_dev_ops ops = {
-		snd_seq_midisynth_register_port,
-		snd_seq_midisynth_unregister_port,
-	};
-	memset(&synths, 0, sizeof(synths));
-	snd_seq_autoload_lock();
-	snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_MIDISYNTH, &ops, 0);
-	snd_seq_autoload_unlock();
-	return 0;
-}
-
-static void __exit alsa_seq_midi_exit(void)
-{
-	snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_MIDISYNTH);
-}
-
-module_init(alsa_seq_midi_init)
-module_exit(alsa_seq_midi_exit)
+module_snd_seq_driver(seq_midisynth_driver);

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

@@ -141,10 +141,8 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client,
 
 	/* create a new port */
 	new_port = kzalloc(sizeof(*new_port), GFP_KERNEL);
-	if (! new_port) {
-		pr_debug("ALSA: seq: malloc failed for registering client port\n");
+	if (!new_port)
 		return NULL;	/* failure, out of memory */
-	}
 	/* init port data */
 	new_port->addr.client = client->number;
 	new_port->addr.port = -1;

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

@@ -59,10 +59,8 @@ struct snd_seq_prioq *snd_seq_prioq_new(void)
 	struct snd_seq_prioq *f;
 
 	f = kzalloc(sizeof(*f), GFP_KERNEL);
-	if (f == NULL) {
-		pr_debug("ALSA: seq: malloc failed for snd_seq_prioq_new()\n");
+	if (!f)
 		return NULL;
-	}
 	
 	spin_lock_init(&f->lock);
 	f->head = NULL;

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

@@ -111,10 +111,8 @@ static struct snd_seq_queue *queue_new(int owner, int locked)
 	struct snd_seq_queue *q;
 
 	q = kzalloc(sizeof(*q), GFP_KERNEL);
-	if (q == NULL) {
-		pr_debug("ALSA: seq: malloc failed for snd_seq_queue_new()\n");
+	if (!q)
 		return NULL;
-	}
 
 	spin_lock_init(&q->owner_lock);
 	spin_lock_init(&q->check_lock);

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

@@ -56,10 +56,8 @@ struct snd_seq_timer *snd_seq_timer_new(void)
 	struct snd_seq_timer *tmr;
 	
 	tmr = kzalloc(sizeof(*tmr), GFP_KERNEL);
-	if (tmr == NULL) {
-		pr_debug("ALSA: seq: malloc failed for snd_seq_timer_new() \n");
+	if (!tmr)
 		return NULL;
-	}
 	spin_lock_init(&tmr->lock);
 
 	/* reset setup to defaults */

+ 5 - 9
sound/core/sound.c

@@ -186,7 +186,7 @@ static const struct file_operations snd_fops =
 };
 
 #ifdef CONFIG_SND_DYNAMIC_MINORS
-static int snd_find_free_minor(int type)
+static int snd_find_free_minor(int type, struct snd_card *card, int dev)
 {
 	int minor;
 
@@ -209,7 +209,7 @@ static int snd_find_free_minor(int type)
 	return -EBUSY;
 }
 #else
-static int snd_kernel_minor(int type, struct snd_card *card, int dev)
+static int snd_find_free_minor(int type, struct snd_card *card, int dev)
 {
 	int minor;
 
@@ -237,6 +237,8 @@ static int snd_kernel_minor(int type, struct snd_card *card, int dev)
 	}
 	if (snd_BUG_ON(minor < 0 || minor >= SNDRV_OS_MINORS))
 		return -EINVAL;
+	if (snd_minors[minor])
+		return -EBUSY;
 	return minor;
 }
 #endif
@@ -276,13 +278,7 @@ int snd_register_device(int type, struct snd_card *card, int dev,
 	preg->private_data = private_data;
 	preg->card_ptr = card;
 	mutex_lock(&sound_mutex);
-#ifdef CONFIG_SND_DYNAMIC_MINORS
-	minor = snd_find_free_minor(type);
-#else
-	minor = snd_kernel_minor(type, card, dev);
-	if (minor >= 0 && snd_minors[minor])
-		minor = -EBUSY;
-#endif
+	minor = snd_find_free_minor(type, card, dev);
 	if (minor < 0) {
 		err = minor;
 		goto error;

+ 1 - 3
sound/core/timer.c

@@ -774,10 +774,8 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
 	if (rtimer)
 		*rtimer = NULL;
 	timer = kzalloc(sizeof(*timer), GFP_KERNEL);
-	if (timer == NULL) {
-		pr_err("ALSA: timer: cannot allocate\n");
+	if (!timer)
 		return -ENOMEM;
-	}
 	timer->tmr_class = tid->dev_class;
 	timer->card = card;
 	timer->tmr_device = tid->device;

+ 14 - 20
sound/drivers/opl3/opl3_seq.c

@@ -216,8 +216,9 @@ static int snd_opl3_synth_create_port(struct snd_opl3 * opl3)
 
 /* ------------------------------ */
 
-static int snd_opl3_seq_new_device(struct snd_seq_device *dev)
+static int snd_opl3_seq_probe(struct device *_dev)
 {
+	struct snd_seq_device *dev = to_seq_dev(_dev);
 	struct snd_opl3 *opl3;
 	int client, err;
 	char name[32];
@@ -257,8 +258,9 @@ static int snd_opl3_seq_new_device(struct snd_seq_device *dev)
 	return 0;
 }
 
-static int snd_opl3_seq_delete_device(struct snd_seq_device *dev)
+static int snd_opl3_seq_remove(struct device *_dev)
 {
+	struct snd_seq_device *dev = to_seq_dev(_dev);
 	struct snd_opl3 *opl3;
 
 	opl3 = *(struct snd_opl3 **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
@@ -275,22 +277,14 @@ static int snd_opl3_seq_delete_device(struct snd_seq_device *dev)
 	return 0;
 }
 
-static int __init alsa_opl3_seq_init(void)
-{
-	static struct snd_seq_dev_ops ops =
-	{
-		snd_opl3_seq_new_device,
-		snd_opl3_seq_delete_device
-	};
-
-	return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_OPL3, &ops,
-					      sizeof(struct snd_opl3 *));
-}
-
-static void __exit alsa_opl3_seq_exit(void)
-{
-	snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_OPL3);
-}
+static struct snd_seq_driver opl3_seq_driver = {
+	.driver = {
+		.name = KBUILD_MODNAME,
+		.probe = snd_opl3_seq_probe,
+		.remove = snd_opl3_seq_remove,
+	},
+	.id = SNDRV_SEQ_DEV_ID_OPL3,
+	.argsize = sizeof(struct snd_opl3 *),
+};
 
-module_init(alsa_opl3_seq_init)
-module_exit(alsa_opl3_seq_exit)
+module_snd_seq_driver(opl3_seq_driver);

+ 14 - 19
sound/drivers/opl4/opl4_seq.c

@@ -124,8 +124,9 @@ static void snd_opl4_seq_free_port(void *private_data)
 	snd_midi_channel_free_set(opl4->chset);
 }
 
-static int snd_opl4_seq_new_device(struct snd_seq_device *dev)
+static int snd_opl4_seq_probe(struct device *_dev)
 {
+	struct snd_seq_device *dev = to_seq_dev(_dev);
 	struct snd_opl4 *opl4;
 	int client;
 	struct snd_seq_port_callback pcallbacks;
@@ -180,8 +181,9 @@ static int snd_opl4_seq_new_device(struct snd_seq_device *dev)
 	return 0;
 }
 
-static int snd_opl4_seq_delete_device(struct snd_seq_device *dev)
+static int snd_opl4_seq_remove(struct device *_dev)
 {
+	struct snd_seq_device *dev = to_seq_dev(_dev);
 	struct snd_opl4 *opl4;
 
 	opl4 = *(struct snd_opl4 **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
@@ -195,21 +197,14 @@ static int snd_opl4_seq_delete_device(struct snd_seq_device *dev)
 	return 0;
 }
 
-static int __init alsa_opl4_synth_init(void)
-{
-	static struct snd_seq_dev_ops ops = {
-		snd_opl4_seq_new_device,
-		snd_opl4_seq_delete_device
-	};
-
-	return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_OPL4, &ops,
-					      sizeof(struct snd_opl4 *));
-}
-
-static void __exit alsa_opl4_synth_exit(void)
-{
-	snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_OPL4);
-}
+static struct snd_seq_driver opl4_seq_driver = {
+	.driver = {
+		.name = KBUILD_MODNAME,
+		.probe = snd_opl4_seq_probe,
+		.remove = snd_opl4_seq_remove,
+	},
+	.id = SNDRV_SEQ_DEV_ID_OPL4,
+	.argsize = sizeof(struct snd_opl4 *),
+};
 
-module_init(alsa_opl4_synth_init)
-module_exit(alsa_opl4_synth_exit)
+module_snd_seq_driver(opl4_seq_driver);

+ 4 - 4
sound/firewire/amdtp.c

@@ -166,10 +166,10 @@ int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s,
 	 * One AMDTP packet can include some frames. In blocking mode, the
 	 * number equals to SYT_INTERVAL. So the number is 8, 16 or 32,
 	 * depending on its sampling rate. For accurate period interrupt, it's
-	 * preferrable to aligh period/buffer sizes to current SYT_INTERVAL.
+	 * preferrable to align period/buffer sizes to current SYT_INTERVAL.
 	 *
-	 * TODO: These constraints can be improved with propper rules.
-	 * Currently apply LCM of SYT_INTEVALs.
+	 * 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);
@@ -270,7 +270,7 @@ static void amdtp_read_s32(struct amdtp_stream *s,
  * @s: the AMDTP stream to configure
  * @format: the format of the ALSA PCM device
  *
- * The sample format must be set after the other paramters (rate/PCM channels/
+ * The sample format must be set after the other parameters (rate/PCM channels/
  * MIDI) and before the stream is started, and must not be changed while the
  * stream is running.
  */

+ 1 - 1
sound/firewire/fireworks/fireworks_transaction.c

@@ -13,7 +13,7 @@
  *
  * Transaction substance:
  *  At first, 6 data exist. Following to the data, parameters for each command
- *  exist. All of the parameters are 32 bit alighed to big endian.
+ *  exist. All of the parameters are 32 bit aligned to big endian.
  *   data[0]:	Length of transaction substance
  *   data[1]:	Transaction version
  *   data[2]:	Sequence number. This is incremented by the device

+ 3 - 0
sound/hda/Kconfig

@@ -0,0 +1,3 @@
+config SND_HDA_CORE
+	tristate
+	select REGMAP

+ 7 - 0
sound/hda/Makefile

@@ -0,0 +1,7 @@
+snd-hda-core-objs := hda_bus_type.o hdac_bus.o hdac_device.o hdac_sysfs.o \
+	hdac_regmap.o array.o
+
+snd-hda-core-objs += trace.o
+CFLAGS_trace.o := -I$(src)
+
+obj-$(CONFIG_SND_HDA_CORE) += snd-hda-core.o

+ 49 - 0
sound/hda/array.c

@@ -0,0 +1,49 @@
+/*
+ * generic arrays
+ */
+
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/hdaudio.h>
+
+/**
+ * snd_array_new - get a new element from the given array
+ * @array: the array object
+ *
+ * Get a new element from the given array.  If it exceeds the
+ * pre-allocated array size, re-allocate the array.
+ *
+ * Returns NULL if allocation failed.
+ */
+void *snd_array_new(struct snd_array *array)
+{
+	if (snd_BUG_ON(!array->elem_size))
+		return NULL;
+	if (array->used >= array->alloced) {
+		int num = array->alloced + array->alloc_align;
+		int size = (num + 1) * array->elem_size;
+		void *nlist;
+		if (snd_BUG_ON(num >= 4096))
+			return NULL;
+		nlist = krealloc(array->list, size, GFP_KERNEL | __GFP_ZERO);
+		if (!nlist)
+			return NULL;
+		array->list = nlist;
+		array->alloced = num;
+	}
+	return snd_array_elem(array, array->used++);
+}
+EXPORT_SYMBOL_GPL(snd_array_new);
+
+/**
+ * snd_array_free - free the given array elements
+ * @array: the array object
+ */
+void snd_array_free(struct snd_array *array)
+{
+	kfree(array->list);
+	array->used = 0;
+	array->alloced = 0;
+	array->list = NULL;
+}
+EXPORT_SYMBOL_GPL(snd_array_free);

+ 42 - 0
sound/hda/hda_bus_type.c

@@ -0,0 +1,42 @@
+/*
+ * HD-audio bus
+ */
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/export.h>
+#include <sound/hdaudio.h>
+
+MODULE_DESCRIPTION("HD-audio bus");
+MODULE_LICENSE("GPL");
+
+static int hda_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct hdac_device *hdev = dev_to_hdac_dev(dev);
+	struct hdac_driver *hdrv = drv_to_hdac_driver(drv);
+
+	if (hdev->type != hdrv->type)
+		return 0;
+	if (hdrv->match)
+		return hdrv->match(hdev, hdrv);
+	return 1;
+}
+
+struct bus_type snd_hda_bus_type = {
+	.name = "hdaudio",
+	.match = hda_bus_match,
+};
+EXPORT_SYMBOL_GPL(snd_hda_bus_type);
+
+static int __init hda_bus_init(void)
+{
+	return bus_register(&snd_hda_bus_type);
+}
+
+static void __exit hda_bus_exit(void)
+{
+	bus_unregister(&snd_hda_bus_type);
+}
+
+subsys_initcall(hda_bus_init);
+module_exit(hda_bus_exit);

+ 186 - 0
sound/hda/hdac_bus.c

@@ -0,0 +1,186 @@
+/*
+ * HD-audio core bus driver
+ */
+
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/export.h>
+#include <sound/hdaudio.h>
+#include "trace.h"
+
+static void process_unsol_events(struct work_struct *work);
+
+/**
+ * snd_hdac_bus_init - initialize a HD-audio bas bus
+ * @bus: the pointer to bus object
+ *
+ * Returns 0 if successful, or a negative error code.
+ */
+int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
+		      const struct hdac_bus_ops *ops)
+{
+	memset(bus, 0, sizeof(*bus));
+	bus->dev = dev;
+	bus->ops = ops;
+	INIT_LIST_HEAD(&bus->codec_list);
+	INIT_WORK(&bus->unsol_work, process_unsol_events);
+	mutex_init(&bus->cmd_mutex);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_bus_init);
+
+/**
+ * snd_hdac_bus_exit - clean up a HD-audio bas bus
+ * @bus: the pointer to bus object
+ */
+void snd_hdac_bus_exit(struct hdac_bus *bus)
+{
+	WARN_ON(!list_empty(&bus->codec_list));
+	cancel_work_sync(&bus->unsol_work);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_bus_exit);
+
+/**
+ * snd_hdac_bus_exec_verb - execute a HD-audio verb on the given bus
+ * @bus: bus object
+ * @cmd: HD-audio encoded verb
+ * @res: pointer to store the response, NULL if performing asynchronously
+ *
+ * Returns 0 if successful, or a negative error code.
+ */
+int snd_hdac_bus_exec_verb(struct hdac_bus *bus, unsigned int addr,
+			   unsigned int cmd, unsigned int *res)
+{
+	int err;
+
+	mutex_lock(&bus->cmd_mutex);
+	err = snd_hdac_bus_exec_verb_unlocked(bus, addr, cmd, res);
+	mutex_unlock(&bus->cmd_mutex);
+	return err;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_bus_exec_verb);
+
+/**
+ * snd_hdac_bus_exec_verb_unlocked - unlocked version
+ * @bus: bus object
+ * @cmd: HD-audio encoded verb
+ * @res: pointer to store the response, NULL if performing asynchronously
+ *
+ * Returns 0 if successful, or a negative error code.
+ */
+int snd_hdac_bus_exec_verb_unlocked(struct hdac_bus *bus, unsigned int addr,
+				    unsigned int cmd, unsigned int *res)
+{
+	unsigned int tmp;
+	int err;
+
+	if (cmd == ~0)
+		return -EINVAL;
+
+	if (res)
+		*res = -1;
+	else if (bus->sync_write)
+		res = &tmp;
+	for (;;) {
+		trace_hda_send_cmd(bus, cmd);
+		err = bus->ops->command(bus, cmd);
+		if (err != -EAGAIN)
+			break;
+		/* process pending verbs */
+		err = bus->ops->get_response(bus, addr, &tmp);
+		if (err)
+			break;
+	}
+	if (!err && res) {
+		err = bus->ops->get_response(bus, addr, res);
+		trace_hda_get_response(bus, addr, *res);
+	}
+	return err;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_bus_exec_verb_unlocked);
+
+/**
+ * snd_hdac_bus_queue_event - add an unsolicited event to queue
+ * @bus: the BUS
+ * @res: unsolicited event (lower 32bit of RIRB entry)
+ * @res_ex: codec addr and flags (upper 32bit or RIRB entry)
+ *
+ * Adds the given event to the queue.  The events are processed in
+ * the workqueue asynchronously.  Call this function in the interrupt
+ * hanlder when RIRB receives an unsolicited event.
+ */
+void snd_hdac_bus_queue_event(struct hdac_bus *bus, u32 res, u32 res_ex)
+{
+	unsigned int wp;
+
+	if (!bus)
+		return;
+
+	trace_hda_unsol_event(bus, res, res_ex);
+	wp = (bus->unsol_wp + 1) % HDA_UNSOL_QUEUE_SIZE;
+	bus->unsol_wp = wp;
+
+	wp <<= 1;
+	bus->unsol_queue[wp] = res;
+	bus->unsol_queue[wp + 1] = res_ex;
+
+	schedule_work(&bus->unsol_work);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_bus_queue_event);
+
+/*
+ * process queued unsolicited events
+ */
+static void process_unsol_events(struct work_struct *work)
+{
+	struct hdac_bus *bus = container_of(work, struct hdac_bus, unsol_work);
+	struct hdac_device *codec;
+	struct hdac_driver *drv;
+	unsigned int rp, caddr, res;
+
+	while (bus->unsol_rp != bus->unsol_wp) {
+		rp = (bus->unsol_rp + 1) % HDA_UNSOL_QUEUE_SIZE;
+		bus->unsol_rp = rp;
+		rp <<= 1;
+		res = bus->unsol_queue[rp];
+		caddr = bus->unsol_queue[rp + 1];
+		if (!(caddr & (1 << 4))) /* no unsolicited event? */
+			continue;
+		codec = bus->caddr_tbl[caddr & 0x0f];
+		if (!codec || !codec->dev.driver)
+			continue;
+		drv = drv_to_hdac_driver(codec->dev.driver);
+		if (drv->unsol_event)
+			drv->unsol_event(codec, res);
+	}
+}
+
+int snd_hdac_bus_add_device(struct hdac_bus *bus, struct hdac_device *codec)
+{
+	if (bus->caddr_tbl[codec->addr]) {
+		dev_err(bus->dev, "address 0x%x is already occupied\n",
+			codec->addr);
+		return -EBUSY;
+	}
+
+	list_add_tail(&codec->list, &bus->codec_list);
+	bus->caddr_tbl[codec->addr] = codec;
+	set_bit(codec->addr, &bus->codec_powered);
+	bus->num_codecs++;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_bus_add_device);
+
+void snd_hdac_bus_remove_device(struct hdac_bus *bus,
+				struct hdac_device *codec)
+{
+	WARN_ON(bus != codec->bus);
+	if (list_empty(&codec->list))
+		return;
+	list_del_init(&codec->list);
+	bus->caddr_tbl[codec->addr] = NULL;
+	clear_bit(codec->addr, &bus->codec_powered);
+	bus->num_codecs--;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_bus_remove_device);

+ 599 - 0
sound/hda/hdac_device.c

@@ -0,0 +1,599 @@
+/*
+ * HD-audio codec core device
+ */
+
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/pm_runtime.h>
+#include <sound/hdaudio.h>
+#include <sound/hda_regmap.h>
+#include "local.h"
+
+static void setup_fg_nodes(struct hdac_device *codec);
+static int get_codec_vendor_name(struct hdac_device *codec);
+
+static void default_release(struct device *dev)
+{
+	snd_hdac_device_exit(container_of(dev, struct hdac_device, dev));
+}
+
+/**
+ * snd_hdac_device_init - initialize the HD-audio codec base device
+ * @codec: device to initialize
+ * @bus: but to attach
+ * @name: device name string
+ * @addr: codec address
+ *
+ * Returns zero for success or a negative error code.
+ *
+ * This function increments the runtime PM counter and marks it active.
+ * The caller needs to turn it off appropriately later.
+ *
+ * The caller needs to set the device's release op properly by itself.
+ */
+int snd_hdac_device_init(struct hdac_device *codec, struct hdac_bus *bus,
+			 const char *name, unsigned int addr)
+{
+	struct device *dev;
+	hda_nid_t fg;
+	int err;
+
+	dev = &codec->dev;
+	device_initialize(dev);
+	dev->parent = bus->dev;
+	dev->bus = &snd_hda_bus_type;
+	dev->release = default_release;
+	dev->groups = hdac_dev_attr_groups;
+	dev_set_name(dev, "%s", name);
+	device_enable_async_suspend(dev);
+
+	codec->bus = bus;
+	codec->addr = addr;
+	codec->type = HDA_DEV_CORE;
+	pm_runtime_set_active(&codec->dev);
+	pm_runtime_get_noresume(&codec->dev);
+	atomic_set(&codec->in_pm, 0);
+
+	err = snd_hdac_bus_add_device(bus, codec);
+	if (err < 0)
+		goto error;
+
+	/* fill parameters */
+	codec->vendor_id = snd_hdac_read_parm(codec, AC_NODE_ROOT,
+					      AC_PAR_VENDOR_ID);
+	if (codec->vendor_id == -1) {
+		/* read again, hopefully the access method was corrected
+		 * in the last read...
+		 */
+		codec->vendor_id = snd_hdac_read_parm(codec, AC_NODE_ROOT,
+						      AC_PAR_VENDOR_ID);
+	}
+
+	codec->subsystem_id = snd_hdac_read_parm(codec, AC_NODE_ROOT,
+						 AC_PAR_SUBSYSTEM_ID);
+	codec->revision_id = snd_hdac_read_parm(codec, AC_NODE_ROOT,
+						AC_PAR_REV_ID);
+
+	setup_fg_nodes(codec);
+	if (!codec->afg && !codec->mfg) {
+		dev_err(dev, "no AFG or MFG node found\n");
+		err = -ENODEV;
+		goto error;
+	}
+
+	fg = codec->afg ? codec->afg : codec->mfg;
+
+	err = snd_hdac_refresh_widgets(codec);
+	if (err < 0)
+		goto error;
+
+	codec->power_caps = snd_hdac_read_parm(codec, fg, AC_PAR_POWER_STATE);
+	/* reread ssid if not set by parameter */
+	if (codec->subsystem_id == -1 || codec->subsystem_id == 0)
+		snd_hdac_read(codec, fg, AC_VERB_GET_SUBSYSTEM_ID, 0,
+			      &codec->subsystem_id);
+
+	err = get_codec_vendor_name(codec);
+	if (err < 0)
+		goto error;
+
+	codec->chip_name = kasprintf(GFP_KERNEL, "ID %x",
+				     codec->vendor_id & 0xffff);
+	if (!codec->chip_name) {
+		err = -ENOMEM;
+		goto error;
+	}
+
+	return 0;
+
+ error:
+	put_device(&codec->dev);
+	return err;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_device_init);
+
+/**
+ * snd_hdac_device_exit - clean up the HD-audio codec base device
+ * @codec: device to clean up
+ */
+void snd_hdac_device_exit(struct hdac_device *codec)
+{
+	pm_runtime_put_noidle(&codec->dev);
+	snd_hdac_bus_remove_device(codec->bus, codec);
+	kfree(codec->vendor_name);
+	kfree(codec->chip_name);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_device_exit);
+
+/**
+ * snd_hdac_device_register - register the hd-audio codec base device
+ * codec: the device to register
+ */
+int snd_hdac_device_register(struct hdac_device *codec)
+{
+	int err;
+
+	err = device_add(&codec->dev);
+	if (err < 0)
+		return err;
+	err = hda_widget_sysfs_init(codec);
+	if (err < 0) {
+		device_del(&codec->dev);
+		return err;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_device_register);
+
+/**
+ * snd_hdac_device_unregister - unregister the hd-audio codec base device
+ * codec: the device to unregister
+ */
+void snd_hdac_device_unregister(struct hdac_device *codec)
+{
+	if (device_is_registered(&codec->dev)) {
+		hda_widget_sysfs_exit(codec);
+		device_del(&codec->dev);
+	}
+}
+EXPORT_SYMBOL_GPL(snd_hdac_device_unregister);
+
+/**
+ * snd_hdac_make_cmd - compose a 32bit command word to be sent to the
+ *	HD-audio controller
+ * @codec: the codec object
+ * @nid: NID to encode
+ * @verb: verb to encode
+ * @parm: parameter to encode
+ *
+ * Return an encoded command verb or -1 for error.
+ */
+unsigned int snd_hdac_make_cmd(struct hdac_device *codec, hda_nid_t nid,
+			       unsigned int verb, unsigned int parm)
+{
+	u32 val, addr;
+
+	addr = codec->addr;
+	if ((addr & ~0xf) || (nid & ~0x7f) ||
+	    (verb & ~0xfff) || (parm & ~0xffff)) {
+		dev_err(&codec->dev, "out of range cmd %x:%x:%x:%x\n",
+			addr, nid, verb, parm);
+		return -1;
+	}
+
+	val = addr << 28;
+	val |= (u32)nid << 20;
+	val |= verb << 8;
+	val |= parm;
+	return val;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_make_cmd);
+
+/**
+ * snd_hdac_exec_verb - execute an encoded verb
+ * @codec: the codec object
+ * @cmd: encoded verb to execute
+ * @flags: optional flags, pass zero for default
+ * @res: the pointer to store the result, NULL if running async
+ *
+ * Returns zero if successful, or a negative error code.
+ *
+ * This calls the exec_verb op when set in hdac_codec.  If not,
+ * call the default snd_hdac_bus_exec_verb().
+ */
+int snd_hdac_exec_verb(struct hdac_device *codec, unsigned int cmd,
+		       unsigned int flags, unsigned int *res)
+{
+	if (codec->exec_verb)
+		return codec->exec_verb(codec, cmd, flags, res);
+	return snd_hdac_bus_exec_verb(codec->bus, codec->addr, cmd, res);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_exec_verb);
+
+
+/**
+ * snd_hdac_read - execute a verb
+ * @codec: the codec object
+ * @nid: NID to execute a verb
+ * @verb: verb to execute
+ * @parm: parameter for a verb
+ * @res: the pointer to store the result, NULL if running async
+ *
+ * Returns zero if successful, or a negative error code.
+ */
+int snd_hdac_read(struct hdac_device *codec, hda_nid_t nid,
+		  unsigned int verb, unsigned int parm, unsigned int *res)
+{
+	unsigned int cmd = snd_hdac_make_cmd(codec, nid, verb, parm);
+
+	return snd_hdac_exec_verb(codec, cmd, 0, res);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_read);
+
+/**
+ * _snd_hdac_read_parm - read a parmeter
+ *
+ * This function returns zero or an error unlike snd_hdac_read_parm().
+ */
+int _snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid, int parm,
+			unsigned int *res)
+{
+	unsigned int cmd;
+
+	cmd = snd_hdac_regmap_encode_verb(nid, AC_VERB_PARAMETERS) | parm;
+	return snd_hdac_regmap_read_raw(codec, cmd, res);
+}
+EXPORT_SYMBOL_GPL(_snd_hdac_read_parm);
+
+/**
+ * snd_hdac_read_parm_uncached - read a codec parameter without caching
+ * @codec: the codec object
+ * @nid: NID to read a parameter
+ * @parm: parameter to read
+ *
+ * Returns -1 for error.  If you need to distinguish the error more
+ * strictly, use snd_hdac_read() directly.
+ */
+int snd_hdac_read_parm_uncached(struct hdac_device *codec, hda_nid_t nid,
+				int parm)
+{
+	int val;
+
+	if (codec->regmap)
+		regcache_cache_bypass(codec->regmap, true);
+	val = snd_hdac_read_parm(codec, nid, parm);
+	if (codec->regmap)
+		regcache_cache_bypass(codec->regmap, false);
+	return val;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_read_parm_uncached);
+
+/**
+ * snd_hdac_override_parm - override read-only parameters
+ * @codec: the codec object
+ * @nid: NID for the parameter
+ * @parm: the parameter to change
+ * @val: the parameter value to overwrite
+ */
+int snd_hdac_override_parm(struct hdac_device *codec, hda_nid_t nid,
+			   unsigned int parm, unsigned int val)
+{
+	unsigned int verb = (AC_VERB_PARAMETERS << 8) | (nid << 20) | parm;
+	int err;
+
+	if (!codec->regmap)
+		return -EINVAL;
+
+	codec->caps_overwriting = true;
+	err = snd_hdac_regmap_write_raw(codec, verb, val);
+	codec->caps_overwriting = false;
+	return err;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_override_parm);
+
+/**
+ * snd_hdac_get_sub_nodes - get start NID and number of subtree nodes
+ * @codec: the codec object
+ * @nid: NID to inspect
+ * @start_id: the pointer to store the starting NID
+ *
+ * Returns the number of subtree nodes or zero if not found.
+ * This function reads parameters always without caching.
+ */
+int snd_hdac_get_sub_nodes(struct hdac_device *codec, hda_nid_t nid,
+			   hda_nid_t *start_id)
+{
+	unsigned int parm;
+
+	parm = snd_hdac_read_parm_uncached(codec, nid, AC_PAR_NODE_COUNT);
+	if (parm == -1) {
+		*start_id = 0;
+		return 0;
+	}
+	*start_id = (parm >> 16) & 0x7fff;
+	return (int)(parm & 0x7fff);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_get_sub_nodes);
+
+/*
+ * look for an AFG and MFG nodes
+ */
+static void setup_fg_nodes(struct hdac_device *codec)
+{
+	int i, total_nodes, function_id;
+	hda_nid_t nid;
+
+	total_nodes = snd_hdac_get_sub_nodes(codec, AC_NODE_ROOT, &nid);
+	for (i = 0; i < total_nodes; i++, nid++) {
+		function_id = snd_hdac_read_parm(codec, nid,
+						 AC_PAR_FUNCTION_TYPE);
+		switch (function_id & 0xff) {
+		case AC_GRP_AUDIO_FUNCTION:
+			codec->afg = nid;
+			codec->afg_function_id = function_id & 0xff;
+			codec->afg_unsol = (function_id >> 8) & 1;
+			break;
+		case AC_GRP_MODEM_FUNCTION:
+			codec->mfg = nid;
+			codec->mfg_function_id = function_id & 0xff;
+			codec->mfg_unsol = (function_id >> 8) & 1;
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+/**
+ * snd_hdac_refresh_widgets - Reset the widget start/end nodes
+ * @codec: the codec object
+ */
+int snd_hdac_refresh_widgets(struct hdac_device *codec)
+{
+	hda_nid_t start_nid;
+	int nums;
+
+	nums = snd_hdac_get_sub_nodes(codec, codec->afg, &start_nid);
+	if (!start_nid || nums <= 0 || nums >= 0xff) {
+		dev_err(&codec->dev, "cannot read sub nodes for FG 0x%02x\n",
+			codec->afg);
+		return -EINVAL;
+	}
+
+	codec->num_nodes = nums;
+	codec->start_nid = start_nid;
+	codec->end_nid = start_nid + nums;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_refresh_widgets);
+
+/* return CONNLIST_LEN parameter of the given widget */
+static unsigned int get_num_conns(struct hdac_device *codec, hda_nid_t nid)
+{
+	unsigned int wcaps = get_wcaps(codec, nid);
+	unsigned int parm;
+
+	if (!(wcaps & AC_WCAP_CONN_LIST) &&
+	    get_wcaps_type(wcaps) != AC_WID_VOL_KNB)
+		return 0;
+
+	parm = snd_hdac_read_parm(codec, nid, AC_PAR_CONNLIST_LEN);
+	if (parm == -1)
+		parm = 0;
+	return parm;
+}
+
+/**
+ * snd_hdac_get_connections - get a widget connection list
+ * @codec: the codec object
+ * @nid: NID
+ * @conn_list: the array to store the results, can be NULL
+ * @max_conns: the max size of the given array
+ *
+ * Returns the number of connected widgets, zero for no connection, or a
+ * negative error code.  When the number of elements don't fit with the
+ * given array size, it returns -ENOSPC.
+ *
+ * When @conn_list is NULL, it just checks the number of connections.
+ */
+int snd_hdac_get_connections(struct hdac_device *codec, hda_nid_t nid,
+			     hda_nid_t *conn_list, int max_conns)
+{
+	unsigned int parm;
+	int i, conn_len, conns, err;
+	unsigned int shift, num_elems, mask;
+	hda_nid_t prev_nid;
+	int null_count = 0;
+
+	parm = get_num_conns(codec, nid);
+	if (!parm)
+		return 0;
+
+	if (parm & AC_CLIST_LONG) {
+		/* long form */
+		shift = 16;
+		num_elems = 2;
+	} else {
+		/* short form */
+		shift = 8;
+		num_elems = 4;
+	}
+	conn_len = parm & AC_CLIST_LENGTH;
+	mask = (1 << (shift-1)) - 1;
+
+	if (!conn_len)
+		return 0; /* no connection */
+
+	if (conn_len == 1) {
+		/* single connection */
+		err = snd_hdac_read(codec, nid, AC_VERB_GET_CONNECT_LIST, 0,
+				    &parm);
+		if (err < 0)
+			return err;
+		if (conn_list)
+			conn_list[0] = parm & mask;
+		return 1;
+	}
+
+	/* multi connection */
+	conns = 0;
+	prev_nid = 0;
+	for (i = 0; i < conn_len; i++) {
+		int range_val;
+		hda_nid_t val, n;
+
+		if (i % num_elems == 0) {
+			err = snd_hdac_read(codec, nid,
+					    AC_VERB_GET_CONNECT_LIST, i,
+					    &parm);
+			if (err < 0)
+				return -EIO;
+		}
+		range_val = !!(parm & (1 << (shift-1))); /* ranges */
+		val = parm & mask;
+		if (val == 0 && null_count++) {  /* no second chance */
+			dev_dbg(&codec->dev,
+				"invalid CONNECT_LIST verb %x[%i]:%x\n",
+				nid, i, parm);
+			return 0;
+		}
+		parm >>= shift;
+		if (range_val) {
+			/* ranges between the previous and this one */
+			if (!prev_nid || prev_nid >= val) {
+				dev_warn(&codec->dev,
+					 "invalid dep_range_val %x:%x\n",
+					 prev_nid, val);
+				continue;
+			}
+			for (n = prev_nid + 1; n <= val; n++) {
+				if (conn_list) {
+					if (conns >= max_conns)
+						return -ENOSPC;
+					conn_list[conns] = n;
+				}
+				conns++;
+			}
+		} else {
+			if (conn_list) {
+				if (conns >= max_conns)
+					return -ENOSPC;
+				conn_list[conns] = val;
+			}
+			conns++;
+		}
+		prev_nid = val;
+	}
+	return conns;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_get_connections);
+
+#ifdef CONFIG_PM
+/**
+ * snd_hdac_power_up - power up the codec
+ * @codec: the codec object
+ *
+ * This function calls the runtime PM helper to power up the given codec.
+ * Unlike snd_hdac_power_up_pm(), you should call this only for the code
+ * path that isn't included in PM path.  Otherwise it gets stuck.
+ */
+void snd_hdac_power_up(struct hdac_device *codec)
+{
+	pm_runtime_get_sync(&codec->dev);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_power_up);
+
+/**
+ * snd_hdac_power_down - power down the codec
+ * @codec: the codec object
+ */
+void snd_hdac_power_down(struct hdac_device *codec)
+{
+	struct device *dev = &codec->dev;
+
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_power_down);
+
+/**
+ * snd_hdac_power_up_pm - power up the codec
+ * @codec: the codec object
+ *
+ * This function can be called in a recursive code path like init code
+ * which may be called by PM suspend/resume again.  OTOH, if a power-up
+ * call must wake up the sleeper (e.g. in a kctl callback), use
+ * snd_hdac_power_up() instead.
+ */
+void snd_hdac_power_up_pm(struct hdac_device *codec)
+{
+	if (!atomic_inc_not_zero(&codec->in_pm))
+		snd_hdac_power_up(codec);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_power_up_pm);
+
+/**
+ * snd_hdac_power_down_pm - power down the codec
+ * @codec: the codec object
+ *
+ * Like snd_hdac_power_up_pm(), this function is used in a recursive
+ * code path like init code which may be called by PM suspend/resume again.
+ */
+void snd_hdac_power_down_pm(struct hdac_device *codec)
+{
+	if (atomic_dec_if_positive(&codec->in_pm) < 0)
+		snd_hdac_power_down(codec);
+}
+EXPORT_SYMBOL_GPL(snd_hdac_power_down_pm);
+#endif
+
+/* codec vendor labels */
+struct hda_vendor_id {
+	unsigned int id;
+	const char *name;
+};
+
+static struct hda_vendor_id hda_vendor_ids[] = {
+	{ 0x1002, "ATI" },
+	{ 0x1013, "Cirrus Logic" },
+	{ 0x1057, "Motorola" },
+	{ 0x1095, "Silicon Image" },
+	{ 0x10de, "Nvidia" },
+	{ 0x10ec, "Realtek" },
+	{ 0x1102, "Creative" },
+	{ 0x1106, "VIA" },
+	{ 0x111d, "IDT" },
+	{ 0x11c1, "LSI" },
+	{ 0x11d4, "Analog Devices" },
+	{ 0x13f6, "C-Media" },
+	{ 0x14f1, "Conexant" },
+	{ 0x17e8, "Chrontel" },
+	{ 0x1854, "LG" },
+	{ 0x1aec, "Wolfson Microelectronics" },
+	{ 0x1af4, "QEMU" },
+	{ 0x434d, "C-Media" },
+	{ 0x8086, "Intel" },
+	{ 0x8384, "SigmaTel" },
+	{} /* terminator */
+};
+
+/* store the codec vendor name */
+static int get_codec_vendor_name(struct hdac_device *codec)
+{
+	const struct hda_vendor_id *c;
+	u16 vendor_id = codec->vendor_id >> 16;
+
+	for (c = hda_vendor_ids; c->id; c++) {
+		if (c->id == vendor_id) {
+			codec->vendor_name = kstrdup(c->name, GFP_KERNEL);
+			return codec->vendor_name ? 0 : -ENOMEM;
+		}
+	}
+
+	codec->vendor_name = kasprintf(GFP_KERNEL, "Generic %04x", vendor_id);
+	return codec->vendor_name ? 0 : -ENOMEM;
+}

+ 472 - 0
sound/hda/hdac_regmap.c

@@ -0,0 +1,472 @@
+/*
+ * Regmap support for HD-audio verbs
+ *
+ * A virtual register is translated to one or more hda verbs for write,
+ * vice versa for read.
+ *
+ * A few limitations:
+ * - Provided for not all verbs but only subset standard non-volatile verbs.
+ * - For reading, only AC_VERB_GET_* variants can be used.
+ * - For writing, mapped to the *corresponding* AC_VERB_SET_* variants,
+ *   so can't handle asymmetric verbs for read and write
+ */
+
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/regmap.h>
+#include <linux/export.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <sound/core.h>
+#include <sound/hdaudio.h>
+#include <sound/hda_regmap.h>
+
+#ifdef CONFIG_PM
+#define codec_is_running(codec)				\
+	(atomic_read(&(codec)->in_pm) ||		\
+	 !pm_runtime_suspended(&(codec)->dev))
+#else
+#define codec_is_running(codec)		true
+#endif
+
+#define get_verb(reg)	(((reg) >> 8) & 0xfff)
+
+static bool hda_volatile_reg(struct device *dev, unsigned int reg)
+{
+	struct hdac_device *codec = dev_to_hdac_dev(dev);
+	unsigned int verb = get_verb(reg);
+
+	switch (verb) {
+	case AC_VERB_GET_PROC_COEF:
+		return !codec->cache_coef;
+	case AC_VERB_GET_COEF_INDEX:
+	case AC_VERB_GET_PROC_STATE:
+	case AC_VERB_GET_POWER_STATE:
+	case AC_VERB_GET_PIN_SENSE:
+	case AC_VERB_GET_HDMI_DIP_SIZE:
+	case AC_VERB_GET_HDMI_ELDD:
+	case AC_VERB_GET_HDMI_DIP_INDEX:
+	case AC_VERB_GET_HDMI_DIP_DATA:
+	case AC_VERB_GET_HDMI_DIP_XMIT:
+	case AC_VERB_GET_HDMI_CP_CTRL:
+	case AC_VERB_GET_HDMI_CHAN_SLOT:
+	case AC_VERB_GET_DEVICE_SEL:
+	case AC_VERB_GET_DEVICE_LIST:	/* read-only volatile */
+		return true;
+	}
+
+	return false;
+}
+
+static bool hda_writeable_reg(struct device *dev, unsigned int reg)
+{
+	struct hdac_device *codec = dev_to_hdac_dev(dev);
+	unsigned int verb = get_verb(reg);
+	int i;
+
+	for (i = 0; i < codec->vendor_verbs.used; i++) {
+		unsigned int *v = snd_array_elem(&codec->vendor_verbs, i);
+		if (verb == *v)
+			return true;
+	}
+
+	if (codec->caps_overwriting)
+		return true;
+
+	switch (verb & 0xf00) {
+	case AC_VERB_GET_STREAM_FORMAT:
+	case AC_VERB_GET_AMP_GAIN_MUTE:
+		return true;
+	case AC_VERB_GET_PROC_COEF:
+		return codec->cache_coef;
+	case 0xf00:
+		break;
+	default:
+		return false;
+	}
+
+	switch (verb) {
+	case AC_VERB_GET_CONNECT_SEL:
+	case AC_VERB_GET_SDI_SELECT:
+	case AC_VERB_GET_PIN_WIDGET_CONTROL:
+	case AC_VERB_GET_UNSOLICITED_RESPONSE: /* only as SET_UNSOLICITED_ENABLE */
+	case AC_VERB_GET_BEEP_CONTROL:
+	case AC_VERB_GET_EAPD_BTLENABLE:
+	case AC_VERB_GET_DIGI_CONVERT_1:
+	case AC_VERB_GET_DIGI_CONVERT_2: /* only for beep control */
+	case AC_VERB_GET_VOLUME_KNOB_CONTROL:
+	case AC_VERB_GET_GPIO_MASK:
+	case AC_VERB_GET_GPIO_DIRECTION:
+	case AC_VERB_GET_GPIO_DATA: /* not for volatile read */
+	case AC_VERB_GET_GPIO_WAKE_MASK:
+	case AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK:
+	case AC_VERB_GET_GPIO_STICKY_MASK:
+		return true;
+	}
+
+	return false;
+}
+
+static bool hda_readable_reg(struct device *dev, unsigned int reg)
+{
+	struct hdac_device *codec = dev_to_hdac_dev(dev);
+	unsigned int verb = get_verb(reg);
+
+	if (codec->caps_overwriting)
+		return true;
+
+	switch (verb) {
+	case AC_VERB_PARAMETERS:
+	case AC_VERB_GET_CONNECT_LIST:
+	case AC_VERB_GET_SUBSYSTEM_ID:
+		return true;
+	/* below are basically writable, but disabled for reducing unnecessary
+	 * writes at sync
+	 */
+	case AC_VERB_GET_CONFIG_DEFAULT: /* usually just read */
+	case AC_VERB_GET_CONV: /* managed in PCM code */
+	case AC_VERB_GET_CVT_CHAN_COUNT: /* managed in HDMI CA code */
+		return true;
+	}
+
+	return hda_writeable_reg(dev, reg);
+}
+
+/*
+ * Stereo amp pseudo register:
+ * for making easier to handle the stereo volume control, we provide a
+ * fake register to deal both left and right channels by a single
+ * (pseudo) register access.  A verb consisting of SET_AMP_GAIN with
+ * *both* SET_LEFT and SET_RIGHT bits takes a 16bit value, the lower 8bit
+ * for the left and the upper 8bit for the right channel.
+ */
+static bool is_stereo_amp_verb(unsigned int reg)
+{
+	if (((reg >> 8) & 0x700) != AC_VERB_SET_AMP_GAIN_MUTE)
+		return false;
+	return (reg & (AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT)) ==
+		(AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT);
+}
+
+/* read a pseudo stereo amp register (16bit left+right) */
+static int hda_reg_read_stereo_amp(struct hdac_device *codec,
+				   unsigned int reg, unsigned int *val)
+{
+	unsigned int left, right;
+	int err;
+
+	reg &= ~(AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT);
+	err = snd_hdac_exec_verb(codec, reg | AC_AMP_GET_LEFT, 0, &left);
+	if (err < 0)
+		return err;
+	err = snd_hdac_exec_verb(codec, reg | AC_AMP_GET_RIGHT, 0, &right);
+	if (err < 0)
+		return err;
+	*val = left | (right << 8);
+	return 0;
+}
+
+/* write a pseudo stereo amp register (16bit left+right) */
+static int hda_reg_write_stereo_amp(struct hdac_device *codec,
+				    unsigned int reg, unsigned int val)
+{
+	int err;
+	unsigned int verb, left, right;
+
+	verb = AC_VERB_SET_AMP_GAIN_MUTE << 8;
+	if (reg & AC_AMP_GET_OUTPUT)
+		verb |= AC_AMP_SET_OUTPUT;
+	else
+		verb |= AC_AMP_SET_INPUT | ((reg & 0xf) << 8);
+	reg = (reg & ~0xfffff) | verb;
+
+	left = val & 0xff;
+	right = (val >> 8) & 0xff;
+	if (left == right) {
+		reg |= AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT;
+		return snd_hdac_exec_verb(codec, reg | left, 0, NULL);
+	}
+
+	err = snd_hdac_exec_verb(codec, reg | AC_AMP_SET_LEFT | left, 0, NULL);
+	if (err < 0)
+		return err;
+	err = snd_hdac_exec_verb(codec, reg | AC_AMP_SET_RIGHT | right, 0, NULL);
+	if (err < 0)
+		return err;
+	return 0;
+}
+
+/* read a pseudo coef register (16bit) */
+static int hda_reg_read_coef(struct hdac_device *codec, unsigned int reg,
+			     unsigned int *val)
+{
+	unsigned int verb;
+	int err;
+
+	if (!codec->cache_coef)
+		return -EINVAL;
+	/* LSB 8bit = coef index */
+	verb = (reg & ~0xfff00) | (AC_VERB_SET_COEF_INDEX << 8);
+	err = snd_hdac_exec_verb(codec, verb, 0, NULL);
+	if (err < 0)
+		return err;
+	verb = (reg & ~0xfffff) | (AC_VERB_GET_COEF_INDEX << 8);
+	return snd_hdac_exec_verb(codec, verb, 0, val);
+}
+
+/* write a pseudo coef register (16bit) */
+static int hda_reg_write_coef(struct hdac_device *codec, unsigned int reg,
+			      unsigned int val)
+{
+	unsigned int verb;
+	int err;
+
+	if (!codec->cache_coef)
+		return -EINVAL;
+	/* LSB 8bit = coef index */
+	verb = (reg & ~0xfff00) | (AC_VERB_SET_COEF_INDEX << 8);
+	err = snd_hdac_exec_verb(codec, verb, 0, NULL);
+	if (err < 0)
+		return err;
+	verb = (reg & ~0xfffff) | (AC_VERB_GET_COEF_INDEX << 8) |
+		(val & 0xffff);
+	return snd_hdac_exec_verb(codec, verb, 0, NULL);
+}
+
+static int hda_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+	struct hdac_device *codec = context;
+	int verb = get_verb(reg);
+	int err;
+
+	if (!codec_is_running(codec) && verb != AC_VERB_GET_POWER_STATE)
+		return -EAGAIN;
+	reg |= (codec->addr << 28);
+	if (is_stereo_amp_verb(reg))
+		return hda_reg_read_stereo_amp(codec, reg, val);
+	if (verb == AC_VERB_GET_PROC_COEF)
+		return hda_reg_read_coef(codec, reg, val);
+	err = snd_hdac_exec_verb(codec, reg, 0, val);
+	if (err < 0)
+		return err;
+	/* special handling for asymmetric reads */
+	if (verb == AC_VERB_GET_POWER_STATE) {
+		if (*val & AC_PWRST_ERROR)
+			*val = -1;
+		else /* take only the actual state */
+			*val = (*val >> 4) & 0x0f;
+	}
+	return 0;
+}
+
+static int hda_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+	struct hdac_device *codec = context;
+	unsigned int verb;
+	int i, bytes, err;
+
+	reg &= ~0x00080000U; /* drop GET bit */
+	reg |= (codec->addr << 28);
+	verb = get_verb(reg);
+
+	if (!codec_is_running(codec) && verb != AC_VERB_SET_POWER_STATE)
+		return codec->lazy_cache ? 0 : -EAGAIN;
+
+	if (is_stereo_amp_verb(reg))
+		return hda_reg_write_stereo_amp(codec, reg, val);
+
+	if (verb == AC_VERB_SET_PROC_COEF)
+		return hda_reg_write_coef(codec, reg, val);
+
+	switch (verb & 0xf00) {
+	case AC_VERB_SET_AMP_GAIN_MUTE:
+		verb = AC_VERB_SET_AMP_GAIN_MUTE;
+		if (reg & AC_AMP_GET_LEFT)
+			verb |= AC_AMP_SET_LEFT >> 8;
+		else
+			verb |= AC_AMP_SET_RIGHT >> 8;
+		if (reg & AC_AMP_GET_OUTPUT) {
+			verb |= AC_AMP_SET_OUTPUT >> 8;
+		} else {
+			verb |= AC_AMP_SET_INPUT >> 8;
+			verb |= reg & 0xf;
+		}
+		break;
+	}
+
+	switch (verb) {
+	case AC_VERB_SET_DIGI_CONVERT_1:
+		bytes = 2;
+		break;
+	case AC_VERB_SET_CONFIG_DEFAULT_BYTES_0:
+		bytes = 4;
+		break;
+	default:
+		bytes = 1;
+		break;
+	}
+
+	for (i = 0; i < bytes; i++) {
+		reg &= ~0xfffff;
+		reg |= (verb + i) << 8 | ((val >> (8 * i)) & 0xff);
+		err = snd_hdac_exec_verb(codec, reg, 0, NULL);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+static const struct regmap_config hda_regmap_cfg = {
+	.name = "hdaudio",
+	.reg_bits = 32,
+	.val_bits = 32,
+	.max_register = 0xfffffff,
+	.writeable_reg = hda_writeable_reg,
+	.readable_reg = hda_readable_reg,
+	.volatile_reg = hda_volatile_reg,
+	.cache_type = REGCACHE_RBTREE,
+	.reg_read = hda_reg_read,
+	.reg_write = hda_reg_write,
+	.use_single_rw = true,
+};
+
+int snd_hdac_regmap_init(struct hdac_device *codec)
+{
+	struct regmap *regmap;
+
+	regmap = regmap_init(&codec->dev, NULL, codec, &hda_regmap_cfg);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+	codec->regmap = regmap;
+	snd_array_init(&codec->vendor_verbs, sizeof(unsigned int), 8);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_regmap_init);
+
+void snd_hdac_regmap_exit(struct hdac_device *codec)
+{
+	if (codec->regmap) {
+		regmap_exit(codec->regmap);
+		codec->regmap = NULL;
+		snd_array_free(&codec->vendor_verbs);
+	}
+}
+EXPORT_SYMBOL_GPL(snd_hdac_regmap_exit);
+
+/**
+ * snd_hdac_regmap_add_vendor_verb - add a vendor-specific verb to regmap
+ * @codec: the codec object
+ * @verb: verb to allow accessing via regmap
+ *
+ * Returns zero for success or a negative error code.
+ */
+int snd_hdac_regmap_add_vendor_verb(struct hdac_device *codec,
+				    unsigned int verb)
+{
+	unsigned int *p = snd_array_new(&codec->vendor_verbs);
+
+	if (!p)
+		return -ENOMEM;
+	*p = verb | 0x800; /* set GET bit */
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_regmap_add_vendor_verb);
+
+/*
+ * helper functions
+ */
+
+/* write a pseudo-register value (w/o power sequence) */
+static int reg_raw_write(struct hdac_device *codec, unsigned int reg,
+			 unsigned int val)
+{
+	if (!codec->regmap)
+		return hda_reg_write(codec, reg, val);
+	else
+		return regmap_write(codec->regmap, reg, val);
+}
+
+/**
+ * snd_hdac_regmap_write_raw - write a pseudo register with power mgmt
+ * @codec: the codec object
+ * @reg: pseudo register
+ * @val: value to write
+ *
+ * Returns zero if successful or a negative error code.
+ */
+int snd_hdac_regmap_write_raw(struct hdac_device *codec, unsigned int reg,
+			      unsigned int val)
+{
+	int err;
+
+	err = reg_raw_write(codec, reg, val);
+	if (err == -EAGAIN) {
+		snd_hdac_power_up_pm(codec);
+		err = reg_raw_write(codec, reg, val);
+		snd_hdac_power_down_pm(codec);
+	}
+	return err;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_regmap_write_raw);
+
+static int reg_raw_read(struct hdac_device *codec, unsigned int reg,
+			unsigned int *val)
+{
+	if (!codec->regmap)
+		return hda_reg_read(codec, reg, val);
+	else
+		return regmap_read(codec->regmap, reg, val);
+}
+
+/**
+ * snd_hdac_regmap_read_raw - read a pseudo register with power mgmt
+ * @codec: the codec object
+ * @reg: pseudo register
+ * @val: pointer to store the read value
+ *
+ * Returns zero if successful or a negative error code.
+ */
+int snd_hdac_regmap_read_raw(struct hdac_device *codec, unsigned int reg,
+			     unsigned int *val)
+{
+	int err;
+
+	err = reg_raw_read(codec, reg, val);
+	if (err == -EAGAIN) {
+		snd_hdac_power_up_pm(codec);
+		err = reg_raw_read(codec, reg, val);
+		snd_hdac_power_down_pm(codec);
+	}
+	return err;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_regmap_read_raw);
+
+/**
+ * snd_hdac_regmap_update_raw - update a pseudo register with power mgmt
+ * @codec: the codec object
+ * @reg: pseudo register
+ * @mask: bit mask to udpate
+ * @val: value to update
+ *
+ * Returns zero if successful or a negative error code.
+ */
+int snd_hdac_regmap_update_raw(struct hdac_device *codec, unsigned int reg,
+			       unsigned int mask, unsigned int val)
+{
+	unsigned int orig;
+	int err;
+
+	val &= mask;
+	err = snd_hdac_regmap_read_raw(codec, reg, &orig);
+	if (err < 0)
+		return err;
+	val |= orig & ~mask;
+	if (val == orig)
+		return 0;
+	err = snd_hdac_regmap_write_raw(codec, reg, val);
+	if (err < 0)
+		return err;
+	return 1;
+}
+EXPORT_SYMBOL_GPL(snd_hdac_regmap_update_raw);

+ 406 - 0
sound/hda/hdac_sysfs.c

@@ -0,0 +1,406 @@
+/*
+ * sysfs support for HD-audio core device
+ */
+
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/hdaudio.h>
+#include "local.h"
+
+struct hdac_widget_tree {
+	struct kobject *root;
+	struct kobject *afg;
+	struct kobject **nodes;
+};
+
+#define CODEC_ATTR(type)					\
+static ssize_t type##_show(struct device *dev,			\
+			   struct device_attribute *attr,	\
+			   char *buf)				\
+{								\
+	struct hdac_device *codec = dev_to_hdac_dev(dev);	\
+	return sprintf(buf, "0x%x\n", codec->type);		\
+} \
+static DEVICE_ATTR_RO(type)
+
+#define CODEC_ATTR_STR(type)					\
+static ssize_t type##_show(struct device *dev,			\
+			     struct device_attribute *attr,	\
+					char *buf)		\
+{								\
+	struct hdac_device *codec = dev_to_hdac_dev(dev);	\
+	return sprintf(buf, "%s\n",				\
+		       codec->type ? codec->type : "");		\
+} \
+static DEVICE_ATTR_RO(type)
+
+CODEC_ATTR(type);
+CODEC_ATTR(vendor_id);
+CODEC_ATTR(subsystem_id);
+CODEC_ATTR(revision_id);
+CODEC_ATTR(afg);
+CODEC_ATTR(mfg);
+CODEC_ATTR_STR(vendor_name);
+CODEC_ATTR_STR(chip_name);
+
+static struct attribute *hdac_dev_attrs[] = {
+	&dev_attr_type.attr,
+	&dev_attr_vendor_id.attr,
+	&dev_attr_subsystem_id.attr,
+	&dev_attr_revision_id.attr,
+	&dev_attr_afg.attr,
+	&dev_attr_mfg.attr,
+	&dev_attr_vendor_name.attr,
+	&dev_attr_chip_name.attr,
+	NULL
+};
+
+static struct attribute_group hdac_dev_attr_group = {
+	.attrs	= hdac_dev_attrs,
+};
+
+const struct attribute_group *hdac_dev_attr_groups[] = {
+	&hdac_dev_attr_group,
+	NULL
+};
+
+/*
+ * Widget tree sysfs
+ *
+ * This is a tree showing the attributes of each widget.  It appears like
+ * /sys/bus/hdaudioC0D0/widgets/04/caps
+ */
+
+struct widget_attribute;
+
+struct widget_attribute {
+	struct attribute	attr;
+	ssize_t (*show)(struct hdac_device *codec, hda_nid_t nid,
+			struct widget_attribute *attr, char *buf);
+	ssize_t (*store)(struct hdac_device *codec, hda_nid_t nid,
+			 struct widget_attribute *attr,
+			 const char *buf, size_t count);
+};
+
+static int get_codec_nid(struct kobject *kobj, struct hdac_device **codecp)
+{
+	struct device *dev = kobj_to_dev(kobj->parent->parent);
+	int nid;
+	ssize_t ret;
+
+	ret = kstrtoint(kobj->name, 16, &nid);
+	if (ret < 0)
+		return ret;
+	*codecp = dev_to_hdac_dev(dev);
+	return nid;
+}
+
+static ssize_t widget_attr_show(struct kobject *kobj, struct attribute *attr,
+				char *buf)
+{
+	struct widget_attribute *wid_attr =
+		container_of(attr, struct widget_attribute, attr);
+	struct hdac_device *codec;
+	int nid;
+
+	if (!wid_attr->show)
+		return -EIO;
+	nid = get_codec_nid(kobj, &codec);
+	if (nid < 0)
+		return nid;
+	return wid_attr->show(codec, nid, wid_attr, buf);
+}
+
+static ssize_t widget_attr_store(struct kobject *kobj, struct attribute *attr,
+				 const char *buf, size_t count)
+{
+	struct widget_attribute *wid_attr =
+		container_of(attr, struct widget_attribute, attr);
+	struct hdac_device *codec;
+	int nid;
+
+	if (!wid_attr->store)
+		return -EIO;
+	nid = get_codec_nid(kobj, &codec);
+	if (nid < 0)
+		return nid;
+	return wid_attr->store(codec, nid, wid_attr, buf, count);
+}
+
+static const struct sysfs_ops widget_sysfs_ops = {
+	.show	= widget_attr_show,
+	.store	= widget_attr_store,
+};
+
+static void widget_release(struct kobject *kobj)
+{
+	kfree(kobj);
+}
+
+static struct kobj_type widget_ktype = {
+	.release	= widget_release,
+	.sysfs_ops	= &widget_sysfs_ops,
+};
+
+#define WIDGET_ATTR_RO(_name) \
+	struct widget_attribute wid_attr_##_name = __ATTR_RO(_name)
+#define WIDGET_ATTR_RW(_name) \
+	struct widget_attribute wid_attr_##_name = __ATTR_RW(_name)
+
+static ssize_t caps_show(struct hdac_device *codec, hda_nid_t nid,
+			struct widget_attribute *attr, char *buf)
+{
+	return sprintf(buf, "0x%08x\n", get_wcaps(codec, nid));
+}
+
+static ssize_t pin_caps_show(struct hdac_device *codec, hda_nid_t nid,
+			     struct widget_attribute *attr, char *buf)
+{
+	if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
+		return 0;
+	return sprintf(buf, "0x%08x\n",
+		       snd_hdac_read_parm(codec, nid, AC_PAR_PIN_CAP));
+}
+
+static ssize_t pin_cfg_show(struct hdac_device *codec, hda_nid_t nid,
+			    struct widget_attribute *attr, char *buf)
+{
+	unsigned int val;
+
+	if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
+		return 0;
+	if (snd_hdac_read(codec, nid, AC_VERB_GET_CONFIG_DEFAULT, 0, &val))
+		return 0;
+	return sprintf(buf, "0x%08x\n", val);
+}
+
+static bool has_pcm_cap(struct hdac_device *codec, hda_nid_t nid)
+{
+	if (nid == codec->afg || nid == codec->mfg)
+		return true;
+	switch (get_wcaps_type(get_wcaps(codec, nid))) {
+	case AC_WID_AUD_OUT:
+	case AC_WID_AUD_IN:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static ssize_t pcm_caps_show(struct hdac_device *codec, hda_nid_t nid,
+			     struct widget_attribute *attr, char *buf)
+{
+	if (!has_pcm_cap(codec, nid))
+		return 0;
+	return sprintf(buf, "0x%08x\n",
+		       snd_hdac_read_parm(codec, nid, AC_PAR_PCM));
+}
+
+static ssize_t pcm_formats_show(struct hdac_device *codec, hda_nid_t nid,
+				struct widget_attribute *attr, char *buf)
+{
+	if (!has_pcm_cap(codec, nid))
+		return 0;
+	return sprintf(buf, "0x%08x\n",
+		       snd_hdac_read_parm(codec, nid, AC_PAR_STREAM));
+}
+
+static ssize_t amp_in_caps_show(struct hdac_device *codec, hda_nid_t nid,
+				struct widget_attribute *attr, char *buf)
+{
+	if (nid != codec->afg && !(get_wcaps(codec, nid) & AC_WCAP_IN_AMP))
+		return 0;
+	return sprintf(buf, "0x%08x\n",
+		       snd_hdac_read_parm(codec, nid, AC_PAR_AMP_IN_CAP));
+}
+
+static ssize_t amp_out_caps_show(struct hdac_device *codec, hda_nid_t nid,
+				 struct widget_attribute *attr, char *buf)
+{
+	if (nid != codec->afg && !(get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
+		return 0;
+	return sprintf(buf, "0x%08x\n",
+		       snd_hdac_read_parm(codec, nid, AC_PAR_AMP_OUT_CAP));
+}
+
+static ssize_t power_caps_show(struct hdac_device *codec, hda_nid_t nid,
+			       struct widget_attribute *attr, char *buf)
+{
+	if (nid != codec->afg && !(get_wcaps(codec, nid) & AC_WCAP_POWER))
+		return 0;
+	return sprintf(buf, "0x%08x\n",
+		       snd_hdac_read_parm(codec, nid, AC_PAR_POWER_STATE));
+}
+
+static ssize_t gpio_caps_show(struct hdac_device *codec, hda_nid_t nid,
+			      struct widget_attribute *attr, char *buf)
+{
+	return sprintf(buf, "0x%08x\n",
+		       snd_hdac_read_parm(codec, nid, AC_PAR_GPIO_CAP));
+}
+
+static ssize_t connections_show(struct hdac_device *codec, hda_nid_t nid,
+				struct widget_attribute *attr, char *buf)
+{
+	hda_nid_t list[32];
+	int i, nconns;
+	ssize_t ret = 0;
+
+	nconns = snd_hdac_get_connections(codec, nid, list, ARRAY_SIZE(list));
+	if (nconns <= 0)
+		return nconns;
+	for (i = 0; i < nconns; i++)
+		ret += sprintf(buf + ret, "%s0x%02x", i ? " " : "", list[i]);
+	ret += sprintf(buf + ret, "\n");
+	return ret;
+}
+
+static WIDGET_ATTR_RO(caps);
+static WIDGET_ATTR_RO(pin_caps);
+static WIDGET_ATTR_RO(pin_cfg);
+static WIDGET_ATTR_RO(pcm_caps);
+static WIDGET_ATTR_RO(pcm_formats);
+static WIDGET_ATTR_RO(amp_in_caps);
+static WIDGET_ATTR_RO(amp_out_caps);
+static WIDGET_ATTR_RO(power_caps);
+static WIDGET_ATTR_RO(gpio_caps);
+static WIDGET_ATTR_RO(connections);
+
+static struct attribute *widget_node_attrs[] = {
+	&wid_attr_caps.attr,
+	&wid_attr_pin_caps.attr,
+	&wid_attr_pin_cfg.attr,
+	&wid_attr_pcm_caps.attr,
+	&wid_attr_pcm_formats.attr,
+	&wid_attr_amp_in_caps.attr,
+	&wid_attr_amp_out_caps.attr,
+	&wid_attr_power_caps.attr,
+	&wid_attr_connections.attr,
+	NULL,
+};
+
+static struct attribute *widget_afg_attrs[] = {
+	&wid_attr_pcm_caps.attr,
+	&wid_attr_pcm_formats.attr,
+	&wid_attr_amp_in_caps.attr,
+	&wid_attr_amp_out_caps.attr,
+	&wid_attr_power_caps.attr,
+	&wid_attr_gpio_caps.attr,
+	NULL,
+};
+
+static const struct attribute_group widget_node_group = {
+	.attrs = widget_node_attrs,
+};
+
+static const struct attribute_group widget_afg_group = {
+	.attrs = widget_afg_attrs,
+};
+
+static void free_widget_node(struct kobject *kobj,
+			     const struct attribute_group *group)
+{
+	if (kobj) {
+		sysfs_remove_group(kobj, group);
+		kobject_put(kobj);
+	}
+}
+
+static void widget_tree_free(struct hdac_device *codec)
+{
+	struct hdac_widget_tree *tree = codec->widgets;
+	struct kobject **p;
+
+	if (!tree)
+		return;
+	free_widget_node(tree->afg, &widget_afg_group);
+	if (tree->nodes) {
+		for (p = tree->nodes; *p; p++)
+			free_widget_node(*p, &widget_node_group);
+		kfree(tree->nodes);
+	}
+	if (tree->root)
+		kobject_put(tree->root);
+	kfree(tree);
+	codec->widgets = NULL;
+}
+
+static int add_widget_node(struct kobject *parent, hda_nid_t nid,
+			   const struct attribute_group *group,
+			   struct kobject **res)
+{
+	struct kobject *kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
+	int err;
+
+	if (!kobj)
+		return -ENOMEM;
+	kobject_init(kobj, &widget_ktype);
+	err = kobject_add(kobj, parent, "%02x", nid);
+	if (err < 0)
+		return err;
+	err = sysfs_create_group(kobj, group);
+	if (err < 0) {
+		kobject_put(kobj);
+		return err;
+	}
+
+	*res = kobj;
+	return 0;
+}
+
+static int widget_tree_create(struct hdac_device *codec)
+{
+	struct hdac_widget_tree *tree;
+	int i, err;
+	hda_nid_t nid;
+
+	tree = codec->widgets = kzalloc(sizeof(*tree), GFP_KERNEL);
+	if (!tree)
+		return -ENOMEM;
+
+	tree->root = kobject_create_and_add("widgets", &codec->dev.kobj);
+	if (!tree->root)
+		return -ENOMEM;
+
+	tree->nodes = kcalloc(codec->num_nodes + 1, sizeof(*tree->nodes),
+			      GFP_KERNEL);
+	if (!tree->nodes)
+		return -ENOMEM;
+
+	for (i = 0, nid = codec->start_nid; i < codec->num_nodes; i++, nid++) {
+		err = add_widget_node(tree->root, nid, &widget_node_group,
+				      &tree->nodes[i]);
+		if (err < 0)
+			return err;
+	}
+
+	if (codec->afg) {
+		err = add_widget_node(tree->root, codec->afg,
+				      &widget_afg_group, &tree->afg);
+		if (err < 0)
+			return err;
+	}
+
+	kobject_uevent(tree->root, KOBJ_CHANGE);
+	return 0;
+}
+
+int hda_widget_sysfs_init(struct hdac_device *codec)
+{
+	int err;
+
+	err = widget_tree_create(codec);
+	if (err < 0) {
+		widget_tree_free(codec);
+		return err;
+	}
+
+	return 0;
+}
+
+void hda_widget_sysfs_exit(struct hdac_device *codec)
+{
+	widget_tree_free(codec);
+}

+ 23 - 0
sound/hda/local.h

@@ -0,0 +1,23 @@
+/*
+ * Local helper macros and functions for HD-audio core drivers
+ */
+
+#ifndef __HDAC_LOCAL_H
+#define __HDAC_LOCAL_H
+
+#define get_wcaps(codec, nid) \
+	snd_hdac_read_parm(codec, nid, AC_PAR_AUDIO_WIDGET_CAP)
+
+/* get the widget type from widget capability bits */
+static inline int get_wcaps_type(unsigned int wcaps)
+{
+	if (!wcaps)
+		return -1; /* invalid type */
+	return (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+}
+
+extern const struct attribute_group *hdac_dev_attr_groups[];
+int hda_widget_sysfs_init(struct hdac_device *codec);
+void hda_widget_sysfs_exit(struct hdac_device *codec);
+
+#endif /* __HDAC_LOCAL_H */

+ 6 - 0
sound/hda/trace.c

@@ -0,0 +1,6 @@
+/*
+ * tracepoint definitions for HD-audio core drivers
+ */
+
+#define CREATE_TRACE_POINTS
+#include "trace.h"

+ 62 - 0
sound/hda/trace.h

@@ -0,0 +1,62 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM hda
+
+#if !defined(__HDAC_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define __HDAC_TRACE_H
+
+#include <linux/tracepoint.h>
+#include <linux/device.h>
+#include <sound/hdaudio.h>
+
+#ifndef HDAC_MSG_MAX
+#define HDAC_MSG_MAX	500
+#endif
+
+struct hdac_bus;
+struct hdac_codec;
+
+TRACE_EVENT(hda_send_cmd,
+	TP_PROTO(struct hdac_bus *bus, unsigned int cmd),
+	TP_ARGS(bus, cmd),
+	TP_STRUCT__entry(__dynamic_array(char, msg, HDAC_MSG_MAX)),
+	TP_fast_assign(
+		snprintf(__get_str(msg), HDAC_MSG_MAX,
+			 "[%s:%d] val=0x%08x",
+			 dev_name((bus)->dev), (cmd) >> 28, cmd);
+	),
+	TP_printk("%s", __get_str(msg))
+);
+
+TRACE_EVENT(hda_get_response,
+	TP_PROTO(struct hdac_bus *bus, unsigned int addr, unsigned int res),
+	TP_ARGS(bus, addr, res),
+	TP_STRUCT__entry(__dynamic_array(char, msg, HDAC_MSG_MAX)),
+	TP_fast_assign(
+		snprintf(__get_str(msg), HDAC_MSG_MAX,
+			 "[%s:%d] val=0x%08x",
+			 dev_name((bus)->dev), addr, res);
+	),
+	TP_printk("%s", __get_str(msg))
+);
+
+TRACE_EVENT(hda_unsol_event,
+	TP_PROTO(struct hdac_bus *bus, u32 res, u32 res_ex),
+	TP_ARGS(bus, res, res_ex),
+	TP_STRUCT__entry(__dynamic_array(char, msg, HDAC_MSG_MAX)),
+	TP_fast_assign(
+		snprintf(__get_str(msg), HDAC_MSG_MAX,
+			 "[%s:%d] res=0x%08x, res_ex=0x%08x",
+			 dev_name((bus)->dev), res_ex & 0x0f, res, res_ex);
+	),
+	TP_printk("%s", __get_str(msg))
+);
+#endif /* __HDAC_TRACE_H */
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+#include <trace/define_trace.h>

+ 2 - 2
sound/i2c/other/ak4113.c

@@ -73,7 +73,7 @@ int snd_ak4113_create(struct snd_card *card, ak4113_read_t *read,
 		void *private_data, struct ak4113 **r_ak4113)
 {
 	struct ak4113 *chip;
-	int err = 0;
+	int err;
 	unsigned char reg;
 	static struct snd_device_ops ops = {
 		.dev_free =     snd_ak4113_dev_free,
@@ -109,7 +109,7 @@ int snd_ak4113_create(struct snd_card *card, ak4113_read_t *read,
 
 __fail:
 	snd_ak4113_free(chip);
-	return err < 0 ? err : -EIO;
+	return err;
 }
 EXPORT_SYMBOL_GPL(snd_ak4113_create);
 

+ 15 - 20
sound/isa/sb/emu8000_synth.c

@@ -34,8 +34,9 @@ MODULE_LICENSE("GPL");
 /*
  * create a new hardware dependent device for Emu8000
  */
-static int snd_emu8000_new_device(struct snd_seq_device *dev)
+static int snd_emu8000_probe(struct device *_dev)
 {
+	struct snd_seq_device *dev = to_seq_dev(_dev);
 	struct snd_emu8000 *hw;
 	struct snd_emux *emu;
 
@@ -93,8 +94,9 @@ static int snd_emu8000_new_device(struct snd_seq_device *dev)
 /*
  * free all resources
  */
-static int snd_emu8000_delete_device(struct snd_seq_device *dev)
+static int snd_emu8000_remove(struct device *_dev)
 {
+	struct snd_seq_device *dev = to_seq_dev(_dev);
 	struct snd_emu8000 *hw;
 
 	if (dev->driver_data == NULL)
@@ -114,21 +116,14 @@ static int snd_emu8000_delete_device(struct snd_seq_device *dev)
  *  INIT part
  */
 
-static int __init alsa_emu8000_init(void)
-{
-	
-	static struct snd_seq_dev_ops ops = {
-		snd_emu8000_new_device,
-		snd_emu8000_delete_device,
-	};
-	return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_EMU8000, &ops,
-					      sizeof(struct snd_emu8000*));
-}
-
-static void __exit alsa_emu8000_exit(void)
-{
-	snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_EMU8000);
-}
-
-module_init(alsa_emu8000_init)
-module_exit(alsa_emu8000_exit)
+static struct snd_seq_driver emu8000_driver = {
+	.driver = {
+		.name = KBUILD_MODNAME,
+		.probe = snd_emu8000_probe,
+		.remove = snd_emu8000_remove,
+	},
+	.id = SNDRV_SEQ_DEV_ID_EMU8000,
+	.argsize = sizeof(struct snd_emu8000 *),
+};
+
+module_snd_seq_driver(emu8000_driver);

+ 3 - 3
sound/isa/wavefront/wavefront_fx.c

@@ -79,13 +79,13 @@ wavefront_fx_memset (snd_wavefront_t *dev,
 	if (page < 0 || page > 7) {
 		snd_printk ("FX memset: "
 			"page must be >= 0 and <= 7\n");
-		return -(EINVAL);
+		return -EINVAL;
 	}
 
 	if (addr < 0 || addr > 0x7f) {
 		snd_printk ("FX memset: "
 			"addr must be >= 0 and <= 7f\n");
-		return -(EINVAL);
+		return -EINVAL;
 	}
 
 	if (cnt == 1) {
@@ -118,7 +118,7 @@ wavefront_fx_memset (snd_wavefront_t *dev,
 			snd_printk ("FX memset "
 				    "(0x%x, 0x%x, 0x%lx, %d) incomplete\n",
 				    page, addr, (unsigned long) data, cnt);
-			return -(EIO);
+			return -EIO;
 		}
 	}
 

+ 13 - 13
sound/isa/wavefront/wavefront_synth.c

@@ -793,7 +793,7 @@ wavefront_send_patch (snd_wavefront_t *dev, wavefront_patch_info *header)
     
 	if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_PATCH, NULL, buf)) {
 		snd_printk ("download patch failed\n");
-		return -(EIO);
+		return -EIO;
 	}
 
 	return (0);
@@ -831,7 +831,7 @@ wavefront_send_program (snd_wavefront_t *dev, wavefront_patch_info *header)
     
 	if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_PROGRAM, NULL, buf)) {
 		snd_printk ("download patch failed\n");	
-		return -(EIO);
+		return -EIO;
 	}
 
 	return (0);
@@ -952,7 +952,7 @@ wavefront_send_sample (snd_wavefront_t *dev,
 	if (skip > 0 && header->hdr.s.SampleResolution != LINEAR_16BIT) {
 		snd_printk ("channel selection only "
 			    "possible on 16-bit samples");
-		return -(EINVAL);
+		return -EINVAL;
 	}
 
 	switch (skip) {
@@ -1049,7 +1049,7 @@ wavefront_send_sample (snd_wavefront_t *dev,
 			   NULL, sample_hdr)) {
 		snd_printk ("sample %sdownload refused.\n",
 			    header->size ? "" : "header ");
-		return -(EIO);
+		return -EIO;
 	}
 
 	if (header->size == 0) {
@@ -1075,7 +1075,7 @@ wavefront_send_sample (snd_wavefront_t *dev,
 		if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_BLOCK, NULL, NULL)) {
 			snd_printk ("download block "
 				    "request refused.\n");
-			return -(EIO);
+			return -EIO;
 		}
 
 		for (i = 0; i < blocksize; i++) {
@@ -1135,12 +1135,12 @@ wavefront_send_sample (snd_wavefront_t *dev,
 			if (dma_ack == -1) {
 				snd_printk ("upload sample "
 					    "DMA ack timeout\n");
-				return -(EIO);
+				return -EIO;
 			} else {
 				snd_printk ("upload sample "
 					    "DMA ack error 0x%x\n",
 					    dma_ack);
-				return -(EIO);
+				return -EIO;
 			}
 		}
 	}
@@ -1181,7 +1181,7 @@ wavefront_send_alias (snd_wavefront_t *dev, wavefront_patch_info *header)
 
 	if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_SAMPLE_ALIAS, NULL, alias_hdr)) {
 		snd_printk ("download alias failed.\n");
-		return -(EIO);
+		return -EIO;
 	}
 
 	dev->sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_ALIAS);
@@ -1232,7 +1232,7 @@ wavefront_send_multisample (snd_wavefront_t *dev, wavefront_patch_info *header)
 			   msample_hdr)) {
 		snd_printk ("download of multisample failed.\n");
 		kfree(msample_hdr);
-		return -(EIO);
+		return -EIO;
 	}
 
 	dev->sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_MULTISAMPLE);
@@ -1254,7 +1254,7 @@ wavefront_fetch_multisample (snd_wavefront_t *dev,
     
 	if (snd_wavefront_cmd (dev, WFC_UPLOAD_MULTISAMPLE, log_ns, number)) {
 		snd_printk ("upload multisample failed.\n");
-		return -(EIO);
+		return -EIO;
 	}
     
 	DPRINT (WF_DEBUG_DATA, "msample %d has %d samples\n",
@@ -1273,14 +1273,14 @@ wavefront_fetch_multisample (snd_wavefront_t *dev,
 		if ((val = wavefront_read (dev)) == -1) {
 			snd_printk ("upload multisample failed "
 				    "during sample loop.\n");
-			return -(EIO);
+			return -EIO;
 		}
 		d[0] = val;
 
 		if ((val = wavefront_read (dev)) == -1) {
 			snd_printk ("upload multisample failed "
 				    "during sample loop.\n");
-			return -(EIO);
+			return -EIO;
 		}
 		d[1] = val;
 	
@@ -1315,7 +1315,7 @@ wavefront_send_drum (snd_wavefront_t *dev, wavefront_patch_info *header)
 
 	if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_EDRUM_PROGRAM, NULL, drumbuf)) {
 		snd_printk ("download drum failed.\n");
-		return -(EIO);
+		return -EIO;
 	}
 
 	return (0);

+ 9 - 3
sound/mips/au1x00.c

@@ -633,19 +633,25 @@ static int au1000_ac97_probe(struct platform_device *pdev)
 
 	au1000->stream[PLAYBACK] = kmalloc(sizeof(struct audio_stream),
 					   GFP_KERNEL);
-	if (!au1000->stream[PLAYBACK])
+	if (!au1000->stream[PLAYBACK]) {
+		err = -ENOMEM;
 		goto out;
+	}
 	au1000->stream[PLAYBACK]->dma = -1;
 
 	au1000->stream[CAPTURE] = kmalloc(sizeof(struct audio_stream),
 					  GFP_KERNEL);
-	if (!au1000->stream[CAPTURE])
+	if (!au1000->stream[CAPTURE]) {
+		err = -ENOMEM;
 		goto out;
+	}
 	au1000->stream[CAPTURE]->dma = -1;
 
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!r)
+	if (!r) {
+		err = -ENODEV;
 		goto out;
+	}
 
 	err = -EBUSY;
 	au1000->ac97_res_port = request_mem_region(r->start, resource_size(r),

+ 3 - 3
sound/oss/dev_table.c

@@ -58,13 +58,13 @@ int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver,
 
 	if (vers != AUDIO_DRIVER_VERSION || driver_size > sizeof(struct audio_driver)) {
 		printk(KERN_ERR "Sound: Incompatible audio driver for %s\n", name);
-		return -(EINVAL);
+		return -EINVAL;
 	}
 	num = sound_alloc_audiodev();
 
 	if (num == -1) {
 		printk(KERN_ERR "sound: Too many audio drivers\n");
-		return -(EBUSY);
+		return -EBUSY;
 	}
 	d = (struct audio_driver *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct audio_driver)));
 	sound_nblocks++;
@@ -79,7 +79,7 @@ int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver,
 	if (d == NULL || op == NULL) {
 		printk(KERN_ERR "Sound: Can't allocate driver for (%s)\n", name);
 		sound_unload_audiodev(num);
-		return -(ENOMEM);
+		return -ENOMEM;
 	}
 	init_waitqueue_head(&op->in_sleeper);
 	init_waitqueue_head(&op->out_sleeper);	

+ 2 - 2
sound/oss/opl3.c

@@ -666,7 +666,7 @@ static int opl3_start_note (int dev, int voice, int note, int volume)
 	opl3_command(map->ioaddr, FNUM_LOW + map->voice_num, data);
 
 	data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3);
-		 devc->voc[voice].keyon_byte = data;
+	devc->voc[voice].keyon_byte = data;
 	opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num, data);
 	if (voice_mode == 4)
 		opl3_command(map->ioaddr, KEYON_BLOCK + map->voice_num + 3, data);
@@ -717,7 +717,7 @@ static void freq_to_fnum    (int freq, int *block, int *fnum)
 
 static void opl3_command    (int io_addr, unsigned int addr, unsigned int val)
 {
-	 int i;
+	int i;
 
 	/*
 	 * The original 2-OP synth requires a quite long delay after writing to a

+ 7 - 12
sound/oss/sb_ess.c

@@ -604,7 +604,7 @@ static void ess_audio_output_block_audio2
 	ess_chgmixer (devc, 0x78, 0x03, 0x03);   /* Go */
 
 	devc->irq_mode_16 = IMODE_OUTPUT;
-		devc->intr_active_16 = 1;
+	devc->intr_active_16 = 1;
 }
 
 static void ess_audio_output_block
@@ -1183,17 +1183,12 @@ FKS_test (devc);
 			chip = "ES1688";
 		}
 
-	    printk ( KERN_INFO "ESS chip %s %s%s\n"
-               , chip
-               , ( devc->sbmo.esstype == ESSTYPE_DETECT || devc->sbmo.esstype == ESSTYPE_LIKE20
-                 ? "detected"
-                 : "specified"
-                 )
-               , ( devc->sbmo.esstype == ESSTYPE_LIKE20
-                 ? " (kernel 2.0 compatible)"
-                 : ""
-                 )
-               );
+		printk(KERN_INFO "ESS chip %s %s%s\n", chip,
+		       (devc->sbmo.esstype == ESSTYPE_DETECT ||
+			devc->sbmo.esstype == ESSTYPE_LIKE20) ?
+				"detected" : "specified",
+			devc->sbmo.esstype == ESSTYPE_LIKE20 ?
+				" (kernel 2.0 compatible)" : "");
 
 		sprintf(name,"ESS %s AudioDrive (rev %d)", chip, ess_minor & 0x0f);
 	} else {

+ 3 - 3
sound/oss/sb_midi.c

@@ -179,14 +179,14 @@ void sb_dsp_midi_init(sb_devc * devc, struct module *owner)
 	{
 		printk(KERN_WARNING "Sound Blaster:  failed to allocate MIDI memory.\n");
 		sound_unload_mididev(dev);
-		  return;
+		return;
 	}
 	memcpy((char *) midi_devs[dev], (char *) &sb_midi_operations,
 	       sizeof(struct midi_operations));
 
 	if (owner)
-			midi_devs[dev]->owner = owner;
-	
+		midi_devs[dev]->owner = owner;
+
 	midi_devs[dev]->devc = devc;
 
 

+ 15 - 20
sound/oss/sys_timer.c

@@ -50,29 +50,24 @@ tmr2ticks(int tmr_value)
 static void
 poll_def_tmr(unsigned long dummy)
 {
+	if (!opened)
+		return;
+	def_tmr.expires = (1) + jiffies;
+	add_timer(&def_tmr);
 
-	if (opened)
-	  {
+	if (!tmr_running)
+		return;
 
-		  {
-			  def_tmr.expires = (1) + jiffies;
-			  add_timer(&def_tmr);
-		  }
+	spin_lock(&lock);
+	tmr_ctr++;
+	curr_ticks = ticks_offs + tmr2ticks(tmr_ctr);
 
-		  if (tmr_running)
-		    {
-				spin_lock(&lock);
-			    tmr_ctr++;
-			    curr_ticks = ticks_offs + tmr2ticks(tmr_ctr);
-
-			    if (curr_ticks >= next_event_time)
-			      {
-				      next_event_time = (unsigned long) -1;
-				      sequencer_timer(0);
-			      }
-				spin_unlock(&lock);
-		    }
-	  }
+	if (curr_ticks >= next_event_time) {
+		next_event_time = (unsigned long) -1;
+		sequencer_timer(0);
+	}
+
+	spin_unlock(&lock);
 }
 
 static void

+ 2 - 2
sound/oss/v_midi.c

@@ -49,13 +49,13 @@ static int v_midi_open (int dev, int mode,
 	unsigned long flags;
 
 	if (devc == NULL)
-		return -(ENXIO);
+		return -ENXIO;
 
 	spin_lock_irqsave(&devc->lock,flags);
 	if (devc->opened)
 	{
 		spin_unlock_irqrestore(&devc->lock,flags);
-		return -(EBUSY);
+		return -EBUSY;
 	}
 	devc->opened = 1;
 	spin_unlock_irqrestore(&devc->lock,flags);

+ 3 - 1
sound/pci/ac97/ac97_codec.c

@@ -177,6 +177,7 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = {
 { 0x54524123, 0xffffffff, "TR28602",		NULL,		NULL }, // only guess --jk [TR28023 = eMicro EM28023 (new CT1297)]
 { 0x54584e03, 0xffffffff, "TLV320AIC27",	NULL,		NULL },
 { 0x54584e20, 0xffffffff, "TLC320AD9xC",	NULL,		NULL },
+{ 0x56494120, 0xfffffff0, "VIA1613",		patch_vt1613,	NULL },
 { 0x56494161, 0xffffffff, "VIA1612A",		NULL,		NULL }, // modified ICE1232 with S/PDIF
 { 0x56494170, 0xffffffff, "VIA1617A",		patch_vt1617a,	NULL }, // modified VT1616 with S/PDIF
 { 0x56494182, 0xffffffff, "VIA1618",		patch_vt1618,   NULL },
@@ -2901,7 +2902,8 @@ static int apply_quirk_str(struct snd_ac97 *ac97, const char *typestr)
  * Return: Zero if successful, or a negative error code on failure.
  */
 
-int snd_ac97_tune_hardware(struct snd_ac97 *ac97, struct ac97_quirk *quirk, const char *override)
+int snd_ac97_tune_hardware(struct snd_ac97 *ac97,
+			   const struct ac97_quirk *quirk, const char *override)
 {
 	int result;
 

+ 27 - 0
sound/pci/ac97/ac97_patch.c

@@ -3351,6 +3351,33 @@ static int patch_cm9780(struct snd_ac97 *ac97)
 	return 0;
 }
 
+/*
+ * VIA VT1613 codec
+ */
+static const struct snd_kcontrol_new snd_ac97_controls_vt1613[] = {
+AC97_SINGLE("DC Offset removal", 0x5a, 10, 1, 0),
+};
+
+static int patch_vt1613_specific(struct snd_ac97 *ac97)
+{
+	return patch_build_controls(ac97, &snd_ac97_controls_vt1613[0],
+				    ARRAY_SIZE(snd_ac97_controls_vt1613));
+};
+
+static const struct snd_ac97_build_ops patch_vt1613_ops = {
+	.build_specific	= patch_vt1613_specific
+};
+
+static int patch_vt1613(struct snd_ac97 *ac97)
+{
+	ac97->build_ops = &patch_vt1613_ops;
+
+	ac97->flags |= AC97_HAS_NO_VIDEO;
+	ac97->caps |= AC97_BC_HEADPHONE;
+
+	return 0;
+}
+
 /*
  * VIA VT1616 codec
  */

+ 1 - 1
sound/pci/ad1889.c

@@ -747,7 +747,7 @@ snd_ad1889_proc_init(struct snd_ad1889 *chip)
 		snd_info_set_text_ops(entry, chip, snd_ad1889_proc_read);
 }
 
-static struct ac97_quirk ac97_quirks[] = {
+static const struct ac97_quirk ac97_quirks[] = {
 	{
 		.subvendor = 0x11d4,	/* AD */
 		.subdevice = 0x1889,	/* AD1889 */

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

@@ -2376,7 +2376,7 @@ static int snd_asihpi_cmode_add(struct snd_card_asihpi *asihpi,
 /*------------------------------------------------------------
    Sampleclock source  controls
  ------------------------------------------------------------*/
-static const char const *sampleclock_sources[] = {
+static const char * const sampleclock_sources[] = {
 	"N/A", "Local PLL", "Digital Sync", "Word External", "Word Header",
 	"SMPTE", "Digital1", "Auto", "Network", "Invalid",
 	"Prev Module", "BLU-Link",

+ 1 - 1
sound/pci/atiixp.c

@@ -1390,7 +1390,7 @@ static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id)
  * ac97 mixer section
  */
 
-static struct ac97_quirk ac97_quirks[] = {
+static const struct ac97_quirk ac97_quirks[] = {
 	{
 		.subvendor = 0x103c,
 		.subdevice = 0x006b,

+ 4 - 3
sound/pci/azt3328.c

@@ -1385,8 +1385,8 @@ snd_azf3328_ctrl_codec_activity(struct snd_azf3328 *chip,
 					.running)
 			     &&  (!chip->codecs[peer_codecs[codec_type].other2]
 					.running));
-		 }
-		 if (call_function)
+		}
+		if (call_function)
 			snd_azf3328_ctrl_enable_codecs(chip, enable);
 
 		/* ...and adjust clock, too
@@ -2126,7 +2126,8 @@ static struct snd_pcm_ops snd_azf3328_i2s_out_ops = {
 static int
 snd_azf3328_pcm(struct snd_azf3328 *chip)
 {
-enum { AZF_PCMDEV_STD, AZF_PCMDEV_I2S_OUT, NUM_AZF_PCMDEVS }; /* pcm devices */
+	/* pcm devices */
+	enum { AZF_PCMDEV_STD, AZF_PCMDEV_I2S_OUT, NUM_AZF_PCMDEVS };
 
 	struct snd_pcm *pcm;
 	int err;

+ 1 - 1
sound/pci/cmipci.c

@@ -2062,7 +2062,7 @@ static int snd_cmipci_get_volume(struct snd_kcontrol *kcontrol,
 		val = (snd_cmipci_mixer_read(cm, reg.right_reg) >> reg.right_shift) & reg.mask;
 		if (reg.invert)
 			val = reg.mask - val;
-		 ucontrol->value.integer.value[1] = val;
+		ucontrol->value.integer.value[1] = val;
 	}
 	spin_unlock_irq(&cm->reg_lock);
 	return 0;

部分文件因文件數量過多而無法顯示