mirror of https://gitee.com/openkylin/linux.git
sound fixes for 5.11-rc4
Here are some piled fixes, hopefully the last big one for 5.11. All changes are device-specific small fixes, and majority of commits are for ASoC while USB-audio got a bit large changes for addressing the regression for devices with quirks. -----BEGIN PGP SIGNATURE----- iQJCBAABCAAsFiEEIXTw5fNLNI7mMiVaLtJE4w1nLE8FAl//Cg0OHHRpd2FpQHN1 c2UuZGUACgkQLtJE4w1nLE9eoBAAj11a4XkuGTM3TxCcnWMvEfHayYtzj3fzsjqV +pQoXYH7A54FzzFeL8lnjt4tbqqwWblPNfiaQGc4KzfGfywDrRpNeuotrx6Dk1ju 5w+Hoxrl/p2uB4QVVX6gQM1jpsMgaUSes3dcivaTuRXwef4tnN3Kh3Y+As9cN9mT NQV2Ulj25iQRNxRTVm9GyPKOVvK54LqxiZKFYKns+KNqpZhO3yQm2HnuXF0uMSJb l4Unmqg3NvO1cD8ROHXwk4siONAmuTr76a1F1gb5cpkwlHgbNxiJtXyqoShWmDwL uuAZ7AAgCVc5b6gVICDVYaqlAUow8J9Pn02KqH+kW7LHTULqooaH+fw/fkq7AB5T 9FMf/BtM29Mlpyfnsu44AlAb8YRhd/IOsr1caDM7/aE+BbnTlxtCZyvFC8Q0p+PJ ayMzLjbcVPd72x3v39WEjXxIzclDLkIDAkzWIyVyfPCZ/G7P8BIm+j0K+NNwVqw4 rtCyaw8vy1PHEJEb6VxcqvqNC8kZ+7tYCAUXVmU8hkBMHG0Rxz4tT4KUP255k/w/ XKHIMn5CQlbsNfPcBZzEdN4A9kahbp0ChVUd4ffkt9wG2DE+gzxWlcA4tDXp3eM7 3oCCBJpLdFwiSZO9iPhthZj9di9PeCVwLQfOpuYK/cKHxakSm/txln8ukTzQaDSu rCQIcfI= =lvKY -----END PGP SIGNATURE----- Merge tag 'sound-5.11-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound Pull sound fixes from Takashi Iwai: "Here are some piled fixes, hopefully the last big one for 5.11. All changes are device-specific small fixes, and majority of commits are for ASoC while USB-audio got a bit large changes for addressing the regression for devices with quirks" * tag 'sound-5.11-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (31 commits) ALSA: hda/hdmi - enable runtime pm for CI AMD display audio ALSA: firewire-tascam: Fix integer overflow in midi_port_work() ALSA: fireface: Fix integer overflow in transmit_midi_msg() ALSA: hda/tegra: fix tegra-hda on tegra30 soc clk: tegra30: Add hda clock default rates to clock driver ALSA: doc: Fix reference to mixart.rst ALSA: usb-audio: Fix implicit feedback sync setup for Pioneer devices ALSA: usb-audio: Annotate the endpoint index in audioformat ALSA: usb-audio: Avoid unnecessary interface re-setup ALSA: usb-audio: Choose audioformat of a counter-part substream ALSA: usb-audio: Fix the missing endpoints creations for quirks ALSA: hda/realtek: fix right sounds and mute/micmute LEDs for HP machines ASoC: AMD Renoir - add DMI entry for Lenovo ThinkPad X395 ASoC: amd: Replacing MSI with Legacy IRQ model ASoC: AMD Renoir - add DMI entry for Lenovo ThinkPad E14 Gen 2 ASoC: meson: axg-tdm-interface: fix loopback ASoC: meson: axg-tdmin: fix axg skew offset ASoC: max98373: don't access volatile registers in bias level off ASoC: rt711: mutex between calibration and power state changes ASoC: Intel: haswell: Add missing pm_ops ...
This commit is contained in:
commit
65f0d2414b
|
@ -1,4 +1,6 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (C) 2020 Texas Instruments Incorporated
|
||||
# Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/ti,j721e-cpb-audio.yaml#
|
||||
|
@ -7,7 +9,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
|||
title: Texas Instruments J721e Common Processor Board Audio Support
|
||||
|
||||
maintainers:
|
||||
- Peter Ujfalusi <peter.ujfalusi@ti.com>
|
||||
- Peter Ujfalusi <peter.ujfalusi@gmail.com>
|
||||
|
||||
description: |
|
||||
The audio support on the board is using pcm3168a codec connected to McASP10
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (C) 2020 Texas Instruments Incorporated
|
||||
# Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/sound/ti,j721e-cpb-ivi-audio.yaml#
|
||||
|
@ -7,7 +9,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
|||
title: Texas Instruments J721e Common Processor Board Audio Support
|
||||
|
||||
maintainers:
|
||||
- Peter Ujfalusi <peter.ujfalusi@ti.com>
|
||||
- Peter Ujfalusi <peter.ujfalusi@gmail.com>
|
||||
|
||||
description: |
|
||||
The Infotainment board plugs into the Common Processor Board, the support of the
|
||||
|
|
|
@ -1501,7 +1501,7 @@ Module for Digigram miXart8 sound cards.
|
|||
|
||||
This module supports multiple cards.
|
||||
Note: One miXart8 board will be represented as 4 alsa cards.
|
||||
See MIXART.txt for details.
|
||||
See Documentation/sound/cards/mixart.rst for details.
|
||||
|
||||
When the driver is compiled as a module and the hotplug firmware
|
||||
is supported, the firmware data is loaded via hotplug automatically.
|
||||
|
|
|
@ -12848,7 +12848,7 @@ F: include/misc/ocxl*
|
|||
F: include/uapi/misc/ocxl.h
|
||||
|
||||
OMAP AUDIO SUPPORT
|
||||
M: Peter Ujfalusi <peter.ujfalusi@ti.com>
|
||||
M: Peter Ujfalusi <peter.ujfalusi@gmail.com>
|
||||
M: Jarkko Nikula <jarkko.nikula@bitmer.com>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
L: linux-omap@vger.kernel.org
|
||||
|
@ -17541,7 +17541,7 @@ F: arch/xtensa/
|
|||
F: drivers/irqchip/irq-xtensa-*
|
||||
|
||||
TEXAS INSTRUMENTS ASoC DRIVERS
|
||||
M: Peter Ujfalusi <peter.ujfalusi@ti.com>
|
||||
M: Peter Ujfalusi <peter.ujfalusi@gmail.com>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: sound/soc/ti/
|
||||
|
@ -17851,7 +17851,7 @@ F: Documentation/devicetree/bindings/net/nfc/trf7970a.txt
|
|||
F: drivers/nfc/trf7970a.c
|
||||
|
||||
TI TWL4030 SERIES SOC CODEC DRIVER
|
||||
M: Peter Ujfalusi <peter.ujfalusi@ti.com>
|
||||
M: Peter Ujfalusi <peter.ujfalusi@gmail.com>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: sound/soc/codecs/twl4030*
|
||||
|
|
|
@ -1256,6 +1256,8 @@ static struct tegra_clk_init_table init_table[] __initdata = {
|
|||
{ TEGRA30_CLK_I2S3_SYNC, TEGRA30_CLK_CLK_MAX, 24000000, 0 },
|
||||
{ TEGRA30_CLK_I2S4_SYNC, TEGRA30_CLK_CLK_MAX, 24000000, 0 },
|
||||
{ TEGRA30_CLK_VIMCLK_SYNC, TEGRA30_CLK_CLK_MAX, 24000000, 0 },
|
||||
{ TEGRA30_CLK_HDA, TEGRA30_CLK_PLL_P, 102000000, 0 },
|
||||
{ TEGRA30_CLK_HDA2CODEC_2X, TEGRA30_CLK_PLL_P, 48000000, 0 },
|
||||
/* must be the last entry */
|
||||
{ TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 },
|
||||
};
|
||||
|
|
|
@ -88,7 +88,7 @@ static void transmit_midi_msg(struct snd_ff *ff, unsigned int port)
|
|||
|
||||
/* Set interval to next transaction. */
|
||||
ff->next_ktime[port] = ktime_add_ns(ktime_get(),
|
||||
ff->rx_bytes[port] * 8 * NSEC_PER_SEC / 31250);
|
||||
ff->rx_bytes[port] * 8 * (NSEC_PER_SEC / 31250));
|
||||
|
||||
if (quad_count == 1)
|
||||
tcode = TCODE_WRITE_QUADLET_REQUEST;
|
||||
|
|
|
@ -209,7 +209,7 @@ static void midi_port_work(struct work_struct *work)
|
|||
|
||||
/* Set interval to next transaction. */
|
||||
port->next_ktime = ktime_add_ns(ktime_get(),
|
||||
port->consume_bytes * 8 * NSEC_PER_SEC / 31250);
|
||||
port->consume_bytes * 8 * (NSEC_PER_SEC / 31250));
|
||||
|
||||
/* Start this transaction. */
|
||||
port->idling = false;
|
||||
|
|
|
@ -2598,7 +2598,8 @@ static const struct pci_device_id azx_ids[] = {
|
|||
.driver_data = AZX_DRIVER_GENERIC | AZX_DCAPS_PRESET_AMD_SB },
|
||||
/* ATI HDMI */
|
||||
{ PCI_DEVICE(0x1002, 0x0002),
|
||||
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
|
||||
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
|
||||
AZX_DCAPS_PM_RUNTIME },
|
||||
{ PCI_DEVICE(0x1002, 0x1308),
|
||||
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
|
||||
{ PCI_DEVICE(0x1002, 0x157a),
|
||||
|
@ -2660,9 +2661,11 @@ static const struct pci_device_id azx_ids[] = {
|
|||
{ PCI_DEVICE(0x1002, 0xaab0),
|
||||
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
|
||||
{ PCI_DEVICE(0x1002, 0xaac0),
|
||||
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
|
||||
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
|
||||
AZX_DCAPS_PM_RUNTIME },
|
||||
{ PCI_DEVICE(0x1002, 0xaac8),
|
||||
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
|
||||
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
|
||||
AZX_DCAPS_PM_RUNTIME },
|
||||
{ PCI_DEVICE(0x1002, 0xaad8),
|
||||
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS |
|
||||
AZX_DCAPS_PM_RUNTIME },
|
||||
|
|
|
@ -388,7 +388,7 @@ static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev)
|
|||
* in powers of 2, next available ratio is 16 which can be
|
||||
* used as a limiting factor here.
|
||||
*/
|
||||
if (of_device_is_compatible(np, "nvidia,tegra194-hda"))
|
||||
if (of_device_is_compatible(np, "nvidia,tegra30-hda"))
|
||||
chip->bus.core.sdo_limit = 16;
|
||||
|
||||
/* codec detection */
|
||||
|
|
|
@ -7970,6 +7970,10 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
|
|||
SND_PCI_QUIRK(0x103c, 0x8760, "HP", ALC285_FIXUP_HP_MUTE_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x877a, "HP", ALC285_FIXUP_HP_MUTE_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x877d, "HP", ALC236_FIXUP_HP_MUTE_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x8780, "HP ZBook Fury 17 G7 Mobile Workstation",
|
||||
ALC285_FIXUP_HP_GPIO_AMP_INIT),
|
||||
SND_PCI_QUIRK(0x103c, 0x8783, "HP ZBook Fury 15 G7 Mobile Workstation",
|
||||
ALC285_FIXUP_HP_GPIO_AMP_INIT),
|
||||
SND_PCI_QUIRK(0x103c, 0x87c8, "HP", ALC287_FIXUP_HP_GPIO_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x87f4, "HP", ALC287_FIXUP_HP_GPIO_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x87f5, "HP", ALC287_FIXUP_HP_GPIO_LED),
|
||||
|
|
|
@ -140,21 +140,14 @@ static int snd_acp3x_probe(struct pci_dev *pci,
|
|||
goto release_regions;
|
||||
}
|
||||
|
||||
/* check for msi interrupt support */
|
||||
ret = pci_enable_msi(pci);
|
||||
if (ret)
|
||||
/* msi is not enabled */
|
||||
irqflags = IRQF_SHARED;
|
||||
else
|
||||
/* msi is enabled */
|
||||
irqflags = 0;
|
||||
irqflags = IRQF_SHARED;
|
||||
|
||||
addr = pci_resource_start(pci, 0);
|
||||
adata->acp3x_base = devm_ioremap(&pci->dev, addr,
|
||||
pci_resource_len(pci, 0));
|
||||
if (!adata->acp3x_base) {
|
||||
ret = -ENOMEM;
|
||||
goto disable_msi;
|
||||
goto release_regions;
|
||||
}
|
||||
pci_set_master(pci);
|
||||
pci_set_drvdata(pci, adata);
|
||||
|
@ -162,7 +155,7 @@ static int snd_acp3x_probe(struct pci_dev *pci,
|
|||
adata->pme_en = rv_readl(adata->acp3x_base + mmACP_PME_EN);
|
||||
ret = acp3x_init(adata);
|
||||
if (ret)
|
||||
goto disable_msi;
|
||||
goto release_regions;
|
||||
|
||||
val = rv_readl(adata->acp3x_base + mmACP_I2S_PIN_CONFIG);
|
||||
switch (val) {
|
||||
|
@ -251,8 +244,6 @@ static int snd_acp3x_probe(struct pci_dev *pci,
|
|||
de_init:
|
||||
if (acp3x_deinit(adata->acp3x_base))
|
||||
dev_err(&pci->dev, "ACP de-init failed\n");
|
||||
disable_msi:
|
||||
pci_disable_msi(pci);
|
||||
release_regions:
|
||||
pci_release_regions(pci);
|
||||
disable_pci:
|
||||
|
@ -311,7 +302,6 @@ static void snd_acp3x_remove(struct pci_dev *pci)
|
|||
dev_err(&pci->dev, "ACP de-init failed\n");
|
||||
pm_runtime_forbid(&pci->dev);
|
||||
pm_runtime_get_noresume(&pci->dev);
|
||||
pci_disable_msi(pci);
|
||||
pci_release_regions(pci);
|
||||
pci_disable_device(pci);
|
||||
}
|
||||
|
|
|
@ -171,6 +171,20 @@ static const struct dmi_system_id rn_acp_quirk_table[] = {
|
|||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "LNVNB161216"),
|
||||
}
|
||||
},
|
||||
{
|
||||
/* Lenovo ThinkPad E14 Gen 2 */
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "20T6CTO1WW"),
|
||||
}
|
||||
},
|
||||
{
|
||||
/* Lenovo ThinkPad X395 */
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "20NLCTO1WW"),
|
||||
}
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ config SND_MCHP_SOC_SPDIFTX
|
|||
- sama7g5
|
||||
|
||||
This S/PDIF TX driver is compliant with IEC-60958 standard and
|
||||
includes programable User Data and Channel Status fields.
|
||||
includes programmable User Data and Channel Status fields.
|
||||
|
||||
config SND_MCHP_SOC_SPDIFRX
|
||||
tristate "Microchip ASoC driver for boards using S/PDIF RX"
|
||||
|
@ -157,5 +157,5 @@ config SND_MCHP_SOC_SPDIFRX
|
|||
- sama7g5
|
||||
|
||||
This S/PDIF RX driver is compliant with IEC-60958 standard and
|
||||
includes programable User Data and Channel Status fields.
|
||||
includes programmable User Data and Channel Status fields.
|
||||
endif
|
||||
|
|
|
@ -457,7 +457,7 @@ config SND_SOC_ADAU7118_HW
|
|||
help
|
||||
Enable support for the Analog Devices ADAU7118 8 Channel PDM-to-I2S/TDM
|
||||
Converter. In this mode, the device works in standalone mode which
|
||||
means that there is no bus to comunicate with it. Stereo mode is not
|
||||
means that there is no bus to communicate with it. Stereo mode is not
|
||||
supported in this mode.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
|
|
|
@ -19,6 +19,12 @@
|
|||
#include <sound/tlv.h>
|
||||
#include "max98373.h"
|
||||
|
||||
static const u32 max98373_i2c_cache_reg[] = {
|
||||
MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK,
|
||||
MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK,
|
||||
MAX98373_R20B6_BDE_CUR_STATE_READBACK,
|
||||
};
|
||||
|
||||
static struct reg_default max98373_reg[] = {
|
||||
{MAX98373_R2000_SW_RESET, 0x00},
|
||||
{MAX98373_R2001_INT_RAW1, 0x00},
|
||||
|
@ -472,6 +478,11 @@ static struct snd_soc_dai_driver max98373_dai[] = {
|
|||
static int max98373_suspend(struct device *dev)
|
||||
{
|
||||
struct max98373_priv *max98373 = dev_get_drvdata(dev);
|
||||
int i;
|
||||
|
||||
/* cache feedback register values before suspend */
|
||||
for (i = 0; i < max98373->cache_num; i++)
|
||||
regmap_read(max98373->regmap, max98373->cache[i].reg, &max98373->cache[i].val);
|
||||
|
||||
regcache_cache_only(max98373->regmap, true);
|
||||
regcache_mark_dirty(max98373->regmap);
|
||||
|
@ -509,6 +520,7 @@ static int max98373_i2c_probe(struct i2c_client *i2c,
|
|||
{
|
||||
int ret = 0;
|
||||
int reg = 0;
|
||||
int i;
|
||||
struct max98373_priv *max98373 = NULL;
|
||||
|
||||
max98373 = devm_kzalloc(&i2c->dev, sizeof(*max98373), GFP_KERNEL);
|
||||
|
@ -534,6 +546,14 @@ static int max98373_i2c_probe(struct i2c_client *i2c,
|
|||
return ret;
|
||||
}
|
||||
|
||||
max98373->cache_num = ARRAY_SIZE(max98373_i2c_cache_reg);
|
||||
max98373->cache = devm_kcalloc(&i2c->dev, max98373->cache_num,
|
||||
sizeof(*max98373->cache),
|
||||
GFP_KERNEL);
|
||||
|
||||
for (i = 0; i < max98373->cache_num; i++)
|
||||
max98373->cache[i].reg = max98373_i2c_cache_reg[i];
|
||||
|
||||
/* voltage/current slot & gpio configuration */
|
||||
max98373_slot_config(&i2c->dev, max98373);
|
||||
|
||||
|
|
|
@ -23,6 +23,12 @@ struct sdw_stream_data {
|
|||
struct sdw_stream_runtime *sdw_stream;
|
||||
};
|
||||
|
||||
static const u32 max98373_sdw_cache_reg[] = {
|
||||
MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK,
|
||||
MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK,
|
||||
MAX98373_R20B6_BDE_CUR_STATE_READBACK,
|
||||
};
|
||||
|
||||
static struct reg_default max98373_reg[] = {
|
||||
{MAX98373_R0040_SCP_INIT_STAT_1, 0x00},
|
||||
{MAX98373_R0041_SCP_INIT_MASK_1, 0x00},
|
||||
|
@ -245,6 +251,11 @@ static const struct regmap_config max98373_sdw_regmap = {
|
|||
static __maybe_unused int max98373_suspend(struct device *dev)
|
||||
{
|
||||
struct max98373_priv *max98373 = dev_get_drvdata(dev);
|
||||
int i;
|
||||
|
||||
/* cache feedback register values before suspend */
|
||||
for (i = 0; i < max98373->cache_num; i++)
|
||||
regmap_read(max98373->regmap, max98373->cache[i].reg, &max98373->cache[i].val);
|
||||
|
||||
regcache_cache_only(max98373->regmap, true);
|
||||
|
||||
|
@ -757,6 +768,7 @@ static int max98373_init(struct sdw_slave *slave, struct regmap *regmap)
|
|||
{
|
||||
struct max98373_priv *max98373;
|
||||
int ret;
|
||||
int i;
|
||||
struct device *dev = &slave->dev;
|
||||
|
||||
/* Allocate and assign private driver data structure */
|
||||
|
@ -768,6 +780,14 @@ static int max98373_init(struct sdw_slave *slave, struct regmap *regmap)
|
|||
max98373->regmap = regmap;
|
||||
max98373->slave = slave;
|
||||
|
||||
max98373->cache_num = ARRAY_SIZE(max98373_sdw_cache_reg);
|
||||
max98373->cache = devm_kcalloc(dev, max98373->cache_num,
|
||||
sizeof(*max98373->cache),
|
||||
GFP_KERNEL);
|
||||
|
||||
for (i = 0; i < max98373->cache_num; i++)
|
||||
max98373->cache[i].reg = max98373_sdw_cache_reg[i];
|
||||
|
||||
/* Read voltage and slot configuration */
|
||||
max98373_slot_config(dev, max98373);
|
||||
|
||||
|
|
|
@ -168,6 +168,31 @@ static SOC_ENUM_SINGLE_DECL(max98373_adc_samplerate_enum,
|
|||
MAX98373_R2051_MEAS_ADC_SAMPLING_RATE, 0,
|
||||
max98373_ADC_samplerate_text);
|
||||
|
||||
static int max98373_feedback_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
|
||||
struct soc_mixer_control *mc =
|
||||
(struct soc_mixer_control *)kcontrol->private_value;
|
||||
struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component);
|
||||
int i;
|
||||
|
||||
if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
|
||||
/*
|
||||
* Register values will be cached before suspend. The cached value
|
||||
* will be a valid value and userspace will happy with that.
|
||||
*/
|
||||
for (i = 0; i < max98373->cache_num; i++) {
|
||||
if (mc->reg == max98373->cache[i].reg) {
|
||||
ucontrol->value.integer.value[0] = max98373->cache[i].val;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return snd_soc_put_volsw(kcontrol, ucontrol);
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new max98373_snd_controls[] = {
|
||||
SOC_SINGLE("Digital Vol Sel Switch", MAX98373_R203F_AMP_DSP_CFG,
|
||||
MAX98373_AMP_VOL_SEL_SHIFT, 1, 0),
|
||||
|
@ -209,8 +234,10 @@ SOC_SINGLE("ADC PVDD FLT Switch", MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG,
|
|||
MAX98373_FLT_EN_SHIFT, 1, 0),
|
||||
SOC_SINGLE("ADC TEMP FLT Switch", MAX98373_R2053_MEAS_ADC_THERM_FLT_CFG,
|
||||
MAX98373_FLT_EN_SHIFT, 1, 0),
|
||||
SOC_SINGLE("ADC PVDD", MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK, 0, 0xFF, 0),
|
||||
SOC_SINGLE("ADC TEMP", MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK, 0, 0xFF, 0),
|
||||
SOC_SINGLE_EXT("ADC PVDD", MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK, 0, 0xFF, 0,
|
||||
max98373_feedback_get, NULL),
|
||||
SOC_SINGLE_EXT("ADC TEMP", MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK, 0, 0xFF, 0,
|
||||
max98373_feedback_get, NULL),
|
||||
SOC_SINGLE("ADC PVDD FLT Coeff", MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG,
|
||||
0, 0x3, 0),
|
||||
SOC_SINGLE("ADC TEMP FLT Coeff", MAX98373_R2053_MEAS_ADC_THERM_FLT_CFG,
|
||||
|
@ -226,7 +253,8 @@ SOC_SINGLE("BDE LVL1 Thresh", MAX98373_R2097_BDE_L1_THRESH, 0, 0xFF, 0),
|
|||
SOC_SINGLE("BDE LVL2 Thresh", MAX98373_R2098_BDE_L2_THRESH, 0, 0xFF, 0),
|
||||
SOC_SINGLE("BDE LVL3 Thresh", MAX98373_R2099_BDE_L3_THRESH, 0, 0xFF, 0),
|
||||
SOC_SINGLE("BDE LVL4 Thresh", MAX98373_R209A_BDE_L4_THRESH, 0, 0xFF, 0),
|
||||
SOC_SINGLE("BDE Active Level", MAX98373_R20B6_BDE_CUR_STATE_READBACK, 0, 8, 0),
|
||||
SOC_SINGLE_EXT("BDE Active Level", MAX98373_R20B6_BDE_CUR_STATE_READBACK, 0, 8, 0,
|
||||
max98373_feedback_get, NULL),
|
||||
SOC_SINGLE("BDE Clip Mode Switch", MAX98373_R2092_BDE_CLIPPER_MODE, 0, 1, 0),
|
||||
SOC_SINGLE("BDE Thresh Hysteresis", MAX98373_R209B_BDE_THRESH_HYST, 0, 0xFF, 0),
|
||||
SOC_SINGLE("BDE Hold Time", MAX98373_R2090_BDE_LVL_HOLD, 0, 0xFF, 0),
|
||||
|
|
|
@ -203,6 +203,11 @@
|
|||
/* MAX98373_R2000_SW_RESET */
|
||||
#define MAX98373_SOFT_RESET (0x1 << 0)
|
||||
|
||||
struct max98373_cache {
|
||||
u32 reg;
|
||||
u32 val;
|
||||
};
|
||||
|
||||
struct max98373_priv {
|
||||
struct regmap *regmap;
|
||||
int reset_gpio;
|
||||
|
@ -212,6 +217,9 @@ struct max98373_priv {
|
|||
bool interleave_mode;
|
||||
unsigned int ch_size;
|
||||
bool tdm_mode;
|
||||
/* cache for reading a valid fake feedback value */
|
||||
struct max98373_cache *cache;
|
||||
int cache_num;
|
||||
/* variables to support soundwire */
|
||||
struct sdw_slave *slave;
|
||||
bool hw_init;
|
||||
|
|
|
@ -462,6 +462,8 @@ static int rt711_set_amp_gain_put(struct snd_kcontrol *kcontrol,
|
|||
unsigned int read_ll, read_rl;
|
||||
int i;
|
||||
|
||||
mutex_lock(&rt711->calibrate_mutex);
|
||||
|
||||
/* Can't use update bit function, so read the original value first */
|
||||
addr_h = mc->reg;
|
||||
addr_l = mc->rreg;
|
||||
|
@ -547,6 +549,8 @@ static int rt711_set_amp_gain_put(struct snd_kcontrol *kcontrol,
|
|||
if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
|
||||
regmap_write(rt711->regmap,
|
||||
RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
|
||||
|
||||
mutex_unlock(&rt711->calibrate_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -859,9 +863,11 @@ static int rt711_set_bias_level(struct snd_soc_component *component,
|
|||
break;
|
||||
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
mutex_lock(&rt711->calibrate_mutex);
|
||||
regmap_write(rt711->regmap,
|
||||
RT711_SET_AUDIO_POWER_STATE,
|
||||
AC_PWRST_D3);
|
||||
mutex_unlock(&rt711->calibrate_mutex);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -164,6 +164,7 @@ static int imx_hdmi_probe(struct platform_device *pdev)
|
|||
|
||||
if ((hdmi_out && hdmi_in) || (!hdmi_out && !hdmi_in)) {
|
||||
dev_err(&pdev->dev, "Invalid HDMI DAI link\n");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
|
|
@ -189,6 +189,7 @@ static struct platform_driver haswell_audio = {
|
|||
.probe = haswell_audio_probe,
|
||||
.driver = {
|
||||
.name = "haswell-audio",
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -224,6 +224,7 @@ static int cnl_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id)
|
|||
"dsp boot timeout, status=%#x error=%#x\n",
|
||||
sst_dsp_shim_read(ctx, CNL_ADSP_FW_STATUS),
|
||||
sst_dsp_shim_read(ctx, CNL_ADSP_ERROR_CODE));
|
||||
ret = -ETIMEDOUT;
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -467,8 +467,20 @@ static int axg_tdm_iface_set_bias_level(struct snd_soc_component *component,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dapm_widget axg_tdm_iface_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_SIGGEN("Playback Signal"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route axg_tdm_iface_dapm_routes[] = {
|
||||
{ "Loopback", NULL, "Playback Signal" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver axg_tdm_iface_component_drv = {
|
||||
.set_bias_level = axg_tdm_iface_set_bias_level,
|
||||
.dapm_widgets = axg_tdm_iface_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(axg_tdm_iface_dapm_widgets),
|
||||
.dapm_routes = axg_tdm_iface_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(axg_tdm_iface_dapm_routes),
|
||||
.set_bias_level = axg_tdm_iface_set_bias_level,
|
||||
};
|
||||
|
||||
static const struct of_device_id axg_tdm_iface_of_match[] = {
|
||||
|
|
|
@ -224,15 +224,6 @@ static const struct axg_tdm_formatter_ops axg_tdmin_ops = {
|
|||
};
|
||||
|
||||
static const struct axg_tdm_formatter_driver axg_tdmin_drv = {
|
||||
.component_drv = &axg_tdmin_component_drv,
|
||||
.regmap_cfg = &axg_tdmin_regmap_cfg,
|
||||
.ops = &axg_tdmin_ops,
|
||||
.quirks = &(const struct axg_tdm_formatter_hw) {
|
||||
.skew_offset = 2,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct axg_tdm_formatter_driver g12a_tdmin_drv = {
|
||||
.component_drv = &axg_tdmin_component_drv,
|
||||
.regmap_cfg = &axg_tdmin_regmap_cfg,
|
||||
.ops = &axg_tdmin_ops,
|
||||
|
@ -247,10 +238,10 @@ static const struct of_device_id axg_tdmin_of_match[] = {
|
|||
.data = &axg_tdmin_drv,
|
||||
}, {
|
||||
.compatible = "amlogic,g12a-tdmin",
|
||||
.data = &g12a_tdmin_drv,
|
||||
.data = &axg_tdmin_drv,
|
||||
}, {
|
||||
.compatible = "amlogic,sm1-tdmin",
|
||||
.data = &g12a_tdmin_drv,
|
||||
.data = &axg_tdmin_drv,
|
||||
}, {}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, axg_tdmin_of_match);
|
||||
|
|
|
@ -270,18 +270,6 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
|
|||
struct lpaif_i2sctl *i2sctl = drvdata->i2sctl;
|
||||
unsigned int id = dai->driver->id;
|
||||
int ret = -EINVAL;
|
||||
unsigned int val = 0;
|
||||
|
||||
ret = regmap_read(drvdata->lpaif_map,
|
||||
LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), &val);
|
||||
if (ret) {
|
||||
dev_err(dai->dev, "error reading from i2sctl reg: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (val == LPAIF_I2SCTL_RESET_STATE) {
|
||||
dev_err(dai->dev, "error in i2sctl register state\n");
|
||||
return -ENOTRECOVERABLE;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
|
@ -454,20 +442,16 @@ static bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg)
|
|||
struct lpass_variant *v = drvdata->variant;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < v->i2s_ports; ++i)
|
||||
if (reg == LPAIF_I2SCTL_REG(v, i))
|
||||
return true;
|
||||
for (i = 0; i < v->irq_ports; ++i)
|
||||
if (reg == LPAIF_IRQSTAT_REG(v, i))
|
||||
return true;
|
||||
|
||||
for (i = 0; i < v->rdma_channels; ++i)
|
||||
if (reg == LPAIF_RDMACURR_REG(v, i) || reg == LPAIF_RDMACTL_REG(v, i))
|
||||
if (reg == LPAIF_RDMACURR_REG(v, i))
|
||||
return true;
|
||||
|
||||
for (i = 0; i < v->wrdma_channels; ++i)
|
||||
if (reg == LPAIF_WRDMACURR_REG(v, i + v->wrdma_channel_start) ||
|
||||
reg == LPAIF_WRDMACTL_REG(v, i + v->wrdma_channel_start))
|
||||
if (reg == LPAIF_WRDMACURR_REG(v, i + v->wrdma_channel_start))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
|
|
@ -452,7 +452,6 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
|
|||
unsigned int reg_irqclr = 0, val_irqclr = 0;
|
||||
unsigned int reg_irqen = 0, val_irqen = 0, val_mask = 0;
|
||||
unsigned int dai_id = cpu_dai->driver->id;
|
||||
unsigned int dma_ctrl_reg = 0;
|
||||
|
||||
ch = pcm_data->dma_ch;
|
||||
if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
|
@ -469,17 +468,7 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
|
|||
id = pcm_data->dma_ch - v->wrdma_channel_start;
|
||||
map = drvdata->lpaif_map;
|
||||
}
|
||||
ret = regmap_read(map, LPAIF_DMACTL_REG(v, ch, dir, dai_id), &dma_ctrl_reg);
|
||||
if (ret) {
|
||||
dev_err(soc_runtime->dev, "error reading from rdmactl reg: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (dma_ctrl_reg == LPAIF_DMACTL_RESET_STATE ||
|
||||
dma_ctrl_reg == LPAIF_DMACTL_RESET_STATE + 1) {
|
||||
dev_err(soc_runtime->dev, "error in rdmactl register state\n");
|
||||
return -ENOTRECOVERABLE;
|
||||
}
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
|
@ -500,7 +489,6 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
|
|||
"error writing to rdmactl reg: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
map = drvdata->hdmiif_map;
|
||||
reg_irqclr = LPASS_HDMITX_APP_IRQCLEAR_REG(v);
|
||||
val_irqclr = (LPAIF_IRQ_ALL(ch) |
|
||||
LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |
|
||||
|
@ -519,7 +507,6 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
|
|||
break;
|
||||
case MI2S_PRIMARY:
|
||||
case MI2S_SECONDARY:
|
||||
map = drvdata->lpaif_map;
|
||||
reg_irqclr = LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
|
||||
val_irqclr = LPAIF_IRQ_ALL(ch);
|
||||
|
||||
|
@ -563,7 +550,6 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
|
|||
"error writing to rdmactl reg: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
map = drvdata->hdmiif_map;
|
||||
reg_irqen = LPASS_HDMITX_APP_IRQEN_REG(v);
|
||||
val_mask = (LPAIF_IRQ_ALL(ch) |
|
||||
LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |
|
||||
|
@ -573,7 +559,6 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
|
|||
break;
|
||||
case MI2S_PRIMARY:
|
||||
case MI2S_SECONDARY:
|
||||
map = drvdata->lpaif_map;
|
||||
reg_irqen = LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
|
||||
val_mask = LPAIF_IRQ_ALL(ch);
|
||||
val_irqen = 0;
|
||||
|
@ -838,6 +823,39 @@ static void lpass_platform_pcm_free(struct snd_soc_component *component,
|
|||
}
|
||||
}
|
||||
|
||||
static int lpass_platform_pcmops_suspend(struct snd_soc_component *component)
|
||||
{
|
||||
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
|
||||
struct regmap *map;
|
||||
unsigned int dai_id = component->id;
|
||||
|
||||
if (dai_id == LPASS_DP_RX)
|
||||
map = drvdata->hdmiif_map;
|
||||
else
|
||||
map = drvdata->lpaif_map;
|
||||
|
||||
regcache_cache_only(map, true);
|
||||
regcache_mark_dirty(map);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpass_platform_pcmops_resume(struct snd_soc_component *component)
|
||||
{
|
||||
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
|
||||
struct regmap *map;
|
||||
unsigned int dai_id = component->id;
|
||||
|
||||
if (dai_id == LPASS_DP_RX)
|
||||
map = drvdata->hdmiif_map;
|
||||
else
|
||||
map = drvdata->lpaif_map;
|
||||
|
||||
regcache_cache_only(map, false);
|
||||
return regcache_sync(map);
|
||||
}
|
||||
|
||||
|
||||
static const struct snd_soc_component_driver lpass_component_driver = {
|
||||
.name = DRV_NAME,
|
||||
.open = lpass_platform_pcmops_open,
|
||||
|
@ -850,6 +868,8 @@ static const struct snd_soc_component_driver lpass_component_driver = {
|
|||
.mmap = lpass_platform_pcmops_mmap,
|
||||
.pcm_construct = lpass_platform_pcm_new,
|
||||
.pcm_destruct = lpass_platform_pcm_free,
|
||||
.suspend = lpass_platform_pcmops_suspend,
|
||||
.resume = lpass_platform_pcmops_resume,
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -366,25 +366,27 @@ void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable)
|
|||
struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
|
||||
struct device *dev = rsnd_priv_to_dev(priv);
|
||||
struct clk *clk;
|
||||
int i, ret;
|
||||
int i;
|
||||
|
||||
for_each_rsnd_clk(clk, adg, i) {
|
||||
ret = 0;
|
||||
if (enable) {
|
||||
ret = clk_prepare_enable(clk);
|
||||
int ret = clk_prepare_enable(clk);
|
||||
|
||||
/*
|
||||
* We shouldn't use clk_get_rate() under
|
||||
* atomic context. Let's keep it when
|
||||
* rsnd_adg_clk_enable() was called
|
||||
*/
|
||||
adg->clk_rate[i] = clk_get_rate(adg->clk[i]);
|
||||
adg->clk_rate[i] = 0;
|
||||
if (ret < 0)
|
||||
dev_warn(dev, "can't use clk %d\n", i);
|
||||
else
|
||||
adg->clk_rate[i] = clk_get_rate(clk);
|
||||
} else {
|
||||
clk_disable_unprepare(clk);
|
||||
if (adg->clk_rate[i])
|
||||
clk_disable_unprepare(clk);
|
||||
adg->clk_rate[i] = 0;
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
dev_warn(dev, "can't use clk %d\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2486,6 +2486,7 @@ void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w)
|
|||
enum snd_soc_dapm_direction dir;
|
||||
|
||||
list_del(&w->list);
|
||||
list_del(&w->dirty);
|
||||
/*
|
||||
* remove source and sink paths associated to this widget.
|
||||
* While removing the path, remove reference to it from both
|
||||
|
|
|
@ -122,7 +122,7 @@ config SND_SOC_SOF_DEBUG_XRUN_STOP
|
|||
bool "SOF stop on XRUN"
|
||||
help
|
||||
This option forces PCMs to stop on any XRUN event. This is useful to
|
||||
preserve any trace data ond pipeline status prior to the XRUN.
|
||||
preserve any trace data and pipeline status prior to the XRUN.
|
||||
Say Y if you are debugging SOF FW pipeline XRUNs.
|
||||
If unsure select "N".
|
||||
|
||||
|
|
|
@ -450,10 +450,8 @@ lookup_device_name(u32 id)
|
|||
static void snd_usb_audio_free(struct snd_card *card)
|
||||
{
|
||||
struct snd_usb_audio *chip = card->private_data;
|
||||
struct snd_usb_endpoint *ep, *n;
|
||||
|
||||
list_for_each_entry_safe(ep, n, &chip->ep_list, list)
|
||||
snd_usb_endpoint_free(ep);
|
||||
snd_usb_endpoint_free_all(chip);
|
||||
|
||||
mutex_destroy(&chip->mutex);
|
||||
if (!atomic_read(&chip->shutdown))
|
||||
|
@ -611,6 +609,7 @@ static int snd_usb_audio_create(struct usb_interface *intf,
|
|||
chip->usb_id = usb_id;
|
||||
INIT_LIST_HEAD(&chip->pcm_list);
|
||||
INIT_LIST_HEAD(&chip->ep_list);
|
||||
INIT_LIST_HEAD(&chip->iface_ref_list);
|
||||
INIT_LIST_HEAD(&chip->midi_list);
|
||||
INIT_LIST_HEAD(&chip->mixer_list);
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ struct audioformat {
|
|||
unsigned int frame_size; /* samples per frame for non-audio */
|
||||
unsigned char iface; /* interface number */
|
||||
unsigned char altsetting; /* corresponding alternate setting */
|
||||
unsigned char ep_idx; /* endpoint array index */
|
||||
unsigned char altset_idx; /* array index of altenate setting */
|
||||
unsigned char attributes; /* corresponding attributes of cs endpoint */
|
||||
unsigned char endpoint; /* endpoint */
|
||||
|
@ -42,6 +43,7 @@ struct audioformat {
|
|||
};
|
||||
|
||||
struct snd_usb_substream;
|
||||
struct snd_usb_iface_ref;
|
||||
struct snd_usb_endpoint;
|
||||
struct snd_usb_power_domain;
|
||||
|
||||
|
@ -58,6 +60,7 @@ struct snd_urb_ctx {
|
|||
|
||||
struct snd_usb_endpoint {
|
||||
struct snd_usb_audio *chip;
|
||||
struct snd_usb_iface_ref *iface_ref;
|
||||
|
||||
int opened; /* open refcount; protect with chip->mutex */
|
||||
atomic_t running; /* running status */
|
||||
|
|
|
@ -24,6 +24,14 @@
|
|||
#define EP_FLAG_RUNNING 1
|
||||
#define EP_FLAG_STOPPING 2
|
||||
|
||||
/* interface refcounting */
|
||||
struct snd_usb_iface_ref {
|
||||
unsigned char iface;
|
||||
bool need_setup;
|
||||
int opened;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
/*
|
||||
* snd_usb_endpoint is a model that abstracts everything related to an
|
||||
* USB endpoint and its streaming.
|
||||
|
@ -488,6 +496,28 @@ static void snd_complete_urb(struct urb *urb)
|
|||
clear_bit(ctx->index, &ep->active_mask);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find or create a refcount object for the given interface
|
||||
*
|
||||
* The objects are released altogether in snd_usb_endpoint_free_all()
|
||||
*/
|
||||
static struct snd_usb_iface_ref *
|
||||
iface_ref_find(struct snd_usb_audio *chip, int iface)
|
||||
{
|
||||
struct snd_usb_iface_ref *ip;
|
||||
|
||||
list_for_each_entry(ip, &chip->iface_ref_list, list)
|
||||
if (ip->iface == iface)
|
||||
return ip;
|
||||
|
||||
ip = kzalloc(sizeof(*ip), GFP_KERNEL);
|
||||
if (!ip)
|
||||
return NULL;
|
||||
ip->iface = iface;
|
||||
list_add_tail(&ip->list, &chip->iface_ref_list);
|
||||
return ip;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the existing endpoint object corresponding EP
|
||||
* Returns NULL if not present.
|
||||
|
@ -520,8 +550,8 @@ snd_usb_get_endpoint(struct snd_usb_audio *chip, int ep_num)
|
|||
*
|
||||
* Returns zero on success or a negative error code.
|
||||
*
|
||||
* New endpoints will be added to chip->ep_list and must be freed by
|
||||
* calling snd_usb_endpoint_free().
|
||||
* New endpoints will be added to chip->ep_list and freed by
|
||||
* calling snd_usb_endpoint_free_all().
|
||||
*
|
||||
* For SND_USB_ENDPOINT_TYPE_SYNC, the caller needs to guarantee that
|
||||
* bNumEndpoints > 1 beforehand.
|
||||
|
@ -653,11 +683,17 @@ snd_usb_endpoint_open(struct snd_usb_audio *chip,
|
|||
} else {
|
||||
ep->iface = fp->iface;
|
||||
ep->altsetting = fp->altsetting;
|
||||
ep->ep_idx = 0;
|
||||
ep->ep_idx = fp->ep_idx;
|
||||
}
|
||||
usb_audio_dbg(chip, "Open EP 0x%x, iface=%d:%d, idx=%d\n",
|
||||
ep_num, ep->iface, ep->altsetting, ep->ep_idx);
|
||||
|
||||
ep->iface_ref = iface_ref_find(chip, ep->iface);
|
||||
if (!ep->iface_ref) {
|
||||
ep = NULL;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
ep->cur_audiofmt = fp;
|
||||
ep->cur_channels = fp->channels;
|
||||
ep->cur_rate = params_rate(params);
|
||||
|
@ -681,6 +717,11 @@ snd_usb_endpoint_open(struct snd_usb_audio *chip,
|
|||
ep->implicit_fb_sync);
|
||||
|
||||
} else {
|
||||
if (WARN_ON(!ep->iface_ref)) {
|
||||
ep = NULL;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (!endpoint_compatible(ep, fp, params)) {
|
||||
usb_audio_err(chip, "Incompatible EP setup for 0x%x\n",
|
||||
ep_num);
|
||||
|
@ -692,6 +733,9 @@ snd_usb_endpoint_open(struct snd_usb_audio *chip,
|
|||
ep_num, ep->opened);
|
||||
}
|
||||
|
||||
if (!ep->iface_ref->opened++)
|
||||
ep->iface_ref->need_setup = true;
|
||||
|
||||
ep->opened++;
|
||||
|
||||
unlock:
|
||||
|
@ -760,12 +804,16 @@ void snd_usb_endpoint_close(struct snd_usb_audio *chip,
|
|||
mutex_lock(&chip->mutex);
|
||||
usb_audio_dbg(chip, "Closing EP 0x%x (count %d)\n",
|
||||
ep->ep_num, ep->opened);
|
||||
if (!--ep->opened) {
|
||||
|
||||
if (!--ep->iface_ref->opened)
|
||||
endpoint_set_interface(chip, ep, false);
|
||||
|
||||
if (!--ep->opened) {
|
||||
ep->iface = 0;
|
||||
ep->altsetting = 0;
|
||||
ep->cur_audiofmt = NULL;
|
||||
ep->cur_rate = 0;
|
||||
ep->iface_ref = NULL;
|
||||
usb_audio_dbg(chip, "EP 0x%x closed\n", ep->ep_num);
|
||||
}
|
||||
mutex_unlock(&chip->mutex);
|
||||
|
@ -775,6 +823,8 @@ void snd_usb_endpoint_close(struct snd_usb_audio *chip,
|
|||
void snd_usb_endpoint_suspend(struct snd_usb_endpoint *ep)
|
||||
{
|
||||
ep->need_setup = true;
|
||||
if (ep->iface_ref)
|
||||
ep->iface_ref->need_setup = true;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1195,11 +1245,13 @@ int snd_usb_endpoint_configure(struct snd_usb_audio *chip,
|
|||
int err = 0;
|
||||
|
||||
mutex_lock(&chip->mutex);
|
||||
if (WARN_ON(!ep->iface_ref))
|
||||
goto unlock;
|
||||
if (!ep->need_setup)
|
||||
goto unlock;
|
||||
|
||||
/* No need to (re-)configure the sync EP belonging to the same altset */
|
||||
if (ep->ep_idx) {
|
||||
/* If the interface has been already set up, just set EP parameters */
|
||||
if (!ep->iface_ref->need_setup) {
|
||||
err = snd_usb_endpoint_set_params(chip, ep);
|
||||
if (err < 0)
|
||||
goto unlock;
|
||||
|
@ -1242,6 +1294,8 @@ int snd_usb_endpoint_configure(struct snd_usb_audio *chip,
|
|||
goto unlock;
|
||||
}
|
||||
|
||||
ep->iface_ref->need_setup = false;
|
||||
|
||||
done:
|
||||
ep->need_setup = false;
|
||||
err = 1;
|
||||
|
@ -1387,15 +1441,21 @@ void snd_usb_endpoint_release(struct snd_usb_endpoint *ep)
|
|||
}
|
||||
|
||||
/**
|
||||
* snd_usb_endpoint_free: Free the resources of an snd_usb_endpoint
|
||||
* snd_usb_endpoint_free_all: Free the resources of an snd_usb_endpoint
|
||||
* @card: The chip
|
||||
*
|
||||
* @ep: the endpoint to free
|
||||
*
|
||||
* This free all resources of the given ep.
|
||||
* This free all endpoints and those resources
|
||||
*/
|
||||
void snd_usb_endpoint_free(struct snd_usb_endpoint *ep)
|
||||
void snd_usb_endpoint_free_all(struct snd_usb_audio *chip)
|
||||
{
|
||||
kfree(ep);
|
||||
struct snd_usb_endpoint *ep, *en;
|
||||
struct snd_usb_iface_ref *ip, *in;
|
||||
|
||||
list_for_each_entry_safe(ep, en, &chip->ep_list, list)
|
||||
kfree(ep);
|
||||
|
||||
list_for_each_entry_safe(ip, in, &chip->iface_ref_list, list)
|
||||
kfree(ip);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -42,7 +42,7 @@ void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep);
|
|||
void snd_usb_endpoint_suspend(struct snd_usb_endpoint *ep);
|
||||
int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep);
|
||||
void snd_usb_endpoint_release(struct snd_usb_endpoint *ep);
|
||||
void snd_usb_endpoint_free(struct snd_usb_endpoint *ep);
|
||||
void snd_usb_endpoint_free_all(struct snd_usb_audio *chip);
|
||||
|
||||
int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep);
|
||||
int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep,
|
||||
|
|
|
@ -58,8 +58,6 @@ static const struct snd_usb_implicit_fb_match playback_implicit_fb_quirks[] = {
|
|||
IMPLICIT_FB_FIXED_DEV(0x0499, 0x172f, 0x81, 2), /* Steinberg UR22C */
|
||||
IMPLICIT_FB_FIXED_DEV(0x0d9a, 0x00df, 0x81, 2), /* RTX6001 */
|
||||
IMPLICIT_FB_FIXED_DEV(0x22f0, 0x0006, 0x81, 3), /* Allen&Heath Qu-16 */
|
||||
IMPLICIT_FB_FIXED_DEV(0x2b73, 0x000a, 0x82, 0), /* Pioneer DJ DJM-900NXS2 */
|
||||
IMPLICIT_FB_FIXED_DEV(0x2b73, 0x0017, 0x82, 0), /* Pioneer DJ DJM-250MK2 */
|
||||
IMPLICIT_FB_FIXED_DEV(0x1686, 0xf029, 0x82, 2), /* Zoom UAC-2 */
|
||||
IMPLICIT_FB_FIXED_DEV(0x2466, 0x8003, 0x86, 2), /* Fractal Audio Axe-Fx II */
|
||||
IMPLICIT_FB_FIXED_DEV(0x0499, 0x172a, 0x86, 2), /* Yamaha MODX */
|
||||
|
@ -100,7 +98,7 @@ static const struct snd_usb_implicit_fb_match capture_implicit_fb_quirks[] = {
|
|||
/* set up sync EP information on the audioformat */
|
||||
static int add_implicit_fb_sync_ep(struct snd_usb_audio *chip,
|
||||
struct audioformat *fmt,
|
||||
int ep, int ifnum,
|
||||
int ep, int ep_idx, int ifnum,
|
||||
const struct usb_host_interface *alts)
|
||||
{
|
||||
struct usb_interface *iface;
|
||||
|
@ -115,7 +113,7 @@ static int add_implicit_fb_sync_ep(struct snd_usb_audio *chip,
|
|||
fmt->sync_ep = ep;
|
||||
fmt->sync_iface = ifnum;
|
||||
fmt->sync_altsetting = alts->desc.bAlternateSetting;
|
||||
fmt->sync_ep_idx = 0;
|
||||
fmt->sync_ep_idx = ep_idx;
|
||||
fmt->implicit_fb = 1;
|
||||
usb_audio_dbg(chip,
|
||||
"%d:%d: added %s implicit_fb sync_ep %x, iface %d:%d\n",
|
||||
|
@ -147,7 +145,7 @@ static int add_generic_uac2_implicit_fb(struct snd_usb_audio *chip,
|
|||
(epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) !=
|
||||
USB_ENDPOINT_USAGE_IMPLICIT_FB)
|
||||
return 0;
|
||||
return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress,
|
||||
return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress, 0,
|
||||
ifnum, alts);
|
||||
}
|
||||
|
||||
|
@ -173,10 +171,32 @@ static int add_roland_implicit_fb(struct snd_usb_audio *chip,
|
|||
(epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) !=
|
||||
USB_ENDPOINT_USAGE_IMPLICIT_FB)
|
||||
return 0;
|
||||
return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress,
|
||||
return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress, 0,
|
||||
ifnum, alts);
|
||||
}
|
||||
|
||||
/* Pioneer devices: playback and capture streams sharing the same iface/altset
|
||||
*/
|
||||
static int add_pioneer_implicit_fb(struct snd_usb_audio *chip,
|
||||
struct audioformat *fmt,
|
||||
struct usb_host_interface *alts)
|
||||
{
|
||||
struct usb_endpoint_descriptor *epd;
|
||||
|
||||
if (alts->desc.bNumEndpoints != 2)
|
||||
return 0;
|
||||
|
||||
epd = get_endpoint(alts, 1);
|
||||
if (!usb_endpoint_is_isoc_in(epd) ||
|
||||
(epd->bmAttributes & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC ||
|
||||
((epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) !=
|
||||
USB_ENDPOINT_USAGE_DATA &&
|
||||
(epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) !=
|
||||
USB_ENDPOINT_USAGE_IMPLICIT_FB))
|
||||
return 0;
|
||||
return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress, 1,
|
||||
alts->desc.bInterfaceNumber, alts);
|
||||
}
|
||||
|
||||
static int __add_generic_implicit_fb(struct snd_usb_audio *chip,
|
||||
struct audioformat *fmt,
|
||||
|
@ -197,7 +217,7 @@ static int __add_generic_implicit_fb(struct snd_usb_audio *chip,
|
|||
if (!usb_endpoint_is_isoc_in(epd) ||
|
||||
(epd->bmAttributes & USB_ENDPOINT_SYNCTYPE) != USB_ENDPOINT_SYNC_ASYNC)
|
||||
return 0;
|
||||
return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress,
|
||||
return add_implicit_fb_sync_ep(chip, fmt, epd->bEndpointAddress, 0,
|
||||
iface, alts);
|
||||
}
|
||||
|
||||
|
@ -250,7 +270,7 @@ static int audioformat_implicit_fb_quirk(struct snd_usb_audio *chip,
|
|||
case IMPLICIT_FB_NONE:
|
||||
return 0; /* No quirk */
|
||||
case IMPLICIT_FB_FIXED:
|
||||
return add_implicit_fb_sync_ep(chip, fmt, p->ep_num,
|
||||
return add_implicit_fb_sync_ep(chip, fmt, p->ep_num, 0,
|
||||
p->iface, NULL);
|
||||
}
|
||||
}
|
||||
|
@ -278,6 +298,14 @@ static int audioformat_implicit_fb_quirk(struct snd_usb_audio *chip,
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* Pioneer devices implicit feedback with vendor spec class */
|
||||
if (attr == USB_ENDPOINT_SYNC_ASYNC &&
|
||||
alts->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC &&
|
||||
USB_ID_VENDOR(chip->usb_id) == 0x2b73 /* Pioneer */) {
|
||||
if (add_pioneer_implicit_fb(chip, fmt, alts))
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Try the generic implicit fb if available */
|
||||
if (chip->generic_implicit_fb)
|
||||
return add_generic_implicit_fb(chip, fmt, alts);
|
||||
|
@ -295,8 +323,8 @@ static int audioformat_capture_quirk(struct snd_usb_audio *chip,
|
|||
|
||||
p = find_implicit_fb_entry(chip, capture_implicit_fb_quirks, alts);
|
||||
if (p && p->type == IMPLICIT_FB_FIXED)
|
||||
return add_implicit_fb_sync_ep(chip, fmt, p->ep_num, p->iface,
|
||||
NULL);
|
||||
return add_implicit_fb_sync_ep(chip, fmt, p->ep_num, 0,
|
||||
p->iface, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -378,20 +406,19 @@ snd_usb_find_implicit_fb_sync_format(struct snd_usb_audio *chip,
|
|||
int stream)
|
||||
{
|
||||
struct snd_usb_substream *subs;
|
||||
const struct audioformat *fp, *sync_fmt;
|
||||
const struct audioformat *fp, *sync_fmt = NULL;
|
||||
int score, high_score;
|
||||
|
||||
/* When sharing the same altset, use the original audioformat */
|
||||
/* Use the original audioformat as fallback for the shared altset */
|
||||
if (target->iface == target->sync_iface &&
|
||||
target->altsetting == target->sync_altsetting)
|
||||
return target;
|
||||
sync_fmt = target;
|
||||
|
||||
subs = find_matching_substream(chip, stream, target->sync_ep,
|
||||
target->fmt_type);
|
||||
if (!subs)
|
||||
return NULL;
|
||||
return sync_fmt;
|
||||
|
||||
sync_fmt = NULL;
|
||||
high_score = 0;
|
||||
list_for_each_entry(fp, &subs->fmt_list, list) {
|
||||
score = match_endpoint_audioformats(subs, fp,
|
||||
|
|
|
@ -3362,6 +3362,7 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
|
|||
.altsetting = 1,
|
||||
.altset_idx = 1,
|
||||
.endpoint = 0x86,
|
||||
.ep_idx = 1,
|
||||
.ep_attr = USB_ENDPOINT_XFER_ISOC|
|
||||
USB_ENDPOINT_SYNC_ASYNC|
|
||||
USB_ENDPOINT_USAGE_IMPLICIT_FB,
|
||||
|
@ -3450,6 +3451,7 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
|
|||
.altsetting = 1,
|
||||
.altset_idx = 1,
|
||||
.endpoint = 0x82,
|
||||
.ep_idx = 1,
|
||||
.ep_attr = USB_ENDPOINT_XFER_ISOC|
|
||||
USB_ENDPOINT_SYNC_ASYNC|
|
||||
USB_ENDPOINT_USAGE_IMPLICIT_FB,
|
||||
|
@ -3506,6 +3508,7 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
|
|||
.altsetting = 1,
|
||||
.altset_idx = 1,
|
||||
.endpoint = 0x82,
|
||||
.ep_idx = 1,
|
||||
.ep_attr = USB_ENDPOINT_XFER_ISOC|
|
||||
USB_ENDPOINT_SYNC_ASYNC|
|
||||
USB_ENDPOINT_USAGE_IMPLICIT_FB,
|
||||
|
@ -3562,6 +3565,7 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
|
|||
.altsetting = 1,
|
||||
.altset_idx = 1,
|
||||
.endpoint = 0x82,
|
||||
.ep_idx = 1,
|
||||
.ep_attr = USB_ENDPOINT_XFER_ISOC|
|
||||
USB_ENDPOINT_SYNC_ASYNC|
|
||||
USB_ENDPOINT_USAGE_IMPLICIT_FB,
|
||||
|
@ -3619,6 +3623,7 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
|
|||
.altsetting = 1,
|
||||
.altset_idx = 1,
|
||||
.endpoint = 0x82,
|
||||
.ep_idx = 1,
|
||||
.ep_attr = USB_ENDPOINT_XFER_ISOC|
|
||||
USB_ENDPOINT_SYNC_ASYNC|
|
||||
USB_ENDPOINT_USAGE_IMPLICIT_FB,
|
||||
|
@ -3679,6 +3684,7 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
|
|||
.altsetting = 1,
|
||||
.altset_idx = 1,
|
||||
.endpoint = 0x82,
|
||||
.ep_idx = 1,
|
||||
.ep_attr = USB_ENDPOINT_XFER_ISOC|
|
||||
USB_ENDPOINT_SYNC_ASYNC|
|
||||
USB_ENDPOINT_USAGE_IMPLICIT_FB,
|
||||
|
|
|
@ -120,6 +120,40 @@ static int create_standard_audio_quirk(struct snd_usb_audio *chip,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* create the audio stream and the corresponding endpoints from the fixed
|
||||
* audioformat object; this is used for quirks with the fixed EPs
|
||||
*/
|
||||
static int add_audio_stream_from_fixed_fmt(struct snd_usb_audio *chip,
|
||||
struct audioformat *fp)
|
||||
{
|
||||
int stream, err;
|
||||
|
||||
stream = (fp->endpoint & USB_DIR_IN) ?
|
||||
SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
|
||||
|
||||
snd_usb_audioformat_set_sync_ep(chip, fp);
|
||||
|
||||
err = snd_usb_add_audio_stream(chip, stream, fp);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = snd_usb_add_endpoint(chip, fp->endpoint,
|
||||
SND_USB_ENDPOINT_TYPE_DATA);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (fp->sync_ep) {
|
||||
err = snd_usb_add_endpoint(chip, fp->sync_ep,
|
||||
fp->implicit_fb ?
|
||||
SND_USB_ENDPOINT_TYPE_DATA :
|
||||
SND_USB_ENDPOINT_TYPE_SYNC);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* create a stream for an endpoint/altsetting without proper descriptors
|
||||
*/
|
||||
|
@ -131,8 +165,8 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
|
|||
struct audioformat *fp;
|
||||
struct usb_host_interface *alts;
|
||||
struct usb_interface_descriptor *altsd;
|
||||
int stream, err;
|
||||
unsigned *rate_table = NULL;
|
||||
int err;
|
||||
|
||||
fp = kmemdup(quirk->data, sizeof(*fp), GFP_KERNEL);
|
||||
if (!fp)
|
||||
|
@ -153,11 +187,6 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
|
|||
fp->rate_table = rate_table;
|
||||
}
|
||||
|
||||
stream = (fp->endpoint & USB_DIR_IN)
|
||||
? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
|
||||
err = snd_usb_add_audio_stream(chip, stream, fp);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
if (fp->iface != get_iface_desc(&iface->altsetting[0])->bInterfaceNumber ||
|
||||
fp->altset_idx >= iface->num_altsetting) {
|
||||
err = -EINVAL;
|
||||
|
@ -165,7 +194,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
|
|||
}
|
||||
alts = &iface->altsetting[fp->altset_idx];
|
||||
altsd = get_iface_desc(alts);
|
||||
if (altsd->bNumEndpoints < 1) {
|
||||
if (altsd->bNumEndpoints <= fp->ep_idx) {
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
@ -175,7 +204,14 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
|
|||
if (fp->datainterval == 0)
|
||||
fp->datainterval = snd_usb_parse_datainterval(chip, alts);
|
||||
if (fp->maxpacksize == 0)
|
||||
fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
|
||||
fp->maxpacksize = le16_to_cpu(get_endpoint(alts, fp->ep_idx)->wMaxPacketSize);
|
||||
if (!fp->fmt_type)
|
||||
fp->fmt_type = UAC_FORMAT_TYPE_I;
|
||||
|
||||
err = add_audio_stream_from_fixed_fmt(chip, fp);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
usb_set_interface(chip->dev, fp->iface, 0);
|
||||
snd_usb_init_pitch(chip, fp);
|
||||
snd_usb_init_sample_rate(chip, fp, fp->rate_max);
|
||||
|
@ -417,7 +453,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
|
|||
struct usb_host_interface *alts;
|
||||
struct usb_interface_descriptor *altsd;
|
||||
struct audioformat *fp;
|
||||
int stream, err;
|
||||
int err;
|
||||
|
||||
/* both PCM and MIDI interfaces have 2 or more altsettings */
|
||||
if (iface->num_altsetting < 2)
|
||||
|
@ -482,9 +518,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip,
|
|||
return -ENXIO;
|
||||
}
|
||||
|
||||
stream = (fp->endpoint & USB_DIR_IN)
|
||||
? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
|
||||
err = snd_usb_add_audio_stream(chip, stream, fp);
|
||||
err = add_audio_stream_from_fixed_fmt(chip, fp);
|
||||
if (err < 0) {
|
||||
list_del(&fp->list); /* unlink for avoiding double-free */
|
||||
kfree(fp);
|
||||
|
|
|
@ -44,6 +44,7 @@ struct snd_usb_audio {
|
|||
|
||||
struct list_head pcm_list; /* list of pcm streams */
|
||||
struct list_head ep_list; /* list of audio-related endpoints */
|
||||
struct list_head iface_ref_list; /* list of interface refcounts */
|
||||
int pcm_devs;
|
||||
|
||||
struct list_head midi_list; /* list of midi interfaces */
|
||||
|
|
Loading…
Reference in New Issue