diff options
Diffstat (limited to 'sound/pci/hda')
-rw-r--r-- | sound/pci/hda/cs35l56_hda.c | 8 | ||||
-rw-r--r-- | sound/pci/hda/hda_component.c | 16 | ||||
-rw-r--r-- | sound/pci/hda/hda_component.h | 7 | ||||
-rw-r--r-- | sound/pci/hda/hda_cs_dsp_ctl.c | 47 | ||||
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 5 |
5 files changed, 55 insertions, 28 deletions
diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c index 558c1f38fe97..11b0570ff56d 100644 --- a/sound/pci/hda/cs35l56_hda.c +++ b/sound/pci/hda/cs35l56_hda.c @@ -732,8 +732,6 @@ static void cs35l56_hda_unbind(struct device *dev, struct device *master, void * if (cs35l56->base.fw_patched) cs_dsp_power_down(&cs35l56->cs_dsp); - cs_dsp_remove(&cs35l56->cs_dsp); - if (comps[cs35l56->index].dev == dev) memset(&comps[cs35l56->index], 0, sizeof(*comps)); @@ -1035,7 +1033,7 @@ int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id) ARRAY_SIZE(cs35l56_hda_dai_config)); ret = cs35l56_force_sync_asp1_registers_from_cache(&cs35l56->base); if (ret) - goto err; + goto dsp_err; /* * By default only enable one ASP1TXn, where n=amplifier index, @@ -1061,6 +1059,8 @@ int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id) pm_err: pm_runtime_disable(cs35l56->base.dev); +dsp_err: + cs_dsp_remove(&cs35l56->cs_dsp); err: gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0); @@ -1078,6 +1078,8 @@ void cs35l56_hda_remove(struct device *dev) component_del(cs35l56->base.dev, &cs35l56_hda_comp_ops); + cs_dsp_remove(&cs35l56->cs_dsp); + kfree(cs35l56->system_name); pm_runtime_put_noidle(cs35l56->base.dev); diff --git a/sound/pci/hda/hda_component.c b/sound/pci/hda/hda_component.c index cd299d7d84ba..d02589014a3f 100644 --- a/sound/pci/hda/hda_component.c +++ b/sound/pci/hda/hda_component.c @@ -123,6 +123,21 @@ static int hda_comp_match_dev_name(struct device *dev, void *data) return !strcmp(d + n, tmp); } +int hda_component_manager_bind(struct hda_codec *cdc, + struct hda_component *comps, int count) +{ + int i; + + /* Init shared data */ + for (i = 0; i < count; ++i) { + memset(&comps[i], 0, sizeof(comps[i])); + comps[i].codec = cdc; + } + + return component_bind_all(hda_codec_dev(cdc), comps); +} +EXPORT_SYMBOL_NS_GPL(hda_component_manager_bind, SND_HDA_SCODEC_COMPONENT); + int hda_component_manager_init(struct hda_codec *cdc, struct hda_component *comps, int count, const char *bus, const char *hid, @@ -143,7 +158,6 @@ int hda_component_manager_init(struct hda_codec *cdc, sm->hid = hid; sm->match_str = match_str; sm->index = i; - comps[i].codec = cdc; component_match_add(dev, &match, hda_comp_match_dev_name, sm); } diff --git a/sound/pci/hda/hda_component.h b/sound/pci/hda/hda_component.h index c80a66691b5d..c70b3de68ab2 100644 --- a/sound/pci/hda/hda_component.h +++ b/sound/pci/hda/hda_component.h @@ -75,11 +75,8 @@ int hda_component_manager_init(struct hda_codec *cdc, void hda_component_manager_free(struct hda_codec *cdc, const struct component_master_ops *ops); -static inline int hda_component_manager_bind(struct hda_codec *cdc, - struct hda_component *comps) -{ - return component_bind_all(hda_codec_dev(cdc), comps); -} +int hda_component_manager_bind(struct hda_codec *cdc, + struct hda_component *comps, int count); static inline void hda_component_manager_unbind(struct hda_codec *cdc, struct hda_component *comps) diff --git a/sound/pci/hda/hda_cs_dsp_ctl.c b/sound/pci/hda/hda_cs_dsp_ctl.c index 463ca06036bf..9db45d7c17e5 100644 --- a/sound/pci/hda/hda_cs_dsp_ctl.c +++ b/sound/pci/hda/hda_cs_dsp_ctl.c @@ -8,6 +8,7 @@ #include <linux/module.h> #include <sound/soc.h> +#include <linux/cleanup.h> #include <linux/firmware/cirrus/cs_dsp.h> #include <linux/firmware/cirrus/wmfw.h> #include "hda_cs_dsp_ctl.h" @@ -97,11 +98,23 @@ static unsigned int wmfw_convert_flags(unsigned int in) return out; } -static void hda_cs_dsp_add_kcontrol(struct hda_cs_dsp_coeff_ctl *ctl, const char *name) +static void hda_cs_dsp_free_kcontrol(struct snd_kcontrol *kctl) { + struct hda_cs_dsp_coeff_ctl *ctl = (struct hda_cs_dsp_coeff_ctl *)snd_kcontrol_chip(kctl); struct cs_dsp_coeff_ctl *cs_ctl = ctl->cs_ctl; + + /* NULL priv to prevent a double-free in hda_cs_dsp_control_remove() */ + cs_ctl->priv = NULL; + kfree(ctl); +} + +static void hda_cs_dsp_add_kcontrol(struct cs_dsp_coeff_ctl *cs_ctl, + const struct hda_cs_dsp_ctl_info *info, + const char *name) +{ struct snd_kcontrol_new kcontrol = {0}; struct snd_kcontrol *kctl; + struct hda_cs_dsp_coeff_ctl *ctl __free(kfree) = NULL; int ret = 0; if (cs_ctl->len > ADSP_MAX_STD_CTRL_SIZE) { @@ -110,6 +123,13 @@ static void hda_cs_dsp_add_kcontrol(struct hda_cs_dsp_coeff_ctl *ctl, const char return; } + ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); + if (!ctl) + return; + + ctl->cs_ctl = cs_ctl; + ctl->card = info->card; + kcontrol.name = name; kcontrol.info = hda_cs_dsp_coeff_info; kcontrol.iface = SNDRV_CTL_ELEM_IFACE_MIXER; @@ -117,20 +137,22 @@ static void hda_cs_dsp_add_kcontrol(struct hda_cs_dsp_coeff_ctl *ctl, const char kcontrol.get = hda_cs_dsp_coeff_get; kcontrol.put = hda_cs_dsp_coeff_put; - /* Save ctl inside private_data, ctl is owned by cs_dsp, - * and will be freed when cs_dsp removes the control */ kctl = snd_ctl_new1(&kcontrol, (void *)ctl); if (!kctl) return; - ret = snd_ctl_add(ctl->card, kctl); + kctl->private_free = hda_cs_dsp_free_kcontrol; + ctl->kctl = kctl; + + /* snd_ctl_add() calls our private_free on error, which will kfree(ctl) */ + cs_ctl->priv = no_free_ptr(ctl); + ret = snd_ctl_add(info->card, kctl); if (ret) { dev_err(cs_ctl->dsp->dev, "Failed to add KControl %s = %d\n", kcontrol.name, ret); return; } dev_dbg(cs_ctl->dsp->dev, "Added KControl: %s\n", kcontrol.name); - ctl->kctl = kctl; } static void hda_cs_dsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl, @@ -138,7 +160,6 @@ static void hda_cs_dsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl, { struct cs_dsp *cs_dsp = cs_ctl->dsp; char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; - struct hda_cs_dsp_coeff_ctl *ctl; const char *region_name; int ret; @@ -163,15 +184,7 @@ static void hda_cs_dsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl, " %.*s", cs_ctl->subname_len - skip, cs_ctl->subname + skip); } - ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); - if (!ctl) - return; - - ctl->cs_ctl = cs_ctl; - ctl->card = info->card; - cs_ctl->priv = ctl; - - hda_cs_dsp_add_kcontrol(ctl, name); + hda_cs_dsp_add_kcontrol(cs_ctl, info, name); } void hda_cs_dsp_add_controls(struct cs_dsp *dsp, const struct hda_cs_dsp_ctl_info *info) @@ -203,7 +216,9 @@ void hda_cs_dsp_control_remove(struct cs_dsp_coeff_ctl *cs_ctl) { struct hda_cs_dsp_coeff_ctl *ctl = cs_ctl->priv; - kfree(ctl); + /* ctl and kctl may already have been removed by ALSA private_free */ + if (ctl && ctl->kctl) + snd_ctl_remove(ctl->card, ctl->kctl); } EXPORT_SYMBOL_NS_GPL(hda_cs_dsp_control_remove, SND_HDA_CS_DSP_CONTROLS); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 3b8b4ab488a6..1a1ca7caaff0 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6793,7 +6793,7 @@ static int comp_bind(struct device *dev) struct alc_spec *spec = cdc->spec; int ret; - ret = hda_component_manager_bind(cdc, spec->comps); + ret = hda_component_manager_bind(cdc, spec->comps, ARRAY_SIZE(spec->comps)); if (ret) return ret; @@ -10103,7 +10103,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8a2c, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8a2d, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8a2e, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2), - SND_PCI_QUIRK(0x103c, 0x8a2e, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8a30, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8a31, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8a6e, "HP EDNA 360", ALC287_FIXUP_CS35L41_I2C_4), @@ -10295,7 +10294,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2), SND_PCI_QUIRK(0x1043, 0x3a20, "ASUS G614JZR", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x3a30, "ASUS G814JVR/JIR", ALC245_FIXUP_CS35L41_SPI_2), - SND_PCI_QUIRK(0x1043, 0x3a40, "ASUS G814JZR", ALC245_FIXUP_CS35L41_SPI_2), + SND_PCI_QUIRK(0x1043, 0x3a40, "ASUS G814JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS), SND_PCI_QUIRK(0x1043, 0x3a50, "ASUS G834JYR/JZR", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x3a60, "ASUS G634JYR/JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS), SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC), |