ASoC: Fixes for v5.17

Quite a few fixes here, including an unusually large set in the core
 spurred on by various testing efforts as well as the usual small driver
 fixes.  There are quite a few fixes for out of bounds writes in both the
 core and the various Qualcomm drivers, plus a couple of fixes for
 locking in the DPCM code.
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAmH5Vi4ACgkQJNaLcl1U
 h9Ah6gf/SdlpKMKgAYiXAfmhb/88UgWkXWwHYgK+uHQXy3VpiG3zOso2uHQTbZ0X
 +QMZ1LwPbcSsz6Ny/w/kQ4MKeklHou0X6GiQ6PRoDukBPQ6yidivwnVXt35qNBwT
 iYmMuLpWsq0CrbUp9cPX+zurX+jUv/CKuwG1JnHxS2+lQ7UjetUOfKzO80X4zUA5
 tm12soU9PSUcSyBICg5Jn+Tt9ZPccJ4cDPLfdRVkKjwb+6o4CnuM56Jq9UeHY6KT
 SGr8/Jt0I61p8UHPUpqJsj2ItHhy80bNraSaNptQljlIYCPidgFlPKyXxgunm8e5
 Z2PUG2mOIR4pk0cj1SxOXwhH9+d3dQ==
 =UdmQ
 -----END PGP SIGNATURE-----

Merge tag 'asoc-fix-v5.17-rc2' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus

ASoC: Fixes for v5.17

Quite a few fixes here, including an unusually large set in the core
spurred on by various testing efforts as well as the usual small driver
fixes.  There are quite a few fixes for out of bounds writes in both the
core and the various Qualcomm drivers, plus a couple of fixes for
locking in the DPCM code.
This commit is contained in:
Takashi Iwai 2022-02-01 16:52:54 +01:00
commit 52517d9c0c
20 changed files with 178 additions and 83 deletions

View File

@ -615,10 +615,9 @@ static int wm97xx_register_touch(struct wm97xx *wm)
* extensions)
*/
wm->touch_dev = platform_device_alloc("wm97xx-touch", -1);
if (!wm->touch_dev) {
ret = -ENOMEM;
goto touch_err;
}
if (!wm->touch_dev)
return -ENOMEM;
platform_set_drvdata(wm->touch_dev, wm);
wm->touch_dev->dev.parent = wm->dev;
wm->touch_dev->dev.platform_data = pdata;
@ -629,9 +628,6 @@ static int wm97xx_register_touch(struct wm97xx *wm)
return 0;
touch_reg_err:
platform_device_put(wm->touch_dev);
touch_err:
input_unregister_device(wm->input_dev);
wm->input_dev = NULL;
return ret;
}
@ -639,8 +635,6 @@ touch_err:
static void wm97xx_unregister_touch(struct wm97xx *wm)
{
platform_device_unregister(wm->touch_dev);
input_unregister_device(wm->input_dev);
wm->input_dev = NULL;
}
static int _wm97xx_probe(struct wm97xx *wm)

View File

@ -617,6 +617,7 @@ void snd_pcm_stream_unlock(struct snd_pcm_substream *substream);
void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream);
void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream);
unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream);
unsigned long _snd_pcm_stream_lock_irqsave_nested(struct snd_pcm_substream *substream);
/**
* snd_pcm_stream_lock_irqsave - Lock the PCM stream
@ -635,6 +636,20 @@ unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream);
void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream,
unsigned long flags);
/**
* snd_pcm_stream_lock_irqsave_nested - Single-nested PCM stream locking
* @substream: PCM substream
* @flags: irq flags
*
* This locks the PCM stream like snd_pcm_stream_lock_irqsave() but with
* the single-depth lockdep subclass.
*/
#define snd_pcm_stream_lock_irqsave_nested(substream, flags) \
do { \
typecheck(unsigned long, flags); \
flags = _snd_pcm_stream_lock_irqsave_nested(substream); \
} while (0)
/**
* snd_pcm_group_for_each_entry - iterate over the linked substreams
* @s: the iterator

View File

@ -56,8 +56,10 @@
* *
****************************************************************************/
#define AES_IEC958_STATUS_SIZE 24
struct snd_aes_iec958 {
unsigned char status[24]; /* AES/IEC958 channel status bits */
unsigned char status[AES_IEC958_STATUS_SIZE]; /* AES/IEC958 channel status bits */
unsigned char subcode[147]; /* AES/IEC958 subcode bits */
unsigned char pad; /* nothing */
unsigned char dig_subframe[4]; /* AES/IEC958 subframe bits */

View File

@ -172,6 +172,19 @@ unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream)
}
EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave);
unsigned long _snd_pcm_stream_lock_irqsave_nested(struct snd_pcm_substream *substream)
{
unsigned long flags = 0;
if (substream->pcm->nonatomic)
mutex_lock_nested(&substream->self_group.mutex,
SINGLE_DEPTH_NESTING);
else
spin_lock_irqsave_nested(&substream->self_group.lock, flags,
SINGLE_DEPTH_NESTING);
return flags;
}
EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave_nested);
/**
* snd_pcm_stream_unlock_irqrestore - Unlock the PCM stream
* @substream: PCM substream

View File

@ -303,11 +303,11 @@ static const struct snd_soc_dapm_route rt1019_map_lr[] = {
static struct snd_soc_codec_conf rt1019_conf[] = {
{
.dlc = COMP_CODEC_CONF("i2c-10EC1019:00"),
.dlc = COMP_CODEC_CONF("i2c-10EC1019:01"),
.name_prefix = "Left",
},
{
.dlc = COMP_CODEC_CONF("i2c-10EC1019:01"),
.dlc = COMP_CODEC_CONF("i2c-10EC1019:00"),
.name_prefix = "Right",
},
};

View File

@ -1667,6 +1667,8 @@ static int cpcap_codec_probe(struct platform_device *pdev)
{
struct device_node *codec_node =
of_get_child_by_name(pdev->dev.parent->of_node, "audio-codec");
if (!codec_node)
return -ENODEV;
pdev->dev.of_node = codec_node;

View File

@ -277,7 +277,7 @@ struct hdmi_codec_priv {
bool busy;
struct snd_soc_jack *jack;
unsigned int jack_status;
u8 iec_status[5];
u8 iec_status[AES_IEC958_STATUS_SIZE];
};
static const struct snd_soc_dapm_widget hdmi_widgets[] = {

View File

@ -2688,8 +2688,8 @@ static uint32_t get_iir_band_coeff(struct snd_soc_component *component,
int reg, b2_reg;
/* Address does not automatically update if reading */
reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx;
b2_reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx;
reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 0x80 * iir_idx;
b2_reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 0x80 * iir_idx;
snd_soc_component_write(component, reg,
((band_idx * BAND_MAX + coeff_idx) *
@ -2718,7 +2718,7 @@ static uint32_t get_iir_band_coeff(struct snd_soc_component *component,
static void set_iir_band_coeff(struct snd_soc_component *component,
int iir_idx, int band_idx, uint32_t value)
{
int reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 16 * iir_idx;
int reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B2_CTL + 0x80 * iir_idx;
snd_soc_component_write(component, reg, (value & 0xFF));
snd_soc_component_write(component, reg, (value >> 8) & 0xFF);
@ -2739,7 +2739,7 @@ static int rx_macro_put_iir_band_audio_mixer(
int iir_idx = ctl->iir_idx;
int band_idx = ctl->band_idx;
u32 coeff[BAND_MAX];
int reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 16 * iir_idx;
int reg = CDC_RX_SIDETONE_IIR0_IIR_COEF_B1_CTL + 0x80 * iir_idx;
memcpy(&coeff[0], ucontrol->value.bytes.data, params->max);

View File

@ -64,7 +64,8 @@ static int speaker_gain_control_put(struct snd_kcontrol *kcontrol,
struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
struct max9759 *priv = snd_soc_component_get_drvdata(c);
if (ucontrol->value.integer.value[0] > 3)
if (ucontrol->value.integer.value[0] < 0 ||
ucontrol->value.integer.value[0] > 3)
return -EINVAL;
priv->gain = ucontrol->value.integer.value[0];

View File

@ -59,18 +59,12 @@ static void rt5682_jd_check_handler(struct work_struct *work)
struct rt5682_priv *rt5682 = container_of(work, struct rt5682_priv,
jd_check_work.work);
if (snd_soc_component_read(rt5682->component, RT5682_AJD1_CTRL)
& RT5682_JDH_RS_MASK) {
if (snd_soc_component_read(rt5682->component, RT5682_AJD1_CTRL) & RT5682_JDH_RS_MASK)
/* jack out */
rt5682->jack_type = rt5682_headset_detect(rt5682->component, 0);
snd_soc_jack_report(rt5682->hs_jack, rt5682->jack_type,
SND_JACK_HEADSET |
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3);
} else {
mod_delayed_work(system_power_efficient_wq,
&rt5682->jack_detect_work, 0);
else
schedule_delayed_work(&rt5682->jd_check_work, 500);
}
}
static irqreturn_t rt5682_irq(int irq, void *data)
@ -198,7 +192,6 @@ static int rt5682_i2c_probe(struct i2c_client *i2c,
}
mutex_init(&rt5682->calibrate_mutex);
mutex_init(&rt5682->jdet_mutex);
rt5682_calibrate(rt5682);
rt5682_apply_patch_list(rt5682, &i2c->dev);

View File

@ -922,15 +922,13 @@ static void rt5682_enable_push_button_irq(struct snd_soc_component *component,
*
* Returns detect status.
*/
int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
static int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
{
struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
struct snd_soc_dapm_context *dapm = &component->dapm;
unsigned int val, count;
if (jack_insert) {
snd_soc_dapm_mutex_lock(dapm);
snd_soc_component_update_bits(component, RT5682_PWR_ANLG_1,
RT5682_PWR_VREF2 | RT5682_PWR_MB,
RT5682_PWR_VREF2 | RT5682_PWR_MB);
@ -981,8 +979,6 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
snd_soc_component_update_bits(component, RT5682_MICBIAS_2,
RT5682_PWR_CLK25M_MASK | RT5682_PWR_CLK1M_MASK,
RT5682_PWR_CLK25M_PU | RT5682_PWR_CLK1M_PU);
snd_soc_dapm_mutex_unlock(dapm);
} else {
rt5682_enable_push_button_irq(component, false);
snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
@ -1011,7 +1007,6 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
dev_dbg(component->dev, "jack_type = %d\n", rt5682->jack_type);
return rt5682->jack_type;
}
EXPORT_SYMBOL_GPL(rt5682_headset_detect);
static int rt5682_set_jack_detect(struct snd_soc_component *component,
struct snd_soc_jack *hs_jack, void *data)
@ -1094,6 +1089,7 @@ void rt5682_jack_detect_handler(struct work_struct *work)
{
struct rt5682_priv *rt5682 =
container_of(work, struct rt5682_priv, jack_detect_work.work);
struct snd_soc_dapm_context *dapm;
int val, btn_type;
while (!rt5682->component)
@ -1102,7 +1098,9 @@ void rt5682_jack_detect_handler(struct work_struct *work)
while (!rt5682->component->card->instantiated)
usleep_range(10000, 15000);
mutex_lock(&rt5682->jdet_mutex);
dapm = snd_soc_component_get_dapm(rt5682->component);
snd_soc_dapm_mutex_lock(dapm);
mutex_lock(&rt5682->calibrate_mutex);
val = snd_soc_component_read(rt5682->component, RT5682_AJD1_CTRL)
@ -1162,6 +1160,9 @@ void rt5682_jack_detect_handler(struct work_struct *work)
rt5682->irq_work_delay_time = 50;
}
mutex_unlock(&rt5682->calibrate_mutex);
snd_soc_dapm_mutex_unlock(dapm);
snd_soc_jack_report(rt5682->hs_jack, rt5682->jack_type,
SND_JACK_HEADSET |
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
@ -1174,9 +1175,6 @@ void rt5682_jack_detect_handler(struct work_struct *work)
else
cancel_delayed_work_sync(&rt5682->jd_check_work);
}
mutex_unlock(&rt5682->calibrate_mutex);
mutex_unlock(&rt5682->jdet_mutex);
}
EXPORT_SYMBOL_GPL(rt5682_jack_detect_handler);
@ -1526,7 +1524,6 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w,
{
struct snd_soc_component *component =
snd_soc_dapm_to_component(w->dapm);
struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
@ -1538,17 +1535,12 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w,
RT5682_DEPOP_1, 0x60, 0x60);
snd_soc_component_update_bits(component,
RT5682_DAC_ADC_DIG_VOL1, 0x00c0, 0x0080);
mutex_lock(&rt5682->jdet_mutex);
snd_soc_component_update_bits(component, RT5682_HP_CTRL_2,
RT5682_HP_C2_DAC_L_EN | RT5682_HP_C2_DAC_R_EN,
RT5682_HP_C2_DAC_L_EN | RT5682_HP_C2_DAC_R_EN);
usleep_range(5000, 10000);
snd_soc_component_update_bits(component, RT5682_CHARGE_PUMP_1,
RT5682_CP_SW_SIZE_MASK, RT5682_CP_SW_SIZE_L);
mutex_unlock(&rt5682->jdet_mutex);
break;
case SND_SOC_DAPM_POST_PMD:

View File

@ -1463,7 +1463,6 @@ struct rt5682_priv {
int jack_type;
int irq_work_delay_time;
struct mutex jdet_mutex;
};
extern const char *rt5682_supply_names[RT5682_NUM_SUPPLIES];
@ -1473,7 +1472,6 @@ int rt5682_sel_asrc_clk_src(struct snd_soc_component *component,
void rt5682_apply_patch_list(struct rt5682_priv *rt5682, struct device *dev);
int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert);
void rt5682_jack_detect_handler(struct work_struct *work);
bool rt5682_volatile_register(struct device *dev, unsigned int reg);

View File

@ -1432,14 +1432,10 @@ static int wcd938x_sdw_connect_port(struct wcd938x_sdw_ch_info *ch_info,
return 0;
}
static int wcd938x_connect_port(struct wcd938x_sdw_priv *wcd, u8 ch_id, u8 enable)
static int wcd938x_connect_port(struct wcd938x_sdw_priv *wcd, u8 port_num, u8 ch_id, u8 enable)
{
u8 port_num;
port_num = wcd->ch_info[ch_id].port_num;
return wcd938x_sdw_connect_port(&wcd->ch_info[ch_id],
&wcd->port_config[port_num],
&wcd->port_config[port_num - 1],
enable);
}
@ -2563,7 +2559,7 @@ static int wcd938x_ear_pa_put_gain(struct snd_kcontrol *kcontrol,
WCD938X_EAR_GAIN_MASK,
ucontrol->value.integer.value[0]);
return 0;
return 1;
}
static int wcd938x_get_compander(struct snd_kcontrol *kcontrol,
@ -2593,6 +2589,7 @@ static int wcd938x_set_compander(struct snd_kcontrol *kcontrol,
struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
struct wcd938x_sdw_priv *wcd;
int value = ucontrol->value.integer.value[0];
int portidx;
struct soc_mixer_control *mc;
bool hphr;
@ -2606,12 +2603,14 @@ static int wcd938x_set_compander(struct snd_kcontrol *kcontrol,
else
wcd938x->comp1_enable = value;
if (value)
wcd938x_connect_port(wcd, mc->reg, true);
else
wcd938x_connect_port(wcd, mc->reg, false);
portidx = wcd->ch_info[mc->reg].port_num;
return 0;
if (value)
wcd938x_connect_port(wcd, portidx, mc->reg, true);
else
wcd938x_connect_port(wcd, portidx, mc->reg, false);
return 1;
}
static int wcd938x_ldoh_get(struct snd_kcontrol *kcontrol,
@ -2882,9 +2881,11 @@ static int wcd938x_get_swr_port(struct snd_kcontrol *kcontrol,
struct wcd938x_sdw_priv *wcd;
struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value;
int dai_id = mixer->shift;
int portidx = mixer->reg;
int portidx, ch_idx = mixer->reg;
wcd = wcd938x->sdw_priv[dai_id];
portidx = wcd->ch_info[ch_idx].port_num;
ucontrol->value.integer.value[0] = wcd->port_enable[portidx];
@ -2899,12 +2900,14 @@ static int wcd938x_set_swr_port(struct snd_kcontrol *kcontrol,
struct wcd938x_sdw_priv *wcd;
struct soc_mixer_control *mixer =
(struct soc_mixer_control *)kcontrol->private_value;
int portidx = mixer->reg;
int ch_idx = mixer->reg;
int portidx;
int dai_id = mixer->shift;
bool enable;
wcd = wcd938x->sdw_priv[dai_id];
portidx = wcd->ch_info[ch_idx].port_num;
if (ucontrol->value.integer.value[0])
enable = true;
else
@ -2912,9 +2915,9 @@ static int wcd938x_set_swr_port(struct snd_kcontrol *kcontrol,
wcd->port_enable[portidx] = enable;
wcd938x_connect_port(wcd, portidx, enable);
wcd938x_connect_port(wcd, portidx, ch_idx, enable);
return 0;
return 1;
}

View File

@ -93,16 +93,21 @@ static int pcm030_fabric_probe(struct platform_device *op)
dev_err(&op->dev, "platform_device_alloc() failed\n");
ret = platform_device_add(pdata->codec_device);
if (ret)
if (ret) {
dev_err(&op->dev, "platform_device_add() failed: %d\n", ret);
platform_device_put(pdata->codec_device);
}
ret = snd_soc_register_card(card);
if (ret)
if (ret) {
dev_err(&op->dev, "snd_soc_register_card() failed: %d\n", ret);
platform_device_del(pdata->codec_device);
platform_device_put(pdata->codec_device);
}
platform_set_drvdata(op, pdata);
return ret;
}
static int pcm030_fabric_remove(struct platform_device *op)

View File

@ -28,6 +28,30 @@ static const struct snd_soc_ops simple_ops = {
.hw_params = asoc_simple_hw_params,
};
static int asoc_simple_parse_platform(struct device_node *node,
struct snd_soc_dai_link_component *dlc)
{
struct of_phandle_args args;
int ret;
if (!node)
return 0;
/*
* Get node via "sound-dai = <&phandle port>"
* it will be used as xxx_of_node on soc_bind_dai_link()
*/
ret = of_parse_phandle_with_args(node, DAI, CELL, 0, &args);
if (ret)
return ret;
/* dai_name is not required and may not exist for plat component */
dlc->of_node = args.np;
return 0;
}
static int asoc_simple_parse_dai(struct device_node *node,
struct snd_soc_dai_link_component *dlc,
int *is_single_link)
@ -289,7 +313,7 @@ static int simple_dai_link_of(struct asoc_simple_priv *priv,
if (ret < 0)
goto dai_link_of_err;
ret = asoc_simple_parse_dai(plat, platforms, NULL);
ret = asoc_simple_parse_platform(plat, platforms);
if (ret < 0)
goto dai_link_of_err;

View File

@ -216,7 +216,7 @@ config SND_SOC_MT8195_MT6359_RT1019_RT5682
config SND_SOC_MT8195_MT6359_RT1011_RT5682
tristate "ASoC Audio driver for MT8195 with MT6359 RT1011 RT5682 codec"
depends on I2C
depends on I2C && GPIOLIB
depends on SND_SOC_MT8195 && MTK_PMIC_WRAP
select SND_SOC_MT6359
select SND_SOC_RT1011

View File

@ -308,8 +308,11 @@ static int q6apm_dai_close(struct snd_soc_component *component,
struct snd_pcm_runtime *runtime = substream->runtime;
struct q6apm_dai_rtd *prtd = runtime->private_data;
q6apm_graph_stop(prtd->graph);
q6apm_unmap_memory_regions(prtd->graph, substream->stream);
if (prtd->state) { /* only stop graph that is started */
q6apm_graph_stop(prtd->graph);
q6apm_unmap_memory_regions(prtd->graph, substream->stream);
}
q6apm_graph_close(prtd->graph);
prtd->graph = NULL;
kfree(prtd);

View File

@ -316,13 +316,27 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
if (sign_bit)
mask = BIT(sign_bit + 1) - 1;
val = ((ucontrol->value.integer.value[0] + min) & mask);
if (ucontrol->value.integer.value[0] < 0)
return -EINVAL;
val = ucontrol->value.integer.value[0];
if (mc->platform_max && val > mc->platform_max)
return -EINVAL;
if (val > max - min)
return -EINVAL;
val = (val + min) & mask;
if (invert)
val = max - val;
val_mask = mask << shift;
val = val << shift;
if (snd_soc_volsw_is_stereo(mc)) {
val2 = ((ucontrol->value.integer.value[1] + min) & mask);
if (ucontrol->value.integer.value[1] < 0)
return -EINVAL;
val2 = ucontrol->value.integer.value[1];
if (mc->platform_max && val2 > mc->platform_max)
return -EINVAL;
if (val2 > max - min)
return -EINVAL;
val2 = (val2 + min) & mask;
if (invert)
val2 = max - val2;
if (reg == reg2) {
@ -409,8 +423,15 @@ int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
int err = 0;
unsigned int val, val_mask;
if (ucontrol->value.integer.value[0] < 0)
return -EINVAL;
val = ucontrol->value.integer.value[0];
if (mc->platform_max && val > mc->platform_max)
return -EINVAL;
if (val > max - min)
return -EINVAL;
val_mask = mask << shift;
val = (ucontrol->value.integer.value[0] + min) & mask;
val = (val + min) & mask;
val = val << shift;
err = snd_soc_component_update_bits(component, reg, val_mask, val);
@ -858,6 +879,8 @@ int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol,
long val = ucontrol->value.integer.value[0];
unsigned int i;
if (val < mc->min || val > mc->max)
return -EINVAL;
if (invert)
val = max - val;
val &= mask;

View File

@ -46,8 +46,8 @@ static inline void snd_soc_dpcm_stream_lock_irq(struct snd_soc_pcm_runtime *rtd,
snd_pcm_stream_lock_irq(snd_soc_dpcm_get_substream(rtd, stream));
}
#define snd_soc_dpcm_stream_lock_irqsave(rtd, stream, flags) \
snd_pcm_stream_lock_irqsave(snd_soc_dpcm_get_substream(rtd, stream), flags)
#define snd_soc_dpcm_stream_lock_irqsave_nested(rtd, stream, flags) \
snd_pcm_stream_lock_irqsave_nested(snd_soc_dpcm_get_substream(rtd, stream), flags)
static inline void snd_soc_dpcm_stream_unlock_irq(struct snd_soc_pcm_runtime *rtd,
int stream)
@ -1268,6 +1268,7 @@ static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe,
void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
{
struct snd_soc_dpcm *dpcm, *d;
LIST_HEAD(deleted_dpcms);
snd_soc_dpcm_mutex_assert_held(fe);
@ -1287,13 +1288,18 @@ void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
/* BEs still alive need new FE */
dpcm_be_reparent(fe, dpcm->be, stream);
dpcm_remove_debugfs_state(dpcm);
list_del(&dpcm->list_be);
list_del(&dpcm->list_fe);
kfree(dpcm);
list_move(&dpcm->list_fe, &deleted_dpcms);
}
snd_soc_dpcm_stream_unlock_irq(fe, stream);
while (!list_empty(&deleted_dpcms)) {
dpcm = list_first_entry(&deleted_dpcms, struct snd_soc_dpcm,
list_fe);
list_del(&dpcm->list_fe);
dpcm_remove_debugfs_state(dpcm);
kfree(dpcm);
}
}
/* get BE for DAI widget and stream */
@ -2094,7 +2100,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
be = dpcm->be;
be_substream = snd_soc_dpcm_get_substream(be, stream);
snd_soc_dpcm_stream_lock_irqsave(be, stream, flags);
snd_soc_dpcm_stream_lock_irqsave_nested(be, stream, flags);
/* is this op for this BE ? */
if (!snd_soc_dpcm_be_can_update(fe, be, stream))

View File

@ -37,6 +37,7 @@
#define XLNX_AUD_XFER_COUNT 0x28
#define XLNX_AUD_CH_STS_START 0x2C
#define XLNX_BYTES_PER_CH 0x44
#define XLNX_AUD_ALIGN_BYTES 64
#define AUD_STS_IOC_IRQ_MASK BIT(31)
#define AUD_STS_CH_STS_MASK BIT(29)
@ -368,12 +369,32 @@ static int xlnx_formatter_pcm_open(struct snd_soc_component *component,
snd_soc_set_runtime_hwparams(substream, &xlnx_pcm_hardware);
runtime->private_data = stream_data;
/* Resize the period size divisible by 64 */
/* Resize the period bytes as divisible by 64 */
err = snd_pcm_hw_constraint_step(runtime, 0,
SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64);
SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
XLNX_AUD_ALIGN_BYTES);
if (err) {
dev_err(component->dev,
"unable to set constraint on period bytes\n");
"Unable to set constraint on period bytes\n");
return err;
}
/* Resize the buffer bytes as divisible by 64 */
err = snd_pcm_hw_constraint_step(runtime, 0,
SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
XLNX_AUD_ALIGN_BYTES);
if (err) {
dev_err(component->dev,
"Unable to set constraint on buffer bytes\n");
return err;
}
/* Set periods as integer multiple */
err = snd_pcm_hw_constraint_integer(runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
if (err < 0) {
dev_err(component->dev,
"Unable to set constraint on periods to be integer\n");
return err;
}