sound updates for 4.13-rc1

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
 
 Note that of-graph change may bring the conflicts with a later pull
 request of devicetree, as currently found in linux-next.
 -----BEGIN PGP SIGNATURE-----
 
 iQJCBAABCAAsFiEECxfAB4MH3rD5mfB6bDGAVD0pKaQFAllbtmMOHHRpd2FpQHN1
 c2UuZGUACgkQbDGAVD0pKaTMkhAAnqvRvh9nYBI1E2VGtJON/AFcsF4s6xdJd0ow
 Bn5Kq/07rGWxAi8Cy69LM930eQrZl+xR69I7LMkC54BxVNhvhXNef7E5GXPbRi+3
 l6dkBmkqvwmmHP5iiOxKtYSAnUfJitu1rmtAOVAjRh8rsWNeLuI8N8V/uilQBioi
 lRywdBjdylub00H1DL8cmZHbrBb4pYrL/LepTswZL3I/UZ225fMiIGFd8tXpQPwZ
 IKRZiuzrc3SykxSsL/aNeyxP+2qTYRtPfl/FGenKBBO2PJmGAb00yAdtQJRcD2eX
 Xf1alfvpNgpy/U6+C7dJgNWQvvr+lPCaFXuMukIDno/zg/xD1V1Ev/fnbVEINLve
 xMOnuJSGGaY6fu6eZ4Cck0VfZIj7UVA9x8zvBOKntIhq/VLfE7DDu3p9tiAZAVfH
 nMOLAhy+0kFyHSrv6zVWQj+cmjPwLvaW7fNWVljL5/MWuF5GJi05DUOfV/vk8BaO
 EnyVqe2ynzNLTsFpLHHy6XKgKtSTkPygxYSNuI7kSYAxD5qE6hXXKXTAqJ3LjDkO
 tGiFmxp/vHrlNvcyRjXc30th/9PPj/mRBcJ2KyjXPa63L5ZW86PiyIHKxJA4yogv
 y4z2ZlhIz90cZvpigFHtFqq1puVlDtKDbAaJ6AKrP8HEHUlMiPNApsSjWWBUcfzV
 DXzrlg0=
 =PUEh
 -----END PGP SIGNATURE-----

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
  ...
This commit is contained in:
Linus Torvalds 2017-07-06 10:56:51 -07:00
commit 920f2ecdf6
349 changed files with 13862 additions and 5656 deletions

View File

@ -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>;
};
};
};
};

View File

@ -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>;
};
};
};
};

View File

@ -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";
...
};
};
};
};

View File

@ -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";
...
};
};
};
};

View File

@ -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

View File

@ -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>;

View File

@ -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

View File

@ -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";
};

View File

@ -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"

View File

@ -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",

View File

@ -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";
compatible = "simple-scu-audio-card";
card-name = "rsnd-ak4643";
format = "left_j";
bitclock-master = <&dpcmcpu>;
frame-master = <&dpcmcpu>;
simple-audio-card,name = "rsnd-ak4643";
simple-audio-card,format = "left_j";
simple-audio-card,bitclock-master = <&dpcmcpu>;
simple-audio-card,frame-master = <&dpcmcpu>;
convert-rate = <48000>; /* see audio_clk_a */
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 {

View File

@ -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>;
};
};
};

View File

@ -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>;
pinctrl-0 = <&pinctrl_sai1a>;
ports {
#address-cells = <1>;
#size-cells = <0>;
sai1b_port: port@0 {
reg = <0>;
sai1b_port: port {
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>;
};
format = "i2s";
};
};
};

View File

@ -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>;
};

View File

@ -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.

View File

@ -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

View File

@ -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>;
};
};

View File

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

View File

@ -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.

View File

@ -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);
Note that both the position and the amount of data are given in frames.
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.
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.
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.
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 ``silence`` callback is also implemented in a similar way
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:
::
my_memcpy(my_buffer + pos, src, count);
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
----------------------

View File

@ -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)

View File

@ -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"

View File

@ -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);

View File

@ -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;

View File

@ -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 = {

View File

@ -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)

View File

@ -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,

View File

@ -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

View File

@ -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,
return snd_pcm_indirect_playback_transfer(substream, pcm_indirect,
snd_bcm2835_pcm_transfer);
return 0;
}
/* trigger callback */

View File

@ -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;
}

View File

@ -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 */

View File

@ -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)
{

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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 */

View File

@ -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;

View File

@ -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
};

View File

@ -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 */

View File

@ -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

View File

@ -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,

View File

@ -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;
}
/*

View File

@ -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);
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);
extern const struct snd_pcm_hw_constraint_list snd_pcm_known_rates;
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

View File

@ -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
};

View File

@ -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

View File

@ -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 */

View File

@ -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 {

View File

@ -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 *);

View File

@ -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,

View File

@ -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 */

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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,

View File

@ -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.

View File

@ -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

View File

@ -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>");

View File

@ -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(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(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;
}
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;
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;
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;
}
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;
return 0;
}
static snd_pcm_uframes_t
@ -593,9 +435,6 @@ 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 -= runtime->dma_addr;
@ -613,9 +452,6 @@ 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 -= runtime->dma_addr;
@ -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,11 +502,9 @@ 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);
block_size = frames_to_bytes(runtime, runtime->period_size);
chip->playback_period++;
if (chip->playback_period == runtime->periods)
@ -681,18 +515,14 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev)
offset = block_size * next_period;
writel(runtime->dma_addr + offset,
chip->regs + ATMEL_PDC_TNPR);
writel(block_size / 2,
chip->regs + ATMEL_PDC_TNCR);
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);
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);
block_size = frames_to_bytes(runtime, runtime->period_size);
chip->capture_period++;
if (chip->capture_period == runtime->periods)
@ -703,13 +533,10 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev)
offset = block_size * next_period;
writel(runtime->dma_addr + offset,
chip->regs + ATMEL_PDC_RNPR);
writel(block_size / 2,
chip->regs + ATMEL_PDC_RNCR);
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);
if (!cpu_is_at32ap7000()) {
err = snd_ac97_pcm_assign(chip->ac97_bus,
retval = 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);
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);
retval = snd_pcm_new(chip->card, chip->card->shortname, 0, 1, 1, &pcm);
if (retval)
return retval;
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;
dev_dbg(&pdev->dev, "could not get irq: %d\n", irq);
return irq;
}
if (cpu_is_at32ap7000()) {
pclk = clk_get(&pdev->dev, "pclk");
} else {
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;

View File

@ -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

View File

@ -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/

View File

@ -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;
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.used++;
if (space > 0) {
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;
out:
up_read(&card->controls_rwsem);
}
if (copy_to_user(_list, &list, sizeof(list)))
return -EFAULT;
return 0;
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)

View File

@ -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,

View File

@ -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);
/*

View File

@ -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)

View File

@ -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 */

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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
/*

View File

@ -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:

View File

@ -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);

View File

@ -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);
err = fill_silence_frames(substream, 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);
}
}
}
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 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);
/* 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;
}
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)
/* 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;
/* 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;
}
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);
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);
/* 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)
goto _end_unlock;
return err;
}
return 0;
}
_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;
/* 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)
{
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_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;
} else {
char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);
if (copy_to_user(buf, hwbuf, frames_to_bytes(runtime, frames)))
return -EFAULT;
}
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)
/* 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 = substream->runtime;
snd_pcm_uframes_t xfer = 0;
snd_pcm_uframes_t offset = 0;
snd_pcm_uframes_t avail;
int err = 0;
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;
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 {
if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
return -EINVAL;
writer = noninterleaved_copy;
}
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);
err = pcm_accessible_state(runtime);
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;
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);
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;
err = pcm_accessible_state(runtime);
if (err < 0)
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);
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
sound/core/pcm_local.h Normal file
View File

@ -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 */

View File

@ -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,

View File

@ -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);
/**

File diff suppressed because it is too large Load Diff

View File

@ -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>

View File

@ -25,6 +25,8 @@
#include <sound/pcm.h>
#include <sound/timer.h>
#include "pcm_local.h"
/*
* Timer functions
*/

View File

@ -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 */

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
/*---------------------------------------------------------------------------*/

View File

@ -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

View File

@ -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);
/*

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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

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