Commit 4cdd5f91 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull sound updates from Takashi Iwai:
 "Many updates in this development cycle are found in ASoC where it got
  a wide range of changes for the continued refactoring.

  Some highlights are below.

  ASoC:

   - Continued refactoring work by Morimoto-san toward the full
     componentization; the changes are seen allover the places

   - Support for force disconnecting muxes in DAPM

   - Continued development of ASoC Intel SOF stuff

   - New drivers for Cirrus Logic CS47L35, CS47L85 and CS47L90, Conexant
     CX2072X, Realtek RT1011 and RT1308

  HD-audio:

   - More fixes and adjustments for ASoC SOF HD-audio

   - Fix for resume problem on some Realtek codecs

  USB-audio:

   - A few fixes for the issues reported by syzbot USB fuzzer

   - Fix for UAC2 extension unit parser

   - Quirks for Line6 Helix, Emgaic Unitor 8

  FireWire:

   - Lots of code refactoring and fixes in most of its components"

* tag 'sound-5.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (626 commits)
  ALSA: firewire-lib: code refactoring for local variables
  ALSA: firewire-lib: code refactoring for post operation to data block counter
  ALSA: firewire-lib: code refactoring for error path of parser for CIP header
  ALSA: firewire-lib: fix different data block counter between probed event and transferred isochronous packet
  ALSA: firewire-lib: fix initial value of data block count for IR context without CIP_DBC_IS_END_EVENT
  ALSA: firewire-lib/fireface: fix initial value of data block counter for IR context with CIP_NO_HEADER
  ALSA: firewire-lib: fix invalid length of rx packet payload for tracepoint events
  ALSA: usb-audio: fix Line6 Helix audio format rates
  firewire-motu: fix wrong reference count for stream functionality at error path of rawmidi interface
  ALSA: firewire-digi00x: fix wrong reference count for stream functionality at error path of rawmidi interface
  ALSA: dice: fix wrong reference count for stream functionality at error path of rawmidi interface
  ALSA: oxfw: fix wrong reference count for stream functionality at error path of rawmidi interface
  ALSA: fireworks: fix wrong reference count for stream functionality at error path of rawmidi interface
  ALSA: bebob: fix wrong reference count for stream functionality at error path of rawmidi interface
  ASoC: SOF: Intel: implement runtime idle for CNL/APL
  ASoC: SOF: add runtime idle callback
  ASoC: hdac_hdmi: report codec link up/down status to bus
  ASoC: SOF: debug: fix possible memory leak in sof_dfsentry_write()
  ASoC: sunxi: sun50i-codec-analog: Add earpiece
  ASoC: rt5665: remove redundant assignment to variable idx
  ...
parents 2d41ef54 0dcb4efb
......@@ -11,7 +11,7 @@ Required properties:
- clock-names: must contain "mclk", which is the DCMI peripherial clock
- pinctrl: the pincontrol settings to configure muxing properly
for pins that connect to DCMI device.
See Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt.
See Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml.
- dmas: phandle to DMA controller node,
see Documentation/devicetree/bindings/dma/stm32-dma.txt
- dma-names: must contain "tx", which is the transmit channel from DCMI to DMA
......
# SPDX-License-Identifier: (GPL-2.0+ OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/allwinner,sun4i-a10-i2s.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Allwinner A10 I2S Controller Device Tree Bindings
maintainers:
- Chen-Yu Tsai <wens@csie.org>
- Maxime Ripard <maxime.ripard@bootlin.com>
properties:
"#sound-dai-cells":
const: 0
compatible:
oneOf:
- const: allwinner,sun4i-a10-i2s
- const: allwinner,sun6i-a31-i2s
- const: allwinner,sun8i-a83t-i2s
- const: allwinner,sun8i-h3-i2s
- const: allwinner,sun50i-a64-codec-i2s
- items:
- const: allwinner,sun50i-a64-i2s
- const: allwinner,sun8i-h3-i2s
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
items:
- description: Bus Clock
- description: Module Clock
clock-names:
items:
- const: apb
- const: mod
# Even though it only applies to subschemas under the conditionals,
# not listing them here will trigger a warning because of the
# additionalsProperties set to false.
dmas: true
dma-names: true
resets:
maxItems: 1
allOf:
- if:
properties:
compatible:
contains:
enum:
- allwinner,sun6i-a31-i2s
- allwinner,sun8i-a83t-i2s
- allwinner,sun8i-h3-i2s
- allwinner,sun50i-a64-codec-i2s
then:
required:
- resets
- if:
properties:
compatible:
contains:
const: allwinner,sun8i-a83t-i2s
then:
properties:
dmas:
minItems: 1
maxItems: 2
items:
- description: RX DMA Channel
- description: TX DMA Channel
description:
Some controllers cannot receive but can only transmit
data. In such a case, the RX DMA channel is to be omitted.
dma-names:
oneOf:
- items:
- const: rx
- const: tx
- const: tx
description:
Some controllers cannot receive but can only transmit
data. In such a case, the RX name is to be omitted.
else:
properties:
dmas:
items:
- description: RX DMA Channel
- description: TX DMA Channel
dma-names:
items:
- const: rx
- const: tx
required:
- "#sound-dai-cells"
- compatible
- reg
- interrupts
- clocks
- clock-names
- dmas
- dma-names
additionalProperties: false
examples:
- |
i2s0: i2s@1c22400 {
#sound-dai-cells = <0>;
compatible = "allwinner,sun4i-a10-i2s";
reg = <0x01c22400 0x400>;
interrupts = <0 16 4>;
clocks = <&apb0_gates 3>, <&i2s0_clk>;
clock-names = "apb", "mod";
dmas = <&dma 0 3>, <&dma 0 3>;
dma-names = "rx", "tx";
};
...
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/allwinner,sun4i-a10-spdif.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Allwinner A10 S/PDIF Controller Device Tree Bindings
maintainers:
- Chen-Yu Tsai <wens@csie.org>
- Liam Girdwood <lgirdwood@gmail.com>
- Mark Brown <broonie@kernel.org>
- Maxime Ripard <maxime.ripard@bootlin.com>
properties:
"#sound-dai-cells":
const: 0
compatible:
oneOf:
- const: allwinner,sun4i-a10-spdif
- const: allwinner,sun6i-a31-spdif
- const: allwinner,sun8i-h3-spdif
- const: allwinner,sun50i-h6-spdif
- items:
- const: allwinner,sun8i-a83t-spdif
- const: allwinner,sun8i-h3-spdif
- items:
- const: allwinner,sun50i-a64-spdif
- const: allwinner,sun8i-h3-spdif
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
items:
- description: Bus Clock
- description: Module Clock
clock-names:
items:
- const: apb
- const: spdif
# Even though it only applies to subschemas under the conditionals,
# not listing them here will trigger a warning because of the
# additionalsProperties set to false.
dmas: true
dma-names: true
resets:
maxItems: 1
allOf:
- if:
properties:
compatible:
contains:
enum:
- allwinner,sun6i-a31-spdif
- allwinner,sun8i-h3-spdif
then:
required:
- resets
- if:
properties:
compatible:
contains:
const: allwinner,sun8i-h3-spdif
then:
properties:
dmas:
description: TX DMA Channel
dma-names:
const: tx
else:
properties:
dmas:
items:
- description: RX DMA Channel
- description: TX DMA Channel
dma-names:
items:
- const: rx
- const: tx
required:
- "#sound-dai-cells"
- compatible
- reg
- interrupts
- clocks
- clock-names
- dmas
- dma-names
additionalProperties: false
examples:
- |
spdif: spdif@1c21000 {
#sound-dai-cells = <0>;
compatible = "allwinner,sun4i-a10-spdif";
reg = <0x01c21000 0x40>;
interrupts = <13>;
clocks = <&apb0_gates 1>, <&spdif_clk>;
clock-names = "apb", "spdif";
dmas = <&dma 0 2>, <&dma 0 2>;
dma-names = "rx", "tx";
};
...
......@@ -15,11 +15,15 @@ Required properties:
* "lrclk" : sample clock
* "lrclk_sel": sample clock input multiplexer
Example of TDMOUT_A on the A113 SoC:
Optional property:
- resets: phandle to the dedicated reset line of the tdm formatter.
Example of TDMOUT_A on the S905X2 SoC:
tdmout_a: audio-controller@500 {
compatible = "amlogic,axg-tdmout";
reg = <0x0 0x500 0x0 0x40>;
resets = <&clkc_audio AUD_RESET_TDMOUT_A>;
clocks = <&clkc_audio AUD_CLKID_TDMOUT_A>,
<&clkc_audio AUD_CLKID_TDMOUT_A_SCLK>,
<&clkc_audio AUD_CLKID_TDMOUT_A_SCLK_SEL>,
......
* Amlogic HDMI Tx control glue
Required properties:
- compatible: "amlogic,g12a-tohdmitx"
- reg: physical base address of the controller and length of memory
mapped region.
- #sound-dai-cells: should be 1.
Example on the S905X2 SoC:
tohdmitx: audio-controller@744 {
compatible = "amlogic,g12a-tohdmitx";
reg = <0x0 0x744 0x0 0x4>;
#sound-dai-cells = <1>;
};
Example of an 'amlogic,axg-sound-card':
sound {
compatible = "amlogic,axg-sound-card";
[...]
dai-link-x {
sound-dai = <&tdmif_a>;
dai-format = "i2s";
dai-tdm-slot-tx-mask-0 = <1 1>;
codec-0 {
sound-dai = <&tohdmitx TOHDMITX_I2S_IN_A>;
};
codec-1 {
sound-dai = <&external_dac>;
};
};
dai-link-y {
sound-dai = <&tdmif_c>;
dai-format = "i2s";
dai-tdm-slot-tx-mask-0 = <1 1>;
codec {
sound-dai = <&tohdmitx TOHDMITX_I2S_IN_C>;
};
};
dai-link-z {
sound-dai = <&tohdmitx TOHDMITX_I2S_OUT>;
codec {
sound-dai = <&hdmi_tx>;
};
};
};
......@@ -14,6 +14,11 @@ Required properties:
- VA-supply, VD-supply, VLS-supply, VLC-supply: power supplies for the device,
as covered in Documentation/devicetree/bindings/regulator/regulator.txt
Optional properties:
- reset-gpios : a GPIO spec to define which pin is connected to the chip's
!RESET pin
Example:
cs42888: codec@48 {
......@@ -25,4 +30,5 @@ cs42888: codec@48 {
VD-supply = <&reg_audio>;
VLS-supply = <&reg_audio>;
VLC-supply = <&reg_audio>;
reset-gpios = <&pca9557_b 1 GPIO_ACTIVE_LOW>;
};
......@@ -44,6 +44,9 @@ Optional properties:
please refer to pinctrl-bindings.txt
- fck_parent : Should contain a valid clock name which will be used as parent
for the McASP fck
- auxclk-fs-ratio: When McASP is bus master indicates the ratio between AUCLK
and FS rate if applicable:
AUCLK rate = auxclk-fs-ratio * FS rate
Optional GPIO support:
If any McASP pin need to be used as GPIO then the McASP node must have:
......
Cirrus Logic Madera class audio codecs
This describes audio configuration bindings for these codecs.
See also the core bindings for the parent MFD driver:
See Documentation/devicetree/bindings/mfd/madera.txt
and defines for values used in these bindings:
include/dt-bindings/sound/madera.h
These properties are all contained in the parent MFD node.
Optional properties:
- cirrus,dmic-ref : Indicates how the MICBIAS pins have been externally
connected to DMICs on each input, one cell per input.
<IN1 IN2 IN3 ...>
A value of 0 indicates MICVDD and is the default, other values depend on the
codec:
For CS47L35 one of the CS47L35_DMIC_REF_xxx values
For all other codecs one of the MADERA_DMIC_REF_xxx values
Also see the datasheet for a description of the INn_DMIC_SUP field.
- cirrus,inmode : A list of input mode settings for each input. A maximum of
16 cells, with four cells per input in the order INnAL, INnAR INnBL INnBR.
For non-muxed inputs the first two cells for that input set the mode for
the left and right channel and the second two cells must be 0.
For muxed inputs the first two cells for that input set the mode of the
left and right A inputs and the second two cells set the mode of the left
and right B inputs.
Valid mode values are one of the MADERA_INMODE_xxx. If the array is shorter
than the number of inputs the unspecified inputs default to
MADERA_INMODE_DIFF.
- cirrus,out-mono : Mono bit for each output, maximum of six cells if the
array is shorter outputs will be set to stereo.
- cirrus,max-channels-clocked : Maximum number of channels that I2S clocks
will be generated for. Useful when clock master for systems where the I2S
bus has multiple data lines.
One cell for each AIF, use a value of zero for AIFs that should be handled
normally.
- cirrus,pdm-fmt : PDM speaker data format, must contain 2 cells
(OUT5 and OUT6). See the PDM_SPKn_FMT field in the datasheet for a
description of this value.
The second cell is ignored for codecs that do not have OUT6.
- cirrus,pdm-mute : PDM mute format, must contain 2 cells
(OUT5 and OUT6). See the PDM_SPKn_CTRL_1 register in the datasheet for a
description of this value.
The second cell is ignored for codecs that do not have OUT6.
Example:
cs47l35@0 {
compatible = "cirrus,cs47l35";
cirrus,dmic-ref = <0 0 CS47L35_DMIC_REF_MICBIAS1B 0>;
cirrus,inmode = <
MADERA_INMODE_DMIC MADERA_INMODE_DMIC /* IN1A digital */
MADERA_INMODE_SE MADERA_INMODE_SE /* IN1B single-ended */
MADERA_INMODE_DIFF MADERA_INMODE_DIFF /* IN2 differential */
0 0 /* not used on this codec */
>;
cirrus,out-mono = <0 0 0 0 0 0>;
cirrus,max-channels-clocked = <2 0 0>;
};
......@@ -9,6 +9,10 @@ Optional properties:
- sdmode-gpios : GPIO specifier for the chip's SD_MODE pin.
If this option is not specified then driver does not manage
the pin state (e.g. chip is always on).
- sdmode-delay : specify delay time for SD_MODE pin.
If this option is specified, which means it's required i2s clocks
ready before SD_MODE is unmuted in order to avoid the speaker pop noise.
It's observed that 5ms is sufficient.
Example:
......
RT1011 Mono Class D Audio Amplifier
This device supports I2C only.
Required properties:
- compatible : "realtek,rt1011".
- reg : The I2C address of the device. This I2C address decide by
two input pins (ASEL1 and ASEL2).
-------------------------------------
| ASEL2 | ASEL1 | Address |
-------------------------------------
| 0 | 0 | 0x38 |
-------------------------------------
| 0 | 1 | 0x39 |
-------------------------------------
| 1 | 0 | 0x3a |
-------------------------------------
| 1 | 1 | 0x3b |
-------------------------------------
Pins on the device (for linking into audio routes) for RT1011:
* SPO
Example:
rt1011: codec@38 {
compatible = "realtek,rt1011";
reg = <0x38>;
};
RT1308 audio Amplifier
This device supports I2C only.
Required properties:
- compatible : "realtek,rt1308".
- reg : The I2C address of the device.
Example:
rt1308: rt1308@10 {
compatible = "realtek,rt1308";
reg = <0x10>;
};
......@@ -18,7 +18,7 @@ Required properties:
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/st,stm32-pinctrl.txt
- pinctrl-0: see Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml
Optional properties:
- resets: Reference to a reset controller asserting the reset controller
......
......@@ -41,7 +41,7 @@ SAI subnodes required properties:
"tx": if sai sub-block is configured as playback DAI
"rx": if sai sub-block is configured as capture DAI
- pinctrl-names: should contain only value "default"
- pinctrl-0: see Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt
- pinctrl-0: see Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml
SAI subnodes Optional properties:
- st,sync: specify synchronization mode.
......
* Allwinner A10 I2S controller
The I2S bus (Inter-IC sound bus) is a serial link for digital
audio data transfer between devices in the system.
Required properties:
- compatible: should be one of the following:
- "allwinner,sun4i-a10-i2s"
- "allwinner,sun6i-a31-i2s"
- "allwinner,sun8i-a83t-i2s"
- "allwinner,sun8i-h3-i2s"
- "allwinner,sun50i-a64-codec-i2s"
- reg: physical base address of the controller and length of memory mapped
region.
- interrupts: should contain the I2S interrupt.
- dmas: DMA specifiers for tx and rx dma. See the DMA client binding,
Documentation/devicetree/bindings/dma/dma.txt
- dma-names: should include "tx" and "rx".
- clocks: a list of phandle + clock-specifer pairs, one for each entry in clock-names.
- clock-names: should contain the following:
- "apb" : clock for the I2S bus interface
- "mod" : module clock for the I2S controller
- #sound-dai-cells : Must be equal to 0
Required properties for the following compatibles:
- "allwinner,sun6i-a31-i2s"
- "allwinner,sun8i-a83t-i2s"
- "allwinner,sun8i-h3-i2s"
- "allwinner,sun50i-a64-codec-i2s"
- resets: phandle to the reset line for this codec
Example:
i2s0: i2s@1c22400 {
#sound-dai-cells = <0>;
compatible = "allwinner,sun4i-a10-i2s";
reg = <0x01c22400 0x400>;
interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&apb0_gates 3>, <&i2s0_clk>;
clock-names = "apb", "mod";
dmas = <&dma SUN4I_DMA_NORMAL 3>,
<&dma SUN4I_DMA_NORMAL 3>;
dma-names = "rx", "tx";
};
Allwinner Sony/Philips Digital Interface Format (S/PDIF) Controller
The Allwinner S/PDIF audio block is a transceiver that allows the
processor to receive and transmit digital audio via an coaxial cable or
a fibre cable.
For now only playback is supported.
Required properties:
- compatible : should be one of the following:
- "allwinner,sun4i-a10-spdif": for the Allwinner A10 SoC
- "allwinner,sun6i-a31-spdif": for the Allwinner A31 SoC
- "allwinner,sun8i-h3-spdif": for the Allwinner H3 SoC
- reg : Offset and length of the register set for the device.
- interrupts : Contains the spdif interrupt.
- dmas : Generic dma devicetree binding as described in
Documentation/devicetree/bindings/dma/dma.txt.
- dma-names : Two dmas have to be defined, "tx" and "rx".
- clocks : Contains an entry for each entry in clock-names.
- clock-names : Includes the following entries:
"apb" clock for the spdif bus.
"spdif" clock for spdif controller.
- resets : reset specifier for the ahb reset (A31 and newer only)
Example:
spdif: spdif@1c21000 {
compatible = "allwinner,sun4i-a10-spdif";
reg = <0x01c21000 0x40>;
interrupts = <13>;
clocks = <&apb0_gates 1>, <&spdif_clk>;
clock-names = "apb", "spdif";
dmas = <&dma 0 2>, <&dma 0 2>;
dma-names = "rx", "tx";
};
......@@ -1297,7 +1297,7 @@ ARM PRIMECELL SSP PL022 SPI DRIVER
M: Linus Walleij <linus.walleij@linaro.org>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: Documentation/devicetree/bindings/spi/spi_pl022.txt
F: Documentation/devicetree/bindings/spi/spi-pl022.yaml
F: drivers/spi/spi-pl022.c
ARM PRIMECELL UART PL010 AND PL011 DRIVERS
......@@ -3942,13 +3942,18 @@ W: https://github.com/CirrusLogic/linux-drivers/wiki
S: Supported
F: Documentation/devicetree/bindings/mfd/madera.txt
F: Documentation/devicetree/bindings/pinctrl/cirrus,madera-pinctrl.txt
F: Documentation/devicetree/bindings/sound/madera.txt
F: include/dt-bindings/sound/madera*
F: include/linux/irqchip/irq-madera*
F: include/linux/mfd/madera/*
F: include/sound/madera*
F: drivers/gpio/gpio-madera*
F: drivers/irqchip/irq-madera*
F: drivers/mfd/madera*
F: drivers/mfd/cs47l*
F: drivers/pinctrl/cirrus/*
F: sound/soc/codecs/cs47l*
F: sound/soc/codecs/madera*
CLANG-FORMAT FILE
M: Miguel Ojeda <miguel.ojeda.sandonis@gmail.com>
......
......@@ -58,6 +58,9 @@
struct vc4_hdmi_audio {
struct snd_soc_card card;
struct snd_soc_dai_link link;
struct snd_soc_dai_link_component cpu;
struct snd_soc_dai_link_component codec;
struct snd_soc_dai_link_component platform;
int samplerate;
int channels;
struct snd_dmaengine_dai_dma_data dma_data;
......@@ -1085,12 +1088,20 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *hdmi)
return ret;
}
dai_link->cpus = &hdmi->audio.cpu;
dai_link->codecs = &hdmi->audio.codec;
dai_link->platforms = &hdmi->audio.platform;
dai_link->num_cpus = 1;
dai_link->num_codecs = 1;
dai_link->num_platforms = 1;
dai_link->name = "MAI";
dai_link->stream_name = "MAI PCM";
dai_link->codec_dai_name = vc4_hdmi_audio_codec_dai_drv.name;
dai_link->cpu_dai_name = dev_name(dev);
dai_link->codec_name = dev_name(dev);
dai_link->platform_name = dev_name(dev);
dai_link->codecs->dai_name = vc4_hdmi_audio_codec_dai_drv.name;
dai_link->cpus->dai_name = dev_name(dev);
dai_link->codecs->name = dev_name(dev);
dai_link->platforms->name = dev_name(dev);
card->dai_link = dai_link;
card->num_links = 1;
......
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Device Tree defines for Madera codecs
*
* Copyright (C) 2016-2017 Cirrus Logic, Inc. and
* Cirrus Logic International Semiconductor Ltd.
*/
#ifndef DT_BINDINGS_SOUND_MADERA_H
#define DT_BINDINGS_SOUND_MADERA_H
#define MADERA_INMODE_DIFF 0
#define MADERA_INMODE_SE 1
#define MADERA_INMODE_DMIC 2
#define MADERA_DMIC_REF_MICVDD 0
#define MADERA_DMIC_REF_MICBIAS1 1
#define MADERA_DMIC_REF_MICBIAS2 2
#define MADERA_DMIC_REF_MICBIAS3 3
#define CS47L35_DMIC_REF_MICBIAS1B 1
#define CS47L35_DMIC_REF_MICBIAS2A 2
#define CS47L35_DMIC_REF_MICBIAS2B 3
#endif
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __DT_MESON_G12A_TOHDMITX_H
#define __DT_MESON_G12A_TOHDMITX_H
#define TOHDMITX_I2S_IN_A 0
#define TOHDMITX_I2S_IN_B 1
#define TOHDMITX_I2S_IN_C 2
#define TOHDMITX_I2S_OUT 3
#define TOHDMITX_SPDIF_IN_A 4
#define TOHDMITX_SPDIF_IN_B 5
#define TOHDMITX_SPDIF_OUT 6
#endif /* __DT_MESON_G12A_TOHDMITX_H */
......@@ -16,6 +16,7 @@
#include <linux/regulator/arizona-ldo1.h>
#include <linux/regulator/arizona-micsupp.h>
#include <linux/regulator/machine.h>
#include <sound/madera-pdata.h>
#define MADERA_MAX_MICBIAS 4
#define MADERA_MAX_CHILD_MICBIAS 4
......@@ -39,6 +40,7 @@ struct madera_codec_pdata;
* @gpsw: General purpose switch mode setting. Depends on the external
* hardware connected to the switch. (See the SW1_MODE field
* in the datasheet for the available values for your codec)
* @codec: Substruct of pdata for the ASoC codec driver
*/
struct madera_pdata {
struct gpio_desc *reset;
......@@ -53,6 +55,8 @@ struct madera_pdata {
int n_gpio_configs;
u32 gpsw[MADERA_MAX_GPSW];
struct madera_codec_pdata codec;
};
#endif
......@@ -18,6 +18,9 @@
#include <sound/hda_verbs.h>
#include <sound/hda_regmap.h>
#define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98)
#define IS_CFL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa348)
/*
* Structures
*/
......@@ -268,9 +271,6 @@ struct hda_codec {
unsigned long jackpoll_interval; /* In jiffies. Zero means no poll, rely on unsol events */
struct delayed_work jackpoll_work;
/* jack detection */
struct snd_array jacks;
int depop_delay; /* depop delay in ms, -1 for default delay time */
/* fix-up list */
......
......@@ -120,7 +120,7 @@ void snd_hdac_device_unregister(struct hdac_device *codec);
int snd_hdac_device_set_chip_name(struct hdac_device *codec, const char *name);
int snd_hdac_codec_modalias(struct hdac_device *hdac, char *buf, size_t size);
int snd_hdac_refresh_widgets(struct hdac_device *codec, bool sysfs);
int snd_hdac_refresh_widgets(struct hdac_device *codec);
unsigned int snd_hdac_make_cmd(struct hdac_device *codec, hda_nid_t nid,
unsigned int verb, unsigned int parm);
......@@ -358,6 +358,9 @@ struct hdac_bus {
bool align_bdle_4k:1; /* BDLE align 4K boundary */
bool reverse_assign:1; /* assign devices in reverse order */
bool corbrp_self_clear:1; /* CORBRP clears itself after reset */
bool polling_mode:1;
int poll_count;
int bdl_pos_adj; /* BDL position adjustment */
......
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Platform data for Madera codec driver
*
* Copyright (C) 2016-2019 Cirrus Logic, Inc. and
* Cirrus Logic International Semiconductor Ltd.
*/
#ifndef MADERA_CODEC_PDATA_H
#define MADERA_CODEC_PDATA_H
#include <linux/kernel.h>
#define MADERA_MAX_INPUT 6
#define MADERA_MAX_MUXED_CHANNELS 4
#define MADERA_MAX_OUTPUT 6
#define MADERA_MAX_AIF 4
#define MADERA_MAX_PDM_SPK 2
#define MADERA_MAX_DSP 7
/**
* struct madera_codec_pdata
*
* @max_channels_clocked: Maximum number of channels that I2S clocks will be
* generated for. Useful when clock master for systems
* where the I2S bus has multiple data lines.
* @dmic_ref: Indicates how the MICBIAS pins have been externally
* connected to DMICs on each input. A value of 0
* indicates MICVDD and is the default. Other values are:
* For CS47L35 one of the CS47L35_DMIC_REF_xxx values
* For all other codecs one of the MADERA_DMIC_REF_xxx
* Also see the datasheet for a description of the
* INn_DMIC_SUP field.
* @inmode: Mode for the ADC inputs. One of the MADERA_INMODE_xxx
* values. Two-dimensional array
* [input_number][channel number], with four slots per
* input in the order
* [n][0]=INnAL [n][1]=INnAR [n][2]=INnBL [n][3]=INnBR
* @out_mono: For each output set the value to TRUE to indicate that
* the output is mono. [0]=OUT1, [1]=OUT2, ...
* @pdm_fmt: PDM speaker data format. See the PDM_SPKn_FMT field in
* the datasheet for a description of this value.
* @pdm_mute: PDM mute format. See the PDM_SPKn_CTRL_1 register
* in the datasheet for a description of this value.
*/
struct madera_codec_pdata {
u32 max_channels_clocked[MADERA_MAX_AIF];
u32 dmic_ref[MADERA_MAX_INPUT];
u32 inmode[MADERA_MAX_INPUT][MADERA_MAX_MUXED_CHANNELS];
bool out_mono[MADERA_MAX_OUTPUT];
u32 pdm_fmt[MADERA_MAX_PDM_SPK];
u32 pdm_mute[MADERA_MAX_PDM_SPK];
};
#endif
......@@ -42,6 +42,7 @@ struct asoc_simple_priv {
struct simple_dai_props {
struct asoc_simple_dai *cpu_dai;
struct asoc_simple_dai *codec_dai;
struct snd_soc_dai_link_component cpus; /* single cpu */
struct snd_soc_dai_link_component codecs; /* single codec */
struct snd_soc_dai_link_component platforms;
struct asoc_simple_data adata;
......@@ -80,16 +81,12 @@ int asoc_simple_parse_card_name(struct snd_soc_card *card,
char *prefix);
#define asoc_simple_parse_clk_cpu(dev, node, dai_link, simple_dai) \
asoc_simple_parse_clk(dev, node, dai_link->cpu_of_node, simple_dai, \
dai_link->cpu_dai_name, NULL)
asoc_simple_parse_clk(dev, node, simple_dai, dai_link->cpus)
#define asoc_simple_parse_clk_codec(dev, node, dai_link, simple_dai) \
asoc_simple_parse_clk(dev, node, dai_link->codec_of_node, simple_dai,\
dai_link->codec_dai_name, dai_link->codecs)
asoc_simple_parse_clk(dev, node, simple_dai, dai_link->codecs)
int asoc_simple_parse_clk(struct device *dev,
struct device_node *node,
struct device_node *dai_of_node,
struct asoc_simple_dai *simple_dai,
const char *dai_name,
struct snd_soc_dai_link_component *dlc);
int asoc_simple_startup(struct snd_pcm_substream *substream);
void asoc_simple_shutdown(struct snd_pcm_substream *substream);
......@@ -100,16 +97,11 @@ int asoc_simple_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params);
#define asoc_simple_parse_cpu(node, dai_link, is_single_link) \
asoc_simple_parse_dai(node, NULL, \
&dai_link->cpu_of_node, \
&dai_link->cpu_dai_name, is_single_link)
asoc_simple_parse_dai(node, dai_link->cpus, is_single_link)
#define asoc_simple_parse_codec(node, dai_link) \
asoc_simple_parse_dai(node, dai_link->codecs, \
&dai_link->codec_of_node, \
&dai_link->codec_dai_name, NULL)
asoc_simple_parse_dai(node, dai_link->codecs, NULL)
#define asoc_simple_parse_platform(node, dai_link) \
asoc_simple_parse_dai(node, dai_link->platforms, \
&dai_link->platform_of_node, NULL, NULL)
asoc_simple_parse_dai(node, dai_link->platforms, NULL)
#define asoc_simple_parse_tdm(np, dai) \
snd_soc_of_parse_tdm_slot(np, &(dai)->tx_slot_mask, \
......
......@@ -900,17 +900,6 @@ struct snd_soc_dai_link {
const char *name; /* Codec name */
const char *stream_name; /* Stream name */
/*
* cpu_name
* cpu_of_node
* cpu_dai_name
*
* These are legacy style, and will be replaced to
* modern style (= snd_soc_dai_link_component) in the future,
* but, not yet supported so far.
* If modern style was supported for CPU, all driver will switch
* to use it, and, legacy style code will be removed from ALSA SoC.
*/
/*
* You MAY specify the link's CPU-side device, either by device name,
* or by DT/OF node, but not both. If this information is omitted,
......@@ -918,57 +907,27 @@ struct snd_soc_dai_link {
* must be globally unique. These fields are currently typically used
* only for codec to codec links, or systems using device tree.
*/
const char *cpu_name;
struct device_node *cpu_of_node;
/*
* You MAY specify the DAI name of the CPU DAI. If this information is
* omitted, the CPU-side DAI is matched using .cpu_name/.cpu_of_node
* only, which only works well when that device exposes a single DAI.
*/
const char *cpu_dai_name;
struct snd_soc_dai_link_component *cpus;
unsigned int num_cpus;
/*
* codec_name
* codec_of_node
* codec_dai_name
*
* These are legacy style, it will be converted to modern style
* (= snd_soc_dai_link_component) automatically in soc-core
* if driver is using legacy style.
* Driver shouldn't use both legacy and modern style in the same time.
* If modern style was supported for CPU, all driver will switch
* to use it, and, legacy style code will be removed from ALSA SoC.
*/
/*
* You MUST specify the link's codec, either by device name, or by
* DT/OF node, but not both.
*/
const char *codec_name;
struct device_node *codec_of_node;
/* You MUST specify the DAI name within the codec */
const char *codec_dai_name;
struct snd_soc_dai_link_component *codecs;
unsigned int num_codecs;
/*
* platform_name
* platform_of_node
*
* These are legacy style, it will be converted to modern style
* (= snd_soc_dai_link_component) automatically in soc-core
* if driver is using legacy style.
* Driver shouldn't use both legacy and modern style in the same time.
* If modern style was supported for CPU, all driver will switch
* to use it, and, legacy style code will be removed from ALSA SoC.
*/
/*
* You MAY specify the link's platform/PCM/DMA driver, either by
* device name, or by DT/OF node, but not both. Some forms of link
* do not need a platform.
* do not need a platform. In such case, platforms are not mandatory.
*/
const char *platform_name;
struct device_node *platform_of_node;
struct snd_soc_dai_link_component *platforms;
unsigned int num_platforms;
......@@ -1030,12 +989,6 @@ struct snd_soc_dai_link {
/* Do not create a PCM for this DAI link (Backend link) */
unsigned int ignore:1;
/*
* This driver uses legacy platform naming. Set by the core, machine
* drivers should not modify this value.
*/
unsigned int legacy_platform:1;
struct list_head list; /* DAI link list of the soc card */
struct snd_soc_dobj dobj; /* For topology */
};
......@@ -1044,6 +997,100 @@ struct snd_soc_dai_link {
((i) < link->num_codecs) && ((codec) = &link->codecs[i]); \
(i)++)
#define for_each_link_platforms(link, i, platform) \
for ((i) = 0; \
((i) < link->num_platforms) && \
((platform) = &link->platforms[i]); \
(i)++)
/*
* Sample 1 : Single CPU/Codec/Platform
*
* SND_SOC_DAILINK_DEFS(test,
* DAILINK_COMP_ARRAY(COMP_CPU("cpu_dai")),
* DAILINK_COMP_ARRAY(COMP_CODEC("codec", "codec_dai")),
* DAILINK_COMP_ARRAY(COMP_PLATFORM("platform")));
*
* struct snd_soc_dai_link link = {
* ...
* SND_SOC_DAILINK_REG(test),
* };
*
* Sample 2 : Multi CPU/Codec, no Platform
*
* SND_SOC_DAILINK_DEFS(test,
* DAILINK_COMP_ARRAY(COMP_CPU("cpu_dai1"),
* COMP_CPU("cpu_dai2")),
* DAILINK_COMP_ARRAY(COMP_CODEC("codec1", "codec_dai1"),
* COMP_CODEC("codec2", "codec_dai2")));
*
* struct snd_soc_dai_link link = {
* ...
* SND_SOC_DAILINK_REG(test),
* };
*
* Sample 3 : Define each CPU/Codec/Platform manually
*
* SND_SOC_DAILINK_DEF(test_cpu,
* DAILINK_COMP_ARRAY(COMP_CPU("cpu_dai1"),
* COMP_CPU("cpu_dai2")));
* SND_SOC_DAILINK_DEF(test_codec,
* DAILINK_COMP_ARRAY(COMP_CODEC("codec1", "codec_dai1"),
* COMP_CODEC("codec2", "codec_dai2")));
* SND_SOC_DAILINK_DEF(test_platform,
* DAILINK_COMP_ARRAY(COMP_PLATFORM("platform")));
*
* struct snd_soc_dai_link link = {
* ...
* SND_SOC_DAILINK_REG(test_cpu,
* test_codec,
* test_platform),
* };
*
* Sample 4 : Sample3 without platform
*
* struct snd_soc_dai_link link = {
* ...
* SND_SOC_DAILINK_REG(test_cpu,
* test_codec);
* };
*/
#define SND_SOC_DAILINK_REG1(name) SND_SOC_DAILINK_REG3(name##_cpus, name##_codecs, name##_platforms)
#define SND_SOC_DAILINK_REG2(cpu, codec) SND_SOC_DAILINK_REG3(cpu, codec, null_dailink_component)
#define SND_SOC_DAILINK_REG3(cpu, codec, platform) \
.cpus = cpu, \
.num_cpus = ARRAY_SIZE(cpu), \
.codecs = codec, \
.num_codecs = ARRAY_SIZE(codec), \
.platforms = platform, \
.num_platforms = ARRAY_SIZE(platform)
#define SND_SOC_DAILINK_REGx(_1, _2, _3, func, ...) func
#define SND_SOC_DAILINK_REG(...) \
SND_SOC_DAILINK_REGx(__VA_ARGS__, \
SND_SOC_DAILINK_REG3, \
SND_SOC_DAILINK_REG2, \
SND_SOC_DAILINK_REG1)(__VA_ARGS__)
#define SND_SOC_DAILINK_DEF(name, def...) \
static struct snd_soc_dai_link_component name[] = { def }
#define SND_SOC_DAILINK_DEFS(name, cpu, codec, platform...) \
SND_SOC_DAILINK_DEF(name##_cpus, cpu); \
SND_SOC_DAILINK_DEF(name##_codecs, codec); \
SND_SOC_DAILINK_DEF(name##_platforms, platform)
#define DAILINK_COMP_ARRAY(param...) param
#define COMP_EMPTY() { }
#define COMP_CPU(_dai) { .dai_name = _dai, }
#define COMP_CODEC(_name, _dai) { .name = _name, .dai_name = _dai, }
#define COMP_PLATFORM(_name) { .name = _name }
#define COMP_DUMMY() { .name = "snd-soc-dummy", .dai_name = "snd-soc-dummy-dai", }
extern struct snd_soc_dai_link_component null_dailink_component[0];
struct snd_soc_codec_conf {
/*
* specify device either by device name, or by
......@@ -1189,7 +1236,7 @@ struct snd_soc_card {
(i)++)
#define for_each_card_links(card, link) \
list_for_each_entry(dai_link, &(card)->dai_link_list, list)
list_for_each_entry(link, &(card)->dai_link_list, list)
#define for_each_card_links_safe(card, link, _link) \
list_for_each_entry_safe(link, _link, &(card)->dai_link_list, list)
......@@ -1214,7 +1261,6 @@ struct snd_soc_pcm_runtime {
/* Dynamic PCM BE runtime data */
struct snd_soc_dpcm_runtime dpcm[2];
int fe_compr;
long pmdown_time;
......@@ -1239,6 +1285,7 @@ struct snd_soc_pcm_runtime {
/* bit field */
unsigned int dev_registered:1;
unsigned int pop_wait:1;
unsigned int fe_compr:1; /* for Dynamic PCM */
};
#define for_each_rtd_codec_dai(rtd, i, dai)\
for ((i) = 0; \
......@@ -1607,15 +1654,11 @@ int snd_soc_fixup_dai_links_platform_name(struct snd_soc_card *card,
if (!name)
return -ENOMEM;
if (dai_link->platforms)
/* only single platform is supported for now */
dai_link->platforms->name = name;
else
/*
* legacy mode, this case will be removed when all
* derivers are switched to modern style dai_link.
*/
dai_link->platform_name = name;
if (!dai_link->platforms)
return -EINVAL;
/* only single platform is supported for now */
dai_link->platforms->name = name;
}
return 0;
......
......@@ -167,9 +167,10 @@ struct sof_ipc_dai_dmic_params {
uint32_t wake_up_time; /**< Time from clock start to data (us) */
uint32_t min_clock_on_time; /**< Min. time that clk is kept on (us) */
uint32_t unmute_ramp_time; /**< Length of logarithmic gain ramp (ms) */
/* reserved for future use */
uint32_t reserved[6];
uint32_t reserved[5];
/**< variable number of pdm controller config */
struct sof_ipc_dai_dmic_pdm_ctrl pdm[0];
......
......@@ -49,6 +49,7 @@
#define SOF_IPC_GLB_DAI_MSG SOF_GLB_TYPE(0x8U)
#define SOF_IPC_GLB_TRACE_MSG SOF_GLB_TYPE(0x9U)
#define SOF_IPC_GLB_GDB_DEBUG SOF_GLB_TYPE(0xAU)
#define SOF_IPC_GLB_TEST_MSG SOF_GLB_TYPE(0xBU)
/*
* DSP Command Message Types
......@@ -99,9 +100,13 @@
#define SOF_IPC_STREAM_VORBIS_PARAMS SOF_CMD_TYPE(0x010)
#define SOF_IPC_STREAM_VORBIS_FREE SOF_CMD_TYPE(0x011)
/* trace and debug */
/* trace */
#define SOF_IPC_TRACE_DMA_PARAMS SOF_CMD_TYPE(0x001)
#define SOF_IPC_TRACE_DMA_POSITION SOF_CMD_TYPE(0x002)
#define SOF_IPC_TRACE_DMA_PARAMS_EXT SOF_CMD_TYPE(0x003)
/* debug */
#define SOF_IPC_TEST_IPC_FLOOD SOF_CMD_TYPE(0x001)
/* Get message component id */
#define SOF_IPC_MESSAGE_ID(x) ((x) & 0xffff)
......
......@@ -35,6 +35,7 @@ enum sof_comp_type {
SOF_COMP_KEYWORD_DETECT,
SOF_COMP_KPB, /* A key phrase buffer component */
SOF_COMP_SELECTOR, /**< channel selector component */
SOF_COMP_DEMUX,
/* keep FILEREAD/FILEWRITE as the last ones */
SOF_COMP_FILEREAD = 10000, /**< host test based file IO */
SOF_COMP_FILEWRITE = 10001, /**< host test based file IO */
......@@ -83,9 +84,9 @@ struct sof_ipc_buffer {
struct sof_ipc_comp_config {
struct sof_ipc_cmd_hdr hdr;
uint32_t periods_sink; /**< 0 means variable */
uint32_t periods_source; /**< 0 means variable */
uint32_t periods_source;/**< 0 means variable */
uint32_t reserved1; /**< reserved */
uint32_t frame_fmt; /**< SOF_IPC_FRAME_ */
uint32_t frame_fmt; /**< SOF_IPC_FRAME_ */
uint32_t xrun_action;
/* reserved for future use */
......@@ -175,6 +176,8 @@ enum sof_ipc_process_type {
SOF_PROCESS_KEYWORD_DETECT, /**< Keyword Detection */
SOF_PROCESS_KPB, /**< KeyPhrase Buffer Manager */
SOF_PROCESS_CHAN_SELECTOR, /**< Channel Selector */
SOF_PROCESS_MUX,
SOF_PROCESS_DEMUX,
};
/* generic "effect", "codec" or proprietary processing component */
......
......@@ -19,12 +19,22 @@
#define SOF_TRACE_FILENAME_SIZE 32
/* DMA for Trace params info - SOF_IPC_DEBUG_DMA_PARAMS */
/* Deprecated - use sof_ipc_dma_trace_params_ext */
struct sof_ipc_dma_trace_params {
struct sof_ipc_cmd_hdr hdr;
struct sof_ipc_host_buffer buffer;
uint32_t stream_tag;
} __packed;
/* DMA for Trace params info - SOF_IPC_DEBUG_DMA_PARAMS_EXT */
struct sof_ipc_dma_trace_params_ext {
struct sof_ipc_cmd_hdr hdr;
struct sof_ipc_host_buffer buffer;
uint32_t stream_tag;
uint64_t timestamp_ns; /* in nanosecond */
uint32_t reserved[8];
} __packed;
/* DMA for Trace params info - SOF_IPC_DEBUG_DMA_PARAMS */
struct sof_ipc_dma_trace_posn {
struct sof_ipc_reply rhdr;
......@@ -56,7 +66,9 @@ struct sof_ipc_dma_trace_posn {
#define SOF_IPC_PANIC_WFI (SOF_IPC_PANIC_MAGIC | 0xa)
#define SOF_IPC_PANIC_ASSERT (SOF_IPC_PANIC_MAGIC | 0xb)
/* panic info include filename and line number */
/* panic info include filename and line number
* filename array will not include null terminator if fully filled
*/
struct sof_ipc_panic_info {
struct sof_ipc_hdr hdr;
uint32_t code; /* SOF_IPC_PANIC_ */
......
......@@ -450,6 +450,43 @@ static inline __u8 *uac_processing_unit_specific(struct uac_processing_unit_desc
}
}
/*
* Extension Unit (XU) has almost compatible layout with Processing Unit, but
* on UAC2, it has a different bmControls size (bControlSize); it's 1 byte for
* XU while 2 bytes for PU. The last iExtension field is a one-byte index as
* well as iProcessing field of PU.
*/
static inline __u8 uac_extension_unit_bControlSize(struct uac_processing_unit_descriptor *desc,
int protocol)
{
switch (protocol) {
case UAC_VERSION_1:
return desc->baSourceID[desc->bNrInPins + 4];
case UAC_VERSION_2:
return 1; /* in UAC2, this value is constant */
case UAC_VERSION_3:
return 4; /* in UAC3, this value is constant */
default:
return 1;
}
}
static inline __u8 uac_extension_unit_iExtension(struct uac_processing_unit_descriptor *desc,
int protocol)
{
__u8 control_size = uac_extension_unit_bControlSize(desc, protocol);
switch (protocol) {
case UAC_VERSION_1:
case UAC_VERSION_2:
default:
return *(uac_processing_unit_bmControls(desc, protocol)
+ control_size);
case UAC_VERSION_3:
return 0; /* UAC3 does not have this field */
}
}
/* 4.5.2 Class-Specific AS Interface Descriptor */
struct uac1_as_header_descriptor {
__u8 bLength; /* in bytes: 7 */
......
......@@ -26,7 +26,7 @@
/* SOF ABI version major, minor and patch numbers */
#define SOF_ABI_MAJOR 3
#define SOF_ABI_MINOR 6
#define SOF_ABI_MINOR 8
#define SOF_ABI_PATCH 0
/* SOF ABI version number. Format within 32bit word is MMmmmppp */
......
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* Copyright(c) 2018 Intel Corporation. All rights reserved.
*/
#ifndef __INCLUDE_UAPI_SOUND_SOF_USER_EQ_H__
#define __INCLUDE_UAPI_SOUND_SOF_USER_EQ_H__
/* FIR EQ type */
#define SOF_EQ_FIR_IDX_SWITCH 0
#define SOF_EQ_FIR_MAX_SIZE 4096 /* Max size allowed for coef data in bytes */
#define SOF_EQ_FIR_MAX_LENGTH 192 /* Max length for individual filter */
#define SOF_EQ_FIR_MAX_RESPONSES 8 /* A blob can define max 8 FIR EQs */
/*
* eq_fir_configuration data structure contains this information
* uint32_t size
* This is the number of bytes need to store the received EQ
* configuration.
* uint16_t channels_in_config
* This describes the number of channels in this EQ config data. It
* can be different from PLATFORM_MAX_CHANNELS.
* uint16_t number_of_responses
* 0=no responses, 1=one response defined, 2=two responses defined, etc.
* int16_t data[]
* assign_response[channels_in_config]
* 0 = use first response, 1 = use 2nd response, etc.
* E.g. {0, 0, 0, 0, 1, 1, 1, 1} would apply to channels 0-3 the
* same first defined response and for to channels 4-7 the second.
* coef_data[]
* Repeated data
* { filter_length, output_shift, h[] }
* for every EQ response defined where vector h has filter_length
* number of coefficients. Coefficients in h[] are in Q1.15 format.
* E.g. 16384 (Q1.15) = 0.5. The shifts are number of right shifts.
*
* NOTE: The channels_in_config must be even to have coef_data aligned to
* 32 bit word in RAM. Therefore a mono EQ assign must be duplicated to 2ch
* even if it would never used. Similarly a 5ch EQ assign must be increased
* to 6ch. EQ init will return an error if this is not met.
*
* NOTE: The filter_length must be multiple of four. Therefore the filter must
* be padded from the end with zeros have this condition met.
*/
struct sof_eq_fir_config {
uint32_t size;
uint16_t channels_in_config;
uint16_t number_of_responses;
/* reserved */
uint32_t reserved[4];
int16_t data[];
} __packed;
struct sof_eq_fir_coef_data {
int16_t length; /* Number of FIR taps */
int16_t out_shift; /* Amount of right shifts at output */
/* reserved */
uint32_t reserved[4];
int16_t coef[]; /* FIR coefficients */
} __packed;
/* In the struct above there's two 16 bit words (length, shift) and four
* reserved 32 bit words before the actual FIR coefficients. This information
* is used in parsing of the configuration blob.
*/
#define SOF_EQ_FIR_COEF_NHEADER \
(sizeof(struct sof_eq_fir_coef_data) / sizeof(int16_t))
/* IIR EQ type */
#define SOF_EQ_IIR_IDX_SWITCH 0
#define SOF_EQ_IIR_MAX_SIZE 1024 /* Max size allowed for coef data in bytes */
#define SOF_EQ_IIR_MAX_RESPONSES 8 /* A blob can define max 8 IIR EQs */
/* eq_iir_configuration
* uint32_t channels_in_config
* This describes the number of channels in this EQ config data. It
* can be different from PLATFORM_MAX_CHANNELS.
* uint32_t number_of_responses_defined
* 0=no responses, 1=one response defined, 2=two responses defined, etc.
* int32_t data[]
* Data consist of two parts. First is the response assign vector that
* has length of channels_in_config. The latter part is coefficient
* data.
* uint32_t assign_response[channels_in_config]
* -1 = not defined, 0 = use first response, 1 = use 2nd, etc.
* E.g. {0, 0, 0, 0, -1, -1, -1, -1} would apply to channels 0-3 the
* same first defined response and leave channels 4-7 unequalized.
* coefficient_data[]
* <1st EQ>
* uint32_t num_biquads
* uint32_t num_biquads_in_series
* <1st biquad>
* int32_t coef_a2 Q2.30 format
* int32_t coef_a1 Q2.30 format
* int32_t coef_b2 Q2.30 format
* int32_t coef_b1 Q2.30 format
* int32_t coef_b0 Q2.30 format
* int32_t output_shift number of shifts right, shift left is negative
* int32_t output_gain Q2.14 format
* <2nd biquad>
* ...
* <2nd EQ>
*
* Note: A flat response biquad can be made with a section set to
* b0 = 1.0, gain = 1.0, and other parameters set to 0
* {0, 0, 0, 0, 1073741824, 0, 16484}
*/
struct sof_eq_iir_config {
uint32_t size;
uint32_t channels_in_config;
uint32_t number_of_responses;
/* reserved */
uint32_t reserved[4];
int32_t data[]; /* eq_assign[channels], eq 0, eq 1, ... */
} __packed;
struct sof_eq_iir_header_df2t {
uint32_t num_sections;
uint32_t num_sections_in_series;
/* reserved */
uint32_t reserved[4];
int32_t biquads[]; /* Repeated biquad coefficients */
} __packed;
struct sof_eq_iir_biquad_df2t {
int32_t a2; /* Q2.30 */
int32_t a1; /* Q2.30 */
int32_t b2; /* Q2.30 */
int32_t b1; /* Q2.30 */
int32_t b0; /* Q2.30 */
int32_t output_shift; /* Number of right shifts */
int32_t output_gain; /* Q2.14 */
} __packed;
/* A full 22th order equalizer with 11 biquads cover octave bands 1-11 in
* in the 0 - 20 kHz bandwidth.
*/
#define SOF_EQ_IIR_DF2T_BIQUADS_MAX 11
/* The number of int32_t words in sof_eq_iir_header_df2t:
* num_sections, num_sections_in_series, reserved[4]
*/
#define SOF_EQ_IIR_NHEADER_DF2T \
(sizeof(struct sof_eq_iir_header_df2t) / sizeof(int32_t))
/* The number of int32_t words in sof_eq_iir_biquad_df2t:
* a2, a1, b2, b1, b0, output_shift, output_gain
*/
#define SOF_EQ_IIR_NBIQUAD_DF2T \
(sizeof(struct sof_eq_iir_biquad_df2t) / sizeof(int32_t))
#endif
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* Copyright(c) 2018 Intel Corporation. All rights reserved.
*/
#ifndef __INCLUDE_UAPI_SOUND_SOF_USER_MANIFEST_H__
#define __INCLUDE_UAPI_SOUND_SOF_USER_MANIFEST_H__
/* start offset for base FW module */
#define SOF_MAN_ELF_TEXT_OFFSET 0x2000
/* FW Extended Manifest Header id = $AE1 */
#define SOF_MAN_EXT_HEADER_MAGIC 0x31454124
/* module type load type */
#define SOF_MAN_MOD_TYPE_BUILTIN 0
#define SOF_MAN_MOD_TYPE_MODULE 1
struct sof_man_module_type {
uint32_t load_type:4; /* SOF_MAN_MOD_TYPE_ */
uint32_t auto_start:1;
uint32_t domain_ll:1;
uint32_t domain_dp:1;
uint32_t rsvd_:25;
};
/* segment flags.type */
#define SOF_MAN_SEGMENT_TEXT 0
#define SOF_MAN_SEGMENT_RODATA 1
#define SOF_MAN_SEGMENT_DATA 1
#define SOF_MAN_SEGMENT_BSS 2
#define SOF_MAN_SEGMENT_EMPTY 15
union sof_man_segment_flags {
uint32_t ul;
struct {
uint32_t contents:1;
uint32_t alloc:1;
uint32_t load:1;
uint32_t readonly:1;
uint32_t code:1;
uint32_t data:1;
uint32_t _rsvd0:2;
uint32_t type:4; /* MAN_SEGMENT_ */
uint32_t _rsvd1:4;
uint32_t length:16; /* of segment in pages */
} r;
} __packed;
/*
* Module segment descriptor. Used by ROM - Immutable.
*/
struct sof_man_segment_desc {
union sof_man_segment_flags flags;
uint32_t v_base_addr;
uint32_t file_offset;
} __packed;
/*
* The firmware binary can be split into several modules.
*/
#define SOF_MAN_MOD_ID_LEN 4
#define SOF_MAN_MOD_NAME_LEN 8
#define SOF_MAN_MOD_SHA256_LEN 32
#define SOF_MAN_MOD_ID {'$', 'A', 'M', 'E'}
/*
* Each module has an entry in the FW header. Used by ROM - Immutable.
*/
struct sof_man_module {
uint8_t struct_id[SOF_MAN_MOD_ID_LEN]; /* SOF_MAN_MOD_ID */
uint8_t name[SOF_MAN_MOD_NAME_LEN];
uint8_t uuid[16];
struct sof_man_module_type type;
uint8_t hash[SOF_MAN_MOD_SHA256_LEN];
uint32_t entry_point;
uint16_t cfg_offset;
uint16_t cfg_count;
uint32_t affinity_mask;
uint16_t instance_max_count; /* max number of instances */
uint16_t instance_bss_size; /* instance (pages) */
struct sof_man_segment_desc segment[3];
} __packed;
/*
* Each module has a configuration in the FW header. Used by ROM - Immutable.
*/
struct sof_man_mod_config {
uint32_t par[4]; /* module parameters */
uint32_t is_pages; /* actual size of instance .bss (pages) */
uint32_t cps; /* cycles per second */
uint32_t ibs; /* input buffer size (bytes) */
uint32_t obs; /* output buffer size (bytes) */
uint32_t module_flags; /* flags, reserved for future use */
uint32_t cpc; /* cycles per single run */
uint32_t obls; /* output block size, reserved for future use */
} __packed;
/*
* FW Manifest Header
*/
#define SOF_MAN_FW_HDR_FW_NAME_LEN 8
#define SOF_MAN_FW_HDR_ID {'$', 'A', 'M', '1'}
#define SOF_MAN_FW_HDR_NAME "ADSPFW"
#define SOF_MAN_FW_HDR_FLAGS 0x0
#define SOF_MAN_FW_HDR_FEATURES 0xff
/*
* The firmware has a standard header that is checked by the ROM on firmware
* loading. preload_page_count is used by DMA code loader and is entire
* image size on CNL. i.e. CNL: total size of the binary’s .text and .rodata
* Used by ROM - Immutable.
*/
struct sof_man_fw_header {
uint8_t header_id[4];
uint32_t header_len;
uint8_t name[SOF_MAN_FW_HDR_FW_NAME_LEN];
/* number of pages of preloaded image loaded by driver */
uint32_t preload_page_count;
uint32_t fw_image_flags;
uint32_t feature_mask;
uint16_t major_version;
uint16_t minor_version;
uint16_t hotfix_version;
uint16_t build_version;
uint32_t num_module_entries;
uint32_t hw_buf_base_addr;
uint32_t hw_buf_length;
/* target address for binary loading as offset in IMR - must be == base offset */
uint32_t load_offset;
} __packed;
/*
* Firmware manifest descriptor. This can contain N modules and N module
* configs. Used by ROM - Immutable.
*/
struct sof_man_fw_desc {
struct sof_man_fw_header header;
/* Warning - hack for module arrays. For some unknown reason the we
* have a variable size array of struct man_module followed by a
* variable size array of struct mod_config. These should have been
* merged into a variable array of a parent structure. We have to hack
* around this in many places....
*
* struct sof_man_module man_module[];
* struct sof_man_mod_config mod_config[];
*/
} __packed;
/*
* Component Descriptor. Used by ROM - Immutable.
*/
struct sof_man_component_desc {
uint32_t reserved[2]; /* all 0 */
uint32_t version;
uint8_t hash[SOF_MAN_MOD_SHA256_LEN];
uint32_t base_offset;
uint32_t limit_offset;
uint32_t attributes[4];
} __packed;
/*
* Audio DSP extended metadata. Used by ROM - Immutable.
*/
struct sof_man_adsp_meta_file_ext {
uint32_t ext_type; /* always 17 for ADSP extension */
uint32_t ext_len;
uint32_t imr_type;
uint8_t reserved[16]; /* all 0 */
struct sof_man_component_desc comp_desc[1];
} __packed;
/*
* Module Manifest for rimage module metadata. Not used by ROM.
*/
struct sof_man_module_manifest {
struct sof_man_module module;
uint32_t text_size;
} __packed;
#endif
......@@ -85,6 +85,7 @@
#define SOF_TKN_INTEL_DMIC_NUM_PDM_ACTIVE 605
#define SOF_TKN_INTEL_DMIC_SAMPLE_RATE 608
#define SOF_TKN_INTEL_DMIC_FIFO_WORD_LENGTH 609
#define SOF_TKN_INTEL_DMIC_UNMUTE_RAMP_TIME_MS 610
/* DMIC PDM */
#define SOF_TKN_INTEL_DMIC_PDM_CTRL_ID 700
......
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* Copyright(c) 2018 Intel Corporation. All rights reserved.
*/
#ifndef __INCLUDE_UAPI_SOUND_SOF_USER_TONE_H__
#define __INCLUDE_UAPI_SOUND_SOF_USER_TONE_H__
#define SOF_TONE_IDX_FREQUENCY 0
#define SOF_TONE_IDX_AMPLITUDE 1
#define SOF_TONE_IDX_FREQ_MULT 2
#define SOF_TONE_IDX_AMPL_MULT 3
#define SOF_TONE_IDX_LENGTH 4
#define SOF_TONE_IDX_PERIOD 5
#define SOF_TONE_IDX_REPEATS 6
#define SOF_TONE_IDX_LIN_RAMP_STEP 7
#endif
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* Copyright(c) 2018 Intel Corporation. All rights reserved.
*/
#ifndef __INCLUDE_UAPI_SOUND_SOF_USER_TRACE_H__
#define __INCLUDE_UAPI_SOUND_SOF_USER_TRACE_H__
/*
* Host system time.
*
* This property is used by the driver to pass down information about
* current system time. It is expressed in us.
* FW translates timestamps (in log entries, probe pockets) to this time
* domain.
*
* (cavs: SystemTime).
*/
struct system_time {
uint32_t val_l; /* Lower dword of current host time value */
uint32_t val_u; /* Upper dword of current host time value */
} __packed;
#define LOG_ENABLE 1 /* Enable logging */
#define LOG_DISABLE 0 /* Disable logging */
#define LOG_LEVEL_CRITICAL 1 /* (FDK fatal) */
#define LOG_LEVEL_VERBOSE 2
/*
* Layout of a log fifo.
*/
struct log_buffer_layout {
uint32_t read_ptr; /*read pointer */
uint32_t write_ptr; /* write pointer */
uint32_t buffer[0]; /* buffer */
} __packed;
/*
* Log buffer status reported by FW.
*/
struct log_buffer_status {
uint32_t core_id; /* ID of core that logged to other half */
} __packed;
#define TRACE_ID_LENGTH 12
/*
* Log entry header.
*
* The header is followed by an array of arguments (uint32_t[]).
* Number of arguments is specified by the params_num field of log_entry
*/
struct log_entry_header {
uint32_t id_0 : TRACE_ID_LENGTH; /* e.g. Pipeline ID */
uint32_t id_1 : TRACE_ID_LENGTH; /* e.g. Component ID */
uint32_t core_id : 8; /* Reporting core's id */
uint64_t timestamp; /* Timestamp (in dsp ticks) */
uint32_t log_entry_address; /* Address of log entry in ELF */
} __packed;
#endif
......@@ -196,16 +196,12 @@ EXPORT_SYMBOL(snd_ctl_notify);
static int snd_ctl_new(struct snd_kcontrol **kctl, unsigned int count,
unsigned int access, struct snd_ctl_file *file)
{
unsigned int size;
unsigned int idx;
if (count == 0 || count > MAX_CONTROL_COUNT)
return -EINVAL;
size = sizeof(struct snd_kcontrol);
size += sizeof(struct snd_kcontrol_volatile) * count;
*kctl = kzalloc(size, GFP_KERNEL);
*kctl = kzalloc(struct_size(*kctl, vd, count), GFP_KERNEL);
if (!*kctl)
return -ENOMEM;
......
......@@ -323,8 +323,8 @@ int snd_pcm_plugin_build_rate(struct snd_pcm_substream *plug,
err = snd_pcm_plugin_build(plug, "rate conversion",
src_format, dst_format,
sizeof(struct rate_priv) +
src_format->channels * sizeof(struct rate_channel),
struct_size(data, channels,
src_format->channels),
&plugin);
if (err < 0)
return err;
......
......@@ -82,7 +82,7 @@ int amdtp_am824_set_parameters(struct amdtp_stream *s, unsigned int rate,
if (err < 0)
return err;
s->fdf = AMDTP_FDF_AM824 | s->sfc;
s->ctx_data.rx.fdf = AMDTP_FDF_AM824 | s->sfc;
p->pcm_channels = pcm_channels;
p->midi_ports = midi_ports;
......@@ -320,7 +320,7 @@ static void read_midi_messages(struct amdtp_stream *s,
u8 *b;
for (f = 0; f < frames; f++) {
port = (8 - s->tx_first_dbc + s->data_block_counter + f) % 8;
port = (8 - s->ctx_data.tx.first_dbc + s->data_block_counter + f) % 8;
b = (u8 *)&buffer[p->midi_position];
len = b[0] - 0x80;
......
......@@ -13,147 +13,16 @@
#include <linux/tracepoint.h>
TRACE_EVENT(in_packet,
TP_PROTO(const struct amdtp_stream *s, u32 cycles, u32 *cip_header, unsigned int payload_length, unsigned int index),
TP_ARGS(s, cycles, cip_header, payload_length, index),
TP_STRUCT__entry(
__field(unsigned int, second)
__field(unsigned int, cycle)
__field(int, channel)
__field(int, src)
__field(int, dest)
__field(u32, cip_header0)
__field(u32, cip_header1)
__field(unsigned int, payload_quadlets)
__field(unsigned int, packet_index)
__field(unsigned int, irq)
__field(unsigned int, index)
),
TP_fast_assign(
__entry->second = cycles / CYCLES_PER_SECOND;
__entry->cycle = cycles % CYCLES_PER_SECOND;
__entry->channel = s->context->channel;
__entry->src = fw_parent_device(s->unit)->node_id;
__entry->dest = fw_parent_device(s->unit)->card->node_id;
__entry->cip_header0 = cip_header[0];
__entry->cip_header1 = cip_header[1];
__entry->payload_quadlets = payload_length / 4;
__entry->packet_index = s->packet_index;
__entry->irq = !!in_interrupt();
__entry->index = index;
),
TP_printk(
"%02u %04u %04x %04x %02d %08x %08x %03u %02u %01u %02u",
__entry->second,
__entry->cycle,
__entry->src,
__entry->dest,
__entry->channel,
__entry->cip_header0,
__entry->cip_header1,
__entry->payload_quadlets,
__entry->packet_index,
__entry->irq,
__entry->index)
);
TRACE_EVENT(out_packet,
TP_PROTO(const struct amdtp_stream *s, u32 cycles, __be32 *cip_header, unsigned int payload_length, unsigned int index),
TP_ARGS(s, cycles, cip_header, payload_length, index),
TP_STRUCT__entry(
__field(unsigned int, second)
__field(unsigned int, cycle)
__field(int, channel)
__field(int, src)
__field(int, dest)
__field(u32, cip_header0)
__field(u32, cip_header1)
__field(unsigned int, payload_quadlets)
__field(unsigned int, packet_index)
__field(unsigned int, irq)
__field(unsigned int, index)
),
TP_fast_assign(
__entry->second = cycles / CYCLES_PER_SECOND;
__entry->cycle = cycles % CYCLES_PER_SECOND;
__entry->channel = s->context->channel;
__entry->src = fw_parent_device(s->unit)->card->node_id;
__entry->dest = fw_parent_device(s->unit)->node_id;
__entry->cip_header0 = be32_to_cpu(cip_header[0]);
__entry->cip_header1 = be32_to_cpu(cip_header[1]);
__entry->payload_quadlets = payload_length / 4;
__entry->packet_index = s->packet_index;
__entry->irq = !!in_interrupt();
__entry->index = index;
),
TP_printk(
"%02u %04u %04x %04x %02d %08x %08x %03u %02u %01u %02u",
__entry->second,
__entry->cycle,
__entry->src,
__entry->dest,
__entry->channel,
__entry->cip_header0,
__entry->cip_header1,
__entry->payload_quadlets,
__entry->packet_index,
__entry->irq,
__entry->index)
);
TRACE_EVENT(in_packet_without_header,
TP_PROTO(const struct amdtp_stream *s, u32 cycles, unsigned int payload_quadlets, unsigned int data_blocks, unsigned int index),
TP_ARGS(s, cycles, payload_quadlets, data_blocks, index),
TP_STRUCT__entry(
__field(unsigned int, second)
__field(unsigned int, cycle)
__field(int, channel)
__field(int, src)
__field(int, dest)
__field(unsigned int, payload_quadlets)
__field(unsigned int, data_blocks)
__field(unsigned int, data_block_counter)
__field(unsigned int, packet_index)
__field(unsigned int, irq)
__field(unsigned int, index)
),
TP_fast_assign(
__entry->second = cycles / CYCLES_PER_SECOND;
__entry->cycle = cycles % CYCLES_PER_SECOND;
__entry->channel = s->context->channel;
__entry->src = fw_parent_device(s->unit)->node_id;
__entry->dest = fw_parent_device(s->unit)->card->node_id;
__entry->payload_quadlets = payload_quadlets;
__entry->data_blocks = data_blocks,
__entry->data_block_counter = s->data_block_counter,
__entry->packet_index = s->packet_index;
__entry->irq = !!in_interrupt();
__entry->index = index;
),
TP_printk(
"%02u %04u %04x %04x %02d %03u %02u %03u %02u %01u %02u",
__entry->second,
__entry->cycle,
__entry->src,
__entry->dest,
__entry->channel,
__entry->payload_quadlets,
__entry->data_blocks,
__entry->data_block_counter,
__entry->packet_index,
__entry->irq,
__entry->index)
);
TRACE_EVENT(out_packet_without_header,
TP_PROTO(const struct amdtp_stream *s, u32 cycles, unsigned int payload_length, unsigned int data_blocks, unsigned int index),
TP_ARGS(s, cycles, payload_length, data_blocks, index),
TRACE_EVENT(amdtp_packet,
TP_PROTO(const struct amdtp_stream *s, u32 cycles, const __be32 *cip_header, unsigned int payload_length, unsigned int data_blocks, unsigned int index),
TP_ARGS(s, cycles, cip_header, payload_length, data_blocks, index),
TP_STRUCT__entry(
__field(unsigned int, second)
__field(unsigned int, cycle)
__field(int, channel)
__field(int, src)
__field(int, dest)
__dynamic_array(u8, cip_header, cip_header ? 8 : 0)
__field(unsigned int, payload_quadlets)
__field(unsigned int, data_blocks)
__field(unsigned int, data_block_counter)
......@@ -165,17 +34,26 @@ TRACE_EVENT(out_packet_without_header,
__entry->second = cycles / CYCLES_PER_SECOND;
__entry->cycle = cycles % CYCLES_PER_SECOND;
__entry->channel = s->context->channel;
__entry->src = fw_parent_device(s->unit)->card->node_id;
__entry->dest = fw_parent_device(s->unit)->node_id;
__entry->payload_quadlets = payload_length / 4;
__entry->data_blocks = data_blocks,
if (s->direction == AMDTP_IN_STREAM) {
__entry->src = fw_parent_device(s->unit)->node_id;
__entry->dest = fw_parent_device(s->unit)->card->node_id;
} else {
__entry->src = fw_parent_device(s->unit)->card->node_id;
__entry->dest = fw_parent_device(s->unit)->node_id;
}
if (cip_header) {
memcpy(__get_dynamic_array(cip_header), cip_header,
__get_dynamic_array_len(cip_header));
}
__entry->payload_quadlets = payload_length / sizeof(__be32);
__entry->data_blocks = data_blocks;
__entry->data_block_counter = s->data_block_counter,
__entry->packet_index = s->packet_index;
__entry->irq = !!in_interrupt();
__entry->index = index;
),
TP_printk(
"%02u %04u %04x %04x %02d %03u %02u %03u %02u %01u %02u",
"%02u %04u %04x %04x %02d %03u %02u %03u %02u %01u %02u %s",
__entry->second,
__entry->cycle,
__entry->src,
......@@ -186,7 +64,10 @@ TRACE_EVENT(out_packet_without_header,
__entry->data_block_counter,
__entry->packet_index,
__entry->irq,
__entry->index)
__entry->index,
__print_array(__get_dynamic_array(cip_header),
__get_dynamic_array_len(cip_header),
sizeof(u8)))
);
#endif
......
This diff is collapsed.
......@@ -108,10 +108,31 @@ struct amdtp_stream {
struct iso_packets_buffer buffer;
int packet_index;
int tag;
int (*handle_packet)(struct amdtp_stream *s,
unsigned int payload_quadlets, unsigned int cycle,
unsigned int index);
unsigned int max_payload_length;
union {
struct {
unsigned int ctx_header_size;
// limit for payload of iso packet.
unsigned int max_ctx_payload_length;
// For quirks of CIP headers.
// Fixed interval of dbc between previos/current
// packets.
unsigned int dbc_interval;
// Indicate the value of dbc field in a first packet.
unsigned int first_dbc;
} tx;
struct {
// To calculate CIP data blocks and tstamp.
unsigned int transfer_delay;
unsigned int data_block_state;
unsigned int last_syt_offset;
unsigned int syt_offset_state;
// To generate CIP header.
unsigned int fdf;
} rx;
} ctx_data;
/* For CIP headers. */
unsigned int source_node_id_field;
......@@ -119,19 +140,10 @@ struct amdtp_stream {
unsigned int data_block_counter;
unsigned int sph;
unsigned int fmt;
unsigned int fdf;
/* quirk: fixed interval of dbc between previos/current packets. */
unsigned int tx_dbc_interval;
/* quirk: indicate the value of dbc field in a first packet. */
unsigned int tx_first_dbc;
/* Internal flags. */
enum cip_sfc sfc;
unsigned int syt_interval;
unsigned int transfer_delay;
unsigned int data_block_state;
unsigned int last_syt_offset;
unsigned int syt_offset_state;
/* For a PCM substream processing. */
struct snd_pcm_substream *pcm;
......
......@@ -92,8 +92,6 @@ struct snd_bebob {
unsigned int midi_input_ports;
unsigned int midi_output_ports;
bool connected;
struct amdtp_stream tx_stream;
struct amdtp_stream rx_stream;
struct cmp_connection out_conn;
......@@ -217,7 +215,8 @@ int snd_bebob_stream_get_clock_src(struct snd_bebob *bebob,
enum snd_bebob_clock_type *src);
int snd_bebob_stream_discover(struct snd_bebob *bebob);
int snd_bebob_stream_init_duplex(struct snd_bebob *bebob);
int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, unsigned int rate);
int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate);
int snd_bebob_stream_start_duplex(struct snd_bebob *bebob);
void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob);
void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob);
......
......@@ -7,58 +7,31 @@
#include "bebob.h"
static int midi_capture_open(struct snd_rawmidi_substream *substream)
static int midi_open(struct snd_rawmidi_substream *substream)
{
struct snd_bebob *bebob = substream->rmidi->private_data;
int err;
err = snd_bebob_stream_lock_try(bebob);
if (err < 0)
goto end;
return err;
mutex_lock(&bebob->mutex);
bebob->substreams_counter++;
err = snd_bebob_stream_start_duplex(bebob, 0);
err = snd_bebob_stream_reserve_duplex(bebob, 0);
if (err >= 0) {
++bebob->substreams_counter;
err = snd_bebob_stream_start_duplex(bebob);
if (err < 0)
--bebob->substreams_counter;
}
mutex_unlock(&bebob->mutex);
if (err < 0)
snd_bebob_stream_lock_release(bebob);
end:
return err;
}
static int midi_playback_open(struct snd_rawmidi_substream *substream)
{
struct snd_bebob *bebob = substream->rmidi->private_data;
int err;
err = snd_bebob_stream_lock_try(bebob);
if (err < 0)
goto end;
mutex_lock(&bebob->mutex);
bebob->substreams_counter++;
err = snd_bebob_stream_start_duplex(bebob, 0);
mutex_unlock(&bebob->mutex);
if (err < 0)
snd_bebob_stream_lock_release(bebob);
end:
return err;
}
static int midi_capture_close(struct snd_rawmidi_substream *substream)
{
struct snd_bebob *bebob = substream->rmidi->private_data;
mutex_lock(&bebob->mutex);
bebob->substreams_counter--;
snd_bebob_stream_stop_duplex(bebob);
mutex_unlock(&bebob->mutex);
snd_bebob_stream_lock_release(bebob);
return 0;
}
static int midi_playback_close(struct snd_rawmidi_substream *substream)
static int midi_close(struct snd_rawmidi_substream *substream)
{
struct snd_bebob *bebob = substream->rmidi->private_data;
......@@ -120,13 +93,13 @@ static void set_midi_substream_names(struct snd_bebob *bebob,
int snd_bebob_create_midi_devices(struct snd_bebob *bebob)
{
static const struct snd_rawmidi_ops capture_ops = {
.open = midi_capture_open,
.close = midi_capture_close,
.open = midi_open,
.close = midi_close,
.trigger = midi_capture_trigger,
};
static const struct snd_rawmidi_ops playback_ops = {
.open = midi_playback_open,
.close = midi_playback_close,
.open = midi_open,
.close = midi_close,
.trigger = midi_playback_trigger,
};
struct snd_rawmidi *rmidi;
......
......@@ -184,9 +184,8 @@ pcm_close(struct snd_pcm_substream *substream)
return 0;
}
static int
pcm_capture_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
static int pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
struct snd_bebob *bebob = substream->private_data;
int err;
......@@ -197,62 +196,31 @@ pcm_capture_hw_params(struct snd_pcm_substream *substream,
return err;
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
mutex_lock(&bebob->mutex);
bebob->substreams_counter++;
mutex_unlock(&bebob->mutex);
}
unsigned int rate = params_rate(hw_params);
return 0;
}
static int
pcm_playback_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
struct snd_bebob *bebob = substream->private_data;
int err;
err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
params_buffer_bytes(hw_params));
if (err < 0)
return err;
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
mutex_lock(&bebob->mutex);
bebob->substreams_counter++;
err = snd_bebob_stream_reserve_duplex(bebob, rate);
if (err >= 0)
++bebob->substreams_counter;
mutex_unlock(&bebob->mutex);
}
return 0;
return err;
}
static int
pcm_capture_hw_free(struct snd_pcm_substream *substream)
static int pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_bebob *bebob = substream->private_data;
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) {
mutex_lock(&bebob->mutex);
bebob->substreams_counter--;
mutex_unlock(&bebob->mutex);
}
snd_bebob_stream_stop_duplex(bebob);
mutex_lock(&bebob->mutex);
return snd_pcm_lib_free_vmalloc_buffer(substream);
}
static int
pcm_playback_hw_free(struct snd_pcm_substream *substream)
{
struct snd_bebob *bebob = substream->private_data;
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) {
mutex_lock(&bebob->mutex);
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
bebob->substreams_counter--;
mutex_unlock(&bebob->mutex);
}
snd_bebob_stream_stop_duplex(bebob);
mutex_unlock(&bebob->mutex);
return snd_pcm_lib_free_vmalloc_buffer(substream);
}
......@@ -260,10 +228,9 @@ static int
pcm_capture_prepare(struct snd_pcm_substream *substream)
{
struct snd_bebob *bebob = substream->private_data;
struct snd_pcm_runtime *runtime = substream->runtime;
int err;
err = snd_bebob_stream_start_duplex(bebob, runtime->rate);
err = snd_bebob_stream_start_duplex(bebob);
if (err >= 0)
amdtp_stream_pcm_prepare(&bebob->tx_stream);
......@@ -273,10 +240,9 @@ static int
pcm_playback_prepare(struct snd_pcm_substream *substream)
{
struct snd_bebob *bebob = substream->private_data;
struct snd_pcm_runtime *runtime = substream->runtime;
int err;
err = snd_bebob_stream_start_duplex(bebob, runtime->rate);
err = snd_bebob_stream_start_duplex(bebob);
if (err >= 0)
amdtp_stream_pcm_prepare(&bebob->rx_stream);
......@@ -353,8 +319,8 @@ int snd_bebob_create_pcm_devices(struct snd_bebob *bebob)
.open = pcm_open,
.close = pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = pcm_capture_hw_params,
.hw_free = pcm_capture_hw_free,
.hw_params = pcm_hw_params,
.hw_free = pcm_hw_free,
.prepare = pcm_capture_prepare,
.trigger = pcm_capture_trigger,
.pointer = pcm_capture_pointer,
......@@ -365,8 +331,8 @@ int snd_bebob_create_pcm_devices(struct snd_bebob *bebob)
.open = pcm_open,
.close = pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = pcm_playback_hw_params,
.hw_free = pcm_playback_hw_free,
.hw_params = pcm_hw_params,
.hw_free = pcm_hw_free,
.prepare = pcm_playback_prepare,
.trigger = pcm_playback_trigger,
.pointer = pcm_playback_pointer,
......
This diff is collapsed.
......@@ -185,6 +185,37 @@ void cmp_connection_destroy(struct cmp_connection *c)
}
EXPORT_SYMBOL(cmp_connection_destroy);
int cmp_connection_reserve(struct cmp_connection *c,
unsigned int max_payload_bytes)
{
int err;
mutex_lock(&c->mutex);
if (WARN_ON(c->resources.allocated)) {
err = -EBUSY;
goto end;
}
c->speed = min(c->max_speed,
fw_parent_device(c->resources.unit)->max_speed);
err = fw_iso_resources_allocate(&c->resources, max_payload_bytes,
c->speed);
end:
mutex_unlock(&c->mutex);
return err;
}
EXPORT_SYMBOL(cmp_connection_reserve);
void cmp_connection_release(struct cmp_connection *c)
{
mutex_lock(&c->mutex);
fw_iso_resources_free(&c->resources);
mutex_unlock(&c->mutex);
}
EXPORT_SYMBOL(cmp_connection_release);
static __be32 ipcr_set_modify(struct cmp_connection *c, __be32 ipcr)
{
......@@ -270,25 +301,18 @@ static int pcr_set_check(struct cmp_connection *c, __be32 pcr)
* When this function succeeds, the caller is responsible for starting
* transmitting packets.
*/
int cmp_connection_establish(struct cmp_connection *c,
unsigned int max_payload_bytes)
int cmp_connection_establish(struct cmp_connection *c)
{
int err;
if (WARN_ON(c->connected))
return -EISCONN;
c->speed = min(c->max_speed,
fw_parent_device(c->resources.unit)->max_speed);
mutex_lock(&c->mutex);
retry_after_bus_reset:
err = fw_iso_resources_allocate(&c->resources,
max_payload_bytes, c->speed);
if (err < 0)
goto err_mutex;
if (WARN_ON(c->connected)) {
mutex_unlock(&c->mutex);
return -EISCONN;
}
retry_after_bus_reset:
if (c->direction == CMP_OUTPUT)
err = pcr_modify(c, opcr_set_modify, pcr_set_check,
ABORT_ON_BUS_RESET);
......@@ -297,21 +321,13 @@ int cmp_connection_establish(struct cmp_connection *c,
ABORT_ON_BUS_RESET);
if (err == -EAGAIN) {
fw_iso_resources_free(&c->resources);
goto retry_after_bus_reset;
err = fw_iso_resources_update(&c->resources);
if (err >= 0)
goto retry_after_bus_reset;
}
if (err < 0)
goto err_resources;
c->connected = true;
mutex_unlock(&c->mutex);
return 0;
if (err >= 0)
c->connected = true;
err_resources:
fw_iso_resources_free(&c->resources);
err_mutex:
mutex_unlock(&c->mutex);
return err;
......@@ -351,14 +367,12 @@ int cmp_connection_update(struct cmp_connection *c)
SUCCEED_ON_BUS_RESET);
if (err < 0)
goto err_resources;
goto err_unconnect;
mutex_unlock(&c->mutex);
return 0;
err_resources:
fw_iso_resources_free(&c->resources);
err_unconnect:
c->connected = false;
mutex_unlock(&c->mutex);
......@@ -395,8 +409,6 @@ void cmp_connection_break(struct cmp_connection *c)
if (err < 0)
cmp_error(c, "plug is still connected\n");
fw_iso_resources_free(&c->resources);
c->connected = false;
mutex_unlock(&c->mutex);
......
......@@ -42,8 +42,11 @@ int cmp_connection_init(struct cmp_connection *connection,
int cmp_connection_check_used(struct cmp_connection *connection, bool *used);
void cmp_connection_destroy(struct cmp_connection *connection);
int cmp_connection_establish(struct cmp_connection *connection,
unsigned int max_payload);
int cmp_connection_reserve(struct cmp_connection *connection,
unsigned int max_payload);
void cmp_connection_release(struct cmp_connection *connection);
int cmp_connection_establish(struct cmp_connection *connection);
int cmp_connection_update(struct cmp_connection *connection);
void cmp_connection_break(struct cmp_connection *connection);
......
# SPDX-License-Identifier: GPL-2.0-only
snd-dice-objs := dice-transaction.o dice-stream.o dice-proc.o dice-midi.o \
dice-pcm.o dice-hwdep.o dice.o dice-tcelectronic.o \
dice-alesis.o dice-extension.o dice-mytek.o
dice-alesis.o dice-extension.o dice-mytek.o dice-presonus.o
obj-$(CONFIG_SND_DICE) += snd-dice.o
......@@ -17,8 +17,13 @@ static int midi_open(struct snd_rawmidi_substream *substream)
mutex_lock(&dice->mutex);
dice->substreams_counter++;
err = snd_dice_stream_start_duplex(dice, 0);
err = snd_dice_stream_reserve_duplex(dice, 0);
if (err >= 0) {
++dice->substreams_counter;
err = snd_dice_stream_start_duplex(dice);
if (err < 0)
--dice->substreams_counter;
}
mutex_unlock(&dice->mutex);
......@@ -34,7 +39,7 @@ static int midi_close(struct snd_rawmidi_substream *substream)
mutex_lock(&dice->mutex);
dice->substreams_counter--;
--dice->substreams_counter;
snd_dice_stream_stop_duplex(dice);
mutex_unlock(&dice->mutex);
......
......@@ -230,8 +230,8 @@ static int pcm_close(struct snd_pcm_substream *substream)
return 0;
}
static int capture_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
static int pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
struct snd_dice *dice = substream->private_data;
int err;
......@@ -242,57 +242,26 @@ static int capture_hw_params(struct snd_pcm_substream *substream,
return err;
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
mutex_lock(&dice->mutex);
dice->substreams_counter++;
mutex_unlock(&dice->mutex);
}
return 0;
}
static int playback_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
struct snd_dice *dice = substream->private_data;
int err;
err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
params_buffer_bytes(hw_params));
if (err < 0)
return err;
unsigned int rate = params_rate(hw_params);
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
mutex_lock(&dice->mutex);
dice->substreams_counter++;
err = snd_dice_stream_reserve_duplex(dice, rate);
if (err >= 0)
++dice->substreams_counter;
mutex_unlock(&dice->mutex);
}
return 0;
}
static int capture_hw_free(struct snd_pcm_substream *substream)
{
struct snd_dice *dice = substream->private_data;
mutex_lock(&dice->mutex);
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
dice->substreams_counter--;
snd_dice_stream_stop_duplex(dice);
mutex_unlock(&dice->mutex);
return snd_pcm_lib_free_vmalloc_buffer(substream);
return err;
}
static int playback_hw_free(struct snd_pcm_substream *substream)
static int pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_dice *dice = substream->private_data;
mutex_lock(&dice->mutex);
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
dice->substreams_counter--;
--dice->substreams_counter;
snd_dice_stream_stop_duplex(dice);
......@@ -308,7 +277,7 @@ static int capture_prepare(struct snd_pcm_substream *substream)
int err;
mutex_lock(&dice->mutex);
err = snd_dice_stream_start_duplex(dice, substream->runtime->rate);
err = snd_dice_stream_start_duplex(dice);
mutex_unlock(&dice->mutex);
if (err >= 0)
amdtp_stream_pcm_prepare(stream);
......@@ -322,7 +291,7 @@ static int playback_prepare(struct snd_pcm_substream *substream)
int err;
mutex_lock(&dice->mutex);
err = snd_dice_stream_start_duplex(dice, substream->runtime->rate);
err = snd_dice_stream_start_duplex(dice);
mutex_unlock(&dice->mutex);
if (err >= 0)
amdtp_stream_pcm_prepare(stream);
......@@ -404,8 +373,8 @@ int snd_dice_create_pcm(struct snd_dice *dice)
.open = pcm_open,
.close = pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = capture_hw_params,
.hw_free = capture_hw_free,
.hw_params = pcm_hw_params,
.hw_free = pcm_hw_free,
.prepare = capture_prepare,
.trigger = capture_trigger,
.pointer = capture_pointer,
......@@ -416,8 +385,8 @@ int snd_dice_create_pcm(struct snd_dice *dice)
.open = pcm_open,
.close = pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = playback_hw_params,
.hw_free = playback_hw_free,
.hw_params = pcm_hw_params,
.hw_free = pcm_hw_free,
.prepare = playback_prepare,
.trigger = playback_trigger,
.pointer = playback_pointer,
......
// SPDX-License-Identifier: GPL-2.0
// dice-presonus.c - a part of driver for DICE based devices
//
// Copyright (c) 2019 Takashi Sakamoto
//
// Licensed under the terms of the GNU General Public License, version 2.
#include "dice.h"
struct dice_presonus_spec {
unsigned int tx_pcm_chs[MAX_STREAMS][SND_DICE_RATE_MODE_COUNT];
unsigned int rx_pcm_chs[MAX_STREAMS][SND_DICE_RATE_MODE_COUNT];
bool has_midi;
};
static const struct dice_presonus_spec dice_presonus_firesutio = {
.tx_pcm_chs = {{16, 16, 0}, {10, 2, 0} },
.rx_pcm_chs = {{16, 16, 0}, {10, 2, 0} },
.has_midi = true,
};
int snd_dice_detect_presonus_formats(struct snd_dice *dice)
{
static const struct {
u32 model_id;
const struct dice_presonus_spec *spec;
} *entry, entries[] = {
{0x000008, &dice_presonus_firesutio},
};
struct fw_csr_iterator it;
int key, val, model_id;
int i;
model_id = 0;
fw_csr_iterator_init(&it, dice->unit->directory);
while (fw_csr_iterator_next(&it, &key, &val)) {
if (key == CSR_MODEL) {
model_id = val;
break;
}
}
for (i = 0; i < ARRAY_SIZE(entries); ++i) {
entry = entries + i;
if (entry->model_id == model_id)
break;
}
if (i == ARRAY_SIZE(entries))
return -ENODEV;
memcpy(dice->tx_pcm_chs, entry->spec->tx_pcm_chs,
MAX_STREAMS * SND_DICE_RATE_MODE_COUNT * sizeof(unsigned int));
memcpy(dice->rx_pcm_chs, entry->spec->rx_pcm_chs,
MAX_STREAMS * SND_DICE_RATE_MODE_COUNT * sizeof(unsigned int));
if (entry->spec->has_midi) {
dice->tx_midi_ports[0] = 1;
dice->rx_midi_ports[0] = 1;
}
return 0;
}
This diff is collapsed.
......@@ -19,6 +19,7 @@ MODULE_LICENSE("GPL v2");
#define OUI_MAUDIO 0x000d6c
#define OUI_MYTEK 0x001ee8
#define OUI_SSL 0x0050c2 // Actually ID reserved by IEEE.
#define OUI_PRESONUS 0x000a92
#define DICE_CATEGORY_ID 0x04
#define WEISS_CATEGORY_ID 0x00
......@@ -371,6 +372,14 @@ static const struct ieee1394_device_id dice_id_table[] = {
.vendor_id = OUI_SSL,
.model_id = 0x000070,
},
// Presonus FireStudio.
{
.match_flags = IEEE1394_MATCH_VENDOR_ID |
IEEE1394_MATCH_MODEL_ID,
.vendor_id = OUI_PRESONUS,
.model_id = 0x000008,
.driver_data = (kernel_ulong_t)snd_dice_detect_presonus_formats,
},
{
.match_flags = IEEE1394_MATCH_VERSION,
.version = DICE_INTERFACE,
......
......@@ -204,10 +204,11 @@ extern const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT];
int snd_dice_stream_get_rate_mode(struct snd_dice *dice, unsigned int rate,
enum snd_dice_rate_mode *mode);
int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate);
int snd_dice_stream_start_duplex(struct snd_dice *dice);
void snd_dice_stream_stop_duplex(struct snd_dice *dice);
int snd_dice_stream_init_duplex(struct snd_dice *dice);
void snd_dice_stream_destroy_duplex(struct snd_dice *dice);
int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate);
void snd_dice_stream_update_duplex(struct snd_dice *dice);
int snd_dice_stream_detect_current_formats(struct snd_dice *dice);
......@@ -226,5 +227,6 @@ int snd_dice_detect_tcelectronic_formats(struct snd_dice *dice);
int snd_dice_detect_alesis_formats(struct snd_dice *dice);
int snd_dice_detect_extension_formats(struct snd_dice *dice);
int snd_dice_detect_mytek_formats(struct snd_dice *dice);
int snd_dice_detect_presonus_formats(struct snd_dice *dice);
#endif
......@@ -127,7 +127,7 @@ int amdtp_dot_set_parameters(struct amdtp_stream *s, unsigned int rate,
if (err < 0)
return err;
s->fdf = AMDTP_FDF_AM824 | s->sfc;
s->ctx_data.rx.fdf = AMDTP_FDF_AM824 | s->sfc;
p->pcm_channels = pcm_channels;
......
......@@ -17,8 +17,13 @@ static int midi_open(struct snd_rawmidi_substream *substream)
return err;
mutex_lock(&dg00x->mutex);
dg00x->substreams_counter++;
err = snd_dg00x_stream_start_duplex(dg00x, 0);
err = snd_dg00x_stream_reserve_duplex(dg00x, 0);
if (err >= 0) {
++dg00x->substreams_counter;
err = snd_dg00x_stream_start_duplex(dg00x);
if (err < 0)
--dg00x->substreams_counter;
}
mutex_unlock(&dg00x->mutex);
if (err < 0)
snd_dg00x_stream_lock_release(dg00x);
......@@ -31,7 +36,7 @@ static int midi_close(struct snd_rawmidi_substream *substream)
struct snd_dg00x *dg00x = substream->rmidi->private_data;
mutex_lock(&dg00x->mutex);
dg00x->substreams_counter--;
--dg00x->substreams_counter;
snd_dg00x_stream_stop_duplex(dg00x);
mutex_unlock(&dg00x->mutex);
......
......@@ -154,8 +154,8 @@ static int pcm_close(struct snd_pcm_substream *substream)
return 0;
}
static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
static int pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
struct snd_dg00x *dg00x = substream->private_data;
int err;
......@@ -166,58 +166,26 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
return err;
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
mutex_lock(&dg00x->mutex);
dg00x->substreams_counter++;
mutex_unlock(&dg00x->mutex);
}
unsigned int rate = params_rate(hw_params);
return 0;
}
static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
struct snd_dg00x *dg00x = substream->private_data;
int err;
err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
params_buffer_bytes(hw_params));
if (err < 0)
return err;
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
mutex_lock(&dg00x->mutex);
dg00x->substreams_counter++;
err = snd_dg00x_stream_reserve_duplex(dg00x, rate);
if (err >= 0)
++dg00x->substreams_counter;
mutex_unlock(&dg00x->mutex);
}
return 0;
}
static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
{
struct snd_dg00x *dg00x = substream->private_data;
mutex_lock(&dg00x->mutex);
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
dg00x->substreams_counter--;
snd_dg00x_stream_stop_duplex(dg00x);
mutex_unlock(&dg00x->mutex);
return snd_pcm_lib_free_vmalloc_buffer(substream);
return err;
}
static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
static int pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_dg00x *dg00x = substream->private_data;
mutex_lock(&dg00x->mutex);
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
dg00x->substreams_counter--;
--dg00x->substreams_counter;
snd_dg00x_stream_stop_duplex(dg00x);
......@@ -229,12 +197,11 @@ static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
static int pcm_capture_prepare(struct snd_pcm_substream *substream)
{
struct snd_dg00x *dg00x = substream->private_data;
struct snd_pcm_runtime *runtime = substream->runtime;
int err;
mutex_lock(&dg00x->mutex);
err = snd_dg00x_stream_start_duplex(dg00x, runtime->rate);
err = snd_dg00x_stream_start_duplex(dg00x);
if (err >= 0)
amdtp_stream_pcm_prepare(&dg00x->tx_stream);
......@@ -246,12 +213,11 @@ static int pcm_capture_prepare(struct snd_pcm_substream *substream)
static int pcm_playback_prepare(struct snd_pcm_substream *substream)
{
struct snd_dg00x *dg00x = substream->private_data;
struct snd_pcm_runtime *runtime = substream->runtime;
int err;
mutex_lock(&dg00x->mutex);
err = snd_dg00x_stream_start_duplex(dg00x, runtime->rate);
err = snd_dg00x_stream_start_duplex(dg00x);
if (err >= 0) {
amdtp_stream_pcm_prepare(&dg00x->rx_stream);
amdtp_dot_reset(&dg00x->rx_stream);
......@@ -332,8 +298,8 @@ int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x)
.open = pcm_open,
.close = pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = pcm_capture_hw_params,
.hw_free = pcm_capture_hw_free,
.hw_params = pcm_hw_params,
.hw_free = pcm_hw_free,
.prepare = pcm_capture_prepare,
.trigger = pcm_capture_trigger,
.pointer = pcm_capture_pointer,
......@@ -344,8 +310,8 @@ int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x)
.open = pcm_open,
.close = pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = pcm_playback_hw_params,
.hw_free = pcm_playback_hw_free,
.hw_params = pcm_hw_params,
.hw_free = pcm_hw_free,
.prepare = pcm_playback_prepare,
.trigger = pcm_playback_trigger,
.pointer = pcm_playback_pointer,
......
......@@ -124,11 +124,25 @@ int snd_dg00x_stream_get_external_rate(struct snd_dg00x *dg00x,
static void finish_session(struct snd_dg00x *dg00x)
{
__be32 data = cpu_to_be32(0x00000003);
__be32 data;
amdtp_stream_stop(&dg00x->tx_stream);
amdtp_stream_stop(&dg00x->rx_stream);
data = cpu_to_be32(0x00000003);
snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
DG00X_ADDR_BASE + DG00X_OFFSET_STREAMING_SET,
&data, sizeof(data), 0);
// Unregister isochronous channels for both direction.
data = 0;
snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
&data, sizeof(data), 0);
// Just after finishing the session, the device may lost transmitting
// functionality for a short time.
msleep(50);
}
static int begin_session(struct snd_dg00x *dg00x)
......@@ -137,11 +151,20 @@ static int begin_session(struct snd_dg00x *dg00x)
u32 curr;
int err;
// Register isochronous channels for both direction.
data = cpu_to_be32((dg00x->tx_resources.channel << 16) |
dg00x->rx_resources.channel);
err = snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
&data, sizeof(data), 0);
if (err < 0)
return err;
err = snd_fw_transaction(dg00x->unit, TCODE_READ_QUADLET_REQUEST,
DG00X_ADDR_BASE + DG00X_OFFSET_STREAMING_STATE,
&data, sizeof(data), 0);
if (err < 0)
goto error;
return err;
curr = be32_to_cpu(data);
if (curr == 0)
......@@ -156,39 +179,23 @@ static int begin_session(struct snd_dg00x *dg00x)
DG00X_OFFSET_STREAMING_SET,
&data, sizeof(data), 0);
if (err < 0)
goto error;
break;
msleep(20);
curr--;
}
return 0;
error:
finish_session(dg00x);
return err;
}
static void release_resources(struct snd_dg00x *dg00x)
static int keep_resources(struct snd_dg00x *dg00x, struct amdtp_stream *stream,
unsigned int rate)
{
__be32 data = 0;
/* Unregister isochronous channels for both direction. */
snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
&data, sizeof(data), 0);
/* Release isochronous resources. */
fw_iso_resources_free(&dg00x->tx_resources);
fw_iso_resources_free(&dg00x->rx_resources);
}
static int keep_resources(struct snd_dg00x *dg00x, unsigned int rate)
{
unsigned int i;
__be32 data;
struct fw_iso_resources *resources;
int i;
int err;
/* Check sampling rate. */
// Check sampling rate.
for (i = 0; i < SND_DG00X_RATE_COUNT; i++) {
if (snd_dg00x_stream_rates[i] == rate)
break;
......@@ -196,41 +203,19 @@ static int keep_resources(struct snd_dg00x *dg00x, unsigned int rate)
if (i == SND_DG00X_RATE_COUNT)
return -EINVAL;
/* Keep resources for out-stream. */
err = amdtp_dot_set_parameters(&dg00x->rx_stream, rate,
snd_dg00x_stream_pcm_channels[i]);
if (err < 0)
return err;
err = fw_iso_resources_allocate(&dg00x->rx_resources,
amdtp_stream_get_max_payload(&dg00x->rx_stream),
fw_parent_device(dg00x->unit)->max_speed);
if (err < 0)
return err;
if (stream == &dg00x->tx_stream)
resources = &dg00x->tx_resources;
else
resources = &dg00x->rx_resources;
/* Keep resources for in-stream. */
err = amdtp_dot_set_parameters(&dg00x->tx_stream, rate,
err = amdtp_dot_set_parameters(stream, rate,
snd_dg00x_stream_pcm_channels[i]);
if (err < 0)
return err;
err = fw_iso_resources_allocate(&dg00x->tx_resources,
amdtp_stream_get_max_payload(&dg00x->tx_stream),
fw_parent_device(dg00x->unit)->max_speed);
if (err < 0)
goto error;
/* Register isochronous channels for both direction. */
data = cpu_to_be32((dg00x->tx_resources.channel << 16) |
dg00x->rx_resources.channel);
err = snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST,
DG00X_ADDR_BASE + DG00X_OFFSET_ISOC_CHANNELS,
&data, sizeof(data), 0);
if (err < 0)
goto error;
return 0;
error:
release_resources(dg00x);
return err;
return fw_iso_resources_allocate(resources,
amdtp_stream_get_max_payload(stream),
fw_parent_device(dg00x->unit)->max_speed);
}
int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x)
......@@ -272,43 +257,68 @@ void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x)
fw_iso_resources_destroy(&dg00x->tx_resources);
}
int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x, unsigned int rate)
int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate)
{
unsigned int curr_rate;
int err = 0;
if (dg00x->substreams_counter == 0)
goto end;
int err;
/* Check current sampling rate. */
err = snd_dg00x_stream_get_local_rate(dg00x, &curr_rate);
if (err < 0)
goto error;
return err;
if (rate == 0)
rate = curr_rate;
if (curr_rate != rate ||
amdtp_streaming_error(&dg00x->tx_stream) ||
amdtp_streaming_error(&dg00x->rx_stream)) {
if (dg00x->substreams_counter == 0 || curr_rate != rate) {
finish_session(dg00x);
amdtp_stream_stop(&dg00x->tx_stream);
amdtp_stream_stop(&dg00x->rx_stream);
release_resources(dg00x);
}
fw_iso_resources_free(&dg00x->tx_resources);
fw_iso_resources_free(&dg00x->rx_resources);
/*
* No packets are transmitted without receiving packets, reagardless of
* which source of clock is used.
*/
if (!amdtp_stream_running(&dg00x->rx_stream)) {
err = snd_dg00x_stream_set_local_rate(dg00x, rate);
if (err < 0)
return err;
err = keep_resources(dg00x, &dg00x->rx_stream, rate);
if (err < 0)
return err;
err = keep_resources(dg00x, &dg00x->tx_stream, rate);
if (err < 0) {
fw_iso_resources_free(&dg00x->rx_resources);
return err;
}
}
return 0;
}
int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x)
{
unsigned int generation = dg00x->rx_resources.generation;
int err = 0;
if (dg00x->substreams_counter == 0)
return 0;
if (amdtp_streaming_error(&dg00x->tx_stream) ||
amdtp_streaming_error(&dg00x->rx_stream))
finish_session(dg00x);
if (generation != fw_parent_device(dg00x->unit)->card->generation) {
err = fw_iso_resources_update(&dg00x->tx_resources);
if (err < 0)
goto error;
err = keep_resources(dg00x, rate);
err = fw_iso_resources_update(&dg00x->rx_resources);
if (err < 0)
goto error;
}
/*
* No packets are transmitted without receiving packets, reagardless of
* which source of clock is used.
*/
if (!amdtp_stream_running(&dg00x->rx_stream)) {
err = begin_session(dg00x);
if (err < 0)
goto error;
......@@ -343,33 +353,22 @@ int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x, unsigned int rate)
goto error;
}
}
end:
return err;
return 0;
error:
finish_session(dg00x);
amdtp_stream_stop(&dg00x->tx_stream);
amdtp_stream_stop(&dg00x->rx_stream);
release_resources(dg00x);
return err;
}
void snd_dg00x_stream_stop_duplex(struct snd_dg00x *dg00x)
{
if (dg00x->substreams_counter > 0)
return;
amdtp_stream_stop(&dg00x->tx_stream);
amdtp_stream_stop(&dg00x->rx_stream);
finish_session(dg00x);
release_resources(dg00x);
if (dg00x->substreams_counter == 0) {
finish_session(dg00x);
/*
* Just after finishing the session, the device may lost transmitting
* functionality for a short time.
*/
msleep(50);
fw_iso_resources_free(&dg00x->tx_resources);
fw_iso_resources_free(&dg00x->rx_resources);
}
}
void snd_dg00x_stream_update_duplex(struct snd_dg00x *dg00x)
......
......@@ -139,7 +139,8 @@ int snd_dg00x_stream_get_clock(struct snd_dg00x *dg00x,
int snd_dg00x_stream_check_external_clock(struct snd_dg00x *dg00x,
bool *detect);
int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x);
int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x, unsigned int rate);
int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate);
int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x);
void snd_dg00x_stream_stop_duplex(struct snd_dg00x *dg00x);
void snd_dg00x_stream_update_duplex(struct snd_dg00x *dg00x);
void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x);
......
......@@ -198,8 +198,8 @@ static int pcm_close(struct snd_pcm_substream *substream)
return 0;
}
static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
static int pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
struct snd_ff *ff = substream->private_data;
int err;
......@@ -210,58 +210,26 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
return err;
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
mutex_lock(&ff->mutex);
ff->substreams_counter++;
mutex_unlock(&ff->mutex);
}
return 0;
}
static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
struct snd_ff *ff = substream->private_data;
int err;
err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
params_buffer_bytes(hw_params));
if (err < 0)
return err;
unsigned int rate = params_rate(hw_params);
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
mutex_lock(&ff->mutex);
ff->substreams_counter++;
err = snd_ff_stream_reserve_duplex(ff, rate);
if (err >= 0)
++ff->substreams_counter;
mutex_unlock(&ff->mutex);
}
return 0;
}
static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
{
struct snd_ff *ff = substream->private_data;
mutex_lock(&ff->mutex);
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
ff->substreams_counter--;
snd_ff_stream_stop_duplex(ff);
mutex_unlock(&ff->mutex);
return snd_pcm_lib_free_vmalloc_buffer(substream);
}
static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
static int pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_ff *ff = substream->private_data;
mutex_lock(&ff->mutex);
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
ff->substreams_counter--;
--ff->substreams_counter;
snd_ff_stream_stop_duplex(ff);
......@@ -374,8 +342,8 @@ int snd_ff_create_pcm_devices(struct snd_ff *ff)
.open = pcm_open,
.close = pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = pcm_capture_hw_params,
.hw_free = pcm_capture_hw_free,
.hw_params = pcm_hw_params,
.hw_free = pcm_hw_free,
.prepare = pcm_capture_prepare,
.trigger = pcm_capture_trigger,
.pointer = pcm_capture_pointer,
......@@ -386,8 +354,8 @@ int snd_ff_create_pcm_devices(struct snd_ff *ff)
.open = pcm_open,
.close = pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = pcm_playback_hw_params,
.hw_free = pcm_playback_hw_free,
.hw_params = pcm_hw_params,
.hw_free = pcm_hw_free,
.prepare = pcm_playback_prepare,
.trigger = pcm_playback_trigger,
.pointer = pcm_playback_pointer,
......
......@@ -97,25 +97,64 @@ static int latter_switch_fetching_mode(struct snd_ff *ff, bool enable)
LATTER_FETCH_MODE, &reg, sizeof(reg), 0);
}
static int keep_resources(struct snd_ff *ff, unsigned int rate)
static int latter_allocate_resources(struct snd_ff *ff, unsigned int rate)
{
enum snd_ff_stream_mode mode;
unsigned int code;
__le32 reg;
unsigned int count;
int i;
int err;
// Check whether the given value is supported or not.
for (i = 0; i < CIP_SFC_COUNT; i++) {
if (amdtp_rate_table[i] == rate)
// Set the number of data blocks transferred in a second.
if (rate % 32000 == 0)
code = 0x00;
else if (rate % 44100 == 0)
code = 0x02;
else if (rate % 48000 == 0)
code = 0x04;
else
return -EINVAL;
if (rate >= 64000 && rate < 128000)
code |= 0x08;
else if (rate >= 128000 && rate < 192000)
code |= 0x10;
reg = cpu_to_le32(code);
err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
LATTER_STF, &reg, sizeof(reg), 0);
if (err < 0)
return err;
// Confirm to shift transmission clock.
count = 0;
while (count++ < 10) {
unsigned int curr_rate;
enum snd_ff_clock_src src;
err = latter_get_clock(ff, &curr_rate, &src);
if (err < 0)
return err;
if (curr_rate == rate)
break;
}
if (i >= CIP_SFC_COUNT)
if (count == 10)
return -ETIMEDOUT;
for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); ++i) {
if (rate == amdtp_rate_table[i])
break;
}
if (i == ARRAY_SIZE(amdtp_rate_table))
return -EINVAL;
err = snd_ff_stream_get_multiplier_mode(i, &mode);
if (err < 0)
return err;
/* Keep resources for in-stream. */
// Keep resources for in-stream.
ff->tx_resources.channels_mask = 0x00000000000000ffuLL;
err = fw_iso_resources_allocate(&ff->tx_resources,
amdtp_stream_get_max_payload(&ff->tx_stream),
......@@ -123,7 +162,7 @@ static int keep_resources(struct snd_ff *ff, unsigned int rate)
if (err < 0)
return err;
/* Keep resources for out-stream. */
// Keep resources for out-stream.
ff->rx_resources.channels_mask = 0x00000000000000ffuLL;
err = fw_iso_resources_allocate(&ff->rx_resources,
amdtp_stream_get_max_payload(&ff->rx_stream),
......@@ -136,60 +175,30 @@ static int keep_resources(struct snd_ff *ff, unsigned int rate)
static int latter_begin_session(struct snd_ff *ff, unsigned int rate)
{
static const struct {
unsigned int stf;
unsigned int code;
unsigned int flag;
} *entry, rate_table[] = {
{ 32000, 0x00, 0x92, },
{ 44100, 0x02, 0x92, },
{ 48000, 0x04, 0x92, },
{ 64000, 0x08, 0x8e, },
{ 88200, 0x0a, 0x8e, },
{ 96000, 0x0c, 0x8e, },
{ 128000, 0x10, 0x8c, },
{ 176400, 0x12, 0x8c, },
{ 192000, 0x14, 0x8c, },
};
unsigned int generation = ff->rx_resources.generation;
unsigned int flag;
u32 data;
__le32 reg;
unsigned int count;
int i;
int err;
for (i = 0; i < ARRAY_SIZE(rate_table); ++i) {
entry = rate_table + i;
if (entry->stf == rate)
break;
}
if (i == ARRAY_SIZE(rate_table))
if (rate >= 32000 && rate <= 48000)
flag = 0x92;
else if (rate >= 64000 && rate <= 96000)
flag = 0x8e;
else if (rate >= 128000 && rate <= 192000)
flag = 0x8c;
else
return -EINVAL;
reg = cpu_to_le32(entry->code);
err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
LATTER_STF, &reg, sizeof(reg), 0);
if (err < 0)
return err;
// Confirm to shift transmission clock.
count = 0;
while (count++ < 10) {
unsigned int curr_rate;
enum snd_ff_clock_src src;
err = latter_get_clock(ff, &curr_rate, &src);
if (generation != fw_parent_device(ff->unit)->card->generation) {
err = fw_iso_resources_update(&ff->tx_resources);
if (err < 0)
return err;
if (curr_rate == rate)
break;
err = fw_iso_resources_update(&ff->rx_resources);
if (err < 0)
return err;
}
if (count == 10)
return -ETIMEDOUT;
err = keep_resources(ff, rate);
if (err < 0)
return err;
data = (ff->tx_resources.channel << 8) | ff->rx_resources.channel;
reg = cpu_to_le32(data);
......@@ -200,7 +209,7 @@ static int latter_begin_session(struct snd_ff *ff, unsigned int rate)
// Always use the maximum number of data channels in data block of
// packet.
reg = cpu_to_le32(entry->flag);
reg = cpu_to_le32(flag);
return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
LATTER_ISOC_START, &reg, sizeof(reg), 0);
}
......@@ -424,6 +433,7 @@ const struct snd_ff_protocol snd_ff_protocol_latter = {
.fill_midi_msg = latter_fill_midi_msg,
.get_clock = latter_get_clock,
.switch_fetching_mode = latter_switch_fetching_mode,
.allocate_resources = latter_allocate_resources,
.begin_session = latter_begin_session,
.finish_session = latter_finish_session,
.dump_status = latter_dump_status,
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -223,7 +223,7 @@ int amdtp_tscm_init(struct amdtp_stream *s, struct fw_unit *unit,
return 0;
/* Use fixed value for FDF field. */
s->fdf = 0x00;
s->ctx_data.rx.fdf = 0x00;
/* This protocol uses fixed number of data channels for PCM samples. */
p = s->protocol;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment