mirror of https://gitee.com/openkylin/linux.git
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:
commit
920f2ecdf6
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -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";
|
||||
...
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -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";
|
||||
...
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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";
|
||||
};
|
|
@ -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"
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -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>;
|
||||
cpu_endpoint: endpoint {
|
||||
remote-endpoint = <&codec_endpoint>;
|
||||
audio-graph-card,format = "i2s";
|
||||
audio-graph-card,bitclock-master = <&codec_endpoint>;
|
||||
audio-graph-card,frame-master = <&codec_endpoint>;
|
||||
};
|
||||
sai1b_port: port {
|
||||
cpu_endpoint: endpoint {
|
||||
remote-endpoint = <&codec_endpoint>;
|
||||
format = "i2s";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
STMicroelectronics STM32 S/PDIF receiver (SPDIFRX).
|
||||
|
||||
The SPDIFRX peripheral, is designed to receive an S/PDIF flow compliant with
|
||||
IEC-60958 and IEC-61937.
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "st,stm32h7-spdifrx"
|
||||
- reg: cpu DAI IP base address and size
|
||||
- clocks: must contain an entry for kclk (used as S/PDIF signal reference)
|
||||
- clock-names: must contain "kclk"
|
||||
- interrupts: cpu DAI interrupt line
|
||||
- dmas: DMA specifiers for audio data DMA and iec control flow DMA
|
||||
See STM32 DMA bindings, Documentation/devicetree/bindings/dma/stm32-dma.txt
|
||||
- dma-names: two dmas have to be defined, "rx" and "rx-ctrl"
|
||||
|
||||
Optional properties:
|
||||
- resets: Reference to a reset controller asserting the SPDIFRX
|
||||
|
||||
The device node should contain one 'port' child node with one child 'endpoint'
|
||||
node, according to the bindings defined in Documentation/devicetree/bindings/
|
||||
graph.txt.
|
||||
|
||||
Example:
|
||||
spdifrx: spdifrx@40004000 {
|
||||
compatible = "st,stm32h7-spdifrx";
|
||||
reg = <0x40004000 0x400>;
|
||||
clocks = <&rcc SPDIFRX_CK>;
|
||||
clock-names = "kclk";
|
||||
interrupts = <97>;
|
||||
dmas = <&dmamux1 2 93 0x400 0x0>,
|
||||
<&dmamux1 3 94 0x400 0x0>;
|
||||
dma-names = "rx", "rx-ctrl";
|
||||
pinctrl-0 = <&spdifrx_pins>;
|
||||
pinctrl-names = "default";
|
||||
|
||||
spdifrx_port: port {
|
||||
cpu_endpoint: endpoint {
|
||||
remote-endpoint = <&codec_endpoint>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
spdif_in: spdif-in {
|
||||
compatible = "linux,spdif-dir";
|
||||
|
||||
codec_port: port {
|
||||
codec_endpoint: endpoint {
|
||||
remote-endpoint = <&cpu_endpoint>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
soundcard {
|
||||
compatible = "audio-graph-card";
|
||||
dais = <&spdifrx_port>;
|
||||
};
|
|
@ -7,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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>;
|
||||
};
|
||||
};
|
|
@ -9,6 +9,7 @@ Designs and Implementations
|
|||
compress-offload
|
||||
timestamping
|
||||
jack-controls
|
||||
tracepoints
|
||||
procfile
|
||||
powersave
|
||||
oss-emulation
|
||||
|
|
|
@ -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.
|
|
@ -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
|
||||
----------------------
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 @@ int of_phandle_iterator_next(struct of_phandle_iterator *it)
|
|||
|
||||
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
|
||||
|
|
|
@ -353,9 +353,8 @@ static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream)
|
|||
struct snd_pcm_indirect *pcm_indirect = &alsa_stream->pcm_indirect;
|
||||
|
||||
pcm_indirect->hw_queue_size = runtime->hw.buffer_bytes_max;
|
||||
snd_pcm_indirect_playback_transfer(substream, pcm_indirect,
|
||||
snd_bcm2835_pcm_transfer);
|
||||
return 0;
|
||||
return snd_pcm_indirect_playback_transfer(substream, pcm_indirect,
|
||||
snd_bcm2835_pcm_transfer);
|
||||
}
|
||||
|
||||
/* trigger callback */
|
||||
|
|
|
@ -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 @@ size_t u_audio_playback(struct gaudio *card, void *buf, size_t count)
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 *);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>");
|
|
@ -11,8 +11,6 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/atmel_pdc.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
@ -34,36 +32,14 @@
|
|||
#include <sound/atmel-ac97c.h>
|
||||
#include <sound/memalloc.h>
|
||||
|
||||
#include <linux/platform_data/dma-dw.h>
|
||||
#include <linux/dma/dw.h>
|
||||
|
||||
#ifdef CONFIG_AVR32
|
||||
#include <mach/cpu.h>
|
||||
#else
|
||||
#define cpu_is_at32ap7000() 0
|
||||
#endif
|
||||
|
||||
#include "ac97c.h"
|
||||
|
||||
enum {
|
||||
DMA_TX_READY = 0,
|
||||
DMA_RX_READY,
|
||||
DMA_TX_CHAN_PRESENT,
|
||||
DMA_RX_CHAN_PRESENT,
|
||||
};
|
||||
|
||||
/* Serialize access to opened variable */
|
||||
static DEFINE_MUTEX(opened_mutex);
|
||||
|
||||
struct atmel_ac97c_dma {
|
||||
struct dma_chan *rx_chan;
|
||||
struct dma_chan *tx_chan;
|
||||
};
|
||||
|
||||
struct atmel_ac97c {
|
||||
struct clk *pclk;
|
||||
struct platform_device *pdev;
|
||||
struct atmel_ac97c_dma dma;
|
||||
|
||||
struct snd_pcm_substream *playback_substream;
|
||||
struct snd_pcm_substream *capture_substream;
|
||||
|
@ -74,7 +50,6 @@ struct atmel_ac97c {
|
|||
|
||||
u64 cur_format;
|
||||
unsigned int cur_rate;
|
||||
unsigned long flags;
|
||||
int playback_period, capture_period;
|
||||
/* Serialize access to opened variable */
|
||||
spinlock_t lock;
|
||||
|
@ -91,65 +66,6 @@ struct atmel_ac97c {
|
|||
#define ac97c_readl(chip, reg) \
|
||||
__raw_readl((chip)->regs + AC97C_##reg)
|
||||
|
||||
/* This function is called by the DMA driver. */
|
||||
static void atmel_ac97c_dma_playback_period_done(void *arg)
|
||||
{
|
||||
struct atmel_ac97c *chip = arg;
|
||||
snd_pcm_period_elapsed(chip->playback_substream);
|
||||
}
|
||||
|
||||
static void atmel_ac97c_dma_capture_period_done(void *arg)
|
||||
{
|
||||
struct atmel_ac97c *chip = arg;
|
||||
snd_pcm_period_elapsed(chip->capture_substream);
|
||||
}
|
||||
|
||||
static int atmel_ac97c_prepare_dma(struct atmel_ac97c *chip,
|
||||
struct snd_pcm_substream *substream,
|
||||
enum dma_transfer_direction direction)
|
||||
{
|
||||
struct dma_chan *chan;
|
||||
struct dw_cyclic_desc *cdesc;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
unsigned long buffer_len, period_len;
|
||||
|
||||
/*
|
||||
* We don't do DMA on "complex" transfers, i.e. with
|
||||
* non-halfword-aligned buffers or lengths.
|
||||
*/
|
||||
if (runtime->dma_addr & 1 || runtime->buffer_size & 1) {
|
||||
dev_dbg(&chip->pdev->dev, "too complex transfer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (direction == DMA_MEM_TO_DEV)
|
||||
chan = chip->dma.tx_chan;
|
||||
else
|
||||
chan = chip->dma.rx_chan;
|
||||
|
||||
buffer_len = frames_to_bytes(runtime, runtime->buffer_size);
|
||||
period_len = frames_to_bytes(runtime, runtime->period_size);
|
||||
|
||||
cdesc = dw_dma_cyclic_prep(chan, runtime->dma_addr, buffer_len,
|
||||
period_len, direction);
|
||||
if (IS_ERR(cdesc)) {
|
||||
dev_dbg(&chip->pdev->dev, "could not prepare cyclic DMA\n");
|
||||
return PTR_ERR(cdesc);
|
||||
}
|
||||
|
||||
if (direction == DMA_MEM_TO_DEV) {
|
||||
cdesc->period_callback = atmel_ac97c_dma_playback_period_done;
|
||||
set_bit(DMA_TX_READY, &chip->flags);
|
||||
} else {
|
||||
cdesc->period_callback = atmel_ac97c_dma_capture_period_done;
|
||||
set_bit(DMA_RX_READY, &chip->flags);
|
||||
}
|
||||
|
||||
cdesc->period_callback_param = chip;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_pcm_hardware atmel_ac97c_hw = {
|
||||
.info = (SNDRV_PCM_INFO_MMAP
|
||||
| SNDRV_PCM_INFO_MMAP_VALID
|
||||
|
@ -254,13 +170,7 @@ static int atmel_ac97c_playback_hw_params(struct snd_pcm_substream *substream,
|
|||
params_buffer_bytes(hw_params));
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
/* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
|
||||
if (cpu_is_at32ap7000()) {
|
||||
/* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
|
||||
if (retval == 1)
|
||||
if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
|
||||
dw_dma_cyclic_free(chip->dma.tx_chan);
|
||||
}
|
||||
|
||||
/* Set restrictions to params. */
|
||||
mutex_lock(&opened_mutex);
|
||||
chip->cur_rate = params_rate(hw_params);
|
||||
|
@ -280,10 +190,6 @@ static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream,
|
|||
params_buffer_bytes(hw_params));
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
/* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
|
||||
if (cpu_is_at32ap7000() && retval == 1)
|
||||
if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
|
||||
dw_dma_cyclic_free(chip->dma.rx_chan);
|
||||
|
||||
/* Set restrictions to params. */
|
||||
mutex_lock(&opened_mutex);
|
||||
|
@ -294,26 +200,6 @@ static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream,
|
|||
return retval;
|
||||
}
|
||||
|
||||
static int atmel_ac97c_playback_hw_free(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
|
||||
if (cpu_is_at32ap7000()) {
|
||||
if (test_and_clear_bit(DMA_TX_READY, &chip->flags))
|
||||
dw_dma_cyclic_free(chip->dma.tx_chan);
|
||||
}
|
||||
return snd_pcm_lib_free_pages(substream);
|
||||
}
|
||||
|
||||
static int atmel_ac97c_capture_hw_free(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
|
||||
if (cpu_is_at32ap7000()) {
|
||||
if (test_and_clear_bit(DMA_RX_READY, &chip->flags))
|
||||
dw_dma_cyclic_free(chip->dma.rx_chan);
|
||||
}
|
||||
return snd_pcm_lib_free_pages(substream);
|
||||
}
|
||||
|
||||
static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
|
||||
|
@ -349,8 +235,6 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream)
|
|||
|
||||
switch (runtime->format) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
if (cpu_is_at32ap7000())
|
||||
word |= AC97C_CMR_CEM_LITTLE;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S16_BE: /* fall through */
|
||||
word &= ~(AC97C_CMR_CEM_LITTLE);
|
||||
|
@ -389,18 +273,11 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream)
|
|||
dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n",
|
||||
runtime->rate);
|
||||
|
||||
if (cpu_is_at32ap7000()) {
|
||||
if (!test_bit(DMA_TX_READY, &chip->flags))
|
||||
retval = atmel_ac97c_prepare_dma(chip, substream,
|
||||
DMA_MEM_TO_DEV);
|
||||
} else {
|
||||
/* Initialize and start the PDC */
|
||||
writel(runtime->dma_addr, chip->regs + ATMEL_PDC_TPR);
|
||||
writel(block_size / 2, chip->regs + ATMEL_PDC_TCR);
|
||||
writel(runtime->dma_addr + block_size,
|
||||
chip->regs + ATMEL_PDC_TNPR);
|
||||
writel(block_size / 2, chip->regs + ATMEL_PDC_TNCR);
|
||||
}
|
||||
/* Initialize and start the PDC */
|
||||
writel(runtime->dma_addr, chip->regs + ATMEL_PDC_TPR);
|
||||
writel(block_size / 2, chip->regs + ATMEL_PDC_TCR);
|
||||
writel(runtime->dma_addr + block_size, chip->regs + ATMEL_PDC_TNPR);
|
||||
writel(block_size / 2, chip->regs + ATMEL_PDC_TNCR);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
@ -440,8 +317,6 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream)
|
|||
|
||||
switch (runtime->format) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
if (cpu_is_at32ap7000())
|
||||
word |= AC97C_CMR_CEM_LITTLE;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S16_BE: /* fall through */
|
||||
word &= ~(AC97C_CMR_CEM_LITTLE);
|
||||
|
@ -480,18 +355,11 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream)
|
|||
dev_dbg(&chip->pdev->dev, "could not set rate %d Hz\n",
|
||||
runtime->rate);
|
||||
|
||||
if (cpu_is_at32ap7000()) {
|
||||
if (!test_bit(DMA_RX_READY, &chip->flags))
|
||||
retval = atmel_ac97c_prepare_dma(chip, substream,
|
||||
DMA_DEV_TO_MEM);
|
||||
} else {
|
||||
/* Initialize and start the PDC */
|
||||
writel(runtime->dma_addr, chip->regs + ATMEL_PDC_RPR);
|
||||
writel(block_size / 2, chip->regs + ATMEL_PDC_RCR);
|
||||
writel(runtime->dma_addr + block_size,
|
||||
chip->regs + ATMEL_PDC_RNPR);
|
||||
writel(block_size / 2, chip->regs + ATMEL_PDC_RNCR);
|
||||
}
|
||||
/* Initialize and start the PDC */
|
||||
writel(runtime->dma_addr, chip->regs + ATMEL_PDC_RPR);
|
||||
writel(block_size / 2, chip->regs + ATMEL_PDC_RCR);
|
||||
writel(runtime->dma_addr + block_size, chip->regs + ATMEL_PDC_RNPR);
|
||||
writel(block_size / 2, chip->regs + ATMEL_PDC_RNCR);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
@ -501,7 +369,6 @@ atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
{
|
||||
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
|
||||
unsigned long camr, ptcr = 0;
|
||||
int retval = 0;
|
||||
|
||||
camr = ac97c_readl(chip, CAMR);
|
||||
|
||||
|
@ -509,35 +376,23 @@ atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
|
||||
case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
if (cpu_is_at32ap7000()) {
|
||||
retval = dw_dma_cyclic_start(chip->dma.tx_chan);
|
||||
if (retval)
|
||||
goto out;
|
||||
} else {
|
||||
ptcr = ATMEL_PDC_TXTEN;
|
||||
}
|
||||
ptcr = ATMEL_PDC_TXTEN;
|
||||
camr |= AC97C_CMR_CENA | AC97C_CSR_ENDTX;
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
if (cpu_is_at32ap7000())
|
||||
dw_dma_cyclic_stop(chip->dma.tx_chan);
|
||||
else
|
||||
ptcr |= ATMEL_PDC_TXTDIS;
|
||||
ptcr |= ATMEL_PDC_TXTDIS;
|
||||
if (chip->opened <= 1)
|
||||
camr &= ~AC97C_CMR_CENA;
|
||||
break;
|
||||
default:
|
||||
retval = -EINVAL;
|
||||
goto out;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ac97c_writel(chip, CAMR, camr);
|
||||
if (!cpu_is_at32ap7000())
|
||||
writel(ptcr, chip->regs + ATMEL_PDC_PTCR);
|
||||
out:
|
||||
return retval;
|
||||
writel(ptcr, chip->regs + ATMEL_PDC_PTCR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -545,7 +400,6 @@ atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
{
|
||||
struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
|
||||
unsigned long camr, ptcr = 0;
|
||||
int retval = 0;
|
||||
|
||||
camr = ac97c_readl(chip, CAMR);
|
||||
ptcr = readl(chip->regs + ATMEL_PDC_PTSR);
|
||||
|
@ -554,35 +408,23 @@ atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
|
||||
case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
if (cpu_is_at32ap7000()) {
|
||||
retval = dw_dma_cyclic_start(chip->dma.rx_chan);
|
||||
if (retval)
|
||||
goto out;
|
||||
} else {
|
||||
ptcr = ATMEL_PDC_RXTEN;
|
||||
}
|
||||
ptcr = ATMEL_PDC_RXTEN;
|
||||
camr |= AC97C_CMR_CENA | AC97C_CSR_ENDRX;
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
if (cpu_is_at32ap7000())
|
||||
dw_dma_cyclic_stop(chip->dma.rx_chan);
|
||||
else
|
||||
ptcr |= (ATMEL_PDC_RXTDIS);
|
||||
ptcr |= ATMEL_PDC_RXTDIS;
|
||||
if (chip->opened <= 1)
|
||||
camr &= ~AC97C_CMR_CENA;
|
||||
break;
|
||||
default:
|
||||
retval = -EINVAL;
|
||||
break;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ac97c_writel(chip, CAMR, camr);
|
||||
if (!cpu_is_at32ap7000())
|
||||
writel(ptcr, chip->regs + ATMEL_PDC_PTCR);
|
||||
out:
|
||||
return retval;
|
||||
writel(ptcr, chip->regs + ATMEL_PDC_PTCR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t
|
||||
|
@ -593,10 +435,7 @@ atmel_ac97c_playback_pointer(struct snd_pcm_substream *substream)
|
|||
snd_pcm_uframes_t frames;
|
||||
unsigned long bytes;
|
||||
|
||||
if (cpu_is_at32ap7000())
|
||||
bytes = dw_dma_get_src_addr(chip->dma.tx_chan);
|
||||
else
|
||||
bytes = readl(chip->regs + ATMEL_PDC_TPR);
|
||||
bytes = readl(chip->regs + ATMEL_PDC_TPR);
|
||||
bytes -= runtime->dma_addr;
|
||||
|
||||
frames = bytes_to_frames(runtime, bytes);
|
||||
|
@ -613,10 +452,7 @@ atmel_ac97c_capture_pointer(struct snd_pcm_substream *substream)
|
|||
snd_pcm_uframes_t frames;
|
||||
unsigned long bytes;
|
||||
|
||||
if (cpu_is_at32ap7000())
|
||||
bytes = dw_dma_get_dst_addr(chip->dma.rx_chan);
|
||||
else
|
||||
bytes = readl(chip->regs + ATMEL_PDC_RPR);
|
||||
bytes = readl(chip->regs + ATMEL_PDC_RPR);
|
||||
bytes -= runtime->dma_addr;
|
||||
|
||||
frames = bytes_to_frames(runtime, bytes);
|
||||
|
@ -630,7 +466,7 @@ static struct snd_pcm_ops atmel_ac97_playback_ops = {
|
|||
.close = atmel_ac97c_playback_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = atmel_ac97c_playback_hw_params,
|
||||
.hw_free = atmel_ac97c_playback_hw_free,
|
||||
.hw_free = snd_pcm_lib_free_pages,
|
||||
.prepare = atmel_ac97c_playback_prepare,
|
||||
.trigger = atmel_ac97c_playback_trigger,
|
||||
.pointer = atmel_ac97c_playback_pointer,
|
||||
|
@ -641,7 +477,7 @@ static struct snd_pcm_ops atmel_ac97_capture_ops = {
|
|||
.close = atmel_ac97c_capture_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = atmel_ac97c_capture_hw_params,
|
||||
.hw_free = atmel_ac97c_capture_hw_free,
|
||||
.hw_free = snd_pcm_lib_free_pages,
|
||||
.prepare = atmel_ac97c_capture_prepare,
|
||||
.trigger = atmel_ac97c_capture_trigger,
|
||||
.pointer = atmel_ac97c_capture_pointer,
|
||||
|
@ -666,49 +502,40 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev)
|
|||
casr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "",
|
||||
casr & AC97C_CSR_TXRDY ? " TXRDY" : "",
|
||||
!casr ? " NONE" : "");
|
||||
if (!cpu_is_at32ap7000()) {
|
||||
if ((casr & camr) & AC97C_CSR_ENDTX) {
|
||||
runtime = chip->playback_substream->runtime;
|
||||
block_size = frames_to_bytes(runtime,
|
||||
runtime->period_size);
|
||||
chip->playback_period++;
|
||||
if ((casr & camr) & AC97C_CSR_ENDTX) {
|
||||
runtime = chip->playback_substream->runtime;
|
||||
block_size = frames_to_bytes(runtime, runtime->period_size);
|
||||
chip->playback_period++;
|
||||
|
||||
if (chip->playback_period == runtime->periods)
|
||||
chip->playback_period = 0;
|
||||
next_period = chip->playback_period + 1;
|
||||
if (next_period == runtime->periods)
|
||||
next_period = 0;
|
||||
if (chip->playback_period == runtime->periods)
|
||||
chip->playback_period = 0;
|
||||
next_period = chip->playback_period + 1;
|
||||
if (next_period == runtime->periods)
|
||||
next_period = 0;
|
||||
|
||||
offset = block_size * next_period;
|
||||
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);
|
||||
}
|
||||
if ((casr & camr) & AC97C_CSR_ENDRX) {
|
||||
runtime = chip->capture_substream->runtime;
|
||||
block_size = frames_to_bytes(runtime,
|
||||
runtime->period_size);
|
||||
chip->capture_period++;
|
||||
snd_pcm_period_elapsed(chip->playback_substream);
|
||||
}
|
||||
if ((casr & camr) & AC97C_CSR_ENDRX) {
|
||||
runtime = chip->capture_substream->runtime;
|
||||
block_size = frames_to_bytes(runtime, runtime->period_size);
|
||||
chip->capture_period++;
|
||||
|
||||
if (chip->capture_period == runtime->periods)
|
||||
chip->capture_period = 0;
|
||||
next_period = chip->capture_period + 1;
|
||||
if (next_period == runtime->periods)
|
||||
next_period = 0;
|
||||
if (chip->capture_period == runtime->periods)
|
||||
chip->capture_period = 0;
|
||||
next_period = chip->capture_period + 1;
|
||||
if (next_period == runtime->periods)
|
||||
next_period = 0;
|
||||
|
||||
offset = block_size * next_period;
|
||||
offset = block_size * next_period;
|
||||
|
||||
writel(runtime->dma_addr + offset,
|
||||
chip->regs + ATMEL_PDC_RNPR);
|
||||
writel(block_size / 2,
|
||||
chip->regs + ATMEL_PDC_RNCR);
|
||||
snd_pcm_period_elapsed(chip->capture_substream);
|
||||
}
|
||||
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,
|
||||
ARRAY_SIZE(at91_ac97_pcm_defs),
|
||||
at91_ac97_pcm_defs);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
retval = snd_pcm_new(chip->card, chip->card->shortname,
|
||||
0, playback, capture, &pcm);
|
||||
retval = snd_ac97_pcm_assign(chip->ac97_bus,
|
||||
ARRAY_SIZE(at91_ac97_pcm_defs),
|
||||
at91_ac97_pcm_defs);
|
||||
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 @@ static unsigned short atmel_ac97c_read(struct snd_ac97 *ac97,
|
|||
return 0xffff;
|
||||
}
|
||||
|
||||
static bool filter(struct dma_chan *chan, void *slave)
|
||||
{
|
||||
struct dw_dma_slave *dws = slave;
|
||||
|
||||
if (dws->dma_dev == chan->device->dev) {
|
||||
chan->private = dws;
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
static void atmel_ac97c_reset(struct atmel_ac97c *chip)
|
||||
{
|
||||
ac97c_writel(chip, MR, 0);
|
||||
|
@ -967,16 +774,11 @@ static int atmel_ac97c_probe(struct platform_device *pdev)
|
|||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_dbg(&pdev->dev, "could not get irq\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
if (cpu_is_at32ap7000()) {
|
||||
pclk = clk_get(&pdev->dev, "pclk");
|
||||
} else {
|
||||
pclk = clk_get(&pdev->dev, "ac97_clk");
|
||||
dev_dbg(&pdev->dev, "could not get irq: %d\n", irq);
|
||||
return irq;
|
||||
}
|
||||
|
||||
pclk = clk_get(&pdev->dev, "ac97_clk");
|
||||
if (IS_ERR(pclk)) {
|
||||
dev_dbg(&pdev->dev, "no peripheral clock\n");
|
||||
return PTR_ERR(pclk);
|
||||
|
@ -1047,88 +849,16 @@ static int atmel_ac97c_probe(struct platform_device *pdev)
|
|||
goto err_ac97_bus;
|
||||
}
|
||||
|
||||
if (cpu_is_at32ap7000()) {
|
||||
if (pdata->rx_dws.dma_dev) {
|
||||
dma_cap_mask_t mask;
|
||||
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
|
||||
chip->dma.rx_chan = dma_request_channel(mask, filter,
|
||||
&pdata->rx_dws);
|
||||
if (chip->dma.rx_chan) {
|
||||
struct dma_slave_config dma_conf = {
|
||||
.src_addr = regs->start + AC97C_CARHR +
|
||||
2,
|
||||
.src_addr_width =
|
||||
DMA_SLAVE_BUSWIDTH_2_BYTES,
|
||||
.src_maxburst = 1,
|
||||
.dst_maxburst = 1,
|
||||
.direction = DMA_DEV_TO_MEM,
|
||||
.device_fc = false,
|
||||
};
|
||||
|
||||
dmaengine_slave_config(chip->dma.rx_chan,
|
||||
&dma_conf);
|
||||
}
|
||||
|
||||
dev_info(&chip->pdev->dev, "using %s for DMA RX\n",
|
||||
dev_name(&chip->dma.rx_chan->dev->device));
|
||||
set_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
|
||||
}
|
||||
|
||||
if (pdata->tx_dws.dma_dev) {
|
||||
dma_cap_mask_t mask;
|
||||
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
|
||||
chip->dma.tx_chan = dma_request_channel(mask, filter,
|
||||
&pdata->tx_dws);
|
||||
if (chip->dma.tx_chan) {
|
||||
struct dma_slave_config dma_conf = {
|
||||
.dst_addr = regs->start + AC97C_CATHR +
|
||||
2,
|
||||
.dst_addr_width =
|
||||
DMA_SLAVE_BUSWIDTH_2_BYTES,
|
||||
.src_maxburst = 1,
|
||||
.dst_maxburst = 1,
|
||||
.direction = DMA_MEM_TO_DEV,
|
||||
.device_fc = false,
|
||||
};
|
||||
|
||||
dmaengine_slave_config(chip->dma.tx_chan,
|
||||
&dma_conf);
|
||||
}
|
||||
|
||||
dev_info(&chip->pdev->dev, "using %s for DMA TX\n",
|
||||
dev_name(&chip->dma.tx_chan->dev->device));
|
||||
set_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
|
||||
}
|
||||
|
||||
if (!test_bit(DMA_RX_CHAN_PRESENT, &chip->flags) &&
|
||||
!test_bit(DMA_TX_CHAN_PRESENT, &chip->flags)) {
|
||||
dev_dbg(&pdev->dev, "DMA not available\n");
|
||||
retval = -ENODEV;
|
||||
goto err_dma;
|
||||
}
|
||||
} else {
|
||||
/* Just pretend that we have DMA channel(for at91 i is actually
|
||||
* the PDC) */
|
||||
set_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
|
||||
set_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
|
||||
}
|
||||
|
||||
retval = atmel_ac97c_pcm_new(chip);
|
||||
if (retval) {
|
||||
dev_dbg(&pdev->dev, "could not register ac97 pcm device\n");
|
||||
goto err_dma;
|
||||
goto err_ac97_bus;
|
||||
}
|
||||
|
||||
retval = snd_card_register(card);
|
||||
if (retval) {
|
||||
dev_dbg(&pdev->dev, "could not register sound card\n");
|
||||
goto err_dma;
|
||||
goto err_ac97_bus;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, card);
|
||||
|
@ -1138,17 +868,6 @@ static int atmel_ac97c_probe(struct platform_device *pdev)
|
|||
|
||||
return 0;
|
||||
|
||||
err_dma:
|
||||
if (cpu_is_at32ap7000()) {
|
||||
if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
|
||||
dma_release_channel(chip->dma.rx_chan);
|
||||
if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags))
|
||||
dma_release_channel(chip->dma.tx_chan);
|
||||
clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
|
||||
clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
|
||||
chip->dma.rx_chan = NULL;
|
||||
chip->dma.tx_chan = NULL;
|
||||
}
|
||||
err_ac97_bus:
|
||||
if (gpio_is_valid(chip->reset_pin))
|
||||
gpio_free(chip->reset_pin);
|
||||
|
@ -1170,14 +889,7 @@ static int atmel_ac97c_suspend(struct device *pdev)
|
|||
struct snd_card *card = dev_get_drvdata(pdev);
|
||||
struct atmel_ac97c *chip = card->private_data;
|
||||
|
||||
if (cpu_is_at32ap7000()) {
|
||||
if (test_bit(DMA_RX_READY, &chip->flags))
|
||||
dw_dma_cyclic_stop(chip->dma.rx_chan);
|
||||
if (test_bit(DMA_TX_READY, &chip->flags))
|
||||
dw_dma_cyclic_stop(chip->dma.tx_chan);
|
||||
}
|
||||
clk_disable_unprepare(chip->pclk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1187,12 +899,6 @@ static int atmel_ac97c_resume(struct device *pdev)
|
|||
struct atmel_ac97c *chip = card->private_data;
|
||||
|
||||
clk_prepare_enable(chip->pclk);
|
||||
if (cpu_is_at32ap7000()) {
|
||||
if (test_bit(DMA_RX_READY, &chip->flags))
|
||||
dw_dma_cyclic_start(chip->dma.rx_chan);
|
||||
if (test_bit(DMA_TX_READY, &chip->flags))
|
||||
dw_dma_cyclic_start(chip->dma.tx_chan);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1219,17 +925,6 @@ static int atmel_ac97c_remove(struct platform_device *pdev)
|
|||
iounmap(chip->regs);
|
||||
free_irq(chip->irq, chip);
|
||||
|
||||
if (cpu_is_at32ap7000()) {
|
||||
if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
|
||||
dma_release_channel(chip->dma.rx_chan);
|
||||
if (test_bit(DMA_TX_CHAN_PRESENT, &chip->flags))
|
||||
dma_release_channel(chip->dma.tx_chan);
|
||||
clear_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
|
||||
clear_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
|
||||
chip->dma.rx_chan = NULL;
|
||||
chip->dma.tx_chan = NULL;
|
||||
}
|
||||
|
||||
snd_card_free(card);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -747,65 +747,45 @@ static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl,
|
|||
static int snd_ctl_elem_list(struct snd_card *card,
|
||||
struct snd_ctl_elem_list __user *_list)
|
||||
{
|
||||
struct list_head *plist;
|
||||
struct snd_ctl_elem_list list;
|
||||
struct snd_kcontrol *kctl;
|
||||
struct snd_ctl_elem_id *dst, *id;
|
||||
struct snd_ctl_elem_id id;
|
||||
unsigned int offset, space, jidx;
|
||||
int err = 0;
|
||||
|
||||
if (copy_from_user(&list, _list, sizeof(list)))
|
||||
return -EFAULT;
|
||||
offset = list.offset;
|
||||
space = list.space;
|
||||
/* try limit maximum space */
|
||||
if (space > 16384)
|
||||
return -ENOMEM;
|
||||
|
||||
down_read(&card->controls_rwsem);
|
||||
list.count = card->controls_count;
|
||||
list.used = 0;
|
||||
if (space > 0) {
|
||||
/* allocate temporary buffer for atomic operation */
|
||||
dst = vmalloc(space * sizeof(struct snd_ctl_elem_id));
|
||||
if (dst == NULL)
|
||||
return -ENOMEM;
|
||||
down_read(&card->controls_rwsem);
|
||||
list.count = card->controls_count;
|
||||
plist = card->controls.next;
|
||||
while (plist != &card->controls) {
|
||||
if (offset == 0)
|
||||
break;
|
||||
kctl = snd_kcontrol(plist);
|
||||
if (offset < kctl->count)
|
||||
break;
|
||||
offset -= kctl->count;
|
||||
plist = plist->next;
|
||||
}
|
||||
list.used = 0;
|
||||
id = dst;
|
||||
while (space > 0 && plist != &card->controls) {
|
||||
kctl = snd_kcontrol(plist);
|
||||
for (jidx = offset; space > 0 && jidx < kctl->count; jidx++) {
|
||||
snd_ctl_build_ioff(id, kctl, jidx);
|
||||
id++;
|
||||
space--;
|
||||
list.used++;
|
||||
list_for_each_entry(kctl, &card->controls, list) {
|
||||
if (offset >= kctl->count) {
|
||||
offset -= kctl->count;
|
||||
continue;
|
||||
}
|
||||
for (jidx = offset; jidx < kctl->count; jidx++) {
|
||||
snd_ctl_build_ioff(&id, kctl, jidx);
|
||||
if (copy_to_user(list.pids + list.used, &id,
|
||||
sizeof(id))) {
|
||||
err = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
list.used++;
|
||||
if (!--space)
|
||||
goto out;
|
||||
}
|
||||
plist = plist->next;
|
||||
offset = 0;
|
||||
}
|
||||
up_read(&card->controls_rwsem);
|
||||
if (list.used > 0 &&
|
||||
copy_to_user(list.pids, dst,
|
||||
list.used * sizeof(struct snd_ctl_elem_id))) {
|
||||
vfree(dst);
|
||||
return -EFAULT;
|
||||
}
|
||||
vfree(dst);
|
||||
} else {
|
||||
down_read(&card->controls_rwsem);
|
||||
list.count = card->controls_count;
|
||||
up_read(&card->controls_rwsem);
|
||||
}
|
||||
if (copy_to_user(_list, &list, sizeof(list)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
out:
|
||||
up_read(&card->controls_rwsem);
|
||||
if (!err && copy_to_user(_list, &list, sizeof(list)))
|
||||
err = -EFAULT;
|
||||
return err;
|
||||
}
|
||||
|
||||
static bool validate_element_member_dimension(struct snd_ctl_elem_info *info)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
/*
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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(®ister_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
|
||||
/*
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
#include <sound/pcm_params.h>
|
||||
#include <sound/timer.h>
|
||||
|
||||
#include "pcm_local.h"
|
||||
|
||||
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include "pcm_trace.h"
|
||||
|
@ -40,8 +42,12 @@
|
|||
#define trace_hwptr(substream, pos, in_interrupt)
|
||||
#define trace_xrun(substream)
|
||||
#define trace_hw_ptr_error(substream, reason)
|
||||
#define trace_applptr(substream, prev, curr)
|
||||
#endif
|
||||
|
||||
static int fill_silence_frames(struct snd_pcm_substream *substream,
|
||||
snd_pcm_uframes_t off, snd_pcm_uframes_t frames);
|
||||
|
||||
/*
|
||||
* fill ring buffer with silence
|
||||
* runtime->silence_start: starting pointer to silence area
|
||||
|
@ -55,18 +61,20 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
|
|||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
snd_pcm_uframes_t frames, ofs, transfer;
|
||||
int err;
|
||||
|
||||
if (runtime->silence_size < runtime->boundary) {
|
||||
snd_pcm_sframes_t noise_dist, n;
|
||||
if (runtime->silence_start != runtime->control->appl_ptr) {
|
||||
n = runtime->control->appl_ptr - runtime->silence_start;
|
||||
snd_pcm_uframes_t appl_ptr = READ_ONCE(runtime->control->appl_ptr);
|
||||
if (runtime->silence_start != appl_ptr) {
|
||||
n = appl_ptr - runtime->silence_start;
|
||||
if (n < 0)
|
||||
n += runtime->boundary;
|
||||
if ((snd_pcm_uframes_t)n < runtime->silence_filled)
|
||||
runtime->silence_filled -= n;
|
||||
else
|
||||
runtime->silence_filled = 0;
|
||||
runtime->silence_start = runtime->control->appl_ptr;
|
||||
runtime->silence_start = appl_ptr;
|
||||
}
|
||||
if (runtime->silence_filled >= runtime->buffer_size)
|
||||
return;
|
||||
|
@ -107,33 +115,8 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram
|
|||
ofs = runtime->silence_start % runtime->buffer_size;
|
||||
while (frames > 0) {
|
||||
transfer = ofs + frames > runtime->buffer_size ? runtime->buffer_size - ofs : frames;
|
||||
if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED ||
|
||||
runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) {
|
||||
if (substream->ops->silence) {
|
||||
int err;
|
||||
err = substream->ops->silence(substream, -1, ofs, transfer);
|
||||
snd_BUG_ON(err < 0);
|
||||
} else {
|
||||
char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, ofs);
|
||||
snd_pcm_format_set_silence(runtime->format, hwbuf, transfer * runtime->channels);
|
||||
}
|
||||
} else {
|
||||
unsigned int c;
|
||||
unsigned int channels = runtime->channels;
|
||||
if (substream->ops->silence) {
|
||||
for (c = 0; c < channels; ++c) {
|
||||
int err;
|
||||
err = substream->ops->silence(substream, c, ofs, transfer);
|
||||
snd_BUG_ON(err < 0);
|
||||
}
|
||||
} else {
|
||||
size_t dma_csize = runtime->dma_bytes / channels;
|
||||
for (c = 0; c < channels; ++c) {
|
||||
char *hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, ofs);
|
||||
snd_pcm_format_set_silence(runtime->format, hwbuf, transfer);
|
||||
}
|
||||
}
|
||||
}
|
||||
err = fill_silence_frames(substream, ofs, transfer);
|
||||
snd_BUG_ON(err < 0);
|
||||
runtime->silence_filled += transfer;
|
||||
frames -= transfer;
|
||||
ofs = 0;
|
||||
|
@ -508,7 +491,6 @@ void snd_pcm_set_ops(struct snd_pcm *pcm, int direction,
|
|||
for (substream = stream->substream; substream != NULL; substream = substream->next)
|
||||
substream->ops = ops;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_pcm_set_ops);
|
||||
|
||||
/**
|
||||
|
@ -526,7 +508,6 @@ void snd_pcm_set_sync(struct snd_pcm_substream *substream)
|
|||
runtime->sync.id32[2] = -1;
|
||||
runtime->sync.id32[3] = -1;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_pcm_set_sync);
|
||||
|
||||
/*
|
||||
|
@ -643,7 +624,6 @@ int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v)
|
|||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_interval_refine);
|
||||
|
||||
static int snd_interval_refine_first(struct snd_interval *i)
|
||||
|
@ -906,7 +886,6 @@ int snd_interval_ratnum(struct snd_interval *i,
|
|||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_interval_ratnum);
|
||||
|
||||
/**
|
||||
|
@ -1044,7 +1023,6 @@ int snd_interval_list(struct snd_interval *i, unsigned int count,
|
|||
}
|
||||
return snd_interval_refine(i, &list_range);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_interval_list);
|
||||
|
||||
/**
|
||||
|
@ -1183,7 +1161,6 @@ int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime, unsigned int cond,
|
|||
va_end(args);
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_pcm_hw_rule_add);
|
||||
|
||||
/**
|
||||
|
@ -1247,7 +1224,6 @@ int snd_pcm_hw_constraint_integer(struct snd_pcm_runtime *runtime, snd_pcm_hw_pa
|
|||
struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints;
|
||||
return snd_interval_setinteger(constrs_interval(constrs, var));
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_pcm_hw_constraint_integer);
|
||||
|
||||
/**
|
||||
|
@ -1273,7 +1249,6 @@ int snd_pcm_hw_constraint_minmax(struct snd_pcm_runtime *runtime, snd_pcm_hw_par
|
|||
t.integer = 0;
|
||||
return snd_interval_refine(constrs_interval(constrs, var), &t);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_pcm_hw_constraint_minmax);
|
||||
|
||||
static int snd_pcm_hw_rule_list(struct snd_pcm_hw_params *params,
|
||||
|
@ -1304,7 +1279,6 @@ int snd_pcm_hw_constraint_list(struct snd_pcm_runtime *runtime,
|
|||
snd_pcm_hw_rule_list, (void *)l,
|
||||
var, -1);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_pcm_hw_constraint_list);
|
||||
|
||||
static int snd_pcm_hw_rule_ranges(struct snd_pcm_hw_params *params,
|
||||
|
@ -1371,7 +1345,6 @@ int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime,
|
|||
snd_pcm_hw_rule_ratnums, (void *)r,
|
||||
var, -1);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_pcm_hw_constraint_ratnums);
|
||||
|
||||
static int snd_pcm_hw_rule_ratdens(struct snd_pcm_hw_params *params,
|
||||
|
@ -1406,7 +1379,6 @@ int snd_pcm_hw_constraint_ratdens(struct snd_pcm_runtime *runtime,
|
|||
snd_pcm_hw_rule_ratdens, (void *)r,
|
||||
var, -1);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_pcm_hw_constraint_ratdens);
|
||||
|
||||
static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params,
|
||||
|
@ -1415,7 +1387,8 @@ static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params,
|
|||
unsigned int l = (unsigned long) rule->private;
|
||||
int width = l & 0xffff;
|
||||
unsigned int msbits = l >> 16;
|
||||
struct snd_interval *i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
|
||||
const struct snd_interval *i =
|
||||
hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
|
||||
|
||||
if (!snd_interval_single(i))
|
||||
return 0;
|
||||
|
@ -1452,7 +1425,6 @@ int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime,
|
|||
(void*) l,
|
||||
SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_pcm_hw_constraint_msbits);
|
||||
|
||||
static int snd_pcm_hw_rule_step(struct snd_pcm_hw_params *params,
|
||||
|
@ -1480,7 +1452,6 @@ int snd_pcm_hw_constraint_step(struct snd_pcm_runtime *runtime,
|
|||
snd_pcm_hw_rule_step, (void *) step,
|
||||
var, -1);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_pcm_hw_constraint_step);
|
||||
|
||||
static int snd_pcm_hw_rule_pow2(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
|
||||
|
@ -1511,7 +1482,6 @@ int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime,
|
|||
snd_pcm_hw_rule_pow2, NULL,
|
||||
var, -1);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2);
|
||||
|
||||
static int snd_pcm_hw_rule_noresample_func(struct snd_pcm_hw_params *params,
|
||||
|
@ -1570,7 +1540,6 @@ void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params)
|
|||
_snd_pcm_hw_param_any(params, k);
|
||||
params->info = ~0U;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(_snd_pcm_hw_params_any);
|
||||
|
||||
/**
|
||||
|
@ -1603,7 +1572,6 @@ int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params,
|
|||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_pcm_hw_param_value);
|
||||
|
||||
void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params,
|
||||
|
@ -1621,7 +1589,6 @@ void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params,
|
|||
snd_BUG();
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(_snd_pcm_hw_param_setempty);
|
||||
|
||||
static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params,
|
||||
|
@ -1668,7 +1635,6 @@ int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm,
|
|||
}
|
||||
return snd_pcm_hw_param_value(params, var, dir);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_pcm_hw_param_first);
|
||||
|
||||
static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params,
|
||||
|
@ -1715,48 +1681,8 @@ int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm,
|
|||
}
|
||||
return snd_pcm_hw_param_value(params, var, dir);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_pcm_hw_param_last);
|
||||
|
||||
/**
|
||||
* snd_pcm_hw_param_choose - choose a configuration defined by @params
|
||||
* @pcm: PCM instance
|
||||
* @params: the hw_params instance
|
||||
*
|
||||
* Choose one configuration from configuration space defined by @params.
|
||||
* The configuration chosen is that obtained fixing in this order:
|
||||
* first access, first format, first subformat, min channels,
|
||||
* min rate, min period time, max buffer size, min tick time
|
||||
*
|
||||
* Return: Zero if successful, or a negative error code on failure.
|
||||
*/
|
||||
int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
static int vars[] = {
|
||||
SNDRV_PCM_HW_PARAM_ACCESS,
|
||||
SNDRV_PCM_HW_PARAM_FORMAT,
|
||||
SNDRV_PCM_HW_PARAM_SUBFORMAT,
|
||||
SNDRV_PCM_HW_PARAM_CHANNELS,
|
||||
SNDRV_PCM_HW_PARAM_RATE,
|
||||
SNDRV_PCM_HW_PARAM_PERIOD_TIME,
|
||||
SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
|
||||
SNDRV_PCM_HW_PARAM_TICK_TIME,
|
||||
-1
|
||||
};
|
||||
int err, *v;
|
||||
|
||||
for (v = vars; *v != -1; v++) {
|
||||
if (*v != SNDRV_PCM_HW_PARAM_BUFFER_SIZE)
|
||||
err = snd_pcm_hw_param_first(pcm, params, *v, NULL);
|
||||
else
|
||||
err = snd_pcm_hw_param_last(pcm, params, *v, NULL);
|
||||
if (snd_BUG_ON(err < 0))
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream,
|
||||
void *arg)
|
||||
{
|
||||
|
@ -1843,8 +1769,6 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
|
|||
unsigned int cmd, void *arg)
|
||||
{
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_IOCTL1_INFO:
|
||||
return 0;
|
||||
case SNDRV_PCM_IOCTL1_RESET:
|
||||
return snd_pcm_lib_ioctl_reset(substream, arg);
|
||||
case SNDRV_PCM_IOCTL1_CHANNEL_INFO:
|
||||
|
@ -1854,7 +1778,6 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
|
|||
}
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_pcm_lib_ioctl);
|
||||
|
||||
/**
|
||||
|
@ -1890,7 +1813,6 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
|
|||
kill_fasync(&runtime->fasync, SIGIO, POLL_IN);
|
||||
snd_pcm_stream_unlock_irqrestore(substream, flags);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(snd_pcm_period_elapsed);
|
||||
|
||||
/*
|
||||
|
@ -1985,129 +1907,147 @@ static int wait_for_avail(struct snd_pcm_substream *substream,
|
|||
return err;
|
||||
}
|
||||
|
||||
static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream,
|
||||
unsigned int hwoff,
|
||||
unsigned long data, unsigned int off,
|
||||
snd_pcm_uframes_t frames)
|
||||
typedef int (*pcm_transfer_f)(struct snd_pcm_substream *substream,
|
||||
int channel, unsigned long hwoff,
|
||||
void *buf, unsigned long bytes);
|
||||
|
||||
typedef int (*pcm_copy_f)(struct snd_pcm_substream *, snd_pcm_uframes_t, void *,
|
||||
snd_pcm_uframes_t, snd_pcm_uframes_t, pcm_transfer_f);
|
||||
|
||||
/* calculate the target DMA-buffer position to be written/read */
|
||||
static void *get_dma_ptr(struct snd_pcm_runtime *runtime,
|
||||
int channel, unsigned long hwoff)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/* default copy_kernel ops for write */
|
||||
static int default_write_copy_kernel(struct snd_pcm_substream *substream,
|
||||
int channel, unsigned long hwoff,
|
||||
void *buf, unsigned long bytes)
|
||||
{
|
||||
memcpy(get_dma_ptr(substream->runtime, channel, hwoff), buf, bytes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* fill silence instead of copy data; called as a transfer helper
|
||||
* from __snd_pcm_lib_write() or directly from noninterleaved_copy() when
|
||||
* a NULL buffer is passed
|
||||
*/
|
||||
static int fill_silence(struct snd_pcm_substream *substream, int channel,
|
||||
unsigned long hwoff, void *buf, unsigned long bytes)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
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)
|
||||
|
||||
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_format_set_silence(runtime->format,
|
||||
get_dma_ptr(runtime, channel, hwoff),
|
||||
bytes_to_samples(runtime, bytes));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* default copy_kernel ops for read */
|
||||
static int default_read_copy_kernel(struct snd_pcm_substream *substream,
|
||||
int channel, unsigned long hwoff,
|
||||
void *buf, unsigned long bytes)
|
||||
{
|
||||
memcpy(buf, get_dma_ptr(substream->runtime, channel, hwoff), bytes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* call transfer function with the converted pointers and sizes;
|
||||
* for interleaved mode, it's one shot for all samples
|
||||
*/
|
||||
static int interleaved_copy(struct snd_pcm_substream *substream,
|
||||
snd_pcm_uframes_t hwoff, void *data,
|
||||
snd_pcm_uframes_t off,
|
||||
snd_pcm_uframes_t frames,
|
||||
pcm_transfer_f transfer)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
|
||||
/* convert to bytes */
|
||||
hwoff = frames_to_bytes(runtime, hwoff);
|
||||
off = frames_to_bytes(runtime, off);
|
||||
frames = frames_to_bytes(runtime, frames);
|
||||
return transfer(substream, 0, hwoff, data + off, frames);
|
||||
}
|
||||
|
||||
/* call transfer function with the converted pointers and sizes for each
|
||||
* non-interleaved channel; when buffer is NULL, silencing instead of copying
|
||||
*/
|
||||
static int noninterleaved_copy(struct snd_pcm_substream *substream,
|
||||
snd_pcm_uframes_t hwoff, void *data,
|
||||
snd_pcm_uframes_t off,
|
||||
snd_pcm_uframes_t frames,
|
||||
pcm_transfer_f transfer)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
int channels = runtime->channels;
|
||||
void **bufs = data;
|
||||
int c, err;
|
||||
|
||||
/* convert to bytes; note that it's not frames_to_bytes() here.
|
||||
* in non-interleaved mode, we copy for each channel, thus
|
||||
* each copy is n_samples bytes x channels = whole frames.
|
||||
*/
|
||||
off = samples_to_bytes(runtime, off);
|
||||
frames = samples_to_bytes(runtime, frames);
|
||||
hwoff = samples_to_bytes(runtime, hwoff);
|
||||
for (c = 0; c < channels; ++c, ++bufs) {
|
||||
if (!data || !*bufs)
|
||||
err = fill_silence(substream, c, hwoff, NULL, frames);
|
||||
else
|
||||
err = transfer(substream, c, hwoff, *bufs + off,
|
||||
frames);
|
||||
if (err < 0)
|
||||
return err;
|
||||
} else {
|
||||
char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);
|
||||
if (copy_from_user(hwbuf, buf, frames_to_bytes(runtime, frames)))
|
||||
return -EFAULT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef int (*transfer_f)(struct snd_pcm_substream *substream, unsigned int hwoff,
|
||||
unsigned long data, unsigned int off,
|
||||
snd_pcm_uframes_t size);
|
||||
|
||||
static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
|
||||
unsigned long data,
|
||||
snd_pcm_uframes_t size,
|
||||
int nonblock,
|
||||
transfer_f transfer)
|
||||
/* 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)
|
||||
{
|
||||
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)
|
||||
return 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
runtime->twake = runtime->control->avail_min ? : 1;
|
||||
if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
|
||||
snd_pcm_update_hw_ptr(substream);
|
||||
avail = snd_pcm_playback_avail(runtime);
|
||||
while (size > 0) {
|
||||
snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
|
||||
snd_pcm_uframes_t cont;
|
||||
if (!avail) {
|
||||
if (nonblock) {
|
||||
err = -EAGAIN;
|
||||
goto _end_unlock;
|
||||
}
|
||||
runtime->twake = min_t(snd_pcm_uframes_t, size,
|
||||
runtime->control->avail_min ? : 1);
|
||||
err = wait_for_avail(substream, &avail);
|
||||
if (err < 0)
|
||||
goto _end_unlock;
|
||||
}
|
||||
frames = size > avail ? avail : size;
|
||||
cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
|
||||
if (frames > cont)
|
||||
frames = cont;
|
||||
if (snd_BUG_ON(!frames)) {
|
||||
runtime->twake = 0;
|
||||
snd_pcm_stream_unlock_irq(substream);
|
||||
return -EINVAL;
|
||||
}
|
||||
appl_ptr = runtime->control->appl_ptr;
|
||||
appl_ofs = appl_ptr % runtime->buffer_size;
|
||||
snd_pcm_stream_unlock_irq(substream);
|
||||
err = transfer(substream, appl_ofs, data, offset, frames);
|
||||
snd_pcm_stream_lock_irq(substream);
|
||||
if (err < 0)
|
||||
goto _end_unlock;
|
||||
switch (runtime->status->state) {
|
||||
case SNDRV_PCM_STATE_XRUN:
|
||||
err = -EPIPE;
|
||||
goto _end_unlock;
|
||||
case SNDRV_PCM_STATE_SUSPENDED:
|
||||
err = -ESTRPIPE;
|
||||
goto _end_unlock;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
appl_ptr += frames;
|
||||
if (appl_ptr >= runtime->boundary)
|
||||
appl_ptr -= runtime->boundary;
|
||||
runtime->control->appl_ptr = appl_ptr;
|
||||
if (substream->ops->ack)
|
||||
substream->ops->ack(substream);
|
||||
|
||||
offset += frames;
|
||||
size -= frames;
|
||||
xfer += frames;
|
||||
avail -= frames;
|
||||
if (runtime->status->state == SNDRV_PCM_STATE_PREPARED &&
|
||||
snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold) {
|
||||
err = snd_pcm_start(substream);
|
||||
if (err < 0)
|
||||
goto _end_unlock;
|
||||
}
|
||||
}
|
||||
_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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
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);
|
||||
trace_applptr(substream, old_appl_ptr, appl_ptr);
|
||||
|
||||
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);
|
||||
if (err < 0)
|
||||
goto _end_unlock;
|
||||
}
|
||||
break;
|
||||
case SNDRV_PCM_STATE_DRAINING:
|
||||
case SNDRV_PCM_STATE_RUNNING:
|
||||
case SNDRV_PCM_STATE_PAUSED:
|
||||
break;
|
||||
case SNDRV_PCM_STATE_XRUN:
|
||||
err = -EPIPE;
|
||||
goto _end_unlock;
|
||||
case SNDRV_PCM_STATE_SUSPENDED:
|
||||
err = -ESTRPIPE;
|
||||
goto _end_unlock;
|
||||
default:
|
||||
err = -EBADFD;
|
||||
err = pcm_accessible_state(runtime);
|
||||
if (err < 0)
|
||||
goto _end_unlock;
|
||||
|
||||
if (!is_playback &&
|
||||
runtime->status->state == SNDRV_PCM_STATE_PREPARED &&
|
||||
size >= runtime->start_threshold) {
|
||||
err = snd_pcm_start(substream);
|
||||
if (err < 0)
|
||||
goto _end_unlock;
|
||||
}
|
||||
|
||||
runtime->twake = runtime->control->avail_min ? : 1;
|
||||
if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
|
||||
snd_pcm_update_hw_ptr(substream);
|
||||
avail = snd_pcm_capture_avail(runtime);
|
||||
if (is_playback)
|
||||
avail = snd_pcm_playback_avail(runtime);
|
||||
else
|
||||
avail = snd_pcm_capture_avail(runtime);
|
||||
while (size > 0) {
|
||||
snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
|
||||
snd_pcm_uframes_t cont;
|
||||
if (!avail) {
|
||||
if (runtime->status->state ==
|
||||
SNDRV_PCM_STATE_DRAINING) {
|
||||
if (!is_playback &&
|
||||
runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
|
||||
snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
|
||||
goto _end_unlock;
|
||||
}
|
||||
|
@ -2291,7 +2204,9 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
|
|||
continue; /* draining */
|
||||
}
|
||||
frames = size > avail ? avail : size;
|
||||
cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
|
||||
appl_ptr = READ_ONCE(runtime->control->appl_ptr);
|
||||
appl_ofs = appl_ptr % runtime->buffer_size;
|
||||
cont = runtime->buffer_size - appl_ofs;
|
||||
if (frames > cont)
|
||||
frames = cont;
|
||||
if (snd_BUG_ON(!frames)) {
|
||||
|
@ -2299,34 +2214,33 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
|
|||
snd_pcm_stream_unlock_irq(substream);
|
||||
return -EINVAL;
|
||||
}
|
||||
appl_ptr = runtime->control->appl_ptr;
|
||||
appl_ofs = appl_ptr % runtime->buffer_size;
|
||||
snd_pcm_stream_unlock_irq(substream);
|
||||
err = transfer(substream, appl_ofs, data, offset, frames);
|
||||
err = writer(substream, appl_ofs, data, offset, frames,
|
||||
transfer);
|
||||
snd_pcm_stream_lock_irq(substream);
|
||||
if (err < 0)
|
||||
goto _end_unlock;
|
||||
switch (runtime->status->state) {
|
||||
case SNDRV_PCM_STATE_XRUN:
|
||||
err = -EPIPE;
|
||||
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
|
||||
|
|
|
@ -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 */
|
|
@ -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,
|
||||
|
|
|
@ -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
|
@ -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>
|
|
@ -25,6 +25,8 @@
|
|||
#include <sound/pcm.h>
|
||||
#include <sound/timer.h>
|
||||
|
||||
#include "pcm_local.h"
|
||||
|
||||
/*
|
||||
* Timer functions
|
||||
*/
|
||||
|
@ -33,8 +35,8 @@ void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream)
|
|||
{
|
||||
unsigned long rate, mult, fsize, l, post;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
|
||||
mult = 1000000000;
|
||||
|
||||
mult = 1000000000;
|
||||
rate = runtime->rate;
|
||||
if (snd_BUG_ON(!rate))
|
||||
return;
|
||||
|
@ -65,7 +67,7 @@ void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream)
|
|||
static unsigned long snd_pcm_timer_resolution(struct snd_timer * timer)
|
||||
{
|
||||
struct snd_pcm_substream *substream;
|
||||
|
||||
|
||||
substream = timer->private_data;
|
||||
return substream->runtime ? substream->runtime->timer_resolution : 0;
|
||||
}
|
||||
|
@ -73,7 +75,7 @@ static unsigned long snd_pcm_timer_resolution(struct snd_timer * timer)
|
|||
static int snd_pcm_timer_start(struct snd_timer * timer)
|
||||
{
|
||||
struct snd_pcm_substream *substream;
|
||||
|
||||
|
||||
substream = snd_timer_chip(timer);
|
||||
substream->timer_running = 1;
|
||||
return 0;
|
||||
|
@ -82,7 +84,7 @@ static int snd_pcm_timer_start(struct snd_timer * timer)
|
|||
static int snd_pcm_timer_stop(struct snd_timer * timer)
|
||||
{
|
||||
struct snd_pcm_substream *substream;
|
||||
|
||||
|
||||
substream = snd_timer_chip(timer);
|
||||
substream->timer_running = 0;
|
||||
return 0;
|
||||
|
@ -112,7 +114,7 @@ void snd_pcm_timer_init(struct snd_pcm_substream *substream)
|
|||
{
|
||||
struct snd_timer_id tid;
|
||||
struct snd_timer *timer;
|
||||
|
||||
|
||||
tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
|
||||
tid.dev_class = SNDRV_TIMER_CLASS_PCM;
|
||||
tid.card = substream->pcm->card->number;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
/*
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue