Explorar o código

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

Pull sound updates from Takashi Iwai:
 "This development cycle resulted in a fair amount of changes in both
  core and driver sides. The most significant change in ALSA core is
  about PCM. Also the support of of-graph card and the new DAPM widget
  for DSP are noteworthy changes in ASoC core. And there're lots of
  small changes splat over the tree, as you can see in diffstat.

  Below are a few highlights:

  ALSA core:
   - Removal of set_fs() hackery from PCM core stuff, and the code
     reorganization / optimization thereafter
   - Improved support of PCM ack ops, and a new ABI for improved
     control/status mmap handling
   - Lots of constifications in various codes

  ASoC core:
   - The support of of-graph card, which may work as a better generic
     device for a replacement of simple-card
   - New widget types intended mainly for use with DSPs

  ASoC drivers:
   - New drivers for Allwinner V3s SoCs
   - Ensonic ES8316 codec support
   - More Intel SKL and KBL works
   - More device support for Intel SST Atom (mostly for cheap tablets
     and 2-in-1 devices)
   - Support for Rockchip PDM controllers
   - Support for STM32 I2S and S/PDIF controllers
   - Support for ZTE AUD96P22 codecs

  HD-audio:
   - Support of new Realtek codecs (ALC215/ALC285/ALC289), more quirks
     for HP and Dell machines
   - A few more fixes for i915 component binding"

* tag 'sound-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (418 commits)
  ALSA: hda - Fix unbalance of i915 module refcount
  ASoC: Intel: Skylake: Remove driver debugfs exit
  ASoC: Intel: Skylake: explicitly add the headers sst-dsp.h
  ALSA: hda/realtek - Remove GPIO_MASK
  ALSA: hda/realtek - Fix typo of pincfg for Dell quirk
  ALSA: pcm: add a documentation for tracepoints
  ALSA: atmel: ac97c: fix error return code in atmel_ac97c_probe()
  ALSA: x86: fix error return code in hdmi_lpe_audio_probe()
  ASoC: Intel: Skylake: Add support to read firmware registers
  ASoC: Intel: Skylake: Add sram address to sst_addr structure
  ASoC: Intel: Skylake: Debugfs facility to dump module config
  ASoC: Intel: Skylake: Add debugfs support
  ASoC: fix semicolon.cocci warnings
  ASoC: rt5645: Add quirk override by module option
  ASoC: rsnd: make arrays path and cmd_case static const
  ASoC: audio-graph-card: add widgets and routing for external amplifier support
  ASoC: audio-graph-card: update bindings for amplifier support
  ASoC: rt5665: calibration should be done before jack detection
  ASoC: rsnd: constify dev_pm_ops structures.
  ASoC: nau8825: change crosstalk-bypass property to bool type
  ...
Linus Torvalds %!s(int64=8) %!d(string=hai) anos
pai
achega
920f2ecdf6
Modificáronse 100 ficheiros con 2522 adicións e 2867 borrados
  1. 8 0
      Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt
  2. 8 1
      Documentation/devicetree/bindings/display/bridge/renesas,dw-hdmi.txt
  3. 129 0
      Documentation/devicetree/bindings/sound/audio-graph-card.txt
  4. 122 0
      Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt
  5. 3 0
      Documentation/devicetree/bindings/sound/cs35l35.txt
  6. 3 0
      Documentation/devicetree/bindings/sound/nau8825.txt
  7. 22 15
      Documentation/devicetree/bindings/sound/renesas,rsnd.txt
  8. 39 0
      Documentation/devicetree/bindings/sound/rockchip,pdm.txt
  9. 2 0
      Documentation/devicetree/bindings/sound/rockchip-spdif.txt
  10. 8 7
      Documentation/devicetree/bindings/sound/samsung,odroid.txt
  11. 25 42
      Documentation/devicetree/bindings/sound/simple-scu-card.txt
  12. 62 0
      Documentation/devicetree/bindings/sound/st,stm32-i2s.txt
  13. 18 23
      Documentation/devicetree/bindings/sound/st,stm32-sai.txt
  14. 56 0
      Documentation/devicetree/bindings/sound/st,stm32-spdifrx.txt
  15. 7 4
      Documentation/devicetree/bindings/sound/sun4i-codec.txt
  16. 1 0
      Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt
  17. 24 0
      Documentation/devicetree/bindings/sound/zte,zx-aud96p22.txt
  18. 1 0
      Documentation/sound/designs/index.rst
  19. 172 0
      Documentation/sound/designs/tracepoints.rst
  20. 76 35
      Documentation/sound/kernel-api/writing-an-alsa-driver.rst
  21. 18 0
      Documentation/sound/soc/dapm.rst
  22. 1 6
      drivers/dma/dw/Kconfig
  23. 2 330
      drivers/dma/dw/core.c
  24. 11 39
      drivers/dma/dw/regs.h
  25. 22 0
      drivers/gpu/drm/bridge/adv7511/adv7511_audio.c
  26. 21 0
      drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c
  27. 24 8
      drivers/media/pci/solo6x10/solo6x10-g723.c
  28. 52 10
      drivers/of/base.c
  29. 2 3
      drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c
  30. 1 6
      drivers/usb/gadget/function/u_uac1_legacy.c
  31. 0 21
      include/linux/dma/dw.h
  32. 21 0
      include/linux/of_graph.h
  33. 9 4
      include/sound/ak4113.h
  34. 9 4
      include/sound/ak4114.h
  35. 9 4
      include/sound/ak4117.h
  36. 3 3
      include/sound/core.h
  37. 2 0
      include/sound/cs35l35.h
  38. 1 0
      include/sound/designware_i2s.h
  39. 3 5
      include/sound/emux_synth.h
  40. 9 0
      include/sound/hdmi-codec.h
  41. 1 1
      include/sound/mixer_oss.h
  42. 3 5
      include/sound/opl3.h
  43. 8 2
      include/sound/pcm-indirect.h
  44. 83 61
      include/sound/pcm.h
  45. 2 2
      include/sound/rawmidi.h
  46. 4 2
      include/sound/rt5645.h
  47. 40 3
      include/sound/simple_card_utils.h
  48. 7 0
      include/sound/soc-dapm.h
  49. 5 0
      include/sound/soc-topology.h
  50. 3 0
      include/sound/soc.h
  51. 9 1
      include/uapi/sound/asoc.h
  52. 3 1
      include/uapi/sound/asound.h
  53. 6 2
      include/uapi/sound/snd_sst_tokens.h
  54. 4 2
      sound/Kconfig
  55. 7 7
      sound/aoa/codecs/tas.c
  56. 4 4
      sound/aoa/fabrics/layout.c
  57. 3 10
      sound/atmel/Kconfig
  58. 0 2
      sound/atmel/Makefile
  59. 0 610
      sound/atmel/abdac.c
  60. 73 378
      sound/atmel/ac97c.c
  61. 9 50
      sound/core/Kconfig
  62. 3 0
      sound/core/Makefile
  63. 25 45
      sound/core/control.c
  64. 1 1
      sound/core/ctljack.c
  65. 3 9
      sound/core/info.c
  66. 0 1
      sound/core/info_oss.c
  67. 1 7
      sound/core/init.c
  68. 0 3
      sound/core/isadma.c
  69. 4 9
      sound/core/memalloc.c
  70. 0 2
      sound/core/memory.c
  71. 0 1
      sound/core/misc.c
  72. 2 2
      sound/core/oss/io.c
  73. 1 2
      sound/core/oss/mixer_oss.c
  74. 24 77
      sound/core/oss/pcm_oss.c
  75. 3 2
      sound/core/oss/pcm_plugin.c
  76. 4 6
      sound/core/oss/pcm_plugin.h
  77. 23 14
      sound/core/pcm.c
  78. 5 8
      sound/core/pcm_compat.c
  79. 4 4
      sound/core/pcm_drm_eld.c
  80. 253 415
      sound/core/pcm_lib.c
  81. 50 0
      sound/core/pcm_local.h
  82. 0 6
      sound/core/pcm_memory.c
  83. 3 11
      sound/core/pcm_misc.c
  84. 559 454
      sound/core/pcm_native.c
  85. 142 0
      sound/core/pcm_param_trace.h
  86. 8 6
      sound/core/pcm_timer.c
  87. 44 6
      sound/core/pcm_trace.h
  88. 2 2
      sound/core/rawmidi.c
  89. 57 11
      sound/core/seq/Kconfig
  90. 7 14
      sound/core/seq/Makefile
  91. 1 1
      sound/core/seq/oss/Makefile
  92. 0 8
      sound/core/seq/seq_clientmgr.c
  93. 0 1
      sound/core/seq/seq_lock.c
  94. 0 2
      sound/core/seq/seq_memory.c
  95. 4 5
      sound/core/seq/seq_midi_emul.c
  96. 8 13
      sound/core/seq/seq_midi_event.c
  97. 0 2
      sound/core/seq/seq_ports.c
  98. 1 2
      sound/core/seq/seq_virmidi.c
  99. 0 0
      sound/core/seq_device.c
  100. 0 2
      sound/core/sound.c

+ 8 - 0
Documentation/devicetree/bindings/display/bridge/adi,adv7511.txt

@@ -78,6 +78,7 @@ graph bindings specified in Documentation/devicetree/bindings/graph.txt.
   remote endpoint phandle should be a reference to a valid mipi_dsi_host device
   node.
 - Video port 1 for the HDMI output
+- Audio port 2 for the HDMI audio input
 
 
 Example
@@ -112,5 +113,12 @@ Example
 					remote-endpoint = <&hdmi_connector_in>;
 				};
 			};
+
+			port@2 {
+				reg = <2>;
+				codec_endpoint: endpoint {
+					remote-endpoint = <&i2s0_cpu_endpoint>;
+				};
+			};
 		};
 	};

+ 8 - 1
Documentation/devicetree/bindings/display/bridge/renesas,dw-hdmi.txt

@@ -25,7 +25,8 @@ Required properties:
 - clock-names: Shall contain "iahb" and "isfr" as defined in dw_hdmi.txt.
 - ports: See dw_hdmi.txt. The DWC HDMI shall have one port numbered 0
   corresponding to the video input of the controller and one port numbered 1
-  corresponding to its HDMI output. Each port shall have a single endpoint.
+  corresponding to its HDMI output, and one port numbered 2 corresponding to
+  sound input of the controller. Each port shall have a single endpoint.
 
 Optional properties:
 
@@ -59,6 +60,12 @@ Example:
 					remote-endpoint = <&hdmi0_con>;
 				};
 			};
+			port@2 {
+				reg = <2>;
+				rcar_dw_hdmi0_sound_in: endpoint {
+					remote-endpoint = <&hdmi_sound_out>;
+				};
+			};
 		};
 	};
 

+ 129 - 0
Documentation/devicetree/bindings/sound/audio-graph-card.txt

@@ -0,0 +1,129 @@
+Audio Graph Card:
+
+Audio Graph Card specifies audio DAI connections of SoC <-> codec.
+It is based on common bindings for device graphs.
+see ${LINUX}/Documentation/devicetree/bindings/graph.txt
+
+Basically, Audio Graph Card property is same as Simple Card.
+see ${LINUX}/Documentation/devicetree/bindings/sound/simple-card.txt
+
+Below are same as Simple-Card.
+
+- label
+- widgets
+- routing
+- dai-format
+- frame-master
+- bitclock-master
+- bitclock-inversion
+- frame-inversion
+- dai-tdm-slot-num
+- dai-tdm-slot-width
+- clocks / system-clock-frequency
+
+Required properties:
+
+- compatible				: "audio-graph-card";
+- dais					: list of CPU DAI port{s}
+
+Optional properties:
+- pa-gpios: GPIO used to control external amplifier.
+
+Example: Single DAI case
+
+	sound_card {
+		compatible = "audio-graph-card";
+
+		dais = <&cpu_port>;
+	};
+
+	dai-controller {
+		...
+		cpu_port: port {
+			cpu_endpoint: endpoint {
+				remote-endpoint = <&codec_endpoint>;
+
+				dai-format = "left_j";
+				...
+			};
+		};
+	};
+
+	audio-codec {
+		...
+		port {
+			codec_endpoint: endpoint {
+				remote-endpoint = <&cpu_endpoint>;
+			};
+		};
+	};
+
+Example: Multi DAI case
+
+	sound-card {
+		compatible = "audio-graph-card";
+
+		label = "sound-card";
+
+		dais = <&cpu_port0
+			&cpu_port1
+			&cpu_port2>;
+	};
+
+	audio-codec@0 {
+		...
+		port {
+			codec0_endpoint: endpoint {
+				remote-endpoint = <&cpu_endpoint0>;
+			};
+		};
+	};
+
+	audio-codec@1 {
+		...
+		port {
+			codec1_endpoint: endpoint {
+				remote-endpoint = <&cpu_endpoint1>;
+			};
+		};
+	};
+
+	audio-codec@2 {
+		...
+		port {
+			codec2_endpoint: endpoint {
+				remote-endpoint = <&cpu_endpoint2>;
+			};
+		};
+	};
+
+	dai-controller {
+		...
+		ports {
+			cpu_port0: port@0 {
+				cpu_endpoint0: endpoint {
+					remote-endpoint = <&codec0_endpoint>;
+
+					dai-format = "left_j";
+					...
+				};
+			};
+			cpu_port1: port@1 {
+				cpu_endpoint1: endpoint {
+					remote-endpoint = <&codec1_endpoint>;
+
+					dai-format = "i2s";
+					...
+				};
+			};
+			cpu_port2: port@2 {
+				cpu_endpoint2: endpoint {
+					remote-endpoint = <&codec2_endpoint>;
+
+					dai-format = "i2s";
+					...
+				};
+			};
+		};
+	};
+

+ 122 - 0
Documentation/devicetree/bindings/sound/audio-graph-scu-card.txt

@@ -0,0 +1,122 @@
+Audio-Graph-SCU-Card:
+
+Audio-Graph-SCU-Card is "Audio-Graph-Card" + "ALSA DPCM".
+
+It is based on common bindings for device graphs.
+see ${LINUX}/Documentation/devicetree/bindings/graph.txt
+
+Basically, Audio-Graph-SCU-Card property is same as
+Simple-Card / Simple-SCU-Card / Audio-Graph-Card.
+see ${LINUX}/Documentation/devicetree/bindings/sound/simple-card.txt
+    ${LINUX}/Documentation/devicetree/bindings/sound/simple-scu-card.txt
+    ${LINUX}/Documentation/devicetree/bindings/sound/audio-graph-card.txt
+
+Below are same as Simple-Card / Audio-Graph-Card.
+
+- label
+- dai-format
+- frame-master
+- bitclock-master
+- bitclock-inversion
+- frame-inversion
+- dai-tdm-slot-num
+- dai-tdm-slot-width
+- clocks / system-clock-frequency
+
+Below are same as Simple-SCU-Card.
+
+- convert-rate
+- convert-channels
+- prefix
+- routing
+
+Required properties:
+
+- compatible				: "audio-graph-scu-card";
+- dais					: list of CPU DAI port{s}
+
+Example 1. Sampling Rate Conversion
+
+	sound_card {
+		compatible = "audio-graph-scu-card";
+
+		label = "sound-card";
+		prefix = "codec";
+		routing = "codec Playback", "DAI0 Playback",
+			"codec Playback", "DAI1 Playback";
+		convert-rate = <48000>;
+
+		dais = <&cpu_port>;
+	};
+
+	audio-codec {
+		...
+
+		port {
+			codec_endpoint: endpoint {
+				remote-endpoint = <&cpu_endpoint>;
+			};
+		};
+	};
+
+	dai-controller {
+		...
+		cpu_port: port {
+			cpu_endpoint: endpoint {
+				remote-endpoint = <&codec_endpoint>;
+
+				dai-format = "left_j";
+				...
+			};
+		};
+	};
+
+Example 2. 2 CPU 1 Codec (Mixing)
+
+	sound_card {
+		compatible = "audio-graph-scu-card";
+
+		label = "sound-card";
+		prefix = "codec";
+		routing = "codec Playback", "DAI0 Playback",
+			"codec Playback", "DAI1 Playback";
+		convert-rate = <48000>;
+
+		dais = <&cpu_port0
+			&cpu_port1>;
+	};
+
+	audio-codec {
+		...
+
+		port {
+			codec_endpoint0: endpoint {
+				remote-endpoint = <&cpu_endpoint0>;
+			};
+			codec_endpoint1: endpoint {
+				remote-endpoint = <&cpu_endpoint1>;
+			};
+		};
+	};
+
+	dai-controller {
+		...
+		ports {
+			cpu_port0: port {
+				cpu_endpoint0: endpoint {
+					remote-endpoint = <&codec_endpoint0>;
+
+					dai-format = "left_j";
+					...
+				};
+			};
+			cpu_port1: port {
+				cpu_endpoint1: endpoint {
+					remote-endpoint = <&codec_endpoint1>;
+
+					dai-format = "left_j";
+					...
+				};
+			};
+		};
+	};

+ 3 - 0
Documentation/devicetree/bindings/sound/cs35l35.txt

@@ -16,6 +16,9 @@ Required properties:
     (See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
     for further information relating to interrupt properties)
 
+ - cirrus,boost-ind-nanohenry: Inductor value for boost converter. The value is
+    in nH and they can be values of 1000nH, 1200nH, 1500nH, and 2200nH.
+
 Optional properties:
   - reset-gpios : gpio used to reset the amplifier
 

+ 3 - 0
Documentation/devicetree/bindings/sound/nau8825.txt

@@ -69,6 +69,8 @@ Optional properties:
   - nuvoton,jack-insert-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms
   - nuvoton,jack-eject-debounce: number from 0 to 7 that sets debounce time to 2^(n+2) ms
 
+  - nuvoton,crosstalk-bypass: make crosstalk function bypass if set.
+
   - clocks: list of phandle and clock specifier pairs according to common clock bindings for the
       clocks described in clock-names
   - clock-names: should include "mclk" for the MCLK master clock
@@ -96,6 +98,7 @@ Example:
       nuvoton,short-key-debounce = <2>;
       nuvoton,jack-insert-debounce = <7>;
       nuvoton,jack-eject-debounce = <7>;
+      nuvoton,crosstalk-bypass;
 
       clock-names = "mclk";
       clocks = <&tegra_car TEGRA210_CLK_CLK_OUT_2>;

+ 22 - 15
Documentation/devicetree/bindings/sound/renesas,rsnd.txt

@@ -83,11 +83,11 @@ SRC can convert [xx]Hz to [yy]Hz. Then, it has below 2 modes
 **     Asynchronous mode
 ------------------
 
-You need to use "renesas,rsrc-card" sound card for it.
+You need to use "simple-scu-audio-card" sound card for it.
 example)
 
 	sound {
-		compatible = "renesas,rsrc-card";
+		compatible = "simple-scu-audio-card";
 		...
 		/*
 		 * SRC Asynchronous mode setting
@@ -97,12 +97,12 @@ example)
 		 * Inputed 48kHz data will be converted to
 		 * system specified Hz
 		 */
-		convert-rate = <48000>;
+		simple-audio-card,convert-rate = <48000>;
 		...
-		cpu {
+		simple-audio-card,cpu {
 			sound-dai = <&rcar_sound>;
 		};
-		codec {
+		simple-audio-card,codec {
 			...
 		};
 	};
@@ -141,23 +141,23 @@ For more detail information, see below
 	${LINUX}/sound/soc/sh/rcar/ctu.c
 	 - comment of header
 
-You need to use "renesas,rsrc-card" sound card for it.
+You need to use "simple-scu-audio-card" sound card for it.
 example)
 
 	sound {
-		compatible = "renesas,rsrc-card";
+		compatible = "simple-scu-audio-card";
 		...
 		/*
 		 * CTU setting
 		 * All input data will be converted to 2ch
 		 * as output data
 		 */
-		convert-channels = <2>;
+		simple-audio-card,convert-channels = <2>;
 		...
-		cpu {
+		simple-audio-card,cpu {
 			sound-dai = <&rcar_sound>;
 		};
-		codec {
+		simple-audio-card,codec {
 			...
 		};
 	};
@@ -190,22 +190,22 @@ and these sounds will be merged by MIX.
 	aplay -D plughw:0,0 xxxx.wav &
 	aplay -D plughw:0,1 yyyy.wav
 
-You need to use "renesas,rsrc-card" sound card for it.
+You need to use "simple-scu-audio-card" sound card for it.
 Ex)
 	[MEM] -> [SRC1] -> [CTU02] -+-> [MIX0] -> [DVC0] -> [SSI0]
 	                            |
 	[MEM] -> [SRC2] -> [CTU03] -+
 
 	sound {
-		compatible = "renesas,rsrc-card";
+		compatible = "simple-scu-audio-card";
 		...
-		cpu@0 {
+		simple-audio-card,cpu@0 {
 			sound-dai = <&rcar_sound 0>;
 		};
-		cpu@1 {
+		simple-audio-card,cpu@1 {
 			sound-dai = <&rcar_sound 1>;
 		};
-		codec {
+		simple-audio-card,codec {
 			...
 		};
 	};
@@ -368,6 +368,10 @@ Required properties:
 				  see below for detail.
 - #sound-dai-cells		: it must be 0 if your system is using single DAI
 				  it must be 1 if your system is using multi  DAI
+- clocks			: References to SSI/SRC/MIX/CTU/DVC/AUDIO_CLK clocks.
+- clock-names			: List of necessary clock names.
+				  "ssi-all", "ssi.X", "src.X", "mix.X", "ctu.X",
+				  "dvc.X", "clk_a", "clk_b", "clk_c", "clk_i"
 
 Optional properties:
 - #clock-cells			: it must be 0 if your system has audio_clkout
@@ -375,6 +379,9 @@ Optional properties:
 - clock-frequency		: for all audio_clkout0/1/2/3
 - clkout-lr-asynchronous	: boolean property. it indicates that audio_clkoutn
 				  is asynchronizes with lr-clock.
+- resets			: References to SSI resets.
+- reset-names			: List of valid reset names.
+				  "ssi-all", "ssi.X"
 
 SSI subnode properties:
 - interrupts			: Should contain SSI interrupt for PIO transfer

+ 39 - 0
Documentation/devicetree/bindings/sound/rockchip,pdm.txt

@@ -0,0 +1,39 @@
+* Rockchip PDM controller
+
+Required properties:
+
+- compatible: "rockchip,pdm"
+- reg: physical base address of the controller and length of memory mapped
+  region.
+- dmas: DMA specifiers for rx dma. See the DMA client binding,
+	Documentation/devicetree/bindings/dma/dma.txt
+- dma-names: should include "rx".
+- clocks: a list of phandle + clock-specifer pairs, one for each entry in clock-names.
+- clock-names: should contain following:
+   - "pdm_hclk": clock for PDM BUS
+   - "pdm_clk" : clock for PDM controller
+- pinctrl-names: Must contain a "default" entry.
+- pinctrl-N: One property must exist for each entry in
+	     pinctrl-names. See ../pinctrl/pinctrl-bindings.txt
+	     for details of the property values.
+
+Example for rk3328 PDM controller:
+
+pdm: pdm@ff040000 {
+	compatible = "rockchip,pdm";
+	reg = <0x0 0xff040000 0x0 0x1000>;
+	clocks = <&clk_pdm>, <&clk_gates28 0>;
+	clock-names = "pdm_clk", "pdm_hclk";
+	dmas = <&pdma 16>;
+	#dma-cells = <1>;
+	dma-names = "rx";
+	pinctrl-names = "default", "sleep";
+	pinctrl-0 = <&pdmm0_clk
+		     &pdmm0_fsync
+		     &pdmm0_sdi0
+		     &pdmm0_sdi1
+		     &pdmm0_sdi2
+		     &pdmm0_sdi3>;
+	pinctrl-1 = <&pdmm0_sleep>;
+	status = "disabled";
+};

+ 2 - 0
Documentation/devicetree/bindings/sound/rockchip-spdif.txt

@@ -9,7 +9,9 @@ Required properties:
 - compatible: should be one of the following:
    - "rockchip,rk3066-spdif"
    - "rockchip,rk3188-spdif"
+   - "rockchip,rk3228-spdif"
    - "rockchip,rk3288-spdif"
+   - "rockchip,rk3328-spdif"
    - "rockchip,rk3366-spdif"
    - "rockchip,rk3368-spdif"
    - "rockchip,rk3399-spdif"

+ 8 - 7
Documentation/devicetree/bindings/sound/samsung,odroid.txt

@@ -5,11 +5,6 @@ Required properties:
  - compatible - "samsung,odroidxu3-audio" - for Odroid XU3 board,
 		"samsung,odroidxu4-audio" - for Odroid XU4 board
  - model - the user-visible name of this sound complex
- - 'cpu' subnode with a 'sound-dai' property containing the phandle of the I2S
-    controller
- - 'codec' subnode with a 'sound-dai' property containing list of phandles
-    to the CODEC nodes, first entry must be corresponding to the MAX98090
-    CODEC and the second entry must be the phandle of the HDMI IP block node
  - clocks - should contain entries matching clock names in the clock-names
     property
  - clock-names - should contain following entries:
@@ -32,12 +27,18 @@ Required properties:
    For Odroid XU4:
      no entries
 
+Required sub-nodes:
+
+ - 'cpu' subnode with a 'sound-dai' property containing the phandle of the I2S
+    controller
+ - 'codec' subnode with a 'sound-dai' property containing list of phandles
+    to the CODEC nodes, first entry must be corresponding to the MAX98090
+    CODEC and the second entry must be the phandle of the HDMI IP block node
+
 Example:
 
 sound {
 	compatible = "samsung,odroidxu3-audio";
-	samsung,cpu-dai = <&i2s0>;
-	samsung,codec-dai = <&max98090>;
 	model = "Odroid-XU3";
 	samsung,audio-routing =
 		"Headphone Jack", "HPL",

+ 25 - 42
Documentation/devicetree/bindings/sound/simple-scu-card.txt

@@ -1,35 +1,29 @@
-ASoC simple SCU Sound Card
+ASoC Simple SCU Sound Card
 
-Simple-Card specifies audio DAI connections of SoC <-> codec.
+Simple SCU Sound Card is "Simple Sound Card" + "ALSA DPCM".
+For example, you can use this driver if you want to exchange sampling rate convert,
+Mixing, etc...
 
 Required properties:
 
 - compatible				: "simple-scu-audio-card"
 					  "renesas,rsrc-card"
-
 Optional properties:
 
-- simple-audio-card,name		: User specified audio sound card name, one string
-					  property.
-- simple-audio-card,cpu			: CPU   sub-node
-- simple-audio-card,codec		: CODEC sub-node
+- simple-audio-card,name		: see simple-audio-card.txt
+- simple-audio-card,cpu			: see simple-audio-card.txt
+- simple-audio-card,codec		: see simple-audio-card.txt
 
 Optional subnode properties:
 
-- simple-audio-card,format		: CPU/CODEC common audio format.
-					  "i2s", "right_j", "left_j" , "dsp_a"
-					  "dsp_b", "ac97", "pdm", "msb", "lsb"
-- simple-audio-card,frame-master	: Indicates dai-link frame master.
-					  phandle to a cpu or codec subnode.
-- simple-audio-card,bitclock-master	: Indicates dai-link bit clock master.
-					  phandle to a cpu or codec subnode.
-- simple-audio-card,bitclock-inversion	: bool property. Add this if the
-					  dai-link uses bit clock inversion.
-- simple-audio-card,frame-inversion	: bool property. Add this if the
-					  dai-link uses frame clock inversion.
+- simple-audio-card,format		: see simple-audio-card.txt
+- simple-audio-card,frame-master	: see simple-audio-card.txt
+- simple-audio-card,bitclock-master	: see simple-audio-card.txt
+- simple-audio-card,bitclock-inversion	: see simple-audio-card.txt
+- simple-audio-card,frame-inversion	: see simple-audio-card.txt
 - simple-audio-card,convert-rate	: platform specified sampling rate convert
 - simple-audio-card,convert-channels	: platform specified converted channel size (2 - 8 ch)
-- simple-audio-card,prefix		: see audio-routing
+- simple-audio-card,prefix		: see routing
 - simple-audio-card,routing		: A list of the connections between audio components.
 					  Each entry is a pair of strings, the first being the connection's sink,
 					  the second being the connection's source. Valid names for sources.
@@ -38,32 +32,23 @@ Optional subnode properties:
 
 Required CPU/CODEC subnodes properties:
 
-- sound-dai				: phandle and port of CPU/CODEC
+- sound-dai				: see simple-audio-card.txt
 
 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().
+- clocks / system-clock-frequency	: see simple-audio-card.txt
 
-Example 1. Sampling Rate Covert
+Example 1. Sampling Rate Conversion
 
 sound {
 	compatible = "simple-scu-audio-card";
 
 	simple-audio-card,name = "rsnd-ak4643";
 	simple-audio-card,format = "left_j";
-	simple-audio-card,format = "left_j";
 	simple-audio-card,bitclock-master = <&sndcodec>;
 	simple-audio-card,frame-master = <&sndcodec>;
 
-	simple-audio-card,convert-rate = <48000>; /* see audio_clk_a */
+	simple-audio-card,convert-rate = <48000>;
 
 	simple-audio-card,prefix = "ak4642";
 	simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback",
@@ -79,20 +64,18 @@ sound {
 	};
 };
 
-Example 2. 2 CPU 1 Codec
+Example 2. 2 CPU 1 Codec (Mixing)
 
 sound {
-	compatible = "renesas,rsrc-card";
-
-	card-name = "rsnd-ak4643";
-	format = "left_j";
-	bitclock-master = <&dpcmcpu>;
-	frame-master = <&dpcmcpu>;
+	compatible = "simple-scu-audio-card";
 
-	convert-rate = <48000>;  /* see audio_clk_a */
+	simple-audio-card,name = "rsnd-ak4643";
+	simple-audio-card,format = "left_j";
+	simple-audio-card,bitclock-master = <&dpcmcpu>;
+	simple-audio-card,frame-master = <&dpcmcpu>;
 
-	audio-prefix = "ak4642";
-	audio-routing = "ak4642 Playback", "DAI0 Playback",
+	simple-audio-card,prefix = "ak4642";
+	simple-audio-card,routing = "ak4642 Playback", "DAI0 Playback",
 			"ak4642 Playback", "DAI1 Playback";
 
 	dpcmcpu: cpu@0 {

+ 62 - 0
Documentation/devicetree/bindings/sound/st,stm32-i2s.txt

@@ -0,0 +1,62 @@
+STMicroelectronics STM32 SPI/I2S Controller
+
+The SPI/I2S block supports I2S/PCM protocols when configured on I2S mode.
+Only some SPI instances support I2S.
+
+Required properties:
+  - compatible: Must be "st,stm32h7-i2s"
+  - reg: Offset and length of the device's register set.
+  - interrupts: Must contain the interrupt line id.
+  - clocks: Must contain phandle and clock specifier pairs for each entry
+	in clock-names.
+  - clock-names: Must contain "i2sclk", "pclk", "x8k" and "x11k".
+	"i2sclk": clock which feeds the internal clock generator
+	"pclk": clock which feeds the peripheral bus interface
+	"x8k": I2S parent clock for sampling rates multiple of 8kHz.
+	"x11k": I2S parent clock for sampling rates multiple of 11.025kHz.
+  - dmas: DMA specifiers for tx and rx dma.
+    See Documentation/devicetree/bindings/dma/stm32-dma.txt.
+  - dma-names: Identifier for each DMA request line. Must be "tx" and "rx".
+  - pinctrl-names: should contain only value "default"
+  - pinctrl-0: see Documentation/devicetree/bindings/pinctrl/pinctrl-stm32.txt
+
+Optional properties:
+  - resets: Reference to a reset controller asserting the reset controller
+
+The device node should contain one 'port' child node with one child 'endpoint'
+node, according to the bindings defined in Documentation/devicetree/bindings/
+graph.txt.
+
+Example:
+sound_card {
+	compatible = "audio-graph-card";
+	dais = <&i2s2_port>;
+};
+
+i2s2: audio-controller@40003800 {
+	compatible = "st,stm32h7-i2s";
+	reg = <0x40003800 0x400>;
+	interrupts = <36>;
+	clocks = <&rcc PCLK1>, <&rcc SPI2_CK>, <&rcc PLL1_Q>, <&rcc PLL2_P>;
+	clock-names = "pclk", "i2sclk",  "x8k", "x11k";
+	dmas = <&dmamux2 2 39 0x400 0x1>,
+           <&dmamux2 3 40 0x400 0x1>;
+	dma-names = "rx", "tx";
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2s2>;
+
+	i2s2_port: port@0 {
+		cpu_endpoint: endpoint {
+			remote-endpoint = <&codec_endpoint>;
+			format = "i2s";
+		};
+	};
+};
+
+audio-codec {
+	codec_port: port@0 {
+		codec_endpoint: endpoint {
+			remote-endpoint = <&cpu_endpoint>;
+		};
+	};
+};

+ 18 - 23
Documentation/devicetree/bindings/sound/st,stm32-sai.txt

@@ -6,7 +6,7 @@ The SAI contains two independent audio sub-blocks. Each sub-block has
 its own clock generator and I/O lines controller.
 
 Required properties:
-  - compatible: Should be "st,stm32f4-sai"
+  - compatible: Should be "st,stm32f4-sai" or "st,stm32h7-sai"
   - reg: Base address and size of SAI common register set.
   - clocks: Must contain phandle and clock specifier pairs for each entry
 	in clock-names.
@@ -36,6 +36,10 @@ SAI subnodes required properties:
   - pinctrl-names: should contain only value "default"
   - pinctrl-0: see Documentation/devicetree/bindings/pinctrl/pinctrl-stm32.txt
 
+The device node should contain one 'port' child node with one child 'endpoint'
+node, according to the bindings defined in Documentation/devicetree/bindings/
+graph.txt.
+
 Example:
 sound_card {
 	compatible = "audio-graph-card";
@@ -43,38 +47,29 @@ sound_card {
 };
 
 sai1: sai1@40015800 {
-	compatible = "st,stm32f4-sai";
+	compatible = "st,stm32h7-sai";
 	#address-cells = <1>;
 	#size-cells = <1>;
-	ranges;
+	ranges = <0 0x40015800 0x400>;
 	reg = <0x40015800 0x4>;
-	clocks = <&rcc 1 CLK_SAIQ_PDIV>, <&rcc 1 CLK_I2SQ_PDIV>;
+	clocks = <&rcc PLL1_Q>, <&rcc PLL2_P>;
 	clock-names = "x8k", "x11k";
 	interrupts = <87>;
 
-	sai1b: audio-controller@40015824 {
-		#sound-dai-cells = <0>;
-		compatible = "st,stm32-sai-sub-b";
-		reg = <0x40015824 0x1C>;
-		clocks = <&rcc 1 CLK_SAI2>;
+	sai1a: audio-controller@40015804 {
+		compatible = "st,stm32-sai-sub-a";
+		reg = <0x4 0x1C>;
+		clocks = <&rcc SAI1_CK>;
 		clock-names = "sai_ck";
-		dmas = <&dma2 5 0 0x400 0x0>;
+		dmas = <&dmamux1 1 87 0x400 0x0>;
 		dma-names = "tx";
 		pinctrl-names = "default";
-		pinctrl-0 = <&pinctrl_sai1b>;
-
-		ports {
-			#address-cells = <1>;
-			#size-cells = <0>;
+		pinctrl-0 = <&pinctrl_sai1a>;
 
-			sai1b_port: port@0 {
-				reg = <0>;
-				cpu_endpoint: endpoint {
-					remote-endpoint = <&codec_endpoint>;
-					audio-graph-card,format = "i2s";
-					audio-graph-card,bitclock-master = <&codec_endpoint>;
-					audio-graph-card,frame-master = <&codec_endpoint>;
-				};
+		sai1b_port: port {
+			cpu_endpoint: endpoint {
+				remote-endpoint = <&codec_endpoint>;
+				format = "i2s";
 			};
 		};
 	};

+ 56 - 0
Documentation/devicetree/bindings/sound/st,stm32-spdifrx.txt

@@ -0,0 +1,56 @@
+STMicroelectronics STM32 S/PDIF receiver (SPDIFRX).
+
+The SPDIFRX peripheral, is designed to receive an S/PDIF flow compliant with
+IEC-60958 and IEC-61937.
+
+Required properties:
+  - compatible: should be "st,stm32h7-spdifrx"
+  - reg: cpu DAI IP base address and size
+  - clocks: must contain an entry for kclk (used as S/PDIF signal reference)
+  - clock-names: must contain "kclk"
+  - interrupts: cpu DAI interrupt line
+  - dmas: DMA specifiers for audio data DMA and iec control flow DMA
+    See STM32 DMA bindings, Documentation/devicetree/bindings/dma/stm32-dma.txt
+  - dma-names: two dmas have to be defined, "rx" and "rx-ctrl"
+
+Optional properties:
+  - resets: Reference to a reset controller asserting the SPDIFRX
+
+The device node should contain one 'port' child node with one child 'endpoint'
+node, according to the bindings defined in Documentation/devicetree/bindings/
+graph.txt.
+
+Example:
+spdifrx: spdifrx@40004000 {
+	compatible = "st,stm32h7-spdifrx";
+	reg = <0x40004000 0x400>;
+	clocks = <&rcc SPDIFRX_CK>;
+	clock-names = "kclk";
+	interrupts = <97>;
+	dmas = <&dmamux1 2 93 0x400 0x0>,
+	       <&dmamux1 3 94 0x400 0x0>;
+	dma-names = "rx", "rx-ctrl";
+	pinctrl-0 = <&spdifrx_pins>;
+	pinctrl-names = "default";
+
+	spdifrx_port: port {
+		cpu_endpoint: endpoint {
+			remote-endpoint = <&codec_endpoint>;
+		};
+	};
+};
+
+spdif_in: spdif-in {
+	compatible = "linux,spdif-dir";
+
+	codec_port: port {
+		codec_endpoint: endpoint {
+			remote-endpoint = <&cpu_endpoint>;
+		};
+	};
+};
+
+soundcard {
+	compatible = "audio-graph-card";
+	dais = <&spdifrx_port>;
+};

+ 7 - 4
Documentation/devicetree/bindings/sound/sun4i-codec.txt

@@ -7,6 +7,7 @@ Required properties:
 		- "allwinner,sun7i-a20-codec"
 		- "allwinner,sun8i-a23-codec"
 		- "allwinner,sun8i-h3-codec"
+		- "allwinner,sun8i-v3s-codec"
 - reg: must contain the registers location and length
 - interrupts: must contain the codec interrupt
 - dmas: DMA channels for tx and rx dma. See the DMA client binding,
@@ -25,6 +26,7 @@ Required properties for the following compatibles:
 		- "allwinner,sun6i-a31-codec"
 		- "allwinner,sun8i-a23-codec"
 		- "allwinner,sun8i-h3-codec"
+		- "allwinner,sun8i-v3s-codec"
 - resets: phandle to the reset control for this device
 - allwinner,audio-routing: A list of the connections between audio components.
 			   Each entry is a pair of strings, the first being the
@@ -34,15 +36,15 @@ Required properties for the following compatibles:
 			   Audio pins on the SoC:
 			   "HP"
 			   "HPCOM"
-			   "LINEIN"
-			   "LINEOUT"	(not on sun8i-a23)
+			   "LINEIN"	(not on sun8i-v3s)
+			   "LINEOUT"	(not on sun8i-a23 or sun8i-v3s)
 			   "MIC1"
-			   "MIC2"
+			   "MIC2"	(not on sun8i-v3s)
 			   "MIC3"	(sun6i-a31 only)
 
 			   Microphone biases from the SoC:
 			   "HBIAS"
-			   "MBIAS"
+			   "MBIAS"	(not on sun8i-v3s)
 
 			   Board connectors:
 			   "Headphone"
@@ -55,6 +57,7 @@ Required properties for the following compatibles:
 Required properties for the following compatibles:
 		- "allwinner,sun8i-a23-codec"
 		- "allwinner,sun8i-h3-codec"
+		- "allwinner,sun8i-v3s-codec"
 - allwinner,codec-analog-controls: A phandle to the codec analog controls
 				   block in the PRCM.
 

+ 1 - 0
Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt

@@ -4,6 +4,7 @@ Required properties:
 - compatible: must be one of the following compatibles:
 		- "allwinner,sun8i-a23-codec-analog"
 		- "allwinner,sun8i-h3-codec-analog"
+		- "allwinner,sun8i-v3s-codec-analog"
 
 Required properties if not a sub-node of the PRCM node:
 - reg: must contain the registers location and length

+ 24 - 0
Documentation/devicetree/bindings/sound/zte,zx-aud96p22.txt

@@ -0,0 +1,24 @@
+ZTE ZX AUD96P22 Audio Codec
+
+Required properties:
+ - compatible: Must be "zte,zx-aud96p22"
+ - #sound-dai-cells: Should be 0
+ - reg: I2C bus slave address of AUD96P22
+
+Example:
+
+	i2c0: i2c@1486000 {
+		compatible = "zte,zx296718-i2c";
+		reg = <0x01486000 0x1000>;
+		interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clocks = <&audiocrm AUDIO_I2C0_WCLK>;
+		clock-frequency = <1600000>;
+
+		aud96p22: codec@22 {
+			compatible = "zte,zx-aud96p22";
+			#sound-dai-cells = <0>;
+			reg = <0x22>;
+		};
+	};

+ 1 - 0
Documentation/sound/designs/index.rst

@@ -9,6 +9,7 @@ Designs and Implementations
    compress-offload
    timestamping
    jack-controls
+   tracepoints
    procfile
    powersave
    oss-emulation

+ 172 - 0
Documentation/sound/designs/tracepoints.rst

@@ -0,0 +1,172 @@
+===================
+Tracepoints in ALSA
+===================
+
+2017/07/02
+Takasahi Sakamoto
+
+Tracepoints in ALSA PCM core
+============================
+
+ALSA PCM core registers ``snd_pcm`` subsystem to kernel tracepoint system.
+This subsystem includes two categories of tracepoints; for state of PCM buffer
+and for processing of PCM hardware parameters. These tracepoints are available
+when corresponding kernel configurations are enabled. When ``CONFIG_SND_DEBUG``
+is enabled, the latter tracepoints are available. When additional
+``SND_PCM_XRUN_DEBUG`` is enabled too, the former trace points are enabled.
+
+Tracepoints for state of PCM buffer
+------------------------------------
+
+This category includes four tracepoints; ``hwptr``, ``applptr``, ``xrun`` and
+``hw_ptr_error``.
+
+Tracepoints for processing of PCM hardware parameters
+-----------------------------------------------------
+
+This category includes two tracepoints; ``hw_mask_param`` and
+``hw_interval_param``.
+
+In a design of ALSA PCM core, data transmission is abstracted as PCM substream.
+Applications manage PCM substream to maintain data transmission for PCM frames.
+Before starting the data transmission, applications need to configure PCM
+substream. In this procedure, PCM hardware parameters are decided by
+interaction between applications and ALSA PCM core. Once decided, runtime of
+the PCM substream keeps the parameters.
+
+The parameters are described in :c:type:`struct snd_pcm_hw_params`. This
+structure includes several types of parameters. Applications set preferable
+value to these parameters, then execute ioctl(2) with SNDRV_PCM_IOCTL_HW_REFINE
+or SNDRV_PCM_IOCTL_HW_PARAMS. The former is used just for refining available
+set of parameters. The latter is used for an actual decision of the parameters.
+
+The :c:type:`struct snd_pcm_hw_params` structure has below members:
+
+``flags``
+        Configurable. ALSA PCM core and some drivers handle this flag to select
+        convenient parameters or change their behaviour.
+``masks``
+        Configurable. This type of parameter is described in
+        :c:type:`struct snd_mask` and represent mask values. As of PCM protocol
+        v2.0.13, three types are defined.
+
+        - SNDRV_PCM_HW_PARAM_ACCESS
+        - SNDRV_PCM_HW_PARAM_FORMAT
+        - SNDRV_PCM_HW_PARAM_SUBFORMAT
+``intervals``
+        Configurable. This type of parameter is described in
+        :c:type:`struct snd_interval` and represent values with a range. As of
+        PCM protocol v2.0.13, twelve types are defined.
+
+        - SNDRV_PCM_HW_PARAM_SAMPLE_BITS
+        - SNDRV_PCM_HW_PARAM_FRAME_BITS
+        - SNDRV_PCM_HW_PARAM_CHANNELS
+        - SNDRV_PCM_HW_PARAM_RATE
+        - SNDRV_PCM_HW_PARAM_PERIOD_TIME
+        - SNDRV_PCM_HW_PARAM_PERIOD_SIZE
+        - SNDRV_PCM_HW_PARAM_PERIOD_BYTES
+        - SNDRV_PCM_HW_PARAM_PERIODS
+        - SNDRV_PCM_HW_PARAM_BUFFER_TIME
+        - SNDRV_PCM_HW_PARAM_BUFFER_SIZE
+        - SNDRV_PCM_HW_PARAM_BUFFER_BYTES
+        - SNDRV_PCM_HW_PARAM_TICK_TIME
+``rmask``
+        Configurable. This is evaluated at ioctl(2) with
+        SNDRV_PCM_IOCTL_HW_REFINE only. Applications can select which
+        mask/interval parameter can be changed by ALSA PCM core. For
+        SNDRV_PCM_IOCTL_HW_PARAMS, this mask is ignored and all of parameters
+        are going to be changed.
+``cmask``
+        Read-only. After returning from ioctl(2), buffer in user space for
+        :c:type:`struct snd_pcm_hw_params` includes result of each operation.
+        This mask represents which mask/interval parameter is actually changed.
+``info``
+        Read-only. This represents hardware/driver capabilities as bit flags
+        with SNDRV_PCM_INFO_XXX. Typically, applications execute ioctl(2) with
+        SNDRV_PCM_IOCTL_HW_REFINE to retrieve this flag, then decide candidates
+        of parameters and execute ioctl(2) with SNDRV_PCM_IOCTL_HW_PARAMS to
+        configure PCM substream.
+``msbits``
+        Read-only. This value represents available bit width in MSB side of
+        a PCM sample. When a parameter of SNDRV_PCM_HW_PARAM_SAMPLE_BITS was
+        decided as a fixed number, this value is also calculated according to
+        it. Else, zero. But this behaviour depends on implementations in driver
+        side.
+``rate_num``
+        Read-only. This value represents numerator of sampling rate in fraction
+        notation. Basically, when a parameter of SNDRV_PCM_HW_PARAM_RATE was
+        decided as a single value, this value is also calculated according to
+        it. Else, zero. But this behaviour depends on implementations in driver
+        side.
+``rate_den``
+        Read-only. This value represents denominator of sampling rate in
+        fraction notation. Basically, when a parameter of
+        SNDRV_PCM_HW_PARAM_RATE was decided as a single value, this value is
+        also calculated according to it. Else, zero. But this behaviour depends
+        on implementations in driver side.
+``fifo_size``
+        Read-only. This value represents the size of FIFO in serial sound
+        interface of hardware. Basically, each driver can assigns a proper
+        value to this parameter but some drivers intentionally set zero with
+        a care of hardware design or data transmission protocol.
+
+ALSA PCM core handles buffer of :c:type:`struct snd_pcm_hw_params` when
+applications execute ioctl(2) with SNDRV_PCM_HW_REFINE or SNDRV_PCM_HW_PARAMS.
+Parameters in the buffer are changed according to
+:c:type:`struct snd_pcm_hardware` and rules of constraints in the runtime. The
+structure describes capabilities of handled hardware. The rules describes
+dependencies on which a parameter is decided according to several parameters.
+A rule has a callback function, and drivers can register arbitrary functions
+to compute the target parameter. ALSA PCM core registers some rules to the
+runtime as a default.
+
+Each driver can join in the interaction as long as it prepared for two stuffs
+in a callback of :c:type:`struct snd_pcm_ops.open`.
+
+1. In the callback, drivers are expected to change a member of
+   :c:type:`struct snd_pcm_hardware` type in the runtime, according to
+   capacities of corresponding hardware.
+2. In the same callback, drivers are also expected to register additional rules
+   of constraints into the runtime when several parameters have dependencies
+   due to hardware design.
+
+The driver can refers to result of the interaction in a callback of
+:c:type:`struct snd_pcm_ops.hw_params`, however it should not change the
+content.
+
+Tracepoints in this category are designed to trace changes of the
+mask/interval parameters. When ALSA PCM core changes them, ``hw_mask_param`` or
+``hw_interval_param`` event is probed according to type of the changed parameter.
+
+ALSA PCM core also has a pretty print format for each of the tracepoints. Below
+is an example for ``hw_mask_param``.
+
+::
+
+    hw_mask_param: pcmC0D0p 001/023 FORMAT 00000000000000000000001000000044 00000000000000000000001000000044
+
+
+Below is an example for ``hw_interval_param``.
+
+::
+
+    hw_interval_param: pcmC0D0p 000/023 BUFFER_SIZE 0 0 [0 4294967295] 0 1 [0 4294967295]
+
+The first three fields are common. They represent name of ALSA PCM character
+device, rules of constraint and name of the changed parameter, in order. The
+field for rules of constraint consists of two sub-fields; index of applied rule
+and total number of rules added to the runtime. As an exception, the index 000
+means that the parameter is changed by ALSA PCM core, regardless of the rules.
+
+The rest of field represent state of the parameter before/after changing. These
+fields are different according to type of the parameter. For parameters of mask
+type, the fields represent hexadecimal dump of content of the parameter. For
+parameters of interval type, the fields represent values of each member of
+``empty``, ``integer``, ``openmin``, ``min``, ``max``, ``openmax`` in
+:c:type:`struct snd_interval` in this order.
+
+Tracepoints in drivers
+======================
+
+Some drivers have tracepoints for developers' convenience. For them, please
+refer to each documentation or implementation.

+ 76 - 35
Documentation/sound/kernel-api/writing-an-alsa-driver.rst

@@ -2080,8 +2080,8 @@ sleeping poll threads, etc.
 
 This callback is also atomic as default.
 
-copy and silence callbacks
-~~~~~~~~~~~~~~~~~~~~~~~~~~
+copy_user, copy_kernel and fill_silence ops
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 These callbacks are not mandatory, and can be omitted in most cases.
 These callbacks are used when the hardware buffer cannot be in the
@@ -3532,8 +3532,9 @@ external hardware buffer in interrupts (or in tasklets, preferably).
 
 The first case works fine if the external hardware buffer is large
 enough. This method doesn't need any extra buffers and thus is more
-effective. You need to define the ``copy`` and ``silence`` callbacks
-for the data transfer. However, there is a drawback: it cannot be
+effective. You need to define the ``copy_user`` and ``copy_kernel``
+callbacks for the data transfer, in addition to ``fill_silence``
+callback for playback. However, there is a drawback: it cannot be
 mmapped. The examples are GUS's GF1 PCM or emu8000's wavetable PCM.
 
 The second case allows for mmap on the buffer, although you have to
@@ -3545,30 +3546,34 @@ Another case is when the chip uses a PCI memory-map region for the
 buffer instead of the host memory. In this case, mmap is available only
 on certain architectures like the Intel one. In non-mmap mode, the data
 cannot be transferred as in the normal way. Thus you need to define the
-``copy`` and ``silence`` callbacks as well, as in the cases above. The
-examples are found in ``rme32.c`` and ``rme96.c``.
+``copy_user``, ``copy_kernel`` and ``fill_silence`` callbacks as well,
+as in the cases above. The examples are found in ``rme32.c`` and
+``rme96.c``.
 
-The implementation of the ``copy`` and ``silence`` callbacks depends
-upon whether the hardware supports interleaved or non-interleaved
-samples. The ``copy`` callback is defined like below, a bit
-differently depending whether the direction is playback or capture:
+The implementation of the ``copy_user``, ``copy_kernel`` and
+``silence`` callbacks depends upon whether the hardware supports
+interleaved or non-interleaved samples. The ``copy_user`` callback is
+defined like below, a bit differently depending whether the direction
+is playback or capture:
 
 ::
 
-  static int playback_copy(struct snd_pcm_substream *substream, int channel,
-               snd_pcm_uframes_t pos, void *src, snd_pcm_uframes_t count);
-  static int capture_copy(struct snd_pcm_substream *substream, int channel,
-               snd_pcm_uframes_t pos, void *dst, snd_pcm_uframes_t count);
+  static int playback_copy_user(struct snd_pcm_substream *substream,
+               int channel, unsigned long pos,
+               void __user *src, unsigned long count);
+  static int capture_copy_user(struct snd_pcm_substream *substream,
+               int channel, unsigned long pos,
+               void __user *dst, unsigned long count);
 
 In the case of interleaved samples, the second argument (``channel``) is
 not used. The third argument (``pos``) points the current position
-offset in frames.
+offset in bytes.
 
 The meaning of the fourth argument is different between playback and
 capture. For playback, it holds the source data pointer, and for
 capture, it's the destination data pointer.
 
-The last argument is the number of frames to be copied.
+The last argument is the number of bytes to be copied.
 
 What you have to do in this callback is again different between playback
 and capture directions. In the playback case, you copy the given amount
@@ -3578,8 +3583,7 @@ way, the copy would be like:
 
 ::
 
-  my_memcpy(my_buffer + frames_to_bytes(runtime, pos), src,
-            frames_to_bytes(runtime, count));
+  my_memcpy_from_user(my_buffer + pos, src, count);
 
 For the capture direction, you copy the given amount of data (``count``)
 at the specified offset (``pos``) on the hardware buffer to the
@@ -3587,31 +3591,68 @@ specified pointer (``dst``).
 
 ::
 
-  my_memcpy(dst, my_buffer + frames_to_bytes(runtime, pos),
-            frames_to_bytes(runtime, count));
+  my_memcpy_to_user(dst, my_buffer + pos, count);
+
+Here the functions are named as ``from_user`` and ``to_user`` because
+it's the user-space buffer that is passed to these callbacks.  That
+is, the callback is supposed to copy from/to the user-space data
+directly to/from the hardware buffer.
 
-Note that both the position and the amount of data are given in frames.
+Careful readers might notice that these callbacks receive the
+arguments in bytes, not in frames like other callbacks.  It's because
+it would make coding easier like the examples above, and also it makes
+easier to unify both the interleaved and non-interleaved cases, as
+explained in the following.
 
 In the case of non-interleaved samples, the implementation will be a bit
-more complicated.
+more complicated.  The callback is called for each channel, passed by
+the second argument, so totally it's called for N-channels times per
+transfer.
+
+The meaning of other arguments are almost same as the interleaved
+case.  The callback is supposed to copy the data from/to the given
+user-space buffer, but only for the given channel.  For the detailed
+implementations, please check ``isa/gus/gus_pcm.c`` or
+"pci/rme9652/rme9652.c" as examples.
+
+The above callbacks are the copy from/to the user-space buffer.  There
+are some cases where we want copy from/to the kernel-space buffer
+instead.  In such a case, ``copy_kernel`` callback is called.  It'd
+look like:
+
+::
+
+  static int playback_copy_kernel(struct snd_pcm_substream *substream,
+               int channel, unsigned long pos,
+               void *src, unsigned long count);
+  static int capture_copy_kernel(struct snd_pcm_substream *substream,
+               int channel, unsigned long pos,
+               void *dst, unsigned long count);
+
+As found easily, the only difference is that the buffer pointer is
+without ``__user`` prefix; that is, a kernel-buffer pointer is passed
+in the fourth argument.  Correspondingly, the implementation would be
+a version without the user-copy, such as:
 
-You need to check the channel argument, and if it's -1, copy the whole
-channels. Otherwise, you have to copy only the specified channel. Please
-check ``isa/gus/gus_pcm.c`` as an example.
+::
+
+  my_memcpy(my_buffer + pos, src, count);
 
-The ``silence`` callback is also implemented in a similar way
+Usually for the playback, another callback ``fill_silence`` is
+defined.  It's implemented in a similar way as the copy callbacks
+above:
 
 ::
 
   static int silence(struct snd_pcm_substream *substream, int channel,
-                     snd_pcm_uframes_t pos, snd_pcm_uframes_t count);
+                     unsigned long pos, unsigned long count);
 
-The meanings of arguments are the same as in the ``copy`` callback,
-although there is no ``src/dst`` argument. In the case of interleaved
-samples, the channel argument has no meaning, as well as on ``copy``
-callback.
+The meanings of arguments are the same as in the ``copy_user`` and
+``copy_kernel`` callbacks, although there is no buffer pointer
+argument. In the case of interleaved samples, the channel argument has
+no meaning, as well as on ``copy_*`` callbacks.
 
-The role of ``silence`` callback is to set the given amount
+The role of ``fill_silence`` callback is to set the given amount
 (``count``) of silence data at the specified offset (``pos``) on the
 hardware buffer. Suppose that the data format is signed (that is, the
 silent-data is 0), and the implementation using a memset-like function
@@ -3619,11 +3660,11 @@ would be like:
 
 ::
 
-  my_memcpy(my_buffer + frames_to_bytes(runtime, pos), 0,
-            frames_to_bytes(runtime, count));
+  my_memset(my_buffer + pos, 0, count);
 
 In the case of non-interleaved samples, again, the implementation
-becomes a bit more complicated. See, for example, ``isa/gus/gus_pcm.c``.
+becomes a bit more complicated, as it's called N-times per transfer
+for each channel. See, for example, ``isa/gus/gus_pcm.c``.
 
 Non-Contiguous Buffers
 ----------------------

+ 18 - 0
Documentation/sound/soc/dapm.rst

@@ -105,6 +105,24 @@ Pre
 	Special PRE widget (exec before all others)
 Post
 	Special POST widget (exec after all others)
+Buffer
+	Inter widget audio data buffer within a DSP.
+Scheduler
+	DSP internal scheduler that schedules component/pipeline processing
+	work.
+Effect
+	Widget that performs an audio processing effect.
+SRC
+	Sample Rate Converter within DSP or CODEC
+ASRC
+	Asynchronous Sample Rate Converter within DSP or CODEC
+Encoder
+	Widget that encodes audio data from one format (usually PCM) to another
+	usually more compressed format.
+Decoder
+	Widget that decodes audio data from a compressed format to an
+	uncompressed format like PCM.
+
 
 (Widgets are defined in include/sound/soc-dapm.h)
 

+ 1 - 6
drivers/dma/dw/Kconfig

@@ -6,17 +6,12 @@ config DW_DMAC_CORE
 	tristate
 	select DMA_ENGINE
 
-config DW_DMAC_BIG_ENDIAN_IO
-	bool
-
 config DW_DMAC
 	tristate "Synopsys DesignWare AHB DMA platform driver"
 	select DW_DMAC_CORE
-	select DW_DMAC_BIG_ENDIAN_IO if AVR32
-	default y if CPU_AT32AP7000
 	help
 	  Support the Synopsys DesignWare AHB DMA controller. This
-	  can be integrated in chips such as the Atmel AT32ap7000.
+	  can be integrated in chips such as the Intel Cherrytrail.
 
 config DW_DMAC_PCI
 	tristate "Synopsys DesignWare AHB DMA PCI driver"

+ 2 - 330
drivers/dma/dw/core.c

@@ -561,92 +561,14 @@ static void dwc_handle_error(struct dw_dma *dw, struct dw_dma_chan *dwc)
 	dwc_descriptor_complete(dwc, bad_desc, true);
 }
 
-/* --------------------- Cyclic DMA API extensions -------------------- */
-
-dma_addr_t dw_dma_get_src_addr(struct dma_chan *chan)
-{
-	struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
-	return channel_readl(dwc, SAR);
-}
-EXPORT_SYMBOL(dw_dma_get_src_addr);
-
-dma_addr_t dw_dma_get_dst_addr(struct dma_chan *chan)
-{
-	struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
-	return channel_readl(dwc, DAR);
-}
-EXPORT_SYMBOL(dw_dma_get_dst_addr);
-
-/* Called with dwc->lock held and all DMAC interrupts disabled */
-static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc,
-		u32 status_block, u32 status_err, u32 status_xfer)
-{
-	unsigned long flags;
-
-	if (status_block & dwc->mask) {
-		void (*callback)(void *param);
-		void *callback_param;
-
-		dev_vdbg(chan2dev(&dwc->chan), "new cyclic period llp 0x%08x\n",
-				channel_readl(dwc, LLP));
-		dma_writel(dw, CLEAR.BLOCK, dwc->mask);
-
-		callback = dwc->cdesc->period_callback;
-		callback_param = dwc->cdesc->period_callback_param;
-
-		if (callback)
-			callback(callback_param);
-	}
-
-	/*
-	 * Error and transfer complete are highly unlikely, and will most
-	 * likely be due to a configuration error by the user.
-	 */
-	if (unlikely(status_err & dwc->mask) ||
-			unlikely(status_xfer & dwc->mask)) {
-		unsigned int i;
-
-		dev_err(chan2dev(&dwc->chan),
-			"cyclic DMA unexpected %s interrupt, stopping DMA transfer\n",
-			status_xfer ? "xfer" : "error");
-
-		spin_lock_irqsave(&dwc->lock, flags);
-
-		dwc_dump_chan_regs(dwc);
-
-		dwc_chan_disable(dw, dwc);
-
-		/* Make sure DMA does not restart by loading a new list */
-		channel_writel(dwc, LLP, 0);
-		channel_writel(dwc, CTL_LO, 0);
-		channel_writel(dwc, CTL_HI, 0);
-
-		dma_writel(dw, CLEAR.BLOCK, dwc->mask);
-		dma_writel(dw, CLEAR.ERROR, dwc->mask);
-		dma_writel(dw, CLEAR.XFER, dwc->mask);
-
-		for (i = 0; i < dwc->cdesc->periods; i++)
-			dwc_dump_lli(dwc, dwc->cdesc->desc[i]);
-
-		spin_unlock_irqrestore(&dwc->lock, flags);
-	}
-
-	/* Re-enable interrupts */
-	channel_set_bit(dw, MASK.BLOCK, dwc->mask);
-}
-
-/* ------------------------------------------------------------------------- */
-
 static void dw_dma_tasklet(unsigned long data)
 {
 	struct dw_dma *dw = (struct dw_dma *)data;
 	struct dw_dma_chan *dwc;
-	u32 status_block;
 	u32 status_xfer;
 	u32 status_err;
 	unsigned int i;
 
-	status_block = dma_readl(dw, RAW.BLOCK);
 	status_xfer = dma_readl(dw, RAW.XFER);
 	status_err = dma_readl(dw, RAW.ERROR);
 
@@ -655,8 +577,7 @@ static void dw_dma_tasklet(unsigned long data)
 	for (i = 0; i < dw->dma.chancnt; i++) {
 		dwc = &dw->chan[i];
 		if (test_bit(DW_DMA_IS_CYCLIC, &dwc->flags))
-			dwc_handle_cyclic(dw, dwc, status_block, status_err,
-					status_xfer);
+			dev_vdbg(dw->dma.dev, "Cyclic xfer is not implemented\n");
 		else if (status_err & (1 << i))
 			dwc_handle_error(dw, dwc);
 		else if (status_xfer & (1 << i))
@@ -1264,255 +1185,6 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
 	dev_vdbg(chan2dev(chan), "%s: done\n", __func__);
 }
 
-/* --------------------- Cyclic DMA API extensions -------------------- */
-
-/**
- * dw_dma_cyclic_start - start the cyclic DMA transfer
- * @chan: the DMA channel to start
- *
- * Must be called with soft interrupts disabled. Returns zero on success or
- * -errno on failure.
- */
-int dw_dma_cyclic_start(struct dma_chan *chan)
-{
-	struct dw_dma_chan	*dwc = to_dw_dma_chan(chan);
-	struct dw_dma		*dw = to_dw_dma(chan->device);
-	unsigned long		flags;
-
-	if (!test_bit(DW_DMA_IS_CYCLIC, &dwc->flags)) {
-		dev_err(chan2dev(&dwc->chan), "missing prep for cyclic DMA\n");
-		return -ENODEV;
-	}
-
-	spin_lock_irqsave(&dwc->lock, flags);
-
-	/* Enable interrupts to perform cyclic transfer */
-	channel_set_bit(dw, MASK.BLOCK, dwc->mask);
-
-	dwc_dostart(dwc, dwc->cdesc->desc[0]);
-
-	spin_unlock_irqrestore(&dwc->lock, flags);
-
-	return 0;
-}
-EXPORT_SYMBOL(dw_dma_cyclic_start);
-
-/**
- * dw_dma_cyclic_stop - stop the cyclic DMA transfer
- * @chan: the DMA channel to stop
- *
- * Must be called with soft interrupts disabled.
- */
-void dw_dma_cyclic_stop(struct dma_chan *chan)
-{
-	struct dw_dma_chan	*dwc = to_dw_dma_chan(chan);
-	struct dw_dma		*dw = to_dw_dma(dwc->chan.device);
-	unsigned long		flags;
-
-	spin_lock_irqsave(&dwc->lock, flags);
-
-	dwc_chan_disable(dw, dwc);
-
-	spin_unlock_irqrestore(&dwc->lock, flags);
-}
-EXPORT_SYMBOL(dw_dma_cyclic_stop);
-
-/**
- * dw_dma_cyclic_prep - prepare the cyclic DMA transfer
- * @chan: the DMA channel to prepare
- * @buf_addr: physical DMA address where the buffer starts
- * @buf_len: total number of bytes for the entire buffer
- * @period_len: number of bytes for each period
- * @direction: transfer direction, to or from device
- *
- * Must be called before trying to start the transfer. Returns a valid struct
- * dw_cyclic_desc if successful or an ERR_PTR(-errno) if not successful.
- */
-struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
-		dma_addr_t buf_addr, size_t buf_len, size_t period_len,
-		enum dma_transfer_direction direction)
-{
-	struct dw_dma_chan		*dwc = to_dw_dma_chan(chan);
-	struct dma_slave_config		*sconfig = &dwc->dma_sconfig;
-	struct dw_cyclic_desc		*cdesc;
-	struct dw_cyclic_desc		*retval = NULL;
-	struct dw_desc			*desc;
-	struct dw_desc			*last = NULL;
-	u8				lms = DWC_LLP_LMS(dwc->dws.m_master);
-	unsigned long			was_cyclic;
-	unsigned int			reg_width;
-	unsigned int			periods;
-	unsigned int			i;
-	unsigned long			flags;
-
-	spin_lock_irqsave(&dwc->lock, flags);
-	if (dwc->nollp) {
-		spin_unlock_irqrestore(&dwc->lock, flags);
-		dev_dbg(chan2dev(&dwc->chan),
-				"channel doesn't support LLP transfers\n");
-		return ERR_PTR(-EINVAL);
-	}
-
-	if (!list_empty(&dwc->queue) || !list_empty(&dwc->active_list)) {
-		spin_unlock_irqrestore(&dwc->lock, flags);
-		dev_dbg(chan2dev(&dwc->chan),
-				"queue and/or active list are not empty\n");
-		return ERR_PTR(-EBUSY);
-	}
-
-	was_cyclic = test_and_set_bit(DW_DMA_IS_CYCLIC, &dwc->flags);
-	spin_unlock_irqrestore(&dwc->lock, flags);
-	if (was_cyclic) {
-		dev_dbg(chan2dev(&dwc->chan),
-				"channel already prepared for cyclic DMA\n");
-		return ERR_PTR(-EBUSY);
-	}
-
-	retval = ERR_PTR(-EINVAL);
-
-	if (unlikely(!is_slave_direction(direction)))
-		goto out_err;
-
-	dwc->direction = direction;
-
-	if (direction == DMA_MEM_TO_DEV)
-		reg_width = __ffs(sconfig->dst_addr_width);
-	else
-		reg_width = __ffs(sconfig->src_addr_width);
-
-	periods = buf_len / period_len;
-
-	/* Check for too big/unaligned periods and unaligned DMA buffer. */
-	if (period_len > (dwc->block_size << reg_width))
-		goto out_err;
-	if (unlikely(period_len & ((1 << reg_width) - 1)))
-		goto out_err;
-	if (unlikely(buf_addr & ((1 << reg_width) - 1)))
-		goto out_err;
-
-	retval = ERR_PTR(-ENOMEM);
-
-	cdesc = kzalloc(sizeof(struct dw_cyclic_desc), GFP_KERNEL);
-	if (!cdesc)
-		goto out_err;
-
-	cdesc->desc = kzalloc(sizeof(struct dw_desc *) * periods, GFP_KERNEL);
-	if (!cdesc->desc)
-		goto out_err_alloc;
-
-	for (i = 0; i < periods; i++) {
-		desc = dwc_desc_get(dwc);
-		if (!desc)
-			goto out_err_desc_get;
-
-		switch (direction) {
-		case DMA_MEM_TO_DEV:
-			lli_write(desc, dar, sconfig->dst_addr);
-			lli_write(desc, sar, buf_addr + period_len * i);
-			lli_write(desc, ctllo, (DWC_DEFAULT_CTLLO(chan)
-				| DWC_CTLL_DST_WIDTH(reg_width)
-				| DWC_CTLL_SRC_WIDTH(reg_width)
-				| DWC_CTLL_DST_FIX
-				| DWC_CTLL_SRC_INC
-				| DWC_CTLL_INT_EN));
-
-			lli_set(desc, ctllo, sconfig->device_fc ?
-					DWC_CTLL_FC(DW_DMA_FC_P_M2P) :
-					DWC_CTLL_FC(DW_DMA_FC_D_M2P));
-
-			break;
-		case DMA_DEV_TO_MEM:
-			lli_write(desc, dar, buf_addr + period_len * i);
-			lli_write(desc, sar, sconfig->src_addr);
-			lli_write(desc, ctllo, (DWC_DEFAULT_CTLLO(chan)
-				| DWC_CTLL_SRC_WIDTH(reg_width)
-				| DWC_CTLL_DST_WIDTH(reg_width)
-				| DWC_CTLL_DST_INC
-				| DWC_CTLL_SRC_FIX
-				| DWC_CTLL_INT_EN));
-
-			lli_set(desc, ctllo, sconfig->device_fc ?
-					DWC_CTLL_FC(DW_DMA_FC_P_P2M) :
-					DWC_CTLL_FC(DW_DMA_FC_D_P2M));
-
-			break;
-		default:
-			break;
-		}
-
-		lli_write(desc, ctlhi, period_len >> reg_width);
-		cdesc->desc[i] = desc;
-
-		if (last)
-			lli_write(last, llp, desc->txd.phys | lms);
-
-		last = desc;
-	}
-
-	/* Let's make a cyclic list */
-	lli_write(last, llp, cdesc->desc[0]->txd.phys | lms);
-
-	dev_dbg(chan2dev(&dwc->chan),
-			"cyclic prepared buf %pad len %zu period %zu periods %d\n",
-			&buf_addr, buf_len, period_len, periods);
-
-	cdesc->periods = periods;
-	dwc->cdesc = cdesc;
-
-	return cdesc;
-
-out_err_desc_get:
-	while (i--)
-		dwc_desc_put(dwc, cdesc->desc[i]);
-out_err_alloc:
-	kfree(cdesc);
-out_err:
-	clear_bit(DW_DMA_IS_CYCLIC, &dwc->flags);
-	return (struct dw_cyclic_desc *)retval;
-}
-EXPORT_SYMBOL(dw_dma_cyclic_prep);
-
-/**
- * dw_dma_cyclic_free - free a prepared cyclic DMA transfer
- * @chan: the DMA channel to free
- */
-void dw_dma_cyclic_free(struct dma_chan *chan)
-{
-	struct dw_dma_chan	*dwc = to_dw_dma_chan(chan);
-	struct dw_dma		*dw = to_dw_dma(dwc->chan.device);
-	struct dw_cyclic_desc	*cdesc = dwc->cdesc;
-	unsigned int		i;
-	unsigned long		flags;
-
-	dev_dbg(chan2dev(&dwc->chan), "%s\n", __func__);
-
-	if (!cdesc)
-		return;
-
-	spin_lock_irqsave(&dwc->lock, flags);
-
-	dwc_chan_disable(dw, dwc);
-
-	dma_writel(dw, CLEAR.BLOCK, dwc->mask);
-	dma_writel(dw, CLEAR.ERROR, dwc->mask);
-	dma_writel(dw, CLEAR.XFER, dwc->mask);
-
-	spin_unlock_irqrestore(&dwc->lock, flags);
-
-	for (i = 0; i < cdesc->periods; i++)
-		dwc_desc_put(dwc, cdesc->desc[i]);
-
-	kfree(cdesc->desc);
-	kfree(cdesc);
-
-	dwc->cdesc = NULL;
-
-	clear_bit(DW_DMA_IS_CYCLIC, &dwc->flags);
-}
-EXPORT_SYMBOL(dw_dma_cyclic_free);
-
-/*----------------------------------------------------------------------*/
-
 int dw_dma_probe(struct dw_dma_chip *chip)
 {
 	struct dw_dma_platform_data *pdata;
@@ -1642,7 +1314,7 @@ int dw_dma_probe(struct dw_dma_chip *chip)
 		if (autocfg) {
 			unsigned int r = DW_DMA_MAX_NR_CHANNELS - i - 1;
 			void __iomem *addr = &__dw_regs(dw)->DWC_PARAMS[r];
-			unsigned int dwc_params = dma_readl_native(addr);
+			unsigned int dwc_params = readl(addr);
 
 			dev_dbg(chip->dev, "DWC_PARAMS[%d]: 0x%08x\n", i,
 					   dwc_params);

+ 11 - 39
drivers/dma/dw/regs.h

@@ -116,20 +116,6 @@ struct dw_dma_regs {
 	DW_REG(GLOBAL_CFG);
 };
 
-/*
- * Big endian I/O access when reading and writing to the DMA controller
- * registers.  This is needed on some platforms, like the Atmel AVR32
- * architecture.
- */
-
-#ifdef CONFIG_DW_DMAC_BIG_ENDIAN_IO
-#define dma_readl_native ioread32be
-#define dma_writel_native iowrite32be
-#else
-#define dma_readl_native readl
-#define dma_writel_native writel
-#endif
-
 /* Bitfields in DW_PARAMS */
 #define DW_PARAMS_NR_CHAN	8		/* number of channels */
 #define DW_PARAMS_NR_MASTER	11		/* number of AHB masters */
@@ -280,7 +266,6 @@ struct dw_dma_chan {
 	unsigned long		flags;
 	struct list_head	active_list;
 	struct list_head	queue;
-	struct dw_cyclic_desc	*cdesc;
 
 	unsigned int		descs_allocated;
 
@@ -302,9 +287,9 @@ __dwc_regs(struct dw_dma_chan *dwc)
 }
 
 #define channel_readl(dwc, name) \
-	dma_readl_native(&(__dwc_regs(dwc)->name))
+	readl(&(__dwc_regs(dwc)->name))
 #define channel_writel(dwc, name, val) \
-	dma_writel_native((val), &(__dwc_regs(dwc)->name))
+	writel((val), &(__dwc_regs(dwc)->name))
 
 static inline struct dw_dma_chan *to_dw_dma_chan(struct dma_chan *chan)
 {
@@ -333,9 +318,9 @@ static inline struct dw_dma_regs __iomem *__dw_regs(struct dw_dma *dw)
 }
 
 #define dma_readl(dw, name) \
-	dma_readl_native(&(__dw_regs(dw)->name))
+	readl(&(__dw_regs(dw)->name))
 #define dma_writel(dw, name, val) \
-	dma_writel_native((val), &(__dw_regs(dw)->name))
+	writel((val), &(__dw_regs(dw)->name))
 
 #define idma32_readq(dw, name)				\
 	hi_lo_readq(&(__dw_regs(dw)->name))
@@ -352,43 +337,30 @@ static inline struct dw_dma *to_dw_dma(struct dma_device *ddev)
 	return container_of(ddev, struct dw_dma, dma);
 }
 
-#ifdef CONFIG_DW_DMAC_BIG_ENDIAN_IO
-typedef __be32 __dw32;
-#else
-typedef __le32 __dw32;
-#endif
-
 /* LLI == Linked List Item; a.k.a. DMA block descriptor */
 struct dw_lli {
 	/* values that are not changed by hardware */
-	__dw32		sar;
-	__dw32		dar;
-	__dw32		llp;		/* chain to next lli */
-	__dw32		ctllo;
+	__le32		sar;
+	__le32		dar;
+	__le32		llp;		/* chain to next lli */
+	__le32		ctllo;
 	/* values that may get written back: */
-	__dw32		ctlhi;
+	__le32		ctlhi;
 	/* sstat and dstat can snapshot peripheral register state.
 	 * silicon config may discard either or both...
 	 */
-	__dw32		sstat;
-	__dw32		dstat;
+	__le32		sstat;
+	__le32		dstat;
 };
 
 struct dw_desc {
 	/* FIRST values the hardware uses */
 	struct dw_lli			lli;
 
-#ifdef CONFIG_DW_DMAC_BIG_ENDIAN_IO
-#define lli_set(d, reg, v)		((d)->lli.reg |= cpu_to_be32(v))
-#define lli_clear(d, reg, v)		((d)->lli.reg &= ~cpu_to_be32(v))
-#define lli_read(d, reg)		be32_to_cpu((d)->lli.reg)
-#define lli_write(d, reg, v)		((d)->lli.reg = cpu_to_be32(v))
-#else
 #define lli_set(d, reg, v)		((d)->lli.reg |= cpu_to_le32(v))
 #define lli_clear(d, reg, v)		((d)->lli.reg &= ~cpu_to_le32(v))
 #define lli_read(d, reg)		le32_to_cpu((d)->lli.reg)
 #define lli_write(d, reg, v)		((d)->lli.reg = cpu_to_le32(v))
-#endif
 
 	/* THEN values for driver housekeeping */
 	struct list_head		desc_node;

+ 22 - 0
drivers/gpu/drm/bridge/adv7511/adv7511_audio.c

@@ -11,6 +11,7 @@
 #include <sound/hdmi-codec.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
+#include <linux/of_graph.h>
 
 #include "adv7511.h"
 
@@ -182,10 +183,31 @@ static void audio_shutdown(struct device *dev, void *data)
 {
 }
 
+static int adv7511_hdmi_i2s_get_dai_id(struct snd_soc_component *component,
+					struct device_node *endpoint)
+{
+	struct of_endpoint of_ep;
+	int ret;
+
+	ret = of_graph_parse_endpoint(endpoint, &of_ep);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * HDMI sound should be located as reg = <2>
+	 * Then, it is sound port 0
+	 */
+	if (of_ep.port == 2)
+		return 0;
+
+	return -EINVAL;
+}
+
 static const struct hdmi_codec_ops adv7511_codec_ops = {
 	.hw_params	= adv7511_hdmi_hw_params,
 	.audio_shutdown = audio_shutdown,
 	.audio_startup	= audio_startup,
+	.get_dai_id	= adv7511_hdmi_i2s_get_dai_id,
 };
 
 static struct hdmi_codec_pdata codec_data = {

+ 21 - 0
drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c

@@ -82,9 +82,30 @@ static void dw_hdmi_i2s_audio_shutdown(struct device *dev, void *data)
 	hdmi_write(audio, HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0);
 }
 
+static int dw_hdmi_i2s_get_dai_id(struct snd_soc_component *component,
+				  struct device_node *endpoint)
+{
+	struct of_endpoint of_ep;
+	int ret;
+
+	ret = of_graph_parse_endpoint(endpoint, &of_ep);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * HDMI sound should be located as reg = <2>
+	 * Then, it is sound port 0
+	 */
+	if (of_ep.port == 2)
+		return 0;
+
+	return -EINVAL;
+}
+
 static struct hdmi_codec_ops dw_hdmi_i2s_ops = {
 	.hw_params	= dw_hdmi_i2s_hw_params,
 	.audio_shutdown	= dw_hdmi_i2s_audio_shutdown,
+	.get_dai_id	= dw_hdmi_i2s_get_dai_id,
 };
 
 static int snd_dw_hdmi_probe(struct platform_device *pdev)

+ 24 - 8
drivers/media/pci/solo6x10/solo6x10-g723.c

@@ -223,9 +223,9 @@ static snd_pcm_uframes_t snd_solo_pcm_pointer(struct snd_pcm_substream *ss)
 	return idx * G723_FRAMES_PER_PAGE;
 }
 
-static int snd_solo_pcm_copy(struct snd_pcm_substream *ss, int channel,
-			     snd_pcm_uframes_t pos, void __user *dst,
-			     snd_pcm_uframes_t count)
+static int __snd_solo_pcm_copy(struct snd_pcm_substream *ss,
+			       unsigned long pos, void *dst,
+			       unsigned long count, bool in_kernel)
 {
 	struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss);
 	struct solo_dev *solo_dev = solo_pcm->solo_dev;
@@ -242,16 +242,31 @@ static int snd_solo_pcm_copy(struct snd_pcm_substream *ss, int channel,
 		if (err)
 			return err;
 
-		err = copy_to_user(dst + (i * G723_PERIOD_BYTES),
-				   solo_pcm->g723_buf, G723_PERIOD_BYTES);
-
-		if (err)
+		if (in_kernel)
+			memcpy(dst, solo_pcm->g723_buf, G723_PERIOD_BYTES);
+		else if (copy_to_user((void __user *)dst,
+				      solo_pcm->g723_buf, G723_PERIOD_BYTES))
 			return -EFAULT;
+		dst += G723_PERIOD_BYTES;
 	}
 
 	return 0;
 }
 
+static int snd_solo_pcm_copy_user(struct snd_pcm_substream *ss, int channel,
+				  unsigned long pos, void __user *dst,
+				  unsigned long count)
+{
+	return __snd_solo_pcm_copy(ss, pos, (void *)dst, count, false);
+}
+
+static int snd_solo_pcm_copy_kernel(struct snd_pcm_substream *ss, int channel,
+				    unsigned long pos, void *dst,
+				    unsigned long count)
+{
+	return __snd_solo_pcm_copy(ss, pos, dst, count, true);
+}
+
 static const struct snd_pcm_ops snd_solo_pcm_ops = {
 	.open = snd_solo_pcm_open,
 	.close = snd_solo_pcm_close,
@@ -261,7 +276,8 @@ static const struct snd_pcm_ops snd_solo_pcm_ops = {
 	.prepare = snd_solo_pcm_prepare,
 	.trigger = snd_solo_pcm_trigger,
 	.pointer = snd_solo_pcm_pointer,
-	.copy = snd_solo_pcm_copy,
+	.copy_user = snd_solo_pcm_copy_user,
+	.copy_kernel = snd_solo_pcm_copy_kernel,
 };
 
 static int snd_solo_capture_volume_info(struct snd_kcontrol *kcontrol,

+ 52 - 10
drivers/of/base.c

@@ -1601,6 +1601,7 @@ int of_phandle_iterator_init(struct of_phandle_iterator *it,
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(of_phandle_iterator_init);
 
 int of_phandle_iterator_next(struct of_phandle_iterator *it)
 {
@@ -1670,6 +1671,7 @@ err:
 
 	return -EINVAL;
 }
+EXPORT_SYMBOL_GPL(of_phandle_iterator_next);
 
 int of_phandle_iterator_args(struct of_phandle_iterator *it,
 			     uint32_t *args,
@@ -2484,6 +2486,41 @@ struct device_node *of_graph_get_endpoint_by_regs(
 }
 EXPORT_SYMBOL(of_graph_get_endpoint_by_regs);
 
+/**
+ * of_graph_get_remote_endpoint() - get remote endpoint node
+ * @node: pointer to a local endpoint device_node
+ *
+ * Return: Remote endpoint node associated with remote endpoint node linked
+ *	   to @node. Use of_node_put() on it when done.
+ */
+struct device_node *of_graph_get_remote_endpoint(const struct device_node *node)
+{
+	/* Get remote endpoint node. */
+	return of_parse_phandle(node, "remote-endpoint", 0);
+}
+EXPORT_SYMBOL(of_graph_get_remote_endpoint);
+
+/**
+ * of_graph_get_port_parent() - get port's parent node
+ * @node: pointer to a local endpoint device_node
+ *
+ * Return: device node associated with endpoint node linked
+ *	   to @node. Use of_node_put() on it when done.
+ */
+struct device_node *of_graph_get_port_parent(struct device_node *node)
+{
+	unsigned int depth;
+
+	/* Walk 3 levels up only if there is 'ports' node. */
+	for (depth = 3; depth && node; depth--) {
+		node = of_get_next_parent(node);
+		if (depth == 2 && of_node_cmp(node->name, "ports"))
+			break;
+	}
+	return node;
+}
+EXPORT_SYMBOL(of_graph_get_port_parent);
+
 /**
  * of_graph_get_remote_port_parent() - get remote port's parent node
  * @node: pointer to a local endpoint device_node
@@ -2495,18 +2532,11 @@ struct device_node *of_graph_get_remote_port_parent(
 			       const struct device_node *node)
 {
 	struct device_node *np;
-	unsigned int depth;
 
 	/* Get remote endpoint node. */
-	np = of_parse_phandle(node, "remote-endpoint", 0);
+	np = of_graph_get_remote_endpoint(node);
 
-	/* Walk 3 levels up only if there is 'ports' node. */
-	for (depth = 3; depth && np; depth--) {
-		np = of_get_next_parent(np);
-		if (depth == 2 && of_node_cmp(np->name, "ports"))
-			break;
-	}
-	return np;
+	return of_graph_get_port_parent(np);
 }
 EXPORT_SYMBOL(of_graph_get_remote_port_parent);
 
@@ -2522,13 +2552,25 @@ struct device_node *of_graph_get_remote_port(const struct device_node *node)
 	struct device_node *np;
 
 	/* Get remote endpoint node. */
-	np = of_parse_phandle(node, "remote-endpoint", 0);
+	np = of_graph_get_remote_endpoint(node);
 	if (!np)
 		return NULL;
 	return of_get_next_parent(np);
 }
 EXPORT_SYMBOL(of_graph_get_remote_port);
 
+int of_graph_get_endpoint_count(const struct device_node *np)
+{
+	struct device_node *endpoint;
+	int num = 0;
+
+	for_each_endpoint_of_node(np, endpoint)
+		num++;
+
+	return num;
+}
+EXPORT_SYMBOL(of_graph_get_endpoint_count);
+
 /**
  * of_graph_get_remote_node() - get remote parent device_node for given port/endpoint
  * @node: pointer to parent device_node containing graph port/endpoint

+ 2 - 3
drivers/staging/vc04_services/bcm2835-audio/bcm2835-pcm.c

@@ -353,9 +353,8 @@ static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream)
 	struct snd_pcm_indirect *pcm_indirect = &alsa_stream->pcm_indirect;
 
 	pcm_indirect->hw_queue_size = runtime->hw.buffer_bytes_max;
-	snd_pcm_indirect_playback_transfer(substream, pcm_indirect,
-					   snd_bcm2835_pcm_transfer);
-	return 0;
+	return snd_pcm_indirect_playback_transfer(substream, pcm_indirect,
+						  snd_bcm2835_pcm_transfer);
 }
 
 /* trigger callback */

+ 1 - 6
drivers/usb/gadget/function/u_uac1_legacy.c

@@ -157,7 +157,6 @@ size_t u_audio_playback(struct gaudio *card, void *buf, size_t count)
 	struct gaudio_snd_dev	*snd = &card->playback;
 	struct snd_pcm_substream *substream = snd->substream;
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	mm_segment_t old_fs;
 	ssize_t result;
 	snd_pcm_sframes_t frames;
 
@@ -174,15 +173,11 @@ try_again:
 	}
 
 	frames = bytes_to_frames(runtime, count);
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	result = snd_pcm_lib_write(snd->substream, (void __user *)buf, frames);
+	result = snd_pcm_kernel_write(snd->substream, buf, frames);
 	if (result != frames) {
 		ERROR(card, "Playback error: %d\n", (int)result);
-		set_fs(old_fs);
 		goto try_again;
 	}
-	set_fs(old_fs);
 
 	return 0;
 }

+ 0 - 21
include/linux/dma/dw.h

@@ -50,25 +50,4 @@ static inline int dw_dma_probe(struct dw_dma_chip *chip) { return -ENODEV; }
 static inline int dw_dma_remove(struct dw_dma_chip *chip) { return 0; }
 #endif /* CONFIG_DW_DMAC_CORE */
 
-/* DMA API extensions */
-struct dw_desc;
-
-struct dw_cyclic_desc {
-	struct dw_desc	**desc;
-	unsigned long	periods;
-	void		(*period_callback)(void *param);
-	void		*period_callback_param;
-};
-
-struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
-		dma_addr_t buf_addr, size_t buf_len, size_t period_len,
-		enum dma_transfer_direction direction);
-void dw_dma_cyclic_free(struct dma_chan *chan);
-int dw_dma_cyclic_start(struct dma_chan *chan);
-void dw_dma_cyclic_stop(struct dma_chan *chan);
-
-dma_addr_t dw_dma_get_src_addr(struct dma_chan *chan);
-
-dma_addr_t dw_dma_get_dst_addr(struct dma_chan *chan);
-
 #endif /* _DMA_DW_H */

+ 21 - 0
include/linux/of_graph.h

@@ -43,11 +43,15 @@ struct of_endpoint {
 #ifdef CONFIG_OF
 int of_graph_parse_endpoint(const struct device_node *node,
 				struct of_endpoint *endpoint);
+int of_graph_get_endpoint_count(const struct device_node *np);
 struct device_node *of_graph_get_port_by_id(struct device_node *node, u32 id);
 struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
 					struct device_node *previous);
 struct device_node *of_graph_get_endpoint_by_regs(
 		const struct device_node *parent, int port_reg, int reg);
+struct device_node *of_graph_get_remote_endpoint(
+					const struct device_node *node);
+struct device_node *of_graph_get_port_parent(struct device_node *node);
 struct device_node *of_graph_get_remote_port_parent(
 					const struct device_node *node);
 struct device_node *of_graph_get_remote_port(const struct device_node *node);
@@ -61,6 +65,11 @@ static inline int of_graph_parse_endpoint(const struct device_node *node,
 	return -ENOSYS;
 }
 
+static inline int of_graph_get_endpoint_count(const struct device_node *np)
+{
+	return 0;
+}
+
 static inline struct device_node *of_graph_get_port_by_id(
 					struct device_node *node, u32 id)
 {
@@ -80,6 +89,18 @@ static inline struct device_node *of_graph_get_endpoint_by_regs(
 	return NULL;
 }
 
+static inline struct device_node *of_graph_get_remote_endpoint(
+					const struct device_node *node)
+{
+	return NULL;
+}
+
+static inline struct device_node *of_graph_get_port_parent(
+	struct device_node *node)
+{
+	return NULL;
+}
+
 static inline struct device_node *of_graph_get_remote_port_parent(
 					const struct device_node *node)
 {

+ 9 - 4
include/sound/ak4113.h

@@ -281,6 +281,14 @@ typedef void (ak4113_write_t)(void *private_data, unsigned char addr,
 		unsigned char data);
 typedef unsigned char (ak4113_read_t)(void *private_data, unsigned char addr);
 
+enum {
+	AK4113_PARITY_ERRORS,
+	AK4113_V_BIT_ERRORS,
+	AK4113_QCRC_ERRORS,
+	AK4113_CCRC_ERRORS,
+	AK4113_NUM_ERRORS
+};
+
 struct ak4113 {
 	struct snd_card *card;
 	ak4113_write_t *write;
@@ -292,10 +300,7 @@ struct ak4113 {
 	unsigned char regmap[AK4113_WRITABLE_REGS];
 	struct snd_kcontrol *kctls[AK4113_CONTROLS];
 	struct snd_pcm_substream *substream;
-	unsigned long parity_errors;
-	unsigned long v_bit_errors;
-	unsigned long qcrc_errors;
-	unsigned long ccrc_errors;
+	unsigned long errors[AK4113_NUM_ERRORS];
 	unsigned char rcs0;
 	unsigned char rcs1;
 	unsigned char rcs2;

+ 9 - 4
include/sound/ak4114.h

@@ -163,6 +163,14 @@
 typedef void (ak4114_write_t)(void *private_data, unsigned char addr, unsigned char data);
 typedef unsigned char (ak4114_read_t)(void *private_data, unsigned char addr);
 
+enum {
+	AK4114_PARITY_ERRORS,
+	AK4114_V_BIT_ERRORS,
+	AK4114_QCRC_ERRORS,
+	AK4114_CCRC_ERRORS,
+	AK4114_NUM_ERRORS
+};
+
 struct ak4114 {
 	struct snd_card *card;
 	ak4114_write_t * write;
@@ -176,10 +184,7 @@ struct ak4114 {
 	struct snd_kcontrol *kctls[AK4114_CONTROLS];
 	struct snd_pcm_substream *playback_substream;
 	struct snd_pcm_substream *capture_substream;
-	unsigned long parity_errors;
-	unsigned long v_bit_errors;
-	unsigned long qcrc_errors;
-	unsigned long ccrc_errors;
+	unsigned long errors[AK4114_NUM_ERRORS];
 	unsigned char rcs0;
 	unsigned char rcs1;
 	struct delayed_work work;

+ 9 - 4
include/sound/ak4117.h

@@ -155,6 +155,14 @@
 typedef void (ak4117_write_t)(void *private_data, unsigned char addr, unsigned char data);
 typedef unsigned char (ak4117_read_t)(void *private_data, unsigned char addr);
 
+enum {
+	AK4117_PARITY_ERRORS,
+	AK4117_V_BIT_ERRORS,
+	AK4117_QCRC_ERRORS,
+	AK4117_CCRC_ERRORS,
+	AK4117_NUM_ERRORS
+};
+
 struct ak4117 {
 	struct snd_card *card;
 	ak4117_write_t * write;
@@ -165,10 +173,7 @@ struct ak4117 {
 	unsigned char regmap[5];
 	struct snd_kcontrol *kctls[AK4117_CONTROLS];
 	struct snd_pcm_substream *substream;
-	unsigned long parity_errors;
-	unsigned long v_bit_errors;
-	unsigned long qcrc_errors;
-	unsigned long ccrc_errors;
+	unsigned long errors[AK4117_NUM_ERRORS];
 	unsigned char rcs0;
 	unsigned char rcs1;
 	unsigned char rcs2;

+ 3 - 3
include/sound/core.h

@@ -142,7 +142,7 @@ struct snd_card {
 	wait_queue_head_t power_sleep;
 #endif
 
-#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
 	struct snd_mixer_oss *mixer_oss;
 	int mixer_oss_change_count;
 #endif
@@ -243,7 +243,7 @@ int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size
 
 extern struct snd_card *snd_cards[SNDRV_CARDS];
 int snd_card_locked(int card);
-#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
 #define SND_MIXER_OSS_NOTIFY_REGISTER	0
 #define SND_MIXER_OSS_NOTIFY_DISCONNECT	1
 #define SND_MIXER_OSS_NOTIFY_FREE	2
@@ -394,7 +394,7 @@ static inline void snd_printdd(const char *format, ...) {}
 #define SNDRV_OSS_VERSION         ((3<<16)|(8<<8)|(1<<4)|(0))	/* 3.8.1a */
 
 /* for easier backward-porting */
-#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
+#if IS_ENABLED(CONFIG_GAMEPORT)
 #define gameport_set_dev_parent(gp,xdev) ((gp)->dev.parent = (xdev))
 #define gameport_set_port_data(gp,r) ((gp)->port_data = (r))
 #define gameport_get_port_data(gp) (gp)->port_data

+ 2 - 0
include/sound/cs35l35.h

@@ -99,6 +99,8 @@ struct cs35l35_platform_data {
 	bool shared_bst;
 	/* Specifies this amp is using an external boost supply */
 	bool ext_bst;
+	/* Inductor Value */
+	int boost_ind;
 	/* ClassH Algorithm */
 	struct classh_cfg classh_algo;
 	/* Monitor Config */

+ 1 - 0
include/sound/designware_i2s.h

@@ -47,6 +47,7 @@ struct i2s_platform_data {
 
 	#define DW_I2S_QUIRK_COMP_REG_OFFSET	(1 << 0)
 	#define DW_I2S_QUIRK_COMP_PARAM1	(1 << 1)
+	#define DW_I2S_QUIRK_16BIT_IDX_OVERRIDE (1 << 2)
 	unsigned int quirks;
 	unsigned int i2s_reg_comp1;
 	unsigned int i2s_reg_comp2;

+ 3 - 5
include/sound/emux_synth.h

@@ -25,9 +25,7 @@
 #include <sound/seq_device.h>
 #include <sound/soundfont.h>
 #include <sound/seq_midi_emul.h>
-#ifdef CONFIG_SND_SEQUENCER_OSS
 #include <sound/seq_oss.h>
-#endif
 #include <sound/emux_legacy.h>
 #include <sound/seq_virmidi.h>
 
@@ -66,7 +64,7 @@ struct snd_emux_operators {
 		       const void __user *data, long count);
 	void (*sysex)(struct snd_emux *emu, char *buf, int len, int parsed,
 		      struct snd_midi_channel_set *chset);
-#ifdef CONFIG_SND_SEQUENCER_OSS
+#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS)
 	int (*oss_ioctl)(struct snd_emux *emu, int cmd, int p1, int p2);
 #endif
 };
@@ -129,7 +127,7 @@ struct snd_emux {
 	struct snd_info_entry *proc;
 #endif
 
-#ifdef CONFIG_SND_SEQUENCER_OSS
+#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS)
 	struct snd_seq_device *oss_synth;
 #endif
 };
@@ -150,7 +148,7 @@ struct snd_emux_port {
 #ifdef SNDRV_EMUX_USE_RAW_EFFECT
 	struct snd_emux_effect_table *effect;
 #endif
-#ifdef CONFIG_SND_SEQUENCER_OSS
+#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS)
 	struct snd_seq_oss_arg *oss_arg;
 #endif
 };

+ 9 - 0
include/sound/hdmi-codec.h

@@ -18,9 +18,11 @@
 #ifndef __HDMI_CODEC_H__
 #define __HDMI_CODEC_H__
 
+#include <linux/of_graph.h>
 #include <linux/hdmi.h>
 #include <drm/drm_edid.h>
 #include <sound/asoundef.h>
+#include <sound/soc.h>
 #include <uapi/sound/asound.h>
 
 /*
@@ -87,6 +89,13 @@ struct hdmi_codec_ops {
 	 */
 	int (*get_eld)(struct device *dev, void *data,
 		       uint8_t *buf, size_t len);
+
+	/*
+	 * Getting DAI ID
+	 * Optional
+	 */
+	int (*get_dai_id)(struct snd_soc_component *comment,
+			  struct device_node *endpoint);
 };
 
 /* HDMI codec initalization data */

+ 1 - 1
include/sound/mixer_oss.h

@@ -22,7 +22,7 @@
  *
  */
 
-#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
 
 #define SNDRV_OSS_MAX_MIXERS	32
 

+ 3 - 5
include/sound/opl3.h

@@ -55,10 +55,8 @@
 #include <sound/hwdep.h>
 #include <sound/timer.h>
 #include <sound/seq_midi_emul.h>
-#ifdef CONFIG_SND_SEQUENCER_OSS
 #include <sound/seq_oss.h>
 #include <sound/seq_oss_legacy.h>
-#endif
 #include <sound/seq_device.h>
 #include <sound/asound_fm.h>
 
@@ -321,7 +319,7 @@ struct snd_opl3 {
 	unsigned char fm_mode;		/* OPL mode, see SNDRV_DM_FM_MODE_XXX */
 	unsigned char rhythm;		/* percussion mode flag */
 	unsigned char max_voices;	/* max number of voices */
-#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
+#if IS_ENABLED(CONFIG_SND_SEQUENCER)
 #define SNDRV_OPL3_MODE_SYNTH 0		/* OSS - voices allocated by application */
 #define SNDRV_OPL3_MODE_SEQ 1		/* ALSA - driver handles voice allocation */
 	int synth_mode;			/* synth mode */
@@ -330,7 +328,7 @@ struct snd_opl3 {
 	struct snd_seq_device *seq_dev;	/* sequencer device */
 	struct snd_midi_channel_set * chset;
 
-#ifdef CONFIG_SND_SEQUENCER_OSS
+#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS)
 	struct snd_seq_device *oss_seq_dev;	/* OSS sequencer device */
 	struct snd_midi_channel_set * oss_chset;
 #endif
@@ -374,7 +372,7 @@ int snd_opl3_release(struct snd_hwdep * hw, struct file *file);
 
 void snd_opl3_reset(struct snd_opl3 * opl3);
 
-#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
+#if IS_ENABLED(CONFIG_SND_SEQUENCER)
 long snd_opl3_write(struct snd_hwdep *hw, const char __user *buf, long count,
 		    loff_t *offset);
 int snd_opl3_load_patch(struct snd_opl3 *opl3,

+ 8 - 2
include/sound/pcm-indirect.h

@@ -43,7 +43,7 @@ typedef void (*snd_pcm_indirect_copy_t)(struct snd_pcm_substream *substream,
 /*
  * helper function for playback ack callback
  */
-static inline void
+static inline int
 snd_pcm_indirect_playback_transfer(struct snd_pcm_substream *substream,
 				   struct snd_pcm_indirect *rec,
 				   snd_pcm_indirect_copy_t copy)
@@ -56,6 +56,8 @@ snd_pcm_indirect_playback_transfer(struct snd_pcm_substream *substream,
 	if (diff) {
 		if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
 			diff += runtime->boundary;
+		if (diff < 0)
+			return -EINVAL;
 		rec->sw_ready += (int)frames_to_bytes(runtime, diff);
 		rec->appl_ptr = appl_ptr;
 	}
@@ -82,6 +84,7 @@ snd_pcm_indirect_playback_transfer(struct snd_pcm_substream *substream,
 		rec->hw_ready += bytes;
 		rec->sw_ready -= bytes;
 	}
+	return 0;
 }
 
 /*
@@ -109,7 +112,7 @@ snd_pcm_indirect_playback_pointer(struct snd_pcm_substream *substream,
 /*
  * helper function for capture ack callback
  */
-static inline void
+static inline int
 snd_pcm_indirect_capture_transfer(struct snd_pcm_substream *substream,
 				  struct snd_pcm_indirect *rec,
 				  snd_pcm_indirect_copy_t copy)
@@ -121,6 +124,8 @@ snd_pcm_indirect_capture_transfer(struct snd_pcm_substream *substream,
 	if (diff) {
 		if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
 			diff += runtime->boundary;
+		if (diff < 0)
+			return -EINVAL;
 		rec->sw_ready -= frames_to_bytes(runtime, diff);
 		rec->appl_ptr = appl_ptr;
 	}
@@ -147,6 +152,7 @@ snd_pcm_indirect_capture_transfer(struct snd_pcm_substream *substream,
 		rec->hw_ready -= bytes;
 		rec->sw_ready += bytes;
 	}
+	return 0;
 }
 
 /*

+ 83 - 61
include/sound/pcm.h

@@ -34,7 +34,7 @@
 #define snd_pcm_substream_chip(substream) ((substream)->private_data)
 #define snd_pcm_chip(pcm) ((pcm)->private_data)
 
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_PCM_OSS)
 #include <sound/pcm_oss.h>
 #endif
 
@@ -78,11 +78,13 @@ struct snd_pcm_ops {
 			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);
-	int (*silence)(struct snd_pcm_substream *substream, int channel, 
-		       snd_pcm_uframes_t pos, snd_pcm_uframes_t count);
+	int (*fill_silence)(struct snd_pcm_substream *substream, int channel,
+			    unsigned long pos, unsigned long bytes);
+	int (*copy_user)(struct snd_pcm_substream *substream, int channel,
+			 unsigned long pos, void __user *buf,
+			 unsigned long bytes);
+	int (*copy_kernel)(struct snd_pcm_substream *substream, int channel,
+			   unsigned long pos, void *buf, unsigned long bytes);
 	struct page *(*page)(struct snd_pcm_substream *substream,
 			     unsigned long offset);
 	int (*mmap)(struct snd_pcm_substream *substream, struct vm_area_struct *vma);
@@ -100,9 +102,9 @@ struct snd_pcm_ops {
 #endif
 
 #define SNDRV_PCM_IOCTL1_RESET		0
-#define SNDRV_PCM_IOCTL1_INFO		1
+/* 1 is absent slot. */
 #define SNDRV_PCM_IOCTL1_CHANNEL_INFO	2
-#define SNDRV_PCM_IOCTL1_GSTATE		3
+/* 3 is absent slot. */
 #define SNDRV_PCM_IOCTL1_FIFO_SIZE	4
 
 #define SNDRV_PCM_TRIGGER_STOP		0
@@ -216,6 +218,7 @@ struct snd_pcm_ops {
 struct snd_pcm_file {
 	struct snd_pcm_substream *substream;
 	int no_compat_mmap;
+	unsigned int user_pversion;	/* supported protocol version */
 };
 
 struct snd_pcm_hw_rule;
@@ -418,7 +421,7 @@ struct snd_pcm_runtime {
 	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)
+#if IS_ENABLED(CONFIG_SND_PCM_OSS)
 	/* -- OSS things -- */
 	struct snd_pcm_oss_runtime oss;
 #endif
@@ -464,7 +467,7 @@ struct snd_pcm_substream {
 	unsigned int f_flags;
 	void (*pcm_release)(struct snd_pcm_substream *);
 	struct pid *pid;
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_PCM_OSS)
 	/* -- OSS things -- */
 	struct snd_pcm_oss_substream oss;
 #endif
@@ -494,7 +497,7 @@ struct snd_pcm_str {
 	unsigned int substream_count;
 	unsigned int substream_opened;
 	struct snd_pcm_substream *substream;
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_PCM_OSS)
 	/* -- OSS things -- */
 	struct snd_pcm_oss_stream oss;
 #endif
@@ -526,18 +529,11 @@ struct snd_pcm {
 	void (*private_free) (struct snd_pcm *pcm);
 	bool internal; /* pcm is for internal use only */
 	bool nonatomic; /* whole PCM operations are in non-atomic context */
-#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
+#if IS_ENABLED(CONFIG_SND_PCM_OSS)
 	struct snd_pcm_oss oss;
 #endif
 };
 
-struct snd_pcm_notify {
-	int (*n_register) (struct snd_pcm * pcm);
-	int (*n_disconnect) (struct snd_pcm * pcm);
-	int (*n_unregister) (struct snd_pcm * pcm);
-	struct list_head list;
-};
-
 /*
  *  Registering
  */
@@ -552,7 +548,15 @@ int snd_pcm_new_internal(struct snd_card *card, const char *id, int device,
 		struct snd_pcm **rpcm);
 int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count);
 
+#if IS_ENABLED(CONFIG_SND_PCM_OSS)
+struct snd_pcm_notify {
+	int (*n_register) (struct snd_pcm * pcm);
+	int (*n_disconnect) (struct snd_pcm * pcm);
+	int (*n_unregister) (struct snd_pcm * pcm);
+	struct list_head list;
+};
 int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree);
+#endif
 
 /*
  *  Native I/O
@@ -968,12 +972,6 @@ static inline unsigned int params_buffer_bytes(const struct snd_pcm_hw_params *p
 }
 
 int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v);
-void snd_interval_mul(const struct snd_interval *a, const struct snd_interval *b, struct snd_interval *c);
-void snd_interval_div(const struct snd_interval *a, const struct snd_interval *b, struct snd_interval *c);
-void snd_interval_muldivk(const struct snd_interval *a, const struct snd_interval *b, 
-			  unsigned int k, struct snd_interval *c);
-void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k,
-			  const struct snd_interval *b, struct snd_interval *c);
 int snd_interval_list(struct snd_interval *i, unsigned int count,
 		      const unsigned int *list, unsigned int mask);
 int snd_interval_ranges(struct snd_interval *i, unsigned int count,
@@ -984,15 +982,9 @@ int snd_interval_ratnum(struct snd_interval *i,
 
 void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params);
 void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params, snd_pcm_hw_param_t var);
-int snd_pcm_hw_params_choose(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params);
 
 int snd_pcm_hw_refine(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params);
 
-int snd_pcm_hw_constraints_init(struct snd_pcm_substream *substream);
-int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream);
-
-int snd_pcm_hw_constraint_mask(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var,
-			       u_int32_t mask);
 int snd_pcm_hw_constraint_mask64(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var,
 				 u_int64_t mask);
 int snd_pcm_hw_constraint_minmax(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var,
@@ -1054,7 +1046,7 @@ int snd_pcm_format_unsigned(snd_pcm_format_t format);
 int snd_pcm_format_linear(snd_pcm_format_t format);
 int snd_pcm_format_little_endian(snd_pcm_format_t format);
 int snd_pcm_format_big_endian(snd_pcm_format_t format);
-#if 0 /* just for DocBook */
+#if 0 /* just for kernel-doc */
 /**
  * snd_pcm_format_cpu_endian - Check the PCM format is CPU-endian
  * @format: the format to check
@@ -1080,22 +1072,66 @@ void snd_pcm_set_ops(struct snd_pcm * pcm, int direction,
 void snd_pcm_set_sync(struct snd_pcm_substream *substream);
 int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
 		      unsigned int cmd, void *arg);                      
-int snd_pcm_update_state(struct snd_pcm_substream *substream,
-			 struct snd_pcm_runtime *runtime);
-int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream);
-void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_uframes_t new_hw_ptr);
 void snd_pcm_period_elapsed(struct snd_pcm_substream *substream);
-snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream,
-				    const void __user *buf,
-				    snd_pcm_uframes_t frames);
-snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream,
-				   void __user *buf, snd_pcm_uframes_t frames);
-snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream,
-				     void __user **bufs, snd_pcm_uframes_t frames);
-snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream,
-				    void __user **bufs, snd_pcm_uframes_t frames);
-
-extern const struct snd_pcm_hw_constraint_list snd_pcm_known_rates;
+snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream,
+				     void *buf, bool interleaved,
+				     snd_pcm_uframes_t frames, bool in_kernel);
+
+static inline snd_pcm_sframes_t
+snd_pcm_lib_write(struct snd_pcm_substream *substream,
+		  const void __user *buf, snd_pcm_uframes_t frames)
+{
+	return __snd_pcm_lib_xfer(substream, (void *)buf, true, frames, false);
+}
+
+static inline snd_pcm_sframes_t
+snd_pcm_lib_read(struct snd_pcm_substream *substream,
+		 void __user *buf, snd_pcm_uframes_t frames)
+{
+	return __snd_pcm_lib_xfer(substream, (void *)buf, true, frames, false);
+}
+
+static inline snd_pcm_sframes_t
+snd_pcm_lib_writev(struct snd_pcm_substream *substream,
+		   void __user **bufs, snd_pcm_uframes_t frames)
+{
+	return __snd_pcm_lib_xfer(substream, (void *)bufs, false, frames, false);
+}
+
+static inline snd_pcm_sframes_t
+snd_pcm_lib_readv(struct snd_pcm_substream *substream,
+		  void __user **bufs, snd_pcm_uframes_t frames)
+{
+	return __snd_pcm_lib_xfer(substream, (void *)bufs, false, frames, false);
+}
+
+static inline snd_pcm_sframes_t
+snd_pcm_kernel_write(struct snd_pcm_substream *substream,
+		     const void *buf, snd_pcm_uframes_t frames)
+{
+	return __snd_pcm_lib_xfer(substream, (void *)buf, true, frames, true);
+}
+
+static inline snd_pcm_sframes_t
+snd_pcm_kernel_read(struct snd_pcm_substream *substream,
+		    void *buf, snd_pcm_uframes_t frames)
+{
+	return __snd_pcm_lib_xfer(substream, buf, true, frames, true);
+}
+
+static inline snd_pcm_sframes_t
+snd_pcm_kernel_writev(struct snd_pcm_substream *substream,
+		      void **bufs, snd_pcm_uframes_t frames)
+{
+	return __snd_pcm_lib_xfer(substream, bufs, false, frames, true);
+}
+
+static inline snd_pcm_sframes_t
+snd_pcm_kernel_readv(struct snd_pcm_substream *substream,
+		     void **bufs, snd_pcm_uframes_t frames)
+{
+	return __snd_pcm_lib_xfer(substream, bufs, false, frames, true);
+}
 
 int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime);
 unsigned int snd_pcm_rate_to_rate_bit(unsigned int rate);
@@ -1130,20 +1166,6 @@ static inline void snd_pcm_set_runtime_buffer(struct snd_pcm_substream *substrea
 	}
 }
 
-/*
- *  Timer interface
- */
-
-#ifdef CONFIG_SND_PCM_TIMER
-void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream);
-void snd_pcm_timer_init(struct snd_pcm_substream *substream);
-void snd_pcm_timer_done(struct snd_pcm_substream *substream);
-#else
-static inline void
-snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream) {}
-static inline void snd_pcm_timer_init(struct snd_pcm_substream *substream) {}
-static inline void snd_pcm_timer_done(struct snd_pcm_substream *substream) {}
-#endif
 /**
  * snd_pcm_gettime - Fill the timespec depending on the timestamp mode
  * @runtime: PCM runtime instance

+ 2 - 2
include/sound/rawmidi.h

@@ -30,7 +30,7 @@
 #include <linux/workqueue.h>
 #include <linux/device.h>
 
-#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
+#if IS_ENABLED(CONFIG_SND_SEQUENCER)
 #include <sound/seq_device.h>
 #endif
 
@@ -144,7 +144,7 @@ struct snd_rawmidi {
 
 	struct snd_info_entry *proc_entry;
 
-#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
+#if IS_ENABLED(CONFIG_SND_SEQUENCER)
 	struct snd_seq_device *seq_dev;
 #endif
 };

+ 4 - 2
include/sound/rt5645.h

@@ -21,8 +21,10 @@ struct rt5645_platform_data {
 	/* 0 = IN2P; 1 = GPIO6; 2 = GPIO10; 3 = GPIO12 */
 
 	unsigned int jd_mode;
-	/* Invert JD when jack insert */
-	bool jd_invert;
+	/* Use level triggered irq */
+	bool level_trigger_irq;
+	/* Invert JD1_1 status polarity */
+	bool inv_jd1_1;
 };
 
 #endif

+ 40 - 3
include/sound/simple_card_utils.h

@@ -22,6 +22,11 @@ struct asoc_simple_dai {
 	struct clk *clk;
 };
 
+struct asoc_simple_card_data {
+	u32 convert_rate;
+	u32 convert_channels;
+};
+
 int asoc_simple_card_parse_daifmt(struct device *dev,
 				  struct device_node *node,
 				  struct device_node *codec,
@@ -35,13 +40,18 @@ int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
 				     char *prefix);
 
 #define asoc_simple_card_parse_clk_cpu(dev, node, dai_link, simple_dai)		\
-	asoc_simple_card_parse_clk(dev, node, dai_link->cpu_of_node, simple_dai)
+	asoc_simple_card_parse_clk(dev, node, dai_link->cpu_of_node, simple_dai, \
+				   dai_link->cpu_dai_name)
 #define asoc_simple_card_parse_clk_codec(dev, node, dai_link, simple_dai)	\
-	asoc_simple_card_parse_clk(dev, node, dai_link->codec_of_node, simple_dai)
+	asoc_simple_card_parse_clk(dev, node, dai_link->codec_of_node, simple_dai,\
+				   dai_link->codec_dai_name)
 int asoc_simple_card_parse_clk(struct device *dev,
 			       struct device_node *node,
 			       struct device_node *dai_of_node,
-			       struct asoc_simple_dai *simple_dai);
+			       struct asoc_simple_dai *simple_dai,
+			       const char *name);
+int asoc_simple_card_clk_enable(struct asoc_simple_dai *dai);
+void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai);
 
 #define asoc_simple_card_parse_cpu(node, dai_link,				\
 				   list_name, cells_name, is_single_link)	\
@@ -60,6 +70,22 @@ int asoc_simple_card_parse_dai(struct device_node *node,
 				  const char *cells_name,
 				  int *is_single_links);
 
+#define asoc_simple_card_parse_graph_cpu(ep, dai_link)			\
+	asoc_simple_card_parse_graph_dai(ep, &dai_link->cpu_of_node,	\
+					 &dai_link->cpu_dai_name)
+#define asoc_simple_card_parse_graph_codec(ep, dai_link)		\
+	asoc_simple_card_parse_graph_dai(ep, &dai_link->codec_of_node,	\
+					 &dai_link->codec_dai_name)
+int asoc_simple_card_parse_graph_dai(struct device_node *ep,
+				     struct device_node **endpoint_np,
+				     const char **dai_name);
+
+#define asoc_simple_card_of_parse_tdm(np, dai)			\
+	snd_soc_of_parse_tdm_slot(np,	&(dai)->tx_slot_mask,	\
+					&(dai)->rx_slot_mask,	\
+					&(dai)->slots,		\
+					&(dai)->slot_width);
+
 int asoc_simple_card_init_dai(struct snd_soc_dai *dai,
 			      struct asoc_simple_dai *simple_dai);
 
@@ -69,4 +95,15 @@ void asoc_simple_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link,
 
 int asoc_simple_card_clean_reference(struct snd_soc_card *card);
 
+void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data,
+				      struct snd_pcm_hw_params *params);
+void asoc_simple_card_parse_convert(struct device *dev, char *prefix,
+				    struct asoc_simple_card_data *data);
+
+int asoc_simple_card_of_parse_routing(struct snd_soc_card *card,
+				      char *prefix,
+				      int optional);
+int asoc_simple_card_of_parse_widgets(struct snd_soc_card *card,
+				      char *prefix);
+
 #endif /* __SIMPLE_CARD_UTILS_H */

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

@@ -510,6 +510,13 @@ enum snd_soc_dapm_type {
 	snd_soc_dapm_dai_out,
 	snd_soc_dapm_dai_link,		/* link between two DAI structures */
 	snd_soc_dapm_kcontrol,		/* Auto-disabled kcontrol */
+	snd_soc_dapm_buffer,		/* DSP/CODEC internal buffer */
+	snd_soc_dapm_scheduler,		/* DSP/CODEC internal scheduler */
+	snd_soc_dapm_effect,		/* DSP/CODEC effect component */
+	snd_soc_dapm_src,		/* DSP/CODEC SRC component */
+	snd_soc_dapm_asrc,		/* DSP/CODEC ASRC component */
+	snd_soc_dapm_encoder,		/* FW/SW audio encoder component */
+	snd_soc_dapm_decoder,		/* FW/SW audio decoder component */
 };
 
 enum snd_soc_dapm_subclass {

+ 5 - 0
include/sound/soc-topology.h

@@ -28,6 +28,8 @@ struct snd_soc_component;
 struct snd_soc_tplg_pcm_fe;
 struct snd_soc_dapm_context;
 struct snd_soc_card;
+struct snd_kcontrol_new;
+struct snd_soc_dai_link;
 
 /* object scan be loaded and unloaded in groups with identfying indexes */
 #define SND_SOC_TPLG_INDEX_ALL	0	/* ID that matches all FW objects */
@@ -116,6 +118,9 @@ struct snd_soc_tplg_ops {
 	int (*widget_load)(struct snd_soc_component *,
 		struct snd_soc_dapm_widget *,
 		struct snd_soc_tplg_dapm_widget *);
+	int (*widget_ready)(struct snd_soc_component *,
+		struct snd_soc_dapm_widget *,
+		struct snd_soc_tplg_dapm_widget *);
 	int (*widget_unload)(struct snd_soc_component *,
 		struct snd_soc_dobj *);
 

+ 3 - 0
include/sound/soc.h

@@ -803,6 +803,8 @@ struct snd_soc_component_driver {
 	int (*of_xlate_dai_name)(struct snd_soc_component *component,
 				 struct of_phandle_args *args,
 				 const char **dai_name);
+	int (*of_xlate_dai_id)(struct snd_soc_component *comment,
+			       struct device_node *endpoint);
 	void (*seq_notifier)(struct snd_soc_component *, enum snd_soc_dapm_type,
 		int subseq);
 	int (*stream_event)(struct snd_soc_component *, int event);
@@ -1676,6 +1678,7 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
 				     const char *prefix,
 				     struct device_node **bitclkmaster,
 				     struct device_node **framemaster);
+int snd_soc_get_dai_id(struct device_node *ep);
 int snd_soc_get_dai_name(struct of_phandle_args *args,
 			 const char **dai_name);
 int snd_soc_of_get_dai_name(struct device_node *of_node,

+ 9 - 1
include/uapi/sound/asoc.h

@@ -73,7 +73,15 @@
 #define SND_SOC_TPLG_DAPM_DAI_IN	13
 #define SND_SOC_TPLG_DAPM_DAI_OUT	14
 #define SND_SOC_TPLG_DAPM_DAI_LINK	15
-#define SND_SOC_TPLG_DAPM_LAST		SND_SOC_TPLG_DAPM_DAI_LINK
+#define SND_SOC_TPLG_DAPM_BUFFER	16
+#define SND_SOC_TPLG_DAPM_SCHEDULER	17
+#define SND_SOC_TPLG_DAPM_EFFECT	18
+#define SND_SOC_TPLG_DAPM_SIGGEN	19
+#define SND_SOC_TPLG_DAPM_SRC		20
+#define SND_SOC_TPLG_DAPM_ASRC		21
+#define SND_SOC_TPLG_DAPM_ENCODER	22
+#define SND_SOC_TPLG_DAPM_DECODER	23
+#define SND_SOC_TPLG_DAPM_LAST		SND_SOC_TPLG_DAPM_DECODER
 
 /* Header magic number and string sizes */
 #define SND_SOC_TPLG_MAGIC		0x41536F43 /* ASoC */

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

@@ -152,7 +152,7 @@ struct snd_hwdep_dsp_image {
  *                                                                           *
  *****************************************************************************/
 
-#define SNDRV_PCM_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 13)
+#define SNDRV_PCM_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 14)
 
 typedef unsigned long snd_pcm_uframes_t;
 typedef signed long snd_pcm_sframes_t;
@@ -268,6 +268,7 @@ typedef int __bitwise snd_pcm_subformat_t;
 #define SNDRV_PCM_INFO_MMAP_VALID	0x00000002	/* period data are valid during transfer */
 #define SNDRV_PCM_INFO_DOUBLE		0x00000004	/* Double buffering needed for PCM start/stop */
 #define SNDRV_PCM_INFO_BATCH		0x00000010	/* double buffering */
+#define SNDRV_PCM_INFO_SYNC_APPLPTR	0x00000020	/* need the explicit sync of appl_ptr update */
 #define SNDRV_PCM_INFO_INTERLEAVED	0x00000100	/* channels are interleaved */
 #define SNDRV_PCM_INFO_NONINTERLEAVED	0x00000200	/* channels are not interleaved */
 #define SNDRV_PCM_INFO_COMPLEX		0x00000400	/* complex frame organization (mmap only) */
@@ -563,6 +564,7 @@ enum {
 #define SNDRV_PCM_IOCTL_INFO		_IOR('A', 0x01, struct snd_pcm_info)
 #define SNDRV_PCM_IOCTL_TSTAMP		_IOW('A', 0x02, int)
 #define SNDRV_PCM_IOCTL_TTSTAMP		_IOW('A', 0x03, int)
+#define SNDRV_PCM_IOCTL_USER_PVERSION	_IOW('A', 0x04, int)
 #define SNDRV_PCM_IOCTL_HW_REFINE	_IOWR('A', 0x10, struct snd_pcm_hw_params)
 #define SNDRV_PCM_IOCTL_HW_PARAMS	_IOWR('A', 0x11, struct snd_pcm_hw_params)
 #define SNDRV_PCM_IOCTL_HW_FREE		_IO('A', 0x12)

+ 6 - 2
include/uapi/sound/snd_sst_tokens.h

@@ -161,6 +161,8 @@
  *
  * %SKL_TKL_U32_D0I3_CAPS:	Specifies the D0i3 capability for module
  *
+ * %SKL_TKN_U32_DMA_BUF_SIZE:	DMA buffer size in millisec
+ *
  * module_id and loadable flags dont have tokens as these values will be
  * read from the DSP FW manifest
  */
@@ -213,8 +215,10 @@ enum SKL_TKNS {
 	SKL_TKN_U32_LIB_COUNT,
 	SKL_TKN_STR_LIB_NAME,
 	SKL_TKN_U32_PMODE,
-	SKL_TKL_U32_D0I3_CAPS,
-	SKL_TKN_MAX = SKL_TKL_U32_D0I3_CAPS,
+	SKL_TKL_U32_D0I3_CAPS, /* Typo added at v4.10 */
+	SKL_TKN_U32_D0I3_CAPS = SKL_TKL_U32_D0I3_CAPS,
+	SKL_TKN_U32_DMA_BUF_SIZE,
+	SKL_TKN_MAX = SKL_TKN_U32_DMA_BUF_SIZE,
 };
 
 #endif

+ 4 - 2
sound/Kconfig

@@ -56,7 +56,7 @@ config SOUND_OSS_CORE_PRECLAIM
 
 source "sound/oss/dmasound/Kconfig"
 
-if !M68K && !UML
+if !UML
 
 menuconfig SND
 	tristate "Advanced Linux Sound Architecture"
@@ -110,6 +110,8 @@ source "sound/soc/Kconfig"
 
 source "sound/x86/Kconfig"
 
+source "sound/synth/Kconfig"
+
 endif # SND
 
 menuconfig SOUND_PRIME
@@ -125,7 +127,7 @@ source "sound/oss/Kconfig"
 
 endif # SOUND_PRIME
 
-endif # !M68K
+endif # !UML
 
 endif # SOUND
 

+ 7 - 7
sound/aoa/codecs/tas.c

@@ -271,7 +271,7 @@ static int tas_snd_vol_put(struct snd_kcontrol *kcontrol,
 	return 1;
 }
 
-static struct snd_kcontrol_new volume_control = {
+static const struct snd_kcontrol_new volume_control = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Master Playback Volume",
 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
@@ -314,7 +314,7 @@ static int tas_snd_mute_put(struct snd_kcontrol *kcontrol,
 	return 1;
 }
 
-static struct snd_kcontrol_new mute_control = {
+static const struct snd_kcontrol_new mute_control = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Master Playback Switch",
 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
@@ -426,7 +426,7 @@ static int tas_snd_drc_range_put(struct snd_kcontrol *kcontrol,
 	return 1;
 }
 
-static struct snd_kcontrol_new drc_range_control = {
+static const struct snd_kcontrol_new drc_range_control = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "DRC Range",
 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
@@ -466,7 +466,7 @@ static int tas_snd_drc_switch_put(struct snd_kcontrol *kcontrol,
 	return 1;
 }
 
-static struct snd_kcontrol_new drc_switch_control = {
+static const struct snd_kcontrol_new drc_switch_control = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "DRC Range Switch",
 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
@@ -524,7 +524,7 @@ static int tas_snd_capture_source_put(struct snd_kcontrol *kcontrol,
 	return 1;
 }
 
-static struct snd_kcontrol_new capture_source_control = {
+static const struct snd_kcontrol_new capture_source_control = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	/* If we name this 'Input Source', it properly shows up in
 	 * alsamixer as a selection, * but it's shown under the
@@ -586,7 +586,7 @@ static int tas_snd_treble_put(struct snd_kcontrol *kcontrol,
 	return 1;
 }
 
-static struct snd_kcontrol_new treble_control = {
+static const struct snd_kcontrol_new treble_control = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Treble",
 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
@@ -637,7 +637,7 @@ static int tas_snd_bass_put(struct snd_kcontrol *kcontrol,
 	return 1;
 }
 
-static struct snd_kcontrol_new bass_control = {
+static const struct snd_kcontrol_new bass_control = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Bass",
 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,

+ 4 - 4
sound/aoa/fabrics/layout.c

@@ -707,7 +707,7 @@ static int detect_choice_put(struct snd_kcontrol *kcontrol,
 	return 1;
 }
 
-static struct snd_kcontrol_new headphone_detect_choice = {
+static const struct snd_kcontrol_new headphone_detect_choice = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Headphone Detect Autoswitch",
 	.info = control_info,
@@ -717,7 +717,7 @@ static struct snd_kcontrol_new headphone_detect_choice = {
 	.private_value = 0,
 };
 
-static struct snd_kcontrol_new lineout_detect_choice = {
+static const struct snd_kcontrol_new lineout_detect_choice = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Line-Out Detect Autoswitch",
 	.info = control_info,
@@ -749,7 +749,7 @@ static int detected_get(struct snd_kcontrol *kcontrol,
 	return 0;
 }
 
-static struct snd_kcontrol_new headphone_detected = {
+static const struct snd_kcontrol_new headphone_detected = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Headphone Detected",
 	.info = control_info,
@@ -758,7 +758,7 @@ static struct snd_kcontrol_new headphone_detected = {
 	.private_value = 0,
 };
 
-static struct snd_kcontrol_new lineout_detected = {
+static const struct snd_kcontrol_new lineout_detected = {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "Line-Out Detected",
 	.info = control_info,

+ 3 - 10
sound/atmel/Kconfig

@@ -1,18 +1,11 @@
-menu "Atmel devices (AVR32 and AT91)"
-	depends on AVR32 || ARCH_AT91
-
-config SND_ATMEL_ABDAC
-	tristate "Atmel Audio Bitstream DAC (ABDAC) driver"
-	select SND_PCM
-	depends on DW_DMAC && AVR32
-	help
-	  ALSA sound driver for the Atmel Audio Bitstream DAC (ABDAC).
+menu "Atmel devices (AT91)"
+	depends on ARCH_AT91
 
 config SND_ATMEL_AC97C
 	tristate "Atmel AC97 Controller (AC97C) driver"
 	select SND_PCM
 	select SND_AC97_CODEC
-	depends on (DW_DMAC && AVR32) || ARCH_AT91
+	depends on ARCH_AT91
 	help
 	  ALSA sound driver for the Atmel AC97 controller.
 

+ 0 - 2
sound/atmel/Makefile

@@ -1,5 +1,3 @@
-snd-atmel-abdac-objs		:= abdac.o
 snd-atmel-ac97c-objs		:= ac97c.o
 
-obj-$(CONFIG_SND_ATMEL_ABDAC)	+= snd-atmel-abdac.o
 obj-$(CONFIG_SND_ATMEL_AC97C)	+= snd-atmel-ac97c.o

+ 0 - 610
sound/atmel/abdac.c

@@ -1,610 +0,0 @@
-/*
- * Driver for the Atmel on-chip Audio Bitstream DAC (ABDAC)
- *
- * Copyright (C) 2006-2009 Atmel Corporation
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#include <linux/clk.h>
-#include <linux/bitmap.h>
-#include <linux/dmaengine.h>
-#include <linux/dma-mapping.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/types.h>
-#include <linux/io.h>
-
-#include <sound/core.h>
-#include <sound/initval.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/atmel-abdac.h>
-
-#include <linux/platform_data/dma-dw.h>
-#include <linux/dma/dw.h>
-
-/* DAC register offsets */
-#define DAC_DATA                                0x0000
-#define DAC_CTRL                                0x0008
-#define DAC_INT_MASK                            0x000c
-#define DAC_INT_EN                              0x0010
-#define DAC_INT_DIS                             0x0014
-#define DAC_INT_CLR                             0x0018
-#define DAC_INT_STATUS                          0x001c
-
-/* Bitfields in CTRL */
-#define DAC_SWAP_OFFSET                         30
-#define DAC_SWAP_SIZE                           1
-#define DAC_EN_OFFSET                           31
-#define DAC_EN_SIZE                             1
-
-/* Bitfields in INT_MASK/INT_EN/INT_DIS/INT_STATUS/INT_CLR */
-#define DAC_UNDERRUN_OFFSET                     28
-#define DAC_UNDERRUN_SIZE                       1
-#define DAC_TX_READY_OFFSET                     29
-#define DAC_TX_READY_SIZE                       1
-
-/* Bit manipulation macros */
-#define DAC_BIT(name)					\
-	(1 << DAC_##name##_OFFSET)
-#define DAC_BF(name, value)				\
-	(((value) & ((1 << DAC_##name##_SIZE) - 1))	\
-	 << DAC_##name##_OFFSET)
-#define DAC_BFEXT(name, value)				\
-	(((value) >> DAC_##name##_OFFSET)		\
-	 & ((1 << DAC_##name##_SIZE) - 1))
-#define DAC_BFINS(name, value, old)			\
-	(((old) & ~(((1 << DAC_##name##_SIZE) - 1)	\
-		    << DAC_##name##_OFFSET))		\
-	 | DAC_BF(name, value))
-
-/* Register access macros */
-#define dac_readl(port, reg)				\
-	__raw_readl((port)->regs + DAC_##reg)
-#define dac_writel(port, reg, value)			\
-	__raw_writel((value), (port)->regs + DAC_##reg)
-
-/*
- * ABDAC supports a maximum of 6 different rates from a generic clock. The
- * generic clock has a power of two divider, which gives 6 steps from 192 kHz
- * to 5112 Hz.
- */
-#define MAX_NUM_RATES	6
-/* ALSA seems to use rates between 192000 Hz and 5112 Hz. */
-#define RATE_MAX	192000
-#define RATE_MIN	5112
-
-enum {
-	DMA_READY = 0,
-};
-
-struct atmel_abdac_dma {
-	struct dma_chan		*chan;
-	struct dw_cyclic_desc	*cdesc;
-};
-
-struct atmel_abdac {
-	struct clk				*pclk;
-	struct clk				*sample_clk;
-	struct platform_device			*pdev;
-	struct atmel_abdac_dma			dma;
-
-	struct snd_pcm_hw_constraint_list	constraints_rates;
-	struct snd_pcm_substream		*substream;
-	struct snd_card				*card;
-	struct snd_pcm				*pcm;
-
-	void __iomem				*regs;
-	unsigned long				flags;
-	unsigned int				rates[MAX_NUM_RATES];
-	unsigned int				rates_num;
-	int					irq;
-};
-
-#define get_dac(card) ((struct atmel_abdac *)(card)->private_data)
-
-/* This function is called by the DMA driver. */
-static void atmel_abdac_dma_period_done(void *arg)
-{
-	struct atmel_abdac *dac = arg;
-	snd_pcm_period_elapsed(dac->substream);
-}
-
-static int atmel_abdac_prepare_dma(struct atmel_abdac *dac,
-		struct snd_pcm_substream *substream,
-		enum dma_data_direction direction)
-{
-	struct dma_chan			*chan = dac->dma.chan;
-	struct dw_cyclic_desc		*cdesc;
-	struct snd_pcm_runtime		*runtime = substream->runtime;
-	unsigned long			buffer_len, period_len;
-
-	/*
-	 * We don't do DMA on "complex" transfers, i.e. with
-	 * non-halfword-aligned buffers or lengths.
-	 */
-	if (runtime->dma_addr & 1 || runtime->buffer_size & 1) {
-		dev_dbg(&dac->pdev->dev, "too complex transfer\n");
-		return -EINVAL;
-	}
-
-	buffer_len = frames_to_bytes(runtime, runtime->buffer_size);
-	period_len = frames_to_bytes(runtime, runtime->period_size);
-
-	cdesc = dw_dma_cyclic_prep(chan, runtime->dma_addr, buffer_len,
-			period_len, DMA_MEM_TO_DEV);
-	if (IS_ERR(cdesc)) {
-		dev_dbg(&dac->pdev->dev, "could not prepare cyclic DMA\n");
-		return PTR_ERR(cdesc);
-	}
-
-	cdesc->period_callback = atmel_abdac_dma_period_done;
-	cdesc->period_callback_param = dac;
-
-	dac->dma.cdesc = cdesc;
-
-	set_bit(DMA_READY, &dac->flags);
-
-	return 0;
-}
-
-static struct snd_pcm_hardware atmel_abdac_hw = {
-	.info			= (SNDRV_PCM_INFO_MMAP
-				  | SNDRV_PCM_INFO_MMAP_VALID
-				  | SNDRV_PCM_INFO_INTERLEAVED
-				  | SNDRV_PCM_INFO_BLOCK_TRANSFER
-				  | SNDRV_PCM_INFO_RESUME
-				  | SNDRV_PCM_INFO_PAUSE),
-	.formats		= (SNDRV_PCM_FMTBIT_S16_BE),
-	.rates			= (SNDRV_PCM_RATE_KNOT),
-	.rate_min		= RATE_MIN,
-	.rate_max		= RATE_MAX,
-	.channels_min		= 2,
-	.channels_max		= 2,
-	.buffer_bytes_max	= 64 * 4096,
-	.period_bytes_min	= 4096,
-	.period_bytes_max	= 4096,
-	.periods_min		= 6,
-	.periods_max		= 64,
-};
-
-static int atmel_abdac_open(struct snd_pcm_substream *substream)
-{
-	struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
-
-	dac->substream = substream;
-	atmel_abdac_hw.rate_max = dac->rates[dac->rates_num - 1];
-	atmel_abdac_hw.rate_min = dac->rates[0];
-	substream->runtime->hw = atmel_abdac_hw;
-
-	return snd_pcm_hw_constraint_list(substream->runtime, 0,
-			SNDRV_PCM_HW_PARAM_RATE, &dac->constraints_rates);
-}
-
-static int atmel_abdac_close(struct snd_pcm_substream *substream)
-{
-	struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
-	dac->substream = NULL;
-	return 0;
-}
-
-static int atmel_abdac_hw_params(struct snd_pcm_substream *substream,
-		struct snd_pcm_hw_params *hw_params)
-{
-	struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
-	int retval;
-
-	retval = snd_pcm_lib_malloc_pages(substream,
-			params_buffer_bytes(hw_params));
-	if (retval < 0)
-		return retval;
-	/* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
-	if (retval == 1)
-		if (test_and_clear_bit(DMA_READY, &dac->flags))
-			dw_dma_cyclic_free(dac->dma.chan);
-
-	return retval;
-}
-
-static int atmel_abdac_hw_free(struct snd_pcm_substream *substream)
-{
-	struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
-	if (test_and_clear_bit(DMA_READY, &dac->flags))
-		dw_dma_cyclic_free(dac->dma.chan);
-	return snd_pcm_lib_free_pages(substream);
-}
-
-static int atmel_abdac_prepare(struct snd_pcm_substream *substream)
-{
-	struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
-	int retval;
-
-	retval = clk_set_rate(dac->sample_clk, 256 * substream->runtime->rate);
-	if (retval)
-		return retval;
-
-	if (!test_bit(DMA_READY, &dac->flags))
-		retval = atmel_abdac_prepare_dma(dac, substream, DMA_TO_DEVICE);
-
-	return retval;
-}
-
-static int atmel_abdac_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-	struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
-	int retval = 0;
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
-	case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
-	case SNDRV_PCM_TRIGGER_START:
-		clk_prepare_enable(dac->sample_clk);
-		retval = dw_dma_cyclic_start(dac->dma.chan);
-		if (retval)
-			goto out;
-		dac_writel(dac, CTRL, DAC_BIT(EN));
-		break;
-	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
-	case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
-	case SNDRV_PCM_TRIGGER_STOP:
-		dw_dma_cyclic_stop(dac->dma.chan);
-		dac_writel(dac, DATA, 0);
-		dac_writel(dac, CTRL, 0);
-		clk_disable_unprepare(dac->sample_clk);
-		break;
-	default:
-		retval = -EINVAL;
-		break;
-	}
-out:
-	return retval;
-}
-
-static snd_pcm_uframes_t
-atmel_abdac_pointer(struct snd_pcm_substream *substream)
-{
-	struct atmel_abdac	*dac = snd_pcm_substream_chip(substream);
-	struct snd_pcm_runtime	*runtime = substream->runtime;
-	snd_pcm_uframes_t	frames;
-	unsigned long		bytes;
-
-	bytes = dw_dma_get_src_addr(dac->dma.chan);
-	bytes -= runtime->dma_addr;
-
-	frames = bytes_to_frames(runtime, bytes);
-	if (frames >= runtime->buffer_size)
-		frames -= runtime->buffer_size;
-
-	return frames;
-}
-
-static irqreturn_t abdac_interrupt(int irq, void *dev_id)
-{
-	struct atmel_abdac *dac = dev_id;
-	u32 status;
-
-	status = dac_readl(dac, INT_STATUS);
-	if (status & DAC_BIT(UNDERRUN)) {
-		dev_err(&dac->pdev->dev, "underrun detected\n");
-		dac_writel(dac, INT_CLR, DAC_BIT(UNDERRUN));
-	} else {
-		dev_err(&dac->pdev->dev, "spurious interrupt (status=0x%x)\n",
-			status);
-		dac_writel(dac, INT_CLR, status);
-	}
-
-	return IRQ_HANDLED;
-}
-
-static struct snd_pcm_ops atmel_abdac_ops = {
-	.open		= atmel_abdac_open,
-	.close		= atmel_abdac_close,
-	.ioctl		= snd_pcm_lib_ioctl,
-	.hw_params	= atmel_abdac_hw_params,
-	.hw_free	= atmel_abdac_hw_free,
-	.prepare	= atmel_abdac_prepare,
-	.trigger	= atmel_abdac_trigger,
-	.pointer	= atmel_abdac_pointer,
-};
-
-static int atmel_abdac_pcm_new(struct atmel_abdac *dac)
-{
-	struct snd_pcm_hardware hw = atmel_abdac_hw;
-	struct snd_pcm *pcm;
-	int retval;
-
-	retval = snd_pcm_new(dac->card, dac->card->shortname,
-			dac->pdev->id, 1, 0, &pcm);
-	if (retval)
-		return retval;
-
-	strcpy(pcm->name, dac->card->shortname);
-	pcm->private_data = dac;
-	pcm->info_flags = 0;
-	dac->pcm = pcm;
-
-	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &atmel_abdac_ops);
-
-	retval = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
-			&dac->pdev->dev, hw.periods_min * hw.period_bytes_min,
-			hw.buffer_bytes_max);
-
-	return retval;
-}
-
-static bool filter(struct dma_chan *chan, void *slave)
-{
-	struct dw_dma_slave *dws = slave;
-
-	if (dws->dma_dev == chan->device->dev) {
-		chan->private = dws;
-		return true;
-	} else
-		return false;
-}
-
-static int set_sample_rates(struct atmel_abdac *dac)
-{
-	long new_rate = RATE_MAX;
-	int retval = -EINVAL;
-	int index = 0;
-
-	/* we start at 192 kHz and work our way down to 5112 Hz */
-	while (new_rate >= RATE_MIN && index < (MAX_NUM_RATES + 1)) {
-		new_rate = clk_round_rate(dac->sample_clk, 256 * new_rate);
-		if (new_rate <= 0)
-			break;
-		/* make sure we are below the ABDAC clock */
-		if (index < MAX_NUM_RATES &&
-		    new_rate <= clk_get_rate(dac->pclk)) {
-			dac->rates[index] = new_rate / 256;
-			index++;
-		}
-		/* divide by 256 and then by two to get next rate */
-		new_rate /= 256 * 2;
-	}
-
-	if (index) {
-		int i;
-
-		/* reverse array, smallest go first */
-		for (i = 0; i < (index / 2); i++) {
-			unsigned int tmp = dac->rates[index - 1 - i];
-			dac->rates[index - 1 - i] = dac->rates[i];
-			dac->rates[i] = tmp;
-		}
-
-		dac->constraints_rates.count = index;
-		dac->constraints_rates.list = dac->rates;
-		dac->constraints_rates.mask = 0;
-		dac->rates_num = index;
-
-		retval = 0;
-	}
-
-	return retval;
-}
-
-static int atmel_abdac_probe(struct platform_device *pdev)
-{
-	struct snd_card		*card;
-	struct atmel_abdac	*dac;
-	struct resource		*regs;
-	struct atmel_abdac_pdata	*pdata;
-	struct clk		*pclk;
-	struct clk		*sample_clk;
-	int			retval;
-	int			irq;
-
-	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!regs) {
-		dev_dbg(&pdev->dev, "no memory resource\n");
-		return -ENXIO;
-	}
-
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0) {
-		dev_dbg(&pdev->dev, "could not get IRQ number\n");
-		return irq;
-	}
-
-	pdata = pdev->dev.platform_data;
-	if (!pdata) {
-		dev_dbg(&pdev->dev, "no platform data\n");
-		return -ENXIO;
-	}
-
-	pclk = clk_get(&pdev->dev, "pclk");
-	if (IS_ERR(pclk)) {
-		dev_dbg(&pdev->dev, "no peripheral clock\n");
-		return PTR_ERR(pclk);
-	}
-	sample_clk = clk_get(&pdev->dev, "sample_clk");
-	if (IS_ERR(sample_clk)) {
-		dev_dbg(&pdev->dev, "no sample clock\n");
-		retval = PTR_ERR(sample_clk);
-		goto out_put_pclk;
-	}
-	clk_prepare_enable(pclk);
-
-	retval = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1,
-			      SNDRV_DEFAULT_STR1, THIS_MODULE,
-			      sizeof(struct atmel_abdac), &card);
-	if (retval) {
-		dev_dbg(&pdev->dev, "could not create sound card device\n");
-		goto out_put_sample_clk;
-	}
-
-	dac = get_dac(card);
-
-	dac->irq = irq;
-	dac->card = card;
-	dac->pclk = pclk;
-	dac->sample_clk = sample_clk;
-	dac->pdev = pdev;
-
-	retval = set_sample_rates(dac);
-	if (retval < 0) {
-		dev_dbg(&pdev->dev, "could not set supported rates\n");
-		goto out_free_card;
-	}
-
-	dac->regs = ioremap(regs->start, resource_size(regs));
-	if (!dac->regs) {
-		dev_dbg(&pdev->dev, "could not remap register memory\n");
-		retval = -ENOMEM;
-		goto out_free_card;
-	}
-
-	/* make sure the DAC is silent and disabled */
-	dac_writel(dac, DATA, 0);
-	dac_writel(dac, CTRL, 0);
-
-	retval = request_irq(irq, abdac_interrupt, 0, "abdac", dac);
-	if (retval) {
-		dev_dbg(&pdev->dev, "could not request irq\n");
-		goto out_unmap_regs;
-	}
-
-	if (pdata->dws.dma_dev) {
-		dma_cap_mask_t mask;
-
-		dma_cap_zero(mask);
-		dma_cap_set(DMA_SLAVE, mask);
-
-		dac->dma.chan = dma_request_channel(mask, filter, &pdata->dws);
-		if (dac->dma.chan) {
-			struct dma_slave_config dma_conf = {
-				.dst_addr = regs->start + DAC_DATA,
-				.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
-				.src_maxburst = 1,
-				.dst_maxburst = 1,
-				.direction = DMA_MEM_TO_DEV,
-				.device_fc = false,
-			};
-
-			dmaengine_slave_config(dac->dma.chan, &dma_conf);
-		}
-	}
-	if (!pdata->dws.dma_dev || !dac->dma.chan) {
-		dev_dbg(&pdev->dev, "DMA not available\n");
-		retval = -ENODEV;
-		goto out_unmap_regs;
-	}
-
-	strcpy(card->driver, "Atmel ABDAC");
-	strcpy(card->shortname, "Atmel ABDAC");
-	sprintf(card->longname, "Atmel Audio Bitstream DAC");
-
-	retval = atmel_abdac_pcm_new(dac);
-	if (retval) {
-		dev_dbg(&pdev->dev, "could not register ABDAC pcm device\n");
-		goto out_release_dma;
-	}
-
-	retval = snd_card_register(card);
-	if (retval) {
-		dev_dbg(&pdev->dev, "could not register sound card\n");
-		goto out_release_dma;
-	}
-
-	platform_set_drvdata(pdev, card);
-
-	dev_info(&pdev->dev, "Atmel ABDAC at 0x%p using %s\n",
-			dac->regs, dev_name(&dac->dma.chan->dev->device));
-
-	return retval;
-
-out_release_dma:
-	dma_release_channel(dac->dma.chan);
-	dac->dma.chan = NULL;
-out_unmap_regs:
-	iounmap(dac->regs);
-out_free_card:
-	snd_card_free(card);
-out_put_sample_clk:
-	clk_put(sample_clk);
-	clk_disable_unprepare(pclk);
-out_put_pclk:
-	clk_put(pclk);
-	return retval;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int atmel_abdac_suspend(struct device *pdev)
-{
-	struct snd_card *card = dev_get_drvdata(pdev);
-	struct atmel_abdac *dac = card->private_data;
-
-	dw_dma_cyclic_stop(dac->dma.chan);
-	clk_disable_unprepare(dac->sample_clk);
-	clk_disable_unprepare(dac->pclk);
-
-	return 0;
-}
-
-static int atmel_abdac_resume(struct device *pdev)
-{
-	struct snd_card *card = dev_get_drvdata(pdev);
-	struct atmel_abdac *dac = card->private_data;
-
-	clk_prepare_enable(dac->pclk);
-	clk_prepare_enable(dac->sample_clk);
-	if (test_bit(DMA_READY, &dac->flags))
-		dw_dma_cyclic_start(dac->dma.chan);
-
-	return 0;
-}
-
-static SIMPLE_DEV_PM_OPS(atmel_abdac_pm, atmel_abdac_suspend, atmel_abdac_resume);
-#define ATMEL_ABDAC_PM_OPS	&atmel_abdac_pm
-#else
-#define ATMEL_ABDAC_PM_OPS	NULL
-#endif
-
-static int atmel_abdac_remove(struct platform_device *pdev)
-{
-	struct snd_card *card = platform_get_drvdata(pdev);
-	struct atmel_abdac *dac = get_dac(card);
-
-	clk_put(dac->sample_clk);
-	clk_disable_unprepare(dac->pclk);
-	clk_put(dac->pclk);
-
-	dma_release_channel(dac->dma.chan);
-	dac->dma.chan = NULL;
-	iounmap(dac->regs);
-	free_irq(dac->irq, dac);
-	snd_card_free(card);
-
-	return 0;
-}
-
-static struct platform_driver atmel_abdac_driver = {
-	.remove		= atmel_abdac_remove,
-	.driver		= {
-		.name	= "atmel_abdac",
-		.pm	= ATMEL_ABDAC_PM_OPS,
-	},
-};
-
-static int __init atmel_abdac_init(void)
-{
-	return platform_driver_probe(&atmel_abdac_driver,
-			atmel_abdac_probe);
-}
-module_init(atmel_abdac_init);
-
-static void __exit atmel_abdac_exit(void)
-{
-	platform_driver_unregister(&atmel_abdac_driver);
-}
-module_exit(atmel_abdac_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Driver for Atmel Audio Bitstream DAC (ABDAC)");
-MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");

+ 73 - 378
sound/atmel/ac97c.c

@@ -11,8 +11,6 @@
 #include <linux/delay.h>
 #include <linux/bitmap.h>
 #include <linux/device.h>
-#include <linux/dmaengine.h>
-#include <linux/dma-mapping.h>
 #include <linux/atmel_pdc.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
@@ -34,36 +32,14 @@
 #include <sound/atmel-ac97c.h>
 #include <sound/memalloc.h>
 
-#include <linux/platform_data/dma-dw.h>
-#include <linux/dma/dw.h>
-
-#ifdef CONFIG_AVR32
-#include <mach/cpu.h>
-#else
-#define cpu_is_at32ap7000() 0
-#endif
-
 #include "ac97c.h"
 
-enum {
-	DMA_TX_READY = 0,
-	DMA_RX_READY,
-	DMA_TX_CHAN_PRESENT,
-	DMA_RX_CHAN_PRESENT,
-};
-
 /* Serialize access to opened variable */
 static DEFINE_MUTEX(opened_mutex);
 
-struct atmel_ac97c_dma {
-	struct dma_chan			*rx_chan;
-	struct dma_chan			*tx_chan;
-};
-
 struct atmel_ac97c {
 	struct clk			*pclk;
 	struct platform_device		*pdev;
-	struct atmel_ac97c_dma		dma;
 
 	struct snd_pcm_substream	*playback_substream;
 	struct snd_pcm_substream	*capture_substream;
@@ -74,7 +50,6 @@ struct atmel_ac97c {
 
 	u64				cur_format;
 	unsigned int			cur_rate;
-	unsigned long			flags;
 	int				playback_period, capture_period;
 	/* Serialize access to opened variable */
 	spinlock_t			lock;
@@ -91,65 +66,6 @@ struct atmel_ac97c {
 #define ac97c_readl(chip, reg)				\
 	__raw_readl((chip)->regs + AC97C_##reg)
 
-/* This function is called by the DMA driver. */
-static void atmel_ac97c_dma_playback_period_done(void *arg)
-{
-	struct atmel_ac97c *chip = arg;
-	snd_pcm_period_elapsed(chip->playback_substream);
-}
-
-static void atmel_ac97c_dma_capture_period_done(void *arg)
-{
-	struct atmel_ac97c *chip = arg;
-	snd_pcm_period_elapsed(chip->capture_substream);
-}
-
-static int atmel_ac97c_prepare_dma(struct atmel_ac97c *chip,
-		struct snd_pcm_substream *substream,
-		enum dma_transfer_direction direction)
-{
-	struct dma_chan			*chan;
-	struct dw_cyclic_desc		*cdesc;
-	struct snd_pcm_runtime		*runtime = substream->runtime;
-	unsigned long			buffer_len, period_len;
-
-	/*
-	 * We don't do DMA on "complex" transfers, i.e. with
-	 * non-halfword-aligned buffers or lengths.
-	 */
-	if (runtime->dma_addr & 1 || runtime->buffer_size & 1) {
-		dev_dbg(&chip->pdev->dev, "too complex transfer\n");
-		return -EINVAL;
-	}
-
-	if (direction == DMA_MEM_TO_DEV)
-		chan = chip->dma.tx_chan;
-	else
-		chan = chip->dma.rx_chan;
-
-	buffer_len = frames_to_bytes(runtime, runtime->buffer_size);
-	period_len = frames_to_bytes(runtime, runtime->period_size);
-
-	cdesc = dw_dma_cyclic_prep(chan, runtime->dma_addr, buffer_len,
-			period_len, direction);
-	if (IS_ERR(cdesc)) {
-		dev_dbg(&chip->pdev->dev, "could not prepare cyclic DMA\n");
-		return PTR_ERR(cdesc);
-	}
-
-	if (direction == DMA_MEM_TO_DEV) {
-		cdesc->period_callback = atmel_ac97c_dma_playback_period_done;
-		set_bit(DMA_TX_READY, &chip->flags);
-	} else {
-		cdesc->period_callback = atmel_ac97c_dma_capture_period_done;
-		set_bit(DMA_RX_READY, &chip->flags);
-	}
-
-	cdesc->period_callback_param = chip;
-
-	return 0;
-}
-
 static struct snd_pcm_hardware atmel_ac97c_hw = {
 	.info			= (SNDRV_PCM_INFO_MMAP
 				  | SNDRV_PCM_INFO_MMAP_VALID
@@ -254,13 +170,7 @@ static int atmel_ac97c_playback_hw_params(struct snd_pcm_substream *substream,
 					params_buffer_bytes(hw_params));
 	if (retval < 0)
 		return retval;
-	/* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
-	if (cpu_is_at32ap7000()) {
-		/* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
-		if (retval == 1)
-			if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
-				dw_dma_cyclic_free(chip->dma.tx_chan);
-	}
+
 	/* Set restrictions to params. */
 	mutex_lock(&opened_mutex);
 	chip->cur_rate = params_rate(hw_params);
@@ -280,10 +190,6 @@ static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream,
 					params_buffer_bytes(hw_params));
 	if (retval < 0)
 		return retval;
-	/* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
-	if (cpu_is_at32ap7000() && retval == 1)
-		if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
-			dw_dma_cyclic_free(chip->dma.rx_chan);
 
 	/* Set restrictions to params. */
 	mutex_lock(&opened_mutex);
@@ -294,26 +200,6 @@ static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream,
 	return retval;
 }
 
-static int atmel_ac97c_playback_hw_free(struct snd_pcm_substream *substream)
-{
-	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
-	if (cpu_is_at32ap7000()) {
-		if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
-			dw_dma_cyclic_free(chip->dma.tx_chan);
-	}
-	return snd_pcm_lib_free_pages(substream);
-}
-
-static int atmel_ac97c_capture_hw_free(struct snd_pcm_substream *substream)
-{
-	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
-	if (cpu_is_at32ap7000()) {
-		if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
-			dw_dma_cyclic_free(chip->dma.rx_chan);
-	}
-	return snd_pcm_lib_free_pages(substream);
-}
-
 static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream)
 {
 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
@@ -349,8 +235,6 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream)
 
 	switch (runtime->format) {
 	case SNDRV_PCM_FORMAT_S16_LE:
-		if (cpu_is_at32ap7000())
-			word |= AC97C_CMR_CEM_LITTLE;
 		break;
 	case SNDRV_PCM_FORMAT_S16_BE: /* fall through */
 		word &= ~(AC97C_CMR_CEM_LITTLE);
@@ -389,18 +273,11 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream)
 		dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n",
 				runtime->rate);
 
-	if (cpu_is_at32ap7000()) {
-		if (!test_bit(DMA_TX_READY, &chip->flags))
-			retval = atmel_ac97c_prepare_dma(chip, substream,
-					DMA_MEM_TO_DEV);
-	} else {
-		/* Initialize and start the PDC */
-		writel(runtime->dma_addr, chip->regs + ATMEL_PDC_TPR);
-		writel(block_size / 2, chip->regs + ATMEL_PDC_TCR);
-		writel(runtime->dma_addr + block_size,
-				chip->regs + ATMEL_PDC_TNPR);
-		writel(block_size / 2, chip->regs + ATMEL_PDC_TNCR);
-	}
+	/* Initialize and start the PDC */
+	writel(runtime->dma_addr, chip->regs + ATMEL_PDC_TPR);
+	writel(block_size / 2, chip->regs + ATMEL_PDC_TCR);
+	writel(runtime->dma_addr + block_size, chip->regs + ATMEL_PDC_TNPR);
+	writel(block_size / 2, chip->regs + ATMEL_PDC_TNCR);
 
 	return retval;
 }
@@ -440,8 +317,6 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream)
 
 	switch (runtime->format) {
 	case SNDRV_PCM_FORMAT_S16_LE:
-		if (cpu_is_at32ap7000())
-			word |= AC97C_CMR_CEM_LITTLE;
 		break;
 	case SNDRV_PCM_FORMAT_S16_BE: /* fall through */
 		word &= ~(AC97C_CMR_CEM_LITTLE);
@@ -480,18 +355,11 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream)
 		dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n",
 				runtime->rate);
 
-	if (cpu_is_at32ap7000()) {
-		if (!test_bit(DMA_RX_READY, &chip->flags))
-			retval = atmel_ac97c_prepare_dma(chip, substream,
-					DMA_DEV_TO_MEM);
-	} else {
-		/* Initialize and start the PDC */
-		writel(runtime->dma_addr, chip->regs + ATMEL_PDC_RPR);
-		writel(block_size / 2, chip->regs + ATMEL_PDC_RCR);
-		writel(runtime->dma_addr + block_size,
-				chip->regs + ATMEL_PDC_RNPR);
-		writel(block_size / 2, chip->regs + ATMEL_PDC_RNCR);
-	}
+	/* Initialize and start the PDC */
+	writel(runtime->dma_addr, chip->regs + ATMEL_PDC_RPR);
+	writel(block_size / 2, chip->regs + ATMEL_PDC_RCR);
+	writel(runtime->dma_addr + block_size, chip->regs + ATMEL_PDC_RNPR);
+	writel(block_size / 2, chip->regs + ATMEL_PDC_RNCR);
 
 	return retval;
 }
@@ -501,7 +369,6 @@ atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd)
 {
 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
 	unsigned long camr, ptcr = 0;
-	int retval = 0;
 
 	camr = ac97c_readl(chip, CAMR);
 
@@ -509,35 +376,23 @@ atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd)
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
 	case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
 	case SNDRV_PCM_TRIGGER_START:
-		if (cpu_is_at32ap7000()) {
-			retval = dw_dma_cyclic_start(chip->dma.tx_chan);
-			if (retval)
-				goto out;
-		} else {
-			ptcr = ATMEL_PDC_TXTEN;
-		}
+		ptcr = ATMEL_PDC_TXTEN;
 		camr |= AC97C_CMR_CENA | AC97C_CSR_ENDTX;
 		break;
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
 	case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
 	case SNDRV_PCM_TRIGGER_STOP:
-		if (cpu_is_at32ap7000())
-			dw_dma_cyclic_stop(chip->dma.tx_chan);
-		else
-			ptcr |= ATMEL_PDC_TXTDIS;
+		ptcr |= ATMEL_PDC_TXTDIS;
 		if (chip->opened <= 1)
 			camr &= ~AC97C_CMR_CENA;
 		break;
 	default:
-		retval = -EINVAL;
-		goto out;
+		return -EINVAL;
 	}
 
 	ac97c_writel(chip, CAMR, camr);
-	if (!cpu_is_at32ap7000())
-		writel(ptcr, chip->regs + ATMEL_PDC_PTCR);
-out:
-	return retval;
+	writel(ptcr, chip->regs + ATMEL_PDC_PTCR);
+	return 0;
 }
 
 static int
@@ -545,7 +400,6 @@ atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd)
 {
 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
 	unsigned long camr, ptcr = 0;
-	int retval = 0;
 
 	camr = ac97c_readl(chip, CAMR);
 	ptcr = readl(chip->regs + ATMEL_PDC_PTSR);
@@ -554,35 +408,23 @@ atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd)
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
 	case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
 	case SNDRV_PCM_TRIGGER_START:
-		if (cpu_is_at32ap7000()) {
-			retval = dw_dma_cyclic_start(chip->dma.rx_chan);
-			if (retval)
-				goto out;
-		} else {
-			ptcr = ATMEL_PDC_RXTEN;
-		}
+		ptcr = ATMEL_PDC_RXTEN;
 		camr |= AC97C_CMR_CENA | AC97C_CSR_ENDRX;
 		break;
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
 	case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
 	case SNDRV_PCM_TRIGGER_STOP:
-		if (cpu_is_at32ap7000())
-			dw_dma_cyclic_stop(chip->dma.rx_chan);
-		else
-			ptcr |= (ATMEL_PDC_RXTDIS);
+		ptcr |= ATMEL_PDC_RXTDIS;
 		if (chip->opened <= 1)
 			camr &= ~AC97C_CMR_CENA;
 		break;
 	default:
-		retval = -EINVAL;
-		break;
+		return -EINVAL;
 	}
 
 	ac97c_writel(chip, CAMR, camr);
-	if (!cpu_is_at32ap7000())
-		writel(ptcr, chip->regs + ATMEL_PDC_PTCR);
-out:
-	return retval;
+	writel(ptcr, chip->regs + ATMEL_PDC_PTCR);
+	return 0;
 }
 
 static snd_pcm_uframes_t
@@ -593,10 +435,7 @@ atmel_ac97c_playback_pointer(struct snd_pcm_substream *substream)
 	snd_pcm_uframes_t	frames;
 	unsigned long		bytes;
 
-	if (cpu_is_at32ap7000())
-		bytes = dw_dma_get_src_addr(chip->dma.tx_chan);
-	else
-		bytes = readl(chip->regs + ATMEL_PDC_TPR);
+	bytes = readl(chip->regs + ATMEL_PDC_TPR);
 	bytes -= runtime->dma_addr;
 
 	frames = bytes_to_frames(runtime, bytes);
@@ -613,10 +452,7 @@ atmel_ac97c_capture_pointer(struct snd_pcm_substream *substream)
 	snd_pcm_uframes_t	frames;
 	unsigned long		bytes;
 
-	if (cpu_is_at32ap7000())
-		bytes = dw_dma_get_dst_addr(chip->dma.rx_chan);
-	else
-		bytes = readl(chip->regs + ATMEL_PDC_RPR);
+	bytes = readl(chip->regs + ATMEL_PDC_RPR);
 	bytes -= runtime->dma_addr;
 
 	frames = bytes_to_frames(runtime, bytes);
@@ -630,7 +466,7 @@ static struct snd_pcm_ops atmel_ac97_playback_ops = {
 	.close		= atmel_ac97c_playback_close,
 	.ioctl		= snd_pcm_lib_ioctl,
 	.hw_params	= atmel_ac97c_playback_hw_params,
-	.hw_free	= atmel_ac97c_playback_hw_free,
+	.hw_free	= snd_pcm_lib_free_pages,
 	.prepare	= atmel_ac97c_playback_prepare,
 	.trigger	= atmel_ac97c_playback_trigger,
 	.pointer	= atmel_ac97c_playback_pointer,
@@ -641,7 +477,7 @@ static struct snd_pcm_ops atmel_ac97_capture_ops = {
 	.close		= atmel_ac97c_capture_close,
 	.ioctl		= snd_pcm_lib_ioctl,
 	.hw_params	= atmel_ac97c_capture_hw_params,
-	.hw_free	= atmel_ac97c_capture_hw_free,
+	.hw_free	= snd_pcm_lib_free_pages,
 	.prepare	= atmel_ac97c_capture_prepare,
 	.trigger	= atmel_ac97c_capture_trigger,
 	.pointer	= atmel_ac97c_capture_pointer,
@@ -666,49 +502,40 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev)
 				casr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "",
 				casr & AC97C_CSR_TXRDY   ? " TXRDY"   : "",
 				!casr                    ? " NONE"    : "");
-		if (!cpu_is_at32ap7000()) {
-			if ((casr & camr) & AC97C_CSR_ENDTX) {
-				runtime = chip->playback_substream->runtime;
-				block_size = frames_to_bytes(runtime,
-						runtime->period_size);
-				chip->playback_period++;
-
-				if (chip->playback_period == runtime->periods)
-					chip->playback_period = 0;
-				next_period = chip->playback_period + 1;
-				if (next_period == runtime->periods)
-					next_period = 0;
-
-				offset = block_size * next_period;
-
-				writel(runtime->dma_addr + offset,
-						chip->regs + ATMEL_PDC_TNPR);
-				writel(block_size / 2,
-						chip->regs + ATMEL_PDC_TNCR);
-
-				snd_pcm_period_elapsed(
-						chip->playback_substream);
-			}
-			if ((casr & camr) & AC97C_CSR_ENDRX) {
-				runtime = chip->capture_substream->runtime;
-				block_size = frames_to_bytes(runtime,
-						runtime->period_size);
-				chip->capture_period++;
-
-				if (chip->capture_period == runtime->periods)
-					chip->capture_period = 0;
-				next_period = chip->capture_period + 1;
-				if (next_period == runtime->periods)
-					next_period = 0;
-
-				offset = block_size * next_period;
-
-				writel(runtime->dma_addr + offset,
-						chip->regs + ATMEL_PDC_RNPR);
-				writel(block_size / 2,
-						chip->regs + ATMEL_PDC_RNCR);
-				snd_pcm_period_elapsed(chip->capture_substream);
-			}
+		if ((casr & camr) & AC97C_CSR_ENDTX) {
+			runtime = chip->playback_substream->runtime;
+			block_size = frames_to_bytes(runtime, runtime->period_size);
+			chip->playback_period++;
+
+			if (chip->playback_period == runtime->periods)
+				chip->playback_period = 0;
+			next_period = chip->playback_period + 1;
+			if (next_period == runtime->periods)
+				next_period = 0;
+
+			offset = block_size * next_period;
+
+			writel(runtime->dma_addr + offset, chip->regs + ATMEL_PDC_TNPR);
+			writel(block_size / 2, chip->regs + ATMEL_PDC_TNCR);
+
+			snd_pcm_period_elapsed(chip->playback_substream);
+		}
+		if ((casr & camr) & AC97C_CSR_ENDRX) {
+			runtime = chip->capture_substream->runtime;
+			block_size = frames_to_bytes(runtime, runtime->period_size);
+			chip->capture_period++;
+
+			if (chip->capture_period == runtime->periods)
+				chip->capture_period = 0;
+			next_period = chip->capture_period + 1;
+			if (next_period == runtime->periods)
+				next_period = 0;
+
+			offset = block_size * next_period;
+
+			writel(runtime->dma_addr + offset, chip->regs + ATMEL_PDC_RNPR);
+			writel(block_size / 2, chip->regs + ATMEL_PDC_RNCR);
+			snd_pcm_period_elapsed(chip->capture_substream);
 		}
 		retval = IRQ_HANDLED;
 	}
@@ -763,29 +590,20 @@ static int atmel_ac97c_pcm_new(struct atmel_ac97c *chip)
 {
 	struct snd_pcm		*pcm;
 	struct snd_pcm_hardware	hw = atmel_ac97c_hw;
-	int			capture, playback, retval, err;
+	int			retval;
 
-	capture = test_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
-	playback = test_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
+	retval = snd_ac97_pcm_assign(chip->ac97_bus,
+				     ARRAY_SIZE(at91_ac97_pcm_defs),
+				     at91_ac97_pcm_defs);
+	if (retval)
+		return retval;
 
-	if (!cpu_is_at32ap7000()) {
-		err = snd_ac97_pcm_assign(chip->ac97_bus,
-				ARRAY_SIZE(at91_ac97_pcm_defs),
-				at91_ac97_pcm_defs);
-		if (err)
-			return err;
-	}
-	retval = snd_pcm_new(chip->card, chip->card->shortname,
-			0, playback, capture, &pcm);
+	retval = snd_pcm_new(chip->card, chip->card->shortname, 0, 1, 1, &pcm);
 	if (retval)
 		return retval;
 
-	if (capture)
-		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
-				&atmel_ac97_capture_ops);
-	if (playback)
-		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
-				&atmel_ac97_playback_ops);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &atmel_ac97_capture_ops);
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &atmel_ac97_playback_ops);
 
 	retval = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
 			&chip->pdev->dev, hw.periods_min * hw.period_bytes_min,
@@ -875,17 +693,6 @@ timed_out:
 	return 0xffff;
 }
 
-static bool filter(struct dma_chan *chan, void *slave)
-{
-	struct dw_dma_slave *dws = slave;
-
-	if (dws->dma_dev == chan->device->dev) {
-		chan->private = dws;
-		return true;
-	} else
-		return false;
-}
-
 static void atmel_ac97c_reset(struct atmel_ac97c *chip)
 {
 	ac97c_writel(chip, MR,   0);
@@ -967,16 +774,11 @@ static int atmel_ac97c_probe(struct platform_device *pdev)
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
-		dev_dbg(&pdev->dev, "could not get irq\n");
-		return -ENXIO;
-	}
-
-	if (cpu_is_at32ap7000()) {
-		pclk = clk_get(&pdev->dev, "pclk");
-	} else {
-		pclk = clk_get(&pdev->dev, "ac97_clk");
+		dev_dbg(&pdev->dev, "could not get irq: %d\n", irq);
+		return irq;
 	}
 
+	pclk = clk_get(&pdev->dev, "ac97_clk");
 	if (IS_ERR(pclk)) {
 		dev_dbg(&pdev->dev, "no peripheral clock\n");
 		return PTR_ERR(pclk);
@@ -1047,88 +849,16 @@ static int atmel_ac97c_probe(struct platform_device *pdev)
 		goto err_ac97_bus;
 	}
 
-	if (cpu_is_at32ap7000()) {
-		if (pdata->rx_dws.dma_dev) {
-			dma_cap_mask_t mask;
-
-			dma_cap_zero(mask);
-			dma_cap_set(DMA_SLAVE, mask);
-
-			chip->dma.rx_chan = dma_request_channel(mask, filter,
-								&pdata->rx_dws);
-			if (chip->dma.rx_chan) {
-				struct dma_slave_config dma_conf = {
-					.src_addr = regs->start + AC97C_CARHR +
-						2,
-					.src_addr_width =
-						DMA_SLAVE_BUSWIDTH_2_BYTES,
-					.src_maxburst = 1,
-					.dst_maxburst = 1,
-					.direction = DMA_DEV_TO_MEM,
-					.device_fc = false,
-				};
-
-				dmaengine_slave_config(chip->dma.rx_chan,
-						&dma_conf);
-			}
-
-			dev_info(&chip->pdev->dev, "using %s for DMA RX\n",
-				dev_name(&chip->dma.rx_chan->dev->device));
-			set_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
-		}
-
-		if (pdata->tx_dws.dma_dev) {
-			dma_cap_mask_t mask;
-
-			dma_cap_zero(mask);
-			dma_cap_set(DMA_SLAVE, mask);
-
-			chip->dma.tx_chan = dma_request_channel(mask, filter,
-								&pdata->tx_dws);
-			if (chip->dma.tx_chan) {
-				struct dma_slave_config dma_conf = {
-					.dst_addr = regs->start + AC97C_CATHR +
-						2,
-					.dst_addr_width =
-						DMA_SLAVE_BUSWIDTH_2_BYTES,
-					.src_maxburst = 1,
-					.dst_maxburst = 1,
-					.direction = DMA_MEM_TO_DEV,
-					.device_fc = false,
-				};
-
-				dmaengine_slave_config(chip->dma.tx_chan,
-						&dma_conf);
-			}
-
-			dev_info(&chip->pdev->dev, "using %s for DMA TX\n",
-				dev_name(&chip->dma.tx_chan->dev->device));
-			set_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
-		}
-
-		if (!test_bit(DMA_RX_CHAN_PRESENT, &chip->flags) &&
-				!test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) {
-			dev_dbg(&pdev->dev, "DMA not available\n");
-			retval = -ENODEV;
-			goto err_dma;
-		}
-	} else {
-		/* Just pretend that we have DMA channel(for at91 i is actually
-		 * the PDC) */
-		set_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
-		set_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
-	}
-
 	retval = atmel_ac97c_pcm_new(chip);
 	if (retval) {
 		dev_dbg(&pdev->dev, "could not register ac97 pcm device\n");
-		goto err_dma;
+		goto err_ac97_bus;
 	}
 
 	retval = snd_card_register(card);
 	if (retval) {
 		dev_dbg(&pdev->dev, "could not register sound card\n");
-		goto err_dma;
+		goto err_ac97_bus;
 	}
 
 	platform_set_drvdata(pdev, card);
@@ -1138,17 +868,6 @@ static int atmel_ac97c_probe(struct platform_device *pdev)
 
 	return 0;
 
-err_dma:
-	if (cpu_is_at32ap7000()) {
-		if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
-			dma_release_channel(chip->dma.rx_chan);
-		if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags))
-			dma_release_channel(chip->dma.tx_chan);
-		clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
-		clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
-		chip->dma.rx_chan = NULL;
-		chip->dma.tx_chan = NULL;
-	}
 err_ac97_bus:
 	if (gpio_is_valid(chip->reset_pin))
 		gpio_free(chip->reset_pin);
@@ -1170,14 +889,7 @@ static int atmel_ac97c_suspend(struct device *pdev)
 	struct snd_card *card = dev_get_drvdata(pdev);
 	struct atmel_ac97c *chip = card->private_data;
 
-	if (cpu_is_at32ap7000()) {
-		if (test_bit(DMA_RX_READY, &chip->flags))
-			dw_dma_cyclic_stop(chip->dma.rx_chan);
-		if (test_bit(DMA_TX_READY, &chip->flags))
-			dw_dma_cyclic_stop(chip->dma.tx_chan);
-	}
 	clk_disable_unprepare(chip->pclk);
-
 	return 0;
 }
 
@@ -1187,12 +899,6 @@ static int atmel_ac97c_resume(struct device *pdev)
 	struct atmel_ac97c *chip = card->private_data;
 
 	clk_prepare_enable(chip->pclk);
-	if (cpu_is_at32ap7000()) {
-		if (test_bit(DMA_RX_READY, &chip->flags))
-			dw_dma_cyclic_start(chip->dma.rx_chan);
-		if (test_bit(DMA_TX_READY, &chip->flags))
-			dw_dma_cyclic_start(chip->dma.tx_chan);
-	}
 	return 0;
 }
 
@@ -1219,17 +925,6 @@ static int atmel_ac97c_remove(struct platform_device *pdev)
 	iounmap(chip->regs);
 	free_irq(chip->irq, chip);
 
-	if (cpu_is_at32ap7000()) {
-		if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
-			dma_release_channel(chip->dma.rx_chan);
-		if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags))
-			dma_release_channel(chip->dma.tx_chan);
-		clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
-		clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
-		chip->dma.rx_chan = NULL;
-		chip->dma.tx_chan = NULL;
-	}
-
 	snd_card_free(card);
 
 	return 0;

+ 9 - 50
sound/core/Kconfig

@@ -18,8 +18,12 @@ config SND_DMAENGINE_PCM
 config SND_HWDEP
 	tristate
 
+config SND_SEQ_DEVICE
+	tristate
+
 config SND_RAWMIDI
 	tristate
+	select SND_SEQ_DEVICE if SND_SEQUENCER != n
 
 config SND_COMPRESS_OFFLOAD
 	tristate
@@ -33,38 +37,15 @@ config SND_JACK_INPUT_DEV
 	depends on SND_JACK
 	default y if INPUT=y || INPUT=SND
 
-config SND_SEQUENCER
-	tristate "Sequencer support"
-	select SND_TIMER
-	help
-	  Say Y or M to enable MIDI sequencer and router support.  This
-	  feature allows routing and enqueueing of MIDI events.  Events
-	  can be processed at a given time.
-
-	  Many programs require this feature, so you should enable it
-	  unless you know what you're doing.
-
-config SND_SEQ_DUMMY
-	tristate "Sequencer dummy client"
-	depends on SND_SEQUENCER
-	help
-	  Say Y here to enable the dummy sequencer client.  This client
-	  is a simple MIDI-through client: all normal input events are
-	  redirected to the output port immediately.
-
-	  You don't need this unless you want to connect many MIDI
-	  devices or applications together.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called snd-seq-dummy.
-
 config SND_OSSEMUL
+	bool "Enable OSS Emulation"
 	select SOUND_OSS_CORE
-	bool
+	help
+	  This option enables the build of OSS emulation layer.
 
 config SND_MIXER_OSS
 	tristate "OSS Mixer API"
-	select SND_OSSEMUL
+	depends on SND_OSSEMUL
 	help
 	  To enable OSS mixer API emulation (/dev/mixer*), say Y here
 	  and read <file:Documentation/sound/alsa/OSS-Emulation.txt>.
@@ -76,7 +57,7 @@ config SND_MIXER_OSS
 
 config SND_PCM_OSS
 	tristate "OSS PCM (digital audio) API"
-	select SND_OSSEMUL
+	depends on SND_OSSEMUL
 	select SND_PCM
 	help
 	  To enable OSS digital audio (PCM) emulation (/dev/dsp*), say Y
@@ -107,20 +88,6 @@ config SND_PCM_TIMER
 	  For some embedded devices, we may disable it to reduce memory
 	  footprint, about 20KB on x86_64 platform.
 
-config SND_SEQUENCER_OSS
-	bool "OSS Sequencer API"
-	depends on SND_SEQUENCER
-	select SND_OSSEMUL
-	help
-	  Say Y here to enable OSS sequencer emulation (both
-	  /dev/sequencer and /dev/music interfaces).
-
-	  Many programs still use the OSS API, so say Y.
-
-	  If you choose M in "Sequencer support" (SND_SEQUENCER),
-	  this will be compiled as a module. The module will be called
-	  snd-seq-oss.
-
 config SND_HRTIMER
 	tristate "HR-timer backend support"
 	depends on HIGH_RES_TIMERS
@@ -133,14 +100,6 @@ config SND_HRTIMER
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-hrtimer.
 
-config SND_SEQ_HRTIMER_DEFAULT
-	bool "Use HR-timer as default sequencer timer"
-	depends on SND_HRTIMER && SND_SEQUENCER
-	default y
-	help
-	  Say Y here to use the HR-timer backend as the default sequencer
-	  timer.
-
 config SND_DYNAMIC_MINORS
 	bool "Dynamic device file minor numbers"
 	help

+ 3 - 0
sound/core/Makefile

@@ -22,6 +22,7 @@ snd-pcm-$(CONFIG_SND_PCM_IEC958) += pcm_iec958.o
 
 # for trace-points
 CFLAGS_pcm_lib.o := -I$(src)
+CFLAGS_pcm_native.o := -I$(src)
 
 snd-pcm-dmaengine-objs := pcm_dmaengine.o
 
@@ -30,6 +31,7 @@ snd-timer-objs    := timer.o
 snd-hrtimer-objs  := hrtimer.o
 snd-rtctimer-objs := rtctimer.o
 snd-hwdep-objs    := hwdep.o
+snd-seq-device-objs := seq_device.o
 
 snd-compress-objs := compress_offload.o
 
@@ -39,6 +41,7 @@ obj-$(CONFIG_SND_TIMER)		+= snd-timer.o
 obj-$(CONFIG_SND_HRTIMER)	+= snd-hrtimer.o
 obj-$(CONFIG_SND_PCM)		+= snd-pcm.o
 obj-$(CONFIG_SND_DMAENGINE_PCM)	+= snd-pcm-dmaengine.o
+obj-$(CONFIG_SND_SEQ_DEVICE)	+= snd-seq-device.o
 obj-$(CONFIG_SND_RAWMIDI)	+= snd-rawmidi.o
 
 obj-$(CONFIG_SND_OSSEMUL)	+= oss/

+ 25 - 45
sound/core/control.c

@@ -747,65 +747,45 @@ static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl,
 static int snd_ctl_elem_list(struct snd_card *card,
 			     struct snd_ctl_elem_list __user *_list)
 {
-	struct list_head *plist;
 	struct snd_ctl_elem_list list;
 	struct snd_kcontrol *kctl;
-	struct snd_ctl_elem_id *dst, *id;
+	struct snd_ctl_elem_id id;
 	unsigned int offset, space, jidx;
+	int err = 0;
 	
 	if (copy_from_user(&list, _list, sizeof(list)))
 		return -EFAULT;
 	offset = list.offset;
 	space = list.space;
-	/* try limit maximum space */
-	if (space > 16384)
-		return -ENOMEM;
+
+	down_read(&card->controls_rwsem);
+	list.count = card->controls_count;
+	list.used = 0;
 	if (space > 0) {
-		/* allocate temporary buffer for atomic operation */
-		dst = vmalloc(space * sizeof(struct snd_ctl_elem_id));
-		if (dst == NULL)
-			return -ENOMEM;
-		down_read(&card->controls_rwsem);
-		list.count = card->controls_count;
-		plist = card->controls.next;
-		while (plist != &card->controls) {
-			if (offset == 0)
-				break;
-			kctl = snd_kcontrol(plist);
-			if (offset < kctl->count)
-				break;
-			offset -= kctl->count;
-			plist = plist->next;
-		}
-		list.used = 0;
-		id = dst;
-		while (space > 0 && plist != &card->controls) {
-			kctl = snd_kcontrol(plist);
-			for (jidx = offset; space > 0 && jidx < kctl->count; jidx++) {
-				snd_ctl_build_ioff(id, kctl, jidx);
-				id++;
-				space--;
+		list_for_each_entry(kctl, &card->controls, list) {
+			if (offset >= kctl->count) {
+				offset -= kctl->count;
+				continue;
+			}
+			for (jidx = offset; jidx < kctl->count; jidx++) {
+				snd_ctl_build_ioff(&id, kctl, jidx);
+				if (copy_to_user(list.pids + list.used, &id,
+						 sizeof(id))) {
+					err = -EFAULT;
+					goto out;
+				}
 				list.used++;
+				if (!--space)
+					goto out;
 			}
-			plist = plist->next;
 			offset = 0;
 		}
-		up_read(&card->controls_rwsem);
-		if (list.used > 0 &&
-		    copy_to_user(list.pids, dst,
-				 list.used * sizeof(struct snd_ctl_elem_id))) {
-			vfree(dst);
-			return -EFAULT;
-		}
-		vfree(dst);
-	} else {
-		down_read(&card->controls_rwsem);
-		list.count = card->controls_count;
-		up_read(&card->controls_rwsem);
 	}
-	if (copy_to_user(_list, &list, sizeof(list)))
-		return -EFAULT;
-	return 0;
+ out:
+	up_read(&card->controls_rwsem);
+	if (!err && copy_to_user(_list, &list, sizeof(list)))
+		err = -EFAULT;
+	return err;
 }
 
 static bool validate_element_member_dimension(struct snd_ctl_elem_info *info)

+ 1 - 1
sound/core/ctljack.c

@@ -23,7 +23,7 @@ static int jack_detect_kctl_get(struct snd_kcontrol *kcontrol,
 	return 0;
 }
 
-static struct snd_kcontrol_new jack_detect_kctl = {
+static const struct snd_kcontrol_new jack_detect_kctl = {
 	/* name is filled later */
 	.iface = SNDRV_CTL_ELEM_IFACE_CARD,
 	.access = SNDRV_CTL_ELEM_ACCESS_READ,

+ 3 - 9
sound/core/info.c

@@ -344,12 +344,12 @@ static ssize_t snd_info_text_entry_write(struct file *file,
 		}
 	}
 	if (next > buf->len) {
-		char *nbuf = krealloc(buf->buffer, PAGE_ALIGN(next),
-				      GFP_KERNEL | __GFP_ZERO);
+		char *nbuf = kvzalloc(PAGE_ALIGN(next), GFP_KERNEL);
 		if (!nbuf) {
 			err = -ENOMEM;
 			goto error;
 		}
+		kvfree(buf->buffer);
 		buf->buffer = nbuf;
 		buf->len = PAGE_ALIGN(next);
 	}
@@ -427,7 +427,7 @@ static int snd_info_text_entry_release(struct inode *inode, struct file *file)
 	single_release(inode, file);
 	kfree(data->rbuffer);
 	if (data->wbuffer) {
-		kfree(data->wbuffer->buffer);
+		kvfree(data->wbuffer->buffer);
 		kfree(data->wbuffer);
 	}
 
@@ -652,7 +652,6 @@ int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len)
 	*line = '\0';
 	return 0;
 }
-
 EXPORT_SYMBOL(snd_info_get_line);
 
 /**
@@ -690,7 +689,6 @@ const char *snd_info_get_str(char *dest, const char *src, int len)
 		src++;
 	return src;
 }
-
 EXPORT_SYMBOL(snd_info_get_str);
 
 /*
@@ -748,7 +746,6 @@ struct snd_info_entry *snd_info_create_module_entry(struct module * module,
 		entry->module = module;
 	return entry;
 }
-
 EXPORT_SYMBOL(snd_info_create_module_entry);
 
 /**
@@ -772,7 +769,6 @@ struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card,
 	}
 	return entry;
 }
-
 EXPORT_SYMBOL(snd_info_create_card_entry);
 
 static void snd_info_disconnect(struct snd_info_entry *entry)
@@ -815,7 +811,6 @@ void snd_info_free_entry(struct snd_info_entry * entry)
 		entry->private_free(entry);
 	kfree(entry);
 }
-
 EXPORT_SYMBOL(snd_info_free_entry);
 
 /**
@@ -858,7 +853,6 @@ int snd_info_register(struct snd_info_entry * entry)
 	mutex_unlock(&info_mutex);
 	return 0;
 }
-
 EXPORT_SYMBOL(snd_info_register);
 
 /*

+ 0 - 1
sound/core/info_oss.c

@@ -61,7 +61,6 @@ int snd_oss_info_register(int dev, int num, char *string)
 	mutex_unlock(&strings);
 	return 0;
 }
-
 EXPORT_SYMBOL(snd_oss_info_register);
 
 static int snd_sndstat_show_strings(struct snd_info_buffer *buf, char *id, int dev)

+ 1 - 7
sound/core/init.c

@@ -452,7 +452,6 @@ int snd_card_disconnect(struct snd_card *card)
 #endif
 	return 0;	
 }
-
 EXPORT_SYMBOL(snd_card_disconnect);
 
 static int snd_card_do_free(struct snd_card *card)
@@ -718,7 +717,7 @@ int snd_card_add_dev_attr(struct snd_card *card,
 
 	dev_err(card->dev, "Too many groups assigned\n");
 	return -ENOSPC;
-};
+}
 EXPORT_SYMBOL_GPL(snd_card_add_dev_attr);
 
 /**
@@ -775,7 +774,6 @@ int snd_card_register(struct snd_card *card)
 #endif
 	return 0;
 }
-
 EXPORT_SYMBOL(snd_card_register);
 
 #ifdef CONFIG_SND_PROC_FS
@@ -895,7 +893,6 @@ int snd_component_add(struct snd_card *card, const char *component)
 	strcat(card->components, component);
 	return 0;
 }
-
 EXPORT_SYMBOL(snd_component_add);
 
 /**
@@ -930,7 +927,6 @@ int snd_card_file_add(struct snd_card *card, struct file *file)
 	spin_unlock(&card->files_lock);
 	return 0;
 }
-
 EXPORT_SYMBOL(snd_card_file_add);
 
 /**
@@ -972,7 +968,6 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)
 	put_device(&card->card_dev);
 	return 0;
 }
-
 EXPORT_SYMBOL(snd_card_file_remove);
 
 #ifdef CONFIG_PM
@@ -1012,6 +1007,5 @@ int snd_power_wait(struct snd_card *card, unsigned int power_state)
 	remove_wait_queue(&card->power_sleep, &wait);
 	return result;
 }
-
 EXPORT_SYMBOL(snd_power_wait);
 #endif /* CONFIG_PM */

+ 0 - 3
sound/core/isadma.c

@@ -55,7 +55,6 @@ void snd_dma_program(unsigned long dma,
 		enable_dma(dma);
 	release_dma_lock(flags);
 }
-
 EXPORT_SYMBOL(snd_dma_program);
 
 /**
@@ -73,7 +72,6 @@ void snd_dma_disable(unsigned long dma)
 	disable_dma(dma);
 	release_dma_lock(flags);
 }
-
 EXPORT_SYMBOL(snd_dma_disable);
 
 /**
@@ -113,5 +111,4 @@ unsigned int snd_dma_pointer(unsigned long dma, unsigned int size)
 	else
 		return size - result;
 }
-
 EXPORT_SYMBOL(snd_dma_pointer);

+ 4 - 9
sound/core/memalloc.c

@@ -54,6 +54,7 @@ void *snd_malloc_pages(size_t size, gfp_t gfp_flags)
 	pg = get_order(size);
 	return (void *) __get_free_pages(gfp_flags, pg);
 }
+EXPORT_SYMBOL(snd_malloc_pages);
 
 /**
  * snd_free_pages - release the pages
@@ -71,6 +72,7 @@ void snd_free_pages(void *ptr, size_t size)
 	pg = get_order(size);
 	free_pages((unsigned long) ptr, pg);
 }
+EXPORT_SYMBOL(snd_free_pages);
 
 /*
  *
@@ -217,6 +219,7 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,
 	dmab->bytes = size;
 	return 0;
 }
+EXPORT_SYMBOL(snd_dma_alloc_pages);
 
 /**
  * snd_dma_alloc_pages_fallback - allocate the buffer area according to the given type with fallback
@@ -254,6 +257,7 @@ int snd_dma_alloc_pages_fallback(int type, struct device *device, size_t size,
 		return -ENOMEM;
 	return 0;
 }
+EXPORT_SYMBOL(snd_dma_alloc_pages_fallback);
 
 
 /**
@@ -287,13 +291,4 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab)
 		pr_err("snd-malloc: invalid device type %d\n", dmab->dev.type);
 	}
 }
-
-/*
- * exports
- */
-EXPORT_SYMBOL(snd_dma_alloc_pages);
-EXPORT_SYMBOL(snd_dma_alloc_pages_fallback);
 EXPORT_SYMBOL(snd_dma_free_pages);
-
-EXPORT_SYMBOL(snd_malloc_pages);
-EXPORT_SYMBOL(snd_free_pages);

+ 0 - 2
sound/core/memory.c

@@ -55,7 +55,6 @@ int copy_to_user_fromio(void __user *dst, const volatile void __iomem *src, size
 	return 0;
 #endif
 }
-
 EXPORT_SYMBOL(copy_to_user_fromio);
 
 /**
@@ -88,5 +87,4 @@ int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size
 	return 0;
 #endif
 }
-
 EXPORT_SYMBOL(copy_from_user_toio);

+ 0 - 1
sound/core/misc.c

@@ -48,7 +48,6 @@ void release_and_free_resource(struct resource *res)
 		kfree(res);
 	}
 }
-
 EXPORT_SYMBOL(release_and_free_resource);
 
 #ifdef CONFIG_SND_VERBOSE_PRINTK

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

@@ -26,9 +26,9 @@
 #include "pcm_plugin.h"
 
 #define pcm_write(plug,buf,count) snd_pcm_oss_write3(plug,buf,count,1)
-#define pcm_writev(plug,vec,count) snd_pcm_oss_writev3(plug,vec,count,1)
+#define pcm_writev(plug,vec,count) snd_pcm_oss_writev3(plug,vec,count)
 #define pcm_read(plug,buf,count) snd_pcm_oss_read3(plug,buf,count,1)
-#define pcm_readv(plug,vec,count) snd_pcm_oss_readv3(plug,vec,count,1)
+#define pcm_readv(plug,vec,count) snd_pcm_oss_readv3(plug,vec,count)
 
 /*
  *  Basic io plugin

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

@@ -395,6 +395,7 @@ int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned l
 	fmixer.mixer = card->mixer_oss;
 	return snd_mixer_oss_ioctl1(&fmixer, cmd, arg);
 }
+EXPORT_SYMBOL(snd_mixer_oss_ioctl_card);
 
 #ifdef CONFIG_COMPAT
 /* all compatible */
@@ -1425,5 +1426,3 @@ static void __exit alsa_mixer_oss_exit(void)
 
 module_init(alsa_mixer_oss_init)
 module_exit(alsa_mixer_oss_exit)
-
-EXPORT_SYMBOL(snd_mixer_oss_ioctl_card);

+ 24 - 77
sound/core/oss/pcm_oss.c

@@ -67,18 +67,6 @@ static int snd_pcm_oss_get_rate(struct snd_pcm_oss_file *pcm_oss_file);
 static int snd_pcm_oss_get_channels(struct snd_pcm_oss_file *pcm_oss_file);
 static int snd_pcm_oss_get_format(struct snd_pcm_oss_file *pcm_oss_file);
 
-static inline mm_segment_t snd_enter_user(void)
-{
-	mm_segment_t fs = get_fs();
-	set_fs(get_ds());
-	return fs;
-}
-
-static inline void snd_leave_user(mm_segment_t fs)
-{
-	set_fs(fs);
-}
-
 /*
  * helper functions to process hw_params
  */
@@ -799,7 +787,7 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
 static int choose_rate(struct snd_pcm_substream *substream,
 		       struct snd_pcm_hw_params *params, unsigned int best_rate)
 {
-	struct snd_interval *it;
+	const struct snd_interval *it;
 	struct snd_pcm_hw_params *save;
 	unsigned int rate, prev;
 
@@ -807,7 +795,7 @@ static int choose_rate(struct snd_pcm_substream *substream,
 	if (save == NULL)
 		return -ENOMEM;
 	*save = *params;
-	it = hw_param_interval(save, SNDRV_PCM_HW_PARAM_RATE);
+	it = hw_param_interval_c(save, SNDRV_PCM_HW_PARAM_RATE);
 
 	/* try multiples of the best rate */
 	rate = best_rate;
@@ -848,7 +836,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream,
 	int direct;
 	snd_pcm_format_t format, sformat;
 	int n;
-	struct snd_mask sformat_mask;
+	const struct snd_mask *sformat_mask;
 	struct snd_mask mask;
 
 	if (trylock) {
@@ -891,18 +879,18 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream,
 
 	format = snd_pcm_oss_format_from(runtime->oss.format);
 
-	sformat_mask = *hw_param_mask(sparams, SNDRV_PCM_HW_PARAM_FORMAT);
+	sformat_mask = hw_param_mask_c(sparams, SNDRV_PCM_HW_PARAM_FORMAT);
 	if (direct)
 		sformat = format;
 	else
-		sformat = snd_pcm_plug_slave_format(format, &sformat_mask);
+		sformat = snd_pcm_plug_slave_format(format, sformat_mask);
 
 	if ((__force int)sformat < 0 ||
-	    !snd_mask_test(&sformat_mask, (__force int)sformat)) {
+	    !snd_mask_test(sformat_mask, (__force int)sformat)) {
 		for (sformat = (__force snd_pcm_format_t)0;
 		     (__force int)sformat <= (__force int)SNDRV_PCM_FORMAT_LAST;
 		     sformat = (__force snd_pcm_format_t)((__force int)sformat + 1)) {
-			if (snd_mask_test(&sformat_mask, (__force int)sformat) &&
+			if (snd_mask_test(sformat_mask, (__force int)sformat) &&
 			    snd_pcm_oss_format_to(sformat) >= 0)
 				break;
 		}
@@ -1191,14 +1179,8 @@ snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream, const
 			if (ret < 0)
 				break;
 		}
-		if (in_kernel) {
-			mm_segment_t fs;
-			fs = snd_enter_user();
-			ret = snd_pcm_lib_write(substream, (void __force __user *)ptr, frames);
-			snd_leave_user(fs);
-		} else {
-			ret = snd_pcm_lib_write(substream, (void __force __user *)ptr, frames);
-		}
+		ret = __snd_pcm_lib_xfer(substream, (void *)ptr, true,
+					 frames, in_kernel);
 		if (ret != -EPIPE && ret != -ESTRPIPE)
 			break;
 		/* test, if we can't store new data, because the stream */
@@ -1234,14 +1216,8 @@ snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *p
 		ret = snd_pcm_oss_capture_position_fixup(substream, &delay);
 		if (ret < 0)
 			break;
-		if (in_kernel) {
-			mm_segment_t fs;
-			fs = snd_enter_user();
-			ret = snd_pcm_lib_read(substream, (void __force __user *)ptr, frames);
-			snd_leave_user(fs);
-		} else {
-			ret = snd_pcm_lib_read(substream, (void __force __user *)ptr, frames);
-		}
+		ret = __snd_pcm_lib_xfer(substream, (void *)ptr, true,
+					 frames, in_kernel);
 		if (ret == -EPIPE) {
 			if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
 				ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
@@ -1256,7 +1232,8 @@ snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream, char *p
 	return ret;
 }
 
-snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel)
+#ifdef CONFIG_SND_PCM_OSS_PLUGINS
+snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	int ret;
@@ -1273,14 +1250,7 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void
 			if (ret < 0)
 				break;
 		}
-		if (in_kernel) {
-			mm_segment_t fs;
-			fs = snd_enter_user();
-			ret = snd_pcm_lib_writev(substream, (void __user **)bufs, frames);
-			snd_leave_user(fs);
-		} else {
-			ret = snd_pcm_lib_writev(substream, (void __user **)bufs, frames);
-		}
+		ret = snd_pcm_kernel_writev(substream, bufs, frames);
 		if (ret != -EPIPE && ret != -ESTRPIPE)
 			break;
 
@@ -1292,7 +1262,7 @@ snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream, void
 	return ret;
 }
 	
-snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel)
+snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void **bufs, snd_pcm_uframes_t frames)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	int ret;
@@ -1313,19 +1283,13 @@ snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream, void *
 			if (ret < 0)
 				break;
 		}
-		if (in_kernel) {
-			mm_segment_t fs;
-			fs = snd_enter_user();
-			ret = snd_pcm_lib_readv(substream, (void __user **)bufs, frames);
-			snd_leave_user(fs);
-		} else {
-			ret = snd_pcm_lib_readv(substream, (void __user **)bufs, frames);
-		}
+		ret = snd_pcm_kernel_readv(substream, bufs, frames);
 		if (ret != -EPIPE && ret != -ESTRPIPE)
 			break;
 	}
 	return ret;
 }
+#endif /* CONFIG_SND_PCM_OSS_PLUGINS */
 
 static ssize_t snd_pcm_oss_write2(struct snd_pcm_substream *substream, const char *buf, size_t bytes, int in_kernel)
 {
@@ -1650,27 +1614,10 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
 		size = runtime->control->appl_ptr % runtime->period_size;
 		if (size > 0) {
 			size = runtime->period_size - size;
-			if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) {
-				size = (runtime->frame_bits * size) / 8;
-				while (size > 0) {
-					mm_segment_t fs;
-					size_t size1 = size < runtime->oss.period_bytes ? size : runtime->oss.period_bytes;
-					size -= size1;
-					size1 *= 8;
-					size1 /= runtime->sample_bits;
-					snd_pcm_format_set_silence(runtime->format,
-								   runtime->oss.buffer,
-								   size1);
-					size1 /= runtime->channels; /* frames */
-					fs = snd_enter_user();
-					snd_pcm_lib_write(substream, (void __force __user *)runtime->oss.buffer, size1);
-					snd_leave_user(fs);
-				}
-			} else if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) {
-				void __user *buffers[runtime->channels];
-				memset(buffers, 0, runtime->channels * sizeof(void *));
-				snd_pcm_lib_writev(substream, buffers, size);
-			}
+			if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED)
+				snd_pcm_lib_write(substream, NULL, size);
+			else if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
+				snd_pcm_lib_writev(substream, NULL, size);
 		}
 		mutex_unlock(&runtime->oss.params_lock);
 		/*
@@ -1780,7 +1727,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
 	int direct;
 	struct snd_pcm_hw_params *params;
 	unsigned int formats = 0;
-	struct snd_mask format_mask;
+	const struct snd_mask *format_mask;
 	int fmt;
 
 	if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
@@ -1802,12 +1749,12 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
 		return -ENOMEM;
 	_snd_pcm_hw_params_any(params);
 	err = snd_pcm_hw_refine(substream, params);
-	format_mask = *hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); 
+	format_mask = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
 	kfree(params);
 	if (err < 0)
 		return err;
 	for (fmt = 0; fmt < 32; ++fmt) {
-		if (snd_mask_test(&format_mask, fmt)) {
+		if (snd_mask_test(format_mask, fmt)) {
 			int f = snd_pcm_oss_format_to(fmt);
 			if (f >= 0)
 				formats |= f;

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

@@ -266,7 +266,8 @@ snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, snd_pc
 	return frames;
 }
 
-static int snd_pcm_plug_formats(struct snd_mask *mask, snd_pcm_format_t format)
+static int snd_pcm_plug_formats(const struct snd_mask *mask,
+				snd_pcm_format_t format)
 {
 	struct snd_mask formats = *mask;
 	u64 linfmts = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 |
@@ -309,7 +310,7 @@ static snd_pcm_format_t preferred_formats[] = {
 };
 
 snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format,
-					   struct snd_mask *format_mask)
+					   const struct snd_mask *format_mask)
 {
 	int i;
 

+ 4 - 6
sound/core/oss/pcm_plugin.h

@@ -126,7 +126,7 @@ int snd_pcm_plug_format_plugins(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *slave_params);
 
 snd_pcm_format_t snd_pcm_plug_slave_format(snd_pcm_format_t format,
-					   struct snd_mask *format_mask);
+					   const struct snd_mask *format_mask);
 
 int snd_pcm_plugin_append(struct snd_pcm_plugin *plugin);
 
@@ -162,17 +162,15 @@ snd_pcm_sframes_t snd_pcm_oss_write3(struct snd_pcm_substream *substream,
 snd_pcm_sframes_t snd_pcm_oss_read3(struct snd_pcm_substream *substream,
 				    char *ptr, snd_pcm_uframes_t size, int in_kernel);
 snd_pcm_sframes_t snd_pcm_oss_writev3(struct snd_pcm_substream *substream,
-				      void **bufs, snd_pcm_uframes_t frames,
-				      int in_kernel);
+				      void **bufs, snd_pcm_uframes_t frames);
 snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream,
-				     void **bufs, snd_pcm_uframes_t frames,
-				     int in_kernel);
+				     void **bufs, snd_pcm_uframes_t frames);
 
 #else
 
 static inline snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t drv_size) { return drv_size; }
 static inline snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t clt_size) { return clt_size; }
-static inline int snd_pcm_plug_slave_format(int format, struct snd_mask *format_mask) { return format; }
+static inline int snd_pcm_plug_slave_format(int format, const struct snd_mask *format_mask) { return format; }
 
 #endif
 

+ 23 - 14
sound/core/pcm.c

@@ -31,13 +31,17 @@
 #include <sound/control.h>
 #include <sound/info.h>
 
+#include "pcm_local.h"
+
 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Abramo Bagnara <abramo@alsa-project.org>");
 MODULE_DESCRIPTION("Midlevel PCM code for ALSA.");
 MODULE_LICENSE("GPL");
 
 static LIST_HEAD(snd_pcm_devices);
-static LIST_HEAD(snd_pcm_notify_list);
 static DEFINE_MUTEX(register_mutex);
+#if IS_ENABLED(CONFIG_SND_PCM_OSS)
+static LIST_HEAD(snd_pcm_notify_list);
+#endif
 
 static int snd_pcm_free(struct snd_pcm *pcm);
 static int snd_pcm_dev_free(struct snd_device *device);
@@ -884,16 +888,23 @@ static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
 		put_device(&pstr->dev);
 }
 
+#if IS_ENABLED(CONFIG_SND_PCM_OSS)
+#define pcm_call_notify(pcm, call)					\
+	do {								\
+		struct snd_pcm_notify *_notify;				\
+		list_for_each_entry(_notify, &snd_pcm_notify_list, list) \
+			_notify->call(pcm);				\
+	} while (0)
+#else
+#define pcm_call_notify(pcm, call) do {} while (0)
+#endif
+
 static int snd_pcm_free(struct snd_pcm *pcm)
 {
-	struct snd_pcm_notify *notify;
-
 	if (!pcm)
 		return 0;
-	if (!pcm->internal) {
-		list_for_each_entry(notify, &snd_pcm_notify_list, list)
-			notify->n_unregister(pcm);
-	}
+	if (!pcm->internal)
+		pcm_call_notify(pcm, n_unregister);
 	if (pcm->private_free)
 		pcm->private_free(pcm);
 	snd_pcm_lib_preallocate_free_for_all(pcm);
@@ -1056,7 +1067,7 @@ static struct attribute *pcm_dev_attrs[] = {
 	NULL
 };
 
-static struct attribute_group pcm_dev_attr_group = {
+static const struct attribute_group pcm_dev_attr_group = {
 	.attrs	= pcm_dev_attrs,
 };
 
@@ -1069,7 +1080,6 @@ static int snd_pcm_dev_register(struct snd_device *device)
 {
 	int cidx, err;
 	struct snd_pcm_substream *substream;
-	struct snd_pcm_notify *notify;
 	struct snd_pcm *pcm;
 
 	if (snd_BUG_ON(!device || !device->device_data))
@@ -1107,8 +1117,7 @@ static int snd_pcm_dev_register(struct snd_device *device)
 			snd_pcm_timer_init(substream);
 	}
 
-	list_for_each_entry(notify, &snd_pcm_notify_list, list)
-		notify->n_register(pcm);
+	pcm_call_notify(pcm, n_register);
 
  unlock:
 	mutex_unlock(&register_mutex);
@@ -1118,7 +1127,6 @@ static int snd_pcm_dev_register(struct snd_device *device)
 static int snd_pcm_dev_disconnect(struct snd_device *device)
 {
 	struct snd_pcm *pcm = device->device_data;
-	struct snd_pcm_notify *notify;
 	struct snd_pcm_substream *substream;
 	int cidx;
 
@@ -1138,8 +1146,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
 		}
 	}
 	if (!pcm->internal) {
-		list_for_each_entry(notify, &snd_pcm_notify_list, list)
-			notify->n_disconnect(pcm);
+		pcm_call_notify(pcm, n_disconnect);
 	}
 	for (cidx = 0; cidx < 2; cidx++) {
 		if (!pcm->internal)
@@ -1151,6 +1158,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
 	return 0;
 }
 
+#if IS_ENABLED(CONFIG_SND_PCM_OSS)
 /**
  * snd_pcm_notify - Add/remove the notify list
  * @notify: PCM notify list
@@ -1183,6 +1191,7 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
 	return 0;
 }
 EXPORT_SYMBOL(snd_pcm_notify);
+#endif /* CONFIG_SND_PCM_OSS */
 
 #ifdef CONFIG_SND_PROC_FS
 /*

+ 5 - 8
sound/core/pcm_compat.c

@@ -27,17 +27,13 @@ static int snd_pcm_ioctl_delay_compat(struct snd_pcm_substream *substream,
 				      s32 __user *src)
 {
 	snd_pcm_sframes_t delay;
-	mm_segment_t fs;
-	int err;
 
-	fs = snd_enter_user();
-	err = snd_pcm_delay(substream, &delay);
-	snd_leave_user(fs);
-	if (err < 0)
-		return err;
+	delay = snd_pcm_delay(substream);
+	if (delay < 0)
+		return delay;
 	if (put_user(delay, src))
 		return -EFAULT;
-	return err;
+	return 0;
 }
 
 static int snd_pcm_ioctl_rewind_compat(struct snd_pcm_substream *substream,
@@ -680,6 +676,7 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
 	case SNDRV_PCM_IOCTL_INFO:
 	case SNDRV_PCM_IOCTL_TSTAMP:
 	case SNDRV_PCM_IOCTL_TTSTAMP:
+	case SNDRV_PCM_IOCTL_USER_PVERSION:
 	case SNDRV_PCM_IOCTL_HWSYNC:
 	case SNDRV_PCM_IOCTL_PREPARE:
 	case SNDRV_PCM_IOCTL_RESET:

+ 4 - 4
sound/core/pcm_drm_eld.c

@@ -29,13 +29,13 @@ static int eld_limit_rates(struct snd_pcm_hw_params *params,
 			   struct snd_pcm_hw_rule *rule)
 {
 	struct snd_interval *r = hw_param_interval(params, rule->var);
-	struct snd_interval *c;
+	const struct snd_interval *c;
 	unsigned int rate_mask = 7, i;
 	const u8 *sad, *eld = rule->private;
 
 	sad = drm_eld_sad(eld);
 	if (sad) {
-		c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+		c = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
 
 		for (i = drm_eld_sad_count(eld); i > 0; i--, sad += 3) {
 			unsigned max_channels = sad_max_channels(sad);
@@ -57,7 +57,7 @@ static int eld_limit_channels(struct snd_pcm_hw_params *params,
 			      struct snd_pcm_hw_rule *rule)
 {
 	struct snd_interval *c = hw_param_interval(params, rule->var);
-	struct snd_interval *r;
+	const struct snd_interval *r;
 	struct snd_interval t = { .min = 1, .max = 2, .integer = 1, };
 	unsigned int i;
 	const u8 *sad, *eld = rule->private;
@@ -67,7 +67,7 @@ static int eld_limit_channels(struct snd_pcm_hw_params *params,
 		unsigned int rate_mask = 0;
 
 		/* Convert the rate interval to a mask */
-		r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+		r = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
 		for (i = 0; i < ARRAY_SIZE(eld_rates); i++)
 			if (r->min <= eld_rates[i] && r->max >= eld_rates[i])
 				rate_mask |= BIT(i);

+ 253 - 415
sound/core/pcm_lib.c

@@ -33,6 +33,8 @@
 #include <sound/pcm_params.h>
 #include <sound/timer.h>
 
+#include "pcm_local.h"
+
 #ifdef CONFIG_SND_PCM_XRUN_DEBUG
 #define CREATE_TRACE_POINTS
 #include "pcm_trace.h"
@@ -40,8 +42,12 @@
 #define trace_hwptr(substream, pos, in_interrupt)
 #define trace_xrun(substream)
 #define trace_hw_ptr_error(substream, reason)
+#define trace_applptr(substream, prev, curr)
 #endif
 
+static int fill_silence_frames(struct snd_pcm_substream *substream,
+			       snd_pcm_uframes_t off, snd_pcm_uframes_t frames);
+
 /*
  * fill ring buffer with silence
  * runtime->silence_start: starting pointer to silence area
@@ -55,18 +61,20 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	snd_pcm_uframes_t frames, ofs, transfer;
+	int err;
 
 	if (runtime->silence_size < runtime->boundary) {
 		snd_pcm_sframes_t noise_dist, n;
-		if (runtime->silence_start != runtime->control->appl_ptr) {
-			n = runtime->control->appl_ptr - runtime->silence_start;
+		snd_pcm_uframes_t appl_ptr = READ_ONCE(runtime->control->appl_ptr);
+		if (runtime->silence_start != appl_ptr) {
+			n = appl_ptr - runtime->silence_start;
 			if (n < 0)
 				n += runtime->boundary;
 			if ((snd_pcm_uframes_t)n < runtime->silence_filled)
 				runtime->silence_filled -= n;
 			else
 				runtime->silence_filled = 0;
-			runtime->silence_start = runtime->control->appl_ptr;
+			runtime->silence_start = appl_ptr;
 		}
 		if (runtime->silence_filled >= runtime->buffer_size)
 			return;
@@ -107,33 +115,8 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
 	ofs = runtime->silence_start % runtime->buffer_size;
 	while (frames > 0) {
 		transfer = ofs + frames > runtime->buffer_size ? runtime->buffer_size - ofs : frames;
-		if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED ||
-		    runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) {
-			if (substream->ops->silence) {
-				int err;
-				err = substream->ops->silence(substream, -1, ofs, transfer);
-				snd_BUG_ON(err < 0);
-			} else {
-				char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, ofs);
-				snd_pcm_format_set_silence(runtime->format, hwbuf, transfer * runtime->channels);
-			}
-		} else {
-			unsigned int c;
-			unsigned int channels = runtime->channels;
-			if (substream->ops->silence) {
-				for (c = 0; c < channels; ++c) {
-					int err;
-					err = substream->ops->silence(substream, c, ofs, transfer);
-					snd_BUG_ON(err < 0);
-				}
-			} else {
-				size_t dma_csize = runtime->dma_bytes / channels;
-				for (c = 0; c < channels; ++c) {
-					char *hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, ofs);
-					snd_pcm_format_set_silence(runtime->format, hwbuf, transfer);
-				}
-			}
-		}
+		err = fill_silence_frames(substream, ofs, transfer);
+		snd_BUG_ON(err < 0);
 		runtime->silence_filled += transfer;
 		frames -= transfer;
 		ofs = 0;
@@ -508,7 +491,6 @@ void snd_pcm_set_ops(struct snd_pcm *pcm, int direction,
 	for (substream = stream->substream; substream != NULL; substream = substream->next)
 		substream->ops = ops;
 }
-
 EXPORT_SYMBOL(snd_pcm_set_ops);
 
 /**
@@ -526,7 +508,6 @@ void snd_pcm_set_sync(struct snd_pcm_substream *substream)
 	runtime->sync.id32[2] = -1;
 	runtime->sync.id32[3] = -1;
 }
-
 EXPORT_SYMBOL(snd_pcm_set_sync);
 
 /*
@@ -643,7 +624,6 @@ int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v)
 	}
 	return changed;
 }
-
 EXPORT_SYMBOL(snd_interval_refine);
 
 static int snd_interval_refine_first(struct snd_interval *i)
@@ -906,7 +886,6 @@ int snd_interval_ratnum(struct snd_interval *i,
 	}
 	return err;
 }
-
 EXPORT_SYMBOL(snd_interval_ratnum);
 
 /**
@@ -1044,7 +1023,6 @@ int snd_interval_list(struct snd_interval *i, unsigned int count,
         }
 	return snd_interval_refine(i, &list_range);
 }
-
 EXPORT_SYMBOL(snd_interval_list);
 
 /**
@@ -1183,7 +1161,6 @@ int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime, unsigned int cond,
 	va_end(args);
 	return 0;
 }
-
 EXPORT_SYMBOL(snd_pcm_hw_rule_add);
 
 /**
@@ -1247,7 +1224,6 @@ int snd_pcm_hw_constraint_integer(struct snd_pcm_runtime *runtime, snd_pcm_hw_pa
 	struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints;
 	return snd_interval_setinteger(constrs_interval(constrs, var));
 }
-
 EXPORT_SYMBOL(snd_pcm_hw_constraint_integer);
 
 /**
@@ -1273,7 +1249,6 @@ int snd_pcm_hw_constraint_minmax(struct snd_pcm_runtime *runtime, snd_pcm_hw_par
 	t.integer = 0;
 	return snd_interval_refine(constrs_interval(constrs, var), &t);
 }
-
 EXPORT_SYMBOL(snd_pcm_hw_constraint_minmax);
 
 static int snd_pcm_hw_rule_list(struct snd_pcm_hw_params *params,
@@ -1304,7 +1279,6 @@ int snd_pcm_hw_constraint_list(struct snd_pcm_runtime *runtime,
 				   snd_pcm_hw_rule_list, (void *)l,
 				   var, -1);
 }
-
 EXPORT_SYMBOL(snd_pcm_hw_constraint_list);
 
 static int snd_pcm_hw_rule_ranges(struct snd_pcm_hw_params *params,
@@ -1371,7 +1345,6 @@ int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime,
 				   snd_pcm_hw_rule_ratnums, (void *)r,
 				   var, -1);
 }
-
 EXPORT_SYMBOL(snd_pcm_hw_constraint_ratnums);
 
 static int snd_pcm_hw_rule_ratdens(struct snd_pcm_hw_params *params,
@@ -1406,7 +1379,6 @@ int snd_pcm_hw_constraint_ratdens(struct snd_pcm_runtime *runtime,
 				   snd_pcm_hw_rule_ratdens, (void *)r,
 				   var, -1);
 }
-
 EXPORT_SYMBOL(snd_pcm_hw_constraint_ratdens);
 
 static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params,
@@ -1415,7 +1387,8 @@ static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params,
 	unsigned int l = (unsigned long) rule->private;
 	int width = l & 0xffff;
 	unsigned int msbits = l >> 16;
-	struct snd_interval *i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
+	const struct snd_interval *i =
+		hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
 
 	if (!snd_interval_single(i))
 		return 0;
@@ -1452,7 +1425,6 @@ int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime,
 				    (void*) l,
 				    SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);
 }
-
 EXPORT_SYMBOL(snd_pcm_hw_constraint_msbits);
 
 static int snd_pcm_hw_rule_step(struct snd_pcm_hw_params *params,
@@ -1480,7 +1452,6 @@ int snd_pcm_hw_constraint_step(struct snd_pcm_runtime *runtime,
 				   snd_pcm_hw_rule_step, (void *) step,
 				   var, -1);
 }
-
 EXPORT_SYMBOL(snd_pcm_hw_constraint_step);
 
 static int snd_pcm_hw_rule_pow2(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
@@ -1511,7 +1482,6 @@ int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime,
 				   snd_pcm_hw_rule_pow2, NULL,
 				   var, -1);
 }
-
 EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2);
 
 static int snd_pcm_hw_rule_noresample_func(struct snd_pcm_hw_params *params,
@@ -1570,7 +1540,6 @@ void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params)
 		_snd_pcm_hw_param_any(params, k);
 	params->info = ~0U;
 }
-
 EXPORT_SYMBOL(_snd_pcm_hw_params_any);
 
 /**
@@ -1603,7 +1572,6 @@ int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params,
 	}
 	return -EINVAL;
 }
-
 EXPORT_SYMBOL(snd_pcm_hw_param_value);
 
 void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params,
@@ -1621,7 +1589,6 @@ void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params,
 		snd_BUG();
 	}
 }
-
 EXPORT_SYMBOL(_snd_pcm_hw_param_setempty);
 
 static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params,
@@ -1668,7 +1635,6 @@ int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm,
 	}
 	return snd_pcm_hw_param_value(params, var, dir);
 }
-
 EXPORT_SYMBOL(snd_pcm_hw_param_first);
 
 static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params,
@@ -1715,48 +1681,8 @@ int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm,
 	}
 	return snd_pcm_hw_param_value(params, var, dir);
 }
-
 EXPORT_SYMBOL(snd_pcm_hw_param_last);
 
-/**
- * snd_pcm_hw_param_choose - choose a configuration defined by @params
- * @pcm: PCM instance
- * @params: the hw_params instance
- *
- * Choose one configuration from configuration space defined by @params.
- * The configuration chosen is that obtained fixing in this order:
- * first access, first format, first subformat, min channels,
- * min rate, min period time, max buffer size, min tick time
- *
- * Return: Zero if successful, or a negative error code on failure.
- */
-int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm,
-			     struct snd_pcm_hw_params *params)
-{
-	static int vars[] = {
-		SNDRV_PCM_HW_PARAM_ACCESS,
-		SNDRV_PCM_HW_PARAM_FORMAT,
-		SNDRV_PCM_HW_PARAM_SUBFORMAT,
-		SNDRV_PCM_HW_PARAM_CHANNELS,
-		SNDRV_PCM_HW_PARAM_RATE,
-		SNDRV_PCM_HW_PARAM_PERIOD_TIME,
-		SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
-		SNDRV_PCM_HW_PARAM_TICK_TIME,
-		-1
-	};
-	int err, *v;
-
-	for (v = vars; *v != -1; v++) {
-		if (*v != SNDRV_PCM_HW_PARAM_BUFFER_SIZE)
-			err = snd_pcm_hw_param_first(pcm, params, *v, NULL);
-		else
-			err = snd_pcm_hw_param_last(pcm, params, *v, NULL);
-		if (snd_BUG_ON(err < 0))
-			return err;
-	}
-	return 0;
-}
-
 static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream,
 				   void *arg)
 {
@@ -1843,8 +1769,6 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
 		      unsigned int cmd, void *arg)
 {
 	switch (cmd) {
-	case SNDRV_PCM_IOCTL1_INFO:
-		return 0;
 	case SNDRV_PCM_IOCTL1_RESET:
 		return snd_pcm_lib_ioctl_reset(substream, arg);
 	case SNDRV_PCM_IOCTL1_CHANNEL_INFO:
@@ -1854,7 +1778,6 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
 	}
 	return -ENXIO;
 }
-
 EXPORT_SYMBOL(snd_pcm_lib_ioctl);
 
 /**
@@ -1890,7 +1813,6 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
 	kill_fasync(&runtime->fasync, SIGIO, POLL_IN);
 	snd_pcm_stream_unlock_irqrestore(substream, flags);
 }
-
 EXPORT_SYMBOL(snd_pcm_period_elapsed);
 
 /*
@@ -1985,129 +1907,147 @@ static int wait_for_avail(struct snd_pcm_substream *substream,
 	return err;
 }
 	
-static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream,
-				      unsigned int hwoff,
-				      unsigned long data, unsigned int off,
-				      snd_pcm_uframes_t frames)
+typedef int (*pcm_transfer_f)(struct snd_pcm_substream *substream,
+			      int channel, unsigned long hwoff,
+			      void *buf, unsigned long bytes);
+
+typedef int (*pcm_copy_f)(struct snd_pcm_substream *, snd_pcm_uframes_t, void *,
+			  snd_pcm_uframes_t, snd_pcm_uframes_t, pcm_transfer_f);
+
+/* calculate the target DMA-buffer position to be written/read */
+static void *get_dma_ptr(struct snd_pcm_runtime *runtime,
+			   int channel, unsigned long hwoff)
 {
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	int err;
-	char __user *buf = (char __user *) data + frames_to_bytes(runtime, off);
-	if (substream->ops->copy) {
-		if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0)
-			return err;
-	} else {
-		char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);
-		if (copy_from_user(hwbuf, buf, frames_to_bytes(runtime, frames)))
-			return -EFAULT;
-	}
+	return runtime->dma_area + hwoff +
+		channel * (runtime->dma_bytes / runtime->channels);
+}
+
+/* default copy_user ops for write; used for both interleaved and non- modes */
+static int default_write_copy(struct snd_pcm_substream *substream,
+			      int channel, unsigned long hwoff,
+			      void *buf, unsigned long bytes)
+{
+	if (copy_from_user(get_dma_ptr(substream->runtime, channel, hwoff),
+			   (void __user *)buf, bytes))
+		return -EFAULT;
 	return 0;
 }
- 
-typedef int (*transfer_f)(struct snd_pcm_substream *substream, unsigned int hwoff,
-			  unsigned long data, unsigned int off,
-			  snd_pcm_uframes_t size);
 
-static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, 
-					    unsigned long data,
-					    snd_pcm_uframes_t size,
-					    int nonblock,
-					    transfer_f transfer)
+/* default copy_kernel ops for write */
+static int default_write_copy_kernel(struct snd_pcm_substream *substream,
+				     int channel, unsigned long hwoff,
+				     void *buf, unsigned long bytes)
+{
+	memcpy(get_dma_ptr(substream->runtime, channel, hwoff), buf, bytes);
+	return 0;
+}
+
+/* fill silence instead of copy data; called as a transfer helper
+ * from __snd_pcm_lib_write() or directly from noninterleaved_copy() when
+ * a NULL buffer is passed
+ */
+static int fill_silence(struct snd_pcm_substream *substream, int channel,
+			unsigned long hwoff, void *buf, unsigned long bytes)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	snd_pcm_uframes_t xfer = 0;
-	snd_pcm_uframes_t offset = 0;
-	snd_pcm_uframes_t avail;
-	int err = 0;
 
-	if (size == 0)
+	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
 		return 0;
+	if (substream->ops->fill_silence)
+		return substream->ops->fill_silence(substream, channel,
+						    hwoff, bytes);
 
-	snd_pcm_stream_lock_irq(substream);
-	switch (runtime->status->state) {
-	case SNDRV_PCM_STATE_PREPARED:
-	case SNDRV_PCM_STATE_RUNNING:
-	case SNDRV_PCM_STATE_PAUSED:
-		break;
-	case SNDRV_PCM_STATE_XRUN:
-		err = -EPIPE;
-		goto _end_unlock;
-	case SNDRV_PCM_STATE_SUSPENDED:
-		err = -ESTRPIPE;
-		goto _end_unlock;
-	default:
-		err = -EBADFD;
-		goto _end_unlock;
-	}
+	snd_pcm_format_set_silence(runtime->format,
+				   get_dma_ptr(runtime, channel, hwoff),
+				   bytes_to_samples(runtime, bytes));
+	return 0;
+}
 
-	runtime->twake = runtime->control->avail_min ? : 1;
-	if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
-		snd_pcm_update_hw_ptr(substream);
-	avail = snd_pcm_playback_avail(runtime);
-	while (size > 0) {
-		snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
-		snd_pcm_uframes_t cont;
-		if (!avail) {
-			if (nonblock) {
-				err = -EAGAIN;
-				goto _end_unlock;
-			}
-			runtime->twake = min_t(snd_pcm_uframes_t, size,
-					runtime->control->avail_min ? : 1);
-			err = wait_for_avail(substream, &avail);
-			if (err < 0)
-				goto _end_unlock;
-		}
-		frames = size > avail ? avail : size;
-		cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
-		if (frames > cont)
-			frames = cont;
-		if (snd_BUG_ON(!frames)) {
-			runtime->twake = 0;
-			snd_pcm_stream_unlock_irq(substream);
-			return -EINVAL;
-		}
-		appl_ptr = runtime->control->appl_ptr;
-		appl_ofs = appl_ptr % runtime->buffer_size;
-		snd_pcm_stream_unlock_irq(substream);
-		err = transfer(substream, appl_ofs, data, offset, frames);
-		snd_pcm_stream_lock_irq(substream);
-		if (err < 0)
-			goto _end_unlock;
-		switch (runtime->status->state) {
-		case SNDRV_PCM_STATE_XRUN:
-			err = -EPIPE;
-			goto _end_unlock;
-		case SNDRV_PCM_STATE_SUSPENDED:
-			err = -ESTRPIPE;
-			goto _end_unlock;
-		default:
-			break;
-		}
-		appl_ptr += frames;
-		if (appl_ptr >= runtime->boundary)
-			appl_ptr -= runtime->boundary;
-		runtime->control->appl_ptr = appl_ptr;
-		if (substream->ops->ack)
-			substream->ops->ack(substream);
+/* default copy_user ops for read; used for both interleaved and non- modes */
+static int default_read_copy(struct snd_pcm_substream *substream,
+			     int channel, unsigned long hwoff,
+			     void *buf, unsigned long bytes)
+{
+	if (copy_to_user((void __user *)buf,
+			 get_dma_ptr(substream->runtime, channel, hwoff),
+			 bytes))
+		return -EFAULT;
+	return 0;
+}
 
-		offset += frames;
-		size -= frames;
-		xfer += frames;
-		avail -= frames;
-		if (runtime->status->state == SNDRV_PCM_STATE_PREPARED &&
-		    snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold) {
-			err = snd_pcm_start(substream);
-			if (err < 0)
-				goto _end_unlock;
-		}
+/* default copy_kernel ops for read */
+static int default_read_copy_kernel(struct snd_pcm_substream *substream,
+				    int channel, unsigned long hwoff,
+				    void *buf, unsigned long bytes)
+{
+	memcpy(buf, get_dma_ptr(substream->runtime, channel, hwoff), bytes);
+	return 0;
+}
+
+/* call transfer function with the converted pointers and sizes;
+ * for interleaved mode, it's one shot for all samples
+ */
+static int interleaved_copy(struct snd_pcm_substream *substream,
+			    snd_pcm_uframes_t hwoff, void *data,
+			    snd_pcm_uframes_t off,
+			    snd_pcm_uframes_t frames,
+			    pcm_transfer_f transfer)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	/* convert to bytes */
+	hwoff = frames_to_bytes(runtime, hwoff);
+	off = frames_to_bytes(runtime, off);
+	frames = frames_to_bytes(runtime, frames);
+	return transfer(substream, 0, hwoff, data + off, frames);
+}
+
+/* call transfer function with the converted pointers and sizes for each
+ * non-interleaved channel; when buffer is NULL, silencing instead of copying
+ */
+static int noninterleaved_copy(struct snd_pcm_substream *substream,
+			       snd_pcm_uframes_t hwoff, void *data,
+			       snd_pcm_uframes_t off,
+			       snd_pcm_uframes_t frames,
+			       pcm_transfer_f transfer)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int channels = runtime->channels;
+	void **bufs = data;
+	int c, err;
+
+	/* convert to bytes; note that it's not frames_to_bytes() here.
+	 * in non-interleaved mode, we copy for each channel, thus
+	 * each copy is n_samples bytes x channels = whole frames.
+	 */
+	off = samples_to_bytes(runtime, off);
+	frames = samples_to_bytes(runtime, frames);
+	hwoff = samples_to_bytes(runtime, hwoff);
+	for (c = 0; c < channels; ++c, ++bufs) {
+		if (!data || !*bufs)
+			err = fill_silence(substream, c, hwoff, NULL, frames);
+		else
+			err = transfer(substream, c, hwoff, *bufs + off,
+				       frames);
+		if (err < 0)
+			return err;
 	}
- _end_unlock:
-	runtime->twake = 0;
-	if (xfer > 0 && err >= 0)
-		snd_pcm_update_state(substream, runtime);
-	snd_pcm_stream_unlock_irq(substream);
-	return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
+	return 0;
+}
+
+/* fill silence on the given buffer position;
+ * called from snd_pcm_playback_silence()
+ */
+static int fill_silence_frames(struct snd_pcm_substream *substream,
+			       snd_pcm_uframes_t off, snd_pcm_uframes_t frames)
+{
+	if (substream->runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED ||
+	    substream->runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED)
+		return interleaved_copy(substream, off, NULL, 0, frames,
+					fill_silence);
+	else
+		return noninterleaved_copy(substream, off, NULL, 0, frames,
+					   fill_silence);
 }
 
 /* sanity-check for read/write methods */
@@ -2117,164 +2057,137 @@ static int pcm_sanity_check(struct snd_pcm_substream *substream)
 	if (PCM_RUNTIME_CHECK(substream))
 		return -ENXIO;
 	runtime = substream->runtime;
-	if (snd_BUG_ON(!substream->ops->copy && !runtime->dma_area))
+	if (snd_BUG_ON(!substream->ops->copy_user && !runtime->dma_area))
 		return -EINVAL;
 	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
 		return -EBADFD;
 	return 0;
 }
 
-snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const void __user *buf, snd_pcm_uframes_t size)
+static int pcm_accessible_state(struct snd_pcm_runtime *runtime)
 {
-	struct snd_pcm_runtime *runtime;
-	int nonblock;
-	int err;
-
-	err = pcm_sanity_check(substream);
-	if (err < 0)
-		return err;
-	runtime = substream->runtime;
-	nonblock = !!(substream->f_flags & O_NONBLOCK);
-
-	if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED &&
-	    runtime->channels > 1)
-		return -EINVAL;
-	return snd_pcm_lib_write1(substream, (unsigned long)buf, size, nonblock,
-				  snd_pcm_lib_write_transfer);
+	switch (runtime->status->state) {
+	case SNDRV_PCM_STATE_PREPARED:
+	case SNDRV_PCM_STATE_RUNNING:
+	case SNDRV_PCM_STATE_PAUSED:
+		return 0;
+	case SNDRV_PCM_STATE_XRUN:
+		return -EPIPE;
+	case SNDRV_PCM_STATE_SUSPENDED:
+		return -ESTRPIPE;
+	default:
+		return -EBADFD;
+	}
 }
 
-EXPORT_SYMBOL(snd_pcm_lib_write);
-
-static int snd_pcm_lib_writev_transfer(struct snd_pcm_substream *substream,
-				       unsigned int hwoff,
-				       unsigned long data, unsigned int off,
-				       snd_pcm_uframes_t frames)
+/* update to the given appl_ptr and call ack callback if needed;
+ * when an error is returned, take back to the original value
+ */
+int pcm_lib_apply_appl_ptr(struct snd_pcm_substream *substream,
+			   snd_pcm_uframes_t appl_ptr)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	int err;
-	void __user **bufs = (void __user **)data;
-	int channels = runtime->channels;
-	int c;
-	if (substream->ops->copy) {
-		if (snd_BUG_ON(!substream->ops->silence))
-			return -EINVAL;
-		for (c = 0; c < channels; ++c, ++bufs) {
-			if (*bufs == NULL) {
-				if ((err = substream->ops->silence(substream, c, hwoff, frames)) < 0)
-					return err;
-			} else {
-				char __user *buf = *bufs + samples_to_bytes(runtime, off);
-				if ((err = substream->ops->copy(substream, c, hwoff, buf, frames)) < 0)
-					return err;
-			}
-		}
-	} else {
-		/* default transfer behaviour */
-		size_t dma_csize = runtime->dma_bytes / channels;
-		for (c = 0; c < channels; ++c, ++bufs) {
-			char *hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, hwoff);
-			if (*bufs == NULL) {
-				snd_pcm_format_set_silence(runtime->format, hwbuf, frames);
-			} else {
-				char __user *buf = *bufs + samples_to_bytes(runtime, off);
-				if (copy_from_user(hwbuf, buf, samples_to_bytes(runtime, frames)))
-					return -EFAULT;
-			}
+	snd_pcm_uframes_t old_appl_ptr = runtime->control->appl_ptr;
+	int ret;
+
+	if (old_appl_ptr == appl_ptr)
+		return 0;
+
+	runtime->control->appl_ptr = appl_ptr;
+	if (substream->ops->ack) {
+		ret = substream->ops->ack(substream);
+		if (ret < 0) {
+			runtime->control->appl_ptr = old_appl_ptr;
+			return ret;
 		}
 	}
+
+	trace_applptr(substream, old_appl_ptr, appl_ptr);
+
 	return 0;
 }
- 
-snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream,
-				     void __user **bufs,
-				     snd_pcm_uframes_t frames)
+
+/* the common loop for read/write data */
+snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream,
+				     void *data, bool interleaved,
+				     snd_pcm_uframes_t size, bool in_kernel)
 {
-	struct snd_pcm_runtime *runtime;
-	int nonblock;
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	snd_pcm_uframes_t xfer = 0;
+	snd_pcm_uframes_t offset = 0;
+	snd_pcm_uframes_t avail;
+	pcm_copy_f writer;
+	pcm_transfer_f transfer;
+	bool nonblock;
+	bool is_playback;
 	int err;
 
 	err = pcm_sanity_check(substream);
 	if (err < 0)
 		return err;
-	runtime = substream->runtime;
-	nonblock = !!(substream->f_flags & O_NONBLOCK);
-
-	if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
-		return -EINVAL;
-	return snd_pcm_lib_write1(substream, (unsigned long)bufs, frames,
-				  nonblock, snd_pcm_lib_writev_transfer);
-}
-
-EXPORT_SYMBOL(snd_pcm_lib_writev);
 
-static int snd_pcm_lib_read_transfer(struct snd_pcm_substream *substream, 
-				     unsigned int hwoff,
-				     unsigned long data, unsigned int off,
-				     snd_pcm_uframes_t frames)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	int err;
-	char __user *buf = (char __user *) data + frames_to_bytes(runtime, off);
-	if (substream->ops->copy) {
-		if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0)
-			return err;
+	is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	if (interleaved) {
+		if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED &&
+		    runtime->channels > 1)
+			return -EINVAL;
+		writer = interleaved_copy;
 	} else {
-		char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);
-		if (copy_to_user(buf, hwbuf, frames_to_bytes(runtime, frames)))
-			return -EFAULT;
+		if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
+			return -EINVAL;
+		writer = noninterleaved_copy;
 	}
-	return 0;
-}
 
-static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
-					   unsigned long data,
-					   snd_pcm_uframes_t size,
-					   int nonblock,
-					   transfer_f transfer)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	snd_pcm_uframes_t xfer = 0;
-	snd_pcm_uframes_t offset = 0;
-	snd_pcm_uframes_t avail;
-	int err = 0;
+	if (!data) {
+		if (is_playback)
+			transfer = fill_silence;
+		else
+			return -EINVAL;
+	} else if (in_kernel) {
+		if (substream->ops->copy_kernel)
+			transfer = substream->ops->copy_kernel;
+		else
+			transfer = is_playback ?
+				default_write_copy_kernel : default_read_copy_kernel;
+	} else {
+		if (substream->ops->copy_user)
+			transfer = (pcm_transfer_f)substream->ops->copy_user;
+		else
+			transfer = is_playback ?
+				default_write_copy : default_read_copy;
+	}
 
 	if (size == 0)
 		return 0;
 
+	nonblock = !!(substream->f_flags & O_NONBLOCK);
+
 	snd_pcm_stream_lock_irq(substream);
-	switch (runtime->status->state) {
-	case SNDRV_PCM_STATE_PREPARED:
-		if (size >= runtime->start_threshold) {
-			err = snd_pcm_start(substream);
-			if (err < 0)
-				goto _end_unlock;
-		}
-		break;
-	case SNDRV_PCM_STATE_DRAINING:
-	case SNDRV_PCM_STATE_RUNNING:
-	case SNDRV_PCM_STATE_PAUSED:
-		break;
-	case SNDRV_PCM_STATE_XRUN:
-		err = -EPIPE;
-		goto _end_unlock;
-	case SNDRV_PCM_STATE_SUSPENDED:
-		err = -ESTRPIPE;
-		goto _end_unlock;
-	default:
-		err = -EBADFD;
+	err = pcm_accessible_state(runtime);
+	if (err < 0)
 		goto _end_unlock;
+
+	if (!is_playback &&
+	    runtime->status->state == SNDRV_PCM_STATE_PREPARED &&
+	    size >= runtime->start_threshold) {
+		err = snd_pcm_start(substream);
+		if (err < 0)
+			goto _end_unlock;
 	}
 
 	runtime->twake = runtime->control->avail_min ? : 1;
 	if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
 		snd_pcm_update_hw_ptr(substream);
-	avail = snd_pcm_capture_avail(runtime);
+	if (is_playback)
+		avail = snd_pcm_playback_avail(runtime);
+	else
+		avail = snd_pcm_capture_avail(runtime);
 	while (size > 0) {
 		snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
 		snd_pcm_uframes_t cont;
 		if (!avail) {
-			if (runtime->status->state ==
-			    SNDRV_PCM_STATE_DRAINING) {
+			if (!is_playback &&
+			    runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
 				snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
 				goto _end_unlock;
 			}
@@ -2291,7 +2204,9 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
 				continue; /* draining */
 		}
 		frames = size > avail ? avail : size;
-		cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
+		appl_ptr = READ_ONCE(runtime->control->appl_ptr);
+		appl_ofs = appl_ptr % runtime->buffer_size;
+		cont = runtime->buffer_size - appl_ofs;
 		if (frames > cont)
 			frames = cont;
 		if (snd_BUG_ON(!frames)) {
@@ -2299,34 +2214,33 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
 			snd_pcm_stream_unlock_irq(substream);
 			return -EINVAL;
 		}
-		appl_ptr = runtime->control->appl_ptr;
-		appl_ofs = appl_ptr % runtime->buffer_size;
 		snd_pcm_stream_unlock_irq(substream);
-		err = transfer(substream, appl_ofs, data, offset, frames);
+		err = writer(substream, appl_ofs, data, offset, frames,
+			     transfer);
 		snd_pcm_stream_lock_irq(substream);
 		if (err < 0)
 			goto _end_unlock;
-		switch (runtime->status->state) {
-		case SNDRV_PCM_STATE_XRUN:
-			err = -EPIPE;
-			goto _end_unlock;
-		case SNDRV_PCM_STATE_SUSPENDED:
-			err = -ESTRPIPE;
+		err = pcm_accessible_state(runtime);
+		if (err < 0)
 			goto _end_unlock;
-		default:
-			break;
-		}
 		appl_ptr += frames;
 		if (appl_ptr >= runtime->boundary)
 			appl_ptr -= runtime->boundary;
-		runtime->control->appl_ptr = appl_ptr;
-		if (substream->ops->ack)
-			substream->ops->ack(substream);
+		err = pcm_lib_apply_appl_ptr(substream, appl_ptr);
+		if (err < 0)
+			goto _end_unlock;
 
 		offset += frames;
 		size -= frames;
 		xfer += frames;
 		avail -= frames;
+		if (is_playback &&
+		    runtime->status->state == SNDRV_PCM_STATE_PREPARED &&
+		    snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold) {
+			err = snd_pcm_start(substream);
+			if (err < 0)
+				goto _end_unlock;
+		}
 	}
  _end_unlock:
 	runtime->twake = 0;
@@ -2335,83 +2249,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
 	snd_pcm_stream_unlock_irq(substream);
 	return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
 }
-
-snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __user *buf, snd_pcm_uframes_t size)
-{
-	struct snd_pcm_runtime *runtime;
-	int nonblock;
-	int err;
-	
-	err = pcm_sanity_check(substream);
-	if (err < 0)
-		return err;
-	runtime = substream->runtime;
-	nonblock = !!(substream->f_flags & O_NONBLOCK);
-	if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED)
-		return -EINVAL;
-	return snd_pcm_lib_read1(substream, (unsigned long)buf, size, nonblock, snd_pcm_lib_read_transfer);
-}
-
-EXPORT_SYMBOL(snd_pcm_lib_read);
-
-static int snd_pcm_lib_readv_transfer(struct snd_pcm_substream *substream,
-				      unsigned int hwoff,
-				      unsigned long data, unsigned int off,
-				      snd_pcm_uframes_t frames)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	int err;
-	void __user **bufs = (void __user **)data;
-	int channels = runtime->channels;
-	int c;
-	if (substream->ops->copy) {
-		for (c = 0; c < channels; ++c, ++bufs) {
-			char __user *buf;
-			if (*bufs == NULL)
-				continue;
-			buf = *bufs + samples_to_bytes(runtime, off);
-			if ((err = substream->ops->copy(substream, c, hwoff, buf, frames)) < 0)
-				return err;
-		}
-	} else {
-		snd_pcm_uframes_t dma_csize = runtime->dma_bytes / channels;
-		for (c = 0; c < channels; ++c, ++bufs) {
-			char *hwbuf;
-			char __user *buf;
-			if (*bufs == NULL)
-				continue;
-
-			hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, hwoff);
-			buf = *bufs + samples_to_bytes(runtime, off);
-			if (copy_to_user(buf, hwbuf, samples_to_bytes(runtime, frames)))
-				return -EFAULT;
-		}
-	}
-	return 0;
-}
- 
-snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream,
-				    void __user **bufs,
-				    snd_pcm_uframes_t frames)
-{
-	struct snd_pcm_runtime *runtime;
-	int nonblock;
-	int err;
-
-	err = pcm_sanity_check(substream);
-	if (err < 0)
-		return err;
-	runtime = substream->runtime;
-	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
-		return -EBADFD;
-
-	nonblock = !!(substream->f_flags & O_NONBLOCK);
-	if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
-		return -EINVAL;
-	return snd_pcm_lib_read1(substream, (unsigned long)bufs, frames, nonblock, snd_pcm_lib_readv_transfer);
-}
-
-EXPORT_SYMBOL(snd_pcm_lib_readv);
+EXPORT_SYMBOL(__snd_pcm_lib_xfer);
 
 /*
  * standard channel mapping helpers

+ 50 - 0
sound/core/pcm_local.h

@@ -0,0 +1,50 @@
+/*
+ * pcm_local.h - a local header file for snd-pcm module.
+ *
+ * Copyright (c) Takashi Sakamoto <o-takashi@sakamocchi.jp>
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#ifndef __SOUND_CORE_PCM_LOCAL_H
+#define __SOUND_CORE_PCM_LOCAL_H
+
+extern const struct snd_pcm_hw_constraint_list snd_pcm_known_rates;
+
+void snd_interval_mul(const struct snd_interval *a,
+		      const struct snd_interval *b, struct snd_interval *c);
+void snd_interval_div(const struct snd_interval *a,
+		      const struct snd_interval *b, struct snd_interval *c);
+void snd_interval_muldivk(const struct snd_interval *a,
+			  const struct snd_interval *b,
+			  unsigned int k, struct snd_interval *c);
+void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k,
+			  const struct snd_interval *b, struct snd_interval *c);
+
+int snd_pcm_hw_constraints_init(struct snd_pcm_substream *substream);
+int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream);
+
+int snd_pcm_hw_constraint_mask(struct snd_pcm_runtime *runtime,
+			       snd_pcm_hw_param_t var, u_int32_t mask);
+
+int pcm_lib_apply_appl_ptr(struct snd_pcm_substream *substream,
+			   snd_pcm_uframes_t appl_ptr);
+int snd_pcm_update_state(struct snd_pcm_substream *substream,
+			 struct snd_pcm_runtime *runtime);
+int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream);
+
+void snd_pcm_playback_silence(struct snd_pcm_substream *substream,
+			      snd_pcm_uframes_t new_hw_ptr);
+
+#ifdef CONFIG_SND_PCM_TIMER
+void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream);
+void snd_pcm_timer_init(struct snd_pcm_substream *substream);
+void snd_pcm_timer_done(struct snd_pcm_substream *substream);
+#else
+static inline void
+snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream) {}
+static inline void snd_pcm_timer_init(struct snd_pcm_substream *substream) {}
+static inline void snd_pcm_timer_done(struct snd_pcm_substream *substream) {}
+#endif
+
+#endif	/* __SOUND_CORE_PCM_LOCAL_H */

+ 0 - 6
sound/core/pcm_memory.c

@@ -120,7 +120,6 @@ int snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm)
 			snd_pcm_lib_preallocate_free(substream);
 	return 0;
 }
-
 EXPORT_SYMBOL(snd_pcm_lib_preallocate_free_for_all);
 
 #ifdef CONFIG_SND_VERBOSE_PROCFS
@@ -263,7 +262,6 @@ int snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream,
 	substream->dma_buffer.dev.dev = data;
 	return snd_pcm_lib_preallocate_pages1(substream, size, max);
 }
-
 EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages);
 
 /**
@@ -292,7 +290,6 @@ int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm,
 				return err;
 	return 0;
 }
-
 EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all);
 
 #ifdef CONFIG_SND_DMA_SGBUF
@@ -314,7 +311,6 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigne
 		return NULL;
 	return sgbuf->page_table[idx];
 }
-
 EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);
 #endif /* CONFIG_SND_DMA_SGBUF */
 
@@ -370,7 +366,6 @@ int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size)
 	runtime->dma_bytes = size;
 	return 1;			/* area was changed */
 }
-
 EXPORT_SYMBOL(snd_pcm_lib_malloc_pages);
 
 /**
@@ -398,7 +393,6 @@ int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream)
 	snd_pcm_set_runtime_buffer(substream, NULL);
 	return 0;
 }
-
 EXPORT_SYMBOL(snd_pcm_lib_free_pages);
 
 int _snd_pcm_lib_alloc_vmalloc_buffer(struct snd_pcm_substream *substream,

+ 3 - 11
sound/core/pcm_misc.c

@@ -23,6 +23,9 @@
 #include <linux/export.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
+
+#include "pcm_local.h"
+
 #define SND_PCM_FORMAT_UNKNOWN (-1)
 
 /* NOTE: "signed" prefix must be given below since the default char is
@@ -245,7 +248,6 @@ int snd_pcm_format_signed(snd_pcm_format_t format)
 		return -EINVAL;
 	return val;
 }
-
 EXPORT_SYMBOL(snd_pcm_format_signed);
 
 /**
@@ -264,7 +266,6 @@ int snd_pcm_format_unsigned(snd_pcm_format_t format)
 		return val;
 	return !val;
 }
-
 EXPORT_SYMBOL(snd_pcm_format_unsigned);
 
 /**
@@ -277,7 +278,6 @@ int snd_pcm_format_linear(snd_pcm_format_t format)
 {
 	return snd_pcm_format_signed(format) >= 0;
 }
-
 EXPORT_SYMBOL(snd_pcm_format_linear);
 
 /**
@@ -296,7 +296,6 @@ int snd_pcm_format_little_endian(snd_pcm_format_t format)
 		return -EINVAL;
 	return val;
 }
-
 EXPORT_SYMBOL(snd_pcm_format_little_endian);
 
 /**
@@ -315,7 +314,6 @@ int snd_pcm_format_big_endian(snd_pcm_format_t format)
 		return val;
 	return !val;
 }
-
 EXPORT_SYMBOL(snd_pcm_format_big_endian);
 
 /**
@@ -334,7 +332,6 @@ int snd_pcm_format_width(snd_pcm_format_t format)
 		return -EINVAL;
 	return val;
 }
-
 EXPORT_SYMBOL(snd_pcm_format_width);
 
 /**
@@ -353,7 +350,6 @@ int snd_pcm_format_physical_width(snd_pcm_format_t format)
 		return -EINVAL;
 	return val;
 }
-
 EXPORT_SYMBOL(snd_pcm_format_physical_width);
 
 /**
@@ -371,7 +367,6 @@ ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples)
 		return -EINVAL;
 	return samples * phys_width / 8;
 }
-
 EXPORT_SYMBOL(snd_pcm_format_size);
 
 /**
@@ -388,7 +383,6 @@ const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format)
 		return NULL;
 	return pcm_formats[(INT)format].silence;
 }
-
 EXPORT_SYMBOL(snd_pcm_format_silence_64);
 
 /**
@@ -459,7 +453,6 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int
 #endif
 	return 0;
 }
-
 EXPORT_SYMBOL(snd_pcm_format_set_silence);
 
 /**
@@ -488,7 +481,6 @@ int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime)
 	}
 	return 0;
 }
-
 EXPORT_SYMBOL(snd_pcm_limit_hw_rates);
 
 /**

+ 559 - 454
sound/core/pcm_native.c

@@ -37,6 +37,18 @@
 #include <sound/minors.h>
 #include <linux/uio.h>
 
+#include "pcm_local.h"
+
+#ifdef CONFIG_SND_DEBUG
+#define CREATE_TRACE_POINTS
+#include "pcm_param_trace.h"
+#else
+#define trace_hw_mask_param_enabled()		0
+#define trace_hw_interval_param_enabled()	0
+#define trace_hw_mask_param(substream, type, index, prev, curr)
+#define trace_hw_interval_param(substream, type, index, prev, curr)
+#endif
+
 /*
  *  Compatibility
  */
@@ -181,20 +193,6 @@ void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream,
 }
 EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irqrestore);
 
-static inline mm_segment_t snd_enter_user(void)
-{
-	mm_segment_t fs = get_fs();
-	set_fs(get_ds());
-	return fs;
-}
-
-static inline void snd_leave_user(mm_segment_t fs)
-{
-	set_fs(fs);
-}
-
-
-
 int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info)
 {
 	struct snd_pcm_runtime *runtime;
@@ -214,11 +212,7 @@ int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info)
 	info->subdevices_avail = pstr->substream_count - pstr->substream_opened;
 	strlcpy(info->subname, substream->name, sizeof(info->subname));
 	runtime = substream->runtime;
-	/* AB: FIXME!!! This is definitely nonsense */
-	if (runtime) {
-		info->sync = runtime->sync;
-		substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_INFO, info);
-	}
+
 	return 0;
 }
 
@@ -255,205 +249,268 @@ static bool hw_support_mmap(struct snd_pcm_substream *substream)
 	return true;
 }
 
-#undef RULES_DEBUG
-
-#ifdef RULES_DEBUG
-#define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #v
-static const char * const snd_pcm_hw_param_names[] = {
-	HW_PARAM(ACCESS),
-	HW_PARAM(FORMAT),
-	HW_PARAM(SUBFORMAT),
-	HW_PARAM(SAMPLE_BITS),
-	HW_PARAM(FRAME_BITS),
-	HW_PARAM(CHANNELS),
-	HW_PARAM(RATE),
-	HW_PARAM(PERIOD_TIME),
-	HW_PARAM(PERIOD_SIZE),
-	HW_PARAM(PERIOD_BYTES),
-	HW_PARAM(PERIODS),
-	HW_PARAM(BUFFER_TIME),
-	HW_PARAM(BUFFER_SIZE),
-	HW_PARAM(BUFFER_BYTES),
-	HW_PARAM(TICK_TIME),
-};
-#endif
-
-int snd_pcm_hw_refine(struct snd_pcm_substream *substream, 
-		      struct snd_pcm_hw_params *params)
+static int constrain_mask_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params)
 {
+	struct snd_pcm_hw_constraints *constrs =
+					&substream->runtime->hw_constraints;
+	struct snd_mask *m;
 	unsigned int k;
-	struct snd_pcm_hardware *hw;
-	struct snd_interval *i = NULL;
-	struct snd_mask *m = NULL;
-	struct snd_pcm_hw_constraints *constrs = &substream->runtime->hw_constraints;
-	unsigned int rstamps[constrs->rules_num];
-	unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1];
-	unsigned int stamp = 2;
-	int changed, again;
-
-	params->info = 0;
-	params->fifo_size = 0;
-	if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_SAMPLE_BITS))
-		params->msbits = 0;
-	if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_RATE)) {
-		params->rate_num = 0;
-		params->rate_den = 0;
-	}
+	struct snd_mask old_mask;
+	int changed;
 
 	for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++) {
 		m = hw_param_mask(params, k);
 		if (snd_mask_empty(m))
 			return -EINVAL;
+
+		/* This parameter is not requested to change by a caller. */
 		if (!(params->rmask & (1 << k)))
 			continue;
-#ifdef RULES_DEBUG
-		pr_debug("%s = ", snd_pcm_hw_param_names[k]);
-		pr_cont("%04x%04x%04x%04x -> ", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);
-#endif
+
+		if (trace_hw_mask_param_enabled())
+			old_mask = *m;
+
 		changed = snd_mask_refine(m, constrs_mask(constrs, k));
-#ifdef RULES_DEBUG
-		pr_cont("%04x%04x%04x%04x\n", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);
-#endif
-		if (changed)
-			params->cmask |= 1 << k;
 		if (changed < 0)
 			return changed;
+		if (changed == 0)
+			continue;
+
+		/* Set corresponding flag so that the caller gets it. */
+		trace_hw_mask_param(substream, k, 0, &old_mask, m);
+		params->cmask |= 1 << k;
 	}
 
+	return 0;
+}
+
+static int constrain_interval_params(struct snd_pcm_substream *substream,
+				     struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_hw_constraints *constrs =
+					&substream->runtime->hw_constraints;
+	struct snd_interval *i;
+	unsigned int k;
+	struct snd_interval old_interval;
+	int changed;
+
 	for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) {
 		i = hw_param_interval(params, k);
 		if (snd_interval_empty(i))
 			return -EINVAL;
+
+		/* This parameter is not requested to change by a caller. */
 		if (!(params->rmask & (1 << k)))
 			continue;
-#ifdef RULES_DEBUG
-		pr_debug("%s = ", snd_pcm_hw_param_names[k]);
-		if (i->empty)
-			pr_cont("empty");
-		else
-			pr_cont("%c%u %u%c",
-			       i->openmin ? '(' : '[', i->min,
-			       i->max, i->openmax ? ')' : ']');
-		pr_cont(" -> ");
-#endif
+
+		if (trace_hw_interval_param_enabled())
+			old_interval = *i;
+
 		changed = snd_interval_refine(i, constrs_interval(constrs, k));
-#ifdef RULES_DEBUG
-		if (i->empty)
-			pr_cont("empty\n");
-		else 
-			pr_cont("%c%u %u%c\n",
-			       i->openmin ? '(' : '[', i->min,
-			       i->max, i->openmax ? ')' : ']');
-#endif
-		if (changed)
-			params->cmask |= 1 << k;
 		if (changed < 0)
 			return changed;
+		if (changed == 0)
+			continue;
+
+		/* Set corresponding flag so that the caller gets it. */
+		trace_hw_interval_param(substream, k, 0, &old_interval, i);
+		params->cmask |= 1 << k;
 	}
 
+	return 0;
+}
+
+static int constrain_params_by_rules(struct snd_pcm_substream *substream,
+				     struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_hw_constraints *constrs =
+					&substream->runtime->hw_constraints;
+	unsigned int k;
+	unsigned int rstamps[constrs->rules_num];
+	unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1];
+	unsigned int stamp;
+	struct snd_pcm_hw_rule *r;
+	unsigned int d;
+	struct snd_mask old_mask;
+	struct snd_interval old_interval;
+	bool again;
+	int changed;
+
+	/*
+	 * Each application of rule has own sequence number.
+	 *
+	 * Each member of 'rstamps' array represents the sequence number of
+	 * recent application of corresponding rule.
+	 */
 	for (k = 0; k < constrs->rules_num; k++)
 		rstamps[k] = 0;
-	for (k = 0; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) 
+
+	/*
+	 * Each member of 'vstamps' array represents the sequence number of
+	 * recent application of rule in which corresponding parameters were
+	 * changed.
+	 *
+	 * In initial state, elements corresponding to parameters requested by
+	 * a caller is 1. For unrequested parameters, corresponding members
+	 * have 0 so that the parameters are never changed anymore.
+	 */
+	for (k = 0; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++)
 		vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0;
-	do {
-		again = 0;
-		for (k = 0; k < constrs->rules_num; k++) {
-			struct snd_pcm_hw_rule *r = &constrs->rules[k];
-			unsigned int d;
-			int doit = 0;
-			if (r->cond && !(r->cond & params->flags))
-				continue;
-			for (d = 0; r->deps[d] >= 0; d++) {
-				if (vstamps[r->deps[d]] > rstamps[k]) {
-					doit = 1;
-					break;
-				}
-			}
-			if (!doit)
-				continue;
-#ifdef RULES_DEBUG
-			pr_debug("Rule %d [%p]: ", k, r->func);
-			if (r->var >= 0) {
-				pr_cont("%s = ", snd_pcm_hw_param_names[r->var]);
-				if (hw_is_mask(r->var)) {
-					m = hw_param_mask(params, r->var);
-					pr_cont("%x", *m->bits);
-				} else {
-					i = hw_param_interval(params, r->var);
-					if (i->empty)
-						pr_cont("empty");
-					else
-						pr_cont("%c%u %u%c",
-						       i->openmin ? '(' : '[', i->min,
-						       i->max, i->openmax ? ')' : ']');
-				}
-			}
-#endif
-			changed = r->func(params, r);
-#ifdef RULES_DEBUG
-			if (r->var >= 0) {
-				pr_cont(" -> ");
-				if (hw_is_mask(r->var))
-					pr_cont("%x", *m->bits);
-				else {
-					if (i->empty)
-						pr_cont("empty");
-					else
-						pr_cont("%c%u %u%c",
-						       i->openmin ? '(' : '[', i->min,
-						       i->max, i->openmax ? ')' : ']');
-				}
+
+	/* Due to the above design, actual sequence number starts at 2. */
+	stamp = 2;
+retry:
+	/* Apply all rules in order. */
+	again = false;
+	for (k = 0; k < constrs->rules_num; k++) {
+		r = &constrs->rules[k];
+
+		/*
+		 * Check condition bits of this rule. When the rule has
+		 * some condition bits, parameter without the bits is
+		 * never processed. SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP
+		 * is an example of the condition bits.
+		 */
+		if (r->cond && !(r->cond & params->flags))
+			continue;
+
+		/*
+		 * The 'deps' array includes maximum three dependencies
+		 * to SNDRV_PCM_HW_PARAM_XXXs for this rule. The fourth
+		 * member of this array is a sentinel and should be
+		 * negative value.
+		 *
+		 * This rule should be processed in this time when dependent
+		 * parameters were changed at former applications of the other
+		 * rules.
+		 */
+		for (d = 0; r->deps[d] >= 0; d++) {
+			if (vstamps[r->deps[d]] > rstamps[k])
+				break;
+		}
+		if (r->deps[d] < 0)
+			continue;
+
+		if (trace_hw_mask_param_enabled()) {
+			if (hw_is_mask(r->var))
+				old_mask = *hw_param_mask(params, r->var);
+		}
+		if (trace_hw_interval_param_enabled()) {
+			if (hw_is_interval(r->var))
+				old_interval = *hw_param_interval(params, r->var);
+		}
+
+		changed = r->func(params, r);
+		if (changed < 0)
+			return changed;
+
+		/*
+		 * When the parameter is changed, notify it to the caller
+		 * by corresponding returned bit, then preparing for next
+		 * iteration.
+		 */
+		if (changed && r->var >= 0) {
+			if (hw_is_mask(r->var)) {
+				trace_hw_mask_param(substream, r->var,
+					k + 1, &old_mask,
+					hw_param_mask(params, r->var));
 			}
-			pr_cont("\n");
-#endif
-			rstamps[k] = stamp;
-			if (changed && r->var >= 0) {
-				params->cmask |= (1 << r->var);
-				vstamps[r->var] = stamp;
-				again = 1;
+			if (hw_is_interval(r->var)) {
+				trace_hw_interval_param(substream, r->var,
+					k + 1, &old_interval,
+					hw_param_interval(params, r->var));
 			}
-			if (changed < 0)
-				return changed;
-			stamp++;
+
+			params->cmask |= (1 << r->var);
+			vstamps[r->var] = stamp;
+			again = true;
 		}
-	} while (again);
+
+		rstamps[k] = stamp++;
+	}
+
+	/* Iterate to evaluate all rules till no parameters are changed. */
+	if (again)
+		goto retry;
+
+	return 0;
+}
+
+static int fixup_unreferenced_params(struct snd_pcm_substream *substream,
+				     struct snd_pcm_hw_params *params)
+{
+	const struct snd_interval *i;
+	const struct snd_mask *m;
+	int err;
+
 	if (!params->msbits) {
-		i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
+		i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
 		if (snd_interval_single(i))
 			params->msbits = snd_interval_value(i);
 	}
 
 	if (!params->rate_den) {
-		i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+		i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
 		if (snd_interval_single(i)) {
 			params->rate_num = snd_interval_value(i);
 			params->rate_den = 1;
 		}
 	}
 
-	hw = &substream->runtime->hw;
+	if (!params->fifo_size) {
+		m = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
+		i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+		if (snd_mask_single(m) && snd_interval_single(i)) {
+			err = substream->ops->ioctl(substream,
+					SNDRV_PCM_IOCTL1_FIFO_SIZE, params);
+			if (err < 0)
+				return err;
+		}
+	}
+
 	if (!params->info) {
-		params->info = hw->info & ~(SNDRV_PCM_INFO_FIFO_IN_FRAMES |
-					    SNDRV_PCM_INFO_DRAIN_TRIGGER);
+		params->info = substream->runtime->hw.info;
+		params->info &= ~(SNDRV_PCM_INFO_FIFO_IN_FRAMES |
+				  SNDRV_PCM_INFO_DRAIN_TRIGGER);
 		if (!hw_support_mmap(substream))
 			params->info &= ~(SNDRV_PCM_INFO_MMAP |
 					  SNDRV_PCM_INFO_MMAP_VALID);
 	}
-	if (!params->fifo_size) {
-		m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
-		i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
-		if (snd_mask_min(m) == snd_mask_max(m) &&
-                    snd_interval_min(i) == snd_interval_max(i)) {
-			changed = substream->ops->ioctl(substream,
-					SNDRV_PCM_IOCTL1_FIFO_SIZE, params);
-			if (changed < 0)
-				return changed;
-		}
+
+	return 0;
+}
+
+int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
+		      struct snd_pcm_hw_params *params)
+{
+	int err;
+
+	params->info = 0;
+	params->fifo_size = 0;
+	if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_SAMPLE_BITS))
+		params->msbits = 0;
+	if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_RATE)) {
+		params->rate_num = 0;
+		params->rate_den = 0;
 	}
+
+	err = constrain_mask_params(substream, params);
+	if (err < 0)
+		return err;
+
+	err = constrain_interval_params(substream, params);
+	if (err < 0)
+		return err;
+
+	err = constrain_params_by_rules(substream, params);
+	if (err < 0)
+		return err;
+
 	params->rmask = 0;
+
 	return 0;
 }
-
 EXPORT_SYMBOL(snd_pcm_hw_refine);
 
 static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream,
@@ -467,11 +524,16 @@ static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream,
 		return PTR_ERR(params);
 
 	err = snd_pcm_hw_refine(substream, params);
-	if (copy_to_user(_params, params, sizeof(*params))) {
-		if (!err)
-			err = -EFAULT;
-	}
+	if (err < 0)
+		goto end;
+
+	err = fixup_unreferenced_params(substream, params);
+	if (err < 0)
+		goto end;
 
+	if (copy_to_user(_params, params, sizeof(*params)))
+		err = -EFAULT;
+end:
 	kfree(params);
 	return err;
 }
@@ -509,6 +571,70 @@ static inline void snd_pcm_timer_notify(struct snd_pcm_substream *substream,
 #endif
 }
 
+/**
+ * snd_pcm_hw_param_choose - choose a configuration defined by @params
+ * @pcm: PCM instance
+ * @params: the hw_params instance
+ *
+ * Choose one configuration from configuration space defined by @params.
+ * The configuration chosen is that obtained fixing in this order:
+ * first access, first format, first subformat, min channels,
+ * min rate, min period time, max buffer size, min tick time
+ *
+ * Return: Zero if successful, or a negative error code on failure.
+ */
+static int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm,
+				    struct snd_pcm_hw_params *params)
+{
+	static const int vars[] = {
+		SNDRV_PCM_HW_PARAM_ACCESS,
+		SNDRV_PCM_HW_PARAM_FORMAT,
+		SNDRV_PCM_HW_PARAM_SUBFORMAT,
+		SNDRV_PCM_HW_PARAM_CHANNELS,
+		SNDRV_PCM_HW_PARAM_RATE,
+		SNDRV_PCM_HW_PARAM_PERIOD_TIME,
+		SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+		SNDRV_PCM_HW_PARAM_TICK_TIME,
+		-1
+	};
+	const int *v;
+	struct snd_mask old_mask;
+	struct snd_interval old_interval;
+	int changed;
+
+	for (v = vars; *v != -1; v++) {
+		/* Keep old parameter to trace. */
+		if (trace_hw_mask_param_enabled()) {
+			if (hw_is_mask(*v))
+				old_mask = *hw_param_mask(params, *v);
+		}
+		if (trace_hw_interval_param_enabled()) {
+			if (hw_is_interval(*v))
+				old_interval = *hw_param_interval(params, *v);
+		}
+		if (*v != SNDRV_PCM_HW_PARAM_BUFFER_SIZE)
+			changed = snd_pcm_hw_param_first(pcm, params, *v, NULL);
+		else
+			changed = snd_pcm_hw_param_last(pcm, params, *v, NULL);
+		if (snd_BUG_ON(changed < 0))
+			return changed;
+		if (changed == 0)
+			continue;
+
+		/* Trace the changed parameter. */
+		if (hw_is_mask(*v)) {
+			trace_hw_mask_param(pcm, *v, 0, &old_mask,
+					    hw_param_mask(params, *v));
+		}
+		if (hw_is_interval(*v)) {
+			trace_hw_interval_param(pcm, *v, 0, &old_interval,
+						hw_param_interval(params, *v));
+		}
+	}
+
+	return 0;
+}
+
 static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *params)
 {
@@ -546,6 +672,10 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
 	if (err < 0)
 		goto _error;
 
+	err = fixup_unreferenced_params(substream, params);
+	if (err < 0)
+		goto _error;
+
 	if (substream->ops->hw_params != NULL) {
 		err = substream->ops->hw_params(substream, params);
 		if (err < 0)
@@ -621,11 +751,12 @@ static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream,
 		return PTR_ERR(params);
 
 	err = snd_pcm_hw_params(substream, params);
-	if (copy_to_user(_params, params, sizeof(*params))) {
-		if (!err)
-			err = -EFAULT;
-	}
+	if (err < 0)
+		goto end;
 
+	if (copy_to_user(_params, params, sizeof(*params)))
+		err = -EFAULT;
+end:
 	kfree(params);
 	return err;
 }
@@ -1081,6 +1212,7 @@ static const struct action_ops snd_pcm_action_start = {
  * @substream: the PCM substream instance
  *
  * Return: Zero if successful, or a negative error code.
+ * The stream lock must be acquired before calling this function.
  */
 int snd_pcm_start(struct snd_pcm_substream *substream)
 {
@@ -1088,6 +1220,13 @@ int snd_pcm_start(struct snd_pcm_substream *substream)
 			      SNDRV_PCM_STATE_RUNNING);
 }
 
+/* take the stream lock and start the streams */
+static int snd_pcm_start_lock_irq(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_action_lock_irq(&snd_pcm_action_start, substream,
+				       SNDRV_PCM_STATE_RUNNING);
+}
+
 /*
  * stop callbacks
  */
@@ -1139,7 +1278,6 @@ int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t state)
 {
 	return snd_pcm_action(&snd_pcm_action_stop, substream, state);
 }
-
 EXPORT_SYMBOL(snd_pcm_stop);
 
 /**
@@ -1314,7 +1452,6 @@ int snd_pcm_suspend(struct snd_pcm_substream *substream)
 	snd_pcm_stream_unlock_irqrestore(substream, flags);
 	return err;
 }
-
 EXPORT_SYMBOL(snd_pcm_suspend);
 
 /**
@@ -1346,7 +1483,6 @@ int snd_pcm_suspend_all(struct snd_pcm *pcm)
 	}
 	return 0;
 }
-
 EXPORT_SYMBOL(snd_pcm_suspend_all);
 
 /* resume */
@@ -1397,14 +1533,7 @@ static const struct action_ops snd_pcm_action_resume = {
 
 static int snd_pcm_resume(struct snd_pcm_substream *substream)
 {
-	struct snd_card *card = substream->pcm->card;
-	int res;
-
-	snd_power_lock(card);
-	if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0)
-		res = snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0);
-	snd_power_unlock(card);
-	return res;
+	return snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0);
 }
 
 #else
@@ -1423,17 +1552,9 @@ static int snd_pcm_resume(struct snd_pcm_substream *substream)
  */
 static int snd_pcm_xrun(struct snd_pcm_substream *substream)
 {
-	struct snd_card *card = substream->pcm->card;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	int result;
 
-	snd_power_lock(card);
-	if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
-		result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
-		if (result < 0)
-			goto _unlock;
-	}
-
 	snd_pcm_stream_lock_irq(substream);
 	switch (runtime->status->state) {
 	case SNDRV_PCM_STATE_XRUN:
@@ -1446,8 +1567,6 @@ static int snd_pcm_xrun(struct snd_pcm_substream *substream)
 		result = -EBADFD;
 	}
 	snd_pcm_stream_unlock_irq(substream);
- _unlock:
-	snd_power_unlock(card);
 	return result;
 }
 
@@ -1551,8 +1670,6 @@ static const struct action_ops snd_pcm_action_prepare = {
 static int snd_pcm_prepare(struct snd_pcm_substream *substream,
 			   struct file *file)
 {
-	int res;
-	struct snd_card *card = substream->pcm->card;
 	int f_flags;
 
 	if (file)
@@ -1560,12 +1677,19 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream,
 	else
 		f_flags = substream->f_flags;
 
-	snd_power_lock(card);
-	if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0)
-		res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare,
-					       substream, f_flags);
-	snd_power_unlock(card);
-	return res;
+	snd_pcm_stream_lock_irq(substream);
+	switch (substream->runtime->status->state) {
+	case SNDRV_PCM_STATE_PAUSED:
+		snd_pcm_pause(substream, 0);
+		/* fallthru */
+	case SNDRV_PCM_STATE_SUSPENDED:
+		snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
+		break;
+	}
+	snd_pcm_stream_unlock_irq(substream);
+
+	return snd_pcm_action_nonatomic(&snd_pcm_action_prepare,
+					substream, f_flags);
 }
 
 /*
@@ -1662,15 +1786,6 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
 	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
 		return -EBADFD;
 
-	snd_power_lock(card);
-	if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
-		result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
-		if (result < 0) {
-			snd_power_unlock(card);
-			return result;
-		}
-	}
-
 	if (file) {
 		if (file->f_flags & O_NONBLOCK)
 			nonblock = 1;
@@ -1753,7 +1868,6 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
  unlock:
 	snd_pcm_stream_unlock_irq(substream);
 	up_read(&snd_pcm_link_rwsem);
-	snd_power_unlock(card);
 
 	return result;
 }
@@ -1773,8 +1887,7 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream)
 	runtime = substream->runtime;
 
 	if (runtime->status->state == SNDRV_PCM_STATE_OPEN ||
-	    runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED ||
-	    runtime->status->state == SNDRV_PCM_STATE_SUSPENDED)
+	    runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED)
 		return -EBADFD;
 
 	snd_pcm_stream_lock_irq(substream);
@@ -1940,7 +2053,8 @@ static int snd_pcm_hw_rule_format(struct snd_pcm_hw_params *params,
 				  struct snd_pcm_hw_rule *rule)
 {
 	unsigned int k;
-	struct snd_interval *i = hw_param_interval(params, rule->deps[0]);
+	const struct snd_interval *i =
+				hw_param_interval_c(params, rule->deps[0]);
 	struct snd_mask m;
 	struct snd_mask *mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
 	snd_mask_any(&m);
@@ -1986,8 +2100,10 @@ static int snd_pcm_hw_rule_sample_bits(struct snd_pcm_hw_params *params,
 #error "Change this table"
 #endif
 
-static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100,
-                                 48000, 64000, 88200, 96000, 176400, 192000 };
+static const unsigned int rates[] = {
+	5512, 8000, 11025, 16000, 22050, 32000, 44100,
+	48000, 64000, 88200, 96000, 176400, 192000
+};
 
 const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = {
 	.count = ARRAY_SIZE(rates),
@@ -2250,7 +2366,6 @@ void snd_pcm_release_substream(struct snd_pcm_substream *substream)
 	}
 	snd_pcm_detach_substream(substream);
 }
-
 EXPORT_SYMBOL(snd_pcm_release_substream);
 
 int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
@@ -2292,7 +2407,6 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
 	snd_pcm_release_substream(substream);
 	return err;
 }
-
 EXPORT_SYMBOL(snd_pcm_open_substream);
 
 static int snd_pcm_open_file(struct file *file,
@@ -2428,50 +2542,84 @@ static int snd_pcm_release(struct inode *inode, struct file *file)
 	return 0;
 }
 
-static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *substream,
-						 snd_pcm_uframes_t frames)
+/* check and update PCM state; return 0 or a negative error
+ * call this inside PCM lock
+ */
+static int do_pcm_hwsync(struct snd_pcm_substream *substream)
 {
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	snd_pcm_sframes_t appl_ptr;
-	snd_pcm_sframes_t ret;
-	snd_pcm_sframes_t hw_avail;
-
-	if (frames == 0)
-		return 0;
-
-	snd_pcm_stream_lock_irq(substream);
-	switch (runtime->status->state) {
-	case SNDRV_PCM_STATE_PREPARED:
-		break;
+	switch (substream->runtime->status->state) {
 	case SNDRV_PCM_STATE_DRAINING:
-	case SNDRV_PCM_STATE_RUNNING:
-		if (snd_pcm_update_hw_ptr(substream) >= 0)
-			break;
+		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+			return -EBADFD;
 		/* Fall through */
-	case SNDRV_PCM_STATE_XRUN:
-		ret = -EPIPE;
-		goto __end;
+	case SNDRV_PCM_STATE_RUNNING:
+		return snd_pcm_update_hw_ptr(substream);
+	case SNDRV_PCM_STATE_PREPARED:
+	case SNDRV_PCM_STATE_PAUSED:
+		return 0;
 	case SNDRV_PCM_STATE_SUSPENDED:
-		ret = -ESTRPIPE;
-		goto __end;
+		return -ESTRPIPE;
+	case SNDRV_PCM_STATE_XRUN:
+		return -EPIPE;
 	default:
-		ret = -EBADFD;
-		goto __end;
+		return -EBADFD;
 	}
+}
 
-	hw_avail = snd_pcm_playback_hw_avail(runtime);
-	if (hw_avail <= 0) {
-		ret = 0;
-		goto __end;
-	}
-	if (frames > (snd_pcm_uframes_t)hw_avail)
-		frames = hw_avail;
+/* increase the appl_ptr; returns the processed frames or a negative error */
+static snd_pcm_sframes_t forward_appl_ptr(struct snd_pcm_substream *substream,
+					  snd_pcm_uframes_t frames,
+					   snd_pcm_sframes_t avail)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	snd_pcm_sframes_t appl_ptr;
+	int ret;
+
+	if (avail <= 0)
+		return 0;
+	if (frames > (snd_pcm_uframes_t)avail)
+		frames = avail;
+	appl_ptr = runtime->control->appl_ptr + frames;
+	if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary)
+		appl_ptr -= runtime->boundary;
+	ret = pcm_lib_apply_appl_ptr(substream, appl_ptr);
+	return ret < 0 ? ret : frames;
+}
+
+/* decrease the appl_ptr; returns the processed frames or a negative error */
+static snd_pcm_sframes_t rewind_appl_ptr(struct snd_pcm_substream *substream,
+					 snd_pcm_uframes_t frames,
+					 snd_pcm_sframes_t avail)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	snd_pcm_sframes_t appl_ptr;
+	int ret;
+
+	if (avail <= 0)
+		return 0;
+	if (frames > (snd_pcm_uframes_t)avail)
+		frames = avail;
 	appl_ptr = runtime->control->appl_ptr - frames;
 	if (appl_ptr < 0)
 		appl_ptr += runtime->boundary;
-	runtime->control->appl_ptr = appl_ptr;
-	ret = frames;
- __end:
+	ret = pcm_lib_apply_appl_ptr(substream, appl_ptr);
+	return ret < 0 ? ret : frames;
+}
+
+static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *substream,
+						 snd_pcm_uframes_t frames)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	snd_pcm_sframes_t ret;
+
+	if (frames == 0)
+		return 0;
+
+	snd_pcm_stream_lock_irq(substream);
+	ret = do_pcm_hwsync(substream);
+	if (!ret)
+		ret = rewind_appl_ptr(substream, frames,
+				      snd_pcm_playback_hw_avail(runtime));
 	snd_pcm_stream_unlock_irq(substream);
 	return ret;
 }
@@ -2480,46 +2628,16 @@ static snd_pcm_sframes_t snd_pcm_capture_rewind(struct snd_pcm_substream *substr
 						snd_pcm_uframes_t frames)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	snd_pcm_sframes_t appl_ptr;
 	snd_pcm_sframes_t ret;
-	snd_pcm_sframes_t hw_avail;
 
 	if (frames == 0)
 		return 0;
 
 	snd_pcm_stream_lock_irq(substream);
-	switch (runtime->status->state) {
-	case SNDRV_PCM_STATE_PREPARED:
-	case SNDRV_PCM_STATE_DRAINING:
-		break;
-	case SNDRV_PCM_STATE_RUNNING:
-		if (snd_pcm_update_hw_ptr(substream) >= 0)
-			break;
-		/* Fall through */
-	case SNDRV_PCM_STATE_XRUN:
-		ret = -EPIPE;
-		goto __end;
-	case SNDRV_PCM_STATE_SUSPENDED:
-		ret = -ESTRPIPE;
-		goto __end;
-	default:
-		ret = -EBADFD;
-		goto __end;
-	}
-
-	hw_avail = snd_pcm_capture_hw_avail(runtime);
-	if (hw_avail <= 0) {
-		ret = 0;
-		goto __end;
-	}
-	if (frames > (snd_pcm_uframes_t)hw_avail)
-		frames = hw_avail;
-	appl_ptr = runtime->control->appl_ptr - frames;
-	if (appl_ptr < 0)
-		appl_ptr += runtime->boundary;
-	runtime->control->appl_ptr = appl_ptr;
-	ret = frames;
- __end:
+	ret = do_pcm_hwsync(substream);
+	if (!ret)
+		ret = rewind_appl_ptr(substream, frames,
+				      snd_pcm_capture_hw_avail(runtime));
 	snd_pcm_stream_unlock_irq(substream);
 	return ret;
 }
@@ -2528,47 +2646,16 @@ static snd_pcm_sframes_t snd_pcm_playback_forward(struct snd_pcm_substream *subs
 						  snd_pcm_uframes_t frames)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	snd_pcm_sframes_t appl_ptr;
 	snd_pcm_sframes_t ret;
-	snd_pcm_sframes_t avail;
 
 	if (frames == 0)
 		return 0;
 
 	snd_pcm_stream_lock_irq(substream);
-	switch (runtime->status->state) {
-	case SNDRV_PCM_STATE_PREPARED:
-	case SNDRV_PCM_STATE_PAUSED:
-		break;
-	case SNDRV_PCM_STATE_DRAINING:
-	case SNDRV_PCM_STATE_RUNNING:
-		if (snd_pcm_update_hw_ptr(substream) >= 0)
-			break;
-		/* Fall through */
-	case SNDRV_PCM_STATE_XRUN:
-		ret = -EPIPE;
-		goto __end;
-	case SNDRV_PCM_STATE_SUSPENDED:
-		ret = -ESTRPIPE;
-		goto __end;
-	default:
-		ret = -EBADFD;
-		goto __end;
-	}
-
-	avail = snd_pcm_playback_avail(runtime);
-	if (avail <= 0) {
-		ret = 0;
-		goto __end;
-	}
-	if (frames > (snd_pcm_uframes_t)avail)
-		frames = avail;
-	appl_ptr = runtime->control->appl_ptr + frames;
-	if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary)
-		appl_ptr -= runtime->boundary;
-	runtime->control->appl_ptr = appl_ptr;
-	ret = frames;
- __end:
+	ret = do_pcm_hwsync(substream);
+	if (!ret)
+		ret = forward_appl_ptr(substream, frames,
+				       snd_pcm_playback_avail(runtime));
 	snd_pcm_stream_unlock_irq(substream);
 	return ret;
 }
@@ -2577,123 +2664,47 @@ static snd_pcm_sframes_t snd_pcm_capture_forward(struct snd_pcm_substream *subst
 						 snd_pcm_uframes_t frames)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	snd_pcm_sframes_t appl_ptr;
 	snd_pcm_sframes_t ret;
-	snd_pcm_sframes_t avail;
 
 	if (frames == 0)
 		return 0;
 
 	snd_pcm_stream_lock_irq(substream);
-	switch (runtime->status->state) {
-	case SNDRV_PCM_STATE_PREPARED:
-	case SNDRV_PCM_STATE_DRAINING:
-	case SNDRV_PCM_STATE_PAUSED:
-		break;
-	case SNDRV_PCM_STATE_RUNNING:
-		if (snd_pcm_update_hw_ptr(substream) >= 0)
-			break;
-		/* Fall through */
-	case SNDRV_PCM_STATE_XRUN:
-		ret = -EPIPE;
-		goto __end;
-	case SNDRV_PCM_STATE_SUSPENDED:
-		ret = -ESTRPIPE;
-		goto __end;
-	default:
-		ret = -EBADFD;
-		goto __end;
-	}
-
-	avail = snd_pcm_capture_avail(runtime);
-	if (avail <= 0) {
-		ret = 0;
-		goto __end;
-	}
-	if (frames > (snd_pcm_uframes_t)avail)
-		frames = avail;
-	appl_ptr = runtime->control->appl_ptr + frames;
-	if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary)
-		appl_ptr -= runtime->boundary;
-	runtime->control->appl_ptr = appl_ptr;
-	ret = frames;
- __end:
+	ret = do_pcm_hwsync(substream);
+	if (!ret)
+		ret = forward_appl_ptr(substream, frames,
+				       snd_pcm_capture_avail(runtime));
 	snd_pcm_stream_unlock_irq(substream);
 	return ret;
 }
 
 static int snd_pcm_hwsync(struct snd_pcm_substream *substream)
 {
-	struct snd_pcm_runtime *runtime = substream->runtime;
 	int err;
 
 	snd_pcm_stream_lock_irq(substream);
-	switch (runtime->status->state) {
-	case SNDRV_PCM_STATE_DRAINING:
-		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-			goto __badfd;
-		/* Fall through */
-	case SNDRV_PCM_STATE_RUNNING:
-		if ((err = snd_pcm_update_hw_ptr(substream)) < 0)
-			break;
-		/* Fall through */
-	case SNDRV_PCM_STATE_PREPARED:
-		err = 0;
-		break;
-	case SNDRV_PCM_STATE_SUSPENDED:
-		err = -ESTRPIPE;
-		break;
-	case SNDRV_PCM_STATE_XRUN:
-		err = -EPIPE;
-		break;
-	default:
-	      __badfd:
-		err = -EBADFD;
-		break;
-	}
+	err = do_pcm_hwsync(substream);
 	snd_pcm_stream_unlock_irq(substream);
 	return err;
 }
 		
-static int snd_pcm_delay(struct snd_pcm_substream *substream,
-			 snd_pcm_sframes_t __user *res)
+static snd_pcm_sframes_t snd_pcm_delay(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	int err;
 	snd_pcm_sframes_t n = 0;
 
 	snd_pcm_stream_lock_irq(substream);
-	switch (runtime->status->state) {
-	case SNDRV_PCM_STATE_DRAINING:
-		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-			goto __badfd;
-		/* Fall through */
-	case SNDRV_PCM_STATE_RUNNING:
-		if ((err = snd_pcm_update_hw_ptr(substream)) < 0)
-			break;
-		/* Fall through */
-	case SNDRV_PCM_STATE_PREPARED:
-	case SNDRV_PCM_STATE_SUSPENDED:
-		err = 0;
+	err = do_pcm_hwsync(substream);
+	if (!err) {
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 			n = snd_pcm_playback_hw_avail(runtime);
 		else
 			n = snd_pcm_capture_avail(runtime);
 		n += runtime->delay;
-		break;
-	case SNDRV_PCM_STATE_XRUN:
-		err = -EPIPE;
-		break;
-	default:
-	      __badfd:
-		err = -EBADFD;
-		break;
 	}
 	snd_pcm_stream_unlock_irq(substream);
-	if (!err)
-		if (put_user(n, res))
-			err = -EFAULT;
-	return err;
+	return err < 0 ? err : n;
 }
 		
 static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,
@@ -2718,10 +2729,16 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,
 			return err;
 	}
 	snd_pcm_stream_lock_irq(substream);
-	if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL))
-		control->appl_ptr = sync_ptr.c.control.appl_ptr;
-	else
+	if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) {
+		err = pcm_lib_apply_appl_ptr(substream,
+					     sync_ptr.c.control.appl_ptr);
+		if (err < 0) {
+			snd_pcm_stream_unlock_irq(substream);
+			return err;
+		}
+	} else {
 		sync_ptr.c.control.appl_ptr = control->appl_ptr;
+	}
 	if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
 		control->avail_min = sync_ptr.c.control.avail_min;
 	else
@@ -2749,10 +2766,12 @@ static int snd_pcm_tstamp(struct snd_pcm_substream *substream, int __user *_arg)
 	return 0;
 }
 		
-static int snd_pcm_common_ioctl1(struct file *file,
+static int snd_pcm_common_ioctl(struct file *file,
 				 struct snd_pcm_substream *substream,
 				 unsigned int cmd, void __user *arg)
 {
+	struct snd_pcm_file *pcm_file = file->private_data;
+
 	switch (cmd) {
 	case SNDRV_PCM_IOCTL_PVERSION:
 		return put_user(SNDRV_PCM_VERSION, (int __user *)arg) ? -EFAULT : 0;
@@ -2762,6 +2781,11 @@ static int snd_pcm_common_ioctl1(struct file *file,
 		return 0;
 	case SNDRV_PCM_IOCTL_TTSTAMP:
 		return snd_pcm_tstamp(substream, arg);
+	case SNDRV_PCM_IOCTL_USER_PVERSION:
+		if (get_user(pcm_file->user_pversion,
+			     (unsigned int __user *)arg))
+			return -EFAULT;
+		return 0;
 	case SNDRV_PCM_IOCTL_HW_REFINE:
 		return snd_pcm_hw_refine_user(substream, arg);
 	case SNDRV_PCM_IOCTL_HW_PARAMS:
@@ -2781,7 +2805,7 @@ static int snd_pcm_common_ioctl1(struct file *file,
 	case SNDRV_PCM_IOCTL_RESET:
 		return snd_pcm_reset(substream);
 	case SNDRV_PCM_IOCTL_START:
-		return snd_pcm_action_lock_irq(&snd_pcm_action_start, substream, SNDRV_PCM_STATE_RUNNING);
+		return snd_pcm_start_lock_irq(substream);
 	case SNDRV_PCM_IOCTL_LINK:
 		return snd_pcm_link(substream, (int)(unsigned long) arg);
 	case SNDRV_PCM_IOCTL_UNLINK:
@@ -2793,7 +2817,16 @@ static int snd_pcm_common_ioctl1(struct file *file,
 	case SNDRV_PCM_IOCTL_HWSYNC:
 		return snd_pcm_hwsync(substream);
 	case SNDRV_PCM_IOCTL_DELAY:
-		return snd_pcm_delay(substream, arg);
+	{
+		snd_pcm_sframes_t delay = snd_pcm_delay(substream);
+		snd_pcm_sframes_t __user *res = arg;
+
+		if (delay < 0)
+			return delay;
+		if (put_user(delay, res))
+			return -EFAULT;
+		return 0;
+	}
 	case SNDRV_PCM_IOCTL_SYNC_PTR:
 		return snd_pcm_sync_ptr(substream, arg);
 #ifdef CONFIG_SND_SUPPORT_OLD_API
@@ -2807,23 +2840,34 @@ static int snd_pcm_common_ioctl1(struct file *file,
 	case SNDRV_PCM_IOCTL_DROP:
 		return snd_pcm_drop(substream);
 	case SNDRV_PCM_IOCTL_PAUSE:
-	{
-		int res;
-		snd_pcm_stream_lock_irq(substream);
-		res = snd_pcm_pause(substream, (int)(unsigned long)arg);
-		snd_pcm_stream_unlock_irq(substream);
-		return res;
-	}
+		return snd_pcm_action_lock_irq(&snd_pcm_action_pause,
+					       substream,
+					       (int)(unsigned long)arg);
 	}
 	pcm_dbg(substream->pcm, "unknown ioctl = 0x%x\n", cmd);
 	return -ENOTTY;
 }
 
+static int snd_pcm_common_ioctl1(struct file *file,
+				 struct snd_pcm_substream *substream,
+				 unsigned int cmd, void __user *arg)
+{
+	struct snd_card *card = substream->pcm->card;
+	int res;
+
+	snd_power_lock(card);
+	res = snd_power_wait(card, SNDRV_CTL_POWER_D0);
+	if (res >= 0)
+		res = snd_pcm_common_ioctl(file, substream, cmd, arg);
+	snd_power_unlock(card);
+	return res;
+}
+
 static int snd_pcm_playback_ioctl1(struct file *file,
 				   struct snd_pcm_substream *substream,
 				   unsigned int cmd, void __user *arg)
 {
-	if (snd_BUG_ON(!substream))
+	if (PCM_RUNTIME_CHECK(substream))
 		return -ENXIO;
 	if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_PLAYBACK))
 		return -EINVAL;
@@ -2903,7 +2947,7 @@ static int snd_pcm_capture_ioctl1(struct file *file,
 				  struct snd_pcm_substream *substream,
 				  unsigned int cmd, void __user *arg)
 {
-	if (snd_BUG_ON(!substream))
+	if (PCM_RUNTIME_CHECK(substream))
 		return -ENXIO;
 	if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_CAPTURE))
 		return -EINVAL;
@@ -3007,30 +3051,55 @@ static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd,
 				      (void __user *)arg);
 }
 
+/**
+ * snd_pcm_kernel_ioctl - Execute PCM ioctl in the kernel-space
+ * @substream: PCM substream
+ * @cmd: IOCTL cmd
+ * @arg: IOCTL argument
+ *
+ * The function is provided primarily for OSS layer and USB gadget drivers,
+ * and it allows only the limited set of ioctls (hw_params, sw_params,
+ * prepare, start, drain, drop, forward).
+ */
 int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream,
 			 unsigned int cmd, void *arg)
 {
-	mm_segment_t fs;
-	int result;
+	snd_pcm_uframes_t *frames = arg;
+	snd_pcm_sframes_t result;
 	
-	fs = snd_enter_user();
-	switch (substream->stream) {
-	case SNDRV_PCM_STREAM_PLAYBACK:
-		result = snd_pcm_playback_ioctl1(NULL, substream, cmd,
-						 (void __user *)arg);
-		break;
-	case SNDRV_PCM_STREAM_CAPTURE:
-		result = snd_pcm_capture_ioctl1(NULL, substream, cmd,
-						(void __user *)arg);
-		break;
+	switch (cmd) {
+	case SNDRV_PCM_IOCTL_FORWARD:
+	{
+		/* provided only for OSS; capture-only and no value returned */
+		if (substream->stream != SNDRV_PCM_STREAM_CAPTURE)
+			return -EINVAL;
+		result = snd_pcm_capture_forward(substream, *frames);
+		return result < 0 ? result : 0;
+	}
+	case SNDRV_PCM_IOCTL_HW_PARAMS:
+		return snd_pcm_hw_params(substream, arg);
+	case SNDRV_PCM_IOCTL_SW_PARAMS:
+		return snd_pcm_sw_params(substream, arg);
+	case SNDRV_PCM_IOCTL_PREPARE:
+		return snd_pcm_prepare(substream, NULL);
+	case SNDRV_PCM_IOCTL_START:
+		return snd_pcm_start_lock_irq(substream);
+	case SNDRV_PCM_IOCTL_DRAIN:
+		return snd_pcm_drain(substream, NULL);
+	case SNDRV_PCM_IOCTL_DROP:
+		return snd_pcm_drop(substream);
+	case SNDRV_PCM_IOCTL_DELAY:
+	{
+		result = snd_pcm_delay(substream);
+		if (result < 0)
+			return result;
+		*frames = result;
+		return 0;
+	}
 	default:
-		result = -EINVAL;
-		break;
+		return -EINVAL;
 	}
-	snd_leave_user(fs);
-	return result;
 }
-
 EXPORT_SYMBOL(snd_pcm_kernel_ioctl);
 
 static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count,
@@ -3314,10 +3383,41 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file
 	area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
 	return 0;
 }
+
+static bool pcm_status_mmap_allowed(struct snd_pcm_file *pcm_file)
+{
+	if (pcm_file->no_compat_mmap)
+		return false;
+	/* See pcm_control_mmap_allowed() below.
+	 * Since older alsa-lib requires both status and control mmaps to be
+	 * coupled, we have to disable the status mmap for old alsa-lib, too.
+	 */
+	if (pcm_file->user_pversion < SNDRV_PROTOCOL_VERSION(2, 0, 14) &&
+	    (pcm_file->substream->runtime->hw.info & SNDRV_PCM_INFO_SYNC_APPLPTR))
+		return false;
+	return true;
+}
+
+static bool pcm_control_mmap_allowed(struct snd_pcm_file *pcm_file)
+{
+	if (pcm_file->no_compat_mmap)
+		return false;
+	/* Disallow the control mmap when SYNC_APPLPTR flag is set;
+	 * it enforces the user-space to fall back to snd_pcm_sync_ptr(),
+	 * thus it effectively assures the manual update of appl_ptr.
+	 */
+	if (pcm_file->substream->runtime->hw.info & SNDRV_PCM_INFO_SYNC_APPLPTR)
+		return false;
+	return true;
+}
+
 #else /* ! coherent mmap */
 /*
  * don't support mmap for status and control records.
  */
+#define pcm_status_mmap_allowed(pcm_file)	false
+#define pcm_control_mmap_allowed(pcm_file)	false
+
 static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file,
 			       struct vm_area_struct *area)
 {
@@ -3437,7 +3537,6 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
 	area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
 	return vm_iomap_memory(area, runtime->dma_addr, runtime->dma_bytes);
 }
-
 EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem);
 #endif /* SNDRV_PCM_INFO_MMAP */
 
@@ -3486,7 +3585,6 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file,
 		atomic_inc(&substream->mmap_count);
 	return err;
 }
-
 EXPORT_SYMBOL(snd_pcm_mmap_data);
 
 static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)
@@ -3503,11 +3601,11 @@ static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)
 	offset = area->vm_pgoff << PAGE_SHIFT;
 	switch (offset) {
 	case SNDRV_PCM_MMAP_OFFSET_STATUS:
-		if (pcm_file->no_compat_mmap)
+		if (!pcm_status_mmap_allowed(pcm_file))
 			return -ENXIO;
 		return snd_pcm_mmap_status(substream, file, area);
 	case SNDRV_PCM_MMAP_OFFSET_CONTROL:
-		if (pcm_file->no_compat_mmap)
+		if (!pcm_control_mmap_allowed(pcm_file))
 			return -ENXIO;
 		return snd_pcm_mmap_control(substream, file, area);
 	default:
@@ -3603,12 +3701,17 @@ static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,
 	}
 	snd_pcm_hw_convert_from_old_params(params, oparams);
 	err = snd_pcm_hw_refine(substream, params);
-	snd_pcm_hw_convert_to_old_params(oparams, params);
-	if (copy_to_user(_oparams, oparams, sizeof(*oparams))) {
-		if (!err)
-			err = -EFAULT;
-	}
+	if (err < 0)
+		goto out_old;
 
+	err = fixup_unreferenced_params(substream, params);
+	if (err < 0)
+		goto out_old;
+
+	snd_pcm_hw_convert_to_old_params(oparams, params);
+	if (copy_to_user(_oparams, oparams, sizeof(*oparams)))
+		err = -EFAULT;
+out_old:
 	kfree(oparams);
 out:
 	kfree(params);
@@ -3631,14 +3734,16 @@ static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream,
 		err = PTR_ERR(oparams);
 		goto out;
 	}
+
 	snd_pcm_hw_convert_from_old_params(params, oparams);
 	err = snd_pcm_hw_params(substream, params);
-	snd_pcm_hw_convert_to_old_params(oparams, params);
-	if (copy_to_user(_oparams, oparams, sizeof(*oparams))) {
-		if (!err)
-			err = -EFAULT;
-	}
+	if (err < 0)
+		goto out_old;
 
+	snd_pcm_hw_convert_to_old_params(oparams, params);
+	if (copy_to_user(_oparams, oparams, sizeof(*oparams)))
+		err = -EFAULT;
+out_old:
 	kfree(oparams);
 out:
 	kfree(params);

+ 142 - 0
sound/core/pcm_param_trace.h

@@ -0,0 +1,142 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM snd_pcm
+
+#if !defined(_PCM_PARAMS_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _PCM_PARAMS_TRACE_H
+
+#include <linux/tracepoint.h>
+
+#define HW_PARAM_ENTRY(param) {SNDRV_PCM_HW_PARAM_##param, #param}
+#define hw_param_labels			\
+	HW_PARAM_ENTRY(ACCESS),		\
+	HW_PARAM_ENTRY(FORMAT),		\
+	HW_PARAM_ENTRY(SUBFORMAT),	\
+	HW_PARAM_ENTRY(SAMPLE_BITS),	\
+	HW_PARAM_ENTRY(FRAME_BITS),	\
+	HW_PARAM_ENTRY(CHANNELS),	\
+	HW_PARAM_ENTRY(RATE),		\
+	HW_PARAM_ENTRY(PERIOD_TIME),	\
+	HW_PARAM_ENTRY(PERIOD_SIZE),	\
+	HW_PARAM_ENTRY(PERIOD_BYTES),	\
+	HW_PARAM_ENTRY(PERIODS),	\
+	HW_PARAM_ENTRY(BUFFER_TIME),	\
+	HW_PARAM_ENTRY(BUFFER_SIZE),	\
+	HW_PARAM_ENTRY(BUFFER_BYTES),	\
+	HW_PARAM_ENTRY(TICK_TIME)
+
+TRACE_EVENT(hw_mask_param,
+	TP_PROTO(struct snd_pcm_substream *substream, snd_pcm_hw_param_t type, int index, const struct snd_mask *prev, const struct snd_mask *curr),
+	TP_ARGS(substream, type, index, prev, curr),
+	TP_STRUCT__entry(
+		__field(int, card)
+		__field(int, device)
+		__field(int, subdevice)
+		__field(int, direction)
+		__field(snd_pcm_hw_param_t, type)
+		__field(int, index)
+		__field(int, total)
+		__array(__u32, prev_bits, 8)
+		__array(__u32, curr_bits, 8)
+	),
+	TP_fast_assign(
+		__entry->card = substream->pcm->card->number;
+		__entry->device = substream->pcm->device;
+		__entry->subdevice = substream->number;
+		__entry->direction = substream->stream;
+		__entry->type = type;
+		__entry->index = index;
+		__entry->total = substream->runtime->hw_constraints.rules_num;
+		memcpy(__entry->prev_bits, prev->bits, sizeof(__u32) * 8);
+		memcpy(__entry->curr_bits, curr->bits, sizeof(__u32) * 8);
+	),
+	TP_printk("pcmC%dD%d%s:%d %03d/%03d %s %08x%08x%08x%08x %08x%08x%08x%08x",
+		  __entry->card,
+		  __entry->device,
+		  __entry->direction ? "c" : "p",
+		  __entry->subdevice,
+		  __entry->index,
+		  __entry->total,
+		  __print_symbolic(__entry->type, hw_param_labels),
+		  __entry->prev_bits[3], __entry->prev_bits[2],
+		  __entry->prev_bits[1], __entry->prev_bits[0],
+		  __entry->curr_bits[3], __entry->curr_bits[2],
+		  __entry->curr_bits[1], __entry->curr_bits[0]
+	)
+);
+
+TRACE_EVENT(hw_interval_param,
+	TP_PROTO(struct snd_pcm_substream *substream, snd_pcm_hw_param_t type, int index, const struct snd_interval *prev, const struct snd_interval *curr),
+	TP_ARGS(substream, type, index, prev, curr),
+	TP_STRUCT__entry(
+		__field(int, card)
+		__field(int, device)
+		__field(int, subdevice)
+		__field(int, direction)
+		__field(snd_pcm_hw_param_t, type)
+		__field(int, index)
+		__field(int, total)
+		__field(unsigned int, prev_min)
+		__field(unsigned int, prev_max)
+		__field(unsigned int, prev_openmin)
+		__field(unsigned int, prev_openmax)
+		__field(unsigned int, prev_integer)
+		__field(unsigned int, prev_empty)
+		__field(unsigned int, curr_min)
+		__field(unsigned int, curr_max)
+		__field(unsigned int, curr_openmin)
+		__field(unsigned int, curr_openmax)
+		__field(unsigned int, curr_integer)
+		__field(unsigned int, curr_empty)
+	),
+	TP_fast_assign(
+		__entry->card = substream->pcm->card->number;
+		__entry->device = substream->pcm->device;
+		__entry->subdevice = substream->number;
+		__entry->direction = substream->stream;
+		__entry->type = type;
+		__entry->index = index;
+		__entry->total = substream->runtime->hw_constraints.rules_num;
+		__entry->prev_min = prev->min;
+		__entry->prev_max = prev->max;
+		__entry->prev_openmin = prev->openmin;
+		__entry->prev_openmax = prev->openmax;
+		__entry->prev_integer = prev->integer;
+		__entry->prev_empty = prev->empty;
+		__entry->curr_min = curr->min;
+		__entry->curr_max = curr->max;
+		__entry->curr_openmin = curr->openmin;
+		__entry->curr_openmax = curr->openmax;
+		__entry->curr_integer = curr->integer;
+		__entry->curr_empty = curr->empty;
+	),
+	TP_printk("pcmC%dD%d%s:%d %03d/%03d %s %d %d %s%u %u%s %d %d %s%u %u%s",
+		  __entry->card,
+		  __entry->device,
+		  __entry->direction ? "c" : "p",
+		  __entry->subdevice,
+		  __entry->index,
+		  __entry->total,
+		  __print_symbolic(__entry->type, hw_param_labels),
+		  __entry->prev_empty,
+		  __entry->prev_integer,
+		  __entry->prev_openmin ? "(" : "[",
+		  __entry->prev_min,
+		  __entry->prev_max,
+		  __entry->prev_openmax ? ")" : "]",
+		  __entry->curr_empty,
+		  __entry->curr_integer,
+		  __entry->curr_openmin ? "(" : "[",
+		  __entry->curr_min,
+		  __entry->curr_max,
+		  __entry->curr_openmax ? ")" : "]"
+	)
+);
+
+#endif /* _PCM_PARAMS_TRACE_H */
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE pcm_param_trace
+#include <trace/define_trace.h>

+ 8 - 6
sound/core/pcm_timer.c

@@ -25,6 +25,8 @@
 #include <sound/pcm.h>
 #include <sound/timer.h>
 
+#include "pcm_local.h"
+
 /*
  *  Timer functions
  */
@@ -33,8 +35,8 @@ void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream)
 {
 	unsigned long rate, mult, fsize, l, post;
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	
-        mult = 1000000000;
+
+	mult = 1000000000;
 	rate = runtime->rate;
 	if (snd_BUG_ON(!rate))
 		return;
@@ -65,7 +67,7 @@ void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream)
 static unsigned long snd_pcm_timer_resolution(struct snd_timer * timer)
 {
 	struct snd_pcm_substream *substream;
-	
+
 	substream = timer->private_data;
 	return substream->runtime ? substream->runtime->timer_resolution : 0;
 }
@@ -73,7 +75,7 @@ static unsigned long snd_pcm_timer_resolution(struct snd_timer * timer)
 static int snd_pcm_timer_start(struct snd_timer * timer)
 {
 	struct snd_pcm_substream *substream;
-	
+
 	substream = snd_timer_chip(timer);
 	substream->timer_running = 1;
 	return 0;
@@ -82,7 +84,7 @@ static int snd_pcm_timer_start(struct snd_timer * timer)
 static int snd_pcm_timer_stop(struct snd_timer * timer)
 {
 	struct snd_pcm_substream *substream;
-	
+
 	substream = snd_timer_chip(timer);
 	substream->timer_running = 0;
 	return 0;
@@ -112,7 +114,7 @@ void snd_pcm_timer_init(struct snd_pcm_substream *substream)
 {
 	struct snd_timer_id tid;
 	struct snd_timer *timer;
-	
+
 	tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
 	tid.dev_class = SNDRV_TIMER_CLASS_PCM;
 	tid.card = substream->pcm->card->number;

+ 44 - 6
sound/core/pcm_trace.h

@@ -34,9 +34,9 @@ TRACE_EVENT(hwptr,
 		__entry->old_hw_ptr = (substream)->runtime->status->hw_ptr;
 		__entry->hw_ptr_base = (substream)->runtime->hw_ptr_base;
 	),
-	TP_printk("pcmC%dD%d%c/sub%d: %s: pos=%lu, old=%lu, base=%lu, period=%lu, buf=%lu",
+	TP_printk("pcmC%dD%d%s/sub%d: %s: pos=%lu, old=%lu, base=%lu, period=%lu, buf=%lu",
 		  __entry->card, __entry->device,
-		  __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c',
+		  __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? "p" : "c",
 		  __entry->number,
 		  __entry->in_interrupt ? "IRQ" : "POS",
 		  (unsigned long)__entry->pos,
@@ -69,9 +69,9 @@ TRACE_EVENT(xrun,
 		__entry->old_hw_ptr = (substream)->runtime->status->hw_ptr;
 		__entry->hw_ptr_base = (substream)->runtime->hw_ptr_base;
 	),
-	TP_printk("pcmC%dD%d%c/sub%d: XRUN: old=%lu, base=%lu, period=%lu, buf=%lu",
+	TP_printk("pcmC%dD%d%s/sub%d: XRUN: old=%lu, base=%lu, period=%lu, buf=%lu",
 		  __entry->card, __entry->device,
-		  __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c',
+		  __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? "p" : "c",
 		  __entry->number,
 		  (unsigned long)__entry->old_hw_ptr,
 		  (unsigned long)__entry->hw_ptr_base,
@@ -96,12 +96,50 @@ TRACE_EVENT(hw_ptr_error,
 		__entry->stream = (substream)->stream;
 		__entry->reason = (why);
 	),
-	TP_printk("pcmC%dD%d%c/sub%d: ERROR: %s",
+	TP_printk("pcmC%dD%d%s/sub%d: ERROR: %s",
 		  __entry->card, __entry->device,
-		  __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c',
+		  __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? "p" : "c",
 		  __entry->number, __entry->reason)
 );
 
+TRACE_EVENT(applptr,
+	TP_PROTO(struct snd_pcm_substream *substream, snd_pcm_uframes_t prev, snd_pcm_uframes_t curr),
+	TP_ARGS(substream, prev, curr),
+	TP_STRUCT__entry(
+		__field( unsigned int, card )
+		__field( unsigned int, device )
+		__field( unsigned int, number )
+		__field( unsigned int, stream )
+		__field( snd_pcm_uframes_t, prev )
+		__field( snd_pcm_uframes_t, curr )
+		__field( snd_pcm_uframes_t, avail )
+		__field( snd_pcm_uframes_t, period_size )
+		__field( snd_pcm_uframes_t, buffer_size )
+	),
+	TP_fast_assign(
+		__entry->card = (substream)->pcm->card->number;
+		__entry->device = (substream)->pcm->device;
+		__entry->number = (substream)->number;
+		__entry->stream = (substream)->stream;
+		__entry->prev = (prev);
+		__entry->curr = (curr);
+		__entry->avail = (substream)->stream ? snd_pcm_capture_avail(substream->runtime) : snd_pcm_playback_avail(substream->runtime);
+		__entry->period_size = (substream)->runtime->period_size;
+		__entry->buffer_size = (substream)->runtime->buffer_size;
+	),
+	TP_printk("pcmC%dD%d%s/sub%d: prev=%lu, curr=%lu, avail=%lu, period=%lu, buf=%lu",
+		__entry->card,
+		__entry->device,
+		__entry->stream ? "c" : "p",
+		__entry->number,
+		__entry->prev,
+		__entry->curr,
+		__entry->avail,
+		__entry->period_size,
+		__entry->buffer_size
+	)
+);
+
 #endif /* _PCM_TRACE_H */
 
 /* This part must be outside protection */

+ 2 - 2
sound/core/rawmidi.c

@@ -1610,7 +1610,7 @@ static int snd_rawmidi_dev_free(struct snd_device *device)
 	return snd_rawmidi_free(rmidi);
 }
 
-#if IS_REACHABLE(CONFIG_SND_SEQUENCER)
+#if IS_ENABLED(CONFIG_SND_SEQUENCER)
 static void snd_rawmidi_dev_seq_free(struct snd_seq_device *device)
 {
 	struct snd_rawmidi *rmidi = device->private_data;
@@ -1691,7 +1691,7 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
 		}
 	}
 	rmidi->proc_entry = entry;
-#if IS_REACHABLE(CONFIG_SND_SEQUENCER)
+#if IS_ENABLED(CONFIG_SND_SEQUENCER)
 	if (!rmidi->ops || !rmidi->ops->dev_register) { /* own registration mechanism */
 		if (snd_seq_device_new(rmidi->card, rmidi->device, SNDRV_SEQ_DEV_ID_MIDISYNTH, 0, &rmidi->seq_dev) >= 0) {
 			rmidi->seq_dev->private_data = rmidi;

+ 57 - 11
sound/core/seq/Kconfig

@@ -1,16 +1,62 @@
-# define SND_XXX_SEQ to min(SND_SEQUENCER,SND_XXX)
+config SND_SEQUENCER
+	tristate "Sequencer support"
+	select SND_TIMER
+	select SND_SEQ_DEVICE
+	help
+	  Say Y or M to enable MIDI sequencer and router support.  This
+	  feature allows routing and enqueueing of MIDI events.  Events
+	  can be processed at a given time.
 
-config SND_RAWMIDI_SEQ
-	def_tristate SND_SEQUENCER && SND_RAWMIDI
+	  Many programs require this feature, so you should enable it
+	  unless you know what you're doing.
 
-config SND_OPL3_LIB_SEQ
-	def_tristate SND_SEQUENCER && SND_OPL3_LIB
+if SND_SEQUENCER
 
-config SND_OPL4_LIB_SEQ
-	def_tristate SND_SEQUENCER && SND_OPL4_LIB
+config SND_SEQ_DUMMY
+	tristate "Sequencer dummy client"
+	help
+	  Say Y here to enable the dummy sequencer client.  This client
+	  is a simple MIDI-through client: all normal input events are
+	  redirected to the output port immediately.
 
-config SND_SBAWE_SEQ
-	def_tristate SND_SEQUENCER && SND_SBAWE
+	  You don't need this unless you want to connect many MIDI
+	  devices or applications together.
 
-config SND_EMU10K1_SEQ
-	def_tristate SND_SEQUENCER && SND_EMU10K1
+	  To compile this driver as a module, choose M here: the module
+	  will be called snd-seq-dummy.
+
+config SND_SEQUENCER_OSS
+	tristate "OSS Sequencer API"
+	depends on SND_OSSEMUL
+	select SND_SEQ_MIDI_EVENT
+	help
+	  Say Y here to enable OSS sequencer emulation (both
+	  /dev/sequencer and /dev/music interfaces).
+
+	  Many programs still use the OSS API, so say Y.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called snd-seq-oss.
+
+config SND_SEQ_HRTIMER_DEFAULT
+	bool "Use HR-timer as default sequencer timer"
+	depends on SND_HRTIMER
+	default y
+	help
+	  Say Y here to use the HR-timer backend as the default sequencer
+	  timer.
+
+config SND_SEQ_MIDI_EVENT
+	def_tristate SND_RAWMIDI
+
+config SND_SEQ_MIDI
+	tristate
+	select SND_SEQ_MIDI_EVENT
+
+config SND_SEQ_MIDI_EMUL
+	tristate
+
+config SND_SEQ_VIRMIDI
+	tristate
+
+endif # SND_SEQUENCER

+ 7 - 14
sound/core/seq/Makefile

@@ -3,7 +3,6 @@
 # Copyright (c) 1999 by Jaroslav Kysela <perex@perex.cz>
 #
 
-snd-seq-device-objs := seq_device.o
 snd-seq-objs := seq.o seq_lock.o seq_clientmgr.o seq_memory.o seq_queue.o \
                 seq_fifo.o seq_prioq.o seq_timer.o \
                 seq_system.o seq_ports.o
@@ -14,17 +13,11 @@ snd-seq-midi-event-objs := seq_midi_event.o
 snd-seq-dummy-objs := seq_dummy.o
 snd-seq-virmidi-objs := seq_virmidi.o
 
-obj-$(CONFIG_SND_SEQUENCER) += snd-seq.o snd-seq-device.o
-ifeq ($(CONFIG_SND_SEQUENCER_OSS),y)
-  obj-$(CONFIG_SND_SEQUENCER) += snd-seq-midi-event.o
-  obj-$(CONFIG_SND_SEQUENCER) += oss/
-endif
-obj-$(CONFIG_SND_SEQ_DUMMY) += snd-seq-dummy.o
+obj-$(CONFIG_SND_SEQUENCER) += snd-seq.o
+obj-$(CONFIG_SND_SEQUENCER_OSS) += oss/
 
-# Toplevel Module Dependency
-obj-$(CONFIG_SND_VIRMIDI) += snd-seq-virmidi.o snd-seq-midi-event.o
-obj-$(CONFIG_SND_RAWMIDI_SEQ) += snd-seq-midi.o snd-seq-midi-event.o
-obj-$(CONFIG_SND_OPL3_LIB_SEQ) += snd-seq-midi-event.o snd-seq-midi-emul.o
-obj-$(CONFIG_SND_OPL4_LIB_SEQ) += snd-seq-midi-event.o snd-seq-midi-emul.o
-obj-$(CONFIG_SND_SBAWE_SEQ) += snd-seq-midi-emul.o snd-seq-virmidi.o
-obj-$(CONFIG_SND_EMU10K1_SEQ) += snd-seq-midi-emul.o snd-seq-virmidi.o
+obj-$(CONFIG_SND_SEQ_DUMMY) += snd-seq-dummy.o
+obj-$(CONFIG_SND_SEQ_MIDI) += snd-seq-midi.o
+obj-$(CONFIG_SND_SEQ_MIDI_EMUL) += snd-seq-midi-emul.o
+obj-$(CONFIG_SND_SEQ_MIDI_EVENT) += snd-seq-midi-event.o
+obj-$(CONFIG_SND_SEQ_VIRMIDI) += snd-seq-virmidi.o

+ 1 - 1
sound/core/seq/oss/Makefile

@@ -7,4 +7,4 @@ snd-seq-oss-objs  := seq_oss.o seq_oss_init.o seq_oss_timer.o seq_oss_ioctl.o \
 		     seq_oss_event.o seq_oss_rw.o seq_oss_synth.o \
 		     seq_oss_midi.o seq_oss_readq.o seq_oss_writeq.o
 
-obj-$(CONFIG_SND_SEQUENCER) += snd-seq-oss.o
+obj-$(CONFIG_SND_SEQUENCER_OSS) += snd-seq-oss.o

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

@@ -1668,7 +1668,6 @@ int snd_seq_set_queue_tempo(int client, struct snd_seq_queue_tempo *tempo)
 		return -EPERM;
 	return snd_seq_queue_timer_set_tempo(tempo->queue, client, tempo);
 }
-
 EXPORT_SYMBOL(snd_seq_set_queue_tempo);
 
 static int snd_seq_ioctl_set_queue_tempo(struct snd_seq_client *client,
@@ -2200,7 +2199,6 @@ int snd_seq_create_kernel_client(struct snd_card *card, int client_index,
 	/* return client number to caller */
 	return client->number;
 }
-
 EXPORT_SYMBOL(snd_seq_create_kernel_client);
 
 /* exported to kernel modules */
@@ -2219,7 +2217,6 @@ int snd_seq_delete_kernel_client(int client)
 	kfree(ptr);
 	return 0;
 }
-
 EXPORT_SYMBOL(snd_seq_delete_kernel_client);
 
 /* skeleton to enqueue event, called from snd_seq_kernel_client_enqueue
@@ -2269,7 +2266,6 @@ int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event * ev,
 {
 	return kernel_client_enqueue(client, ev, NULL, 0, atomic, hop);
 }
-
 EXPORT_SYMBOL(snd_seq_kernel_client_enqueue);
 
 /*
@@ -2283,7 +2279,6 @@ int snd_seq_kernel_client_enqueue_blocking(int client, struct snd_seq_event * ev
 {
 	return kernel_client_enqueue(client, ev, file, 1, atomic, hop);
 }
-
 EXPORT_SYMBOL(snd_seq_kernel_client_enqueue_blocking);
 
 /* 
@@ -2321,7 +2316,6 @@ int snd_seq_kernel_client_dispatch(int client, struct snd_seq_event * ev,
 	snd_seq_client_unlock(cptr);
 	return result;
 }
-
 EXPORT_SYMBOL(snd_seq_kernel_client_dispatch);
 
 /**
@@ -2354,7 +2348,6 @@ int snd_seq_kernel_client_ctl(int clientid, unsigned int cmd, void *arg)
 		 cmd, _IOC_TYPE(cmd), _IOC_NR(cmd));
 	return -ENOTTY;
 }
-
 EXPORT_SYMBOL(snd_seq_kernel_client_ctl);
 
 /* exported (for OSS emulator) */
@@ -2372,7 +2365,6 @@ int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table
 		return 1;
 	return 0;
 }
-
 EXPORT_SYMBOL(snd_seq_kernel_client_write_poll);
 
 /*---------------------------------------------------------------------------*/

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

@@ -40,7 +40,6 @@ void snd_use_lock_sync_helper(snd_use_lock_t *lockp, const char *file, int line)
 		schedule_timeout_uninterruptible(1);
 	}
 }
-
 EXPORT_SYMBOL(snd_use_lock_sync_helper);
 
 #endif

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

@@ -118,7 +118,6 @@ int snd_seq_dump_var_event(const struct snd_seq_event *event,
 	}
 	return 0;
 }
-
 EXPORT_SYMBOL(snd_seq_dump_var_event);
 
 
@@ -169,7 +168,6 @@ int snd_seq_expand_var_event(const struct snd_seq_event *event, int count, char
 				     &buf);
 	return err < 0 ? err : newlen;
 }
-
 EXPORT_SYMBOL(snd_seq_expand_var_event);
 
 /*

+ 4 - 5
sound/core/seq/seq_midi_emul.c

@@ -236,6 +236,7 @@ snd_midi_process_event(struct snd_midi_op *ops,
 		break;
 	}
 }
+EXPORT_SYMBOL(snd_midi_process_event);
 
 
 /*
@@ -409,6 +410,7 @@ snd_midi_channel_set_clear(struct snd_midi_channel_set *chset)
 			chan->drum_channel = 0;
 	}
 }
+EXPORT_SYMBOL(snd_midi_channel_set_clear);
 
 /*
  * Process a rpn message.
@@ -701,6 +703,7 @@ struct snd_midi_channel_set *snd_midi_channel_alloc_set(int n)
 	}
 	return chset;
 }
+EXPORT_SYMBOL(snd_midi_channel_alloc_set);
 
 /*
  * Reset the midi controllers on a particular channel to default values.
@@ -724,6 +727,7 @@ void snd_midi_channel_free_set(struct snd_midi_channel_set *chset)
 	kfree(chset->channels);
 	kfree(chset);
 }
+EXPORT_SYMBOL(snd_midi_channel_free_set);
 
 static int __init alsa_seq_midi_emul_init(void)
 {
@@ -736,8 +740,3 @@ static void __exit alsa_seq_midi_emul_exit(void)
 
 module_init(alsa_seq_midi_emul_init)
 module_exit(alsa_seq_midi_emul_exit)
-
-EXPORT_SYMBOL(snd_midi_process_event);
-EXPORT_SYMBOL(snd_midi_channel_set_clear);
-EXPORT_SYMBOL(snd_midi_channel_alloc_set);
-EXPORT_SYMBOL(snd_midi_channel_free_set);

+ 8 - 13
sound/core/seq/seq_midi_event.c

@@ -134,6 +134,7 @@ int snd_midi_event_new(int bufsize, struct snd_midi_event **rdev)
 	*rdev = dev;
 	return 0;
 }
+EXPORT_SYMBOL(snd_midi_event_new);
 
 void snd_midi_event_free(struct snd_midi_event *dev)
 {
@@ -142,6 +143,7 @@ void snd_midi_event_free(struct snd_midi_event *dev)
 		kfree(dev);
 	}
 }
+EXPORT_SYMBOL(snd_midi_event_free);
 
 /*
  * initialize record
@@ -161,6 +163,7 @@ void snd_midi_event_reset_encode(struct snd_midi_event *dev)
 	reset_encode(dev);
 	spin_unlock_irqrestore(&dev->lock, flags);
 }
+EXPORT_SYMBOL(snd_midi_event_reset_encode);
 
 void snd_midi_event_reset_decode(struct snd_midi_event *dev)
 {
@@ -170,6 +173,7 @@ void snd_midi_event_reset_decode(struct snd_midi_event *dev)
 	dev->lastcmd = 0xff;
 	spin_unlock_irqrestore(&dev->lock, flags);
 }
+EXPORT_SYMBOL(snd_midi_event_reset_decode);
 
 #if 0
 void snd_midi_event_init(struct snd_midi_event *dev)
@@ -183,6 +187,7 @@ void snd_midi_event_no_status(struct snd_midi_event *dev, int on)
 {
 	dev->nostat = on ? 1 : 0;
 }
+EXPORT_SYMBOL(snd_midi_event_no_status);
 
 /*
  * resize buffer
@@ -232,6 +237,7 @@ long snd_midi_event_encode(struct snd_midi_event *dev, unsigned char *buf, long
 
 	return result;
 }
+EXPORT_SYMBOL(snd_midi_event_encode);
 
 /*
  *  read one byte and encode to sequencer event:
@@ -307,6 +313,7 @@ int snd_midi_event_encode_byte(struct snd_midi_event *dev, int c,
 	spin_unlock_irqrestore(&dev->lock, flags);
 	return rc;
 }
+EXPORT_SYMBOL(snd_midi_event_encode_byte);
 
 /* encode note event */
 static void note_event(struct snd_midi_event *dev, struct snd_seq_event *ev)
@@ -408,6 +415,7 @@ long snd_midi_event_decode(struct snd_midi_event *dev, unsigned char *buf, long
 		return qlen;
 	}
 }
+EXPORT_SYMBOL(snd_midi_event_decode);
 
 
 /* decode note event */
@@ -524,19 +532,6 @@ static int extra_decode_xrpn(struct snd_midi_event *dev, unsigned char *buf,
 	return idx;
 }
 
-/*
- *  exports
- */
- 
-EXPORT_SYMBOL(snd_midi_event_new);
-EXPORT_SYMBOL(snd_midi_event_free);
-EXPORT_SYMBOL(snd_midi_event_reset_encode);
-EXPORT_SYMBOL(snd_midi_event_reset_decode);
-EXPORT_SYMBOL(snd_midi_event_no_status);
-EXPORT_SYMBOL(snd_midi_event_encode);
-EXPORT_SYMBOL(snd_midi_event_encode_byte);
-EXPORT_SYMBOL(snd_midi_event_decode);
-
 static int __init alsa_seq_midi_event_init(void)
 {
 	return 0;

+ 0 - 2
sound/core/seq/seq_ports.c

@@ -685,7 +685,6 @@ int snd_seq_event_port_attach(int client,
 
 	return ret;
 }
-
 EXPORT_SYMBOL(snd_seq_event_port_attach);
 
 /*
@@ -706,5 +705,4 @@ int snd_seq_event_port_detach(int client, int port)
 
 	return err;
 }
-
 EXPORT_SYMBOL(snd_seq_event_port_detach);

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

@@ -534,6 +534,7 @@ int snd_virmidi_new(struct snd_card *card, int device, struct snd_rawmidi **rrmi
 	*rrmidi = rmidi;
 	return 0;
 }
+EXPORT_SYMBOL(snd_virmidi_new);
 
 /*
  *  ENTRY functions
@@ -550,5 +551,3 @@ static void __exit alsa_virmidi_exit(void)
 
 module_init(alsa_virmidi_init)
 module_exit(alsa_virmidi_exit)
-
-EXPORT_SYMBOL(snd_virmidi_new);

+ 0 - 0
sound/core/seq/seq_device.c → sound/core/seq_device.c


+ 0 - 2
sound/core/sound.c

@@ -74,7 +74,6 @@ void snd_request_card(int card)
 		return;
 	request_module("snd-card-%i", card);
 }
-
 EXPORT_SYMBOL(snd_request_card);
 
 static void snd_request_other(int minor)
@@ -124,7 +123,6 @@ void *snd_lookup_minor_data(unsigned int minor, int type)
 	mutex_unlock(&sound_mutex);
 	return private_data;
 }
-
 EXPORT_SYMBOL(snd_lookup_minor_data);
 
 #ifdef CONFIG_MODULES

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio