From 1ac1b4b79bf51edcf4f25a1980334bd467880e7d Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 20 Jan 2024 10:42:12 +0100 Subject: ALSA: synth: Save a few bytes of memory when registering a 'snd_emux' snd_emux_register() calls pass a string literal as the 'name' parameter. So kstrdup_const() can be used instead of kfree() to avoid a memory allocation in such cases. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/9e7b94c852a25ed4be5382e5e48a7dd77e8d4d1a.1705743706.git.christophe.jaillet@wanadoo.fr Signed-off-by: Takashi Iwai --- sound/synth/emux/emux.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/synth/emux/emux.c b/sound/synth/emux/emux.c index 0006c3ddb51d6..a82af93748526 100644 --- a/sound/synth/emux/emux.c +++ b/sound/synth/emux/emux.c @@ -85,7 +85,7 @@ int snd_emux_register(struct snd_emux *emu, struct snd_card *card, int index, ch return -EINVAL; emu->card = card; - emu->name = kstrdup(name, GFP_KERNEL); + emu->name = kstrdup_const(name, GFP_KERNEL); emu->voices = kcalloc(emu->max_voices, sizeof(struct snd_emux_voice), GFP_KERNEL); if (emu->name == NULL || emu->voices == NULL) @@ -140,7 +140,7 @@ int snd_emux_free(struct snd_emux *emu) snd_emux_delete_hwdep(emu); snd_sf_free(emu->sflist); kfree(emu->voices); - kfree(emu->name); + kfree_const(emu->name); kfree(emu); return 0; } -- cgit 1.2.3-korg From cf0d956635e7dabc5e85f100e37a1d64a48becb4 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 24 Jan 2024 11:26:06 +0000 Subject: ALSA: hda: realtek: Re-work CS35L41 fixups to re-use for other amps Slightly re-work the code around cs35l41_generic_fixup() and the component binding search so that it can be re-used for other amps that use the component binding mechanism. The match string is stored in struct scodec_dev_name instead of hardcoding it in the match function. The tas2781 does not use the amp index as part of the driver name match. But its match format string does not include a field for the index, so snprintf() would safely ignore the p->index argument. Because of this there is no need for a special match function for this case, the CS35L41 code can be re-used. Signed-off-by: Richard Fitzgerald Tested-by: Gergo Koteles Link: https://lore.kernel.org/r/20240124112607.77614-2-rf@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 83 ++++++++----------------------------------- 1 file changed, 15 insertions(+), 68 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 19f2eb26659d8..2e2906d2dd1c0 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6841,11 +6841,12 @@ static void comp_generic_playback_hook(struct hda_pcm_stream *hinfo, struct hda_ struct scodec_dev_name { const char *bus; const char *hid; + const char *match_str; int index; }; /* match the device name in a slightly relaxed manner */ -static int comp_match_cs35l41_dev_name(struct device *dev, void *data) +static int comp_match_dev_name(struct device *dev, void *data) { struct scodec_dev_name *p = data; const char *d = dev_name(dev); @@ -6859,32 +6860,12 @@ static int comp_match_cs35l41_dev_name(struct device *dev, void *data) if (isdigit(d[n])) n++; /* the rest must be exact matching */ - snprintf(tmp, sizeof(tmp), "-%s:00-cs35l41-hda.%d", p->hid, p->index); + snprintf(tmp, sizeof(tmp), p->match_str, p->hid, p->index); return !strcmp(d + n, tmp); } -static int comp_match_tas2781_dev_name(struct device *dev, - void *data) -{ - struct scodec_dev_name *p = data; - const char *d = dev_name(dev); - int n = strlen(p->bus); - char tmp[32]; - - /* check the bus name */ - if (strncmp(d, p->bus, n)) - return 0; - /* skip the bus number */ - if (isdigit(d[n])) - n++; - /* the rest must be exact matching */ - snprintf(tmp, sizeof(tmp), "-%s:00", p->hid); - - return !strcmp(d + n, tmp); -} - -static void cs35l41_generic_fixup(struct hda_codec *cdc, int action, const char *bus, - const char *hid, int count) +static void comp_generic_fixup(struct hda_codec *cdc, int action, const char *bus, + const char *hid, const char *match_str, int count) { struct device *dev = hda_codec_dev(cdc); struct alc_spec *spec = cdc->spec; @@ -6899,10 +6880,11 @@ static void cs35l41_generic_fixup(struct hda_codec *cdc, int action, const char return; rec->bus = bus; rec->hid = hid; + rec->match_str = match_str; rec->index = i; spec->comps[i].codec = cdc; component_match_add(dev, &spec->match, - comp_match_cs35l41_dev_name, rec); + comp_match_dev_name, rec); } ret = component_master_add_with_match(dev, &comp_master_ops, spec->match); if (ret) @@ -6916,83 +6898,48 @@ static void cs35l41_generic_fixup(struct hda_codec *cdc, int action, const char } } -static void tas2781_generic_fixup(struct hda_codec *cdc, int action, - const char *bus, const char *hid) -{ - struct device *dev = hda_codec_dev(cdc); - struct alc_spec *spec = cdc->spec; - struct scodec_dev_name *rec; - int ret; - - switch (action) { - case HDA_FIXUP_ACT_PRE_PROBE: - rec = devm_kmalloc(dev, sizeof(*rec), GFP_KERNEL); - if (!rec) - return; - rec->bus = bus; - rec->hid = hid; - rec->index = 0; - spec->comps[0].codec = cdc; - component_match_add(dev, &spec->match, - comp_match_tas2781_dev_name, rec); - ret = component_master_add_with_match(dev, &comp_master_ops, - spec->match); - if (ret) - codec_err(cdc, - "Fail to register component aggregator %d\n", - ret); - else - spec->gen.pcm_playback_hook = - comp_generic_playback_hook; - break; - case HDA_FIXUP_ACT_FREE: - component_master_del(dev, &comp_master_ops); - break; - } -} - static void cs35l41_fixup_i2c_two(struct hda_codec *cdc, const struct hda_fixup *fix, int action) { - cs35l41_generic_fixup(cdc, action, "i2c", "CSC3551", 2); + comp_generic_fixup(cdc, action, "i2c", "CSC3551", "-%s:00-cs35l41-hda.%d", 2); } static void cs35l41_fixup_i2c_four(struct hda_codec *cdc, const struct hda_fixup *fix, int action) { - cs35l41_generic_fixup(cdc, action, "i2c", "CSC3551", 4); + comp_generic_fixup(cdc, action, "i2c", "CSC3551", "-%s:00-cs35l41-hda.%d", 4); } static void cs35l41_fixup_spi_two(struct hda_codec *codec, const struct hda_fixup *fix, int action) { - cs35l41_generic_fixup(codec, action, "spi", "CSC3551", 2); + comp_generic_fixup(codec, action, "spi", "CSC3551", "-%s:00-cs35l41-hda.%d", 2); } static void cs35l41_fixup_spi_four(struct hda_codec *codec, const struct hda_fixup *fix, int action) { - cs35l41_generic_fixup(codec, action, "spi", "CSC3551", 4); + comp_generic_fixup(codec, action, "spi", "CSC3551", "-%s:00-cs35l41-hda.%d", 4); } static void alc287_fixup_legion_16achg6_speakers(struct hda_codec *cdc, const struct hda_fixup *fix, int action) { - cs35l41_generic_fixup(cdc, action, "i2c", "CLSA0100", 2); + comp_generic_fixup(cdc, action, "i2c", "CLSA0100", "-%s:00-cs35l41-hda.%d", 2); } static void alc287_fixup_legion_16ithg6_speakers(struct hda_codec *cdc, const struct hda_fixup *fix, int action) { - cs35l41_generic_fixup(cdc, action, "i2c", "CLSA0101", 2); + comp_generic_fixup(cdc, action, "i2c", "CLSA0101", "-%s:00-cs35l41-hda.%d", 2); } static void tas2781_fixup_i2c(struct hda_codec *cdc, const struct hda_fixup *fix, int action) { - tas2781_generic_fixup(cdc, action, "i2c", "TIAS2781"); + comp_generic_fixup(cdc, action, "i2c", "TIAS2781", "-%s:00", 1); } static void yoga7_14arb7_fixup_i2c(struct hda_codec *cdc, const struct hda_fixup *fix, int action) { - tas2781_generic_fixup(cdc, action, "i2c", "INT8866"); + comp_generic_fixup(cdc, action, "i2c", "INT8866", "-%s:00", 1); } /* for alc295_fixup_hp_top_speakers */ -- cgit 1.2.3-korg From fd895a74dc1dca31f4ce7786b36812fda6727477 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 24 Jan 2024 11:26:07 +0000 Subject: ALSA: hda: realtek: Move hda_component implementation to module Move the generic parts of the hda_component implementation into a new hda_component module. This will allow other HDA codecs to add support for the component binding API without duplicating all the code. Signed-off-by: Richard Fitzgerald Tested-by: Gergo Koteles Link: https://lore.kernel.org/r/20240124112607.77614-3-rf@opensource.cirrus.com Signed-off-by: Takashi Iwai --- MAINTAINERS | 1 + sound/pci/hda/Kconfig | 4 + sound/pci/hda/Makefile | 2 + sound/pci/hda/hda_component.c | 169 ++++++++++++++++++++++++++++++++++++++++++ sound/pci/hda/hda_component.h | 59 +++++++++++++++ sound/pci/hda/patch_realtek.c | 146 +++++------------------------------- 6 files changed, 252 insertions(+), 129 deletions(-) create mode 100644 sound/pci/hda/hda_component.c (limited to 'sound') diff --git a/MAINTAINERS b/MAINTAINERS index 8d1052fa6a692..bfc7062cf7b1a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5014,6 +5014,7 @@ F: include/linux/mfd/cs42l43* F: include/sound/cs* F: sound/pci/hda/cirrus* F: sound/pci/hda/cs* +F: sound/pci/hda/hda_component* F: sound/pci/hda/hda_cs_dsp_ctl.* F: sound/soc/codecs/cs* diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 21a90b3c4cc73..20d757e38f94e 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -116,6 +116,9 @@ config SND_HDA_CS_DSP_CONTROLS tristate select FW_CS_DSP +config SND_HDA_SCODEC_COMPONENT + tristate + config SND_HDA_SCODEC_CS35L41_I2C tristate "Build CS35L41 HD-audio side codec support for I2C Bus" depends on I2C @@ -201,6 +204,7 @@ config SND_HDA_CODEC_REALTEK tristate "Build Realtek HD-audio codec support" select SND_HDA_GENERIC select SND_HDA_GENERIC_LEDS + select SND_HDA_SCODEC_COMPONENT help Say Y or M here to include Realtek HD-audio codec support in snd-hda-intel driver, such as ALC880. diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 793e296c3f642..13e04e1f65de2 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -37,6 +37,7 @@ snd-hda-scodec-cs35l56-objs := cs35l56_hda.o snd-hda-scodec-cs35l56-i2c-objs := cs35l56_hda_i2c.o snd-hda-scodec-cs35l56-spi-objs := cs35l56_hda_spi.o snd-hda-cs-dsp-ctls-objs := hda_cs_dsp_ctl.o +snd-hda-scodec-component-objs := hda_component.o snd-hda-scodec-tas2781-i2c-objs := tas2781_hda_i2c.o # common driver @@ -67,6 +68,7 @@ obj-$(CONFIG_SND_HDA_SCODEC_CS35L56) += snd-hda-scodec-cs35l56.o obj-$(CONFIG_SND_HDA_SCODEC_CS35L56_I2C) += snd-hda-scodec-cs35l56-i2c.o obj-$(CONFIG_SND_HDA_SCODEC_CS35L56_SPI) += snd-hda-scodec-cs35l56-spi.o obj-$(CONFIG_SND_HDA_CS_DSP_CONTROLS) += snd-hda-cs-dsp-ctls.o +obj-$(CONFIG_SND_HDA_SCODEC_COMPONENT) += snd-hda-scodec-component.o obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_I2C) += snd-hda-scodec-tas2781-i2c.o # this must be the last entry after codec drivers; diff --git a/sound/pci/hda/hda_component.c b/sound/pci/hda/hda_component.c new file mode 100644 index 0000000000000..cd299d7d84baf --- /dev/null +++ b/sound/pci/hda/hda_component.c @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * HD audio Component Binding Interface + * + * Copyright (C) 2021, 2023 Cirrus Logic, Inc. and + * Cirrus Logic International Semiconductor Ltd. + */ + +#include +#include +#include +#include +#include +#include "hda_component.h" +#include "hda_local.h" + +#ifdef CONFIG_ACPI +void hda_component_acpi_device_notify(struct hda_component *comps, int num_comps, + acpi_handle handle, u32 event, void *data) +{ + int i; + + for (i = 0; i < num_comps; i++) { + if (comps[i].dev && comps[i].acpi_notify) + comps[i].acpi_notify(acpi_device_handle(comps[i].adev), event, + comps[i].dev); + } +} +EXPORT_SYMBOL_NS_GPL(hda_component_acpi_device_notify, SND_HDA_SCODEC_COMPONENT); + +int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc, + struct hda_component *comps, int num_comps, + acpi_notify_handler handler, void *data) +{ + bool support_notifications = false; + struct acpi_device *adev; + int ret; + int i; + + adev = comps[0].adev; + if (!acpi_device_handle(adev)) + return 0; + + for (i = 0; i < num_comps; i++) + support_notifications = support_notifications || + comps[i].acpi_notifications_supported; + + if (support_notifications) { + ret = acpi_install_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY, + handler, data); + if (ret < 0) { + codec_warn(cdc, "Failed to install notify handler: %d\n", ret); + return 0; + } + + codec_dbg(cdc, "Notify handler installed\n"); + } + + return 0; +} +EXPORT_SYMBOL_NS_GPL(hda_component_manager_bind_acpi_notifications, SND_HDA_SCODEC_COMPONENT); + +void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc, + struct hda_component *comps, + acpi_notify_handler handler) +{ + struct acpi_device *adev; + int ret; + + adev = comps[0].adev; + if (!acpi_device_handle(adev)) + return; + + ret = acpi_remove_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY, handler); + if (ret < 0) + codec_warn(cdc, "Failed to uninstall notify handler: %d\n", ret); +} +EXPORT_SYMBOL_NS_GPL(hda_component_manager_unbind_acpi_notifications, SND_HDA_SCODEC_COMPONENT); +#endif /* ifdef CONFIG_ACPI */ + +void hda_component_manager_playback_hook(struct hda_component *comps, int num_comps, int action) +{ + int i; + + for (i = 0; i < num_comps; i++) { + if (comps[i].dev && comps[i].pre_playback_hook) + comps[i].pre_playback_hook(comps[i].dev, action); + } + for (i = 0; i < num_comps; i++) { + if (comps[i].dev && comps[i].playback_hook) + comps[i].playback_hook(comps[i].dev, action); + } + for (i = 0; i < num_comps; i++) { + if (comps[i].dev && comps[i].post_playback_hook) + comps[i].post_playback_hook(comps[i].dev, action); + } +} +EXPORT_SYMBOL_NS_GPL(hda_component_manager_playback_hook, SND_HDA_SCODEC_COMPONENT); + +struct hda_scodec_match { + const char *bus; + const char *hid; + const char *match_str; + int index; +}; + +/* match the device name in a slightly relaxed manner */ +static int hda_comp_match_dev_name(struct device *dev, void *data) +{ + struct hda_scodec_match *p = data; + const char *d = dev_name(dev); + int n = strlen(p->bus); + char tmp[32]; + + /* check the bus name */ + if (strncmp(d, p->bus, n)) + return 0; + /* skip the bus number */ + if (isdigit(d[n])) + n++; + /* the rest must be exact matching */ + snprintf(tmp, sizeof(tmp), p->match_str, p->hid, p->index); + return !strcmp(d + n, tmp); +} + +int hda_component_manager_init(struct hda_codec *cdc, + struct hda_component *comps, int count, + const char *bus, const char *hid, + const char *match_str, + const struct component_master_ops *ops) +{ + struct device *dev = hda_codec_dev(cdc); + struct component_match *match = NULL; + struct hda_scodec_match *sm; + int ret, i; + + for (i = 0; i < count; i++) { + sm = devm_kmalloc(dev, sizeof(*sm), GFP_KERNEL); + if (!sm) + return -ENOMEM; + + sm->bus = bus; + 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); + } + + ret = component_master_add_with_match(dev, ops, match); + if (ret) + codec_err(cdc, "Fail to register component aggregator %d\n", ret); + + return ret; +} +EXPORT_SYMBOL_NS_GPL(hda_component_manager_init, SND_HDA_SCODEC_COMPONENT); + +void hda_component_manager_free(struct hda_codec *cdc, + const struct component_master_ops *ops) +{ + struct device *dev = hda_codec_dev(cdc); + + component_master_del(dev, ops); +} +EXPORT_SYMBOL_NS_GPL(hda_component_manager_free, SND_HDA_SCODEC_COMPONENT); + +MODULE_DESCRIPTION("HD Audio component binding library"); +MODULE_AUTHOR("Richard Fitzgerald "); +MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/hda_component.h b/sound/pci/hda/hda_component.h index bbd6f0ed16c13..deae9dea01b4e 100644 --- a/sound/pci/hda/hda_component.h +++ b/sound/pci/hda/hda_component.h @@ -23,3 +23,62 @@ struct hda_component { void (*playback_hook)(struct device *dev, int action); void (*post_playback_hook)(struct device *dev, int action); }; + +#ifdef CONFIG_ACPI +void hda_component_acpi_device_notify(struct hda_component *comps, int num_comps, + acpi_handle handle, u32 event, void *data); +int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc, + struct hda_component *comps, int num_comps, + acpi_notify_handler handler, void *data); +void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc, + struct hda_component *comps, + acpi_notify_handler handler); +#else +static inline void hda_component_acpi_device_notify(struct hda_component *comps, + int num_comps, + acpi_handle handle, + u32 event, + void *data) +{ +} + +static inline int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc, + struct hda_component *comps, + int num_comps, + acpi_notify_handler handler, + void *data) + +{ + return 0; +} + +static inline void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc, + struct hda_component *comps, + acpi_notify_handler handler) +{ +} +#endif /* ifdef CONFIG_ACPI */ + +void hda_component_manager_playback_hook(struct hda_component *comps, int num_comps, + int action); + +int hda_component_manager_init(struct hda_codec *cdc, + struct hda_component *comps, int count, + const char *bus, const char *hid, + const char *match_str, + const struct component_master_ops *ops); + +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); +} + +static inline void hda_component_manager_unbind(struct hda_codec *cdc, + struct hda_component *comps) +{ + component_unbind_all(hda_codec_dev(cdc), comps); +} diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 2e2906d2dd1c0..62382a1b0e05e 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -133,7 +133,6 @@ struct alc_spec { u8 alc_mute_keycode_map[1]; /* component binding */ - struct component_match *match; struct hda_component comps[HDA_MAX_COMPONENTS]; }; @@ -6717,91 +6716,30 @@ static void alc287_fixup_legion_15imhg05_speakers(struct hda_codec *codec, } } -#ifdef CONFIG_ACPI static void comp_acpi_device_notify(acpi_handle handle, u32 event, void *data) { struct hda_codec *cdc = data; struct alc_spec *spec = cdc->spec; - int i; codec_info(cdc, "ACPI Notification %d\n", event); - for (i = 0; i < HDA_MAX_COMPONENTS; i++) { - if (spec->comps[i].dev && spec->comps[i].acpi_notify) - spec->comps[i].acpi_notify(acpi_device_handle(spec->comps[i].adev), event, - spec->comps[i].dev); - } -} - -static int comp_bind_acpi(struct device *dev) -{ - struct hda_codec *cdc = dev_to_hda_codec(dev); - struct alc_spec *spec = cdc->spec; - bool support_notifications = false; - struct acpi_device *adev; - int ret; - int i; - - adev = spec->comps[0].adev; - if (!acpi_device_handle(adev)) - return 0; - - for (i = 0; i < HDA_MAX_COMPONENTS; i++) - support_notifications = support_notifications || - spec->comps[i].acpi_notifications_supported; - - if (support_notifications) { - ret = acpi_install_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY, - comp_acpi_device_notify, cdc); - if (ret < 0) { - codec_warn(cdc, "Failed to install notify handler: %d\n", ret); - return 0; - } - - codec_dbg(cdc, "Notify handler installed\n"); - } - - return 0; -} - -static void comp_unbind_acpi(struct device *dev) -{ - struct hda_codec *cdc = dev_to_hda_codec(dev); - struct alc_spec *spec = cdc->spec; - struct acpi_device *adev; - int ret; - - adev = spec->comps[0].adev; - if (!acpi_device_handle(adev)) - return; - - ret = acpi_remove_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY, - comp_acpi_device_notify); - if (ret < 0) - codec_warn(cdc, "Failed to uninstall notify handler: %d\n", ret); -} -#else -static int comp_bind_acpi(struct device *dev) -{ - return 0; + hda_component_acpi_device_notify(spec->comps, ARRAY_SIZE(spec->comps), + handle, event, data); } -static void comp_unbind_acpi(struct device *dev) -{ -} -#endif - static int comp_bind(struct device *dev) { struct hda_codec *cdc = dev_to_hda_codec(dev); struct alc_spec *spec = cdc->spec; int ret; - ret = component_bind_all(dev, spec->comps); + ret = hda_component_manager_bind(cdc, spec->comps); if (ret) return ret; - return comp_bind_acpi(dev); + return hda_component_manager_bind_acpi_notifications(cdc, + spec->comps, ARRAY_SIZE(spec->comps), + comp_acpi_device_notify, cdc); } static void comp_unbind(struct device *dev) @@ -6809,8 +6747,8 @@ static void comp_unbind(struct device *dev) struct hda_codec *cdc = dev_to_hda_codec(dev); struct alc_spec *spec = cdc->spec; - comp_unbind_acpi(dev); - component_unbind_all(dev, spec->comps); + hda_component_manager_unbind_acpi_notifications(cdc, spec->comps, comp_acpi_device_notify); + hda_component_manager_unbind(cdc, spec->comps); } static const struct component_master_ops comp_master_ops = { @@ -6822,78 +6760,27 @@ static void comp_generic_playback_hook(struct hda_pcm_stream *hinfo, struct hda_ struct snd_pcm_substream *sub, int action) { struct alc_spec *spec = cdc->spec; - int i; - - for (i = 0; i < HDA_MAX_COMPONENTS; i++) { - if (spec->comps[i].dev && spec->comps[i].pre_playback_hook) - spec->comps[i].pre_playback_hook(spec->comps[i].dev, action); - } - for (i = 0; i < HDA_MAX_COMPONENTS; i++) { - if (spec->comps[i].dev && spec->comps[i].playback_hook) - spec->comps[i].playback_hook(spec->comps[i].dev, action); - } - for (i = 0; i < HDA_MAX_COMPONENTS; i++) { - if (spec->comps[i].dev && spec->comps[i].post_playback_hook) - spec->comps[i].post_playback_hook(spec->comps[i].dev, action); - } -} - -struct scodec_dev_name { - const char *bus; - const char *hid; - const char *match_str; - int index; -}; - -/* match the device name in a slightly relaxed manner */ -static int comp_match_dev_name(struct device *dev, void *data) -{ - struct scodec_dev_name *p = data; - const char *d = dev_name(dev); - int n = strlen(p->bus); - char tmp[32]; - /* check the bus name */ - if (strncmp(d, p->bus, n)) - return 0; - /* skip the bus number */ - if (isdigit(d[n])) - n++; - /* the rest must be exact matching */ - snprintf(tmp, sizeof(tmp), p->match_str, p->hid, p->index); - return !strcmp(d + n, tmp); + hda_component_manager_playback_hook(spec->comps, ARRAY_SIZE(spec->comps), action); } static void comp_generic_fixup(struct hda_codec *cdc, int action, const char *bus, const char *hid, const char *match_str, int count) { - struct device *dev = hda_codec_dev(cdc); struct alc_spec *spec = cdc->spec; - struct scodec_dev_name *rec; - int ret, i; + int ret; switch (action) { case HDA_FIXUP_ACT_PRE_PROBE: - for (i = 0; i < count; i++) { - rec = devm_kmalloc(dev, sizeof(*rec), GFP_KERNEL); - if (!rec) - return; - rec->bus = bus; - rec->hid = hid; - rec->match_str = match_str; - rec->index = i; - spec->comps[i].codec = cdc; - component_match_add(dev, &spec->match, - comp_match_dev_name, rec); - } - ret = component_master_add_with_match(dev, &comp_master_ops, spec->match); + ret = hda_component_manager_init(cdc, spec->comps, count, bus, hid, + match_str, &comp_master_ops); if (ret) - codec_err(cdc, "Fail to register component aggregator %d\n", ret); - else - spec->gen.pcm_playback_hook = comp_generic_playback_hook; + return; + + spec->gen.pcm_playback_hook = comp_generic_playback_hook; break; case HDA_FIXUP_ACT_FREE: - component_master_del(dev, &comp_master_ops); + hda_component_manager_free(cdc, &comp_master_ops); break; } } @@ -12568,6 +12455,7 @@ MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_realtek); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Realtek HD-audio codec"); +MODULE_IMPORT_NS(SND_HDA_SCODEC_COMPONENT); static struct hda_codec_driver realtek_driver = { .id = snd_hda_id_realtek, -- cgit 1.2.3-korg From b2d6a1fd0e3e513f5ebfc152d6fedae093df8e21 Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Thu, 25 Jan 2024 12:33:01 +0000 Subject: ALSA: hda/realtek: Add quirks for HP G11 Laptops using CS35L56 Add quirks for two HP G11 laptops that use a Realtek HDA codec combined with four CS35L56 amplifiers using SPI. The CS35L56 driver uses the component binding interface, so uses the same setup code as the CS35L41 quirks. Signed-off-by: Simon Trimmer Signed-off-by: Richard Fitzgerald Link: https://lore.kernel.org/r/20240125123301.41692-1-rf@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 62382a1b0e05e..885d85937755c 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6817,6 +6817,11 @@ static void alc287_fixup_legion_16ithg6_speakers(struct hda_codec *cdc, const st comp_generic_fixup(cdc, action, "i2c", "CLSA0101", "-%s:00-cs35l41-hda.%d", 2); } +static void cs35l56_fixup_spi_four(struct hda_codec *cdc, const struct hda_fixup *fix, int action) +{ + comp_generic_fixup(cdc, action, "spi", "CSC3556", "-%s:00-cs35l56-hda.%d", 4); +} + static void tas2781_fixup_i2c(struct hda_codec *cdc, const struct hda_fixup *fix, int action) { @@ -7308,6 +7313,7 @@ enum { ALC2XX_FIXUP_HEADSET_MIC, ALC289_FIXUP_DELL_CS35L41_SPI_2, ALC294_FIXUP_CS35L41_I2C_2, + ALC245_FIXUP_CS35L56_SPI_4_HP_GPIO_LED, }; /* A special fixup for Lenovo C940 and Yoga Duet 7; @@ -9459,6 +9465,12 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = cs35l41_fixup_i2c_two, }, + [ALC245_FIXUP_CS35L56_SPI_4_HP_GPIO_LED] = { + .type = HDA_FIXUP_FUNC, + .v.func = cs35l56_fixup_spi_four, + .chained = true, + .chain_id = ALC285_FIXUP_HP_GPIO_LED, + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -9786,6 +9798,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8c47, "HP EliteBook 840 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8c48, "HP EliteBook 860 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8c49, "HP Elite x360 830 2-in-1 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8c52, "HP EliteBook 1040 G11", ALC245_FIXUP_CS35L56_SPI_4_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8c53, "HP Elite x360 1040 2-in-1 G11", ALC245_FIXUP_CS35L56_SPI_4_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8c70, "HP EliteBook 835 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8c71, "HP EliteBook 845 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8c72, "HP EliteBook 865 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED), -- cgit 1.2.3-korg From 135096ebfab656823d0037102a00776f3914fee3 Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 26 Jan 2024 16:40:02 +0000 Subject: ALSA: hda: cs35l41: Set Channel Index correctly when system is missing _DSD Current method to set Channel Index when the system is missing _DSD assumes that the channels alternate, which is not guaranteed. Instead use the same methodology as the main driver does when _DSD exists. Fixes: 8c4c216db8fb ("ALSA: hda: cs35l41: Add config table to support many laptops without _DSD") Signed-off-by: Stefan Binding Link: https://lore.kernel.org/r/20240126164005.367021-2-sbinding@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/cs35l41_hda_property.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/cs35l41_hda_property.c b/sound/pci/hda/cs35l41_hda_property.c index 35277ce890a46..87edf0d2fbb0c 100644 --- a/sound/pci/hda/cs35l41_hda_property.c +++ b/sound/pci/hda/cs35l41_hda_property.c @@ -203,6 +203,7 @@ static int generic_dsd_config(struct cs35l41_hda *cs35l41, struct device *physde struct spi_device *spi; bool dsd_found; int ret; + int i; for (cfg = cs35l41_config_table; cfg->ssid; cfg++) { if (!strcasecmp(cfg->ssid, cs35l41->acpi_subsystem_id)) @@ -288,16 +289,6 @@ static int generic_dsd_config(struct cs35l41_hda *cs35l41, struct device *physde cs35l41->index = id == 0x40 ? 0 : 1; } - if (cfg->num_amps == 3) - /* 3 amps means a center channel, so no duplicate channels */ - cs35l41->channel_index = 0; - else - /* - * if 4 amps, there are duplicate channels, so they need different indexes - * if 2 amps, no duplicate channels, channel_index would be 0 - */ - cs35l41->channel_index = cs35l41->index / 2; - cs35l41->reset_gpio = fwnode_gpiod_get_index(acpi_fwnode_handle(cs35l41->dacpi), "reset", cs35l41->index, GPIOD_OUT_LOW, "cs35l41-reset"); @@ -305,6 +296,11 @@ static int generic_dsd_config(struct cs35l41_hda *cs35l41, struct device *physde hw_cfg->spk_pos = cfg->channel[cs35l41->index]; + cs35l41->channel_index = 0; + for (i = 0; i < cs35l41->index; i++) + if (cfg->channel[i] == hw_cfg->spk_pos) + cs35l41->channel_index++; + if (cfg->boost_type == INTERNAL) { hw_cfg->bst_type = CS35L41_INT_BOOST; hw_cfg->bst_ind = cfg->boost_ind_nanohenry; -- cgit 1.2.3-korg From 33e5e648e6311135e4ada01bcfb6ff54be98926d Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 26 Jan 2024 16:40:03 +0000 Subject: ALSA: hda: cs35l41: Support additional HP Envy Models Add new model entries into configuration table. Signed-off-by: Stefan Binding Link: https://lore.kernel.org/r/20240126164005.367021-3-sbinding@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/cs35l41_hda_property.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/cs35l41_hda_property.c b/sound/pci/hda/cs35l41_hda_property.c index 87edf0d2fbb0c..6714740b85c82 100644 --- a/sound/pci/hda/cs35l41_hda_property.c +++ b/sound/pci/hda/cs35l41_hda_property.c @@ -51,19 +51,30 @@ static const struct cs35l41_config cs35l41_config_table[] = { { "103C8A2E", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, { "103C8A30", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, { "103C8A31", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, + { "103C8A6E", 4, EXTERNAL, { CS35L41_LEFT, CS35L41_LEFT, CS35L41_RIGHT, CS35L41_RIGHT }, 0, -1, -1, 0, 0, 0 }, { "103C8BB3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, { "103C8BB4", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, + { "103C8BDD", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, + { "103C8BDE", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, { "103C8BDF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, { "103C8BE0", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, { "103C8BE1", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, { "103C8BE2", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, - { "103C8BE9", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, - { "103C8BDD", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, - { "103C8BDE", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, { "103C8BE3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, { "103C8BE5", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, { "103C8BE6", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, + { "103C8BE7", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, + { "103C8BE8", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, + { "103C8BE9", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, { "103C8B3A", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, + { "103C8C15", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4000, 24 }, + { "103C8C16", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4000, 24 }, + { "103C8C17", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4000, 24 }, + { "103C8C4F", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, + { "103C8C50", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, + { "103C8C51", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, + { "103C8CDD", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 }, + { "103C8CDE", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 3900, 24 }, { "104312AF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 }, { "10431433", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 }, { "10431463", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 }, @@ -381,19 +392,30 @@ static const struct cs35l41_prop_model cs35l41_prop_model_table[] = { { "CSC3551", "103C8A2E", generic_dsd_config }, { "CSC3551", "103C8A30", generic_dsd_config }, { "CSC3551", "103C8A31", generic_dsd_config }, + { "CSC3551", "103C8A6E", generic_dsd_config }, { "CSC3551", "103C8BB3", generic_dsd_config }, { "CSC3551", "103C8BB4", generic_dsd_config }, + { "CSC3551", "103C8BDD", generic_dsd_config }, + { "CSC3551", "103C8BDE", generic_dsd_config }, { "CSC3551", "103C8BDF", generic_dsd_config }, { "CSC3551", "103C8BE0", generic_dsd_config }, { "CSC3551", "103C8BE1", generic_dsd_config }, { "CSC3551", "103C8BE2", generic_dsd_config }, - { "CSC3551", "103C8BE9", generic_dsd_config }, - { "CSC3551", "103C8BDD", generic_dsd_config }, - { "CSC3551", "103C8BDE", generic_dsd_config }, { "CSC3551", "103C8BE3", generic_dsd_config }, { "CSC3551", "103C8BE5", generic_dsd_config }, { "CSC3551", "103C8BE6", generic_dsd_config }, + { "CSC3551", "103C8BE7", generic_dsd_config }, + { "CSC3551", "103C8BE8", generic_dsd_config }, + { "CSC3551", "103C8BE9", generic_dsd_config }, { "CSC3551", "103C8B3A", generic_dsd_config }, + { "CSC3551", "103C8C15", generic_dsd_config }, + { "CSC3551", "103C8C16", generic_dsd_config }, + { "CSC3551", "103C8C17", generic_dsd_config }, + { "CSC3551", "103C8C4F", generic_dsd_config }, + { "CSC3551", "103C8C50", generic_dsd_config }, + { "CSC3551", "103C8C51", generic_dsd_config }, + { "CSC3551", "103C8CDD", generic_dsd_config }, + { "CSC3551", "103C8CDE", generic_dsd_config }, { "CSC3551", "104312AF", generic_dsd_config }, { "CSC3551", "10431433", generic_dsd_config }, { "CSC3551", "10431463", generic_dsd_config }, -- cgit 1.2.3-korg From 92bf7367857e2a36dc6ec3c0bcadfc8c0b74d1b3 Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 26 Jan 2024 16:40:04 +0000 Subject: ALSA: hda: cs35l41: Support HP models without _DSD using dual Speaker ID Laptops 103C8C66, 103C8C67, 103C8C68, 103C8C6A use a dual speaker id system where each speaker has its own speaker id. The generic configuration table doesn't support this, so it needs its own function. Signed-off-by: Stefan Binding Link: https://lore.kernel.org/r/20240126164005.367021-4-sbinding@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/cs35l41_hda_property.c | 40 ++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/cs35l41_hda_property.c b/sound/pci/hda/cs35l41_hda_property.c index 6714740b85c82..5f8c214699d6d 100644 --- a/sound/pci/hda/cs35l41_hda_property.c +++ b/sound/pci/hda/cs35l41_hda_property.c @@ -335,6 +335,42 @@ static int generic_dsd_config(struct cs35l41_hda *cs35l41, struct device *physde return 0; } +/* + * Systems 103C8C66, 103C8C67, 103C8C68, 103C8C6A use a dual speaker id system - each speaker has + * its own speaker id. + */ +static int hp_i2c_int_2amp_dual_spkid(struct cs35l41_hda *cs35l41, struct device *physdev, int id, + const char *hid) +{ + struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg; + + /* If _DSD exists for this laptop, we cannot support it through here */ + if (acpi_dev_has_props(cs35l41->dacpi)) + return -ENOENT; + + /* check I2C address to assign the index */ + cs35l41->index = id == 0x40 ? 0 : 1; + cs35l41->channel_index = 0; + cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 0, GPIOD_OUT_HIGH); + if (cs35l41->index == 0) + cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, 0, 0, 1); + else + cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, 0, 0, 2); + hw_cfg->spk_pos = cs35l41->index; + hw_cfg->gpio2.func = CS35L41_INTERRUPT; + hw_cfg->gpio2.valid = true; + hw_cfg->valid = true; + + hw_cfg->bst_type = CS35L41_INT_BOOST; + hw_cfg->bst_ind = 1000; + hw_cfg->bst_ipk = 4100; + hw_cfg->bst_cap = 24; + hw_cfg->gpio1.func = CS35L41_NOT_USED; + hw_cfg->gpio1.valid = true; + + return 0; +} + /* * Device CLSA010(0/1) doesn't have _DSD so a gpiod_get by the label reset won't work. * And devices created by serial-multi-instantiate don't have their device struct @@ -414,6 +450,10 @@ static const struct cs35l41_prop_model cs35l41_prop_model_table[] = { { "CSC3551", "103C8C4F", generic_dsd_config }, { "CSC3551", "103C8C50", generic_dsd_config }, { "CSC3551", "103C8C51", generic_dsd_config }, + { "CSC3551", "103C8C66", hp_i2c_int_2amp_dual_spkid }, + { "CSC3551", "103C8C67", hp_i2c_int_2amp_dual_spkid }, + { "CSC3551", "103C8C68", hp_i2c_int_2amp_dual_spkid }, + { "CSC3551", "103C8C6A", hp_i2c_int_2amp_dual_spkid }, { "CSC3551", "103C8CDD", generic_dsd_config }, { "CSC3551", "103C8CDE", generic_dsd_config }, { "CSC3551", "104312AF", generic_dsd_config }, -- cgit 1.2.3-korg From aa8e3ef4fe5332c2ce33507e874b20d9c0077c21 Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 26 Jan 2024 16:40:05 +0000 Subject: ALSA: hda/realtek: Add quirks for various HP ENVY models These models use 2 or 4 CS35L41 amps with HDA using I2C or SPI. Some models have _DSD support inside cs35l41_hda_property.c. Signed-off-by: Stefan Binding Link: https://lore.kernel.org/r/20240126164005.367021-5-sbinding@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 885d85937755c..f89f48bf38922 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -9756,9 +9756,21 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x89c6, "Zbook Fury 17 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x89ca, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), SND_PCI_QUIRK(0x103c, 0x89d3, "HP EliteBook 645 G9 (MB 89D2)", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x89e7, "HP Elite x2 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8a0f, "HP Pavilion 14-ec1xxx", ALC287_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8a20, "HP Laptop 15s-fq5xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), SND_PCI_QUIRK(0x103c, 0x8a25, "HP Victus 16-d1xxx (MB 8A25)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), + SND_PCI_QUIRK(0x103c, 0x8a28, "HP Envy 13", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8a29, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8a2a, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8a2b, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2), + 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), SND_PCI_QUIRK(0x103c, 0x8a78, "HP Dev One", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x103c, 0x8aa0, "HP ProBook 440 G9 (MB 8A9E)", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8aa3, "HP ProBook 450 G9 (MB 8AA1)", ALC236_FIXUP_HP_GPIO_LED), @@ -9767,7 +9779,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8abb, "HP ZBook Firefly 14 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8ad1, "HP EliteBook 840 14 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8ad2, "HP EliteBook 860 16 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8ad8, "HP 800 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8b2f, "HP 255 15.6 inch G10 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), + SND_PCI_QUIRK(0x103c, 0x8b3a, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8b42, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8b43, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8b44, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), @@ -9793,13 +9807,35 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8b92, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8b96, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), SND_PCI_QUIRK(0x103c, 0x8b97, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), + SND_PCI_QUIRK(0x103c, 0x8bdd, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8bde, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8bdf, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8be0, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8be1, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8be2, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8be3, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8be5, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8be6, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8be7, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8be8, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8be9, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8bf0, "HP", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8c15, "HP Spectre 14", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8c16, "HP Spectre 16", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8c17, "HP Spectre 16", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8c46, "HP EliteBook 830 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8c47, "HP EliteBook 840 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8c48, "HP EliteBook 860 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8c49, "HP Elite x360 830 2-in-1 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8c4f, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8c50, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8c51, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8c52, "HP EliteBook 1040 G11", ALC245_FIXUP_CS35L56_SPI_4_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8c53, "HP Elite x360 1040 2-in-1 G11", ALC245_FIXUP_CS35L56_SPI_4_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8c66, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8c67, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8c68, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8c6a, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8c70, "HP EliteBook 835 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8c71, "HP EliteBook 845 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8c72, "HP EliteBook 865 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED), @@ -9809,7 +9845,11 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8ca2, "HP ZBook Power", ALC236_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8ca4, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8ca7, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8cdd, "HP Spectre", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8cde, "HP Spectre", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8cf5, "HP ZBook Studio 16", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8d01, "HP EliteBook G12", ALC287_FIXUP_CS35L41_I2C_4), + SND_PCI_QUIRK(0x103c, 0x8d08, "HP EliteBook 1045 G12", ALC287_FIXUP_CS35L41_I2C_4), SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), -- cgit 1.2.3-korg From 6d5a2dda9beacfbec60e764356144438da12b597 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 29 Jan 2024 11:27:11 +0900 Subject: ALSA: firewire-motu: add support for MOTU 896 mk3 FireWire and Hybrid Mark of the Unicorn released 896 mk3 FireWire in 2008 as part of the third generation of its FireWire series. In 2011, 896 mk3 hybrid was released to support USB protocol. It supports sampling transfer frequency up to 192.0 kHz. The packet format differs depending on both of current sampling transfer frequency and the type of signal in optical interfaces. The model supports transmission of PCM frames as well as MIDI messages. The 896 mk3 FireWire consists of below ICs: * Texas Instruments TSB41AB2 * Xilinx Spartan-3A FPGA, XC3S500E * Texas Instruments TMS320C6722 * Microchip (Atmel) AT91SAM SAM7S256 It supports sampling transfer frequency up to 192.0 kHz. The packet format differs depending on both of current sampling transfer frequency and the type of signal in two pairs of optical interfaces. The model supports transmission of PCM frames, while has no port for MIDi messages. The model supports command mechanism to configure internal DSP. Hardware meter information is available in the first 2 chunks of each data block of tx packet. This commit adds support for it. The 896 mk3 FireWire is just tested, but the 896 mk3 Hybrid is not yet. $ config-rom-pretty-printer < motu-896mk3fw.img ROM header and bus information block ----------------------------------------------------------------- 1024 04100ce1 bus_info_length 4, crc_length 16, crc 3297 1028 31333934 bus_name "1394" 1032 20ff7000 irmc 0, cmc 0, isc 1, bmc 0, cyc_clk_acc 255, max_rec 7 (256) 1036 0001f200 company_id 0001f2 | 1040 00093add device_id 0000604893 | EUI-64 0547556791237341 root directory ----------------------------------------------------------------- 1044 0004ef04 directory_length 4, crc 61188 1048 030001f2 vendor 1052 0c0083c0 node capabilities: per IEEE 1394 1056 d1000002 --> unit directory at 1064 1060 8d000005 --> eui-64 leaf at 1080 unit directory at 1064 ----------------------------------------------------------------- 1064 0003998d directory_length 3, crc 39309 1068 120001f2 specifier id 1072 13000017 version 1076 17101800 model eui-64 leaf at 1080 ----------------------------------------------------------------- 1080 0002cc82 leaf_length 2, crc 52354 1084 0001f200 company_id 0001f2 | 1088 00093add device_id 0000604893 | EUI-64 0547556791237341 $ config-rom-pretty-printer < motu-896mk3hybrid.img ROM header and bus information block ----------------------------------------------------------------- 1024 04103cbe bus_info_length 4, crc_length 16, crc 15550 1028 31333934 bus_name "1394" 1032 20ff7000 irmc 0, cmc 0, isc 1, bmc 0, cyc_clk_acc 255, max_rec 7 (256) 1036 0001f200 company_id 0001f2 | 1040 000ae601 device_id 0000714241 | EUI-64 0547556791346689 root directory ----------------------------------------------------------------- 1044 0004ef04 directory_length 4, crc 61188 1048 030001f2 vendor 1052 0c0083c0 node capabilities: per IEEE 1394 1056 d1000002 --> unit directory at 1064 1060 8d000005 --> eui-64 leaf at 1080 unit directory at 1064 ----------------------------------------------------------------- 1064 000394ac directory_length 3, crc 38060 1068 120001f2 specifier id 1072 13000037 version 1076 17102800 model eui-64 leaf at 1080 ----------------------------------------------------------------- 1080 0002cf69 leaf_length 2, crc 53097 1084 0001f200 company_id 0001f2 | 1088 000ae601 device_id 0000714241 | EUI-64 0547556791346689 Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20240129022711.254383-1-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/Kconfig | 2 ++ sound/firewire/motu/motu-protocol-v3.c | 9 +++++++++ sound/firewire/motu/motu.c | 2 ++ sound/firewire/motu/motu.h | 1 + 4 files changed, 14 insertions(+) (limited to 'sound') diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig index 22b6c779682a3..5973c25c2add6 100644 --- a/sound/firewire/Kconfig +++ b/sound/firewire/Kconfig @@ -175,6 +175,8 @@ config SND_FIREWIRE_MOTU * 8pre * 828mk3 (FireWire only) * 828mk3 (Hybrid) + * 896mk3 (FireWire only) + * 896mk3 (Hybrid) * Ultralite mk3 (FireWire only) * Ultralite mk3 (Hybrid) * Traveler mk3 diff --git a/sound/firewire/motu/motu-protocol-v3.c b/sound/firewire/motu/motu-protocol-v3.c index 8a0426920a760..7254fdfe046ab 100644 --- a/sound/firewire/motu/motu-protocol-v3.c +++ b/sound/firewire/motu/motu-protocol-v3.c @@ -261,6 +261,7 @@ int snd_motu_protocol_v3_cache_packet_formats(struct snd_motu *motu) if (motu->spec == &snd_motu_spec_828mk3_fw || motu->spec == &snd_motu_spec_828mk3_hybrid || + motu->spec == &snd_motu_spec_896mk3 || motu->spec == &snd_motu_spec_traveler_mk3 || motu->spec == &snd_motu_spec_track16) return detect_packet_formats_with_opt_ifaces(motu, data); @@ -288,6 +289,14 @@ const struct snd_motu_spec snd_motu_spec_828mk3_hybrid = { .rx_fixed_pcm_chunks = {14, 14, 14}, // Additional 4 dummy chunks at higher rate. }; +const struct snd_motu_spec snd_motu_spec_896mk3 = { + .name = "896mk3", + .protocol_version = SND_MOTU_PROTOCOL_V3, + .flags = SND_MOTU_SPEC_COMMAND_DSP, + .tx_fixed_pcm_chunks = {18, 14, 10}, + .rx_fixed_pcm_chunks = {18, 14, 10}, +}; + const struct snd_motu_spec snd_motu_spec_traveler_mk3 = { .name = "TravelerMk3", .protocol_version = SND_MOTU_PROTOCOL_V3, diff --git a/sound/firewire/motu/motu.c b/sound/firewire/motu/motu.c index d73599eb7d5aa..d14ab5dd5bea4 100644 --- a/sound/firewire/motu/motu.c +++ b/sound/firewire/motu/motu.c @@ -168,10 +168,12 @@ static const struct ieee1394_device_id motu_id_table[] = { SND_MOTU_DEV_ENTRY(0x00000d, &snd_motu_spec_ultralite), SND_MOTU_DEV_ENTRY(0x00000f, &snd_motu_spec_8pre), SND_MOTU_DEV_ENTRY(0x000015, &snd_motu_spec_828mk3_fw), // FireWire only. + SND_MOTU_DEV_ENTRY(0x000017, &snd_motu_spec_896mk3), // FireWire only. SND_MOTU_DEV_ENTRY(0x000019, &snd_motu_spec_ultralite_mk3), // FireWire only. SND_MOTU_DEV_ENTRY(0x00001b, &snd_motu_spec_traveler_mk3), SND_MOTU_DEV_ENTRY(0x000030, &snd_motu_spec_ultralite_mk3), // Hybrid. SND_MOTU_DEV_ENTRY(0x000035, &snd_motu_spec_828mk3_hybrid), // Hybrid. + SND_MOTU_DEV_ENTRY(0x000037, &snd_motu_spec_896mk3), // Hybrid. SND_MOTU_DEV_ENTRY(0x000033, &snd_motu_spec_audio_express), SND_MOTU_DEV_ENTRY(0x000039, &snd_motu_spec_track16), SND_MOTU_DEV_ENTRY(0x000045, &snd_motu_spec_4pre), diff --git a/sound/firewire/motu/motu.h b/sound/firewire/motu/motu.h index 3b1dc98a7be02..c66be0a89ccf1 100644 --- a/sound/firewire/motu/motu.h +++ b/sound/firewire/motu/motu.h @@ -138,6 +138,7 @@ extern const struct snd_motu_spec snd_motu_spec_8pre; extern const struct snd_motu_spec snd_motu_spec_828mk3_fw; extern const struct snd_motu_spec snd_motu_spec_828mk3_hybrid; +extern const struct snd_motu_spec snd_motu_spec_896mk3; extern const struct snd_motu_spec snd_motu_spec_traveler_mk3; extern const struct snd_motu_spec snd_motu_spec_ultralite_mk3; extern const struct snd_motu_spec snd_motu_spec_audio_express; -- cgit 1.2.3-korg From d1eb913c8df4574df2861db03d2411023bd7930a Mon Sep 17 00:00:00 2001 From: Ivan Orlov Date: Thu, 25 Jan 2024 22:35:20 +0000 Subject: ALSA: pcm: Fix snd_pcm_format_name function Fix snd_pcm_format_name so it won't return NULL-pointer in case if it can't find the format in the 'snd_pcm_format_names' list. Return "Unknown" instead, as it is done if the number passed to the function is larger than a list size. Signed-off-by: Ivan Orlov Link: https://lore.kernel.org/r/20240125223522.1122765-2-ivan.orlov0322@gmail.com Signed-off-by: Takashi Iwai --- sound/core/pcm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/core/pcm.c b/sound/core/pcm.c index d0788126cbab1..d9b338088d104 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -225,9 +225,11 @@ static const char * const snd_pcm_format_names[] = { */ const char *snd_pcm_format_name(snd_pcm_format_t format) { - if ((__force unsigned int)format >= ARRAY_SIZE(snd_pcm_format_names)) + unsigned int format_num = (__force unsigned int)format; + + if (format_num >= ARRAY_SIZE(snd_pcm_format_names) || !snd_pcm_format_names[format_num]) return "Unknown"; - return snd_pcm_format_names[(__force unsigned int)format]; + return snd_pcm_format_names[format_num]; } EXPORT_SYMBOL_GPL(snd_pcm_format_name); -- cgit 1.2.3-korg From 3e39acf56ededdebd1033349a16b704839b94b28 Mon Sep 17 00:00:00 2001 From: Ivan Orlov Date: Thu, 25 Jan 2024 22:35:21 +0000 Subject: ALSA: core: Add sound core KUnit test At the moment, we have a decent amount of integration tests (selftests) covering different aspects of the sound subsystem. However, a lot of of sound-related in-kernel functions remains uncovered. This patch introduces the KUnit test for the core part of the sound subsystem. It includes 10 test cases: - Coverage of the format-related inline functions from 'pcm.h' header file: snd_pcm_format_physical_width, snd_pcm_format_width, snd_pcm_format_signed, test_format_endianness - Coverage of the available bytes counting functions from 'pcm.h' header: snd_pcm_capture_avail, snd_pcm_playback_avail - Coverage of functions from pcm_misc: snd_pcm_format_set_silence, snd_pcm_format_name - Coverage of card-related functions from init.c: snd_card_set_id, snd_component_add This patch depends on the previous patches in this patch series as they contain fix for the bug, which was found during the test development. Without them, the test doesn't pass. Signed-off-by: Ivan Orlov Link: https://lore.kernel.org/r/20240125223522.1122765-3-ivan.orlov0322@gmail.com Signed-off-by: Takashi Iwai --- MAINTAINERS | 6 + sound/core/Kconfig | 16 +++ sound/core/Makefile | 2 + sound/core/sound_kunit.c | 310 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 334 insertions(+) create mode 100644 sound/core/sound_kunit.c (limited to 'sound') diff --git a/MAINTAINERS b/MAINTAINERS index 8d1052fa6a692..dbc61d5657600 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20484,6 +20484,12 @@ F: include/uapi/sound/compress_* F: sound/core/compress_offload.c F: sound/soc/soc-compress.c +SOUND - CORE KUNIT TEST +M: Ivan Orlov +L: linux-sound@vger.kernel.org +S: Supported +F: sound/core/sound_kunit.c + SOUND - DMAENGINE HELPERS M: Lars-Peter Clausen S: Supported diff --git a/sound/core/Kconfig b/sound/core/Kconfig index e41818e59a158..664c6ee2b5a1d 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -39,6 +39,22 @@ config SND_UMP_LEGACY_RAWMIDI legacy MIDI 1.0 byte streams is created for each UMP Endpoint. The device contains 16 substreams corresponding to UMP groups. +config SND_CORE_TEST + tristate "Sound core KUnit test" + depends on KUNIT + default KUNIT_ALL_TESTS + help + This options enables the sound core functions KUnit test. + + KUnit tests run during boot and output the results to the debug + log in TAP format (https://testanything.org/). Only useful for + kernel devs running KUnit test harness and are not for inclusion + into a production build. + + For more information on KUnit and unit tests in general, refer + to the KUnit documentation in Documentation/dev-tools/kunit/. + + config SND_COMPRESS_OFFLOAD tristate diff --git a/sound/core/Makefile b/sound/core/Makefile index a6b444ee28326..1d34e6950317c 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile @@ -49,6 +49,8 @@ obj-$(CONFIG_SND_SEQ_DEVICE) += snd-seq-device.o obj-$(CONFIG_SND_RAWMIDI) += snd-rawmidi.o obj-$(CONFIG_SND_UMP) += snd-ump.o +obj-$(CONFIG_SND_CORE_TEST) += sound_kunit.o + obj-$(CONFIG_SND_OSSEMUL) += oss/ obj-$(CONFIG_SND_SEQUENCER) += seq/ diff --git a/sound/core/sound_kunit.c b/sound/core/sound_kunit.c new file mode 100644 index 0000000000000..5d5a7bf88de4f --- /dev/null +++ b/sound/core/sound_kunit.c @@ -0,0 +1,310 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Sound core KUnit test + * Author: Ivan Orlov + */ + +#include +#include +#include + +#define SILENCE_BUFFER_SIZE 2048 +#define SILENCE(...) { __VA_ARGS__ } +#define DEFINE_FORMAT(fmt, pbits, wd, endianness, signd, silence_arr) { \ + .format = SNDRV_PCM_FORMAT_##fmt, .physical_bits = pbits, \ + .width = wd, .le = endianness, .sd = signd, .silence = silence_arr, \ + .name = #fmt, \ +} + +#define WRONG_FORMAT (SNDRV_PCM_FORMAT_LAST + 1) + +#define VALID_NAME "ValidName" +#define NAME_W_SPEC_CHARS "In%v@1id name" +#define NAME_W_SPACE "Test name" +#define NAME_W_SPACE_REMOVED "Testname" + +#define TEST_FIRST_COMPONENT "Component1" +#define TEST_SECOND_COMPONENT "Component2" + +struct snd_format_test_data { + snd_pcm_format_t format; + int physical_bits; + int width; + int le; + int sd; + unsigned char silence[8]; + unsigned char *name; +}; + +struct avail_test_data { + snd_pcm_uframes_t buffer_size; + snd_pcm_uframes_t hw_ptr; + snd_pcm_uframes_t appl_ptr; + snd_pcm_uframes_t expected_avail; +}; + +static struct snd_format_test_data valid_fmt[] = { + DEFINE_FORMAT(S8, 8, 8, -1, 1, SILENCE()), + DEFINE_FORMAT(U8, 8, 8, -1, 0, SILENCE(0x80)), + DEFINE_FORMAT(S16_LE, 16, 16, 1, 1, SILENCE()), + DEFINE_FORMAT(S16_BE, 16, 16, 0, 1, SILENCE()), + DEFINE_FORMAT(U16_LE, 16, 16, 1, 0, SILENCE(0x00, 0x80)), + DEFINE_FORMAT(U16_BE, 16, 16, 0, 0, SILENCE(0x80, 0x00)), + DEFINE_FORMAT(S24_LE, 32, 24, 1, 1, SILENCE()), + DEFINE_FORMAT(S24_BE, 32, 24, 0, 1, SILENCE()), + DEFINE_FORMAT(U24_LE, 32, 24, 1, 0, SILENCE(0x00, 0x00, 0x80)), + DEFINE_FORMAT(U24_BE, 32, 24, 0, 0, SILENCE(0x00, 0x80, 0x00, 0x00)), + DEFINE_FORMAT(S32_LE, 32, 32, 1, 1, SILENCE()), + DEFINE_FORMAT(S32_BE, 32, 32, 0, 1, SILENCE()), + DEFINE_FORMAT(U32_LE, 32, 32, 1, 0, SILENCE(0x00, 0x00, 0x00, 0x80)), + DEFINE_FORMAT(U32_BE, 32, 32, 0, 0, SILENCE(0x80, 0x00, 0x00, 0x00)), + DEFINE_FORMAT(FLOAT_LE, 32, 32, 1, -1, SILENCE()), + DEFINE_FORMAT(FLOAT_BE, 32, 32, 0, -1, SILENCE()), + DEFINE_FORMAT(FLOAT64_LE, 64, 64, 1, -1, SILENCE()), + DEFINE_FORMAT(FLOAT64_BE, 64, 64, 0, -1, SILENCE()), + DEFINE_FORMAT(IEC958_SUBFRAME_LE, 32, 32, 1, -1, SILENCE()), + DEFINE_FORMAT(IEC958_SUBFRAME_BE, 32, 32, 0, -1, SILENCE()), + DEFINE_FORMAT(MU_LAW, 8, 8, -1, -1, SILENCE(0x7f)), + DEFINE_FORMAT(A_LAW, 8, 8, -1, -1, SILENCE(0x55)), + DEFINE_FORMAT(IMA_ADPCM, 4, 4, -1, -1, SILENCE()), + DEFINE_FORMAT(G723_24, 3, 3, -1, -1, SILENCE()), + DEFINE_FORMAT(G723_40, 5, 5, -1, -1, SILENCE()), + DEFINE_FORMAT(DSD_U8, 8, 8, 1, 0, SILENCE(0x69)), + DEFINE_FORMAT(DSD_U16_LE, 16, 16, 1, 0, SILENCE(0x69, 0x69)), + DEFINE_FORMAT(DSD_U32_LE, 32, 32, 1, 0, SILENCE(0x69, 0x69, 0x69, 0x69)), + DEFINE_FORMAT(DSD_U16_BE, 16, 16, 0, 0, SILENCE(0x69, 0x69)), + DEFINE_FORMAT(DSD_U32_BE, 32, 32, 0, 0, SILENCE(0x69, 0x69, 0x69, 0x69)), + DEFINE_FORMAT(S20_LE, 32, 20, 1, 1, SILENCE()), + DEFINE_FORMAT(S20_BE, 32, 20, 0, 1, SILENCE()), + DEFINE_FORMAT(U20_LE, 32, 20, 1, 0, SILENCE(0x00, 0x00, 0x08, 0x00)), + DEFINE_FORMAT(U20_BE, 32, 20, 0, 0, SILENCE(0x00, 0x08, 0x00, 0x00)), + DEFINE_FORMAT(S24_3LE, 24, 24, 1, 1, SILENCE()), + DEFINE_FORMAT(S24_3BE, 24, 24, 0, 1, SILENCE()), + DEFINE_FORMAT(U24_3LE, 24, 24, 1, 0, SILENCE(0x00, 0x00, 0x80)), + DEFINE_FORMAT(U24_3BE, 24, 24, 0, 0, SILENCE(0x80, 0x00, 0x00)), + DEFINE_FORMAT(S20_3LE, 24, 20, 1, 1, SILENCE()), + DEFINE_FORMAT(S20_3BE, 24, 20, 0, 1, SILENCE()), + DEFINE_FORMAT(U20_3LE, 24, 20, 1, 0, SILENCE(0x00, 0x00, 0x08)), + DEFINE_FORMAT(U20_3BE, 24, 20, 0, 0, SILENCE(0x08, 0x00, 0x00)), + DEFINE_FORMAT(S18_3LE, 24, 18, 1, 1, SILENCE()), + DEFINE_FORMAT(S18_3BE, 24, 18, 0, 1, SILENCE()), + DEFINE_FORMAT(U18_3LE, 24, 18, 1, 0, SILENCE(0x00, 0x00, 0x02)), + DEFINE_FORMAT(U18_3BE, 24, 18, 0, 0, SILENCE(0x02, 0x00, 0x00)), + DEFINE_FORMAT(G723_24_1B, 8, 3, -1, -1, SILENCE()), + DEFINE_FORMAT(G723_40_1B, 8, 5, -1, -1, SILENCE()), +}; + +static void test_phys_format_size(struct kunit *test) +{ + u32 i; + + for (i = 0; i < ARRAY_SIZE(valid_fmt); i++) { + KUNIT_EXPECT_EQ(test, snd_pcm_format_physical_width(valid_fmt[i].format), + valid_fmt[i].physical_bits); + } + + KUNIT_EXPECT_EQ(test, snd_pcm_format_physical_width(WRONG_FORMAT), -EINVAL); + KUNIT_EXPECT_EQ(test, snd_pcm_format_physical_width(-1), -EINVAL); +} + +static void test_format_width(struct kunit *test) +{ + u32 i; + + for (i = 0; i < ARRAY_SIZE(valid_fmt); i++) { + KUNIT_EXPECT_EQ(test, snd_pcm_format_width(valid_fmt[i].format), + valid_fmt[i].width); + } + + KUNIT_EXPECT_EQ(test, snd_pcm_format_width(WRONG_FORMAT), -EINVAL); + KUNIT_EXPECT_EQ(test, snd_pcm_format_width(-1), -EINVAL); +} + +static void test_format_signed(struct kunit *test) +{ + u32 i; + + for (i = 0; i < ARRAY_SIZE(valid_fmt); i++) { + KUNIT_EXPECT_EQ(test, snd_pcm_format_signed(valid_fmt[i].format), + valid_fmt[i].sd < 0 ? -EINVAL : valid_fmt[i].sd); + KUNIT_EXPECT_EQ(test, snd_pcm_format_unsigned(valid_fmt[i].format), + valid_fmt[i].sd < 0 ? -EINVAL : 1 - valid_fmt[i].sd); + } + + KUNIT_EXPECT_EQ(test, snd_pcm_format_width(WRONG_FORMAT), -EINVAL); + KUNIT_EXPECT_EQ(test, snd_pcm_format_width(-1), -EINVAL); +} + +static void test_format_endianness(struct kunit *test) +{ + u32 i; + + for (i = 0; i < ARRAY_SIZE(valid_fmt); i++) { + KUNIT_EXPECT_EQ(test, snd_pcm_format_little_endian(valid_fmt[i].format), + valid_fmt[i].le < 0 ? -EINVAL : valid_fmt[i].le); + KUNIT_EXPECT_EQ(test, snd_pcm_format_big_endian(valid_fmt[i].format), + valid_fmt[i].le < 0 ? -EINVAL : 1 - valid_fmt[i].le); + } + + KUNIT_EXPECT_EQ(test, snd_pcm_format_little_endian(WRONG_FORMAT), -EINVAL); + KUNIT_EXPECT_EQ(test, snd_pcm_format_little_endian(-1), -EINVAL); + KUNIT_EXPECT_EQ(test, snd_pcm_format_big_endian(WRONG_FORMAT), -EINVAL); + KUNIT_EXPECT_EQ(test, snd_pcm_format_big_endian(-1), -EINVAL); +} + +static void _test_fill_silence(struct kunit *test, struct snd_format_test_data *data, + u8 *buffer, size_t samples_count) +{ + size_t sample_bytes = data->physical_bits >> 3; + u32 i; + + KUNIT_ASSERT_EQ(test, snd_pcm_format_set_silence(data->format, buffer, samples_count), 0); + for (i = 0; i < samples_count * sample_bytes; i++) + KUNIT_EXPECT_EQ(test, buffer[i], data->silence[i % sample_bytes]); +} + +static void test_format_fill_silence(struct kunit *test) +{ + u32 buf_samples[] = { 10, 20, 32, 64, 129, 260 }; + u8 *buffer; + u32 i, j; + + buffer = kunit_kzalloc(test, SILENCE_BUFFER_SIZE, GFP_KERNEL); + + for (i = 0; i < ARRAY_SIZE(buf_samples); i++) { + for (j = 0; j < ARRAY_SIZE(valid_fmt); j++) + _test_fill_silence(test, &valid_fmt[j], buffer, buf_samples[i]); + } + + KUNIT_EXPECT_EQ(test, snd_pcm_format_set_silence(WRONG_FORMAT, buffer, 20), -EINVAL); + KUNIT_EXPECT_EQ(test, snd_pcm_format_set_silence(SNDRV_PCM_FORMAT_LAST, buffer, 0), 0); +} + +static snd_pcm_uframes_t calculate_boundary(snd_pcm_uframes_t buffer_size) +{ + snd_pcm_uframes_t boundary = buffer_size; + + while (boundary * 2 <= 0x7fffffffUL - buffer_size) + boundary *= 2; + return boundary; +} + +static struct avail_test_data p_avail_data[] = { + /* buf_size + hw_ptr < appl_ptr => avail = buf_size + hw_ptr - appl_ptr + boundary */ + { 128, 1000, 1129, 1073741824UL - 1 }, + /* + * buf_size + hw_ptr - appl_ptr >= boundary => + * => avail = buf_size + hw_ptr - appl_ptr - boundary + */ + { 128, 1073741824UL, 10, 118 }, + /* standard case: avail = buf_size + hw_ptr - appl_ptr */ + { 128, 1000, 1001, 127 }, +}; + +static void test_playback_avail(struct kunit *test) +{ + struct snd_pcm_runtime *r = kunit_kzalloc(test, sizeof(*r), GFP_KERNEL); + u32 i; + + r->status = kunit_kzalloc(test, sizeof(*r->status), GFP_KERNEL); + r->control = kunit_kzalloc(test, sizeof(*r->control), GFP_KERNEL); + + for (i = 0; i < ARRAY_SIZE(p_avail_data); i++) { + r->buffer_size = p_avail_data[i].buffer_size; + r->boundary = calculate_boundary(r->buffer_size); + r->status->hw_ptr = p_avail_data[i].hw_ptr; + r->control->appl_ptr = p_avail_data[i].appl_ptr; + KUNIT_EXPECT_EQ(test, snd_pcm_playback_avail(r), p_avail_data[i].expected_avail); + } +} + +static struct avail_test_data c_avail_data[] = { + /* hw_ptr - appl_ptr < 0 => avail = hw_ptr - appl_ptr + boundary */ + { 128, 1000, 1001, 1073741824UL - 1 }, + /* standard case: avail = hw_ptr - appl_ptr */ + { 128, 1001, 1000, 1 }, +}; + +static void test_capture_avail(struct kunit *test) +{ + struct snd_pcm_runtime *r = kunit_kzalloc(test, sizeof(*r), GFP_KERNEL); + u32 i; + + r->status = kunit_kzalloc(test, sizeof(*r->status), GFP_KERNEL); + r->control = kunit_kzalloc(test, sizeof(*r->control), GFP_KERNEL); + + for (i = 0; i < ARRAY_SIZE(c_avail_data); i++) { + r->buffer_size = c_avail_data[i].buffer_size; + r->boundary = calculate_boundary(r->buffer_size); + r->status->hw_ptr = c_avail_data[i].hw_ptr; + r->control->appl_ptr = c_avail_data[i].appl_ptr; + KUNIT_EXPECT_EQ(test, snd_pcm_capture_avail(r), c_avail_data[i].expected_avail); + } +} + +static void test_card_set_id(struct kunit *test) +{ + struct snd_card *card = kunit_kzalloc(test, sizeof(*card), GFP_KERNEL); + + snd_card_set_id(card, VALID_NAME); + KUNIT_EXPECT_STREQ(test, card->id, VALID_NAME); + + /* clear the first id character so we can set it again */ + card->id[0] = '\0'; + snd_card_set_id(card, NAME_W_SPEC_CHARS); + KUNIT_EXPECT_STRNEQ(test, card->id, NAME_W_SPEC_CHARS); + + card->id[0] = '\0'; + snd_card_set_id(card, NAME_W_SPACE); + kunit_info(test, "%s", card->id); + KUNIT_EXPECT_STREQ(test, card->id, NAME_W_SPACE_REMOVED); +} + +static void test_pcm_format_name(struct kunit *test) +{ + u32 i; + const char *name; + + for (i = 0; i < ARRAY_SIZE(valid_fmt); i++) { + name = snd_pcm_format_name(valid_fmt[i].format); + KUNIT_ASSERT_NOT_NULL_MSG(test, name, "Don't have name for %s", valid_fmt[i].name); + KUNIT_EXPECT_STREQ(test, name, valid_fmt[i].name); + } + + KUNIT_ASSERT_STREQ(test, snd_pcm_format_name(WRONG_FORMAT), "Unknown"); + KUNIT_ASSERT_STREQ(test, snd_pcm_format_name(-1), "Unknown"); +} + +static void test_card_add_component(struct kunit *test) +{ + struct snd_card *card = kunit_kzalloc(test, sizeof(*card), GFP_KERNEL); + + snd_component_add(card, TEST_FIRST_COMPONENT); + KUNIT_ASSERT_STREQ(test, card->components, TEST_FIRST_COMPONENT); + + snd_component_add(card, TEST_SECOND_COMPONENT); + KUNIT_ASSERT_STREQ(test, card->components, TEST_FIRST_COMPONENT " " TEST_SECOND_COMPONENT); +} + +static struct kunit_case sound_utils_cases[] = { + KUNIT_CASE(test_phys_format_size), + KUNIT_CASE(test_format_width), + KUNIT_CASE(test_format_endianness), + KUNIT_CASE(test_format_signed), + KUNIT_CASE(test_format_fill_silence), + KUNIT_CASE(test_playback_avail), + KUNIT_CASE(test_capture_avail), + KUNIT_CASE(test_card_set_id), + KUNIT_CASE(test_pcm_format_name), + KUNIT_CASE(test_card_add_component), + {}, +}; + +static struct kunit_suite sound_utils_suite = { + .name = "sound-core-test", + .test_cases = sound_utils_cases, +}; + +kunit_test_suite(sound_utils_suite); +MODULE_AUTHOR("Ivan Orlov"); +MODULE_LICENSE("GPL"); -- cgit 1.2.3-korg From 6da404e78d392c7b35ac902072cf79ffe336556d Mon Sep 17 00:00:00 2001 From: Ivan Orlov Date: Thu, 1 Feb 2024 22:11:22 +0000 Subject: ALSA: core: Fix dependencies for SND_CORE_TEST Select CONFIG_SND_PCM when enabling CONFIG_SND_CORE_TEST, as the test uses symbols from 'pcm_misc.c'. Fixes: 3e39acf56ede ("ALSA: core: Add sound core KUnit test") Signed-off-by: Ivan Orlov Link: https://lore.kernel.org/r/20240201221122.16627-1-ivan.orlov0322@gmail.com Signed-off-by: Takashi Iwai --- sound/core/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 664c6ee2b5a1d..8077f481d84fd 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -42,6 +42,7 @@ config SND_UMP_LEGACY_RAWMIDI config SND_CORE_TEST tristate "Sound core KUnit test" depends on KUNIT + select SND_PCM default KUNIT_ALL_TESTS help This options enables the sound core functions KUnit test. -- cgit 1.2.3-korg From 498e963ec7f0e26d505a84e17723a458b03fca72 Mon Sep 17 00:00:00 2001 From: Stefan Binding Date: Fri, 2 Feb 2024 17:08:42 +0000 Subject: ALSA: hda/realtek: Remove two HP Laptops using CS35L41 The SKUs, and associated SSIDs, are no longer going to include the CS35L41. They may come back, but will need a different quirk. Fixes: aa8e3ef4fe53 ("ALSA: hda/realtek: Add quirks for various HP ENVY models") Signed-off-by: Stefan Binding Link: https://lore.kernel.org/r/20240202170842.321818-1-sbinding@opensource.cirrus.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index dde21bebed173..0fdd0f7e28e02 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -9853,8 +9853,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8cdd, "HP Spectre", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8cde, "HP Spectre", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8cf5, "HP ZBook Studio 16", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED), - SND_PCI_QUIRK(0x103c, 0x8d01, "HP EliteBook G12", ALC287_FIXUP_CS35L41_I2C_4), - SND_PCI_QUIRK(0x103c, 0x8d08, "HP EliteBook 1045 G12", ALC287_FIXUP_CS35L41_I2C_4), SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), -- cgit 1.2.3-korg From 3d6a89a6dc58f2a96daf7fd4232970794ffbb188 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 8 Feb 2024 10:37:50 -0600 Subject: ALSA: HDA: intel-sdw-acpi: add kernel parameter to select alternate controller Existing DSDT or SSDT platforms hard-code clock and frame shape configurations. For validation, we'd like to use alternate configurations. It's not always possible to generate new tables due to missing symbols, and modifying existing objects usually leads to AE_OBJECT_EXIST errors. The mechanism suggested in this patch is to add a NEW ACPI controller device with a different _ADR value. e.g. Scope (_SB_.PC00.RP08.PXSX.HDAS) { Device (SDWP) { Name (_ADR, 0x40000001) // _ADR: Address The desired _ADR can be passed as a parameter with options snd-intel-sdw-acpi sdw_ctrl_addr=0x40000001 This solution leads to minimal tables with just what the developers or validation engineers need, and without overriding any of the existing firmware definitions. It's consistent with the recommendation to extend ACPI definitions and not redefine them with a risk of conflict. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Bard Liao Link: https://lore.kernel.org/r/20240208163750.92849-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- sound/hda/intel-sdw-acpi.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sound') diff --git a/sound/hda/intel-sdw-acpi.c b/sound/hda/intel-sdw-acpi.c index b57d72ea4503f..5f60658c6051c 100644 --- a/sound/hda/intel-sdw-acpi.c +++ b/sound/hda/intel-sdw-acpi.c @@ -23,6 +23,10 @@ static int ctrl_link_mask; module_param_named(sdw_link_mask, ctrl_link_mask, int, 0444); MODULE_PARM_DESC(sdw_link_mask, "Intel link mask (one bit per link)"); +static ulong ctrl_addr = 0x40000000; +module_param_named(sdw_ctrl_addr, ctrl_addr, ulong, 0444); +MODULE_PARM_DESC(sdw_ctrl_addr, "Intel SoundWire Controller _ADR"); + static bool is_link_enabled(struct fwnode_handle *fw_node, u8 idx) { struct fwnode_handle *link; @@ -141,6 +145,9 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level, if (FIELD_GET(GENMASK(31, 28), adr) != SDW_LINK_TYPE) return AE_OK; /* keep going */ + if (adr != ctrl_addr) + return AE_OK; /* keep going */ + /* found the correct SoundWire controller */ info->handle = handle; -- cgit 1.2.3-korg From a097812310b5748358e32d87c6c1c18d249a397b Mon Sep 17 00:00:00 2001 From: "Sayed, Karimuddin" Date: Thu, 8 Feb 2024 10:39:04 -0600 Subject: ALSA: hda/realtek: Add "Intel Reference board" SSID in the ALC256. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add "Intel Reference board" SSID in the alc256. Enable "power saving mode" and Enable "headset jack mode". Reviewed-by: Péter Ujfalusi Signed-off-by: Sayed, Karimuddin Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20240208163904.92977-1-pierre-louis.bossart@linux.intel.com Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 0fdd0f7e28e02..a6ddcb0de9c60 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -9974,6 +9974,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x10ec, 0x1252, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK), SND_PCI_QUIRK(0x10ec, 0x1254, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK), SND_PCI_QUIRK(0x10ec, 0x12cc, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK), + SND_PCI_QUIRK(0x10ec, 0x12f6, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK), SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-SZ6", ALC269_FIXUP_HEADSET_MODE), SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x144d, 0xc169, "Samsung Notebook 9 Pen (NP930SBE-K01US)", ALC298_FIXUP_SAMSUNG_AMP), -- cgit 1.2.3-korg From d6568e3de42dd971a1356f7ba581e6600d53f0a0 Mon Sep 17 00:00:00 2001 From: Anton Yakovlev Date: Mon, 15 Jan 2024 14:36:54 +0100 Subject: ALSA: virtio: add support for audio controls Implementation of support for audio controls in accordance with the extension of the virtio sound device specification [1] planned for virtio-v1.3-cs01. The device can announce the VIRTIO_SND_F_CTLS feature. If the feature is negotiated, then an additional field appears in the configuration space: struct virtio_snd_config { ... /* number of available control elements */ __le32 controls; }; The driver can send the following requests to manage audio controls: enum { ... /* control element request types */ VIRTIO_SND_R_CTL_INFO = 0x0300, VIRTIO_SND_R_CTL_ENUM_ITEMS, VIRTIO_SND_R_CTL_READ, VIRTIO_SND_R_CTL_WRITE, VIRTIO_SND_R_CTL_TLV_READ, VIRTIO_SND_R_CTL_TLV_WRITE, VIRTIO_SND_R_CTL_TLV_COMMAND, ... }; And the device can send the following audio control event notification: enum { ... /* control element event types */ VIRTIO_SND_EVT_CTL_NOTIFY = 0x1200, ... }; See additional details in [1]. [1] https://lists.oasis-open.org/archives/virtio-comment/202104/msg00013.html Signed-off-by: Anton Yakovlev Signed-off-by: Aiswarya Cyriac Link: https://lore.kernel.org/r/20240115133654.576068-2-aiswarya.cyriac@opensynergy.com Signed-off-by: Takashi Iwai --- include/uapi/linux/virtio_snd.h | 154 +++++++++++++ sound/virtio/Makefile | 1 + sound/virtio/virtio_card.c | 21 ++ sound/virtio/virtio_card.h | 22 ++ sound/virtio/virtio_kctl.c | 466 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 664 insertions(+) create mode 100644 sound/virtio/virtio_kctl.c (limited to 'sound') diff --git a/include/uapi/linux/virtio_snd.h b/include/uapi/linux/virtio_snd.h index dfe49547a7b04..5f4100c2cf04c 100644 --- a/include/uapi/linux/virtio_snd.h +++ b/include/uapi/linux/virtio_snd.h @@ -7,6 +7,14 @@ #include +/******************************************************************************* + * FEATURE BITS + */ +enum { + /* device supports control elements */ + VIRTIO_SND_F_CTLS = 0 +}; + /******************************************************************************* * CONFIGURATION SPACE */ @@ -17,6 +25,8 @@ struct virtio_snd_config { __le32 streams; /* # of available channel maps */ __le32 chmaps; + /* # of available control elements */ + __le32 controls; }; enum { @@ -55,6 +65,15 @@ enum { /* channel map control request types */ VIRTIO_SND_R_CHMAP_INFO = 0x0200, + /* control element request types */ + VIRTIO_SND_R_CTL_INFO = 0x0300, + VIRTIO_SND_R_CTL_ENUM_ITEMS, + VIRTIO_SND_R_CTL_READ, + VIRTIO_SND_R_CTL_WRITE, + VIRTIO_SND_R_CTL_TLV_READ, + VIRTIO_SND_R_CTL_TLV_WRITE, + VIRTIO_SND_R_CTL_TLV_COMMAND, + /* jack event types */ VIRTIO_SND_EVT_JACK_CONNECTED = 0x1000, VIRTIO_SND_EVT_JACK_DISCONNECTED, @@ -63,6 +82,9 @@ enum { VIRTIO_SND_EVT_PCM_PERIOD_ELAPSED = 0x1100, VIRTIO_SND_EVT_PCM_XRUN, + /* control element event types */ + VIRTIO_SND_EVT_CTL_NOTIFY = 0x1200, + /* common status codes */ VIRTIO_SND_S_OK = 0x8000, VIRTIO_SND_S_BAD_MSG, @@ -331,4 +353,136 @@ struct virtio_snd_chmap_info { __u8 positions[VIRTIO_SND_CHMAP_MAX_SIZE]; }; +/******************************************************************************* + * CONTROL ELEMENTS MESSAGES + */ +struct virtio_snd_ctl_hdr { + /* VIRTIO_SND_R_CTL_XXX */ + struct virtio_snd_hdr hdr; + /* 0 ... virtio_snd_config::controls - 1 */ + __le32 control_id; +}; + +/* supported roles for control elements */ +enum { + VIRTIO_SND_CTL_ROLE_UNDEFINED = 0, + VIRTIO_SND_CTL_ROLE_VOLUME, + VIRTIO_SND_CTL_ROLE_MUTE, + VIRTIO_SND_CTL_ROLE_GAIN +}; + +/* supported value types for control elements */ +enum { + VIRTIO_SND_CTL_TYPE_BOOLEAN = 0, + VIRTIO_SND_CTL_TYPE_INTEGER, + VIRTIO_SND_CTL_TYPE_INTEGER64, + VIRTIO_SND_CTL_TYPE_ENUMERATED, + VIRTIO_SND_CTL_TYPE_BYTES, + VIRTIO_SND_CTL_TYPE_IEC958 +}; + +/* supported access rights for control elements */ +enum { + VIRTIO_SND_CTL_ACCESS_READ = 0, + VIRTIO_SND_CTL_ACCESS_WRITE, + VIRTIO_SND_CTL_ACCESS_VOLATILE, + VIRTIO_SND_CTL_ACCESS_INACTIVE, + VIRTIO_SND_CTL_ACCESS_TLV_READ, + VIRTIO_SND_CTL_ACCESS_TLV_WRITE, + VIRTIO_SND_CTL_ACCESS_TLV_COMMAND +}; + +struct virtio_snd_ctl_info { + /* common header */ + struct virtio_snd_info hdr; + /* element role (VIRTIO_SND_CTL_ROLE_XXX) */ + __le32 role; + /* element value type (VIRTIO_SND_CTL_TYPE_XXX) */ + __le32 type; + /* element access right bit map (1 << VIRTIO_SND_CTL_ACCESS_XXX) */ + __le32 access; + /* # of members in the element value */ + __le32 count; + /* index for an element with a non-unique name */ + __le32 index; + /* name identifier string for the element */ + __u8 name[44]; + /* additional information about the element's value */ + union { + /* VIRTIO_SND_CTL_TYPE_INTEGER */ + struct { + /* minimum supported value */ + __le32 min; + /* maximum supported value */ + __le32 max; + /* fixed step size for value (0 = variable size) */ + __le32 step; + } integer; + /* VIRTIO_SND_CTL_TYPE_INTEGER64 */ + struct { + /* minimum supported value */ + __le64 min; + /* maximum supported value */ + __le64 max; + /* fixed step size for value (0 = variable size) */ + __le64 step; + } integer64; + /* VIRTIO_SND_CTL_TYPE_ENUMERATED */ + struct { + /* # of options supported for value */ + __le32 items; + } enumerated; + } value; +}; + +struct virtio_snd_ctl_enum_item { + /* option name */ + __u8 item[64]; +}; + +struct virtio_snd_ctl_iec958 { + /* AES/IEC958 channel status bits */ + __u8 status[24]; + /* AES/IEC958 subcode bits */ + __u8 subcode[147]; + /* nothing */ + __u8 pad; + /* AES/IEC958 subframe bits */ + __u8 dig_subframe[4]; +}; + +struct virtio_snd_ctl_value { + union { + /* VIRTIO_SND_CTL_TYPE_BOOLEAN|INTEGER value */ + __le32 integer[128]; + /* VIRTIO_SND_CTL_TYPE_INTEGER64 value */ + __le64 integer64[64]; + /* VIRTIO_SND_CTL_TYPE_ENUMERATED value (option indexes) */ + __le32 enumerated[128]; + /* VIRTIO_SND_CTL_TYPE_BYTES value */ + __u8 bytes[512]; + /* VIRTIO_SND_CTL_TYPE_IEC958 value */ + struct virtio_snd_ctl_iec958 iec958; + } value; +}; + +/* supported event reason types */ +enum { + /* element's value has changed */ + VIRTIO_SND_CTL_EVT_MASK_VALUE = 0, + /* element's information has changed */ + VIRTIO_SND_CTL_EVT_MASK_INFO, + /* element's metadata has changed */ + VIRTIO_SND_CTL_EVT_MASK_TLV +}; + +struct virtio_snd_ctl_event { + /* VIRTIO_SND_EVT_CTL_NOTIFY */ + struct virtio_snd_hdr hdr; + /* 0 ... virtio_snd_config::controls - 1 */ + __le16 control_id; + /* event reason bit map (1 << VIRTIO_SND_CTL_EVT_MASK_XXX) */ + __le16 mask; +}; + #endif /* VIRTIO_SND_IF_H */ diff --git a/sound/virtio/Makefile b/sound/virtio/Makefile index 2742bddb88741..a839f8c8b5e64 100644 --- a/sound/virtio/Makefile +++ b/sound/virtio/Makefile @@ -7,6 +7,7 @@ virtio_snd-objs := \ virtio_chmap.o \ virtio_ctl_msg.o \ virtio_jack.o \ + virtio_kctl.o \ virtio_pcm.o \ virtio_pcm_msg.o \ virtio_pcm_ops.o diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c index b158c3cb8e5f5..2da20c6252477 100644 --- a/sound/virtio/virtio_card.c +++ b/sound/virtio/virtio_card.c @@ -64,6 +64,9 @@ static void virtsnd_event_dispatch(struct virtio_snd *snd, case VIRTIO_SND_EVT_PCM_XRUN: virtsnd_pcm_event(snd, event); break; + case VIRTIO_SND_EVT_CTL_NOTIFY: + virtsnd_kctl_event(snd, event); + break; } } @@ -233,6 +236,12 @@ static int virtsnd_build_devs(struct virtio_snd *snd) if (rc) return rc; + if (virtio_has_feature(vdev, VIRTIO_SND_F_CTLS)) { + rc = virtsnd_kctl_parse_cfg(snd); + if (rc) + return rc; + } + if (snd->njacks) { rc = virtsnd_jack_build_devs(snd); if (rc) @@ -251,6 +260,12 @@ static int virtsnd_build_devs(struct virtio_snd *snd) return rc; } + if (snd->nkctls) { + rc = virtsnd_kctl_build_devs(snd); + if (rc) + return rc; + } + return snd_card_register(snd->card); } @@ -417,10 +432,16 @@ static const struct virtio_device_id id_table[] = { { 0 }, }; +static unsigned int features[] = { + VIRTIO_SND_F_CTLS +}; + static struct virtio_driver virtsnd_driver = { .driver.name = KBUILD_MODNAME, .driver.owner = THIS_MODULE, .id_table = id_table, + .feature_table = features, + .feature_table_size = ARRAY_SIZE(features), .validate = virtsnd_validate, .probe = virtsnd_probe, .remove = virtsnd_remove, diff --git a/sound/virtio/virtio_card.h b/sound/virtio/virtio_card.h index 86ef3941895ed..3ceee4e416fc7 100644 --- a/sound/virtio/virtio_card.h +++ b/sound/virtio/virtio_card.h @@ -31,6 +31,16 @@ struct virtio_snd_queue { struct virtqueue *vqueue; }; +/** + * struct virtio_kctl - VirtIO control element. + * @kctl: ALSA control element. + * @items: Items for the ENUMERATED element type. + */ +struct virtio_kctl { + struct snd_kcontrol *kctl; + struct virtio_snd_ctl_enum_item *items; +}; + /** * struct virtio_snd - VirtIO sound card device. * @vdev: Underlying virtio device. @@ -45,6 +55,9 @@ struct virtio_snd_queue { * @nsubstreams: Number of PCM substreams. * @chmaps: VirtIO channel maps. * @nchmaps: Number of channel maps. + * @kctl_infos: VirtIO control element information. + * @kctls: VirtIO control elements. + * @nkctls: Number of control elements. */ struct virtio_snd { struct virtio_device *vdev; @@ -59,6 +72,9 @@ struct virtio_snd { u32 nsubstreams; struct virtio_snd_chmap_info *chmaps; u32 nchmaps; + struct virtio_snd_ctl_info *kctl_infos; + struct virtio_kctl *kctls; + u32 nkctls; }; /* Message completion timeout in milliseconds (module parameter). */ @@ -108,4 +124,10 @@ int virtsnd_chmap_parse_cfg(struct virtio_snd *snd); int virtsnd_chmap_build_devs(struct virtio_snd *snd); +int virtsnd_kctl_parse_cfg(struct virtio_snd *snd); + +int virtsnd_kctl_build_devs(struct virtio_snd *snd); + +void virtsnd_kctl_event(struct virtio_snd *snd, struct virtio_snd_event *event); + #endif /* VIRTIO_SND_CARD_H */ diff --git a/sound/virtio/virtio_kctl.c b/sound/virtio/virtio_kctl.c new file mode 100644 index 0000000000000..0c6ac74aca1ea --- /dev/null +++ b/sound/virtio/virtio_kctl.c @@ -0,0 +1,466 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * virtio-snd: Virtio sound device + * Copyright (C) 2022 OpenSynergy GmbH + */ +#include +#include + +#include "virtio_card.h" + +/* Map for converting VirtIO types to ALSA types. */ +static const snd_ctl_elem_type_t g_v2a_type_map[] = { + [VIRTIO_SND_CTL_TYPE_BOOLEAN] = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + [VIRTIO_SND_CTL_TYPE_INTEGER] = SNDRV_CTL_ELEM_TYPE_INTEGER, + [VIRTIO_SND_CTL_TYPE_INTEGER64] = SNDRV_CTL_ELEM_TYPE_INTEGER64, + [VIRTIO_SND_CTL_TYPE_ENUMERATED] = SNDRV_CTL_ELEM_TYPE_ENUMERATED, + [VIRTIO_SND_CTL_TYPE_BYTES] = SNDRV_CTL_ELEM_TYPE_BYTES, + [VIRTIO_SND_CTL_TYPE_IEC958] = SNDRV_CTL_ELEM_TYPE_IEC958 +}; + +/* Map for converting VirtIO access rights to ALSA access rights. */ +static const unsigned int g_v2a_access_map[] = { + [VIRTIO_SND_CTL_ACCESS_READ] = SNDRV_CTL_ELEM_ACCESS_READ, + [VIRTIO_SND_CTL_ACCESS_WRITE] = SNDRV_CTL_ELEM_ACCESS_WRITE, + [VIRTIO_SND_CTL_ACCESS_VOLATILE] = SNDRV_CTL_ELEM_ACCESS_VOLATILE, + [VIRTIO_SND_CTL_ACCESS_INACTIVE] = SNDRV_CTL_ELEM_ACCESS_INACTIVE, + [VIRTIO_SND_CTL_ACCESS_TLV_READ] = SNDRV_CTL_ELEM_ACCESS_TLV_READ, + [VIRTIO_SND_CTL_ACCESS_TLV_WRITE] = SNDRV_CTL_ELEM_ACCESS_TLV_WRITE, + [VIRTIO_SND_CTL_ACCESS_TLV_COMMAND] = SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND +}; + +/* Map for converting VirtIO event masks to ALSA event masks. */ +static const unsigned int g_v2a_mask_map[] = { + [VIRTIO_SND_CTL_EVT_MASK_VALUE] = SNDRV_CTL_EVENT_MASK_VALUE, + [VIRTIO_SND_CTL_EVT_MASK_INFO] = SNDRV_CTL_EVENT_MASK_INFO, + [VIRTIO_SND_CTL_EVT_MASK_TLV] = SNDRV_CTL_EVENT_MASK_TLV +}; + +/** + * virtsnd_kctl_info() - Returns information about the control. + * @kcontrol: ALSA control element. + * @uinfo: Element information. + * + * Context: Process context. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_kctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct virtio_snd *snd = kcontrol->private_data; + struct virtio_kctl *kctl = &snd->kctls[kcontrol->private_value]; + struct virtio_snd_ctl_info *kinfo = + &snd->kctl_infos[kcontrol->private_value]; + unsigned int i; + + uinfo->type = g_v2a_type_map[le32_to_cpu(kinfo->type)]; + uinfo->count = le32_to_cpu(kinfo->count); + + switch (uinfo->type) { + case SNDRV_CTL_ELEM_TYPE_INTEGER: + uinfo->value.integer.min = + le32_to_cpu(kinfo->value.integer.min); + uinfo->value.integer.max = + le32_to_cpu(kinfo->value.integer.max); + uinfo->value.integer.step = + le32_to_cpu(kinfo->value.integer.step); + + break; + case SNDRV_CTL_ELEM_TYPE_INTEGER64: + uinfo->value.integer64.min = + le64_to_cpu(kinfo->value.integer64.min); + uinfo->value.integer64.max = + le64_to_cpu(kinfo->value.integer64.max); + uinfo->value.integer64.step = + le64_to_cpu(kinfo->value.integer64.step); + + break; + case SNDRV_CTL_ELEM_TYPE_ENUMERATED: + uinfo->value.enumerated.items = + le32_to_cpu(kinfo->value.enumerated.items); + i = uinfo->value.enumerated.item; + if (i >= uinfo->value.enumerated.items) + return -EINVAL; + + strscpy(uinfo->value.enumerated.name, kctl->items[i].item, + sizeof(uinfo->value.enumerated.name)); + + break; + } + + return 0; +} + +/** + * virtsnd_kctl_get() - Read the value from the control. + * @kcontrol: ALSA control element. + * @uvalue: Element value. + * + * Context: Process context. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_kctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uvalue) +{ + struct virtio_snd *snd = kcontrol->private_data; + struct virtio_snd_ctl_info *kinfo = + &snd->kctl_infos[kcontrol->private_value]; + unsigned int type = le32_to_cpu(kinfo->type); + unsigned int count = le32_to_cpu(kinfo->count); + struct virtio_snd_msg *msg; + struct virtio_snd_ctl_hdr *hdr; + struct virtio_snd_ctl_value *kvalue; + size_t request_size = sizeof(*hdr); + size_t response_size = sizeof(struct virtio_snd_hdr) + sizeof(*kvalue); + unsigned int i; + int rc; + + msg = virtsnd_ctl_msg_alloc(request_size, response_size, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + virtsnd_ctl_msg_ref(msg); + + hdr = virtsnd_ctl_msg_request(msg); + hdr->hdr.code = cpu_to_le32(VIRTIO_SND_R_CTL_READ); + hdr->control_id = cpu_to_le32(kcontrol->private_value); + + rc = virtsnd_ctl_msg_send_sync(snd, msg); + if (rc) + goto on_failure; + + kvalue = (void *)((u8 *)virtsnd_ctl_msg_response(msg) + + sizeof(struct virtio_snd_hdr)); + + switch (type) { + case VIRTIO_SND_CTL_TYPE_BOOLEAN: + case VIRTIO_SND_CTL_TYPE_INTEGER: + for (i = 0; i < count; ++i) + uvalue->value.integer.value[i] = + le32_to_cpu(kvalue->value.integer[i]); + break; + case VIRTIO_SND_CTL_TYPE_INTEGER64: + for (i = 0; i < count; ++i) + uvalue->value.integer64.value[i] = + le64_to_cpu(kvalue->value.integer64[i]); + break; + case VIRTIO_SND_CTL_TYPE_ENUMERATED: + for (i = 0; i < count; ++i) + uvalue->value.enumerated.item[i] = + le32_to_cpu(kvalue->value.enumerated[i]); + break; + case VIRTIO_SND_CTL_TYPE_BYTES: + memcpy(uvalue->value.bytes.data, kvalue->value.bytes, count); + break; + case VIRTIO_SND_CTL_TYPE_IEC958: + memcpy(&uvalue->value.iec958, &kvalue->value.iec958, + sizeof(uvalue->value.iec958)); + break; + } + +on_failure: + virtsnd_ctl_msg_unref(msg); + + return rc; +} + +/** + * virtsnd_kctl_put() - Write the value to the control. + * @kcontrol: ALSA control element. + * @uvalue: Element value. + * + * Context: Process context. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_kctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uvalue) +{ + struct virtio_snd *snd = kcontrol->private_data; + struct virtio_snd_ctl_info *kinfo = + &snd->kctl_infos[kcontrol->private_value]; + unsigned int type = le32_to_cpu(kinfo->type); + unsigned int count = le32_to_cpu(kinfo->count); + struct virtio_snd_msg *msg; + struct virtio_snd_ctl_hdr *hdr; + struct virtio_snd_ctl_value *kvalue; + size_t request_size = sizeof(*hdr) + sizeof(*kvalue); + size_t response_size = sizeof(struct virtio_snd_hdr); + unsigned int i; + + msg = virtsnd_ctl_msg_alloc(request_size, response_size, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + hdr = virtsnd_ctl_msg_request(msg); + hdr->hdr.code = cpu_to_le32(VIRTIO_SND_R_CTL_WRITE); + hdr->control_id = cpu_to_le32(kcontrol->private_value); + + kvalue = (void *)((u8 *)hdr + sizeof(*hdr)); + + switch (type) { + case VIRTIO_SND_CTL_TYPE_BOOLEAN: + case VIRTIO_SND_CTL_TYPE_INTEGER: + for (i = 0; i < count; ++i) + kvalue->value.integer[i] = + cpu_to_le32(uvalue->value.integer.value[i]); + break; + case VIRTIO_SND_CTL_TYPE_INTEGER64: + for (i = 0; i < count; ++i) + kvalue->value.integer64[i] = + cpu_to_le64(uvalue->value.integer64.value[i]); + break; + case VIRTIO_SND_CTL_TYPE_ENUMERATED: + for (i = 0; i < count; ++i) + kvalue->value.enumerated[i] = + cpu_to_le32(uvalue->value.enumerated.item[i]); + break; + case VIRTIO_SND_CTL_TYPE_BYTES: + memcpy(kvalue->value.bytes, uvalue->value.bytes.data, count); + break; + case VIRTIO_SND_CTL_TYPE_IEC958: + memcpy(&kvalue->value.iec958, &uvalue->value.iec958, + sizeof(kvalue->value.iec958)); + break; + } + + return virtsnd_ctl_msg_send_sync(snd, msg); +} + +/** + * virtsnd_kctl_tlv_op() - Perform an operation on the control's metadata. + * @kcontrol: ALSA control element. + * @op_flag: Operation code (SNDRV_CTL_TLV_OP_XXX). + * @size: Size of the TLV data in bytes. + * @utlv: TLV data. + * + * Context: Process context. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_kctl_tlv_op(struct snd_kcontrol *kcontrol, int op_flag, + unsigned int size, unsigned int __user *utlv) +{ + struct virtio_snd *snd = kcontrol->private_data; + struct virtio_snd_msg *msg; + struct virtio_snd_ctl_hdr *hdr; + unsigned int *tlv; + struct scatterlist sg; + int rc; + + msg = virtsnd_ctl_msg_alloc(sizeof(*hdr), sizeof(struct virtio_snd_hdr), + GFP_KERNEL); + if (!msg) + return -ENOMEM; + + tlv = kzalloc(size, GFP_KERNEL); + if (!tlv) { + virtsnd_ctl_msg_unref(msg); + return -ENOMEM; + } + + sg_init_one(&sg, tlv, size); + + hdr = virtsnd_ctl_msg_request(msg); + hdr->control_id = cpu_to_le32(kcontrol->private_value); + + switch (op_flag) { + case SNDRV_CTL_TLV_OP_READ: + hdr->hdr.code = cpu_to_le32(VIRTIO_SND_R_CTL_TLV_READ); + + rc = virtsnd_ctl_msg_send(snd, msg, NULL, &sg, false); + if (!rc) { + if (copy_to_user(utlv, tlv, size)) + rc = -EFAULT; + } + + break; + case SNDRV_CTL_TLV_OP_WRITE: + case SNDRV_CTL_TLV_OP_CMD: + if (op_flag == SNDRV_CTL_TLV_OP_WRITE) + hdr->hdr.code = cpu_to_le32(VIRTIO_SND_R_CTL_TLV_WRITE); + else + hdr->hdr.code = + cpu_to_le32(VIRTIO_SND_R_CTL_TLV_COMMAND); + + if (copy_from_user(tlv, utlv, size)) + rc = -EFAULT; + else + rc = virtsnd_ctl_msg_send(snd, msg, &sg, NULL, false); + + break; + } + + kfree(tlv); + + return rc; +} + +/** + * virtsnd_kctl_get_enum_items() - Query items for the ENUMERATED element type. + * @snd: VirtIO sound device. + * @cid: Control element ID. + * + * This function is called during initial device initialization. + * + * Context: Any context that permits to sleep. + * Return: 0 on success, -errno on failure. + */ +static int virtsnd_kctl_get_enum_items(struct virtio_snd *snd, unsigned int cid) +{ + struct virtio_device *vdev = snd->vdev; + struct virtio_snd_ctl_info *kinfo = &snd->kctl_infos[cid]; + struct virtio_kctl *kctl = &snd->kctls[cid]; + struct virtio_snd_msg *msg; + struct virtio_snd_ctl_hdr *hdr; + unsigned int n = le32_to_cpu(kinfo->value.enumerated.items); + struct scatterlist sg; + + msg = virtsnd_ctl_msg_alloc(sizeof(*hdr), + sizeof(struct virtio_snd_hdr), GFP_KERNEL); + if (!msg) + return -ENOMEM; + + kctl->items = devm_kcalloc(&vdev->dev, n, sizeof(*kctl->items), + GFP_KERNEL); + if (!kctl->items) { + virtsnd_ctl_msg_unref(msg); + return -ENOMEM; + } + + sg_init_one(&sg, kctl->items, n * sizeof(*kctl->items)); + + hdr = virtsnd_ctl_msg_request(msg); + hdr->hdr.code = cpu_to_le32(VIRTIO_SND_R_CTL_ENUM_ITEMS); + hdr->control_id = cpu_to_le32(cid); + + return virtsnd_ctl_msg_send(snd, msg, NULL, &sg, false); +} + +/** + * virtsnd_kctl_parse_cfg() - Parse the control element configuration. + * @snd: VirtIO sound device. + * + * This function is called during initial device initialization. + * + * Context: Any context that permits to sleep. + * Return: 0 on success, -errno on failure. + */ +int virtsnd_kctl_parse_cfg(struct virtio_snd *snd) +{ + struct virtio_device *vdev = snd->vdev; + u32 i; + int rc; + + virtio_cread_le(vdev, struct virtio_snd_config, controls, + &snd->nkctls); + if (!snd->nkctls) + return 0; + + snd->kctl_infos = devm_kcalloc(&vdev->dev, snd->nkctls, + sizeof(*snd->kctl_infos), GFP_KERNEL); + if (!snd->kctl_infos) + return -ENOMEM; + + snd->kctls = devm_kcalloc(&vdev->dev, snd->nkctls, sizeof(*snd->kctls), + GFP_KERNEL); + if (!snd->kctls) + return -ENOMEM; + + rc = virtsnd_ctl_query_info(snd, VIRTIO_SND_R_CTL_INFO, 0, snd->nkctls, + sizeof(*snd->kctl_infos), snd->kctl_infos); + if (rc) + return rc; + + for (i = 0; i < snd->nkctls; ++i) { + struct virtio_snd_ctl_info *kinfo = &snd->kctl_infos[i]; + unsigned int type = le32_to_cpu(kinfo->type); + + if (type == VIRTIO_SND_CTL_TYPE_ENUMERATED) { + rc = virtsnd_kctl_get_enum_items(snd, i); + if (rc) + return rc; + } + } + + return 0; +} + +/** + * virtsnd_kctl_build_devs() - Build ALSA control elements. + * @snd: VirtIO sound device. + * + * Context: Any context that permits to sleep. + * Return: 0 on success, -errno on failure. + */ +int virtsnd_kctl_build_devs(struct virtio_snd *snd) +{ + unsigned int cid; + + for (cid = 0; cid < snd->nkctls; ++cid) { + struct virtio_snd_ctl_info *kinfo = &snd->kctl_infos[cid]; + struct virtio_kctl *kctl = &snd->kctls[cid]; + struct snd_kcontrol_new kctl_new; + unsigned int i; + int rc; + + memset(&kctl_new, 0, sizeof(kctl_new)); + + kctl_new.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + kctl_new.name = kinfo->name; + kctl_new.index = le32_to_cpu(kinfo->index); + + for (i = 0; i < ARRAY_SIZE(g_v2a_access_map); ++i) + if (le32_to_cpu(kinfo->access) & (1 << i)) + kctl_new.access |= g_v2a_access_map[i]; + + if (kctl_new.access & (SNDRV_CTL_ELEM_ACCESS_TLV_READ | + SNDRV_CTL_ELEM_ACCESS_TLV_WRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND)) { + kctl_new.access |= SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; + kctl_new.tlv.c = virtsnd_kctl_tlv_op; + } + + kctl_new.info = virtsnd_kctl_info; + kctl_new.get = virtsnd_kctl_get; + kctl_new.put = virtsnd_kctl_put; + kctl_new.private_value = cid; + + kctl->kctl = snd_ctl_new1(&kctl_new, snd); + if (!kctl->kctl) + return -ENOMEM; + + rc = snd_ctl_add(snd->card, kctl->kctl); + if (rc) + return rc; + } + + return 0; +} + +/** + * virtsnd_kctl_event() - Handle the control element event notification. + * @snd: VirtIO sound device. + * @event: VirtIO sound event. + * + * Context: Interrupt context. + */ +void virtsnd_kctl_event(struct virtio_snd *snd, struct virtio_snd_event *event) +{ + struct virtio_snd_ctl_event *kevent = + (struct virtio_snd_ctl_event *)event; + struct virtio_kctl *kctl; + unsigned int cid = le16_to_cpu(kevent->control_id); + unsigned int mask = 0; + unsigned int i; + + if (cid >= snd->nkctls) + return; + + for (i = 0; i < ARRAY_SIZE(g_v2a_mask_map); ++i) + if (le16_to_cpu(kevent->mask) & (1 << i)) + mask |= g_v2a_mask_map[i]; + + + kctl = &snd->kctls[cid]; + + snd_ctl_notify(snd->card, mask, &kctl->kctl->id); +} -- cgit 1.2.3-korg From dd96516a7d85ded7bfb49f717074be20ad78bad5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Feb 2024 16:51:12 +0100 Subject: ALSA: aloop: Replace with DEFINE_SIMPLE_DEV_PM_OPS() Use the new DEFINE_SIMPLE_DEV_PM_OPS() instead of SIMPLE_DEV_PM_OPS() for code-simplification. We need no longer CONFIG_PM_SLEEP ifdefs. Just a cleanup, no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240207155140.18238-2-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/drivers/aloop.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 1c65e0a3b13ce..892c4e29c0a34 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -1830,7 +1830,6 @@ static int loopback_probe(struct platform_device *devptr) return 0; } -#ifdef CONFIG_PM_SLEEP static int loopback_suspend(struct device *pdev) { struct snd_card *card = dev_get_drvdata(pdev); @@ -1847,11 +1846,7 @@ static int loopback_resume(struct device *pdev) return 0; } -static SIMPLE_DEV_PM_OPS(loopback_pm, loopback_suspend, loopback_resume); -#define LOOPBACK_PM_OPS &loopback_pm -#else -#define LOOPBACK_PM_OPS NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(loopback_pm, loopback_suspend, loopback_resume); #define SND_LOOPBACK_DRIVER "snd_aloop" @@ -1859,7 +1854,7 @@ static struct platform_driver loopback_driver = { .probe = loopback_probe, .driver = { .name = SND_LOOPBACK_DRIVER, - .pm = LOOPBACK_PM_OPS, + .pm = &loopback_pm, }, }; -- cgit 1.2.3-korg From d728eed42fbf6f199a2e12cbecac3b199181573c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Feb 2024 16:51:13 +0100 Subject: ALSA: dummy: Replace with DEFINE_SIPMLE_DEV_PM_OPS() Use the new DEFINE_SIMPLE_DEV_PM_OPS() instead of SIMPLE_DEV_PM_OPS() for code-simplification. We need no longer CONFIG_PM_SLEEP ifdefs. Just a cleanup, no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240207155140.18238-3-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/drivers/dummy.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 4317677ba24aa..52ff6ac3f7435 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -1098,7 +1098,6 @@ static int snd_dummy_probe(struct platform_device *devptr) return 0; } -#ifdef CONFIG_PM_SLEEP static int snd_dummy_suspend(struct device *pdev) { struct snd_card *card = dev_get_drvdata(pdev); @@ -1115,11 +1114,7 @@ static int snd_dummy_resume(struct device *pdev) return 0; } -static SIMPLE_DEV_PM_OPS(snd_dummy_pm, snd_dummy_suspend, snd_dummy_resume); -#define SND_DUMMY_PM_OPS &snd_dummy_pm -#else -#define SND_DUMMY_PM_OPS NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(snd_dummy_pm, snd_dummy_suspend, snd_dummy_resume); #define SND_DUMMY_DRIVER "snd_dummy" @@ -1127,7 +1122,7 @@ static struct platform_driver snd_dummy_driver = { .probe = snd_dummy_probe, .driver = { .name = SND_DUMMY_DRIVER, - .pm = SND_DUMMY_PM_OPS, + .pm = &snd_dummy_pm, }, }; -- cgit 1.2.3-korg From 19e332e50219412d417c0c79efdd4d3db9c633da Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Feb 2024 16:51:14 +0100 Subject: ALSA: pcsp: Replace with DEFINE_SIMPLE_DEV_PM_OPS() Use the new DEFINE_SIMPLE_DEV_PM_OPS() instead of SIMPLE_DEV_PM_OPS() for code-simplification. We need no longer CONFIG_PM_SLEEP ifdefs. Just a cleanup, no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240207155140.18238-4-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/drivers/pcsp/pcsp.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/drivers/pcsp/pcsp.c b/sound/drivers/pcsp/pcsp.c index c7be1c395bcb3..7195cb49e00f8 100644 --- a/sound/drivers/pcsp/pcsp.c +++ b/sound/drivers/pcsp/pcsp.c @@ -176,7 +176,6 @@ static void pcsp_stop_beep(struct snd_pcsp *chip) pcspkr_stop_sound(); } -#ifdef CONFIG_PM_SLEEP static int pcsp_suspend(struct device *dev) { struct snd_pcsp *chip = dev_get_drvdata(dev); @@ -184,11 +183,7 @@ static int pcsp_suspend(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(pcsp_pm, pcsp_suspend, NULL); -#define PCSP_PM_OPS &pcsp_pm -#else -#define PCSP_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ +static DEFINE_SIMPLE_DEV_PM_OPS(pcsp_pm, pcsp_suspend, NULL); static void pcsp_shutdown(struct platform_device *dev) { @@ -199,7 +194,7 @@ static void pcsp_shutdown(struct platform_device *dev) static struct platform_driver pcsp_platform_driver = { .driver = { .name = "pcspkr", - .pm = PCSP_PM_OPS, + .pm = &pcsp_pm, }, .probe = pcsp_probe, .shutdown = pcsp_shutdown, -- cgit 1.2.3-korg From 7aa8073066b74e20d9a5b92ab30b714fc5c4da26 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Feb 2024 16:51:15 +0100 Subject: ALSA: als300: Replace with DEFINE_SIMPLE_DEV_PM_OPS() Use the new DEFINE_SIMPLE_DEV_PM_OPS() instead of SIMPLE_DEV_PM_OPS() for code-simplification. We need no longer CONFIG_PM_SLEEP ifdefs. Just a cleanup, no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240207155140.18238-5-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/als300.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/pci/als300.c b/sound/pci/als300.c index c70aff0601205..c7c481203ef86 100644 --- a/sound/pci/als300.c +++ b/sound/pci/als300.c @@ -654,7 +654,6 @@ static int snd_als300_create(struct snd_card *card, return 0; } -#ifdef CONFIG_PM_SLEEP static int snd_als300_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); @@ -677,11 +676,7 @@ static int snd_als300_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(snd_als300_pm, snd_als300_suspend, snd_als300_resume); -#define SND_ALS300_PM_OPS &snd_als300_pm -#else -#define SND_ALS300_PM_OPS NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(snd_als300_pm, snd_als300_suspend, snd_als300_resume); static int snd_als300_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) @@ -739,7 +734,7 @@ static struct pci_driver als300_driver = { .id_table = snd_als300_ids, .probe = snd_als300_probe, .driver = { - .pm = SND_ALS300_PM_OPS, + .pm = &snd_als300_pm, }, }; -- cgit 1.2.3-korg From 8cd4a3b221c4033422f875fdfe5d43f84cad65a5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Feb 2024 16:51:16 +0100 Subject: ALSA: als4000: Replace with DEFINE_SIMPLE_DEV_PM_OPS() Use the new DEFINE_SIMPLE_DEV_PM_OPS() instead of SIMPLE_DEV_PM_OPS() for code-simplification. We need no longer CONFIG_PM_SLEEP ifdefs. For building properly, add the dummy functions for snd_sbmixer_suspend/resume() functions, too. Just a cleanup, no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240207155140.18238-6-tiwai@suse.de Signed-off-by: Takashi Iwai --- include/sound/sb.h | 3 +++ sound/pci/als4000.c | 9 ++------- 2 files changed, 5 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/include/sound/sb.h b/include/sound/sb.h index f540339fb0c77..24970f36c38ae 100644 --- a/include/sound/sb.h +++ b/include/sound/sb.h @@ -290,6 +290,9 @@ int snd_sbmixer_new(struct snd_sb *chip); #ifdef CONFIG_PM void snd_sbmixer_suspend(struct snd_sb *chip); void snd_sbmixer_resume(struct snd_sb *chip); +#else +static inline void snd_sbmixer_suspend(struct snd_sb *chip) {} +static inline void snd_sbmixer_resume(struct snd_sb *chip) {} #endif /* sb8_init.c */ diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index f33aeb692a112..022473594c73e 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c @@ -936,7 +936,6 @@ static int snd_card_als4000_probe(struct pci_dev *pci, return snd_card_free_on_error(&pci->dev, __snd_card_als4000_probe(pci, pci_id)); } -#ifdef CONFIG_PM_SLEEP static int snd_als4000_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); @@ -968,18 +967,14 @@ static int snd_als4000_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(snd_als4000_pm, snd_als4000_suspend, snd_als4000_resume); -#define SND_ALS4000_PM_OPS &snd_als4000_pm -#else -#define SND_ALS4000_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ +static DEFINE_SIMPLE_DEV_PM_OPS(snd_als4000_pm, snd_als4000_suspend, snd_als4000_resume); static struct pci_driver als4000_driver = { .name = KBUILD_MODNAME, .id_table = snd_als4000_ids, .probe = snd_card_als4000_probe, .driver = { - .pm = SND_ALS4000_PM_OPS, + .pm = &snd_als4000_pm, }, }; -- cgit 1.2.3-korg From b462d0b9e3a46e9309e836b2c371b67f722b1e66 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Feb 2024 16:51:17 +0100 Subject: ALSA: atiixp: Replace with DEFINE_SIMPLE_DEV_PM_OPS() Use the new DEFINE_SIMPLE_DEV_PM_OPS() instead of SIMPLE_DEV_PM_OPS() for code-simplification. We need no longer CONFIG_PM_SLEEP ifdefs. Just a cleanup, no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240207155140.18238-7-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/atiixp.c | 12 ++---------- sound/pci/atiixp_modem.c | 11 ++--------- 2 files changed, 4 insertions(+), 19 deletions(-) (limited to 'sound') diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 43d01f1847ed7..df2fef726d603 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -520,7 +520,6 @@ static int snd_atiixp_aclink_reset(struct atiixp *chip) return 0; } -#ifdef CONFIG_PM_SLEEP static int snd_atiixp_aclink_down(struct atiixp *chip) { // if (atiixp_read(chip, MODEM_MIRROR) & 0x1) /* modem running, too? */ @@ -530,7 +529,6 @@ static int snd_atiixp_aclink_down(struct atiixp *chip) ATI_REG_CMD_POWERDOWN); return 0; } -#endif /* * auto-detection of codecs @@ -1454,7 +1452,6 @@ static int snd_atiixp_mixer_new(struct atiixp *chip, int clock, } -#ifdef CONFIG_PM_SLEEP /* * power management */ @@ -1499,12 +1496,7 @@ static int snd_atiixp_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(snd_atiixp_pm, snd_atiixp_suspend, snd_atiixp_resume); -#define SND_ATIIXP_PM_OPS &snd_atiixp_pm -#else -#define SND_ATIIXP_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ - +static DEFINE_SIMPLE_DEV_PM_OPS(snd_atiixp_pm, snd_atiixp_suspend, snd_atiixp_resume); /* * proc interface for register dump @@ -1634,7 +1626,7 @@ static struct pci_driver atiixp_driver = { .id_table = snd_atiixp_ids, .probe = snd_atiixp_probe, .driver = { - .pm = SND_ATIIXP_PM_OPS, + .pm = &snd_atiixp_pm, }, }; diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index 8864c4c3c7e13..eb569539f3225 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -496,7 +496,6 @@ static int snd_atiixp_aclink_reset(struct atiixp_modem *chip) return 0; } -#ifdef CONFIG_PM_SLEEP static int snd_atiixp_aclink_down(struct atiixp_modem *chip) { // if (atiixp_read(chip, MODEM_MIRROR) & 0x1) /* modem running, too? */ @@ -506,7 +505,6 @@ static int snd_atiixp_aclink_down(struct atiixp_modem *chip) ATI_REG_CMD_POWERDOWN); return 0; } -#endif /* * auto-detection of codecs @@ -1094,7 +1092,6 @@ static int snd_atiixp_mixer_new(struct atiixp_modem *chip, int clock) } -#ifdef CONFIG_PM_SLEEP /* * power management */ @@ -1128,11 +1125,7 @@ static int snd_atiixp_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(snd_atiixp_pm, snd_atiixp_suspend, snd_atiixp_resume); -#define SND_ATIIXP_PM_OPS &snd_atiixp_pm -#else -#define SND_ATIIXP_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ +static DEFINE_SIMPLE_DEV_PM_OPS(snd_atiixp_pm, snd_atiixp_suspend, snd_atiixp_resume); /* * proc interface for register dump @@ -1258,7 +1251,7 @@ static struct pci_driver atiixp_modem_driver = { .id_table = snd_atiixp_ids, .probe = snd_atiixp_probe, .driver = { - .pm = SND_ATIIXP_PM_OPS, + .pm = &snd_atiixp_pm, }, }; -- cgit 1.2.3-korg From fd1786bf7104b2520e5c1d115b1845c474257e73 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Feb 2024 16:51:18 +0100 Subject: ALSA: ens137x: Replace with DEFINE_SIMPLE_DEV_PM_OPS() Use the new DEFINE_SIMPLE_DEV_PM_OPS() instead of SIMPLE_DEV_PM_OPS() for code-simplification. We need no longer CONFIG_PM_SLEEP ifdefs. For building properly, add the dummy functions for snd_ak4531_suspend/resume() functions, too. Just a cleanup, no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240207155140.18238-8-tiwai@suse.de Signed-off-by: Takashi Iwai --- include/sound/ak4531_codec.h | 3 +++ sound/pci/ens1370.c | 9 ++------- 2 files changed, 5 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/include/sound/ak4531_codec.h b/include/sound/ak4531_codec.h index 9a4429970d929..64402347d7a25 100644 --- a/include/sound/ak4531_codec.h +++ b/include/sound/ak4531_codec.h @@ -65,6 +65,9 @@ int snd_ak4531_mixer(struct snd_card *card, struct snd_ak4531 *_ak4531, #ifdef CONFIG_PM void snd_ak4531_suspend(struct snd_ak4531 *ak4531); void snd_ak4531_resume(struct snd_ak4531 *ak4531); +#else +static inline void snd_ak4531_suspend(struct snd_ak4531 *ak4531) {} +static inline void snd_ak4531_resume(struct snd_ak4531 *ak4531) {} #endif #endif /* __SOUND_AK4531_CODEC_H */ diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index 89210b2c73424..18928b905939c 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -1968,7 +1968,6 @@ static void snd_ensoniq_chip_init(struct ensoniq *ensoniq) outl(ensoniq->cssr, ES_REG(ensoniq, STATUS)); } -#ifdef CONFIG_PM_SLEEP static int snd_ensoniq_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); @@ -2007,11 +2006,7 @@ static int snd_ensoniq_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(snd_ensoniq_pm, snd_ensoniq_suspend, snd_ensoniq_resume); -#define SND_ENSONIQ_PM_OPS &snd_ensoniq_pm -#else -#define SND_ENSONIQ_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ +static DEFINE_SIMPLE_DEV_PM_OPS(snd_ensoniq_pm, snd_ensoniq_suspend, snd_ensoniq_resume); static int snd_ensoniq_create(struct snd_card *card, struct pci_dev *pci) @@ -2380,7 +2375,7 @@ static struct pci_driver ens137x_driver = { .id_table = snd_audiopci_ids, .probe = snd_audiopci_probe, .driver = { - .pm = SND_ENSONIQ_PM_OPS, + .pm = &snd_ensoniq_pm, }, }; -- cgit 1.2.3-korg From 13c1b30c5ea790b491863bf8e08d04975bade24f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Feb 2024 16:51:19 +0100 Subject: ALSA: intel8x0: Replace with DEFINE_SIMPLE_DEV_PM_OPS() Use the new DEFINE_SIMPLE_DEV_PM_OPS() instead of SIMPLE_DEV_PM_OPS() for code-simplification. We need no longer CONFIG_PM_SLEEP ifdefs. Just a cleanup, no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240207155140.18238-9-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/intel8x0.c | 9 ++------- sound/pci/intel8x0m.c | 9 ++------- 2 files changed, 4 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index ae285c0a629c8..dae3e15ba534d 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -2555,7 +2555,6 @@ static void snd_intel8x0_free(struct snd_card *card) free_irq(chip->irq, chip); } -#ifdef CONFIG_PM_SLEEP /* * power management */ @@ -2628,11 +2627,7 @@ static int intel8x0_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(intel8x0_pm, intel8x0_suspend, intel8x0_resume); -#define INTEL8X0_PM_OPS &intel8x0_pm -#else -#define INTEL8X0_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ +static DEFINE_SIMPLE_DEV_PM_OPS(intel8x0_pm, intel8x0_suspend, intel8x0_resume); #define INTEL8X0_TESTBUF_SIZE 32768 /* enough large for one shot */ @@ -3200,7 +3195,7 @@ static struct pci_driver intel8x0_driver = { .id_table = snd_intel8x0_ids, .probe = snd_intel8x0_probe, .driver = { - .pm = INTEL8X0_PM_OPS, + .pm = &intel8x0_pm, }, }; diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 653ecca782382..3d6f5b3cc73e1 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -965,7 +965,6 @@ static void snd_intel8x0m_free(struct snd_card *card) free_irq(chip->irq, chip); } -#ifdef CONFIG_PM_SLEEP /* * power management */ @@ -1006,11 +1005,7 @@ static int intel8x0m_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(intel8x0m_pm, intel8x0m_suspend, intel8x0m_resume); -#define INTEL8X0M_PM_OPS &intel8x0m_pm -#else -#define INTEL8X0M_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ +static DEFINE_SIMPLE_DEV_PM_OPS(intel8x0m_pm, intel8x0m_suspend, intel8x0m_resume); static void snd_intel8x0m_proc_read(struct snd_info_entry * entry, struct snd_info_buffer *buffer) @@ -1236,7 +1231,7 @@ static struct pci_driver intel8x0m_driver = { .id_table = snd_intel8x0m_ids, .probe = snd_intel8x0m_probe, .driver = { - .pm = INTEL8X0M_PM_OPS, + .pm = &intel8x0m_pm, }, }; -- cgit 1.2.3-korg From 36cd7671ee5f88a65ee752f08f0f5b7a02f5c29e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Feb 2024 16:51:20 +0100 Subject: ALSA: nm256: Replace with DEFINE_SIMPLE_DEV_PM_OPS() Use the new DEFINE_SIMPLE_DEV_PM_OPS() instead of SIMPLE_DEV_PM_OPS() for code-simplification. We need no longer CONFIG_PM_SLEEP ifdefs. Just a cleanup, no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240207155140.18238-10-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/nm256/nm256.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 34f90829e6569..11ba7d4eac2a4 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -1356,7 +1356,6 @@ snd_nm256_peek_for_sig(struct nm256 *chip) return 0; } -#ifdef CONFIG_PM_SLEEP /* * APM event handler, so the card is properly reinitialized after a power * event. @@ -1400,11 +1399,7 @@ static int nm256_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(nm256_pm, nm256_suspend, nm256_resume); -#define NM256_PM_OPS &nm256_pm -#else -#define NM256_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ +static DEFINE_SIMPLE_DEV_PM_OPS(nm256_pm, nm256_suspend, nm256_resume); static void snd_nm256_free(struct snd_card *card) { @@ -1660,7 +1655,7 @@ static struct pci_driver nm256_driver = { .id_table = snd_nm256_ids, .probe = snd_nm256_probe, .driver = { - .pm = NM256_PM_OPS, + .pm = &nm256_pm, }, }; -- cgit 1.2.3-korg From ae69d94f808aba1f6457b474c65d047418c0ce63 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Feb 2024 16:51:21 +0100 Subject: ALSA: aoa: Replace with DEFINE_SIMPLE_DEV_PM_OPS() Use the new DEFINE_SIMPLE_DEV_PM_OPS() instead of SIMPLE_DEV_PM_OPS() for code-simplification. We need no longer CONFIG_PM_SLEEP ifdefs. Just a cleanup, no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240207155140.18238-11-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/aoa/fabrics/layout.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/aoa/fabrics/layout.c b/sound/aoa/fabrics/layout.c index 0cd19a05db198..e68b4cb4df296 100644 --- a/sound/aoa/fabrics/layout.c +++ b/sound/aoa/fabrics/layout.c @@ -1126,7 +1126,6 @@ static void aoa_fabric_layout_remove(struct soundbus_dev *sdev) sdev->pcmname = NULL; } -#ifdef CONFIG_PM_SLEEP static int aoa_fabric_layout_suspend(struct device *dev) { struct layout_dev *ldev = dev_get_drvdata(dev); @@ -1147,11 +1146,9 @@ static int aoa_fabric_layout_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(aoa_fabric_layout_pm_ops, +static DEFINE_SIMPLE_DEV_PM_OPS(aoa_fabric_layout_pm_ops, aoa_fabric_layout_suspend, aoa_fabric_layout_resume); -#endif - static struct soundbus_driver aoa_soundbus_driver = { .name = "snd_aoa_soundbus_drv", .owner = THIS_MODULE, @@ -1159,9 +1156,7 @@ static struct soundbus_driver aoa_soundbus_driver = { .remove = aoa_fabric_layout_remove, .driver = { .owner = THIS_MODULE, -#ifdef CONFIG_PM_SLEEP .pm = &aoa_fabric_layout_pm_ops, -#endif } }; -- cgit 1.2.3-korg From bb7e551c403e774f84b382c8ceaffd66be4a88e8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Feb 2024 16:51:22 +0100 Subject: ALSA: aaci: Replace with DEFINE_SIMPLE_DEV_PM_OPS() Use the new DEFINE_SIMPLE_DEV_PM_OPS() instead of SIMPLE_DEV_PM_OPS() for code-simplification. We need no longer CONFIG_PM_SLEEP ifdefs. Just a cleanup, no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240207155140.18238-12-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/arm/aaci.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index 0817ad21af74f..f64896564728b 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -737,7 +737,6 @@ static const struct snd_pcm_ops aaci_capture_ops = { /* * Power Management. */ -#ifdef CONFIG_PM static int aaci_do_suspend(struct snd_card *card) { struct aaci *aaci = card->private_data; @@ -763,12 +762,7 @@ static int aaci_resume(struct device *dev) return card ? aaci_do_resume(card) : 0; } -static SIMPLE_DEV_PM_OPS(aaci_dev_pm_ops, aaci_suspend, aaci_resume); -#define AACI_DEV_PM_OPS (&aaci_dev_pm_ops) -#else -#define AACI_DEV_PM_OPS NULL -#endif - +static DEFINE_SIMPLE_DEV_PM_OPS(aaci_dev_pm_ops, aaci_suspend, aaci_resume); static const struct ac97_pcm ac97_defs[] = { [0] = { /* Front PCM */ @@ -1081,7 +1075,7 @@ MODULE_DEVICE_TABLE(amba, aaci_ids); static struct amba_driver aaci_driver = { .drv = { .name = DRIVER_NAME, - .pm = AACI_DEV_PM_OPS, + .pm = &aaci_dev_pm_ops, }, .probe = aaci_probe, .remove = aaci_remove, -- cgit 1.2.3-korg From 765daab29a0edc152e6c2513c61aefca2722c53f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Feb 2024 16:51:23 +0100 Subject: ALSA: pxa2xx-ac97: Replace with DEFINE_SIMPLE_DEV_PM_OPS() Use the new DEFINE_SIMPLE_DEV_PM_OPS() instead of SIMPLE_DEV_PM_OPS() for code-simplification. We need no longer CONFIG_PM_SLEEP ifdefs. Just a cleanup, no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240207155140.18238-13-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/arm/pxa2xx-ac97.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c index 2d83ad91f9680..4c367e73b2c9b 100644 --- a/sound/arm/pxa2xx-ac97.c +++ b/sound/arm/pxa2xx-ac97.c @@ -111,8 +111,6 @@ static int pxa2xx_ac97_pcm_prepare(struct snd_pcm_substream *substream) return snd_ac97_set_rate(pxa2xx_ac97_ac97, reg, runtime->rate); } -#ifdef CONFIG_PM_SLEEP - static int pxa2xx_ac97_do_suspend(struct snd_card *card) { pxa2xx_audio_ops_t *platform_ops = card->dev->platform_data; @@ -164,8 +162,7 @@ static int pxa2xx_ac97_resume(struct device *dev) return ret; } -static SIMPLE_DEV_PM_OPS(pxa2xx_ac97_pm_ops, pxa2xx_ac97_suspend, pxa2xx_ac97_resume); -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(pxa2xx_ac97_pm_ops, pxa2xx_ac97_suspend, pxa2xx_ac97_resume); static const struct snd_pcm_ops pxa2xx_ac97_pcm_ops = { .open = pxa2xx_ac97_pcm_open, @@ -277,9 +274,7 @@ static struct platform_driver pxa2xx_ac97_driver = { .remove_new = pxa2xx_ac97_remove, .driver = { .name = "pxa2xx-ac97", -#ifdef CONFIG_PM_SLEEP .pm = &pxa2xx_ac97_pm_ops, -#endif }, }; -- cgit 1.2.3-korg From 8e5ffd767bac48180235456255831083d0d00195 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Feb 2024 16:51:24 +0100 Subject: ASoC: pxa2xx-ac97: Replace with DEFINE_SIMPLE_DEV_PM_OPS() Use the new DEFINE_SIMPLE_DEV_PM_OPS() instead of SIMPLE_DEV_PM_OPS() for code-simplification. We need no longer CONFIG_PM_SLEEP ifdefs. Just a cleanup, no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240207155140.18238-14-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/soc/pxa/pxa2xx-ac97.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index e73bd62c033c5..80e0ea0ec9fb3 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c @@ -271,7 +271,6 @@ static void pxa2xx_ac97_dev_remove(struct platform_device *pdev) pxa2xx_ac97_hw_remove(pdev); } -#ifdef CONFIG_PM_SLEEP static int pxa2xx_ac97_dev_suspend(struct device *dev) { return pxa2xx_ac97_hw_suspend(); @@ -282,18 +281,15 @@ static int pxa2xx_ac97_dev_resume(struct device *dev) return pxa2xx_ac97_hw_resume(); } -static SIMPLE_DEV_PM_OPS(pxa2xx_ac97_pm_ops, +static DEFINE_SIMPLE_DEV_PM_OPS(pxa2xx_ac97_pm_ops, pxa2xx_ac97_dev_suspend, pxa2xx_ac97_dev_resume); -#endif static struct platform_driver pxa2xx_ac97_driver = { .probe = pxa2xx_ac97_dev_probe, .remove_new = pxa2xx_ac97_dev_remove, .driver = { .name = "pxa2xx-ac97", -#ifdef CONFIG_PM_SLEEP .pm = &pxa2xx_ac97_pm_ops, -#endif .of_match_table = of_match_ptr(pxa2xx_ac97_dt_ids), }, }; -- cgit 1.2.3-korg From 8ca0d10268b8b5951de13a21eb24744dc88d2e4b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Feb 2024 16:51:25 +0100 Subject: ALSA: at73c213: Replace with DEFINE_SIMPLE_DEV_PM_OPS() Use the new DEFINE_SIMPLE_DEV_PM_OPS() instead of SIMPLE_DEV_PM_OPS() for code-simplification. We need no longer CONFIG_PM_SLEEP ifdefs. Just a cleanup, no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240207155140.18238-15-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/spi/at73c213.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c index 1e8765d75d8f8..5648d744aa79f 100644 --- a/sound/spi/at73c213.c +++ b/sound/spi/at73c213.c @@ -1076,8 +1076,6 @@ out: snd_card_free(card); } -#ifdef CONFIG_PM_SLEEP - static int snd_at73c213_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); @@ -1109,18 +1107,13 @@ static int snd_at73c213_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(at73c213_pm_ops, snd_at73c213_suspend, +static DEFINE_SIMPLE_DEV_PM_OPS(at73c213_pm_ops, snd_at73c213_suspend, snd_at73c213_resume); -#define AT73C213_PM_OPS (&at73c213_pm_ops) - -#else -#define AT73C213_PM_OPS NULL -#endif static struct spi_driver at73c213_driver = { .driver = { .name = "at73c213", - .pm = AT73C213_PM_OPS, + .pm = &at73c213_pm_ops, }, .probe = snd_at73c213_probe, .remove = snd_at73c213_remove, -- cgit 1.2.3-korg From b9beb229eb265c544314a4e834d8467943c89650 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Feb 2024 16:51:26 +0100 Subject: ALSA: ali5451: Embed suspend image into struct snd_ali Instead of allocating the memory with an additional devm_kmalloc(), just put the image into the existing struct snd_ali. The allocation size isn't too big, hence it works better with less allocation calls. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240207155140.18238-16-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/ali5451/ali5451.c | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index 2378a39abaebe..9d48638a3ab40 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -244,7 +244,7 @@ struct snd_ali { spinlock_t voice_alloc; #ifdef CONFIG_PM_SLEEP - struct snd_ali_image *image; + struct snd_ali_image image; #endif }; @@ -1829,13 +1829,9 @@ static int ali_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct snd_ali *chip = card->private_data; - struct snd_ali_image *im; + struct snd_ali_image *im = &chip->image; int i, j; - im = chip->image; - if (!im) - return 0; - snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); for (i = 0; i < chip->num_of_codecs; i++) snd_ac97_suspend(chip->ac97[i]); @@ -1872,13 +1868,9 @@ static int ali_resume(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct snd_ali *chip = card->private_data; - struct snd_ali_image *im; + struct snd_ali_image *im = &chip->image; int i, j; - im = chip->image; - if (!im) - return 0; - spin_lock_irq(&chip->reg_lock); for (i = 0; i < ALI_CHANNELS; i++) { @@ -2112,13 +2104,6 @@ static int snd_ali_create(struct snd_card *card, return err; } -#ifdef CONFIG_PM_SLEEP - codec->image = devm_kmalloc(&pci->dev, sizeof(*codec->image), - GFP_KERNEL); - if (!codec->image) - dev_warn(card->dev, "can't allocate apm buffer\n"); -#endif - snd_ali_enable_address_interrupt(codec); codec->hw_initialized = 1; return 0; -- cgit 1.2.3-korg From 00545e3eb74a1892a13670cb03089a701b782b30 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Feb 2024 16:51:27 +0100 Subject: ALSA: ali5451: Simplify with DEFINE_SIMPLE_DEV_PM_OPS() Use the new DEFINE_SIMPLE_DEV_PM_OPS() instead of SIMPLE_DEV_PM_OPS() for code-simplification. We need no longer CONFIG_PM_SLEEP ifdefs. This ends up with the allocation of a few additional bytes for the image even if it's not really used, but the code-simplification should justify the cost. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240207155140.18238-17-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/ali5451/ali5451.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index 9d48638a3ab40..31e51e2df6557 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -243,9 +243,7 @@ struct snd_ali { spinlock_t reg_lock; spinlock_t voice_alloc; -#ifdef CONFIG_PM_SLEEP struct snd_ali_image image; -#endif }; static const struct pci_device_id snd_ali_ids[] = { @@ -1824,7 +1822,6 @@ static int snd_ali_mixer(struct snd_ali *codec) return 0; } -#ifdef CONFIG_PM_SLEEP static int ali_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); @@ -1900,11 +1897,7 @@ static int ali_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(ali_pm, ali_suspend, ali_resume); -#define ALI_PM_OPS &ali_pm -#else -#define ALI_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ +static DEFINE_SIMPLE_DEV_PM_OPS(ali_pm, ali_suspend, ali_resume); static void snd_ali_free(struct snd_card *card) { @@ -2166,7 +2159,7 @@ static struct pci_driver ali5451_driver = { .id_table = snd_ali_ids, .probe = snd_ali_probe, .driver = { - .pm = ALI_PM_OPS, + .pm = &ali_pm, }, }; -- cgit 1.2.3-korg From 9e5f7322773169f3fcdc841b4c1ae5e19afe4ef6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Feb 2024 16:51:28 +0100 Subject: ALSA: azt3328: Simplify with DEFINE_SIMPLE_DEV_PM_OPS() Use the new DEFINE_SIMPLE_DEV_PM_OPS() instead of SIMPLE_DEV_PM_OPS() for code-simplification. We need no longer CONFIG_PM_SLEEP ifdefs. This ends up with the allocation of a few additional bytes for the register dumps even if it's not really used, but the code simplification should justify the cost. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240207155140.18238-18-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/azt3328.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 431f0026b507e..84989c291cd77 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -295,7 +295,6 @@ struct snd_azf3328 { * CONFIG_PM register storage below, but that's slightly difficult. */ u16 shadow_reg_ctrl_6AH; -#ifdef CONFIG_PM_SLEEP /* register value containers for power management * Note: not always full I/O range preserved (similar to Win driver!) */ u32 saved_regs_ctrl[AZF_ALIGN(AZF_IO_SIZE_CTRL_PM) / 4]; @@ -303,7 +302,6 @@ struct snd_azf3328 { u32 saved_regs_mpu[AZF_ALIGN(AZF_IO_SIZE_MPU_PM) / 4]; u32 saved_regs_opl3[AZF_ALIGN(AZF_IO_SIZE_OPL3_PM) / 4]; u32 saved_regs_mixer[AZF_ALIGN(AZF_IO_SIZE_MIXER_PM) / 4]; -#endif }; static const struct pci_device_id snd_azf3328_ids[] = { @@ -2517,7 +2515,6 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) return snd_card_free_on_error(&pci->dev, __snd_azf3328_probe(pci, pci_id)); } -#ifdef CONFIG_PM_SLEEP static inline void snd_azf3328_suspend_regs(const struct snd_azf3328 *chip, unsigned long io_addr, unsigned count, u32 *saved_regs) @@ -2633,18 +2630,14 @@ snd_azf3328_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(snd_azf3328_pm, snd_azf3328_suspend, snd_azf3328_resume); -#define SND_AZF3328_PM_OPS &snd_azf3328_pm -#else -#define SND_AZF3328_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ +static DEFINE_SIMPLE_DEV_PM_OPS(snd_azf3328_pm, snd_azf3328_suspend, snd_azf3328_resume); static struct pci_driver azf3328_driver = { .name = KBUILD_MODNAME, .id_table = snd_azf3328_ids, .probe = snd_azf3328_probe, .driver = { - .pm = SND_AZF3328_PM_OPS, + .pm = &snd_azf3328_pm, }, }; -- cgit 1.2.3-korg From 1c69bc3955aae7cc0c7eff673122d048bc8bc571 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Feb 2024 16:51:29 +0100 Subject: ALSA: cmipci: Simplify with DEFINE_SIMPLE_DEV_PM_OPS() Use the new DEFINE_SIMPLE_DEV_PM_OPS() instead of SIMPLE_DEV_PM_OPS() for code-simplification. We need no longer CONFIG_PM_SLEEP ifdefs. This ends up with the allocation of a few additional bytes for the register dumps even if it's not really used, but the code simplification should justify the cost. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240207155140.18238-19-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/cmipci.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 08e34b1847801..36014501f7ed2 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -486,10 +486,8 @@ struct cmipci { spinlock_t reg_lock; -#ifdef CONFIG_PM_SLEEP unsigned int saved_regs[0x20]; unsigned char saved_mixers[0x20]; -#endif }; @@ -3260,7 +3258,6 @@ static int snd_cmipci_probe(struct pci_dev *pci, return err; } -#ifdef CONFIG_PM_SLEEP /* * power management */ @@ -3324,18 +3321,14 @@ static int snd_cmipci_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(snd_cmipci_pm, snd_cmipci_suspend, snd_cmipci_resume); -#define SND_CMIPCI_PM_OPS &snd_cmipci_pm -#else -#define SND_CMIPCI_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ +static DEFINE_SIMPLE_DEV_PM_OPS(snd_cmipci_pm, snd_cmipci_suspend, snd_cmipci_resume); static struct pci_driver cmipci_driver = { .name = KBUILD_MODNAME, .id_table = snd_cmipci_ids, .probe = snd_cmipci_probe, .driver = { - .pm = SND_CMIPCI_PM_OPS, + .pm = &snd_cmipci_pm, }, }; -- cgit 1.2.3-korg From cbdcefbde882c156b29b48dc76ab2738b9ceb2fc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Feb 2024 16:51:30 +0100 Subject: ALSA: cs4281: Simplify with DEFINE_SIMPLE_DEV_PM_OPS() Use the new DEFINE_SIMPLE_DEV_PM_OPS() instead of SIMPLE_DEV_PM_OPS() for code-simplification. We need no longer CONFIG_PM_SLEEP ifdefs. This ends up with the allocation of a few additional bytes for the register dumps even if it's not really used, but the code simplification should justify the cost. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240207155140.18238-20-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/cs4281.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 0c9cadf7b3b80..0cc86e73cc62e 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -470,10 +470,7 @@ struct cs4281 { struct gameport *gameport; -#ifdef CONFIG_PM_SLEEP u32 suspend_regs[SUSPEND_REGISTERS]; -#endif - }; static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id); @@ -1897,8 +1894,6 @@ static int snd_cs4281_probe(struct pci_dev *pci, /* * Power Management */ -#ifdef CONFIG_PM_SLEEP - static const int saved_regs[SUSPEND_REGISTERS] = { BA0_JSCTL, BA0_GPIOR, @@ -1987,18 +1982,14 @@ static int cs4281_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(cs4281_pm, cs4281_suspend, cs4281_resume); -#define CS4281_PM_OPS &cs4281_pm -#else -#define CS4281_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ +static DEFINE_SIMPLE_DEV_PM_OPS(cs4281_pm, cs4281_suspend, cs4281_resume); static struct pci_driver cs4281_driver = { .name = KBUILD_MODNAME, .id_table = snd_cs4281_ids, .probe = snd_cs4281_probe, .driver = { - .pm = CS4281_PM_OPS, + .pm = &cs4281_pm, }, }; -- cgit 1.2.3-korg From f8f137a708865e6479d466b905f702e456227ecc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Feb 2024 16:51:31 +0100 Subject: ALSA: echoaudio: Simplify with DEFINE_SIMPLE_DEV_PM_OPS() Use the new DEFINE_SIMPLE_DEV_PM_OPS() instead of SIMPLE_DEV_PM_OPS() for code-simplification. We need no longer CONFIG_PM_SLEEP ifdefs. This ends up with the allocation of firmware caches if it's not really used without CONFIG_PM, but the code simplification should justify the cost. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240207155140.18238-21-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/echoaudio/echoaudio.c | 21 ++------------------- sound/pci/echoaudio/echoaudio.h | 2 -- 2 files changed, 2 insertions(+), 21 deletions(-) (limited to 'sound') diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index c70c3ac4e99a5..7484de255a3ed 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -34,7 +34,6 @@ static int get_firmware(const struct firmware **fw_entry, int err; char name[30]; -#ifdef CONFIG_PM_SLEEP if (chip->fw_cache[fw_index]) { dev_dbg(chip->card->dev, "firmware requested: %s is cached\n", @@ -42,7 +41,6 @@ static int get_firmware(const struct firmware **fw_entry, *fw_entry = chip->fw_cache[fw_index]; return 0; } -#endif dev_dbg(chip->card->dev, "firmware requested: %s\n", card_fw[fw_index].data); @@ -51,10 +49,8 @@ static int get_firmware(const struct firmware **fw_entry, if (err < 0) dev_err(chip->card->dev, "get_firmware(): Firmware not available (%d)\n", err); -#ifdef CONFIG_PM_SLEEP else chip->fw_cache[fw_index] = *fw_entry; -#endif return err; } @@ -63,18 +59,13 @@ static int get_firmware(const struct firmware **fw_entry, static void free_firmware(const struct firmware *fw_entry, struct echoaudio *chip) { -#ifdef CONFIG_PM_SLEEP dev_dbg(chip->card->dev, "firmware not released (kept in cache)\n"); -#else - release_firmware(fw_entry); -#endif } static void free_firmware_cache(struct echoaudio *chip) { -#ifdef CONFIG_PM_SLEEP int i; for (i = 0; i < 8 ; i++) @@ -82,8 +73,6 @@ static void free_firmware_cache(struct echoaudio *chip) release_firmware(chip->fw_cache[i]); dev_dbg(chip->card->dev, "release_firmware(%d)\n", i); } - -#endif } @@ -2146,8 +2135,6 @@ static int snd_echo_probe(struct pci_dev *pci, } -#if defined(CONFIG_PM_SLEEP) - static int snd_echo_suspend(struct device *dev) { struct echoaudio *chip = dev_get_drvdata(dev); @@ -2237,11 +2224,7 @@ static int snd_echo_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(snd_echo_pm, snd_echo_suspend, snd_echo_resume); -#define SND_ECHO_PM_OPS &snd_echo_pm -#else -#define SND_ECHO_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ +static DEFINE_SIMPLE_DEV_PM_OPS(snd_echo_pm, snd_echo_suspend, snd_echo_resume); /****************************************************************************** Everything starts and ends here @@ -2253,7 +2236,7 @@ static struct pci_driver echo_driver = { .id_table = snd_echo_ids, .probe = snd_echo_probe, .driver = { - .pm = SND_ECHO_PM_OPS, + .pm = &snd_echo_pm, }, }; diff --git a/sound/pci/echoaudio/echoaudio.h b/sound/pci/echoaudio/echoaudio.h index d51de3e4edfa8..511f2fcc0fb92 100644 --- a/sound/pci/echoaudio/echoaudio.h +++ b/sound/pci/echoaudio/echoaudio.h @@ -422,9 +422,7 @@ struct echoaudio { u32 __iomem *dsp_registers; /* DSP's register base */ u32 active_mask; /* Chs. active mask or * punks out */ -#ifdef CONFIG_PM_SLEEP const struct firmware *fw_cache[8]; /* Cached firmwares */ -#endif #ifdef ECHOCARD_HAS_MIDI u16 mtc_state; /* State for MIDI input parsing state machine */ -- cgit 1.2.3-korg From c70b12adf2016e0c3a628a9c380b589473ae535d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Feb 2024 16:51:32 +0100 Subject: ALSA: es1938: Simplify with DEFINE_SIMPLE_DEV_PM_OPS() Use the new DEFINE_SIMPLE_DEV_PM_OPS() instead of SIMPLE_DEV_PM_OPS() for code-simplification. We need no longer CONFIG_PM_SLEEP ifdefs. This ends up with the allocation of a few additional bytes for the register dumps even if it's not really used, but the code simplification should justify the cost. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240207155140.18238-22-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/es1938.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index ec598ba1a8833..018a8d53ca53a 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -216,9 +216,7 @@ struct es1938 { #ifdef SUPPORT_JOYSTICK struct gameport *gameport; #endif -#ifdef CONFIG_PM_SLEEP unsigned char saved_regs[SAVED_REG_SIZE]; -#endif }; static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id); @@ -1395,7 +1393,6 @@ static void snd_es1938_chip_init(struct es1938 *chip) outb(0, SLDM_REG(chip, DMACLEAR)); } -#ifdef CONFIG_PM_SLEEP /* * PM support */ @@ -1461,11 +1458,7 @@ static int es1938_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(es1938_pm, es1938_suspend, es1938_resume); -#define ES1938_PM_OPS &es1938_pm -#else -#define ES1938_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ +static DEFINE_SIMPLE_DEV_PM_OPS(es1938_pm, es1938_suspend, es1938_resume); #ifdef SUPPORT_JOYSTICK static int snd_es1938_create_gameport(struct es1938 *chip) @@ -1787,7 +1780,7 @@ static struct pci_driver es1938_driver = { .id_table = snd_es1938_ids, .probe = snd_es1938_probe, .driver = { - .pm = ES1938_PM_OPS, + .pm = &es1938_pm, }, }; -- cgit 1.2.3-korg From 5947c394aced16848c24ed9fc653f4c07cec68a2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Feb 2024 16:51:33 +0100 Subject: ALSA: es1968: Simplify with DEFINE_SIMPLE_DEV_PM_OPS() Use the new DEFINE_SIMPLE_DEV_PM_OPS() instead of SIMPLE_DEV_PM_OPS() for code-simplification. We need no longer CONFIG_PM_SLEEP ifdefs. This ends up with the allocation of a few additional bytes for the register dumps even if it's not really used, but the code simplification should justify the cost. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240207155140.18238-23-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/es1968.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index 4bc0f53c223b7..c6c018b40c69f 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -473,9 +473,7 @@ struct esschan { /* linked list */ struct list_head list; -#ifdef CONFIG_PM_SLEEP u16 wc_map[4]; -#endif }; struct es1968 { @@ -526,9 +524,7 @@ struct es1968 { struct list_head substream_list; spinlock_t substream_lock; -#ifdef CONFIG_PM_SLEEP u16 apu_map[NR_APUS][NR_APU_REGS]; -#endif #ifdef SUPPORT_JOYSTICK struct gameport *gameport; @@ -689,9 +685,7 @@ static void __apu_set_register(struct es1968 *chip, u16 channel, u8 reg, u16 dat { if (snd_BUG_ON(channel >= NR_APUS)) return; -#ifdef CONFIG_PM_SLEEP chip->apu_map[channel][reg] = data; -#endif reg |= (channel << 4); apu_index_set(chip, reg); apu_data_set(chip, data); @@ -976,9 +970,7 @@ static void snd_es1968_program_wavecache(struct es1968 *chip, struct esschan *es /* set the wavecache control reg */ wave_set_register(chip, es->apu[channel] << 3, tmpval); -#ifdef CONFIG_PM_SLEEP es->wc_map[channel] = tmpval; -#endif } @@ -2356,7 +2348,6 @@ static void snd_es1968_start_irq(struct es1968 *chip) outw(w, chip->io_port + ESM_PORT_HOST_IRQ); } -#ifdef CONFIG_PM_SLEEP /* * PM support */ @@ -2418,11 +2409,7 @@ static int es1968_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(es1968_pm, es1968_suspend, es1968_resume); -#define ES1968_PM_OPS &es1968_pm -#else -#define ES1968_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ +static DEFINE_SIMPLE_DEV_PM_OPS(es1968_pm, es1968_suspend, es1968_resume); #ifdef SUPPORT_JOYSTICK #define JOYSTICK_ADDR 0x200 @@ -2852,7 +2839,7 @@ static struct pci_driver es1968_driver = { .id_table = snd_es1968_ids, .probe = snd_es1968_probe, .driver = { - .pm = ES1968_PM_OPS, + .pm = &es1968_pm, }, }; -- cgit 1.2.3-korg From e6c2f5ec419adf3abf59e50cf566498239a385e9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Feb 2024 16:51:34 +0100 Subject: ALSA: fm801: Simplify with DEFINE_SIMPLE_DEV_PM_OPS() Use the new DEFINE_SIMPLE_DEV_PM_OPS() instead of SIMPLE_DEV_PM_OPS() for code-simplification. We need no longer CONFIG_PM_SLEEP ifdefs. This ends up with the allocation of a few additional bytes for the register dumps even if it's not really used, but the code simplification should justify the cost. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240207155140.18238-24-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/fm801.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 62b3cb126c6d0..7f4834c2d5e6b 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -222,9 +222,7 @@ struct fm801 { struct snd_tea575x tea; #endif -#ifdef CONFIG_PM_SLEEP u16 saved_regs[0x20]; -#endif }; /* @@ -1339,7 +1337,6 @@ static int snd_card_fm801_probe(struct pci_dev *pci, return snd_card_free_on_error(&pci->dev, __snd_card_fm801_probe(pci, pci_id)); } -#ifdef CONFIG_PM_SLEEP static const unsigned char saved_regs[] = { FM801_PCM_VOL, FM801_I2S_VOL, FM801_FM_VOL, FM801_REC_SRC, FM801_PLY_CTRL, FM801_PLY_COUNT, FM801_PLY_BUF1, FM801_PLY_BUF2, @@ -1396,18 +1393,14 @@ static int snd_fm801_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(snd_fm801_pm, snd_fm801_suspend, snd_fm801_resume); -#define SND_FM801_PM_OPS &snd_fm801_pm -#else -#define SND_FM801_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ +static DEFINE_SIMPLE_DEV_PM_OPS(snd_fm801_pm, snd_fm801_suspend, snd_fm801_resume); static struct pci_driver fm801_driver = { .name = KBUILD_MODNAME, .id_table = snd_fm801_ids, .probe = snd_card_fm801_probe, .driver = { - .pm = SND_FM801_PM_OPS, + .pm = &snd_fm801_pm, }, }; -- cgit 1.2.3-korg From a2280df4f92899ab1cf89300947cdc9b8294d7a8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Feb 2024 16:51:35 +0100 Subject: ALSA: maestro3: Simplify with DEFINE_SIMPLE_DEV_PM_OPS() Use the new DEFINE_SIMPLE_DEV_PM_OPS() instead of SIMPLE_DEV_PM_OPS() for code-simplification. We need no longer CONFIG_PM_SLEEP ifdefs. The area for register dump is conditionally allocated instead of ifdef now. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240207155140.18238-25-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/maestro3.c | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) (limited to 'sound') diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 305cbd24a3918..f4d211970d7ec 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -769,9 +769,7 @@ struct snd_m3 { unsigned int in_suspend; -#ifdef CONFIG_PM_SLEEP u16 *suspend_mem; -#endif const struct firmware *assp_kernel_image; const struct firmware *assp_minisrc_image; @@ -2354,9 +2352,7 @@ static void snd_m3_free(struct snd_card *card) outw(0, chip->iobase + HOST_INT_CTRL); /* disable ints */ } -#ifdef CONFIG_PM_SLEEP vfree(chip->suspend_mem); -#endif release_firmware(chip->assp_kernel_image); release_firmware(chip->assp_minisrc_image); } @@ -2365,7 +2361,6 @@ static void snd_m3_free(struct snd_card *card) /* * APM support */ -#ifdef CONFIG_PM_SLEEP static int m3_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); @@ -2439,11 +2434,7 @@ static int m3_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(m3_pm, m3_suspend, m3_resume); -#define M3_PM_OPS &m3_pm -#else -#define M3_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ +static DEFINE_SIMPLE_DEV_PM_OPS(m3_pm, m3_suspend, m3_resume); #ifdef CONFIG_SND_MAESTRO3_INPUT static int snd_m3_input_register(struct snd_m3 *chip) @@ -2587,14 +2578,14 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, chip->irq = pci->irq; card->sync_irq = chip->irq; -#ifdef CONFIG_PM_SLEEP - chip->suspend_mem = - vmalloc(array_size(sizeof(u16), - REV_B_CODE_MEMORY_LENGTH + - REV_B_DATA_MEMORY_LENGTH)); - if (chip->suspend_mem == NULL) - dev_warn(card->dev, "can't allocate apm buffer\n"); -#endif + if (IS_ENABLED(CONFIG_PM_SLEEP)) { + chip->suspend_mem = + vmalloc(array_size(sizeof(u16), + REV_B_CODE_MEMORY_LENGTH + + REV_B_DATA_MEMORY_LENGTH)); + if (!chip->suspend_mem) + dev_warn(card->dev, "can't allocate apm buffer\n"); + } err = snd_m3_mixer(chip); if (err < 0) @@ -2706,7 +2697,7 @@ static struct pci_driver m3_driver = { .id_table = snd_m3_ids, .probe = snd_m3_probe, .driver = { - .pm = M3_PM_OPS, + .pm = &m3_pm, }, }; -- cgit 1.2.3-korg From 9de7d0caefd0cdf6d3e301e3aad84fd9a5ce12e8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Feb 2024 16:51:36 +0100 Subject: ALSA: riptide: Simplify with DEFINE_SIMPLE_DEV_PM_OPS() Use the new DEFINE_SIMPLE_DEV_PM_OPS() instead of SIMPLE_DEV_PM_OPS() for code-simplification. We need no longer CONFIG_PM_SLEEP ifdefs. This ends up with an additional allocation of a flag without CONFIG_PM, but the code simplification should justify the cost. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240207155140.18238-26-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/riptide/riptide.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index 9dee0345f22cf..7e80686fb41a3 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -448,9 +448,7 @@ struct snd_riptide { unsigned long received_irqs; unsigned long handled_irqs; -#ifdef CONFIG_PM_SLEEP int in_suspend; -#endif }; struct sgd { /* scatter gather desriptor */ @@ -1142,7 +1140,6 @@ static irqreturn_t riptide_handleirq(int irq, void *dev_id) return IRQ_HANDLED; } -#ifdef CONFIG_PM_SLEEP static int riptide_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); @@ -1166,11 +1163,7 @@ static int riptide_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(riptide_pm, riptide_suspend, riptide_resume); -#define RIPTIDE_PM_OPS &riptide_pm -#else -#define RIPTIDE_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ +static DEFINE_SIMPLE_DEV_PM_OPS(riptide_pm, riptide_suspend, riptide_resume); static int try_to_load_firmware(struct cmdif *cif, struct snd_riptide *chip) { @@ -2135,7 +2128,7 @@ static struct pci_driver driver = { .id_table = snd_riptide_ids, .probe = snd_card_riptide_probe, .driver = { - .pm = RIPTIDE_PM_OPS, + .pm = &riptide_pm, }, }; -- cgit 1.2.3-korg From ea1741dc34f4b70539729e51b0f09cbf7e5faae8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Feb 2024 16:51:37 +0100 Subject: ALSA: rme96: Simplify with DEFINE_SIMPLE_DEV_PM_OPS() Use the new DEFINE_SIMPLE_DEV_PM_OPS() instead of SIMPLE_DEV_PM_OPS() for code-simplification. We need no longer CONFIG_PM_SLEEP ifdefs. The temporary buffers for PCM stream backups are conditionally allocated since the sizes aren't too small. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240207155140.18238-27-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/rme96.c | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) (limited to 'sound') diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 6b5ffb18197b0..d50ad25574ada 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -220,12 +220,10 @@ struct rme96 { u8 rev; /* card revision number */ -#ifdef CONFIG_PM_SLEEP u32 playback_pointer; u32 capture_pointer; void *playback_suspend_buffer; void *capture_suspend_buffer; -#endif struct snd_pcm_substream *playback_substream; struct snd_pcm_substream *capture_substream; @@ -1543,10 +1541,8 @@ snd_rme96_free(struct rme96 *rme96) rme96->areg &= ~RME96_AR_DAC_EN; writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG); } -#ifdef CONFIG_PM_SLEEP vfree(rme96->playback_suspend_buffer); vfree(rme96->capture_suspend_buffer); -#endif } static void @@ -2329,8 +2325,6 @@ snd_rme96_create_switches(struct snd_card *card, * Card initialisation */ -#ifdef CONFIG_PM_SLEEP - static int rme96_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); @@ -2392,11 +2386,7 @@ static int rme96_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(rme96_pm, rme96_suspend, rme96_resume); -#define RME96_PM_OPS &rme96_pm -#else -#define RME96_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ +static DEFINE_SIMPLE_DEV_PM_OPS(rme96_pm, rme96_suspend, rme96_resume); static void snd_rme96_card_free(struct snd_card *card) { @@ -2432,14 +2422,14 @@ __snd_rme96_probe(struct pci_dev *pci, if (err) return err; -#ifdef CONFIG_PM_SLEEP - rme96->playback_suspend_buffer = vmalloc(RME96_BUFFER_SIZE); - if (!rme96->playback_suspend_buffer) - return -ENOMEM; - rme96->capture_suspend_buffer = vmalloc(RME96_BUFFER_SIZE); - if (!rme96->capture_suspend_buffer) - return -ENOMEM; -#endif + if (IS_ENABLED(CONFIG_PM_SLEEP)) { + rme96->playback_suspend_buffer = vmalloc(RME96_BUFFER_SIZE); + if (!rme96->playback_suspend_buffer) + return -ENOMEM; + rme96->capture_suspend_buffer = vmalloc(RME96_BUFFER_SIZE); + if (!rme96->capture_suspend_buffer) + return -ENOMEM; + } strcpy(card->driver, "Digi96"); switch (rme96->pci->device) { @@ -2483,7 +2473,7 @@ static struct pci_driver rme96_driver = { .id_table = snd_rme96_ids, .probe = snd_rme96_probe, .driver = { - .pm = RME96_PM_OPS, + .pm = &rme96_pm, }, }; -- cgit 1.2.3-korg From 6750d6ed2749f7d431e64a7891188809d1adec54 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Feb 2024 16:51:38 +0100 Subject: ALSA: sis7019: Simplify with DEFINE_SIMPLE_DEV_PM_OPS() Use the new DEFINE_SIMPLE_DEV_PM_OPS() instead of SIMPLE_DEV_PM_OPS() for code-simplification. We need no longer CONFIG_PM_SLEEP ifdefs. This ends up with the allocation of all 4 pages no matter with CONFIG_PM, but the code simplification should justify the cost. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240207155140.18238-28-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/sis7019.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c index fabe393607f8f..53206beb2cb50 100644 --- a/sound/pci/sis7019.c +++ b/sound/pci/sis7019.c @@ -90,11 +90,7 @@ struct voice { * we're not doing power management, we still need to allocate a page * for the silence buffer. */ -#ifdef CONFIG_PM_SLEEP #define SIS_SUSPEND_PAGES 4 -#else -#define SIS_SUSPEND_PAGES 1 -#endif struct sis7019 { unsigned long ioport; @@ -1152,7 +1148,6 @@ static int sis_chip_init(struct sis7019 *sis) return 0; } -#ifdef CONFIG_PM_SLEEP static int sis_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); @@ -1231,11 +1226,7 @@ error: return -EIO; } -static SIMPLE_DEV_PM_OPS(sis_pm, sis_suspend, sis_resume); -#define SIS_PM_OPS &sis_pm -#else -#define SIS_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ +static DEFINE_SIMPLE_DEV_PM_OPS(sis_pm, sis_suspend, sis_resume); static int sis_alloc_suspend(struct sis7019 *sis) { @@ -1397,7 +1388,7 @@ static struct pci_driver sis7019_driver = { .id_table = snd_sis7019_ids, .probe = snd_sis7019_probe, .driver = { - .pm = SIS_PM_OPS, + .pm = &sis_pm, }, }; -- cgit 1.2.3-korg From 8dbcc799a401fe0a37db323f1e77333b4d92b937 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 7 Feb 2024 16:51:39 +0100 Subject: ALSA: via82xx: Simplify with DEFINE_SIMPLE_DEV_PM_OPS() Use the new DEFINE_SIMPLE_DEV_PM_OPS() instead of SIMPLE_DEV_PM_OPS() for code-simplification. We need no longer CONFIG_PM_SLEEP ifdefs. This ends up with the allocation of a few additional bytes for the state dumps even if it's not really used, but the code simplification should justify the cost. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240207155140.18238-29-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/via82xx.c | 15 ++------------- sound/pci/via82xx_modem.c | 9 ++------- 2 files changed, 4 insertions(+), 20 deletions(-) (limited to 'sound') diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index d8666ff7bdfae..89838b4fb118a 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -347,13 +347,11 @@ struct via82xx { unsigned char old_legacy; unsigned char old_legacy_cfg; -#ifdef CONFIG_PM_SLEEP unsigned char legacy_saved; unsigned char legacy_cfg_saved; unsigned char spdif_ctrl_saved; unsigned char capture_src_saved[2]; unsigned int mpu_port_saved; -#endif unsigned char playback_volume[4][2]; /* for VIA8233/C/8235; default = 0 */ unsigned char playback_volume_c[2]; /* for VIA8233/C/8235; default = 0 */ @@ -2031,9 +2029,7 @@ static int snd_via686_init_misc(struct via82xx *chip) if (mpu_port >= 0x200) { /* force MIDI */ mpu_port &= 0xfffc; pci_write_config_dword(chip->pci, 0x18, mpu_port | 0x01); -#ifdef CONFIG_PM_SLEEP chip->mpu_port_saved = mpu_port; -#endif } else { mpu_port = pci_resource_start(chip->pci, 2); } @@ -2085,10 +2081,8 @@ static int snd_via686_init_misc(struct via82xx *chip) snd_via686_create_gameport(chip, &legacy); -#ifdef CONFIG_PM_SLEEP chip->legacy_saved = legacy; chip->legacy_cfg_saved = legacy_cfg; -#endif return 0; } @@ -2234,7 +2228,6 @@ static int snd_via82xx_chip_init(struct via82xx *chip) return 0; } -#ifdef CONFIG_PM_SLEEP /* * power management */ @@ -2287,11 +2280,7 @@ static int snd_via82xx_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(snd_via82xx_pm, snd_via82xx_suspend, snd_via82xx_resume); -#define SND_VIA82XX_PM_OPS &snd_via82xx_pm -#else -#define SND_VIA82XX_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ +static DEFINE_SIMPLE_DEV_PM_OPS(snd_via82xx_pm, snd_via82xx_suspend, snd_via82xx_resume); static void snd_via82xx_free(struct snd_card *card) { @@ -2576,7 +2565,7 @@ static struct pci_driver via82xx_driver = { .id_table = snd_via82xx_ids, .probe = snd_via82xx_probe, .driver = { - .pm = SND_VIA82XX_PM_OPS, + .pm = &snd_via82xx_pm, }, }; diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index ca7f024bf8ec6..a0a49b8d15116 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -1008,7 +1008,6 @@ static int snd_via82xx_chip_init(struct via82xx_modem *chip) return 0; } -#ifdef CONFIG_PM_SLEEP /* * power management */ @@ -1042,11 +1041,7 @@ static int snd_via82xx_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(snd_via82xx_pm, snd_via82xx_suspend, snd_via82xx_resume); -#define SND_VIA82XX_PM_OPS &snd_via82xx_pm -#else -#define SND_VIA82XX_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ +static DEFINE_SIMPLE_DEV_PM_OPS(snd_via82xx_pm, snd_via82xx_suspend, snd_via82xx_resume); static void snd_via82xx_free(struct snd_card *card) { @@ -1168,7 +1163,7 @@ static struct pci_driver via82xx_modem_driver = { .id_table = snd_via82xx_modem_ids, .probe = snd_via82xx_probe, .driver = { - .pm = SND_VIA82XX_PM_OPS, + .pm = &snd_via82xx_pm, }, }; -- cgit 1.2.3-korg From aabdedf4d2fe2f83cb025ae972202dcee4eb024b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 13 Feb 2024 11:12:46 +0100 Subject: ALSA: ctxfi: avoid casting function pointers This driver creates an abstraction for different components by casting function pointers to slightly incompatible types for each one to get the correct argument even when the caller does not know those types. This is a bit unreliable and not allowed in combination with control flow integrity (KCFI): sound/pci/ctxfi/ctatc.c:115:25: error: cast from 'int (*)(struct hw *, struct src_mgr **)' to 'create_t' (aka 'int (*)(struct hw *, void **)') converts to incompatible function type [-Werror,-Wcast-function-type-strict] 115 | [SRC] = { .create = (create_t)src_mgr_create, | ^~~~~~~~~~~~~~~~~~~~~~~~ sound/pci/ctxfi/ctatc.c:116:20: error: cast from 'int (*)(struct src_mgr *)' to 'destroy_t' (aka 'int (*)(void *)') converts to incompatible function type [-Werror,-Wcast-function-type-strict] 116 | .destroy = (destroy_t)src_mgr_destroy }, | ^~~~~~~~~~~~~~~~~~~~~~~~~~ sound/pci/ctxfi/ctatc.c:117:27: error: cast from 'int (*)(struct hw *, struct srcimp_mgr **)' to 'create_t' (aka 'int (*)(struct hw *, void **)') converts to incompatible function type [-Werror,-Wcast-function-type-strict] 117 | [SRCIMP] = { .create = (create_t)srcimp_mgr_create, | ^~~~~~~~~~~~~~~~~~~~~~~~~~~ sound/pci/ctxfi/ctatc.c:118:20: error: cast from 'int (*)(struct srcimp_mgr *)' to 'destroy_t' (aka 'int (*)(void *)') converts to incompatible function type [-Werror,-Wcast-function-type-strict] 118 | .destroy = (destroy_t)srcimp_mgr_destroy }, | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Change these to always pass void pointers and move the abstraction one level down. Fixes: 8cc72361481f ("ALSA: SB X-Fi driver merge") Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20240213101303.460008-1-arnd@kernel.org Signed-off-by: Takashi Iwai --- sound/pci/ctxfi/ctamixer.c | 10 ++++++---- sound/pci/ctxfi/ctamixer.h | 8 ++++---- sound/pci/ctxfi/ctatc.c | 23 ++++++++++------------- sound/pci/ctxfi/ctdaio.c | 5 +++-- sound/pci/ctxfi/ctdaio.h | 4 ++-- sound/pci/ctxfi/ctsrc.c | 10 ++++++---- sound/pci/ctxfi/ctsrc.h | 8 ++++---- 7 files changed, 35 insertions(+), 33 deletions(-) (limited to 'sound') diff --git a/sound/pci/ctxfi/ctamixer.c b/sound/pci/ctxfi/ctamixer.c index d074727c3e21d..397900929aa65 100644 --- a/sound/pci/ctxfi/ctamixer.c +++ b/sound/pci/ctxfi/ctamixer.c @@ -292,7 +292,7 @@ static int put_amixer_rsc(struct amixer_mgr *mgr, struct amixer *amixer) return 0; } -int amixer_mgr_create(struct hw *hw, struct amixer_mgr **ramixer_mgr) +int amixer_mgr_create(struct hw *hw, void **ramixer_mgr) { int err; struct amixer_mgr *amixer_mgr; @@ -321,8 +321,9 @@ error: return err; } -int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr) +int amixer_mgr_destroy(void *ptr) { + struct amixer_mgr *amixer_mgr = ptr; rsc_mgr_uninit(&amixer_mgr->mgr); kfree(amixer_mgr); return 0; @@ -446,7 +447,7 @@ static int put_sum_rsc(struct sum_mgr *mgr, struct sum *sum) return 0; } -int sum_mgr_create(struct hw *hw, struct sum_mgr **rsum_mgr) +int sum_mgr_create(struct hw *hw, void **rsum_mgr) { int err; struct sum_mgr *sum_mgr; @@ -475,8 +476,9 @@ error: return err; } -int sum_mgr_destroy(struct sum_mgr *sum_mgr) +int sum_mgr_destroy(void *ptr) { + struct sum_mgr *sum_mgr = ptr; rsc_mgr_uninit(&sum_mgr->mgr); kfree(sum_mgr); return 0; diff --git a/sound/pci/ctxfi/ctamixer.h b/sound/pci/ctxfi/ctamixer.h index 4498e6139d0ef..8fc017da6bda8 100644 --- a/sound/pci/ctxfi/ctamixer.h +++ b/sound/pci/ctxfi/ctamixer.h @@ -43,8 +43,8 @@ struct sum_mgr { }; /* Constructor and destructor of daio resource manager */ -int sum_mgr_create(struct hw *hw, struct sum_mgr **rsum_mgr); -int sum_mgr_destroy(struct sum_mgr *sum_mgr); +int sum_mgr_create(struct hw *hw, void **ptr); +int sum_mgr_destroy(void *ptr); /* Define the descriptor of a amixer resource */ struct amixer_rsc_ops; @@ -89,7 +89,7 @@ struct amixer_mgr { }; /* Constructor and destructor of amixer resource manager */ -int amixer_mgr_create(struct hw *hw, struct amixer_mgr **ramixer_mgr); -int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr); +int amixer_mgr_create(struct hw *hw, void **ramixer_mgr); +int amixer_mgr_destroy(void *amixer_mgr); #endif /* CTAMIXER_H */ diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index fbdb8a3d5b8e5..2a3e9d8ba7dbe 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -105,23 +105,20 @@ static struct { .public_name = "Mixer"} }; -typedef int (*create_t)(struct hw *, void **); -typedef int (*destroy_t)(void *); - static struct { int (*create)(struct hw *hw, void **rmgr); int (*destroy)(void *mgr); } rsc_mgr_funcs[NUM_RSCTYP] = { - [SRC] = { .create = (create_t)src_mgr_create, - .destroy = (destroy_t)src_mgr_destroy }, - [SRCIMP] = { .create = (create_t)srcimp_mgr_create, - .destroy = (destroy_t)srcimp_mgr_destroy }, - [AMIXER] = { .create = (create_t)amixer_mgr_create, - .destroy = (destroy_t)amixer_mgr_destroy }, - [SUM] = { .create = (create_t)sum_mgr_create, - .destroy = (destroy_t)sum_mgr_destroy }, - [DAIO] = { .create = (create_t)daio_mgr_create, - .destroy = (destroy_t)daio_mgr_destroy } + [SRC] = { .create = src_mgr_create, + .destroy = src_mgr_destroy }, + [SRCIMP] = { .create = srcimp_mgr_create, + .destroy = srcimp_mgr_destroy }, + [AMIXER] = { .create = amixer_mgr_create, + .destroy = amixer_mgr_destroy }, + [SUM] = { .create = sum_mgr_create, + .destroy = sum_mgr_destroy }, + [DAIO] = { .create = daio_mgr_create, + .destroy = daio_mgr_destroy } }; static int diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c index 7fc720046ce29..83aaf9441ef30 100644 --- a/sound/pci/ctxfi/ctdaio.c +++ b/sound/pci/ctxfi/ctdaio.c @@ -684,7 +684,7 @@ static int daio_mgr_commit_write(struct daio_mgr *mgr) return 0; } -int daio_mgr_create(struct hw *hw, struct daio_mgr **rdaio_mgr) +int daio_mgr_create(struct hw *hw, void **rdaio_mgr) { int err, i; struct daio_mgr *daio_mgr; @@ -738,8 +738,9 @@ error1: return err; } -int daio_mgr_destroy(struct daio_mgr *daio_mgr) +int daio_mgr_destroy(void *ptr) { + struct daio_mgr *daio_mgr = ptr; unsigned long flags; /* free daio input mapper list */ diff --git a/sound/pci/ctxfi/ctdaio.h b/sound/pci/ctxfi/ctdaio.h index bd6310f480139..15147fe5f74a0 100644 --- a/sound/pci/ctxfi/ctdaio.h +++ b/sound/pci/ctxfi/ctdaio.h @@ -115,7 +115,7 @@ struct daio_mgr { }; /* Constructor and destructor of daio resource manager */ -int daio_mgr_create(struct hw *hw, struct daio_mgr **rdaio_mgr); -int daio_mgr_destroy(struct daio_mgr *daio_mgr); +int daio_mgr_create(struct hw *hw, void **ptr); +int daio_mgr_destroy(void *ptr); #endif /* CTDAIO_H */ diff --git a/sound/pci/ctxfi/ctsrc.c b/sound/pci/ctxfi/ctsrc.c index 4a94b4708a77e..159bd40080691 100644 --- a/sound/pci/ctxfi/ctsrc.c +++ b/sound/pci/ctxfi/ctsrc.c @@ -540,7 +540,7 @@ static int src_mgr_commit_write(struct src_mgr *mgr) return 0; } -int src_mgr_create(struct hw *hw, struct src_mgr **rsrc_mgr) +int src_mgr_create(struct hw *hw, void **rsrc_mgr) { int err, i; struct src_mgr *src_mgr; @@ -580,8 +580,9 @@ error1: return err; } -int src_mgr_destroy(struct src_mgr *src_mgr) +int src_mgr_destroy(void *ptr) { + struct src_mgr *src_mgr = ptr; rsc_mgr_uninit(&src_mgr->mgr); kfree(src_mgr); @@ -821,7 +822,7 @@ static int srcimp_imap_delete(struct srcimp_mgr *mgr, struct imapper *entry) return err; } -int srcimp_mgr_create(struct hw *hw, struct srcimp_mgr **rsrcimp_mgr) +int srcimp_mgr_create(struct hw *hw, void **rsrcimp_mgr) { int err; struct srcimp_mgr *srcimp_mgr; @@ -866,8 +867,9 @@ error1: return err; } -int srcimp_mgr_destroy(struct srcimp_mgr *srcimp_mgr) +int srcimp_mgr_destroy(void *ptr) { + struct srcimp_mgr *srcimp_mgr = ptr; unsigned long flags; /* free src input mapper list */ diff --git a/sound/pci/ctxfi/ctsrc.h b/sound/pci/ctxfi/ctsrc.h index 1124daf50c9be..e6366cc6a7ae6 100644 --- a/sound/pci/ctxfi/ctsrc.h +++ b/sound/pci/ctxfi/ctsrc.h @@ -139,10 +139,10 @@ struct srcimp_mgr { }; /* Constructor and destructor of SRC resource manager */ -int src_mgr_create(struct hw *hw, struct src_mgr **rsrc_mgr); -int src_mgr_destroy(struct src_mgr *src_mgr); +int src_mgr_create(struct hw *hw, void **ptr); +int src_mgr_destroy(void *ptr); /* Constructor and destructor of SRCIMP resource manager */ -int srcimp_mgr_create(struct hw *hw, struct srcimp_mgr **rsrc_mgr); -int srcimp_mgr_destroy(struct srcimp_mgr *srcimp_mgr); +int srcimp_mgr_create(struct hw *hw, void **ptr); +int srcimp_mgr_destroy(void *ptr); #endif /* CTSRC_H */ -- cgit 1.2.3-korg From 022a13a1db302d55aad3c7c4c40d2c9392f3842b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 13 Feb 2024 11:13:19 +0100 Subject: ALSA: aw2: avoid casting function pointers clang-16 started warning about incompatible function pointers here: sound/pci/aw2/aw2-alsa.c:363:11: error: cast from 'void (*)(struct snd_pcm_substream *)' to 'snd_aw2_saa7146_it_cb' (aka 'void (*)(void *)') converts to incompatible function type [-Werror,-Wcast-function-type-strict] 363 | (snd_aw2_saa7146_it_cb) | ^~~~~~~~~~~~~~~~~~~~~~~ 364 | snd_pcm_period_elapsed, | ~~~~~~~~~~~~~~~~~~~~~~ sound/pci/aw2/aw2-alsa.c:392:10: error: cast from 'void (*)(struct snd_pcm_substream *)' to 'snd_aw2_saa7146_it_cb' (aka 'void (*)(void *)') converts to incompatible function type [-Werror,-Wcast-function-type-strict] 392 | (snd_aw2_saa7146_it_cb) | ^~~~~~~~~~~~~~~~~~~~~~~ 393 | snd_pcm_period_elapsed, | ~~~~~~~~~~~~~~~~~~~~~~ Add a forward declaration for struct snd_pcm_substrea to allow it to just use the correct prototype. Fixes: 98f2a97f207a ("[ALSA] Emagic Audiowerk 2 ALSA driver.") Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20240213101327.460191-1-arnd@kernel.org Signed-off-by: Takashi Iwai --- sound/pci/aw2/aw2-saa7146.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/aw2/aw2-saa7146.h b/sound/pci/aw2/aw2-saa7146.h index b5c5a71c0ac38..3a3de56b9b07a 100644 --- a/sound/pci/aw2/aw2-saa7146.h +++ b/sound/pci/aw2/aw2-saa7146.h @@ -19,11 +19,12 @@ #define NUM_STREAM_CAPTURE_ANA 0 -typedef void (*snd_aw2_saa7146_it_cb) (void *); +struct snd_pcm_substream; +typedef void (*snd_aw2_saa7146_it_cb) (struct snd_pcm_substream *); struct snd_aw2_saa7146_cb_param { snd_aw2_saa7146_it_cb p_it_callback; - void *p_callback_param; + struct snd_pcm_substream *p_callback_param; }; /* definition of the chip-specific record */ -- cgit 1.2.3-korg From d7bf73809849463f76de42aad62c850305dd6c5d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 13 Feb 2024 14:53:43 +0100 Subject: ALSA: seq: fix function cast warnings clang-16 points out a control flow integrity (kcfi) issue when event callbacks get converted to incompatible types: sound/core/seq/seq_midi.c:135:30: error: cast from 'int (*)(struct snd_rawmidi_substream *, const char *, int)' to 'snd_seq_dump_func_t' (aka 'int (*)(void *, void *, int)') converts to incompatible function type [-Werror,-Wcast-function-type-strict] 135 | snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)dump_midi, substream); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sound/core/seq/seq_virmidi.c:83:31: error: cast from 'int (*)(struct snd_rawmidi_substream *, const unsigned char *, int)' to 'snd_seq_dump_func_t' (aka 'int (*)(void *, void *, int)') converts to incompatible function type [-Werror,-Wcast-function-type-strict] 83 | snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)snd_rawmidi_receive, vmidi->substream); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ For addressing those errors, introduce wrapper functions that are used for callbacks and bridge to the actual function call with pointer cast. The code was originally added with the initial ALSA merge in linux-2.5.4. [ the patch description shamelessly copied from Arnd's original patch -- tiwai ] Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reported-by: Arnd Bergmann Link: https://lore.kernel.org/r/20240213101020.459183-1-arnd@kernel.org Link: https://lore.kernel.org/r/20240213135343.16411-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/seq/seq_midi.c | 8 +++++++- sound/core/seq/seq_virmidi.c | 9 ++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index 18320a248aa7d..78dcb0ea15582 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c @@ -113,6 +113,12 @@ static int dump_midi(struct snd_rawmidi_substream *substream, const char *buf, i return 0; } +/* callback for snd_seq_dump_var_event(), bridging to dump_midi() */ +static int __dump_midi(void *ptr, void *buf, int count) +{ + return dump_midi(ptr, buf, count); +} + static int event_process_midi(struct snd_seq_event *ev, int direct, void *private_data, int atomic, int hop) { @@ -132,7 +138,7 @@ static int event_process_midi(struct snd_seq_event *ev, int direct, pr_debug("ALSA: seq_midi: invalid sysex event flags = 0x%x\n", ev->flags); return 0; } - snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)dump_midi, substream); + snd_seq_dump_var_event(ev, __dump_midi, substream); snd_midi_event_reset_decode(msynth->parser); } else { if (msynth->parser == NULL) diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 1b9260108e482..1678737f11be7 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -62,6 +62,13 @@ static void snd_virmidi_init_event(struct snd_virmidi *vmidi, /* * decode input event and put to read buffer of each opened file */ + +/* callback for snd_seq_dump_var_event(), bridging to snd_rawmidi_receive() */ +static int dump_to_rawmidi(void *ptr, void *buf, int count) +{ + return snd_rawmidi_receive(ptr, buf, count); +} + static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev, struct snd_seq_event *ev, bool atomic) @@ -80,7 +87,7 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev, if (ev->type == SNDRV_SEQ_EVENT_SYSEX) { if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE) continue; - snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)snd_rawmidi_receive, vmidi->substream); + snd_seq_dump_var_event(ev, dump_to_rawmidi, vmidi->substream); snd_midi_event_reset_decode(vmidi->parser); } else { len = snd_midi_event_decode(vmidi->parser, msg, sizeof(msg), ev); -- cgit 1.2.3-korg From 6eb25606fd4b4793ab486ba90c4f86463991bf42 Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Wed, 14 Feb 2024 16:28:28 -0300 Subject: ALSA: aoa: make soundbus_bus_type const Since commit d492cc2573a0 ("driver core: device.h: make struct bus_type a const *"), the driver core can properly handle constant struct bus_type, move the soundbus_bus_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20240214-bus_cleanup-alsa-v1-1-8fedbb4afa94@marliere.net Signed-off-by: Takashi Iwai --- sound/aoa/soundbus/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/aoa/soundbus/core.c b/sound/aoa/soundbus/core.c index 8f24a3eea16bd..2a295f6105942 100644 --- a/sound/aoa/soundbus/core.c +++ b/sound/aoa/soundbus/core.c @@ -127,7 +127,7 @@ static void soundbus_device_shutdown(struct device *dev) /* soundbus_dev_attrs is declared in sysfs.c */ ATTRIBUTE_GROUPS(soundbus_dev); -static struct bus_type soundbus_bus_type = { +static const struct bus_type soundbus_bus_type = { .name = "aoa-soundbus", .probe = soundbus_probe, .uevent = soundbus_uevent, -- cgit 1.2.3-korg From 0081e83be0ca99db7bac487156d0b3ae49d936be Mon Sep 17 00:00:00 2001 From: "Ricardo B. Marliere" Date: Wed, 14 Feb 2024 16:28:29 -0300 Subject: ALSA: seq: make snd_seq_bus_type const Since commit d492cc2573a0 ("driver core: device.h: make struct bus_type a const *"), the driver core can properly handle constant struct bus_type, move the snd_seq_bus_type variable to be a constant structure as well, placing it into read-only memory which can not be modified at runtime. Cc: Greg Kroah-Hartman Suggested-by: Greg Kroah-Hartman Signed-off-by: Ricardo B. Marliere Reviewed-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20240214-bus_cleanup-alsa-v1-2-8fedbb4afa94@marliere.net Signed-off-by: Takashi Iwai --- sound/core/seq_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/seq_device.c b/sound/core/seq_device.c index 7f3fd8eb016fe..654d620d0199f 100644 --- a/sound/core/seq_device.c +++ b/sound/core/seq_device.c @@ -49,7 +49,7 @@ static int snd_seq_bus_match(struct device *dev, struct device_driver *drv) sdrv->argsize == sdev->argsize; } -static struct bus_type snd_seq_bus_type = { +static const struct bus_type snd_seq_bus_type = { .name = "snd_seq", .match = snd_seq_bus_match, }; -- cgit 1.2.3-korg From 8e8bc5000328a1ba8f93d43faf427e8ac31fb416 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 15 Feb 2024 22:53:04 +0900 Subject: ALSA: seq: remove redundant 'tristate' for SND_SEQ_UMP_CLIENT 'def_tristate' is a shorthand for 'default' + 'tristate'. Another 'tristate' is redundant. Signed-off-by: Masahiro Yamada Link: https://lore.kernel.org/r/20240215135304.1909431-1-masahiroy@kernel.org Signed-off-by: Takashi Iwai --- sound/core/seq/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/core/seq/Kconfig b/sound/core/seq/Kconfig index c14981daf9432..0374bbf51cd4d 100644 --- a/sound/core/seq/Kconfig +++ b/sound/core/seq/Kconfig @@ -71,7 +71,6 @@ config SND_SEQ_UMP among legacy and UMP clients. config SND_SEQ_UMP_CLIENT - tristate def_tristate SND_UMP endif # SND_SEQUENCER -- cgit 1.2.3-korg From ff16cbc4dc3494d02e625c76342bcdea54cfb9a4 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 16 Feb 2024 14:02:04 +0100 Subject: ALSA: avoid 'bool' as variable name In modern C versions, 'bool' is a keyword that cannot be used as a variable name, so change this instance use something else, and change the type to bool instead. Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20240216130211.3828455-1-arnd@kernel.org Signed-off-by: Takashi Iwai --- sound/core/seq/oss/seq_oss_device.h | 2 +- sound/core/seq/oss/seq_oss_init.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/core/seq/oss/seq_oss_device.h b/sound/core/seq/oss/seq_oss_device.h index 6c2c4fb9b7537..f0e964b19af7a 100644 --- a/sound/core/seq/oss/seq_oss_device.h +++ b/sound/core/seq/oss/seq_oss_device.h @@ -163,6 +163,6 @@ snd_seq_oss_fill_addr(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, /* misc. functions for proc interface */ -char *enabled_str(int bool); +char *enabled_str(bool b); #endif /* __SEQ_OSS_DEVICE_H */ diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c index 42d4e7535a820..76bf41c26acda 100644 --- a/sound/core/seq/oss/seq_oss_init.c +++ b/sound/core/seq/oss/seq_oss_init.c @@ -455,9 +455,9 @@ snd_seq_oss_reset(struct seq_oss_devinfo *dp) * misc. functions for proc interface */ char * -enabled_str(int bool) +enabled_str(bool b) { - return bool ? "enabled" : "disabled"; + return b ? "enabled" : "disabled"; } static const char * -- cgit 1.2.3-korg From ba00e413fa1515e4d0890803c01ebc555f500f15 Mon Sep 17 00:00:00 2001 From: Aiswarya Cyriac Date: Fri, 16 Feb 2024 11:06:43 +0100 Subject: ALSA: virtio: Fix "Coverity: virtsnd_kctl_tlv_op(): Uninitialized variables" warning. This commit fixes the following warning when building virtio_snd driver. " *** CID 1583619: Uninitialized variables (UNINIT) sound/virtio/virtio_kctl.c:294 in virtsnd_kctl_tlv_op() 288 289 break; 290 } 291 292 kfree(tlv); 293 vvv CID 1583619: Uninitialized variables (UNINIT) vvv Using uninitialized value "rc". 294 return rc; 295 } 296 297 /** 298 * virtsnd_kctl_get_enum_items() - Query items for the ENUMERATED element type. 299 * @snd: VirtIO sound device. " This warning is caused by the absence of the "default" branch in the switch-block, and is a false positive because the kernel calls virtsnd_kctl_tlv_op() only with values for op_flag processed in this block. Also, this commit unifies the cleanup path for all possible control paths in the callback function. Signed-off-by: Anton Yakovlev Signed-off-by: Aiswarya Cyriac Reported-by: coverity-bot Addresses-Coverity-ID: 1583619 ("Uninitialized variables") Fixes: d6568e3de42d ("ALSA: virtio: add support for audio controls") Acked-by: Michael S. Tsirkin Link: https://lore.kernel.org/r/20240216100643.688590-1-aiswarya.cyriac@opensynergy.com Signed-off-by: Takashi Iwai --- sound/virtio/virtio_kctl.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/virtio/virtio_kctl.c b/sound/virtio/virtio_kctl.c index 0c6ac74aca1ea..7aa79c05b4648 100644 --- a/sound/virtio/virtio_kctl.c +++ b/sound/virtio/virtio_kctl.c @@ -253,8 +253,8 @@ static int virtsnd_kctl_tlv_op(struct snd_kcontrol *kcontrol, int op_flag, tlv = kzalloc(size, GFP_KERNEL); if (!tlv) { - virtsnd_ctl_msg_unref(msg); - return -ENOMEM; + rc = -ENOMEM; + goto on_msg_unref; } sg_init_one(&sg, tlv, size); @@ -281,14 +281,25 @@ static int virtsnd_kctl_tlv_op(struct snd_kcontrol *kcontrol, int op_flag, hdr->hdr.code = cpu_to_le32(VIRTIO_SND_R_CTL_TLV_COMMAND); - if (copy_from_user(tlv, utlv, size)) + if (copy_from_user(tlv, utlv, size)) { rc = -EFAULT; - else + goto on_msg_unref; + } else { rc = virtsnd_ctl_msg_send(snd, msg, &sg, NULL, false); + } break; + default: + rc = -EINVAL; + /* We never get here - we listed all values for op_flag */ + WARN_ON(1); + goto on_msg_unref; } + kfree(tlv); + return rc; +on_msg_unref: + virtsnd_ctl_msg_unref(msg); kfree(tlv); return rc; -- cgit 1.2.3-korg From e8991d1d6498f663889e99ea7fd3cb9c464cebf1 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Sat, 17 Feb 2024 11:42:38 +0100 Subject: ALSA: core: fix buffer overflow in test_format_fill_silence() KASAN caught a buffer overflow with the hardcoded 2048 byte buffer size, when 2080 bytes are written to it: BUG: KASAN: slab-out-of-bounds in snd_pcm_format_set_silence+0x3bc/0x3e4 Write of size 8 at addr ffff0000c8149800 by task kunit_try_catch/1297 CPU: 0 PID: 1297 Comm: kunit_try_catch Tainted: G N 6.8.0-rc4-next-20240216 #1 Hardware name: linux,dummy-virt (DT) Call trace: kasan_report+0x78/0xc0 __asan_report_store_n_noabort+0x1c/0x28 snd_pcm_format_set_silence+0x3bc/0x3e4 _test_fill_silence+0xdc/0x298 test_format_fill_silence+0x110/0x228 kunit_try_run_case+0x144/0x3bc kunit_generic_run_threadfn_adapter+0x50/0x94 kthread+0x330/0x3e8 ret_from_fork+0x10/0x20 Allocated by task 1297: __kmalloc+0x17c/0x2f0 kunit_kmalloc_array+0x2c/0x78 test_format_fill_silence+0xcc/0x228 kunit_try_run_case+0x144/0x3bc kunit_generic_run_threadfn_adapter+0x50/0x94 kthread+0x330/0x3e8 ret_from_fork+0x10/0x20 Replace the incorrect size with the correct length of 260 64-bit samples. Reported-by: Naresh Kamboju Suggested-by: Ivan Orlov Fixes: 3e39acf56ede ("ALSA: core: Add sound core KUnit test") Signed-off-by: Arnd Bergmann Tested-by: Linux Kernel Functional Testing Acked-by: Ivan Orlov Link: https://lore.kernel.org/r/20240217104311.3749655-1-arnd@kernel.org Signed-off-by: Takashi Iwai --- sound/core/sound_kunit.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/core/sound_kunit.c b/sound/core/sound_kunit.c index 5d5a7bf88de4f..4212c4a20697d 100644 --- a/sound/core/sound_kunit.c +++ b/sound/core/sound_kunit.c @@ -8,7 +8,8 @@ #include #include -#define SILENCE_BUFFER_SIZE 2048 +#define SILENCE_BUFFER_MAX_FRAMES 260 +#define SILENCE_BUFFER_SIZE (sizeof(u64) * SILENCE_BUFFER_MAX_FRAMES) #define SILENCE(...) { __VA_ARGS__ } #define DEFINE_FORMAT(fmt, pbits, wd, endianness, signd, silence_arr) { \ .format = SNDRV_PCM_FORMAT_##fmt, .physical_bits = pbits, \ @@ -165,7 +166,7 @@ static void _test_fill_silence(struct kunit *test, struct snd_format_test_data * static void test_format_fill_silence(struct kunit *test) { - u32 buf_samples[] = { 10, 20, 32, 64, 129, 260 }; + u32 buf_samples[] = { 10, 20, 32, 64, 129, SILENCE_BUFFER_MAX_FRAMES }; u8 *buffer; u32 i, j; -- cgit 1.2.3-korg From 5c0a35b26f3b7b260475bd0e62261584aab8e486 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 18 Feb 2024 16:41:25 +0900 Subject: ALSA: oxfw: use const qualifier for immutable argument In the helper function, the first argument is immutable, thus it is preferable to use const qualifier. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20240218074128.95210-2-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/oxfw-stream.c | 2 +- sound/firewire/oxfw/oxfw.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index f4a702def3979..6d8722f9d3a58 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -515,7 +515,7 @@ end: * in AV/C Stream Format Information Specification 1.1 (Apr 2005, 1394TA) * Also 'Clause 12 AM824 sequence adaption layers' in IEC 61883-6:2005 */ -int snd_oxfw_stream_parse_format(u8 *format, +int snd_oxfw_stream_parse_format(const u8 *format, struct snd_oxfw_stream_formation *formation) { unsigned int i, e, channels, type; diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index d728e451a25c6..39316aeafeaa4 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -136,7 +136,7 @@ struct snd_oxfw_stream_formation { unsigned int pcm; unsigned int midi; }; -int snd_oxfw_stream_parse_format(u8 *format, +int snd_oxfw_stream_parse_format(const u8 *format, struct snd_oxfw_stream_formation *formation); int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir, -- cgit 1.2.3-korg From 25ab2b2f6ac209a3746eec42210a98fe047a7453 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 18 Feb 2024 16:41:26 +0900 Subject: ALSA: oxfw: support the case that AV/C Stream Format Information command is not available Miglia Harmony Audio does neither support AV/C Stream Format Information command nor AV/C Extended Stream Format Information command. This commit adds a workaround for the case and uses the hard-coded formats. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20240218074128.95210-3-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/oxfw-stream.c | 96 +++++++++++++++++++++++++++++---------- sound/firewire/oxfw/oxfw.h | 2 + 2 files changed, 75 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index 6d8722f9d3a58..40716bb989c7f 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -486,26 +486,57 @@ int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir, struct snd_oxfw_stream_formation *formation) { - u8 *format; - unsigned int len; int err; - len = AVC_GENERIC_FRAME_MAXIMUM_BYTES; - format = kmalloc(len, GFP_KERNEL); - if (format == NULL) - return -ENOMEM; + if (!(oxfw->quirks & SND_OXFW_QUIRK_STREAM_FORMAT_INFO_UNSUPPORTED)) { + u8 *format; + unsigned int len; - err = avc_stream_get_format_single(oxfw->unit, dir, 0, format, &len); - if (err < 0) - goto end; - if (len < 3) { - err = -EIO; - goto end; + len = AVC_GENERIC_FRAME_MAXIMUM_BYTES; + format = kmalloc(len, GFP_KERNEL); + if (format == NULL) + return -ENOMEM; + + err = avc_stream_get_format_single(oxfw->unit, dir, 0, format, &len); + if (err >= 0) { + if (len < 3) + err = -EIO; + else + err = snd_oxfw_stream_parse_format(format, formation); + } + + kfree(format); + } else { + // Miglia Harmony Audio does not support Extended Stream Format Information + // command. Use the duplicated hard-coded format, instead. + unsigned int rate; + u8 *const *formats; + int i; + + err = avc_general_get_sig_fmt(oxfw->unit, &rate, dir, 0); + if (err < 0) + return err; + + if (dir == AVC_GENERAL_PLUG_DIR_IN) + formats = oxfw->rx_stream_formats; + else + formats = oxfw->tx_stream_formats; + + for (i = 0; (i < SND_OXFW_STREAM_FORMAT_ENTRIES); ++i) { + if (!formats[i]) + continue; + + err = snd_oxfw_stream_parse_format(formats[i], formation); + if (err < 0) + continue; + + if (formation->rate == rate) + break; + } + if (i == SND_OXFW_STREAM_FORMAT_ENTRIES) + return -EIO; } - err = snd_oxfw_stream_parse_format(format, formation); -end: - kfree(format); return err; } @@ -600,14 +631,33 @@ assume_stream_formats(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir, unsigned int i, eid; int err; - /* get format at current sampling rate */ - err = avc_stream_get_format_single(oxfw->unit, dir, pid, buf, len); - if (err < 0) { - dev_err(&oxfw->unit->device, - "fail to get current stream format for isoc %s plug %d:%d\n", - (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out", - pid, err); - goto end; + // get format at current sampling rate. + if (!(oxfw->quirks & SND_OXFW_QUIRK_STREAM_FORMAT_INFO_UNSUPPORTED)) { + err = avc_stream_get_format_single(oxfw->unit, dir, pid, buf, len); + if (err < 0) { + dev_err(&oxfw->unit->device, + "fail to get current stream format for isoc %s plug %d:%d\n", + (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out", + pid, err); + goto end; + } + } else { + // Miglia Harmony Audio does not support Extended Stream Format Information + // command. Use the hard-coded format, instead. + buf[0] = 0x90; + buf[1] = 0x40; + buf[2] = avc_stream_rate_table[0]; + buf[3] = 0x00; + buf[4] = 0x01; + + if (dir == AVC_GENERAL_PLUG_DIR_IN) + buf[5] = 0x08; + else + buf[5] = 0x02; + + buf[6] = 0x06; + + *len = 7; } /* parse and set stream format */ diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index 39316aeafeaa4..3bf8d7bec6369 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -52,6 +52,8 @@ enum snd_oxfw_quirk { // performs media clock recovery voluntarily. In the recovery, the packets with NO_INFO // are ignored, thus driver should transfer packets with timestamp. SND_OXFW_QUIRK_VOLUNTARY_RECOVERY = 0x20, + // Miglia Harmony Audio does not support AV/C Stream Format Information command. + SND_OXFW_QUIRK_STREAM_FORMAT_INFO_UNSUPPORTED = 0x40, }; /* This is an arbitrary number for convinience. */ -- cgit 1.2.3-korg From 4a486439d2ca85752c46711f373b6ddc107bb35d Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 18 Feb 2024 16:41:27 +0900 Subject: ALSA: firewire-lib: handle quirk to calculate payload quadlets as data block counter Miglia Harmony Audio (OXFW970) has a quirk to put the number of accumulated quadlets in CIP payload into the dbc field of CIP header. This commit handles the quirk in the packet processing layer. Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20240218074128.95210-4-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/amdtp-stream.c | 12 ++++++++---- sound/firewire/amdtp-stream.h | 4 ++++ 2 files changed, 12 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index a13c0b408aadf..9d5a025d2e967 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -773,10 +773,14 @@ static int check_cip_header(struct amdtp_stream *s, const __be32 *buf, } else { unsigned int dbc_interval; - if (*data_blocks > 0 && s->ctx_data.tx.dbc_interval > 0) - dbc_interval = s->ctx_data.tx.dbc_interval; - else - dbc_interval = *data_blocks; + if (!(s->flags & CIP_DBC_IS_PAYLOAD_QUADLETS)) { + if (*data_blocks > 0 && s->ctx_data.tx.dbc_interval > 0) + dbc_interval = s->ctx_data.tx.dbc_interval; + else + dbc_interval = *data_blocks; + } else { + dbc_interval = payload_length / sizeof(__be32); + } lost = dbc != ((*data_block_counter + dbc_interval) & 0xff); } diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index b7ff44751ab93..a1ed2e80f91a7 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -37,6 +37,9 @@ * the value of current SYT_INTERVAL; e.g. initial value is not zero. * @CIP_UNAWARE_SYT: For outgoing packet, the value in SYT field of CIP is 0xffff. * For incoming packet, the value in SYT field of CIP is not handled. + * @CIP_DBC_IS_PAYLOAD_QUADLETS: Available for incoming packet, and only effective with + * CIP_DBC_IS_END_EVENT flag. The value of dbc field is the number of accumulated quadlets + * in CIP payload, instead of the number of accumulated data blocks. */ enum cip_flags { CIP_NONBLOCKING = 0x00, @@ -51,6 +54,7 @@ enum cip_flags { CIP_NO_HEADER = 0x100, CIP_UNALIGHED_DBC = 0x200, CIP_UNAWARE_SYT = 0x400, + CIP_DBC_IS_PAYLOAD_QUADLETS = 0x800, }; /** -- cgit 1.2.3-korg From 52592932405cecaaa0f4b8cb41128d014b96858c Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 18 Feb 2024 16:41:28 +0900 Subject: ALSA: oxfw: add support for Miglia Harmony Audio Miglia Technology ships Harmony Audio 2004. It uses Oxford Semiconductor OXFW970 for communication function in IEEE 1394 bus. This commit adds support for the model. In my opinion, the firmware of ASIC is really the initial stage, since it has the following quirks. * It skips several isochronous cycles to transmit isochronous packets when receiving any asynchronous transaction. * The value of dbc field in the transmitted packet is the number of accumulated quadlets in CIP payload, instead of the accumulated data blocks. Furthermore, the value includes the quadlets of CIP payload in the packet. * It neither supports AV/C Stream Format Information command nor AV/C Extended Stream Format Information command. * The vendor and model information in root directory of configuration ROM includes some mistakes. Additionally, when operating at 96.0 kHz, it often skips much isochronous cycles to transmit the isochronous packets. The issue is detected as cycle discontinuity and ALSA PCM application receives -EIO at any operation for PCM substream. I have never found any workaround yet. $ config-rom-pretty-printer < /sys/bus/firewire/devices/fw1/config_rom ROM header and bus information block ----------------------------------------------------------------- 1024 04249e04 bus_info_length 4, crc_length 36, crc 40452 1028 31333934 bus_name "1394" 1032 20ff5003 irmc 0, cmc 0, isc 1, bmc 0, cyc_clk_acc 255, max_rec 5 (64) 1036 0030e002 company_id 0030e0 | 1040 00454647 device_id 8594474567 | EUI-64 13757098081207879 root directory ----------------------------------------------------------------- 1044 00062d69 directory_length 6, crc 11625 1048 030030e0 vendor 1052 8100000a --> descriptor leaf at 1092 1056 1700f970 model 1060 81000011 --> descriptor leaf at 1128 1064 0c0083c0 node capabilities: per IEEE 1394 1068 d1000001 --> unit directory at 1072 unit directory at 1072 ----------------------------------------------------------------- 1072 00046ff9 directory_length 4, crc 28665 (should be 43676) 1076 1200a02d specifier id 1080 13010001 version 1084 1700f970 model 1088 8100000f --> descriptor leaf at 1148 descriptor leaf at 1092 ----------------------------------------------------------------- 1092 00085f8a leaf_length 8, crc 24458 1096 00000000 textual descriptor 1100 00000000 minimal ASCII 1104 4d69676c "Migl" 1108 69612054 "ia T" 1112 6563686e "echn" 1116 6f6c6f67 "olog" 1120 79204c74 "y Lt" 1124 642e0000 "d." descriptor leaf at 1128 ----------------------------------------------------------------- 1128 00040514 leaf_length 4, crc 1300 1132 00000000 textual descriptor 1136 00000000 minimal ASCII 1140 4f584657 "OXFW" 1144 20393730 " 970" descriptor leaf at 1148 ----------------------------------------------------------------- 1148 0005a1dc leaf_length 5, crc 41436 1152 00000000 textual descriptor 1156 00000000 minimal ASCII 1160 4861726d "Harm" 1164 6f6e7941 "onyA" 1168 7564696f "udio" Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20240218074128.95210-5-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai --- sound/firewire/oxfw/oxfw-stream.c | 2 ++ sound/firewire/oxfw/oxfw.c | 10 +++++++++- sound/firewire/oxfw/oxfw.h | 3 +++ 3 files changed, 14 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index 40716bb989c7f..00f7feb91f929 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -177,6 +177,8 @@ static int init_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream) flags |= CIP_JUMBO_PAYLOAD; if (oxfw->quirks & SND_OXFW_QUIRK_WRONG_DBS) flags |= CIP_WRONG_DBS; + if (oxfw->quirks & SND_OXFW_QUIRK_DBC_IS_TOTAL_PAYLOAD_QUADLETS) + flags |= CIP_DBC_IS_END_EVENT | CIP_DBC_IS_PAYLOAD_QUADLETS; } else { conn = &oxfw->in_conn; c_dir = CMP_INPUT; diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 241a697ce26b2..98ae0e8cba879 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -21,6 +21,7 @@ #define VENDOR_TASCAM 0x00022e #define OUI_STANTON 0x001260 #define OUI_APOGEE 0x0003db +#define OUI_OXFORD 0x0030e0 #define MODEL_SATELLITE 0x00200f #define MODEL_SCS1M 0x001000 @@ -232,6 +233,11 @@ static int oxfw_probe(struct fw_unit *unit, const struct ieee1394_device_id *ent if (err < 0) goto error; + if (entry->vendor_id == OUI_OXFORD && entry->model_id == 0x00f970) { + oxfw->quirks |= SND_OXFW_QUIRK_STREAM_FORMAT_INFO_UNSUPPORTED | + SND_OXFW_QUIRK_DBC_IS_TOTAL_PAYLOAD_QUADLETS; + } + err = snd_oxfw_stream_discover(oxfw); if (err < 0) goto error; @@ -330,6 +336,9 @@ static const struct ieee1394_device_id oxfw_id_table[] = { // OXFW_DEV_ENTRY(VENDOR_GRIFFIN, 0x00f970, &griffin_firewave), OXFW_DEV_ENTRY(VENDOR_LACIE, 0x00f970, &lacie_speakers), + // Miglia HarmonyAudio (HA02). The numeric vendor ID is ASIC vendor and the model ID is the + // default value of ASIC. + OXFW_DEV_ENTRY(OUI_OXFORD, 0x00f970, NULL), // Behringer,F-Control Audio 202. The value of SYT field is not reliable at all. OXFW_DEV_ENTRY(VENDOR_BEHRINGER, 0x00fc22, NULL), // Loud Technologies, Tapco Link.FireWire 4x6. The value of SYT field is always 0xffff. @@ -337,7 +346,6 @@ static const struct ieee1394_device_id oxfw_id_table[] = { // Loud Technologies, Mackie Onyx Satellite. Although revised version of firmware is // installed to avoid the postpone, the value of SYT field is always 0xffff. OXFW_DEV_ENTRY(VENDOR_LOUD, MODEL_SATELLITE, NULL), - // Miglia HarmonyAudio. Not yet identified. // // OXFW971 devices: diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index 3bf8d7bec6369..39ea9a6dde33a 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -54,6 +54,9 @@ enum snd_oxfw_quirk { SND_OXFW_QUIRK_VOLUNTARY_RECOVERY = 0x20, // Miglia Harmony Audio does not support AV/C Stream Format Information command. SND_OXFW_QUIRK_STREAM_FORMAT_INFO_UNSUPPORTED = 0x40, + // Miglia Harmony Audio transmits CIP in which the value of dbc field expresses the number + // of accumulated payload quadlets including the packet. + SND_OXFW_QUIRK_DBC_IS_TOTAL_PAYLOAD_QUADLETS = 0x80, }; /* This is an arbitrary number for convinience. */ -- cgit 1.2.3-korg From 04438a06c43d09486e4323928b3bb93bd7407488 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 21 Feb 2024 11:06:06 +0100 Subject: ALSA: hda: Set up BDL table at hw_params So far the setup of BDL table is performed at the prepare stage, where all PCM parameters have been already set up. When something wrong happens at it, we return -EINVAL; it's supposed to be a rare case since the involved memory allocation is a small chunk of kmalloc for the table. However, when we receive too many small non-contiguous pages in highly fragmented memories, it may overflow the max table size, resulting in the same -EINVAL error from the prepare, too. A bad scenario is that user-space cannot know what went wrong (as it's an error from the prepare stage) and -EINVAL, hence it may retry with the same parameters, failing again repeatedly. In this patch, we try to set up the BDL table at hw_params right after the buffer allocation, and return -ENOMEM if it overflows. This allows user-space knowing that it should reduce the buffer size request accordingly and may retry with more fitting parameters. Link: https://lore.kernel.org/r/20240221100607.6565-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_controller.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 3e7bfeee84fda..29eae7244fe73 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -24,6 +24,7 @@ #include #include +#include #include "hda_controller.h" #include "hda_local.h" @@ -108,6 +109,7 @@ static int azx_pcm_hw_params(struct snd_pcm_substream *substream, struct azx_pcm *apcm = snd_pcm_substream_chip(substream); struct azx *chip = apcm->chip; struct azx_dev *azx_dev = get_azx_dev(substream); + struct hdac_stream *hdas = azx_stream(azx_dev); int ret = 0; trace_azx_pcm_hw_params(chip, azx_dev); @@ -117,9 +119,15 @@ static int azx_pcm_hw_params(struct snd_pcm_substream *substream, goto unlock; } - azx_dev->core.bufsize = 0; - azx_dev->core.period_bytes = 0; - azx_dev->core.format_val = 0; + /* Set up BDLEs here, return -ENOMEM if too many BDLEs are required */ + hdas->bufsize = params_buffer_bytes(hw_params); + hdas->period_bytes = params_period_bytes(hw_params); + hdas->format_val = 0; + hdas->no_period_wakeup = + (hw_params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) && + (hw_params->flags & SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP); + if (snd_hdac_stream_setup_periods(hdas) < 0) + ret = -ENOMEM; unlock: dsp_unlock(azx_dev); -- cgit 1.2.3-korg From 5f91a62217730910ceb3e712dd0c28ee71423a27 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 21 Feb 2024 11:06:07 +0100 Subject: ALSA: hda: Downgrade BDL table overflow message When BDL table entry overflow happens, the driver spews an error message explicitly. But basically this condition can be triggered easily by an application and it may flood of error logs unnecessarily. Downgrade the error message with dev_dbg() as a debug message instead. Link: https://lore.kernel.org/r/20240221100607.6565-2-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/hda/hdac_stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c index 610ea7a33cd85..b53de020309f2 100644 --- a/sound/hda/hdac_stream.c +++ b/sound/hda/hdac_stream.c @@ -567,7 +567,7 @@ int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev) return 0; error: - dev_err(bus->dev, "Too many BDL entries: buffer=%d, period=%d\n", + dev_dbg(bus->dev, "Too many BDL entries: buffer=%d, period=%d\n", azx_dev->bufsize, period_bytes); return -EINVAL; } -- cgit 1.2.3-korg From 372709508b847e7df3bbe2c52ab4c783bbce738f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 21 Feb 2024 11:38:09 +0000 Subject: ALSA: echoaudio: remove redundant assignment to variable clock The variable clock is being assigned a value that is never read, it is being re-assigned a new value in every case in the following switch statement. The assignment is redundant and can be removed. Cleans up clang scan build warning: sound/pci/echoaudio/echoaudio_3g.c:277:2: warning: Value stored to 'clock' is never read [deadcode.DeadStores] Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20240221113809.3410109-1-colin.i.king@gmail.com Signed-off-by: Takashi Iwai --- sound/pci/echoaudio/echoaudio_3g.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/echoaudio/echoaudio_3g.c b/sound/pci/echoaudio/echoaudio_3g.c index cc3c79387194f..18b4d4b4d38df 100644 --- a/sound/pci/echoaudio/echoaudio_3g.c +++ b/sound/pci/echoaudio/echoaudio_3g.c @@ -274,7 +274,6 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate) chip->digital_mode == DIGITAL_MODE_ADAT)) return -EINVAL; - clock = 0; control_reg = le32_to_cpu(chip->comm_page->control_register); control_reg &= E3G_CLOCK_CLEAR_MASK; -- cgit 1.2.3-korg From bc80e83ebbb274fcd40b17dd8c4f8a6b74808feb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 22 Feb 2024 16:31:48 +0100 Subject: ALSA: hda: beep: Drop stale mutex The beep->mutex is no longer used since the drop of beep_mode=2. Let's get rid of it. Fixes: 0920c9b4c4d8 ("ALSA: hda - Remove beep_mode=2") Link: https://lore.kernel.org/r/20240222153148.19691-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_beep.c | 1 - sound/pci/hda/hda_beep.h | 1 - 2 files changed, 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index e63621bcb2142..e51d475725576 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -231,7 +231,6 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) codec->beep = beep; INIT_WORK(&beep->beep_work, &snd_hda_generate_beep); - mutex_init(&beep->mutex); input_dev = input_allocate_device(); if (!input_dev) { diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h index db76e3ddba654..923ea862446a0 100644 --- a/sound/pci/hda/hda_beep.h +++ b/sound/pci/hda/hda_beep.h @@ -27,7 +27,6 @@ struct hda_beep { unsigned int playing:1; unsigned int keep_power_at_enable:1; /* set by driver */ struct work_struct beep_work; /* scheduled task for beep event */ - struct mutex mutex; void (*power_hook)(struct hda_beep *beep, bool on); }; -- cgit 1.2.3-korg From ec89fc1b71766c9e7a122f8ba7a21933fe6a95b4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 22 Feb 2024 14:21:52 +0100 Subject: ALSA: seq: prioq: Unify cell removal functions Both snd_seq_prioq_remove_events() and snd_seq_prioq_leave() have a very similar loop for removing events. Unify them with a callback for code simplification. Only the code refactoring, and no functional changes. Link: https://lore.kernel.org/r/20240222132152.29063-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/seq/seq_prioq.c | 197 +++++++++++++++++++-------------------------- 1 file changed, 84 insertions(+), 113 deletions(-) (limited to 'sound') diff --git a/sound/core/seq/seq_prioq.c b/sound/core/seq/seq_prioq.c index 1d857981e8764..e062df7610e1d 100644 --- a/sound/core/seq/seq_prioq.c +++ b/sound/core/seq/seq_prioq.c @@ -249,30 +249,11 @@ int snd_seq_prioq_avail(struct snd_seq_prioq * f) return f->cells; } -static inline int prioq_match(struct snd_seq_event_cell *cell, - int client, int timestamp) -{ - if (cell->event.source.client == client || - cell->event.dest.client == client) - return 1; - if (!timestamp) - return 0; - switch (cell->event.flags & SNDRV_SEQ_TIME_STAMP_MASK) { - case SNDRV_SEQ_TIME_STAMP_TICK: - if (cell->event.time.tick) - return 1; - break; - case SNDRV_SEQ_TIME_STAMP_REAL: - if (cell->event.time.time.tv_sec || - cell->event.time.time.tv_nsec) - return 1; - break; - } - return 0; -} - -/* remove cells for left client */ -void snd_seq_prioq_leave(struct snd_seq_prioq * f, int client, int timestamp) +/* remove cells matching with the condition */ +static void prioq_remove_cells(struct snd_seq_prioq *f, + bool (*match)(struct snd_seq_event_cell *cell, + void *arg), + void *arg) { register struct snd_seq_event_cell *cell, *next; unsigned long flags; @@ -281,39 +262,29 @@ void snd_seq_prioq_leave(struct snd_seq_prioq * f, int client, int timestamp) /* collect all removed cells */ spin_lock_irqsave(&f->lock, flags); - cell = f->head; - while (cell) { + for (cell = f->head; cell; cell = next) { next = cell->next; - if (prioq_match(cell, client, timestamp)) { - /* remove cell from prioq */ - if (cell == f->head) { - f->head = cell->next; - } else { - prev->next = cell->next; - } - if (cell == f->tail) - f->tail = cell->next; - f->cells--; - /* add cell to free list */ - cell->next = NULL; - if (freefirst == NULL) { - freefirst = cell; - } else { - freeprev->next = cell; - } - freeprev = cell; - } else { -#if 0 - pr_debug("ALSA: seq: type = %i, source = %i, dest = %i, " - "client = %i\n", - cell->event.type, - cell->event.source.client, - cell->event.dest.client, - client); -#endif + if (!match(cell, arg)) { prev = cell; + continue; } - cell = next; + + /* remove cell from prioq */ + if (cell == f->head) + f->head = cell->next; + else + prev->next = cell->next; + if (cell == f->tail) + f->tail = cell->next; + f->cells--; + + /* add cell to free list */ + cell->next = NULL; + if (freefirst == NULL) + freefirst = cell; + else + freeprev->next = cell; + freeprev = cell; } spin_unlock_irqrestore(&f->lock, flags); @@ -325,22 +296,68 @@ void snd_seq_prioq_leave(struct snd_seq_prioq * f, int client, int timestamp) } } -static int prioq_remove_match(struct snd_seq_remove_events *info, - struct snd_seq_event *ev) +struct prioq_match_arg { + int client; + int timestamp; +}; + +static inline bool prioq_match(struct snd_seq_event_cell *cell, void *arg) +{ + struct prioq_match_arg *v = arg; + + if (cell->event.source.client == v->client || + cell->event.dest.client == v->client) + return true; + if (!v->timestamp) + return false; + switch (cell->event.flags & SNDRV_SEQ_TIME_STAMP_MASK) { + case SNDRV_SEQ_TIME_STAMP_TICK: + if (cell->event.time.tick) + return true; + break; + case SNDRV_SEQ_TIME_STAMP_REAL: + if (cell->event.time.time.tv_sec || + cell->event.time.time.tv_nsec) + return true; + break; + } + return false; +} + +/* remove cells for left client */ +void snd_seq_prioq_leave(struct snd_seq_prioq *f, int client, int timestamp) { + struct prioq_match_arg arg = { client, timestamp }; + + return prioq_remove_cells(f, prioq_match, &arg); +} + +struct prioq_remove_match_arg { + int client; + struct snd_seq_remove_events *info; +}; + +static bool prioq_remove_match(struct snd_seq_event_cell *cell, void *arg) +{ + struct prioq_remove_match_arg *v = arg; + struct snd_seq_event *ev = &cell->event; + struct snd_seq_remove_events *info = v->info; int res; + if (ev->source.client != v->client) + return false; + if (info->remove_mode & SNDRV_SEQ_REMOVE_DEST) { if (ev->dest.client != info->dest.client || ev->dest.port != info->dest.port) - return 0; + return false; } if (info->remove_mode & SNDRV_SEQ_REMOVE_DEST_CHANNEL) { if (! snd_seq_ev_is_channel_type(ev)) - return 0; + return false; /* data.note.channel and data.control.channel are identical */ if (ev->data.note.channel != info->channel) - return 0; + return false; } if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_AFTER) { if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_TICK) @@ -348,7 +365,7 @@ static int prioq_remove_match(struct snd_seq_remove_events *info, else res = snd_seq_compare_real_time(&ev->time.time, &info->time.time); if (!res) - return 0; + return false; } if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_BEFORE) { if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_TICK) @@ -356,81 +373,35 @@ static int prioq_remove_match(struct snd_seq_remove_events *info, else res = snd_seq_compare_real_time(&ev->time.time, &info->time.time); if (res) - return 0; + return false; } if (info->remove_mode & SNDRV_SEQ_REMOVE_EVENT_TYPE) { if (ev->type != info->type) - return 0; + return false; } if (info->remove_mode & SNDRV_SEQ_REMOVE_IGNORE_OFF) { /* Do not remove off events */ switch (ev->type) { case SNDRV_SEQ_EVENT_NOTEOFF: /* case SNDRV_SEQ_EVENT_SAMPLE_STOP: */ - return 0; + return false; default: break; } } if (info->remove_mode & SNDRV_SEQ_REMOVE_TAG_MATCH) { if (info->tag != ev->tag) - return 0; + return false; } - return 1; + return true; } /* remove cells matching remove criteria */ void snd_seq_prioq_remove_events(struct snd_seq_prioq * f, int client, struct snd_seq_remove_events *info) { - struct snd_seq_event_cell *cell, *next; - unsigned long flags; - struct snd_seq_event_cell *prev = NULL; - struct snd_seq_event_cell *freefirst = NULL, *freeprev = NULL, *freenext; + struct prioq_remove_match_arg arg = { client, info }; - /* collect all removed cells */ - spin_lock_irqsave(&f->lock, flags); - cell = f->head; - - while (cell) { - next = cell->next; - if (cell->event.source.client == client && - prioq_remove_match(info, &cell->event)) { - - /* remove cell from prioq */ - if (cell == f->head) { - f->head = cell->next; - } else { - prev->next = cell->next; - } - - if (cell == f->tail) - f->tail = cell->next; - f->cells--; - - /* add cell to free list */ - cell->next = NULL; - if (freefirst == NULL) { - freefirst = cell; - } else { - freeprev->next = cell; - } - - freeprev = cell; - } else { - prev = cell; - } - cell = next; - } - spin_unlock_irqrestore(&f->lock, flags); - - /* remove selected cells */ - while (freefirst) { - freenext = freefirst->next; - snd_seq_cell_free(freefirst); - freefirst = freenext; - } + return prioq_remove_cells(f, prioq_remove_match, &arg); } - - -- cgit 1.2.3-korg From ae921398486419c6284d70bd8332eb7edbdb4f70 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 22 Feb 2024 12:15:01 +0100 Subject: ALSA: pcm: Use automatic cleanup of kfree() There are common patterns where a temporary buffer is allocated and freed at the exit, and those can be simplified with the recent cleanup mechanism via __free(kfree). A caveat is that some allocations are memdup_user() and they return an error pointer instead of NULL. Those need special cares and the value has to be cleared with no_free_ptr() at the allocation error path. Other than that, the conversions are straightforward. No functional changes, only code refactoring. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240222111509.28390-2-tiwai@suse.de --- sound/core/pcm.c | 4 +- sound/core/pcm_compat.c | 29 +++++---------- sound/core/pcm_native.c | 99 +++++++++++++++++++------------------------------ 3 files changed, 49 insertions(+), 83 deletions(-) (limited to 'sound') diff --git a/sound/core/pcm.c b/sound/core/pcm.c index d9b338088d104..87d27fbdfe5c8 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -342,7 +342,7 @@ static const char *snd_pcm_oss_format_name(int format) static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream, struct snd_info_buffer *buffer) { - struct snd_pcm_info *info; + struct snd_pcm_info *info __free(kfree) = NULL; int err; if (! substream) @@ -355,7 +355,6 @@ static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream, err = snd_pcm_info(substream, info); if (err < 0) { snd_iprintf(buffer, "error %d\n", err); - kfree(info); return; } snd_iprintf(buffer, "card: %d\n", info->card); @@ -369,7 +368,6 @@ static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream, snd_iprintf(buffer, "subclass: %d\n", info->dev_subclass); snd_iprintf(buffer, "subdevices_count: %d\n", info->subdevices_count); snd_iprintf(buffer, "subdevices_avail: %d\n", info->subdevices_avail); - kfree(info); } static void snd_pcm_stream_proc_info_read(struct snd_info_entry *entry, diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index c96483091f30a..ef3c0d1775104 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c @@ -235,7 +235,7 @@ static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream, int refine, struct snd_pcm_hw_params32 __user *data32) { - struct snd_pcm_hw_params *data; + struct snd_pcm_hw_params *data __free(kfree) = NULL; struct snd_pcm_runtime *runtime; int err; @@ -248,34 +248,28 @@ static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream, return -ENOMEM; /* only fifo_size (RO from userspace) is different, so just copy all */ - if (copy_from_user(data, data32, sizeof(*data32))) { - err = -EFAULT; - goto error; - } + if (copy_from_user(data, data32, sizeof(*data32))) + return -EFAULT; if (refine) { err = snd_pcm_hw_refine(substream, data); if (err < 0) - goto error; + return err; err = fixup_unreferenced_params(substream, data); } else { err = snd_pcm_hw_params(substream, data); } if (err < 0) - goto error; + return err; if (copy_to_user(data32, data, sizeof(*data32)) || - put_user(data->fifo_size, &data32->fifo_size)) { - err = -EFAULT; - goto error; - } + put_user(data->fifo_size, &data32->fifo_size)) + return -EFAULT; if (! refine) { unsigned int new_boundary = recalculate_boundary(runtime); if (new_boundary) runtime->boundary = new_boundary; } - error: - kfree(data); return err; } @@ -338,7 +332,7 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream, compat_caddr_t buf; compat_caddr_t __user *bufptr; u32 frames; - void __user **bufs; + void __user **bufs __free(kfree) = NULL; int err, ch, i; if (! substream->runtime) @@ -360,10 +354,8 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream, return -ENOMEM; for (i = 0; i < ch; i++) { u32 ptr; - if (get_user(ptr, bufptr)) { - kfree(bufs); + if (get_user(ptr, bufptr)) return -EFAULT; - } bufs[i] = compat_ptr(ptr); bufptr++; } @@ -373,9 +365,8 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream, err = snd_pcm_lib_readv(substream, bufs, frames); if (err >= 0) { if (put_user(err, &data32->result)) - err = -EFAULT; + return -EFAULT; } - kfree(bufs); return err; } diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index f5ff00f99788a..beee5249dae11 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -236,7 +236,7 @@ int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info) int snd_pcm_info_user(struct snd_pcm_substream *substream, struct snd_pcm_info __user * _info) { - struct snd_pcm_info *info; + struct snd_pcm_info *info __free(kfree) = NULL; int err; info = kmalloc(sizeof(*info), GFP_KERNEL); @@ -247,7 +247,6 @@ int snd_pcm_info_user(struct snd_pcm_substream *substream, if (copy_to_user(_info, info, sizeof(*info))) err = -EFAULT; } - kfree(info); return err; } @@ -359,7 +358,7 @@ static int constrain_params_by_rules(struct snd_pcm_substream *substream, struct snd_pcm_hw_constraints *constrs = &substream->runtime->hw_constraints; unsigned int k; - unsigned int *rstamps; + unsigned int *rstamps __free(kfree) = NULL; unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1]; unsigned int stamp; struct snd_pcm_hw_rule *r; @@ -435,10 +434,8 @@ retry: } changed = r->func(params, r); - if (changed < 0) { - err = changed; - goto out; - } + if (changed < 0) + return changed; /* * When the parameter is changed, notify it to the caller @@ -469,8 +466,6 @@ retry: if (again) goto retry; - out: - kfree(rstamps); return err; } @@ -571,26 +566,24 @@ EXPORT_SYMBOL(snd_pcm_hw_refine); static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream, struct snd_pcm_hw_params __user * _params) { - struct snd_pcm_hw_params *params; + struct snd_pcm_hw_params *params __free(kfree) = NULL; int err; params = memdup_user(_params, sizeof(*params)); if (IS_ERR(params)) - return PTR_ERR(params); + return PTR_ERR(no_free_ptr(params)); err = snd_pcm_hw_refine(substream, params); if (err < 0) - goto end; + return err; err = fixup_unreferenced_params(substream, params); if (err < 0) - goto end; + return err; if (copy_to_user(_params, params, sizeof(*params))) - err = -EFAULT; -end: - kfree(params); - return err; + return -EFAULT; + return 0; } static int period_to_usecs(struct snd_pcm_runtime *runtime) @@ -864,21 +857,19 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream, struct snd_pcm_hw_params __user * _params) { - struct snd_pcm_hw_params *params; + struct snd_pcm_hw_params *params __free(kfree) = NULL; int err; params = memdup_user(_params, sizeof(*params)); if (IS_ERR(params)) - return PTR_ERR(params); + return PTR_ERR(no_free_ptr(params)); err = snd_pcm_hw_params(substream, params); if (err < 0) - goto end; + return err; if (copy_to_user(_params, params, sizeof(*params))) - err = -EFAULT; -end: - kfree(params); + return -EFAULT; return err; } @@ -2271,7 +2262,8 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) int res = 0; struct snd_pcm_file *pcm_file; struct snd_pcm_substream *substream1; - struct snd_pcm_group *group, *target_group; + struct snd_pcm_group *group __free(kfree) = NULL; + struct snd_pcm_group *target_group; bool nonatomic = substream->pcm->nonatomic; struct fd f = fdget(fd); @@ -2281,6 +2273,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) res = -EBADFD; goto _badf; } + pcm_file = f.file->private_data; substream1 = pcm_file->substream; @@ -2292,8 +2285,9 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) group = kzalloc(sizeof(*group), GFP_KERNEL); if (!group) { res = -ENOMEM; - goto _nolock; + goto _badf; } + snd_pcm_group_init(group); down_write(&snd_pcm_link_rwsem); @@ -2324,8 +2318,6 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) snd_pcm_group_unlock_irq(target_group, nonatomic); _end: up_write(&snd_pcm_link_rwsem); - _nolock: - kfree(group); _badf: fdput(f); return res; @@ -3279,7 +3271,7 @@ static int snd_pcm_xfern_frames_ioctl(struct snd_pcm_substream *substream, { struct snd_xfern xfern; struct snd_pcm_runtime *runtime = substream->runtime; - void *bufs; + void *bufs __free(kfree) = NULL; snd_pcm_sframes_t result; if (runtime->state == SNDRV_PCM_STATE_OPEN) @@ -3293,12 +3285,11 @@ static int snd_pcm_xfern_frames_ioctl(struct snd_pcm_substream *substream, bufs = memdup_user(xfern.bufs, sizeof(void *) * runtime->channels); if (IS_ERR(bufs)) - return PTR_ERR(bufs); + return PTR_ERR(no_free_ptr(bufs)); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) result = snd_pcm_lib_writev(substream, bufs, xfern.frames); else result = snd_pcm_lib_readv(substream, bufs, xfern.frames); - kfree(bufs); if (put_user(result, &_xfern->result)) return -EFAULT; return result < 0 ? result : 0; @@ -3566,7 +3557,7 @@ static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to) struct snd_pcm_runtime *runtime; snd_pcm_sframes_t result; unsigned long i; - void __user **bufs; + void __user **bufs __free(kfree) = NULL; snd_pcm_uframes_t frames; const struct iovec *iov = iter_iov(to); @@ -3595,7 +3586,6 @@ static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to) result = snd_pcm_lib_readv(substream, bufs, frames); if (result > 0) result = frames_to_bytes(runtime, result); - kfree(bufs); return result; } @@ -3606,7 +3596,7 @@ static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from) struct snd_pcm_runtime *runtime; snd_pcm_sframes_t result; unsigned long i; - void __user **bufs; + void __user **bufs __free(kfree) = NULL; snd_pcm_uframes_t frames; const struct iovec *iov = iter_iov(from); @@ -3634,7 +3624,6 @@ static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from) result = snd_pcm_lib_writev(substream, bufs, frames); if (result > 0) result = frames_to_bytes(runtime, result); - kfree(bufs); return result; } @@ -4076,8 +4065,8 @@ static void snd_pcm_hw_convert_to_old_params(struct snd_pcm_hw_params_old *opara static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream, struct snd_pcm_hw_params_old __user * _oparams) { - struct snd_pcm_hw_params *params; - struct snd_pcm_hw_params_old *oparams = NULL; + struct snd_pcm_hw_params *params __free(kfree) = NULL; + struct snd_pcm_hw_params_old *oparams __free(kfree) = NULL; int err; params = kmalloc(sizeof(*params), GFP_KERNEL); @@ -4085,34 +4074,28 @@ static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream, return -ENOMEM; oparams = memdup_user(_oparams, sizeof(*oparams)); - if (IS_ERR(oparams)) { - err = PTR_ERR(oparams); - goto out; - } + if (IS_ERR(oparams)) + return PTR_ERR(no_free_ptr(oparams)); snd_pcm_hw_convert_from_old_params(params, oparams); err = snd_pcm_hw_refine(substream, params); if (err < 0) - goto out_old; + return err; err = fixup_unreferenced_params(substream, params); if (err < 0) - goto out_old; + return err; snd_pcm_hw_convert_to_old_params(oparams, params); if (copy_to_user(_oparams, oparams, sizeof(*oparams))) - err = -EFAULT; -out_old: - kfree(oparams); -out: - kfree(params); - return err; + return -EFAULT; + return 0; } static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream, struct snd_pcm_hw_params_old __user * _oparams) { - struct snd_pcm_hw_params *params; - struct snd_pcm_hw_params_old *oparams = NULL; + struct snd_pcm_hw_params *params __free(kfree) = NULL; + struct snd_pcm_hw_params_old *oparams __free(kfree) = NULL; int err; params = kmalloc(sizeof(*params), GFP_KERNEL); @@ -4120,24 +4103,18 @@ static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream, return -ENOMEM; oparams = memdup_user(_oparams, sizeof(*oparams)); - if (IS_ERR(oparams)) { - err = PTR_ERR(oparams); - goto out; - } + if (IS_ERR(oparams)) + return PTR_ERR(no_free_ptr(oparams)); snd_pcm_hw_convert_from_old_params(params, oparams); err = snd_pcm_hw_params(substream, params); if (err < 0) - goto out_old; + return err; snd_pcm_hw_convert_to_old_params(oparams, params); if (copy_to_user(_oparams, oparams, sizeof(*oparams))) - err = -EFAULT; -out_old: - kfree(oparams); -out: - kfree(params); - return err; + return -EFAULT; + return 0; } #endif /* CONFIG_SND_SUPPORT_OLD_API */ -- cgit 1.2.3-korg From 1052d988226948493eb9730b3424308972eca5f4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 22 Feb 2024 12:15:02 +0100 Subject: ALSA: control: Use automatic cleanup of kfree() There are common patterns where a temporary buffer is allocated and freed at the exit, and those can be simplified with the recent cleanup mechanism via __free(kfree). A caveat is that some allocations are memdup_user() and they return an error pointer instead of NULL. Those need special cares and the value has to be cleared with no_free_ptr() at the allocation error path. Other than that, the conversions are straightforward. No functional changes, only code refactoring. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240222111509.28390-3-tiwai@suse.de --- sound/core/control.c | 23 ++++++--------- sound/core/control_compat.c | 69 +++++++++++++++++---------------------------- 2 files changed, 34 insertions(+), 58 deletions(-) (limited to 'sound') diff --git a/sound/core/control.c b/sound/core/control.c index 59c8658966d4c..c8cd70aed6af4 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -932,7 +932,7 @@ EXPORT_SYMBOL(snd_ctl_find_id); static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl, unsigned int cmd, void __user *arg) { - struct snd_ctl_card_info *info; + struct snd_ctl_card_info *info __free(kfree) = NULL; info = kzalloc(sizeof(*info), GFP_KERNEL); if (! info) @@ -946,11 +946,8 @@ static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl, strscpy(info->mixername, card->mixername, sizeof(info->mixername)); strscpy(info->components, card->components, sizeof(info->components)); up_read(&snd_ioctl_rwsem); - if (copy_to_user(arg, info, sizeof(struct snd_ctl_card_info))) { - kfree(info); + if (copy_to_user(arg, info, sizeof(struct snd_ctl_card_info))) return -EFAULT; - } - kfree(info); return 0; } @@ -1339,12 +1336,10 @@ static int snd_ctl_elem_read_user(struct snd_card *card, result = snd_ctl_elem_read(card, control); if (result < 0) - goto error; + return result; if (copy_to_user(_control, control, sizeof(*control))) - result = -EFAULT; - error: - kfree(control); + return -EFAULT; return result; } @@ -1406,23 +1401,21 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, static int snd_ctl_elem_write_user(struct snd_ctl_file *file, struct snd_ctl_elem_value __user *_control) { - struct snd_ctl_elem_value *control; + struct snd_ctl_elem_value *control __free(kfree) = NULL; struct snd_card *card; int result; control = memdup_user(_control, sizeof(*control)); if (IS_ERR(control)) - return PTR_ERR(control); + return PTR_ERR(no_free_ptr(control)); card = file->card; result = snd_ctl_elem_write(card, file, control); if (result < 0) - goto error; + return result; if (copy_to_user(_control, control, sizeof(*control))) - result = -EFAULT; - error: - kfree(control); + return -EFAULT; return result; } diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c index 63d787501066c..8392183c77ed3 100644 --- a/sound/core/control_compat.c +++ b/sound/core/control_compat.c @@ -79,61 +79,56 @@ struct snd_ctl_elem_info32 { static int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl, struct snd_ctl_elem_info32 __user *data32) { - struct snd_ctl_elem_info *data; + struct snd_ctl_elem_info *data __free(kfree) = NULL; int err; data = kzalloc(sizeof(*data), GFP_KERNEL); if (! data) return -ENOMEM; - err = -EFAULT; /* copy id */ if (copy_from_user(&data->id, &data32->id, sizeof(data->id))) - goto error; + return -EFAULT; /* we need to copy the item index. * hope this doesn't break anything.. */ if (get_user(data->value.enumerated.item, &data32->value.enumerated.item)) - goto error; + return -EFAULT; err = snd_ctl_elem_info(ctl, data); if (err < 0) - goto error; + return err; /* restore info to 32bit */ - err = -EFAULT; /* id, type, access, count */ if (copy_to_user(&data32->id, &data->id, sizeof(data->id)) || copy_to_user(&data32->type, &data->type, 3 * sizeof(u32))) - goto error; + return -EFAULT; if (put_user(data->owner, &data32->owner)) - goto error; + return -EFAULT; switch (data->type) { case SNDRV_CTL_ELEM_TYPE_BOOLEAN: case SNDRV_CTL_ELEM_TYPE_INTEGER: if (put_user(data->value.integer.min, &data32->value.integer.min) || put_user(data->value.integer.max, &data32->value.integer.max) || put_user(data->value.integer.step, &data32->value.integer.step)) - goto error; + return -EFAULT; break; case SNDRV_CTL_ELEM_TYPE_INTEGER64: if (copy_to_user(&data32->value.integer64, &data->value.integer64, sizeof(data->value.integer64))) - goto error; + return -EFAULT; break; case SNDRV_CTL_ELEM_TYPE_ENUMERATED: if (copy_to_user(&data32->value.enumerated, &data->value.enumerated, sizeof(data->value.enumerated))) - goto error; + return -EFAULT; break; default: break; } - err = 0; - error: - kfree(data); - return err; + return 0; } /* read / write */ @@ -169,7 +164,7 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id, int *countp) { struct snd_kcontrol *kctl; - struct snd_ctl_elem_info *info; + struct snd_ctl_elem_info *info __free(kfree) = NULL; int err; down_read(&card->controls_rwsem); @@ -193,7 +188,6 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id, err = info->type; *countp = info->count; } - kfree(info); return err; } @@ -289,7 +283,7 @@ static int copy_ctl_value_to_user(void __user *userdata, static int ctl_elem_read_user(struct snd_card *card, void __user *userdata, void __user *valuep) { - struct snd_ctl_elem_value *data; + struct snd_ctl_elem_value *data __free(kfree) = NULL; int err, type, count; data = kzalloc(sizeof(*data), GFP_KERNEL); @@ -299,21 +293,18 @@ static int ctl_elem_read_user(struct snd_card *card, err = copy_ctl_value_from_user(card, data, userdata, valuep, &type, &count); if (err < 0) - goto error; + return err; err = snd_ctl_elem_read(card, data); if (err < 0) - goto error; - err = copy_ctl_value_to_user(userdata, valuep, data, type, count); - error: - kfree(data); - return err; + return err; + return copy_ctl_value_to_user(userdata, valuep, data, type, count); } static int ctl_elem_write_user(struct snd_ctl_file *file, void __user *userdata, void __user *valuep) { - struct snd_ctl_elem_value *data; + struct snd_ctl_elem_value *data __free(kfree) = NULL; struct snd_card *card = file->card; int err, type, count; @@ -324,15 +315,12 @@ static int ctl_elem_write_user(struct snd_ctl_file *file, err = copy_ctl_value_from_user(card, data, userdata, valuep, &type, &count); if (err < 0) - goto error; + return err; err = snd_ctl_elem_write(card, file, data); if (err < 0) - goto error; - err = copy_ctl_value_to_user(userdata, valuep, data, type, count); - error: - kfree(data); - return err; + return err; + return copy_ctl_value_to_user(userdata, valuep, data, type, count); } static int snd_ctl_elem_read_user_compat(struct snd_card *card, @@ -366,49 +354,44 @@ static int snd_ctl_elem_add_compat(struct snd_ctl_file *file, struct snd_ctl_elem_info32 __user *data32, int replace) { - struct snd_ctl_elem_info *data; - int err; + struct snd_ctl_elem_info *data __free(kfree) = NULL; data = kzalloc(sizeof(*data), GFP_KERNEL); if (! data) return -ENOMEM; - err = -EFAULT; /* id, type, access, count */ \ if (copy_from_user(&data->id, &data32->id, sizeof(data->id)) || copy_from_user(&data->type, &data32->type, 3 * sizeof(u32))) - goto error; + return -EFAULT; if (get_user(data->owner, &data32->owner)) - goto error; + return -EFAULT; switch (data->type) { case SNDRV_CTL_ELEM_TYPE_BOOLEAN: case SNDRV_CTL_ELEM_TYPE_INTEGER: if (get_user(data->value.integer.min, &data32->value.integer.min) || get_user(data->value.integer.max, &data32->value.integer.max) || get_user(data->value.integer.step, &data32->value.integer.step)) - goto error; + return -EFAULT; break; case SNDRV_CTL_ELEM_TYPE_INTEGER64: if (copy_from_user(&data->value.integer64, &data32->value.integer64, sizeof(data->value.integer64))) - goto error; + return -EFAULT; break; case SNDRV_CTL_ELEM_TYPE_ENUMERATED: if (copy_from_user(&data->value.enumerated, &data32->value.enumerated, sizeof(data->value.enumerated))) - goto error; + return -EFAULT; data->value.enumerated.names_ptr = (uintptr_t)compat_ptr(data->value.enumerated.names_ptr); break; default: break; } - err = snd_ctl_elem_add(file, data, replace); - error: - kfree(data); - return err; + return snd_ctl_elem_add(file, data, replace); } enum { -- cgit 1.2.3-korg From 9b02221422a55e834469fdc91dc4d5147f5a1fb9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 22 Feb 2024 12:15:03 +0100 Subject: ALSA: compress_offload: Use automatic cleanup of kfree() There are common patterns where a temporary buffer is allocated and freed at the exit, and those can be simplified with the recent cleanup mechanism via __free(kfree). A caveat is that some allocations are memdup_user() and they return an error pointer instead of NULL. Those need special cares and the value has to be cleared with no_free_ptr() at the allocation error path. Other than that, the conversions are straightforward. No functional changes, only code refactoring. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240222111509.28390-4-tiwai@suse.de --- sound/core/compress_offload.c | 36 +++++++++++++----------------------- 1 file changed, 13 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index 619371aa9964d..5d926c5b737d3 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -465,7 +465,7 @@ static int snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg) { int retval; - struct snd_compr_codec_caps *caps; + struct snd_compr_codec_caps *caps __free(kfree) = NULL; if (!stream->ops->get_codec_caps) return -ENXIO; @@ -476,12 +476,9 @@ snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg) retval = stream->ops->get_codec_caps(stream, caps); if (retval) - goto out; + return retval; if (copy_to_user((void __user *)arg, caps, sizeof(*caps))) - retval = -EFAULT; - -out: - kfree(caps); + return -EFAULT; return retval; } #endif /* !COMPR_CODEC_CAPS_OVERFLOW */ @@ -586,7 +583,7 @@ static int snd_compress_check_input(struct snd_compr_params *params) static int snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg) { - struct snd_compr_params *params; + struct snd_compr_params *params __free(kfree) = NULL; int retval; if (stream->runtime->state == SNDRV_PCM_STATE_OPEN || stream->next_track) { @@ -596,24 +593,22 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg) */ params = memdup_user((void __user *)arg, sizeof(*params)); if (IS_ERR(params)) - return PTR_ERR(params); + return PTR_ERR(no_free_ptr(params)); retval = snd_compress_check_input(params); if (retval) - goto out; + return retval; retval = snd_compr_allocate_buffer(stream, params); - if (retval) { - retval = -ENOMEM; - goto out; - } + if (retval) + return -ENOMEM; retval = stream->ops->set_params(stream, params); if (retval) - goto out; + return retval; if (stream->next_track) - goto out; + return retval; stream->metadata_set = false; stream->next_track = false; @@ -622,15 +617,13 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg) } else { return -EPERM; } -out: - kfree(params); return retval; } static int snd_compr_get_params(struct snd_compr_stream *stream, unsigned long arg) { - struct snd_codec *params; + struct snd_codec *params __free(kfree) = NULL; int retval; if (!stream->ops->get_params) @@ -641,12 +634,9 @@ snd_compr_get_params(struct snd_compr_stream *stream, unsigned long arg) return -ENOMEM; retval = stream->ops->get_params(stream, params); if (retval) - goto out; + return retval; if (copy_to_user((char __user *)arg, params, sizeof(*params))) - retval = -EFAULT; - -out: - kfree(params); + return -EFAULT; return retval; } -- cgit 1.2.3-korg From ed96f6394e1bf44ae03327683f2970302f431320 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 22 Feb 2024 12:15:04 +0100 Subject: ALSA: timer: Use automatic cleanup of kfree() There are common patterns where a temporary buffer is allocated and freed at the exit, and those can be simplified with the recent cleanup mechanism via __free(kfree). No functional changes, only code refactoring. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240222111509.28390-5-tiwai@suse.de --- sound/core/timer.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/core/timer.c b/sound/core/timer.c index e6e551d4a29e0..a595c4fb4b2a0 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1645,7 +1645,7 @@ static int snd_timer_user_next_device(struct snd_timer_id __user *_tid) static int snd_timer_user_ginfo(struct file *file, struct snd_timer_ginfo __user *_ginfo) { - struct snd_timer_ginfo *ginfo; + struct snd_timer_ginfo *ginfo __free(kfree) = NULL; struct snd_timer_id tid; struct snd_timer *t; struct list_head *p; @@ -1653,7 +1653,7 @@ static int snd_timer_user_ginfo(struct file *file, ginfo = memdup_user(_ginfo, sizeof(*ginfo)); if (IS_ERR(ginfo)) - return PTR_ERR(ginfo); + return PTR_ERR(no_free_ptr(ginfo)); tid = ginfo->tid; memset(ginfo, 0, sizeof(*ginfo)); @@ -1682,7 +1682,6 @@ static int snd_timer_user_ginfo(struct file *file, mutex_unlock(®ister_mutex); if (err >= 0 && copy_to_user(_ginfo, ginfo, sizeof(*ginfo))) err = -EFAULT; - kfree(ginfo); return err; } @@ -1804,9 +1803,8 @@ static int snd_timer_user_info(struct file *file, struct snd_timer_info __user *_info) { struct snd_timer_user *tu; - struct snd_timer_info *info; + struct snd_timer_info *info __free(kfree) = NULL; struct snd_timer *t; - int err = 0; tu = file->private_data; if (!tu->timeri) @@ -1827,9 +1825,8 @@ static int snd_timer_user_info(struct file *file, info->resolution = snd_timer_hw_resolution(t); spin_unlock_irq(&t->lock); if (copy_to_user(_info, info, sizeof(*_info))) - err = -EFAULT; - kfree(info); - return err; + return -EFAULT; + return 0; } static int snd_timer_user_params(struct file *file, -- cgit 1.2.3-korg From fb9e197f3f27133f9137c6c0eb7352529a272419 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 22 Feb 2024 12:15:05 +0100 Subject: ALSA: vmaster: Use automatic cleanup of kfree() There are common patterns where a temporary buffer is allocated and freed at the exit, and those can be simplified with the recent cleanup mechanism via __free(kfree). No functional changes, only code refactoring. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240222111509.28390-6-tiwai@suse.de --- sound/core/vmaster.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c index 378d2c7c3d4af..04a57f7be6ea4 100644 --- a/sound/core/vmaster.c +++ b/sound/core/vmaster.c @@ -56,7 +56,7 @@ struct link_follower { static int follower_update(struct link_follower *follower) { - struct snd_ctl_elem_value *uctl; + struct snd_ctl_elem_value *uctl __free(kfree) = NULL; int err, ch; uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); @@ -65,18 +65,16 @@ static int follower_update(struct link_follower *follower) uctl->id = follower->follower.id; err = follower->follower.get(&follower->follower, uctl); if (err < 0) - goto error; + return err; for (ch = 0; ch < follower->info.count; ch++) follower->vals[ch] = uctl->value.integer.value[ch]; - error: - kfree(uctl); - return err < 0 ? err : 0; + return 0; } /* get the follower ctl info and save the initial values */ static int follower_init(struct link_follower *follower) { - struct snd_ctl_elem_info *uinfo; + struct snd_ctl_elem_info *uinfo __free(kfree) = NULL; int err; if (follower->info.count) { @@ -91,22 +89,18 @@ static int follower_init(struct link_follower *follower) return -ENOMEM; uinfo->id = follower->follower.id; err = follower->follower.info(&follower->follower, uinfo); - if (err < 0) { - kfree(uinfo); + if (err < 0) return err; - } follower->info.type = uinfo->type; follower->info.count = uinfo->count; if (follower->info.count > 2 || (follower->info.type != SNDRV_CTL_ELEM_TYPE_INTEGER && follower->info.type != SNDRV_CTL_ELEM_TYPE_BOOLEAN)) { pr_err("ALSA: vmaster: invalid follower element\n"); - kfree(uinfo); return -EINVAL; } follower->info.min_val = uinfo->value.integer.min; follower->info.max_val = uinfo->value.integer.max; - kfree(uinfo); return follower_update(follower); } @@ -341,7 +335,7 @@ static int master_get(struct snd_kcontrol *kcontrol, static int sync_followers(struct link_master *master, int old_val, int new_val) { struct link_follower *follower; - struct snd_ctl_elem_value *uval; + struct snd_ctl_elem_value *uval __free(kfree) = NULL; uval = kmalloc(sizeof(*uval), GFP_KERNEL); if (!uval) @@ -353,7 +347,6 @@ static int sync_followers(struct link_master *master, int old_val, int new_val) master->val = new_val; follower_put_val(follower, uval); } - kfree(uval); return 0; } -- cgit 1.2.3-korg From 1c4025d4ea0cabe05b2425889eed9298c713c771 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 22 Feb 2024 12:15:06 +0100 Subject: ALSA: seq: oss: Use automatic cleanup of kfree() There are common patterns where a temporary buffer is allocated and freed at the exit, and those can be simplified with the recent cleanup mechanism via __free(kfree). No functional changes, only code refactoring. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240222111509.28390-7-tiwai@suse.de --- sound/core/seq/oss/seq_oss_init.c | 15 +++++---------- sound/core/seq/oss/seq_oss_midi.c | 11 +++-------- 2 files changed, 8 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c index 76bf41c26acda..676246fa02f15 100644 --- a/sound/core/seq/oss/seq_oss_init.c +++ b/sound/core/seq/oss/seq_oss_init.c @@ -63,20 +63,18 @@ int __init snd_seq_oss_create_client(void) { int rc; - struct snd_seq_port_info *port; + struct snd_seq_port_info *port __free(kfree) = NULL; struct snd_seq_port_callback port_callback; port = kzalloc(sizeof(*port), GFP_KERNEL); - if (!port) { - rc = -ENOMEM; - goto __error; - } + if (!port) + return -ENOMEM; /* create ALSA client */ rc = snd_seq_create_kernel_client(NULL, SNDRV_SEQ_CLIENT_OSS, "OSS sequencer"); if (rc < 0) - goto __error; + return rc; system_client = rc; @@ -104,14 +102,11 @@ snd_seq_oss_create_client(void) subs.dest.port = system_port; call_ctl(SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs); } - rc = 0; /* look up midi devices */ schedule_work(&async_lookup_work); - __error: - kfree(port); - return rc; + return 0; } diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c index f2940b29595f0..f8e247d9e5c99 100644 --- a/sound/core/seq/oss/seq_oss_midi.c +++ b/sound/core/seq/oss/seq_oss_midi.c @@ -64,16 +64,13 @@ static int send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, int snd_seq_oss_midi_lookup_ports(int client) { - struct snd_seq_client_info *clinfo; - struct snd_seq_port_info *pinfo; + struct snd_seq_client_info *clinfo __free(kfree) = NULL; + struct snd_seq_port_info *pinfo __free(kfree) = NULL; clinfo = kzalloc(sizeof(*clinfo), GFP_KERNEL); pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL); - if (! clinfo || ! pinfo) { - kfree(clinfo); - kfree(pinfo); + if (!clinfo || !pinfo) return -ENOMEM; - } clinfo->client = -1; while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT, clinfo) == 0) { if (clinfo->client == client) @@ -83,8 +80,6 @@ snd_seq_oss_midi_lookup_ports(int client) while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, pinfo) == 0) snd_seq_oss_midi_check_new_port(pinfo); } - kfree(clinfo); - kfree(pinfo); return 0; } -- cgit 1.2.3-korg From 5d04ad53e54c1513a90f44367d5712e984ba579b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 22 Feb 2024 12:15:07 +0100 Subject: ALSA: seq: virmidi: Use automatic cleanup of kfree() There are common patterns where a temporary buffer is allocated and freed at the exit, and those can be simplified with the recent cleanup mechanism via __free(kfree). No functional changes, only code refactoring. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240222111509.28390-8-tiwai@suse.de --- sound/core/seq/seq_virmidi.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 1678737f11be7..35f93b43dd2ac 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -363,26 +363,22 @@ static int snd_virmidi_dev_attach_seq(struct snd_virmidi_dev *rdev) { int client; struct snd_seq_port_callback pcallbacks; - struct snd_seq_port_info *pinfo; + struct snd_seq_port_info *pinfo __free(kfree) = NULL; int err; if (rdev->client >= 0) return 0; pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL); - if (!pinfo) { - err = -ENOMEM; - goto __error; - } + if (!pinfo) + return -ENOMEM; client = snd_seq_create_kernel_client(rdev->card, rdev->device, "%s %d-%d", rdev->rmidi->name, rdev->card->number, rdev->device); - if (client < 0) { - err = client; - goto __error; - } + if (client < 0) + return client; rdev->client = client; /* create a port */ @@ -410,15 +406,11 @@ static int snd_virmidi_dev_attach_seq(struct snd_virmidi_dev *rdev) if (err < 0) { snd_seq_delete_kernel_client(client); rdev->client = -1; - goto __error; + return err; } rdev->port = pinfo->addr.port; - err = 0; /* success */ - - __error: - kfree(pinfo); - return err; + return 0; /* success */ } -- cgit 1.2.3-korg From 316e38ef776663a7a4c5d76438c42c948c574df4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 22 Feb 2024 12:15:08 +0100 Subject: ALSA: seq: ump: Use automatic cleanup of kfree() There are common patterns where a temporary buffer is allocated and freed at the exit, and those can be simplified with the recent cleanup mechanism via __free(kfree). No functional changes, only code refactoring. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240222111509.28390-9-tiwai@suse.de --- sound/core/seq/seq_ump_client.c | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) (limited to 'sound') diff --git a/sound/core/seq/seq_ump_client.c b/sound/core/seq/seq_ump_client.c index 2db371d79930d..ccac2d3a9fbcb 100644 --- a/sound/core/seq/seq_ump_client.c +++ b/sound/core/seq/seq_ump_client.c @@ -217,15 +217,12 @@ static void fill_port_info(struct snd_seq_port_info *port, static int seq_ump_group_init(struct seq_ump_client *client, int group_index) { struct seq_ump_group *group = &client->groups[group_index]; - struct snd_seq_port_info *port; + struct snd_seq_port_info *port __free(kfree) = NULL; struct snd_seq_port_callback pcallbacks; - int err; port = kzalloc(sizeof(*port), GFP_KERNEL); - if (!port) { - err = -ENOMEM; - goto error; - } + if (!port) + return -ENOMEM; fill_port_info(port, client, group); port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT; @@ -238,24 +235,22 @@ static int seq_ump_group_init(struct seq_ump_client *client, int group_index) pcallbacks.unuse = seq_ump_unuse; pcallbacks.event_input = seq_ump_process_event; port->kernel = &pcallbacks; - err = snd_seq_kernel_client_ctl(client->seq_client, - SNDRV_SEQ_IOCTL_CREATE_PORT, - port); - error: - kfree(port); - return err; + return snd_seq_kernel_client_ctl(client->seq_client, + SNDRV_SEQ_IOCTL_CREATE_PORT, + port); } /* update the sequencer ports; called from notify_fb_change callback */ static void update_port_infos(struct seq_ump_client *client) { - struct snd_seq_port_info *old, *new; + struct snd_seq_port_info *old __free(kfree) = NULL; + struct snd_seq_port_info *new __free(kfree) = NULL; int i, err; old = kzalloc(sizeof(*old), GFP_KERNEL); new = kzalloc(sizeof(*new), GFP_KERNEL); if (!old || !new) - goto error; + return; for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++) { old->addr.client = client->seq_client; @@ -264,7 +259,7 @@ static void update_port_infos(struct seq_ump_client *client) SNDRV_SEQ_IOCTL_GET_PORT_INFO, old); if (err < 0) - goto error; + return; fill_port_info(new, client, &client->groups[i]); if (old->capability == new->capability && !strcmp(old->name, new->name)) @@ -273,13 +268,10 @@ static void update_port_infos(struct seq_ump_client *client) SNDRV_SEQ_IOCTL_SET_PORT_INFO, new); if (err < 0) - goto error; + return; /* notify to system port */ snd_seq_system_client_ev_port_change(client->seq_client, i); } - error: - kfree(new); - kfree(old); } /* update dir_bits and active flag for all groups in the client */ @@ -334,7 +326,7 @@ static void update_group_attrs(struct seq_ump_client *client) /* create a UMP Endpoint port */ static int create_ump_endpoint_port(struct seq_ump_client *client) { - struct snd_seq_port_info *port; + struct snd_seq_port_info *port __free(kfree) = NULL; struct snd_seq_port_callback pcallbacks; unsigned int rawmidi_info = client->ump->core.info_flags; int err; @@ -383,7 +375,6 @@ static int create_ump_endpoint_port(struct seq_ump_client *client) err = snd_seq_kernel_client_ctl(client->seq_client, SNDRV_SEQ_IOCTL_CREATE_PORT, port); - kfree(port); return err; } -- cgit 1.2.3-korg From edbcf872c14690c2894b726b67a871b4d238eea8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 22 Feb 2024 12:15:09 +0100 Subject: ALSA: seq: core: Use automatic cleanup of kfree() There are common patterns where a temporary buffer is allocated and freed at the exit, and those can be simplified with the recent cleanup mechanism via __free(kfree). No functional changes, only code refactoring. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240222111509.28390-10-tiwai@suse.de --- sound/core/seq/seq_compat.c | 12 +++++------- sound/core/seq/seq_midi.c | 14 +++----------- 2 files changed, 8 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/core/seq/seq_compat.c b/sound/core/seq/seq_compat.c index 1e35bf086a51d..643af4c1e8386 100644 --- a/sound/core/seq/seq_compat.c +++ b/sound/core/seq/seq_compat.c @@ -31,8 +31,8 @@ struct snd_seq_port_info32 { static int snd_seq_call_port_info_ioctl(struct snd_seq_client *client, unsigned int cmd, struct snd_seq_port_info32 __user *data32) { - int err = -EFAULT; - struct snd_seq_port_info *data; + struct snd_seq_port_info *data __free(kfree) = NULL; + int err; data = kmalloc(sizeof(*data), GFP_KERNEL); if (!data) @@ -41,20 +41,18 @@ static int snd_seq_call_port_info_ioctl(struct snd_seq_client *client, unsigned if (copy_from_user(data, data32, sizeof(*data32)) || get_user(data->flags, &data32->flags) || get_user(data->time_queue, &data32->time_queue)) - goto error; + return -EFAULT; data->kernel = NULL; err = snd_seq_kernel_client_ctl(client->number, cmd, data); if (err < 0) - goto error; + return err; if (copy_to_user(data32, data, sizeof(*data32)) || put_user(data->flags, &data32->flags) || put_user(data->time_queue, &data32->time_queue)) - err = -EFAULT; + return -EFAULT; - error: - kfree(data); return err; } diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index 78dcb0ea15582..0594269d92abc 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c @@ -270,8 +270,8 @@ snd_seq_midisynth_probe(struct device *_dev) struct snd_seq_device *dev = to_seq_dev(_dev); struct seq_midisynth_client *client; struct seq_midisynth *msynth, *ms; - struct snd_seq_port_info *port; - struct snd_rawmidi_info *info; + struct snd_seq_port_info *port __free(kfree) = NULL; + struct snd_rawmidi_info *info __free(kfree) = NULL; struct snd_rawmidi *rmidi = dev->private_data; int newclient = 0; unsigned int p, ports; @@ -297,10 +297,8 @@ snd_seq_midisynth_probe(struct device *_dev) ports = output_count; if (ports < input_count) ports = input_count; - if (ports == 0) { - kfree(info); + if (ports == 0) return -ENODEV; - } if (ports > (256 / SNDRV_RAWMIDI_DEVICES)) ports = 256 / SNDRV_RAWMIDI_DEVICES; @@ -311,7 +309,6 @@ snd_seq_midisynth_probe(struct device *_dev) client = kzalloc(sizeof(*client), GFP_KERNEL); if (client == NULL) { mutex_unlock(®ister_mutex); - kfree(info); return -ENOMEM; } client->seq_client = @@ -321,7 +318,6 @@ snd_seq_midisynth_probe(struct device *_dev) if (client->seq_client < 0) { kfree(client); mutex_unlock(®ister_mutex); - kfree(info); return -ENOMEM; } } @@ -403,8 +399,6 @@ snd_seq_midisynth_probe(struct device *_dev) if (newclient) synths[card->number] = client; mutex_unlock(®ister_mutex); - kfree(info); - kfree(port); return 0; /* success */ __nomem: @@ -417,8 +411,6 @@ snd_seq_midisynth_probe(struct device *_dev) snd_seq_delete_kernel_client(client->seq_client); kfree(client); } - kfree(info); - kfree(port); mutex_unlock(®ister_mutex); return -ENOMEM; } -- cgit 1.2.3-korg From d90950c6a2658ed8cffb4255a5ddba9c831389fe Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 23 Feb 2024 09:42:38 +0100 Subject: ALSA: pcm: Use CLASS() for fdget()/fdput() Now we have a nice definition of CLASS(fd) that can be applied as a clean up for the fdget/fdput pairs in snd_pcm_link(). No functional changes, only code refactoring. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240223084241.3361-2-tiwai@suse.de --- sound/core/pcm_native.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index beee5249dae11..0e84de4b484db 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -2265,28 +2265,22 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) struct snd_pcm_group *group __free(kfree) = NULL; struct snd_pcm_group *target_group; bool nonatomic = substream->pcm->nonatomic; - struct fd f = fdget(fd); + CLASS(fd, f)(fd); if (!f.file) return -EBADFD; - if (!is_pcm_file(f.file)) { - res = -EBADFD; - goto _badf; - } + if (!is_pcm_file(f.file)) + return -EBADFD; pcm_file = f.file->private_data; substream1 = pcm_file->substream; - if (substream == substream1) { - res = -EINVAL; - goto _badf; - } + if (substream == substream1) + return -EINVAL; group = kzalloc(sizeof(*group), GFP_KERNEL); - if (!group) { - res = -ENOMEM; - goto _badf; - } + if (!group) + return -ENOMEM; snd_pcm_group_init(group); @@ -2318,8 +2312,6 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) snd_pcm_group_unlock_irq(target_group, nonatomic); _end: up_write(&snd_pcm_link_rwsem); - _badf: - fdput(f); return res; } -- cgit 1.2.3-korg From 6c40eec521af8cea034777f877ead19bfa7309f4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 23 Feb 2024 09:42:40 +0100 Subject: ALSA: mixer_oss: ump: Use automatic cleanup of kfree() There are common patterns where a temporary buffer is allocated and freed at the exit, and those can be simplified with the recent cleanup mechanism via __free(kfree). No functional changes, only code refactoring. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240223084241.3361-4-tiwai@suse.de --- sound/core/oss/mixer_oss.c | 59 ++++++++++++++-------------------------------- 1 file changed, 18 insertions(+), 41 deletions(-) (limited to 'sound') diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index dae2da3808351..e10017a42ed8c 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -532,8 +532,8 @@ static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer, unsigned int numid, int *left, int *right) { - struct snd_ctl_elem_info *uinfo; - struct snd_ctl_elem_value *uctl; + struct snd_ctl_elem_info *uinfo __free(kfree) = NULL; + struct snd_ctl_elem_value *uctl __free(kfree) = NULL; struct snd_kcontrol *kctl; struct snd_card *card = fmixer->card; @@ -561,8 +561,6 @@ static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer, *right = snd_mixer_oss_conv1(uctl->value.integer.value[1], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[1]); __unalloc: up_read(&card->controls_rwsem); - kfree(uctl); - kfree(uinfo); } static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer, @@ -571,8 +569,8 @@ static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer, int *left, int *right, int route) { - struct snd_ctl_elem_info *uinfo; - struct snd_ctl_elem_value *uctl; + struct snd_ctl_elem_info *uinfo __free(kfree) = NULL; + struct snd_ctl_elem_value *uctl __free(kfree) = NULL; struct snd_kcontrol *kctl; struct snd_card *card = fmixer->card; @@ -601,8 +599,6 @@ static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer, *right = 0; __unalloc: up_read(&card->controls_rwsem); - kfree(uctl); - kfree(uinfo); } static int snd_mixer_oss_get_volume1(struct snd_mixer_oss_file *fmixer, @@ -636,8 +632,8 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer, unsigned int numid, int left, int right) { - struct snd_ctl_elem_info *uinfo; - struct snd_ctl_elem_value *uctl; + struct snd_ctl_elem_info *uinfo __free(kfree) = NULL; + struct snd_ctl_elem_value *uctl __free(kfree) = NULL; struct snd_kcontrol *kctl; struct snd_card *card = fmixer->card; int res; @@ -669,8 +665,6 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer, snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); __unalloc: up_read(&card->controls_rwsem); - kfree(uctl); - kfree(uinfo); } static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer, @@ -679,8 +673,8 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer, int left, int right, int route) { - struct snd_ctl_elem_info *uinfo; - struct snd_ctl_elem_value *uctl; + struct snd_ctl_elem_info *uinfo __free(kfree) = NULL; + struct snd_ctl_elem_value *uctl __free(kfree) = NULL; struct snd_kcontrol *kctl; struct snd_card *card = fmixer->card; int res; @@ -716,8 +710,6 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer, snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); __unalloc: up_read(&card->controls_rwsem); - kfree(uctl); - kfree(uinfo); } static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer, @@ -822,16 +814,14 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned struct snd_kcontrol *kctl; struct snd_mixer_oss_slot *pslot; struct slot *slot; - struct snd_ctl_elem_info *uinfo; - struct snd_ctl_elem_value *uctl; + struct snd_ctl_elem_info *uinfo __free(kfree) = NULL; + struct snd_ctl_elem_value *uctl __free(kfree) = NULL; int err, idx; uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); - if (uinfo == NULL || uctl == NULL) { - err = -ENOMEM; - goto __free_only; - } + if (uinfo == NULL || uctl == NULL) + return -ENOMEM; down_read(&card->controls_rwsem); kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); if (! kctl) { @@ -861,9 +851,6 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned err = 0; __unlock: up_read(&card->controls_rwsem); - __free_only: - kfree(uctl); - kfree(uinfo); return err; } @@ -874,17 +861,15 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned struct snd_kcontrol *kctl; struct snd_mixer_oss_slot *pslot; struct slot *slot = NULL; - struct snd_ctl_elem_info *uinfo; - struct snd_ctl_elem_value *uctl; + struct snd_ctl_elem_info *uinfo __free(kfree) = NULL; + struct snd_ctl_elem_value *uctl __free(kfree) = NULL; int err; unsigned int idx; uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); - if (uinfo == NULL || uctl == NULL) { - err = -ENOMEM; - goto __free_only; - } + if (uinfo == NULL || uctl == NULL) + return -ENOMEM; down_read(&card->controls_rwsem); kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); if (! kctl) { @@ -917,9 +902,6 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned err = 0; __unlock: up_read(&card->controls_rwsem); - __free_only: - kfree(uctl); - kfree(uinfo); return err; } @@ -931,7 +913,7 @@ struct snd_mixer_oss_assign_table { static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *slot, const char *name, int index, int item) { - struct snd_ctl_elem_info *info; + struct snd_ctl_elem_info *info __free(kfree) = NULL; struct snd_kcontrol *kcontrol; struct snd_card *card = mixer->card; int err; @@ -950,7 +932,6 @@ static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *sl err = kcontrol->info(kcontrol, info); if (err < 0) { up_read(&card->controls_rwsem); - kfree(info); return err; } slot->numid[item] = kcontrol->id.numid; @@ -958,7 +939,6 @@ static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *sl if (info->count > slot->channels) slot->channels = info->count; slot->present |= 1 << item; - kfree(info); return 0; } @@ -1073,7 +1053,7 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, if (!ptr->index) kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); if (kctl) { - struct snd_ctl_elem_info *uinfo; + struct snd_ctl_elem_info *uinfo __free(kfree) = NULL; uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); if (! uinfo) { @@ -1083,7 +1063,6 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, if (kctl->info(kctl, uinfo)) { up_read(&mixer->card->controls_rwsem); - kfree(uinfo); return 0; } strcpy(str, ptr->name); @@ -1099,7 +1078,6 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, uinfo->value.enumerated.item = slot.capture_item; if (kctl->info(kctl, uinfo)) { up_read(&mixer->card->controls_rwsem); - kfree(uinfo); return 0; } if (!strcmp(uinfo->value.enumerated.name, str)) { @@ -1108,7 +1086,6 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, } } } - kfree(uinfo); } up_read(&mixer->card->controls_rwsem); if (slot.present != 0) { -- cgit 1.2.3-korg From a55bc334d3dfbfdc075632a144e821a564da38d5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 23 Feb 2024 09:42:41 +0100 Subject: ALSA: pcm_oss: ump: Use automatic cleanup of kfree() There are common patterns where a temporary buffer is allocated and freed at the exit, and those can be simplified with the recent cleanup mechanism via __free(kfree). No functional changes, only code refactoring. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240223084241.3361-5-tiwai@suse.de --- sound/core/oss/pcm_oss.c | 33 ++++++++++----------------------- 1 file changed, 10 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 728c211142d14..e4e292b2db06e 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -377,7 +377,7 @@ static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm, snd_pcm_hw_param_t var, unsigned int best, int *dir) { - struct snd_pcm_hw_params *save = NULL; + struct snd_pcm_hw_params *save __free(kfree) = NULL; int v; unsigned int saved_min; int last = 0; @@ -404,38 +404,30 @@ static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm, saved_min = min; min = snd_pcm_hw_param_min(pcm, params, var, min, &mindir); if (min >= 0) { - struct snd_pcm_hw_params *params1; + struct snd_pcm_hw_params *params1 __free(kfree) = NULL; if (max < 0) goto _end; if ((unsigned int)min == saved_min && mindir == valdir) goto _end; params1 = kmalloc(sizeof(*params1), GFP_KERNEL); - if (params1 == NULL) { - kfree(save); + if (params1 == NULL) return -ENOMEM; - } *params1 = *save; max = snd_pcm_hw_param_max(pcm, params1, var, max, &maxdir); - if (max < 0) { - kfree(params1); + if (max < 0) goto _end; - } if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) { *params = *params1; last = 1; } - kfree(params1); } else { *params = *save; max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir); - if (max < 0) { - kfree(save); + if (max < 0) return max; - } last = 1; } _end: - kfree(save); if (last) v = snd_pcm_hw_param_last(pcm, params, var, dir); else @@ -789,7 +781,7 @@ static int choose_rate(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, unsigned int best_rate) { const struct snd_interval *it; - struct snd_pcm_hw_params *save; + struct snd_pcm_hw_params *save __free(kfree) = NULL; unsigned int rate, prev; save = kmalloc(sizeof(*save), GFP_KERNEL); @@ -808,10 +800,8 @@ static int choose_rate(struct snd_pcm_substream *substream, ret = snd_pcm_hw_param_set(substream, params, SNDRV_PCM_HW_PARAM_RATE, rate, 0); - if (ret == (int)rate) { - kfree(save); + if (ret == (int)rate) return rate; - } *params = *save; } prev = rate; @@ -821,7 +811,6 @@ static int choose_rate(struct snd_pcm_substream *substream, } /* not found, use the nearest rate */ - kfree(save); return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL); } @@ -1847,7 +1836,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file) struct snd_pcm_substream *substream; int err; int direct; - struct snd_pcm_hw_params *params; + struct snd_pcm_hw_params *params __free(kfree) = NULL; unsigned int formats = 0; const struct snd_mask *format_mask; int fmt; @@ -1873,7 +1862,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file) _snd_pcm_hw_params_any(params); err = snd_pcm_hw_refine(substream, params); if (err < 0) - goto error; + return err; format_mask = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT); for (fmt = 0; fmt < 32; ++fmt) { if (snd_mask_test(format_mask, fmt)) { @@ -1883,9 +1872,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file) } } - error: - kfree(params); - return err < 0 ? err : formats; + return formats; } static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int format) -- cgit 1.2.3-korg From 9301a412303725ae511229c22ea0f326ad47ad07 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Feb 2024 11:49:12 +0100 Subject: ALSA: kunit: Fix sparse warnings There were a few sparse warnings about the cast of strong-typed snd_pcm_format_t. Fix them with cast with __force. For spreading the ugly mess, put them in the definitions WRONG_FORMAT_1 and WRONG_FORMAT_2 and use them in the callers. Fixes: 3e39acf56ede ("ALSA: core: Add sound core KUnit test") Reported-by: kernel test robot Closes: https://lore.kernel.org/r/202402270303.PmvmQrJV-lkp@intel.com Link: https://lore.kernel.org/r/20240227104912.18921-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/core/sound_kunit.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/core/sound_kunit.c b/sound/core/sound_kunit.c index 4212c4a20697d..eb90f62228c02 100644 --- a/sound/core/sound_kunit.c +++ b/sound/core/sound_kunit.c @@ -17,7 +17,8 @@ .name = #fmt, \ } -#define WRONG_FORMAT (SNDRV_PCM_FORMAT_LAST + 1) +#define WRONG_FORMAT_1 (__force snd_pcm_format_t)((__force int)SNDRV_PCM_FORMAT_LAST + 1) +#define WRONG_FORMAT_2 (__force snd_pcm_format_t)-1 #define VALID_NAME "ValidName" #define NAME_W_SPEC_CHARS "In%v@1id name" @@ -104,8 +105,8 @@ static void test_phys_format_size(struct kunit *test) valid_fmt[i].physical_bits); } - KUNIT_EXPECT_EQ(test, snd_pcm_format_physical_width(WRONG_FORMAT), -EINVAL); - KUNIT_EXPECT_EQ(test, snd_pcm_format_physical_width(-1), -EINVAL); + KUNIT_EXPECT_EQ(test, snd_pcm_format_physical_width(WRONG_FORMAT_1), -EINVAL); + KUNIT_EXPECT_EQ(test, snd_pcm_format_physical_width(WRONG_FORMAT_2), -EINVAL); } static void test_format_width(struct kunit *test) @@ -117,8 +118,8 @@ static void test_format_width(struct kunit *test) valid_fmt[i].width); } - KUNIT_EXPECT_EQ(test, snd_pcm_format_width(WRONG_FORMAT), -EINVAL); - KUNIT_EXPECT_EQ(test, snd_pcm_format_width(-1), -EINVAL); + KUNIT_EXPECT_EQ(test, snd_pcm_format_width(WRONG_FORMAT_1), -EINVAL); + KUNIT_EXPECT_EQ(test, snd_pcm_format_width(WRONG_FORMAT_2), -EINVAL); } static void test_format_signed(struct kunit *test) @@ -132,8 +133,8 @@ static void test_format_signed(struct kunit *test) valid_fmt[i].sd < 0 ? -EINVAL : 1 - valid_fmt[i].sd); } - KUNIT_EXPECT_EQ(test, snd_pcm_format_width(WRONG_FORMAT), -EINVAL); - KUNIT_EXPECT_EQ(test, snd_pcm_format_width(-1), -EINVAL); + KUNIT_EXPECT_EQ(test, snd_pcm_format_width(WRONG_FORMAT_1), -EINVAL); + KUNIT_EXPECT_EQ(test, snd_pcm_format_width(WRONG_FORMAT_2), -EINVAL); } static void test_format_endianness(struct kunit *test) @@ -147,10 +148,10 @@ static void test_format_endianness(struct kunit *test) valid_fmt[i].le < 0 ? -EINVAL : 1 - valid_fmt[i].le); } - KUNIT_EXPECT_EQ(test, snd_pcm_format_little_endian(WRONG_FORMAT), -EINVAL); - KUNIT_EXPECT_EQ(test, snd_pcm_format_little_endian(-1), -EINVAL); - KUNIT_EXPECT_EQ(test, snd_pcm_format_big_endian(WRONG_FORMAT), -EINVAL); - KUNIT_EXPECT_EQ(test, snd_pcm_format_big_endian(-1), -EINVAL); + KUNIT_EXPECT_EQ(test, snd_pcm_format_little_endian(WRONG_FORMAT_1), -EINVAL); + KUNIT_EXPECT_EQ(test, snd_pcm_format_little_endian(WRONG_FORMAT_2), -EINVAL); + KUNIT_EXPECT_EQ(test, snd_pcm_format_big_endian(WRONG_FORMAT_1), -EINVAL); + KUNIT_EXPECT_EQ(test, snd_pcm_format_big_endian(WRONG_FORMAT_2), -EINVAL); } static void _test_fill_silence(struct kunit *test, struct snd_format_test_data *data, @@ -177,7 +178,7 @@ static void test_format_fill_silence(struct kunit *test) _test_fill_silence(test, &valid_fmt[j], buffer, buf_samples[i]); } - KUNIT_EXPECT_EQ(test, snd_pcm_format_set_silence(WRONG_FORMAT, buffer, 20), -EINVAL); + KUNIT_EXPECT_EQ(test, snd_pcm_format_set_silence(WRONG_FORMAT_1, buffer, 20), -EINVAL); KUNIT_EXPECT_EQ(test, snd_pcm_format_set_silence(SNDRV_PCM_FORMAT_LAST, buffer, 0), 0); } @@ -272,8 +273,8 @@ static void test_pcm_format_name(struct kunit *test) KUNIT_EXPECT_STREQ(test, name, valid_fmt[i].name); } - KUNIT_ASSERT_STREQ(test, snd_pcm_format_name(WRONG_FORMAT), "Unknown"); - KUNIT_ASSERT_STREQ(test, snd_pcm_format_name(-1), "Unknown"); + KUNIT_ASSERT_STREQ(test, snd_pcm_format_name(WRONG_FORMAT_1), "Unknown"); + KUNIT_ASSERT_STREQ(test, snd_pcm_format_name(WRONG_FORMAT_2), "Unknown"); } static void test_card_add_component(struct kunit *test) -- cgit 1.2.3-korg From 631896f7eaaf8cf8c639b065d3c9fbaa66da5d32 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Feb 2024 09:52:43 +0100 Subject: ALSA: ump: Use guard() for locking We can simplify the code gracefully with new guard() macro and co for automatic cleanup of locks. Only the code refactoring, and no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240227085306.9764-2-tiwai@suse.de --- sound/core/ump.c | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/sound/core/ump.c b/sound/core/ump.c index fe7911498cc43..fd6a68a542788 100644 --- a/sound/core/ump.c +++ b/sound/core/ump.c @@ -985,13 +985,11 @@ static int snd_ump_legacy_open(struct snd_rawmidi_substream *substream) struct snd_ump_endpoint *ump = substream->rmidi->private_data; int dir = substream->stream; int group = ump->legacy_mapping[substream->number]; - int err = 0; + int err; - mutex_lock(&ump->open_mutex); - if (ump->legacy_substreams[dir][group]) { - err = -EBUSY; - goto unlock; - } + guard(mutex)(&ump->open_mutex); + if (ump->legacy_substreams[dir][group]) + return -EBUSY; if (dir == SNDRV_RAWMIDI_STREAM_OUTPUT) { if (!ump->legacy_out_opens) { err = snd_rawmidi_kernel_open(&ump->core, 0, @@ -999,17 +997,14 @@ static int snd_ump_legacy_open(struct snd_rawmidi_substream *substream) SNDRV_RAWMIDI_LFLG_APPEND, &ump->legacy_out_rfile); if (err < 0) - goto unlock; + return err; } ump->legacy_out_opens++; snd_ump_convert_reset(&ump->out_cvts[group]); } - spin_lock_irq(&ump->legacy_locks[dir]); + guard(spinlock_irq)(&ump->legacy_locks[dir]); ump->legacy_substreams[dir][group] = substream; - spin_unlock_irq(&ump->legacy_locks[dir]); - unlock: - mutex_unlock(&ump->open_mutex); - return err; + return 0; } static int snd_ump_legacy_close(struct snd_rawmidi_substream *substream) @@ -1018,15 +1013,13 @@ static int snd_ump_legacy_close(struct snd_rawmidi_substream *substream) int dir = substream->stream; int group = ump->legacy_mapping[substream->number]; - mutex_lock(&ump->open_mutex); - spin_lock_irq(&ump->legacy_locks[dir]); - ump->legacy_substreams[dir][group] = NULL; - spin_unlock_irq(&ump->legacy_locks[dir]); + guard(mutex)(&ump->open_mutex); + scoped_guard(spinlock_irq, &ump->legacy_locks[dir]) + ump->legacy_substreams[dir][group] = NULL; if (dir == SNDRV_RAWMIDI_STREAM_OUTPUT) { if (!--ump->legacy_out_opens) snd_rawmidi_kernel_release(&ump->legacy_out_rfile); } - mutex_unlock(&ump->open_mutex); return 0; } @@ -1078,12 +1071,11 @@ static int process_legacy_output(struct snd_ump_endpoint *ump, const int dir = SNDRV_RAWMIDI_STREAM_OUTPUT; unsigned char c; int group, size = 0; - unsigned long flags; if (!ump->out_cvts || !ump->legacy_out_opens) return 0; - spin_lock_irqsave(&ump->legacy_locks[dir], flags); + guard(spinlock_irqsave)(&ump->legacy_locks[dir]); for (group = 0; group < SNDRV_UMP_MAX_GROUPS; group++) { substream = ump->legacy_substreams[dir][group]; if (!substream) @@ -1099,7 +1091,6 @@ static int process_legacy_output(struct snd_ump_endpoint *ump, break; } } - spin_unlock_irqrestore(&ump->legacy_locks[dir], flags); return size; } @@ -1109,18 +1100,16 @@ static void process_legacy_input(struct snd_ump_endpoint *ump, const u32 *src, struct snd_rawmidi_substream *substream; unsigned char buf[16]; unsigned char group; - unsigned long flags; const int dir = SNDRV_RAWMIDI_STREAM_INPUT; int size; size = snd_ump_convert_from_ump(src, buf, &group); if (size <= 0) return; - spin_lock_irqsave(&ump->legacy_locks[dir], flags); + guard(spinlock_irqsave)(&ump->legacy_locks[dir]); substream = ump->legacy_substreams[dir][group]; if (substream) snd_rawmidi_receive(substream, buf, size); - spin_unlock_irqrestore(&ump->legacy_locks[dir], flags); } /* Fill ump->legacy_mapping[] for groups to be used for legacy rawmidi */ -- cgit 1.2.3-korg From d648843aa4742377b22e273c80d575e98195930f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Feb 2024 09:52:44 +0100 Subject: ALSA: compress_offload: Use guard() for locking We can simplify the code gracefully with new guard() macro and co for automatic cleanup of locks. The explicit mutex_lock/unlock are still seen only in snd_compress_wait_for_drain() which does temporary unlock/relocking. Only the code refactoring, and no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240227085306.9764-3-tiwai@suse.de --- sound/core/compress_offload.c | 98 +++++++++++++++---------------------------- 1 file changed, 33 insertions(+), 65 deletions(-) (limited to 'sound') diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index 5d926c5b737d3..f0008fa2d8396 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -127,9 +127,8 @@ static int snd_compr_open(struct inode *inode, struct file *f) init_waitqueue_head(&runtime->sleep); data->stream.runtime = runtime; f->private_data = (void *)data; - mutex_lock(&compr->lock); - ret = compr->ops->open(&data->stream); - mutex_unlock(&compr->lock); + scoped_guard(mutex, &compr->lock) + ret = compr->ops->open(&data->stream); if (ret) { kfree(runtime); kfree(data); @@ -288,7 +287,7 @@ static ssize_t snd_compr_write(struct file *f, const char __user *buf, return -EFAULT; stream = &data->stream; - mutex_lock(&stream->device->lock); + guard(mutex)(&stream->device->lock); /* write is allowed when stream is running or has been steup */ switch (stream->runtime->state) { case SNDRV_PCM_STATE_SETUP: @@ -296,7 +295,6 @@ static ssize_t snd_compr_write(struct file *f, const char __user *buf, case SNDRV_PCM_STATE_RUNNING: break; default: - mutex_unlock(&stream->device->lock); return -EBADFD; } @@ -322,7 +320,6 @@ static ssize_t snd_compr_write(struct file *f, const char __user *buf, pr_debug("stream prepared, Houston we are good to go\n"); } - mutex_unlock(&stream->device->lock); return retval; } @@ -339,7 +336,7 @@ static ssize_t snd_compr_read(struct file *f, char __user *buf, return -EFAULT; stream = &data->stream; - mutex_lock(&stream->device->lock); + guard(mutex)(&stream->device->lock); /* read is allowed when stream is running, paused, draining and setup * (yes setup is state which we transition to after stop, so if user @@ -350,11 +347,9 @@ static ssize_t snd_compr_read(struct file *f, char __user *buf, case SNDRV_PCM_STATE_PREPARED: case SNDRV_PCM_STATE_SUSPENDED: case SNDRV_PCM_STATE_DISCONNECTED: - retval = -EBADFD; - goto out; + return -EBADFD; case SNDRV_PCM_STATE_XRUN: - retval = -EPIPE; - goto out; + return -EPIPE; } avail = snd_compr_get_avail(stream); @@ -363,17 +358,13 @@ static ssize_t snd_compr_read(struct file *f, char __user *buf, if (avail > count) avail = count; - if (stream->ops->copy) { + if (stream->ops->copy) retval = stream->ops->copy(stream, buf, avail); - } else { - retval = -ENXIO; - goto out; - } + else + return -ENXIO; if (retval > 0) stream->runtime->total_bytes_transferred += retval; -out: - mutex_unlock(&stream->device->lock); return retval; } @@ -402,13 +393,12 @@ static __poll_t snd_compr_poll(struct file *f, poll_table *wait) stream = &data->stream; - mutex_lock(&stream->device->lock); + guard(mutex)(&stream->device->lock); switch (stream->runtime->state) { case SNDRV_PCM_STATE_OPEN: case SNDRV_PCM_STATE_XRUN: - retval = snd_compr_get_poll(stream) | EPOLLERR; - goto out; + return snd_compr_get_poll(stream) | EPOLLERR; default: break; } @@ -433,11 +423,9 @@ static __poll_t snd_compr_poll(struct file *f, poll_table *wait) retval = snd_compr_get_poll(stream); break; default: - retval = snd_compr_get_poll(stream) | EPOLLERR; - break; + return snd_compr_get_poll(stream) | EPOLLERR; } -out: - mutex_unlock(&stream->device->lock); + return retval; } @@ -795,12 +783,10 @@ static void error_delayed_work(struct work_struct *work) stream = container_of(work, struct snd_compr_stream, error_work.work); - mutex_lock(&stream->device->lock); + guard(mutex)(&stream->device->lock); stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP); wake_up(&stream->runtime->sleep); - - mutex_unlock(&stream->device->lock); } /** @@ -957,70 +943,52 @@ static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg) { struct snd_compr_file *data = f->private_data; struct snd_compr_stream *stream; - int retval = -ENOTTY; if (snd_BUG_ON(!data)) return -EFAULT; stream = &data->stream; - mutex_lock(&stream->device->lock); + guard(mutex)(&stream->device->lock); switch (_IOC_NR(cmd)) { case _IOC_NR(SNDRV_COMPRESS_IOCTL_VERSION): - retval = put_user(SNDRV_COMPRESS_VERSION, + return put_user(SNDRV_COMPRESS_VERSION, (int __user *)arg) ? -EFAULT : 0; - break; case _IOC_NR(SNDRV_COMPRESS_GET_CAPS): - retval = snd_compr_get_caps(stream, arg); - break; + return snd_compr_get_caps(stream, arg); #ifndef COMPR_CODEC_CAPS_OVERFLOW case _IOC_NR(SNDRV_COMPRESS_GET_CODEC_CAPS): - retval = snd_compr_get_codec_caps(stream, arg); - break; + return snd_compr_get_codec_caps(stream, arg); #endif case _IOC_NR(SNDRV_COMPRESS_SET_PARAMS): - retval = snd_compr_set_params(stream, arg); - break; + return snd_compr_set_params(stream, arg); case _IOC_NR(SNDRV_COMPRESS_GET_PARAMS): - retval = snd_compr_get_params(stream, arg); - break; + return snd_compr_get_params(stream, arg); case _IOC_NR(SNDRV_COMPRESS_SET_METADATA): - retval = snd_compr_set_metadata(stream, arg); - break; + return snd_compr_set_metadata(stream, arg); case _IOC_NR(SNDRV_COMPRESS_GET_METADATA): - retval = snd_compr_get_metadata(stream, arg); - break; + return snd_compr_get_metadata(stream, arg); case _IOC_NR(SNDRV_COMPRESS_TSTAMP): - retval = snd_compr_tstamp(stream, arg); - break; + return snd_compr_tstamp(stream, arg); case _IOC_NR(SNDRV_COMPRESS_AVAIL): - retval = snd_compr_ioctl_avail(stream, arg); - break; + return snd_compr_ioctl_avail(stream, arg); case _IOC_NR(SNDRV_COMPRESS_PAUSE): - retval = snd_compr_pause(stream); - break; + return snd_compr_pause(stream); case _IOC_NR(SNDRV_COMPRESS_RESUME): - retval = snd_compr_resume(stream); - break; + return snd_compr_resume(stream); case _IOC_NR(SNDRV_COMPRESS_START): - retval = snd_compr_start(stream); - break; + return snd_compr_start(stream); case _IOC_NR(SNDRV_COMPRESS_STOP): - retval = snd_compr_stop(stream); - break; + return snd_compr_stop(stream); case _IOC_NR(SNDRV_COMPRESS_DRAIN): - retval = snd_compr_drain(stream); - break; + return snd_compr_drain(stream); case _IOC_NR(SNDRV_COMPRESS_PARTIAL_DRAIN): - retval = snd_compr_partial_drain(stream); - break; + return snd_compr_partial_drain(stream); case _IOC_NR(SNDRV_COMPRESS_NEXT_TRACK): - retval = snd_compr_next_track(stream); - break; - + return snd_compr_next_track(stream); } - mutex_unlock(&stream->device->lock); - return retval; + + return -ENOTTY; } /* support of 32bit userspace on 64bit platforms */ -- cgit 1.2.3-korg From beb45974dd49068b24788bbfc2abe20d50503761 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Feb 2024 09:52:45 +0100 Subject: ALSA: timer: Use guard() for locking We can simplify the code gracefully with new guard() macro and co for automatic cleanup of locks. For making changes easier, some functions widen the application of register_mutex, but those shouldn't influence on any actual performance. Also, one code block was factored out as a function so that guard() can be applied cleanly without much indentation. There are still a few remaining explicit spin_lock/unlock calls, and those are for the places where we do temporary unlock/relock, which doesn't fit well with the guard(), so far. Only the code refactoring, and no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240227085306.9764-4-tiwai@suse.de --- sound/core/timer.c | 429 +++++++++++++++++++--------------------------- sound/core/timer_compat.c | 7 +- 2 files changed, 177 insertions(+), 259 deletions(-) (limited to 'sound') diff --git a/sound/core/timer.c b/sound/core/timer.c index a595c4fb4b2a0..15b07d09c4b72 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -224,14 +224,12 @@ static int check_matching_master_slave(struct snd_timer_instance *master, return -EBUSY; list_move_tail(&slave->open_list, &master->slave_list_head); master->timer->num_instances++; - spin_lock_irq(&slave_active_lock); - spin_lock(&master->timer->lock); + guard(spinlock_irq)(&slave_active_lock); + guard(spinlock)(&master->timer->lock); slave->master = master; slave->timer = master->timer; if (slave->flags & SNDRV_TIMER_IFLG_RUNNING) list_add_tail(&slave->active_list, &master->slave_active_head); - spin_unlock(&master->timer->lock); - spin_unlock_irq(&slave_active_lock); return 1; } @@ -382,6 +380,25 @@ list_added: } EXPORT_SYMBOL(snd_timer_open); +/* remove slave links, called from snd_timer_close_locked() below */ +static void remove_slave_links(struct snd_timer_instance *timeri, + struct snd_timer *timer) +{ + struct snd_timer_instance *slave, *tmp; + + guard(spinlock_irq)(&slave_active_lock); + guard(spinlock)(&timer->lock); + timeri->timer = NULL; + list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head, open_list) { + list_move_tail(&slave->open_list, &snd_timer_slave_list); + timer->num_instances--; + slave->master = NULL; + slave->timer = NULL; + list_del_init(&slave->ack_list); + list_del_init(&slave->active_list); + } +} + /* * close a timer instance * call this with register_mutex down. @@ -390,12 +407,10 @@ static void snd_timer_close_locked(struct snd_timer_instance *timeri, struct device **card_devp_to_put) { struct snd_timer *timer = timeri->timer; - struct snd_timer_instance *slave, *tmp; if (timer) { - spin_lock_irq(&timer->lock); + guard(spinlock)(&timer->lock); timeri->flags |= SNDRV_TIMER_IFLG_DEAD; - spin_unlock_irq(&timer->lock); } if (!list_empty(&timeri->open_list)) { @@ -418,21 +433,7 @@ static void snd_timer_close_locked(struct snd_timer_instance *timeri, } spin_unlock_irq(&timer->lock); - /* remove slave links */ - spin_lock_irq(&slave_active_lock); - spin_lock(&timer->lock); - timeri->timer = NULL; - list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head, - open_list) { - list_move_tail(&slave->open_list, &snd_timer_slave_list); - timer->num_instances--; - slave->master = NULL; - slave->timer = NULL; - list_del_init(&slave->ack_list); - list_del_init(&slave->active_list); - } - spin_unlock(&timer->lock); - spin_unlock_irq(&slave_active_lock); + remove_slave_links(timeri, timer); /* slave doesn't need to release timer resources below */ if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) @@ -459,9 +460,8 @@ void snd_timer_close(struct snd_timer_instance *timeri) if (snd_BUG_ON(!timeri)) return; - mutex_lock(®ister_mutex); - snd_timer_close_locked(timeri, &card_dev_to_put); - mutex_unlock(®ister_mutex); + scoped_guard(mutex, ®ister_mutex) + snd_timer_close_locked(timeri, &card_dev_to_put); /* put_device() is called after unlock for avoiding deadlock */ if (card_dev_to_put) put_device(card_dev_to_put); @@ -480,15 +480,13 @@ unsigned long snd_timer_resolution(struct snd_timer_instance *timeri) { struct snd_timer * timer; unsigned long ret = 0; - unsigned long flags; if (timeri == NULL) return 0; timer = timeri->timer; if (timer) { - spin_lock_irqsave(&timer->lock, flags); + guard(spinlock_irqsave)(&timer->lock); ret = snd_timer_hw_resolution(timer); - spin_unlock_irqrestore(&timer->lock, flags); } return ret; } @@ -532,26 +530,19 @@ static int snd_timer_start1(struct snd_timer_instance *timeri, { struct snd_timer *timer; int result; - unsigned long flags; timer = timeri->timer; if (!timer) return -EINVAL; - spin_lock_irqsave(&timer->lock, flags); - if (timeri->flags & SNDRV_TIMER_IFLG_DEAD) { - result = -EINVAL; - goto unlock; - } - if (timer->card && timer->card->shutdown) { - result = -ENODEV; - goto unlock; - } + guard(spinlock_irqsave)(&timer->lock); + if (timeri->flags & SNDRV_TIMER_IFLG_DEAD) + return -EINVAL; + if (timer->card && timer->card->shutdown) + return -ENODEV; if (timeri->flags & (SNDRV_TIMER_IFLG_RUNNING | - SNDRV_TIMER_IFLG_START)) { - result = -EBUSY; - goto unlock; - } + SNDRV_TIMER_IFLG_START)) + return -EBUSY; if (start) timeri->ticks = timeri->cticks = ticks; @@ -577,8 +568,6 @@ static int snd_timer_start1(struct snd_timer_instance *timeri, } snd_timer_notify1(timeri, start ? SNDRV_TIMER_EVENT_START : SNDRV_TIMER_EVENT_CONTINUE); - unlock: - spin_unlock_irqrestore(&timer->lock, flags); return result; } @@ -586,53 +575,38 @@ static int snd_timer_start1(struct snd_timer_instance *timeri, static int snd_timer_start_slave(struct snd_timer_instance *timeri, bool start) { - unsigned long flags; - int err; - - spin_lock_irqsave(&slave_active_lock, flags); - if (timeri->flags & SNDRV_TIMER_IFLG_DEAD) { - err = -EINVAL; - goto unlock; - } - if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) { - err = -EBUSY; - goto unlock; - } + guard(spinlock_irqsave)(&slave_active_lock); + if (timeri->flags & SNDRV_TIMER_IFLG_DEAD) + return -EINVAL; + if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) + return -EBUSY; timeri->flags |= SNDRV_TIMER_IFLG_RUNNING; if (timeri->master && timeri->timer) { - spin_lock(&timeri->timer->lock); + guard(spinlock)(&timeri->timer->lock); list_add_tail(&timeri->active_list, &timeri->master->slave_active_head); snd_timer_notify1(timeri, start ? SNDRV_TIMER_EVENT_START : SNDRV_TIMER_EVENT_CONTINUE); - spin_unlock(&timeri->timer->lock); } - err = 1; /* delayed start */ - unlock: - spin_unlock_irqrestore(&slave_active_lock, flags); - return err; + return 1; /* delayed start */ } /* stop/pause a master timer */ static int snd_timer_stop1(struct snd_timer_instance *timeri, bool stop) { struct snd_timer *timer; - int result = 0; - unsigned long flags; timer = timeri->timer; if (!timer) return -EINVAL; - spin_lock_irqsave(&timer->lock, flags); + guard(spinlock_irqsave)(&timer->lock); list_del_init(&timeri->ack_list); list_del_init(&timeri->active_list); if (!(timeri->flags & (SNDRV_TIMER_IFLG_RUNNING | - SNDRV_TIMER_IFLG_START))) { - result = -EBUSY; - goto unlock; - } + SNDRV_TIMER_IFLG_START))) + return -EBUSY; if (timer->card && timer->card->shutdown) - goto unlock; + return 0; if (stop) { timeri->cticks = timeri->ticks; timeri->pticks = 0; @@ -656,30 +630,25 @@ static int snd_timer_stop1(struct snd_timer_instance *timeri, bool stop) timeri->flags |= SNDRV_TIMER_IFLG_PAUSED; snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP : SNDRV_TIMER_EVENT_PAUSE); - unlock: - spin_unlock_irqrestore(&timer->lock, flags); - return result; + return 0; } /* stop/pause a slave timer */ static int snd_timer_stop_slave(struct snd_timer_instance *timeri, bool stop) { - unsigned long flags; bool running; - spin_lock_irqsave(&slave_active_lock, flags); + guard(spinlock_irqsave)(&slave_active_lock); running = timeri->flags & SNDRV_TIMER_IFLG_RUNNING; timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; if (timeri->timer) { - spin_lock(&timeri->timer->lock); + guard(spinlock)(&timeri->timer->lock); list_del_init(&timeri->ack_list); list_del_init(&timeri->active_list); if (running) snd_timer_notify1(timeri, stop ? SNDRV_TIMER_EVENT_STOP : SNDRV_TIMER_EVENT_PAUSE); - spin_unlock(&timeri->timer->lock); } - spin_unlock_irqrestore(&slave_active_lock, flags); return running ? 0 : -EBUSY; } @@ -804,12 +773,9 @@ static void snd_timer_process_callbacks(struct snd_timer *timer, static void snd_timer_clear_callbacks(struct snd_timer *timer, struct list_head *head) { - unsigned long flags; - - spin_lock_irqsave(&timer->lock, flags); + guard(spinlock_irqsave)(&timer->lock); while (!list_empty(head)) list_del_init(head->next); - spin_unlock_irqrestore(&timer->lock, flags); } /* @@ -819,16 +785,14 @@ static void snd_timer_clear_callbacks(struct snd_timer *timer, static void snd_timer_work(struct work_struct *work) { struct snd_timer *timer = container_of(work, struct snd_timer, task_work); - unsigned long flags; if (timer->card && timer->card->shutdown) { snd_timer_clear_callbacks(timer, &timer->sack_list_head); return; } - spin_lock_irqsave(&timer->lock, flags); + guard(spinlock_irqsave)(&timer->lock); snd_timer_process_callbacks(timer, &timer->sack_list_head); - spin_unlock_irqrestore(&timer->lock, flags); } /* @@ -842,8 +806,6 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) struct snd_timer_instance *ti, *ts, *tmp; unsigned long resolution; struct list_head *ack_list_head; - unsigned long flags; - bool use_work = false; if (timer == NULL) return; @@ -853,7 +815,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) return; } - spin_lock_irqsave(&timer->lock, flags); + guard(spinlock_irqsave)(&timer->lock); /* remember the current resolution */ resolution = snd_timer_hw_resolution(timer); @@ -919,10 +881,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) snd_timer_process_callbacks(timer, &timer->ack_list_head); /* do we have any slow callbacks? */ - use_work = !list_empty(&timer->sack_list_head); - spin_unlock_irqrestore(&timer->lock, flags); - - if (use_work) + if (!list_empty(&timer->sack_list_head)) queue_work(system_highpri_wq, &timer->task_work); } EXPORT_SYMBOL(snd_timer_interrupt); @@ -988,7 +947,7 @@ static int snd_timer_free(struct snd_timer *timer) if (!timer) return 0; - mutex_lock(®ister_mutex); + guard(mutex)(®ister_mutex); if (! list_empty(&timer->open_list_head)) { struct list_head *p, *n; struct snd_timer_instance *ti; @@ -1000,7 +959,6 @@ static int snd_timer_free(struct snd_timer *timer) } } list_del(&timer->device_list); - mutex_unlock(®ister_mutex); if (timer->private_free) timer->private_free(timer); @@ -1025,7 +983,7 @@ static int snd_timer_dev_register(struct snd_device *dev) !timer->hw.resolution && timer->hw.c_resolution == NULL) return -EINVAL; - mutex_lock(®ister_mutex); + guard(mutex)(®ister_mutex); list_for_each_entry(timer1, &snd_timer_list, device_list) { if (timer1->tmr_class > timer->tmr_class) break; @@ -1046,11 +1004,9 @@ static int snd_timer_dev_register(struct snd_device *dev) if (timer1->tmr_subdevice < timer->tmr_subdevice) continue; /* conflicts.. */ - mutex_unlock(®ister_mutex); return -EBUSY; } list_add_tail(&timer->device_list, &timer1->device_list); - mutex_unlock(®ister_mutex); return 0; } @@ -1059,20 +1015,18 @@ static int snd_timer_dev_disconnect(struct snd_device *device) struct snd_timer *timer = device->device_data; struct snd_timer_instance *ti; - mutex_lock(®ister_mutex); + guard(mutex)(®ister_mutex); list_del_init(&timer->device_list); /* wake up pending sleepers */ list_for_each_entry(ti, &timer->open_list_head, open_list) { if (ti->disconnect) ti->disconnect(ti); } - mutex_unlock(®ister_mutex); return 0; } void snd_timer_notify(struct snd_timer *timer, int event, struct timespec64 *tstamp) { - unsigned long flags; unsigned long resolution = 0; struct snd_timer_instance *ti, *ts; @@ -1083,7 +1037,7 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec64 *tst if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_MSTART || event > SNDRV_TIMER_EVENT_MRESUME)) return; - spin_lock_irqsave(&timer->lock, flags); + guard(spinlock_irqsave)(&timer->lock); if (event == SNDRV_TIMER_EVENT_MSTART || event == SNDRV_TIMER_EVENT_MCONTINUE || event == SNDRV_TIMER_EVENT_MRESUME) @@ -1095,7 +1049,6 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec64 *tst if (ts->ccallback) ts->ccallback(ts, event, tstamp, resolution); } - spin_unlock_irqrestore(&timer->lock, flags); } EXPORT_SYMBOL(snd_timer_notify); @@ -1248,7 +1201,7 @@ static void snd_timer_proc_read(struct snd_info_entry *entry, struct snd_timer_instance *ti; unsigned long resolution; - mutex_lock(®ister_mutex); + guard(mutex)(®ister_mutex); list_for_each_entry(timer, &snd_timer_list, device_list) { if (timer->card && timer->card->shutdown) continue; @@ -1270,9 +1223,8 @@ static void snd_timer_proc_read(struct snd_info_entry *entry, timer->tmr_device, timer->tmr_subdevice); } snd_iprintf(buffer, "%s :", timer->name); - spin_lock_irq(&timer->lock); - resolution = snd_timer_hw_resolution(timer); - spin_unlock_irq(&timer->lock); + scoped_guard(spinlock_irq, &timer->lock) + resolution = snd_timer_hw_resolution(timer); if (resolution) snd_iprintf(buffer, " %lu.%03luus (%lu ticks)", resolution / 1000, @@ -1288,7 +1240,6 @@ static void snd_timer_proc_read(struct snd_info_entry *entry, SNDRV_TIMER_IFLG_RUNNING)) ? "running" : "stopped"); } - mutex_unlock(®ister_mutex); } static struct snd_info_entry *snd_timer_proc_entry; @@ -1329,7 +1280,7 @@ static void snd_timer_user_interrupt(struct snd_timer_instance *timeri, struct snd_timer_read *r; int prev; - spin_lock(&tu->qlock); + guard(spinlock)(&tu->qlock); if (tu->qused > 0) { prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1; r = &tu->queue[prev]; @@ -1348,7 +1299,6 @@ static void snd_timer_user_interrupt(struct snd_timer_instance *timeri, tu->qused++; } __wake: - spin_unlock(&tu->qlock); snd_kill_fasync(tu->fasync, SIGIO, POLL_IN); wake_up(&tu->qchange_sleep); } @@ -1372,7 +1322,6 @@ static void snd_timer_user_ccallback(struct snd_timer_instance *timeri, { struct snd_timer_user *tu = timeri->callback_data; struct snd_timer_tread64 r1; - unsigned long flags; if (event >= SNDRV_TIMER_EVENT_START && event <= SNDRV_TIMER_EVENT_PAUSE) @@ -1384,9 +1333,8 @@ static void snd_timer_user_ccallback(struct snd_timer_instance *timeri, r1.tstamp_sec = tstamp->tv_sec; r1.tstamp_nsec = tstamp->tv_nsec; r1.val = resolution; - spin_lock_irqsave(&tu->qlock, flags); - snd_timer_user_append_to_tqueue(tu, &r1); - spin_unlock_irqrestore(&tu->qlock, flags); + scoped_guard(spinlock_irqsave, &tu->qlock) + snd_timer_user_append_to_tqueue(tu, &r1); snd_kill_fasync(tu->fasync, SIGIO, POLL_IN); wake_up(&tu->qchange_sleep); } @@ -1410,51 +1358,48 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri, memset(&r1, 0, sizeof(r1)); memset(&tstamp, 0, sizeof(tstamp)); - spin_lock(&tu->qlock); - if ((tu->filter & ((1 << SNDRV_TIMER_EVENT_RESOLUTION) | - (1 << SNDRV_TIMER_EVENT_TICK))) == 0) { - spin_unlock(&tu->qlock); - return; - } - if (tu->last_resolution != resolution || ticks > 0) { - if (timer_tstamp_monotonic) - ktime_get_ts64(&tstamp); - else - ktime_get_real_ts64(&tstamp); - } - if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) && - tu->last_resolution != resolution) { - r1.event = SNDRV_TIMER_EVENT_RESOLUTION; + scoped_guard(spinlock, &tu->qlock) { + if ((tu->filter & ((1 << SNDRV_TIMER_EVENT_RESOLUTION) | + (1 << SNDRV_TIMER_EVENT_TICK))) == 0) + return; + if (tu->last_resolution != resolution || ticks > 0) { + if (timer_tstamp_monotonic) + ktime_get_ts64(&tstamp); + else + ktime_get_real_ts64(&tstamp); + } + if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) && + tu->last_resolution != resolution) { + r1.event = SNDRV_TIMER_EVENT_RESOLUTION; + r1.tstamp_sec = tstamp.tv_sec; + r1.tstamp_nsec = tstamp.tv_nsec; + r1.val = resolution; + snd_timer_user_append_to_tqueue(tu, &r1); + tu->last_resolution = resolution; + append++; + } + if ((tu->filter & (1 << SNDRV_TIMER_EVENT_TICK)) == 0) + break; + if (ticks == 0) + break; + if (tu->qused > 0) { + prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1; + r = &tu->tqueue[prev]; + if (r->event == SNDRV_TIMER_EVENT_TICK) { + r->tstamp_sec = tstamp.tv_sec; + r->tstamp_nsec = tstamp.tv_nsec; + r->val += ticks; + append++; + break; + } + } + r1.event = SNDRV_TIMER_EVENT_TICK; r1.tstamp_sec = tstamp.tv_sec; r1.tstamp_nsec = tstamp.tv_nsec; - r1.val = resolution; + r1.val = ticks; snd_timer_user_append_to_tqueue(tu, &r1); - tu->last_resolution = resolution; append++; } - if ((tu->filter & (1 << SNDRV_TIMER_EVENT_TICK)) == 0) - goto __wake; - if (ticks == 0) - goto __wake; - if (tu->qused > 0) { - prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1; - r = &tu->tqueue[prev]; - if (r->event == SNDRV_TIMER_EVENT_TICK) { - r->tstamp_sec = tstamp.tv_sec; - r->tstamp_nsec = tstamp.tv_nsec; - r->val += ticks; - append++; - goto __wake; - } - } - r1.event = SNDRV_TIMER_EVENT_TICK; - r1.tstamp_sec = tstamp.tv_sec; - r1.tstamp_nsec = tstamp.tv_nsec; - r1.val = ticks; - snd_timer_user_append_to_tqueue(tu, &r1); - append++; - __wake: - spin_unlock(&tu->qlock); if (append == 0) return; snd_kill_fasync(tu->fasync, SIGIO, POLL_IN); @@ -1476,14 +1421,13 @@ static int realloc_user_queue(struct snd_timer_user *tu, int size) return -ENOMEM; } - spin_lock_irq(&tu->qlock); + guard(spinlock_irq)(&tu->qlock); kfree(tu->queue); kfree(tu->tqueue); tu->queue_size = size; tu->queue = queue; tu->tqueue = tqueue; tu->qhead = tu->qtail = tu->qused = 0; - spin_unlock_irq(&tu->qlock); return 0; } @@ -1519,12 +1463,12 @@ static int snd_timer_user_release(struct inode *inode, struct file *file) if (file->private_data) { tu = file->private_data; file->private_data = NULL; - mutex_lock(&tu->ioctl_lock); - if (tu->timeri) { - snd_timer_close(tu->timeri); - snd_timer_instance_free(tu->timeri); + scoped_guard(mutex, &tu->ioctl_lock) { + if (tu->timeri) { + snd_timer_close(tu->timeri); + snd_timer_instance_free(tu->timeri); + } } - mutex_unlock(&tu->ioctl_lock); snd_fasync_free(tu->fasync); kfree(tu->queue); kfree(tu->tqueue); @@ -1559,7 +1503,7 @@ static int snd_timer_user_next_device(struct snd_timer_id __user *_tid) if (copy_from_user(&id, _tid, sizeof(id))) return -EFAULT; - mutex_lock(®ister_mutex); + guard(mutex)(®ister_mutex); if (id.dev_class < 0) { /* first item */ if (list_empty(&snd_timer_list)) snd_timer_user_zero_id(&id); @@ -1636,7 +1580,6 @@ static int snd_timer_user_next_device(struct snd_timer_id __user *_tid) snd_timer_user_zero_id(&id); } } - mutex_unlock(®ister_mutex); if (copy_to_user(_tid, &id, sizeof(*_tid))) return -EFAULT; return 0; @@ -1649,7 +1592,6 @@ static int snd_timer_user_ginfo(struct file *file, struct snd_timer_id tid; struct snd_timer *t; struct list_head *p; - int err = 0; ginfo = memdup_user(_ginfo, sizeof(*ginfo)); if (IS_ERR(ginfo)) @@ -1658,56 +1600,42 @@ static int snd_timer_user_ginfo(struct file *file, tid = ginfo->tid; memset(ginfo, 0, sizeof(*ginfo)); ginfo->tid = tid; - mutex_lock(®ister_mutex); + guard(mutex)(®ister_mutex); t = snd_timer_find(&tid); - if (t != NULL) { - ginfo->card = t->card ? t->card->number : -1; - if (t->hw.flags & SNDRV_TIMER_HW_SLAVE) - ginfo->flags |= SNDRV_TIMER_FLG_SLAVE; - strscpy(ginfo->id, t->id, sizeof(ginfo->id)); - strscpy(ginfo->name, t->name, sizeof(ginfo->name)); - spin_lock_irq(&t->lock); + if (!t) + return -ENODEV; + ginfo->card = t->card ? t->card->number : -1; + if (t->hw.flags & SNDRV_TIMER_HW_SLAVE) + ginfo->flags |= SNDRV_TIMER_FLG_SLAVE; + strscpy(ginfo->id, t->id, sizeof(ginfo->id)); + strscpy(ginfo->name, t->name, sizeof(ginfo->name)); + scoped_guard(spinlock_irq, &t->lock) ginfo->resolution = snd_timer_hw_resolution(t); - spin_unlock_irq(&t->lock); - if (t->hw.resolution_min > 0) { - ginfo->resolution_min = t->hw.resolution_min; - ginfo->resolution_max = t->hw.resolution_max; - } - list_for_each(p, &t->open_list_head) { - ginfo->clients++; - } - } else { - err = -ENODEV; + if (t->hw.resolution_min > 0) { + ginfo->resolution_min = t->hw.resolution_min; + ginfo->resolution_max = t->hw.resolution_max; } - mutex_unlock(®ister_mutex); - if (err >= 0 && copy_to_user(_ginfo, ginfo, sizeof(*ginfo))) - err = -EFAULT; - return err; + list_for_each(p, &t->open_list_head) { + ginfo->clients++; + } + if (copy_to_user(_ginfo, ginfo, sizeof(*ginfo))) + return -EFAULT; + return 0; } static int timer_set_gparams(struct snd_timer_gparams *gparams) { struct snd_timer *t; - int err; - mutex_lock(®ister_mutex); + guard(mutex)(®ister_mutex); t = snd_timer_find(&gparams->tid); - if (!t) { - err = -ENODEV; - goto _error; - } - if (!list_empty(&t->open_list_head)) { - err = -EBUSY; - goto _error; - } - if (!t->hw.set_period) { - err = -ENOSYS; - goto _error; - } - err = t->hw.set_period(t, gparams->period_num, gparams->period_den); -_error: - mutex_unlock(®ister_mutex); - return err; + if (!t) + return -ENODEV; + if (!list_empty(&t->open_list_head)) + return -EBUSY; + if (!t->hw.set_period) + return -ENOSYS; + return t->hw.set_period(t, gparams->period_num, gparams->period_den); } static int snd_timer_user_gparams(struct file *file, @@ -1733,10 +1661,10 @@ static int snd_timer_user_gstatus(struct file *file, tid = gstatus.tid; memset(&gstatus, 0, sizeof(gstatus)); gstatus.tid = tid; - mutex_lock(®ister_mutex); + guard(mutex)(®ister_mutex); t = snd_timer_find(&tid); if (t != NULL) { - spin_lock_irq(&t->lock); + guard(spinlock_irq)(&t->lock); gstatus.resolution = snd_timer_hw_resolution(t); if (t->hw.precise_resolution) { t->hw.precise_resolution(t, &gstatus.resolution_num, @@ -1745,11 +1673,9 @@ static int snd_timer_user_gstatus(struct file *file, gstatus.resolution_num = gstatus.resolution; gstatus.resolution_den = 1000000000uL; } - spin_unlock_irq(&t->lock); } else { err = -ENODEV; } - mutex_unlock(®ister_mutex); if (err >= 0 && copy_to_user(_gstatus, &gstatus, sizeof(gstatus))) err = -EFAULT; return err; @@ -1821,9 +1747,8 @@ static int snd_timer_user_info(struct file *file, info->flags |= SNDRV_TIMER_FLG_SLAVE; strscpy(info->id, t->id, sizeof(info->id)); strscpy(info->name, t->name, sizeof(info->name)); - spin_lock_irq(&t->lock); - info->resolution = snd_timer_hw_resolution(t); - spin_unlock_irq(&t->lock); + scoped_guard(spinlock_irq, &t->lock) + info->resolution = snd_timer_hw_resolution(t); if (copy_to_user(_info, info, sizeof(*_info))) return -EFAULT; return 0; @@ -1884,45 +1809,47 @@ static int snd_timer_user_params(struct file *file, goto _end; } snd_timer_stop(tu->timeri); - spin_lock_irq(&t->lock); - tu->timeri->flags &= ~(SNDRV_TIMER_IFLG_AUTO| - SNDRV_TIMER_IFLG_EXCLUSIVE| - SNDRV_TIMER_IFLG_EARLY_EVENT); - if (params.flags & SNDRV_TIMER_PSFLG_AUTO) - tu->timeri->flags |= SNDRV_TIMER_IFLG_AUTO; - if (params.flags & SNDRV_TIMER_PSFLG_EXCLUSIVE) - tu->timeri->flags |= SNDRV_TIMER_IFLG_EXCLUSIVE; - if (params.flags & SNDRV_TIMER_PSFLG_EARLY_EVENT) - tu->timeri->flags |= SNDRV_TIMER_IFLG_EARLY_EVENT; - spin_unlock_irq(&t->lock); + scoped_guard(spinlock_irq, &t->lock) { + tu->timeri->flags &= ~(SNDRV_TIMER_IFLG_AUTO| + SNDRV_TIMER_IFLG_EXCLUSIVE| + SNDRV_TIMER_IFLG_EARLY_EVENT); + if (params.flags & SNDRV_TIMER_PSFLG_AUTO) + tu->timeri->flags |= SNDRV_TIMER_IFLG_AUTO; + if (params.flags & SNDRV_TIMER_PSFLG_EXCLUSIVE) + tu->timeri->flags |= SNDRV_TIMER_IFLG_EXCLUSIVE; + if (params.flags & SNDRV_TIMER_PSFLG_EARLY_EVENT) + tu->timeri->flags |= SNDRV_TIMER_IFLG_EARLY_EVENT; + } if (params.queue_size > 0 && (unsigned int)tu->queue_size != params.queue_size) { err = realloc_user_queue(tu, params.queue_size); if (err < 0) goto _end; } - spin_lock_irq(&tu->qlock); - tu->qhead = tu->qtail = tu->qused = 0; - if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) { - if (tu->tread) { - struct snd_timer_tread64 tread; - memset(&tread, 0, sizeof(tread)); - tread.event = SNDRV_TIMER_EVENT_EARLY; - tread.tstamp_sec = 0; - tread.tstamp_nsec = 0; - tread.val = 0; - snd_timer_user_append_to_tqueue(tu, &tread); - } else { - struct snd_timer_read *r = &tu->queue[0]; - r->resolution = 0; - r->ticks = 0; - tu->qused++; - tu->qtail++; + scoped_guard(spinlock_irq, &tu->qlock) { + tu->qhead = tu->qtail = tu->qused = 0; + if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) { + if (tu->tread) { + struct snd_timer_tread64 tread; + + memset(&tread, 0, sizeof(tread)); + tread.event = SNDRV_TIMER_EVENT_EARLY; + tread.tstamp_sec = 0; + tread.tstamp_nsec = 0; + tread.val = 0; + snd_timer_user_append_to_tqueue(tu, &tread); + } else { + struct snd_timer_read *r = &tu->queue[0]; + + r->resolution = 0; + r->ticks = 0; + tu->qused++; + tu->qtail++; + } } + tu->filter = params.filter; + tu->ticks = params.ticks; } - tu->filter = params.filter; - tu->ticks = params.ticks; - spin_unlock_irq(&tu->qlock); err = 0; _end: if (copy_to_user(_params, ¶ms, sizeof(params))) @@ -1945,9 +1872,8 @@ static int snd_timer_user_status32(struct file *file, status.resolution = snd_timer_resolution(tu->timeri); status.lost = tu->timeri->lost; status.overrun = tu->overrun; - spin_lock_irq(&tu->qlock); - status.queue = tu->qused; - spin_unlock_irq(&tu->qlock); + scoped_guard(spinlock_irq, &tu->qlock) + status.queue = tu->qused; if (copy_to_user(_status, &status, sizeof(status))) return -EFAULT; return 0; @@ -1968,9 +1894,8 @@ static int snd_timer_user_status64(struct file *file, status.resolution = snd_timer_resolution(tu->timeri); status.lost = tu->timeri->lost; status.overrun = tu->overrun; - spin_lock_irq(&tu->qlock); - status.queue = tu->qused; - spin_unlock_irq(&tu->qlock); + scoped_guard(spinlock_irq, &tu->qlock) + status.queue = tu->qused; if (copy_to_user(_status, &status, sizeof(status))) return -EFAULT; return 0; @@ -2128,12 +2053,9 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct snd_timer_user *tu = file->private_data; - long ret; - mutex_lock(&tu->ioctl_lock); - ret = __snd_timer_user_ioctl(file, cmd, arg, false); - mutex_unlock(&tu->ioctl_lock); - return ret; + guard(mutex)(&tu->ioctl_lock); + return __snd_timer_user_ioctl(file, cmd, arg, false); } static int snd_timer_user_fasync(int fd, struct file * file, int on) @@ -2260,12 +2182,11 @@ static __poll_t snd_timer_user_poll(struct file *file, poll_table * wait) poll_wait(file, &tu->qchange_sleep, wait); mask = 0; - spin_lock_irq(&tu->qlock); + guard(spinlock_irq)(&tu->qlock); if (tu->qused) mask |= EPOLLIN | EPOLLRDNORM; if (tu->disconnected) mask |= EPOLLERR; - spin_unlock_irq(&tu->qlock); return mask; } diff --git a/sound/core/timer_compat.c b/sound/core/timer_compat.c index ee973b7b80449..4ae9eaeb5afb1 100644 --- a/sound/core/timer_compat.c +++ b/sound/core/timer_compat.c @@ -115,10 +115,7 @@ static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) { struct snd_timer_user *tu = file->private_data; - long ret; - mutex_lock(&tu->ioctl_lock); - ret = __snd_timer_user_ioctl_compat(file, cmd, arg); - mutex_unlock(&tu->ioctl_lock); - return ret; + guard(mutex)(&tu->ioctl_lock); + return __snd_timer_user_ioctl_compat(file, cmd, arg); } -- cgit 1.2.3-korg From b04892691d2659a592eaaa0444d60eb12cfa4df8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Feb 2024 09:52:46 +0100 Subject: ALSA: hrtimer: Use guard() for locking We can simplify the code gracefully with new guard() macro and co for automatic cleanup of locks. Only the code refactoring, and no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240227085306.9764-5-tiwai@suse.de --- sound/core/hrtimer.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/core/hrtimer.c b/sound/core/hrtimer.c index e97ff8cccb643..147c1fea4708e 100644 --- a/sound/core/hrtimer.c +++ b/sound/core/hrtimer.c @@ -35,12 +35,12 @@ static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt) unsigned long ticks; enum hrtimer_restart ret = HRTIMER_NORESTART; - spin_lock(&t->lock); - if (!t->running) - goto out; /* fast path */ - stime->in_callback = true; - ticks = t->sticks; - spin_unlock(&t->lock); + scoped_guard(spinlock, &t->lock) { + if (!t->running) + return HRTIMER_NORESTART; /* fast path */ + stime->in_callback = true; + ticks = t->sticks; + } /* calculate the drift */ delta = ktime_sub(hrt->base->get_time(), hrtimer_get_expires(hrt)); @@ -49,15 +49,13 @@ static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt) snd_timer_interrupt(stime->timer, ticks); - spin_lock(&t->lock); + guard(spinlock)(&t->lock); if (t->running) { hrtimer_add_expires_ns(hrt, t->sticks * resolution); ret = HRTIMER_RESTART; } stime->in_callback = false; - out: - spin_unlock(&t->lock); return ret; } @@ -80,10 +78,10 @@ static int snd_hrtimer_close(struct snd_timer *t) struct snd_hrtimer *stime = t->private_data; if (stime) { - spin_lock_irq(&t->lock); - t->running = 0; /* just to be sure */ - stime->in_callback = 1; /* skip start/stop */ - spin_unlock_irq(&t->lock); + scoped_guard(spinlock_irq, &t->lock) { + t->running = 0; /* just to be sure */ + stime->in_callback = 1; /* skip start/stop */ + } hrtimer_cancel(&stime->hrt); kfree(stime); -- cgit 1.2.3-korg From e6684d08cc1935774b07efc262e70b41ac1c0f93 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Feb 2024 09:52:47 +0100 Subject: ALSA: hwdep: Use guard() for locking We can simplify the code gracefully with new guard() macro and co for automatic cleanup of locks. There are still a few remaining explicit mutex_lock/unlock calls, and those are for the places where we do temporary unlock/relock, which doesn't fit well with the guard(), so far. Only the code refactoring, and no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240227085306.9764-6-tiwai@suse.de --- sound/core/hwdep.c | 89 ++++++++++++++++++++++++------------------------------ 1 file changed, 40 insertions(+), 49 deletions(-) (limited to 'sound') diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index de7476034f2cf..9d7e5039c8930 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c @@ -149,12 +149,12 @@ static int snd_hwdep_release(struct inode *inode, struct file * file) struct snd_hwdep *hw = file->private_data; struct module *mod = hw->card->module; - mutex_lock(&hw->open_mutex); - if (hw->ops.release) - err = hw->ops.release(hw, file); - if (hw->used > 0) - hw->used--; - mutex_unlock(&hw->open_mutex); + scoped_guard(mutex, &hw->open_mutex) { + if (hw->ops.release) + err = hw->ops.release(hw, file); + if (hw->used > 0) + hw->used--; + } wake_up(&hw->open_wait); snd_card_file_remove(hw->card, file); @@ -272,43 +272,43 @@ static int snd_hwdep_control_ioctl(struct snd_card *card, if (get_user(device, (int __user *)arg)) return -EFAULT; - mutex_lock(®ister_mutex); - - if (device < 0) - device = 0; - else if (device < SNDRV_MINOR_HWDEPS) - device++; - else - device = SNDRV_MINOR_HWDEPS; - - while (device < SNDRV_MINOR_HWDEPS) { - if (snd_hwdep_search(card, device)) - break; - device++; + + scoped_guard(mutex, ®ister_mutex) { + if (device < 0) + device = 0; + else if (device < SNDRV_MINOR_HWDEPS) + device++; + else + device = SNDRV_MINOR_HWDEPS; + + while (device < SNDRV_MINOR_HWDEPS) { + if (snd_hwdep_search(card, device)) + break; + device++; + } + if (device >= SNDRV_MINOR_HWDEPS) + device = -1; + if (put_user(device, (int __user *)arg)) + return -EFAULT; + return 0; } - if (device >= SNDRV_MINOR_HWDEPS) - device = -1; - mutex_unlock(®ister_mutex); - if (put_user(device, (int __user *)arg)) - return -EFAULT; - return 0; + break; } case SNDRV_CTL_IOCTL_HWDEP_INFO: { struct snd_hwdep_info __user *info = (struct snd_hwdep_info __user *)arg; - int device, err; + int device; struct snd_hwdep *hwdep; if (get_user(device, &info->device)) return -EFAULT; - mutex_lock(®ister_mutex); - hwdep = snd_hwdep_search(card, device); - if (hwdep) - err = snd_hwdep_info(hwdep, info); - else - err = -ENXIO; - mutex_unlock(®ister_mutex); - return err; + scoped_guard(mutex, ®ister_mutex) { + hwdep = snd_hwdep_search(card, device); + if (!hwdep) + return -ENXIO; + return snd_hwdep_info(hwdep, info); + } + break; } } return -ENOIOCTLCMD; @@ -422,11 +422,9 @@ static int snd_hwdep_dev_register(struct snd_device *device) struct snd_card *card = hwdep->card; int err; - mutex_lock(®ister_mutex); - if (snd_hwdep_search(card, hwdep->device)) { - mutex_unlock(®ister_mutex); + guard(mutex)(®ister_mutex); + if (snd_hwdep_search(card, hwdep->device)) return -EBUSY; - } list_add_tail(&hwdep->list, &snd_hwdep_devices); err = snd_register_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device, @@ -434,7 +432,6 @@ static int snd_hwdep_dev_register(struct snd_device *device) if (err < 0) { dev_err(hwdep->dev, "unable to register\n"); list_del(&hwdep->list); - mutex_unlock(®ister_mutex); return err; } @@ -454,7 +451,6 @@ static int snd_hwdep_dev_register(struct snd_device *device) hwdep->ossreg = 1; } #endif - mutex_unlock(®ister_mutex); return 0; } @@ -464,12 +460,10 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device) if (snd_BUG_ON(!hwdep)) return -ENXIO; - mutex_lock(®ister_mutex); - if (snd_hwdep_search(hwdep->card, hwdep->device) != hwdep) { - mutex_unlock(®ister_mutex); + guard(mutex)(®ister_mutex); + if (snd_hwdep_search(hwdep->card, hwdep->device) != hwdep) return -EINVAL; - } - mutex_lock(&hwdep->open_mutex); + guard(mutex)(&hwdep->open_mutex); wake_up(&hwdep->open_wait); #ifdef CONFIG_SND_OSSEMUL if (hwdep->ossreg) @@ -477,8 +471,6 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device) #endif snd_unregister_device(hwdep->dev); list_del_init(&hwdep->list); - mutex_unlock(&hwdep->open_mutex); - mutex_unlock(®ister_mutex); return 0; } @@ -492,11 +484,10 @@ static void snd_hwdep_proc_read(struct snd_info_entry *entry, { struct snd_hwdep *hwdep; - mutex_lock(®ister_mutex); + guard(mutex)(®ister_mutex); list_for_each_entry(hwdep, &snd_hwdep_devices, list) snd_iprintf(buffer, "%02i-%02i: %s\n", hwdep->card->number, hwdep->device, hwdep->name); - mutex_unlock(®ister_mutex); } static struct snd_info_entry *snd_hwdep_proc_entry; -- cgit 1.2.3-korg From 4b72362b1228d9aad684e4fcaa422d9562066fe1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Feb 2024 09:52:48 +0100 Subject: ALSA: info: Use guard() for locking We can simplify the code gracefully with new guard() macro and co for automatic cleanup of locks. Only the code refactoring, and no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240227085306.9764-7-tiwai@suse.de --- sound/core/info.c | 93 +++++++++++++++++---------------------------------- sound/core/info_oss.c | 10 ++---- 2 files changed, 33 insertions(+), 70 deletions(-) (limited to 'sound') diff --git a/sound/core/info.c b/sound/core/info.c index e2f302e55bbb2..1f5b8a3d9e3b6 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -105,17 +105,15 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig) { struct snd_info_private_data *data; struct snd_info_entry *entry; - loff_t ret = -EINVAL, size; + loff_t size; data = file->private_data; entry = data->entry; - mutex_lock(&entry->access); - if (entry->c.ops->llseek) { - ret = entry->c.ops->llseek(entry, - data->file_private_data, - file, offset, orig); - goto out; - } + guard(mutex)(&entry->access); + if (entry->c.ops->llseek) + return entry->c.ops->llseek(entry, + data->file_private_data, + file, offset, orig); size = entry->size; switch (orig) { @@ -126,21 +124,18 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig) break; case SEEK_END: if (!size) - goto out; + return -EINVAL; offset += size; break; default: - goto out; + return -EINVAL; } if (offset < 0) - goto out; + return -EINVAL; if (size && offset > size) offset = size; file->f_pos = offset; - ret = offset; - out: - mutex_unlock(&entry->access); - return ret; + return offset; } static ssize_t snd_info_entry_read(struct file *file, char __user *buffer, @@ -238,10 +233,10 @@ static int snd_info_entry_open(struct inode *inode, struct file *file) struct snd_info_private_data *data; int mode, err; - mutex_lock(&info_mutex); + guard(mutex)(&info_mutex); err = alloc_info_private(entry, &data); if (err < 0) - goto unlock; + return err; mode = file->f_flags & O_ACCMODE; if (((mode == O_RDONLY || mode == O_RDWR) && !entry->c.ops->read) || @@ -257,14 +252,11 @@ static int snd_info_entry_open(struct inode *inode, struct file *file) } file->private_data = data; - mutex_unlock(&info_mutex); return 0; error: kfree(data); module_put(entry->module); - unlock: - mutex_unlock(&info_mutex); return err; } @@ -306,7 +298,6 @@ static ssize_t snd_info_text_entry_write(struct file *file, struct snd_info_buffer *buf; loff_t pos; size_t next; - int err = 0; if (!entry->c.text.write) return -EIO; @@ -317,34 +308,24 @@ static ssize_t snd_info_text_entry_write(struct file *file, /* don't handle too large text inputs */ if (next > 16 * 1024) return -EIO; - mutex_lock(&entry->access); + guard(mutex)(&entry->access); buf = data->wbuffer; if (!buf) { data->wbuffer = buf = kzalloc(sizeof(*buf), GFP_KERNEL); - if (!buf) { - err = -ENOMEM; - goto error; - } + if (!buf) + return -ENOMEM; } if (next > buf->len) { char *nbuf = kvzalloc(PAGE_ALIGN(next), GFP_KERNEL); - if (!nbuf) { - err = -ENOMEM; - goto error; - } + if (!nbuf) + return -ENOMEM; kvfree(buf->buffer); buf->buffer = nbuf; buf->len = PAGE_ALIGN(next); } - if (copy_from_user(buf->buffer + pos, buffer, count)) { - err = -EFAULT; - goto error; - } + if (copy_from_user(buf->buffer + pos, buffer, count)) + return -EFAULT; buf->size = next; - error: - mutex_unlock(&entry->access); - if (err < 0) - return err; *offset = next; return count; } @@ -369,10 +350,10 @@ static int snd_info_text_entry_open(struct inode *inode, struct file *file) struct snd_info_private_data *data; int err; - mutex_lock(&info_mutex); + guard(mutex)(&info_mutex); err = alloc_info_private(entry, &data); if (err < 0) - goto unlock; + return err; data->rbuffer = kzalloc(sizeof(*data->rbuffer), GFP_KERNEL); if (!data->rbuffer) { @@ -386,15 +367,12 @@ static int snd_info_text_entry_open(struct inode *inode, struct file *file) err = single_open(file, snd_info_seq_show, data); if (err < 0) goto error; - mutex_unlock(&info_mutex); return 0; error: kfree(data->rbuffer); kfree(data); module_put(entry->module); - unlock: - mutex_unlock(&info_mutex); return err; } @@ -549,7 +527,7 @@ int snd_info_card_register(struct snd_card *card) */ void snd_info_card_id_change(struct snd_card *card) { - mutex_lock(&info_mutex); + guard(mutex)(&info_mutex); if (card->proc_root_link) { proc_remove(card->proc_root_link); card->proc_root_link = NULL; @@ -558,7 +536,6 @@ void snd_info_card_id_change(struct snd_card *card) card->proc_root_link = proc_symlink(card->id, snd_proc_root->p, card->proc_root->name); - mutex_unlock(&info_mutex); } /* @@ -574,12 +551,11 @@ void snd_info_card_disconnect(struct snd_card *card) if (card->proc_root) proc_remove(card->proc_root->p); - mutex_lock(&info_mutex); + guard(mutex)(&info_mutex); if (card->proc_root) snd_info_clear_entries(card->proc_root); card->proc_root_link = NULL; card->proc_root = NULL; - mutex_unlock(&info_mutex); } /* @@ -703,9 +679,8 @@ snd_info_create_entry(const char *name, struct snd_info_entry *parent, entry->parent = parent; entry->module = module; if (parent) { - mutex_lock(&parent->access); + guard(mutex)(&parent->access); list_add_tail(&entry->list, &parent->children); - mutex_unlock(&parent->access); } return entry; } @@ -775,9 +750,8 @@ void snd_info_free_entry(struct snd_info_entry * entry) return; if (entry->p) { proc_remove(entry->p); - mutex_lock(&info_mutex); + guard(mutex)(&info_mutex); snd_info_clear_entries(entry); - mutex_unlock(&info_mutex); } /* free all children at first */ @@ -786,9 +760,8 @@ void snd_info_free_entry(struct snd_info_entry * entry) p = entry->parent; if (p) { - mutex_lock(&p->access); + guard(mutex)(&p->access); list_del(&entry->list); - mutex_unlock(&p->access); } kfree(entry->name); if (entry->private_free) @@ -804,15 +777,13 @@ static int __snd_info_register(struct snd_info_entry *entry) if (snd_BUG_ON(!entry)) return -ENXIO; root = entry->parent == NULL ? snd_proc_root->p : entry->parent->p; - mutex_lock(&info_mutex); + guard(mutex)(&info_mutex); if (entry->p || !root) - goto unlock; + return 0; if (S_ISDIR(entry->mode)) { p = proc_mkdir_mode(entry->name, entry->mode, root); - if (!p) { - mutex_unlock(&info_mutex); + if (!p) return -ENOMEM; - } } else { const struct proc_ops *ops; if (entry->content == SNDRV_INFO_CONTENT_DATA) @@ -821,15 +792,11 @@ static int __snd_info_register(struct snd_info_entry *entry) ops = &snd_info_text_entry_ops; p = proc_create_data(entry->name, entry->mode, root, ops, entry); - if (!p) { - mutex_unlock(&info_mutex); + if (!p) return -ENOMEM; - } proc_set_size(p, entry->size); } entry->p = p; - unlock: - mutex_unlock(&info_mutex); return 0; } diff --git a/sound/core/info_oss.c b/sound/core/info_oss.c index ebc714b2f46b3..0dbbb80055700 100644 --- a/sound/core/info_oss.c +++ b/sound/core/info_oss.c @@ -29,20 +29,17 @@ int snd_oss_info_register(int dev, int num, char *string) return -ENXIO; if (snd_BUG_ON(num < 0 || num >= SNDRV_CARDS)) return -ENXIO; - mutex_lock(&strings); + guard(mutex)(&strings); if (string == NULL) { x = snd_sndstat_strings[num][dev]; kfree(x); x = NULL; } else { x = kstrdup(string, GFP_KERNEL); - if (x == NULL) { - mutex_unlock(&strings); + if (x == NULL) return -ENOMEM; - } } snd_sndstat_strings[num][dev] = x; - mutex_unlock(&strings); return 0; } EXPORT_SYMBOL(snd_oss_info_register); @@ -53,7 +50,7 @@ static int snd_sndstat_show_strings(struct snd_info_buffer *buf, char *id, int d char *str; snd_iprintf(buf, "\n%s:", id); - mutex_lock(&strings); + guard(mutex)(&strings); for (idx = 0; idx < SNDRV_CARDS; idx++) { str = snd_sndstat_strings[idx][dev]; if (str) { @@ -64,7 +61,6 @@ static int snd_sndstat_show_strings(struct snd_info_buffer *buf, char *id, int d snd_iprintf(buf, "%i: %s\n", idx, str); } } - mutex_unlock(&strings); if (ok < 0) snd_iprintf(buf, " NOT ENABLED IN CONFIG\n"); return ok; -- cgit 1.2.3-korg From 2dc49651fca1e8ecd6c177cd9b576a26761a5cdf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Feb 2024 09:52:49 +0100 Subject: ALSA: mixer_oss: Use guard() for locking We can simplify the code gracefully with new guard() macro and co for automatic cleanup of locks. Only the code refactoring, and no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240227085306.9764-8-tiwai@suse.de --- sound/core/oss/mixer_oss.c | 228 +++++++++++++++++---------------------------- 1 file changed, 86 insertions(+), 142 deletions(-) (limited to 'sound') diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index e10017a42ed8c..6a0508093ea68 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -130,13 +130,12 @@ static int snd_mixer_oss_devmask(struct snd_mixer_oss_file *fmixer) if (mixer == NULL) return -EIO; - mutex_lock(&mixer->reg_mutex); + guard(mutex)(&mixer->reg_mutex); for (chn = 0; chn < 31; chn++) { pslot = &mixer->slots[chn]; if (pslot->put_volume || pslot->put_recsrc) result |= 1 << chn; } - mutex_unlock(&mixer->reg_mutex); return result; } @@ -148,13 +147,12 @@ static int snd_mixer_oss_stereodevs(struct snd_mixer_oss_file *fmixer) if (mixer == NULL) return -EIO; - mutex_lock(&mixer->reg_mutex); + guard(mutex)(&mixer->reg_mutex); for (chn = 0; chn < 31; chn++) { pslot = &mixer->slots[chn]; if (pslot->put_volume && pslot->stereo) result |= 1 << chn; } - mutex_unlock(&mixer->reg_mutex); return result; } @@ -165,7 +163,7 @@ static int snd_mixer_oss_recmask(struct snd_mixer_oss_file *fmixer) if (mixer == NULL) return -EIO; - mutex_lock(&mixer->reg_mutex); + guard(mutex)(&mixer->reg_mutex); if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */ result = mixer->mask_recsrc; } else { @@ -177,7 +175,6 @@ static int snd_mixer_oss_recmask(struct snd_mixer_oss_file *fmixer) result |= 1 << chn; } } - mutex_unlock(&mixer->reg_mutex); return result; } @@ -188,12 +185,12 @@ static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer) if (mixer == NULL) return -EIO; - mutex_lock(&mixer->reg_mutex); + guard(mutex)(&mixer->reg_mutex); if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */ unsigned int index; result = mixer->get_recsrc(fmixer, &index); if (result < 0) - goto unlock; + return result; result = 1 << index; } else { struct snd_mixer_oss_slot *pslot; @@ -209,8 +206,6 @@ static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer) } } mixer->oss_recsrc = result; - unlock: - mutex_unlock(&mixer->reg_mutex); return result; } @@ -224,7 +219,7 @@ static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsr if (mixer == NULL) return -EIO; - mutex_lock(&mixer->reg_mutex); + guard(mutex)(&mixer->reg_mutex); if (mixer->get_recsrc && mixer->put_recsrc) { /* exclusive input */ if (recsrc & ~mixer->oss_recsrc) recsrc &= ~mixer->oss_recsrc; @@ -250,7 +245,6 @@ static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsr } } } - mutex_unlock(&mixer->reg_mutex); return result; } @@ -262,7 +256,7 @@ static int snd_mixer_oss_get_volume(struct snd_mixer_oss_file *fmixer, int slot) if (mixer == NULL || slot > 30) return -EIO; - mutex_lock(&mixer->reg_mutex); + guard(mutex)(&mixer->reg_mutex); pslot = &mixer->slots[slot]; left = pslot->volume[0]; right = pslot->volume[1]; @@ -270,21 +264,15 @@ static int snd_mixer_oss_get_volume(struct snd_mixer_oss_file *fmixer, int slot) result = pslot->get_volume(fmixer, pslot, &left, &right); if (!pslot->stereo) right = left; - if (snd_BUG_ON(left < 0 || left > 100)) { - result = -EIO; - goto unlock; - } - if (snd_BUG_ON(right < 0 || right > 100)) { - result = -EIO; - goto unlock; - } + if (snd_BUG_ON(left < 0 || left > 100)) + return -EIO; + if (snd_BUG_ON(right < 0 || right > 100)) + return -EIO; if (result >= 0) { pslot->volume[0] = left; pslot->volume[1] = right; result = (left & 0xff) | ((right & 0xff) << 8); } - unlock: - mutex_unlock(&mixer->reg_mutex); return result; } @@ -297,7 +285,7 @@ static int snd_mixer_oss_set_volume(struct snd_mixer_oss_file *fmixer, if (mixer == NULL || slot > 30) return -EIO; - mutex_lock(&mixer->reg_mutex); + guard(mutex)(&mixer->reg_mutex); pslot = &mixer->slots[slot]; if (left > 100) left = 100; @@ -308,12 +296,10 @@ static int snd_mixer_oss_set_volume(struct snd_mixer_oss_file *fmixer, if (pslot->put_volume) result = pslot->put_volume(fmixer, pslot, left, right); if (result < 0) - goto unlock; + return result; pslot->volume[0] = left; pslot->volume[1] = right; result = (left & 0xff) | ((right & 0xff) << 8); - unlock: - mutex_unlock(&mixer->reg_mutex); return result; } @@ -539,28 +525,24 @@ static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer, if (numid == ID_UNKNOWN) return; - down_read(&card->controls_rwsem); + guard(rwsem_read)(&card->controls_rwsem); kctl = snd_ctl_find_numid_locked(card, numid); - if (!kctl) { - up_read(&card->controls_rwsem); + if (!kctl) return; - } uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) - goto __unalloc; + return; if (kctl->info(kctl, uinfo)) - goto __unalloc; + return; if (kctl->get(kctl, uctl)) - goto __unalloc; + return; if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN && uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1) - goto __unalloc; + return; *left = snd_mixer_oss_conv1(uctl->value.integer.value[0], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[0]); if (uinfo->count > 1) *right = snd_mixer_oss_conv1(uctl->value.integer.value[1], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[1]); - __unalloc: - up_read(&card->controls_rwsem); } static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer, @@ -576,20 +558,18 @@ static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer, if (numid == ID_UNKNOWN) return; - down_read(&card->controls_rwsem); + guard(rwsem_read)(&card->controls_rwsem); kctl = snd_ctl_find_numid_locked(card, numid); - if (!kctl) { - up_read(&card->controls_rwsem); + if (!kctl) return; - } uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) - goto __unalloc; + return; if (kctl->info(kctl, uinfo)) - goto __unalloc; + return; if (kctl->get(kctl, uctl)) - goto __unalloc; + return; if (!uctl->value.integer.value[0]) { *left = 0; if (uinfo->count == 1) @@ -597,8 +577,6 @@ static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer, } if (uinfo->count > 1 && !uctl->value.integer.value[route ? 3 : 1]) *right = 0; - __unalloc: - up_read(&card->controls_rwsem); } static int snd_mixer_oss_get_volume1(struct snd_mixer_oss_file *fmixer, @@ -640,31 +618,27 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer, if (numid == ID_UNKNOWN) return; - down_read(&card->controls_rwsem); + guard(rwsem_read)(&card->controls_rwsem); kctl = snd_ctl_find_numid_locked(card, numid); - if (!kctl) { - up_read(&card->controls_rwsem); + if (!kctl) return; - } uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) - goto __unalloc; + return; if (kctl->info(kctl, uinfo)) - goto __unalloc; + return; if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN && uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1) - goto __unalloc; + return; uctl->value.integer.value[0] = snd_mixer_oss_conv2(left, uinfo->value.integer.min, uinfo->value.integer.max); if (uinfo->count > 1) uctl->value.integer.value[1] = snd_mixer_oss_conv2(right, uinfo->value.integer.min, uinfo->value.integer.max); res = kctl->put(kctl, uctl); if (res < 0) - goto __unalloc; + return; if (res > 0) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); - __unalloc: - up_read(&card->controls_rwsem); } static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer, @@ -681,18 +655,16 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer, if (numid == ID_UNKNOWN) return; - down_read(&card->controls_rwsem); + guard(rwsem_read)(&card->controls_rwsem); kctl = snd_ctl_find_numid_locked(card, numid); - if (!kctl) { - up_read(&card->controls_rwsem); + if (!kctl) return; - } uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) - goto __unalloc; + return; if (kctl->info(kctl, uinfo)) - goto __unalloc; + return; if (uinfo->count > 1) { uctl->value.integer.value[0] = left > 0 ? 1 : 0; uctl->value.integer.value[route ? 3 : 1] = right > 0 ? 1 : 0; @@ -705,11 +677,9 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer, } res = kctl->put(kctl, uctl); if (res < 0) - goto __unalloc; + return; if (res > 0) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); - __unalloc: - up_read(&card->controls_rwsem); } static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer, @@ -822,18 +792,16 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) return -ENOMEM; - down_read(&card->controls_rwsem); + guard(rwsem_read)(&card->controls_rwsem); kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); - if (! kctl) { - err = -ENOENT; - goto __unlock; - } + if (!kctl) + return -ENOENT; err = kctl->info(kctl, uinfo); if (err < 0) - goto __unlock; + return err; err = kctl->get(kctl, uctl); if (err < 0) - goto __unlock; + return err; for (idx = 0; idx < 32; idx++) { if (!(mixer->mask_recsrc & (1 << idx))) continue; @@ -848,10 +816,7 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned break; } } - err = 0; - __unlock: - up_read(&card->controls_rwsem); - return err; + return 0; } static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned int active_index) @@ -870,15 +835,13 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) return -ENOMEM; - down_read(&card->controls_rwsem); + guard(rwsem_read)(&card->controls_rwsem); kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); - if (! kctl) { - err = -ENOENT; - goto __unlock; - } + if (!kctl) + return -ENOENT; err = kctl->info(kctl, uinfo); if (err < 0) - goto __unlock; + return err; for (idx = 0; idx < 32; idx++) { if (!(mixer->mask_recsrc & (1 << idx))) continue; @@ -892,17 +855,14 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned break; slot = NULL; } - if (! slot) - goto __unlock; + if (!slot) + return 0; for (idx = 0; idx < uinfo->count; idx++) uctl->value.enumerated.item[idx] = slot->capture_item; err = kctl->put(kctl, uctl); if (err > 0) snd_ctl_notify(fmixer->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); - err = 0; - __unlock: - up_read(&card->controls_rwsem); - return err; + return 0; } struct snd_mixer_oss_assign_table { @@ -918,24 +878,18 @@ static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *sl struct snd_card *card = mixer->card; int err; - down_read(&card->controls_rwsem); - kcontrol = snd_mixer_oss_test_id(mixer, name, index); - if (kcontrol == NULL) { - up_read(&card->controls_rwsem); - return 0; - } - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (! info) { - up_read(&card->controls_rwsem); - return -ENOMEM; - } - err = kcontrol->info(kcontrol, info); - if (err < 0) { - up_read(&card->controls_rwsem); - return err; + scoped_guard(rwsem_read, &card->controls_rwsem) { + kcontrol = snd_mixer_oss_test_id(mixer, name, index); + if (kcontrol == NULL) + return 0; + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + err = kcontrol->info(kcontrol, info); + if (err < 0) + return err; + slot->numid[item] = kcontrol->id.numid; } - slot->numid[item] = kcontrol->id.numid; - up_read(&card->controls_rwsem); if (info->count > slot->channels) slot->channels = info->count; slot->present |= 1 << item; @@ -1048,7 +1002,7 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, memset(slot.numid, 0xff, sizeof(slot.numid)); /* ID_UNKNOWN */ if (snd_mixer_oss_build_test_all(mixer, ptr, &slot)) return 0; - down_read(&mixer->card->controls_rwsem); + guard(rwsem_read)(&mixer->card->controls_rwsem); kctl = NULL; if (!ptr->index) kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); @@ -1056,15 +1010,11 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, struct snd_ctl_elem_info *uinfo __free(kfree) = NULL; uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); - if (! uinfo) { - up_read(&mixer->card->controls_rwsem); + if (!uinfo) return -ENOMEM; - } - if (kctl->info(kctl, uinfo)) { - up_read(&mixer->card->controls_rwsem); + if (kctl->info(kctl, uinfo)) return 0; - } strcpy(str, ptr->name); if (!strcmp(str, "Master")) strcpy(str, "Mix"); @@ -1076,10 +1026,8 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, } else { for (slot.capture_item = 1; slot.capture_item < uinfo->value.enumerated.items; slot.capture_item++) { uinfo->value.enumerated.item = slot.capture_item; - if (kctl->info(kctl, uinfo)) { - up_read(&mixer->card->controls_rwsem); + if (kctl->info(kctl, uinfo)) return 0; - } if (!strcmp(uinfo->value.enumerated.name, str)) { slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE; break; @@ -1087,7 +1035,6 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, } } } - up_read(&mixer->card->controls_rwsem); if (slot.present != 0) { pslot = kmalloc(sizeof(slot), GFP_KERNEL); if (! pslot) @@ -1160,7 +1107,7 @@ static void snd_mixer_oss_proc_read(struct snd_info_entry *entry, struct snd_mixer_oss *mixer = entry->private_data; int i; - mutex_lock(&mixer->reg_mutex); + guard(mutex)(&mixer->reg_mutex); for (i = 0; i < SNDRV_OSS_MAX_MIXERS; i++) { struct slot *p; @@ -1175,7 +1122,6 @@ static void snd_mixer_oss_proc_read(struct snd_info_entry *entry, else snd_iprintf(buffer, "\"\" 0\n"); } - mutex_unlock(&mixer->reg_mutex); } static void snd_mixer_oss_proc_write(struct snd_info_entry *entry, @@ -1202,9 +1148,8 @@ static void snd_mixer_oss_proc_write(struct snd_info_entry *entry, cptr = snd_info_get_str(str, cptr, sizeof(str)); if (! *str) { /* remove the entry */ - mutex_lock(&mixer->reg_mutex); - mixer_slot_clear(&mixer->slots[ch]); - mutex_unlock(&mixer->reg_mutex); + scoped_guard(mutex, &mixer->reg_mutex) + mixer_slot_clear(&mixer->slots[ch]); continue; } snd_info_get_str(idxstr, cptr, sizeof(idxstr)); @@ -1213,28 +1158,27 @@ static void snd_mixer_oss_proc_write(struct snd_info_entry *entry, pr_err("ALSA: mixer_oss: invalid index %d\n", idx); continue; } - mutex_lock(&mixer->reg_mutex); - slot = (struct slot *)mixer->slots[ch].private_data; - if (slot && slot->assigned && - slot->assigned->index == idx && ! strcmp(slot->assigned->name, str)) - /* not changed */ - goto __unlock; - tbl = kmalloc(sizeof(*tbl), GFP_KERNEL); - if (!tbl) - goto __unlock; - tbl->oss_id = ch; - tbl->name = kstrdup(str, GFP_KERNEL); - if (! tbl->name) { - kfree(tbl); - goto __unlock; - } - tbl->index = idx; - if (snd_mixer_oss_build_input(mixer, tbl, 1, 1) <= 0) { - kfree(tbl->name); - kfree(tbl); + scoped_guard(mutex, &mixer->reg_mutex) { + slot = (struct slot *)mixer->slots[ch].private_data; + if (slot && slot->assigned && + slot->assigned->index == idx && !strcmp(slot->assigned->name, str)) + /* not changed */ + break; + tbl = kmalloc(sizeof(*tbl), GFP_KERNEL); + if (!tbl) + break; + tbl->oss_id = ch; + tbl->name = kstrdup(str, GFP_KERNEL); + if (!tbl->name) { + kfree(tbl); + break; + } + tbl->index = idx; + if (snd_mixer_oss_build_input(mixer, tbl, 1, 1) <= 0) { + kfree(tbl->name); + kfree(tbl); + } } - __unlock: - mutex_unlock(&mixer->reg_mutex); } } -- cgit 1.2.3-korg From 471be437be779a028040afc151972e3125b5b23c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Feb 2024 09:52:50 +0100 Subject: ALSA: control: Use guard() for locking We can simplify the code gracefully with new guard() macro and co for automatic cleanup of locks. The lops calls under multiple rwsems are factored out as a simple macro, so that it can be called easily from snd_ctl_dev_register() and snd_ctl_dev_disconnect(). There are a few remaining explicit rwsem and spinlock calls, and those are the places where the lock downgrade happens or where the temporary unlock/relocking happens -- which guard() doens't cover well yet. Only the code refactoring, and no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240227085306.9764-9-tiwai@suse.de --- sound/core/control.c | 431 ++++++++++++++++++-------------------------- sound/core/control_compat.c | 18 +- 2 files changed, 176 insertions(+), 273 deletions(-) (limited to 'sound') diff --git a/sound/core/control.c b/sound/core/control.c index c8cd70aed6af4..8367fd4853716 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -44,7 +44,6 @@ static int snd_ctl_remove_locked(struct snd_card *card, static int snd_ctl_open(struct inode *inode, struct file *file) { - unsigned long flags; struct snd_card *card; struct snd_ctl_file *ctl; int i, err; @@ -80,9 +79,8 @@ static int snd_ctl_open(struct inode *inode, struct file *file) ctl->preferred_subdevice[i] = -1; ctl->pid = get_pid(task_pid(current)); file->private_data = ctl; - write_lock_irqsave(&card->ctl_files_rwlock, flags); - list_add_tail(&ctl->list, &card->ctl_files); - write_unlock_irqrestore(&card->ctl_files_rwlock, flags); + scoped_guard(write_lock_irqsave, &card->ctl_files_rwlock) + list_add_tail(&ctl->list, &card->ctl_files); snd_card_unref(card); return 0; @@ -98,21 +96,18 @@ static int snd_ctl_open(struct inode *inode, struct file *file) static void snd_ctl_empty_read_queue(struct snd_ctl_file * ctl) { - unsigned long flags; struct snd_kctl_event *cread; - spin_lock_irqsave(&ctl->read_lock, flags); + guard(spinlock_irqsave)(&ctl->read_lock); while (!list_empty(&ctl->events)) { cread = snd_kctl_event(ctl->events.next); list_del(&cread->list); kfree(cread); } - spin_unlock_irqrestore(&ctl->read_lock, flags); } static int snd_ctl_release(struct inode *inode, struct file *file) { - unsigned long flags; struct snd_card *card; struct snd_ctl_file *ctl; struct snd_kcontrol *control; @@ -121,15 +116,17 @@ static int snd_ctl_release(struct inode *inode, struct file *file) ctl = file->private_data; file->private_data = NULL; card = ctl->card; - write_lock_irqsave(&card->ctl_files_rwlock, flags); - list_del(&ctl->list); - write_unlock_irqrestore(&card->ctl_files_rwlock, flags); - down_write(&card->controls_rwsem); - list_for_each_entry(control, &card->controls, list) - for (idx = 0; idx < control->count; idx++) - if (control->vd[idx].owner == ctl) - control->vd[idx].owner = NULL; - up_write(&card->controls_rwsem); + + scoped_guard(write_lock_irqsave, &card->ctl_files_rwlock) + list_del(&ctl->list); + + scoped_guard(rwsem_write, &card->controls_rwsem) { + list_for_each_entry(control, &card->controls, list) + for (idx = 0; idx < control->count; idx++) + if (control->vd[idx].owner == ctl) + control->vd[idx].owner = NULL; + } + snd_fasync_free(ctl->fasync); snd_ctl_empty_read_queue(ctl); put_pid(ctl->pid); @@ -152,7 +149,6 @@ static int snd_ctl_release(struct inode *inode, struct file *file) void snd_ctl_notify(struct snd_card *card, unsigned int mask, struct snd_ctl_elem_id *id) { - unsigned long flags; struct snd_ctl_file *ctl; struct snd_kctl_event *ev; @@ -160,34 +156,34 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask, return; if (card->shutdown) return; - read_lock_irqsave(&card->ctl_files_rwlock, flags); + + guard(read_lock_irqsave)(&card->ctl_files_rwlock); #if IS_ENABLED(CONFIG_SND_MIXER_OSS) card->mixer_oss_change_count++; #endif list_for_each_entry(ctl, &card->ctl_files, list) { if (!ctl->subscribed) continue; - spin_lock(&ctl->read_lock); - list_for_each_entry(ev, &ctl->events, list) { - if (ev->id.numid == id->numid) { - ev->mask |= mask; - goto _found; + scoped_guard(spinlock, &ctl->read_lock) { + list_for_each_entry(ev, &ctl->events, list) { + if (ev->id.numid == id->numid) { + ev->mask |= mask; + goto _found; + } } + ev = kzalloc(sizeof(*ev), GFP_ATOMIC); + if (ev) { + ev->id = *id; + ev->mask = mask; + list_add_tail(&ev->list, &ctl->events); + } else { + dev_err(card->dev, "No memory available to allocate event\n"); + } +_found: + wake_up(&ctl->change_sleep); } - ev = kzalloc(sizeof(*ev), GFP_ATOMIC); - if (ev) { - ev->id = *id; - ev->mask = mask; - list_add_tail(&ev->list, &ctl->events); - } else { - dev_err(card->dev, "No memory available to allocate event\n"); - } - _found: - wake_up(&ctl->change_sleep); - spin_unlock(&ctl->read_lock); snd_kill_fasync(ctl->fasync, SIGIO, POLL_IN); } - read_unlock_irqrestore(&card->ctl_files_rwlock, flags); } EXPORT_SYMBOL(snd_ctl_notify); @@ -210,10 +206,9 @@ void snd_ctl_notify_one(struct snd_card *card, unsigned int mask, id.index += ioff; id.numid += ioff; snd_ctl_notify(card, mask, &id); - down_read(&snd_ctl_layer_rwsem); + guard(rwsem_read)(&snd_ctl_layer_rwsem); for (lops = snd_ctl_layer; lops; lops = lops->next) lops->lnotify(card, mask, kctl, ioff); - up_read(&snd_ctl_layer_rwsem); } EXPORT_SYMBOL(snd_ctl_notify_one); @@ -520,9 +515,9 @@ static int snd_ctl_add_replace(struct snd_card *card, if (snd_BUG_ON(!card || !kcontrol->info)) goto error; - down_write(&card->controls_rwsem); - err = __snd_ctl_add_replace(card, kcontrol, mode); - up_write(&card->controls_rwsem); + scoped_guard(rwsem_write, &card->controls_rwsem) + err = __snd_ctl_add_replace(card, kcontrol, mode); + if (err < 0) goto error; return 0; @@ -616,12 +611,8 @@ static inline int snd_ctl_remove_locked(struct snd_card *card, */ int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol) { - int ret; - - down_write(&card->controls_rwsem); - ret = snd_ctl_remove_locked(card, kcontrol); - up_write(&card->controls_rwsem); - return ret; + guard(rwsem_write)(&card->controls_rwsem); + return snd_ctl_remove_locked(card, kcontrol); } EXPORT_SYMBOL(snd_ctl_remove); @@ -638,17 +629,12 @@ EXPORT_SYMBOL(snd_ctl_remove); int snd_ctl_remove_id(struct snd_card *card, struct snd_ctl_elem_id *id) { struct snd_kcontrol *kctl; - int ret; - down_write(&card->controls_rwsem); + guard(rwsem_write)(&card->controls_rwsem); kctl = snd_ctl_find_id_locked(card, id); - if (kctl == NULL) { - up_write(&card->controls_rwsem); + if (kctl == NULL) return -ENOENT; - } - ret = snd_ctl_remove_locked(card, kctl); - up_write(&card->controls_rwsem); - return ret; + return snd_ctl_remove_locked(card, kctl); } EXPORT_SYMBOL(snd_ctl_remove_id); @@ -667,27 +653,18 @@ static int snd_ctl_remove_user_ctl(struct snd_ctl_file * file, { struct snd_card *card = file->card; struct snd_kcontrol *kctl; - int idx, ret; + int idx; - down_write(&card->controls_rwsem); + guard(rwsem_write)(&card->controls_rwsem); kctl = snd_ctl_find_id_locked(card, id); - if (kctl == NULL) { - ret = -ENOENT; - goto error; - } - if (!(kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_USER)) { - ret = -EINVAL; - goto error; - } + if (kctl == NULL) + return -ENOENT; + if (!(kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_USER)) + return -EINVAL; for (idx = 0; idx < kctl->count; idx++) - if (kctl->vd[idx].owner != NULL && kctl->vd[idx].owner != file) { - ret = -EBUSY; - goto error; - } - ret = snd_ctl_remove_locked(card, kctl); -error: - up_write(&card->controls_rwsem); - return ret; + if (kctl->vd[idx].owner != NULL && kctl->vd[idx].owner != file) + return -EBUSY; + return snd_ctl_remove_locked(card, kctl); } /** @@ -764,18 +741,15 @@ int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id, struct snd_kcontrol *kctl; int saved_numid; - down_write(&card->controls_rwsem); + guard(rwsem_write)(&card->controls_rwsem); kctl = snd_ctl_find_id_locked(card, src_id); - if (kctl == NULL) { - up_write(&card->controls_rwsem); + if (kctl == NULL) return -ENOENT; - } saved_numid = kctl->id.numid; remove_hash_entries(card, kctl); kctl->id = *dst_id; kctl->id.numid = saved_numid; add_hash_entries(card, kctl); - up_write(&card->controls_rwsem); return 0; } EXPORT_SYMBOL(snd_ctl_rename_id); @@ -793,7 +767,7 @@ EXPORT_SYMBOL(snd_ctl_rename_id); void snd_ctl_rename(struct snd_card *card, struct snd_kcontrol *kctl, const char *name) { - down_write(&card->controls_rwsem); + guard(rwsem_write)(&card->controls_rwsem); remove_hash_entries(card, kctl); if (strscpy(kctl->id.name, name, sizeof(kctl->id.name)) < 0) @@ -801,7 +775,6 @@ void snd_ctl_rename(struct snd_card *card, struct snd_kcontrol *kctl, name, kctl->id.name); add_hash_entries(card, kctl); - up_write(&card->controls_rwsem); } EXPORT_SYMBOL(snd_ctl_rename); @@ -859,12 +832,8 @@ EXPORT_SYMBOL(snd_ctl_find_numid_locked); struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numid) { - struct snd_kcontrol *kctl; - - down_read(&card->controls_rwsem); - kctl = snd_ctl_find_numid_locked(card, numid); - up_read(&card->controls_rwsem); - return kctl; + guard(rwsem_read)(&card->controls_rwsem); + return snd_ctl_find_numid_locked(card, numid); } EXPORT_SYMBOL(snd_ctl_find_numid); @@ -920,12 +889,8 @@ EXPORT_SYMBOL(snd_ctl_find_id_locked); struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card, const struct snd_ctl_elem_id *id) { - struct snd_kcontrol *kctl; - - down_read(&card->controls_rwsem); - kctl = snd_ctl_find_id_locked(card, id); - up_read(&card->controls_rwsem); - return kctl; + guard(rwsem_read)(&card->controls_rwsem); + return snd_ctl_find_id_locked(card, id); } EXPORT_SYMBOL(snd_ctl_find_id); @@ -937,15 +902,15 @@ static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl, info = kzalloc(sizeof(*info), GFP_KERNEL); if (! info) return -ENOMEM; - down_read(&snd_ioctl_rwsem); - info->card = card->number; - strscpy(info->id, card->id, sizeof(info->id)); - strscpy(info->driver, card->driver, sizeof(info->driver)); - strscpy(info->name, card->shortname, sizeof(info->name)); - strscpy(info->longname, card->longname, sizeof(info->longname)); - strscpy(info->mixername, card->mixername, sizeof(info->mixername)); - strscpy(info->components, card->components, sizeof(info->components)); - up_read(&snd_ioctl_rwsem); + scoped_guard(rwsem_read, &snd_ioctl_rwsem) { + info->card = card->number; + strscpy(info->id, card->id, sizeof(info->id)); + strscpy(info->driver, card->driver, sizeof(info->driver)); + strscpy(info->name, card->shortname, sizeof(info->name)); + strscpy(info->longname, card->longname, sizeof(info->longname)); + strscpy(info->mixername, card->mixername, sizeof(info->mixername)); + strscpy(info->components, card->components, sizeof(info->components)); + } if (copy_to_user(arg, info, sizeof(struct snd_ctl_card_info))) return -EFAULT; return 0; @@ -957,37 +922,31 @@ static int snd_ctl_elem_list(struct snd_card *card, struct snd_kcontrol *kctl; struct snd_ctl_elem_id id; unsigned int offset, space, jidx; - int err = 0; offset = list->offset; space = list->space; - down_read(&card->controls_rwsem); + guard(rwsem_read)(&card->controls_rwsem); list->count = card->controls_count; list->used = 0; - if (space > 0) { - list_for_each_entry(kctl, &card->controls, list) { - if (offset >= kctl->count) { - offset -= kctl->count; - continue; - } - for (jidx = offset; jidx < kctl->count; jidx++) { - snd_ctl_build_ioff(&id, kctl, jidx); - if (copy_to_user(list->pids + list->used, &id, - sizeof(id))) { - err = -EFAULT; - goto out; - } - list->used++; - if (!--space) - goto out; - } - offset = 0; + if (!space) + return 0; + list_for_each_entry(kctl, &card->controls, list) { + if (offset >= kctl->count) { + offset -= kctl->count; + continue; + } + for (jidx = offset; jidx < kctl->count; jidx++) { + snd_ctl_build_ioff(&id, kctl, jidx); + if (copy_to_user(list->pids + list->used, &id, sizeof(id))) + return -EFAULT; + list->used++; + if (!--space) + return 0; } + offset = 0; } - out: - up_read(&card->controls_rwsem); - return err; + return 0; } static int snd_ctl_elem_list_user(struct snd_card *card, @@ -1235,16 +1194,12 @@ static int snd_ctl_elem_info(struct snd_ctl_file *ctl, { struct snd_card *card = ctl->card; struct snd_kcontrol *kctl; - int result; - down_read(&card->controls_rwsem); + guard(rwsem_read)(&card->controls_rwsem); kctl = snd_ctl_find_id_locked(card, &info->id); - if (kctl == NULL) - result = -ENOENT; - else - result = __snd_ctl_elem_info(card, kctl, info, ctl); - up_read(&card->controls_rwsem); - return result; + if (!kctl) + return -ENOENT; + return __snd_ctl_elem_info(card, kctl, info, ctl); } static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl, @@ -1276,19 +1231,15 @@ static int snd_ctl_elem_read(struct snd_card *card, const u32 pattern = 0xdeadbeef; int ret; - down_read(&card->controls_rwsem); + guard(rwsem_read)(&card->controls_rwsem); kctl = snd_ctl_find_id_locked(card, &control->id); - if (kctl == NULL) { - ret = -ENOENT; - goto unlock; - } + if (!kctl) + return -ENOENT; index_offset = snd_ctl_get_ioff(kctl, &control->id); vd = &kctl->vd[index_offset]; - if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) || kctl->get == NULL) { - ret = -EPERM; - goto unlock; - } + if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) || !kctl->get) + return -EPERM; snd_ctl_build_ioff(&control->id, kctl, index_offset); @@ -1298,7 +1249,7 @@ static int snd_ctl_elem_read(struct snd_card *card, info.id = control->id; ret = __snd_ctl_elem_info(card, kctl, &info, NULL); if (ret < 0) - goto unlock; + return ret; #endif if (!snd_ctl_skip_validation(&info)) @@ -1308,7 +1259,7 @@ static int snd_ctl_elem_read(struct snd_card *card, ret = kctl->get(kctl, control); snd_power_unref(card); if (ret < 0) - goto unlock; + return ret; if (!snd_ctl_skip_validation(&info) && sanity_check_elem_value(card, control, &info, pattern) < 0) { dev_err(card->dev, @@ -1316,12 +1267,9 @@ static int snd_ctl_elem_read(struct snd_card *card, control->id.iface, control->id.device, control->id.subdevice, control->id.name, control->id.index); - ret = -EINVAL; - goto unlock; + return -EINVAL; } -unlock: - up_read(&card->controls_rwsem); - return ret; + return 0; } static int snd_ctl_elem_read_user(struct snd_card *card, @@ -1426,25 +1374,18 @@ static int snd_ctl_elem_lock(struct snd_ctl_file *file, struct snd_ctl_elem_id id; struct snd_kcontrol *kctl; struct snd_kcontrol_volatile *vd; - int result; if (copy_from_user(&id, _id, sizeof(id))) return -EFAULT; - down_write(&card->controls_rwsem); + guard(rwsem_write)(&card->controls_rwsem); kctl = snd_ctl_find_id_locked(card, &id); - if (kctl == NULL) { - result = -ENOENT; - } else { - vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)]; - if (vd->owner != NULL) - result = -EBUSY; - else { - vd->owner = file; - result = 0; - } - } - up_write(&card->controls_rwsem); - return result; + if (!kctl) + return -ENOENT; + vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)]; + if (vd->owner) + return -EBUSY; + vd->owner = file; + return 0; } static int snd_ctl_elem_unlock(struct snd_ctl_file *file, @@ -1454,27 +1395,20 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file, struct snd_ctl_elem_id id; struct snd_kcontrol *kctl; struct snd_kcontrol_volatile *vd; - int result; if (copy_from_user(&id, _id, sizeof(id))) return -EFAULT; - down_write(&card->controls_rwsem); + guard(rwsem_write)(&card->controls_rwsem); kctl = snd_ctl_find_id_locked(card, &id); - if (kctl == NULL) { - result = -ENOENT; - } else { - vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)]; - if (vd->owner == NULL) - result = -EINVAL; - else if (vd->owner != file) - result = -EPERM; - else { - vd->owner = NULL; - result = 0; - } - } - up_write(&card->controls_rwsem); - return result; + if (!kctl) + return -ENOENT; + vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)]; + if (!vd->owner) + return -EINVAL; + if (vd->owner != file) + return -EPERM; + vd->owner = NULL; + return 0; } struct user_element { @@ -1756,11 +1690,9 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, private_size = value_sizes[info->type] * info->count; alloc_size = compute_user_elem_size(private_size, count); - down_write(&card->controls_rwsem); - if (check_user_elem_overflow(card, alloc_size)) { - err = -ENOMEM; - goto unlock; - } + guard(rwsem_write)(&card->controls_rwsem); + if (check_user_elem_overflow(card, alloc_size)) + return -ENOMEM; /* * Keep memory object for this userspace control. After passing this @@ -1770,13 +1702,12 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, */ err = snd_ctl_new(&kctl, count, access, file); if (err < 0) - goto unlock; + return err; memcpy(&kctl->id, &info->id, sizeof(kctl->id)); ue = kzalloc(alloc_size, GFP_KERNEL); if (!ue) { kfree(kctl); - err = -ENOMEM; - goto unlock; + return -ENOMEM; } kctl->private_data = ue; kctl->private_free = snd_ctl_elem_user_free; @@ -1794,7 +1725,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, err = snd_ctl_elem_init_enum_names(ue); if (err < 0) { snd_ctl_free_one(kctl); - goto unlock; + return err; } } @@ -1814,7 +1745,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, err = __snd_ctl_add_replace(card, kctl, CTL_ADD_EXCLUSIVE); if (err < 0) { snd_ctl_free_one(kctl); - goto unlock; + return err; } offset = snd_ctl_get_ioff(kctl, &info->id); snd_ctl_build_ioff(&info->id, kctl, offset); @@ -1825,9 +1756,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, * applications because the field originally means PID of a process * which locks the element. */ - unlock: - up_write(&card->controls_rwsem); - return err; + return 0; } static int snd_ctl_elem_add_user(struct snd_ctl_file *file, @@ -2029,34 +1958,29 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS: return snd_ctl_subscribe_events(ctl, ip); case SNDRV_CTL_IOCTL_TLV_READ: - down_read(&ctl->card->controls_rwsem); - err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_READ); - up_read(&ctl->card->controls_rwsem); + scoped_guard(rwsem_read, &ctl->card->controls_rwsem) + err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_READ); return err; case SNDRV_CTL_IOCTL_TLV_WRITE: - down_write(&ctl->card->controls_rwsem); - err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_WRITE); - up_write(&ctl->card->controls_rwsem); + scoped_guard(rwsem_write, &ctl->card->controls_rwsem) + err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_WRITE); return err; case SNDRV_CTL_IOCTL_TLV_COMMAND: - down_write(&ctl->card->controls_rwsem); - err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_CMD); - up_write(&ctl->card->controls_rwsem); + scoped_guard(rwsem_write, &ctl->card->controls_rwsem) + err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_CMD); return err; case SNDRV_CTL_IOCTL_POWER: return -ENOPROTOOPT; case SNDRV_CTL_IOCTL_POWER_STATE: return put_user(SNDRV_CTL_POWER_D0, ip) ? -EFAULT : 0; } - down_read(&snd_ioctl_rwsem); + + guard(rwsem_read)(&snd_ioctl_rwsem); list_for_each_entry(p, &snd_control_ioctls, list) { err = p->fioctl(card, ctl, cmd, arg); - if (err != -ENOIOCTLCMD) { - up_read(&snd_ioctl_rwsem); + if (err != -ENOIOCTLCMD) return err; - } } - up_read(&snd_ioctl_rwsem); dev_dbg(card->dev, "unknown ioctl = 0x%x\n", cmd); return -ENOTTY; } @@ -2148,9 +2072,8 @@ static int _snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head * if (pn == NULL) return -ENOMEM; pn->fioctl = fcn; - down_write(&snd_ioctl_rwsem); + guard(rwsem_write)(&snd_ioctl_rwsem); list_add_tail(&pn->list, lists); - up_write(&snd_ioctl_rwsem); return 0; } @@ -2193,16 +2116,14 @@ static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn, if (snd_BUG_ON(!fcn)) return -EINVAL; - down_write(&snd_ioctl_rwsem); + guard(rwsem_write)(&snd_ioctl_rwsem); list_for_each_entry(p, lists, list) { if (p->fioctl == fcn) { list_del(&p->list); - up_write(&snd_ioctl_rwsem); kfree(p); return 0; } } - up_write(&snd_ioctl_rwsem); snd_BUG(); return -EINVAL; } @@ -2249,9 +2170,8 @@ int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type) { struct snd_ctl_file *kctl; int subdevice = -1; - unsigned long flags; - read_lock_irqsave(&card->ctl_files_rwlock, flags); + guard(read_lock_irqsave)(&card->ctl_files_rwlock); list_for_each_entry(kctl, &card->ctl_files, list) { if (kctl->pid == task_pid(current)) { subdevice = kctl->preferred_subdevice[type]; @@ -2259,7 +2179,6 @@ int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type) break; } } - read_unlock_irqrestore(&card->ctl_files_rwlock, flags); return subdevice; } EXPORT_SYMBOL_GPL(snd_ctl_get_preferred_subdevice); @@ -2289,13 +2208,11 @@ int snd_ctl_request_layer(const char *module_name) if (module_name == NULL) return 0; - down_read(&snd_ctl_layer_rwsem); - for (lops = snd_ctl_layer; lops; lops = lops->next) - if (strcmp(lops->module_name, module_name) == 0) - break; - up_read(&snd_ctl_layer_rwsem); - if (lops) - return 0; + scoped_guard(rwsem_read, &snd_ctl_layer_rwsem) { + for (lops = snd_ctl_layer; lops; lops = lops->next) + if (strcmp(lops->module_name, module_name) == 0) + return 0; + } return request_module(module_name); } EXPORT_SYMBOL_GPL(snd_ctl_request_layer); @@ -2312,16 +2229,15 @@ void snd_ctl_register_layer(struct snd_ctl_layer_ops *lops) struct snd_card *card; int card_number; - down_write(&snd_ctl_layer_rwsem); - lops->next = snd_ctl_layer; - snd_ctl_layer = lops; - up_write(&snd_ctl_layer_rwsem); + scoped_guard(rwsem_write, &snd_ctl_layer_rwsem) { + lops->next = snd_ctl_layer; + snd_ctl_layer = lops; + } for (card_number = 0; card_number < SNDRV_CARDS; card_number++) { card = snd_card_ref(card_number); if (card) { - down_read(&card->controls_rwsem); - lops->lregister(card); - up_read(&card->controls_rwsem); + scoped_guard(rwsem_read, &card->controls_rwsem) + lops->lregister(card); snd_card_unref(card); } } @@ -2340,7 +2256,7 @@ void snd_ctl_disconnect_layer(struct snd_ctl_layer_ops *lops) { struct snd_ctl_layer_ops *lops2, *prev_lops2; - down_write(&snd_ctl_layer_rwsem); + guard(rwsem_write)(&snd_ctl_layer_rwsem); for (lops2 = snd_ctl_layer, prev_lops2 = NULL; lops2; lops2 = lops2->next) { if (lops2 == lops) { if (!prev_lops2) @@ -2351,7 +2267,6 @@ void snd_ctl_disconnect_layer(struct snd_ctl_layer_ops *lops) } prev_lops2 = lops2; } - up_write(&snd_ctl_layer_rwsem); } EXPORT_SYMBOL_GPL(snd_ctl_disconnect_layer); @@ -2372,25 +2287,29 @@ static const struct file_operations snd_ctl_f_ops = .fasync = snd_ctl_fasync, }; +/* call lops under rwsems; called from snd_ctl_dev_*() below() */ +#define call_snd_ctl_lops(_card, _op) \ + do { \ + struct snd_ctl_layer_ops *lops; \ + guard(rwsem_read)(&(_card)->controls_rwsem); \ + guard(rwsem_read)(&snd_ctl_layer_rwsem); \ + for (lops = snd_ctl_layer; lops; lops = lops->next) \ + lops->_op(_card); \ + } while (0) + /* * registration of the control device */ static int snd_ctl_dev_register(struct snd_device *device) { struct snd_card *card = device->device_data; - struct snd_ctl_layer_ops *lops; int err; err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1, &snd_ctl_f_ops, card, card->ctl_dev); if (err < 0) return err; - down_read(&card->controls_rwsem); - down_read(&snd_ctl_layer_rwsem); - for (lops = snd_ctl_layer; lops; lops = lops->next) - lops->lregister(card); - up_read(&snd_ctl_layer_rwsem); - up_read(&card->controls_rwsem); + call_snd_ctl_lops(card, lregister); return 0; } @@ -2401,23 +2320,15 @@ static int snd_ctl_dev_disconnect(struct snd_device *device) { struct snd_card *card = device->device_data; struct snd_ctl_file *ctl; - struct snd_ctl_layer_ops *lops; - unsigned long flags; - read_lock_irqsave(&card->ctl_files_rwlock, flags); - list_for_each_entry(ctl, &card->ctl_files, list) { - wake_up(&ctl->change_sleep); - snd_kill_fasync(ctl->fasync, SIGIO, POLL_ERR); + scoped_guard(read_lock_irqsave, &card->ctl_files_rwlock) { + list_for_each_entry(ctl, &card->ctl_files, list) { + wake_up(&ctl->change_sleep); + snd_kill_fasync(ctl->fasync, SIGIO, POLL_ERR); + } } - read_unlock_irqrestore(&card->ctl_files_rwlock, flags); - - down_read(&card->controls_rwsem); - down_read(&snd_ctl_layer_rwsem); - for (lops = snd_ctl_layer; lops; lops = lops->next) - lops->ldisconnect(card); - up_read(&snd_ctl_layer_rwsem); - up_read(&card->controls_rwsem); + call_snd_ctl_lops(card, ldisconnect); return snd_unregister_device(card->ctl_dev); } @@ -2429,17 +2340,17 @@ static int snd_ctl_dev_free(struct snd_device *device) struct snd_card *card = device->device_data; struct snd_kcontrol *control; - down_write(&card->controls_rwsem); - while (!list_empty(&card->controls)) { - control = snd_kcontrol(card->controls.next); - __snd_ctl_remove(card, control, false); - } + scoped_guard(rwsem_write, &card->controls_rwsem) { + while (!list_empty(&card->controls)) { + control = snd_kcontrol(card->controls.next); + __snd_ctl_remove(card, control, false); + } #ifdef CONFIG_SND_CTL_FAST_LOOKUP - xa_destroy(&card->ctl_numids); - xa_destroy(&card->ctl_hash); + xa_destroy(&card->ctl_numids); + xa_destroy(&card->ctl_hash); #endif - up_write(&card->controls_rwsem); + } put_device(card->ctl_dev); return 0; } diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c index 8392183c77ed3..934bb945e702a 100644 --- a/sound/core/control_compat.c +++ b/sound/core/control_compat.c @@ -167,23 +167,18 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id, struct snd_ctl_elem_info *info __free(kfree) = NULL; int err; - down_read(&card->controls_rwsem); + guard(rwsem_read)(&card->controls_rwsem); kctl = snd_ctl_find_id_locked(card, id); - if (! kctl) { - up_read(&card->controls_rwsem); + if (!kctl) return -ENOENT; - } info = kzalloc(sizeof(*info), GFP_KERNEL); - if (info == NULL) { - up_read(&card->controls_rwsem); + if (info == NULL) return -ENOMEM; - } info->id = *id; err = snd_power_ref_and_wait(card); if (!err) err = kctl->info(kctl, info); snd_power_unref(card); - up_read(&card->controls_rwsem); if (err >= 0) { err = info->type; *countp = info->count; @@ -451,16 +446,13 @@ static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, uns #endif /* CONFIG_X86_X32_ABI */ } - down_read(&snd_ioctl_rwsem); + guard(rwsem_read)(&snd_ioctl_rwsem); list_for_each_entry(p, &snd_control_compat_ioctls, list) { if (p->fioctl) { err = p->fioctl(ctl->card, ctl, cmd, arg); - if (err != -ENOIOCTLCMD) { - up_read(&snd_ioctl_rwsem); + if (err != -ENOIOCTLCMD) return err; - } } } - up_read(&snd_ioctl_rwsem); return -ENOIOCTLCMD; } -- cgit 1.2.3-korg From 84bb065b316e8367e14a8824a8f4d21056b10c53 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Feb 2024 09:52:51 +0100 Subject: ALSA: rawmidi: Use guard() for locking We can simplify the code gracefully with new guard() macro and co for automatic cleanup of locks. There are a few remaining explicit mutex and spinlock calls, and those are the places where the temporary unlock/relocking happens -- which guard() doens't cover well yet. Only the code refactoring, and no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240227085306.9764-10-tiwai@suse.de --- sound/core/rawmidi.c | 253 +++++++++++++++++++-------------------------------- 1 file changed, 93 insertions(+), 160 deletions(-) (limited to 'sound') diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 1431cb997808d..7accf9a1ddf4c 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -105,13 +105,8 @@ static inline bool __snd_rawmidi_ready(struct snd_rawmidi_runtime *runtime) static bool snd_rawmidi_ready(struct snd_rawmidi_substream *substream) { - unsigned long flags; - bool ready; - - spin_lock_irqsave(&substream->lock, flags); - ready = __snd_rawmidi_ready(substream->runtime); - spin_unlock_irqrestore(&substream->lock, flags); - return ready; + guard(spinlock_irqsave)(&substream->lock); + return __snd_rawmidi_ready(substream->runtime); } static inline int snd_rawmidi_ready_append(struct snd_rawmidi_substream *substream, @@ -238,12 +233,9 @@ static void __reset_runtime_ptrs(struct snd_rawmidi_runtime *runtime, static void reset_runtime_ptrs(struct snd_rawmidi_substream *substream, bool is_input) { - unsigned long flags; - - spin_lock_irqsave(&substream->lock, flags); + guard(spinlock_irqsave)(&substream->lock); if (substream->opened && substream->runtime) __reset_runtime_ptrs(substream->runtime, is_input); - spin_unlock_irqrestore(&substream->lock, flags); } int snd_rawmidi_drop_output(struct snd_rawmidi_substream *substream) @@ -260,33 +252,29 @@ int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream) long timeout; struct snd_rawmidi_runtime *runtime; - spin_lock_irq(&substream->lock); - runtime = substream->runtime; - if (!substream->opened || !runtime || !runtime->buffer) { - err = -EINVAL; - } else { + scoped_guard(spinlock_irq, &substream->lock) { + runtime = substream->runtime; + if (!substream->opened || !runtime || !runtime->buffer) + return -EINVAL; snd_rawmidi_buffer_ref(runtime); runtime->drain = 1; } - spin_unlock_irq(&substream->lock); - if (err < 0) - return err; timeout = wait_event_interruptible_timeout(runtime->sleep, (runtime->avail >= runtime->buffer_size), 10*HZ); - spin_lock_irq(&substream->lock); - if (signal_pending(current)) - err = -ERESTARTSYS; - if (runtime->avail < runtime->buffer_size && !timeout) { - rmidi_warn(substream->rmidi, - "rawmidi drain error (avail = %li, buffer_size = %li)\n", - (long)runtime->avail, (long)runtime->buffer_size); - err = -EIO; + scoped_guard(spinlock_irq, &substream->lock) { + if (signal_pending(current)) + err = -ERESTARTSYS; + if (runtime->avail < runtime->buffer_size && !timeout) { + rmidi_warn(substream->rmidi, + "rawmidi drain error (avail = %li, buffer_size = %li)\n", + (long)runtime->avail, (long)runtime->buffer_size); + err = -EIO; + } + runtime->drain = 0; } - runtime->drain = 0; - spin_unlock_irq(&substream->lock); if (err != -ERESTARTSYS) { /* we need wait a while to make sure that Tx FIFOs are empty */ @@ -297,9 +285,8 @@ int snd_rawmidi_drain_output(struct snd_rawmidi_substream *substream) snd_rawmidi_drop_output(substream); } - spin_lock_irq(&substream->lock); - snd_rawmidi_buffer_unref(runtime); - spin_unlock_irq(&substream->lock); + scoped_guard(spinlock_irq, &substream->lock) + snd_rawmidi_buffer_unref(runtime); return err; } @@ -363,14 +350,13 @@ static int open_substream(struct snd_rawmidi *rmidi, snd_rawmidi_runtime_free(substream); return err; } - spin_lock_irq(&substream->lock); + guard(spinlock_irq)(&substream->lock); substream->opened = 1; substream->active_sensing = 0; if (mode & SNDRV_RAWMIDI_LFLG_APPEND) substream->append = 1; substream->pid = get_pid(task_pid(current)); rmidi->streams[substream->stream].substream_opened++; - spin_unlock_irq(&substream->lock); } substream->use_count++; return 0; @@ -433,9 +419,8 @@ int snd_rawmidi_kernel_open(struct snd_rawmidi *rmidi, int subdevice, if (!try_module_get(rmidi->card->module)) return -ENXIO; - mutex_lock(&rmidi->open_mutex); + guard(mutex)(&rmidi->open_mutex); err = rawmidi_open_priv(rmidi, subdevice, mode, rfile); - mutex_unlock(&rmidi->open_mutex); if (err < 0) module_put(rmidi->card->module); return err; @@ -568,10 +553,10 @@ static void close_substream(struct snd_rawmidi *rmidi, } snd_rawmidi_buffer_ref_sync(substream); } - spin_lock_irq(&substream->lock); - substream->opened = 0; - substream->append = 0; - spin_unlock_irq(&substream->lock); + scoped_guard(spinlock_irq, &substream->lock) { + substream->opened = 0; + substream->append = 0; + } substream->ops->close(substream); if (substream->runtime->private_free) substream->runtime->private_free(substream); @@ -586,7 +571,7 @@ static void rawmidi_release_priv(struct snd_rawmidi_file *rfile) struct snd_rawmidi *rmidi; rmidi = rfile->rmidi; - mutex_lock(&rmidi->open_mutex); + guard(mutex)(&rmidi->open_mutex); if (rfile->input) { close_substream(rmidi, rfile->input, 1); rfile->input = NULL; @@ -596,7 +581,6 @@ static void rawmidi_release_priv(struct snd_rawmidi_file *rfile) rfile->output = NULL; } rfile->rmidi = NULL; - mutex_unlock(&rmidi->open_mutex); wake_up(&rmidi->open_wait); } @@ -695,12 +679,8 @@ static int __snd_rawmidi_info_select(struct snd_card *card, int snd_rawmidi_info_select(struct snd_card *card, struct snd_rawmidi_info *info) { - int ret; - - mutex_lock(®ister_mutex); - ret = __snd_rawmidi_info_select(card, info); - mutex_unlock(®ister_mutex); - return ret; + guard(mutex)(®ister_mutex); + return __snd_rawmidi_info_select(card, info); } EXPORT_SYMBOL(snd_rawmidi_info_select); @@ -744,9 +724,8 @@ static int resize_runtime_buffer(struct snd_rawmidi_substream *substream, newbuf = kvzalloc(params->buffer_size, GFP_KERNEL); if (!newbuf) return -ENOMEM; - spin_lock_irq(&substream->lock); + guard(spinlock_irq)(&substream->lock); if (runtime->buffer_ref) { - spin_unlock_irq(&substream->lock); kvfree(newbuf); return -EBUSY; } @@ -754,7 +733,6 @@ static int resize_runtime_buffer(struct snd_rawmidi_substream *substream, runtime->buffer = newbuf; runtime->buffer_size = params->buffer_size; __reset_runtime_ptrs(runtime, is_input); - spin_unlock_irq(&substream->lock); kvfree(oldbuf); } runtime->avail_min = params->avail_min; @@ -767,15 +745,12 @@ int snd_rawmidi_output_params(struct snd_rawmidi_substream *substream, int err; snd_rawmidi_drain_output(substream); - mutex_lock(&substream->rmidi->open_mutex); + guard(mutex)(&substream->rmidi->open_mutex); if (substream->append && substream->use_count > 1) - err = -EBUSY; - else - err = resize_runtime_buffer(substream, params, false); - + return -EBUSY; + err = resize_runtime_buffer(substream, params, false); if (!err) substream->active_sensing = !params->no_active_sensing; - mutex_unlock(&substream->rmidi->open_mutex); return err; } EXPORT_SYMBOL(snd_rawmidi_output_params); @@ -788,7 +763,7 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream, int err; snd_rawmidi_drain_input(substream); - mutex_lock(&substream->rmidi->open_mutex); + guard(mutex)(&substream->rmidi->open_mutex); if (framing == SNDRV_RAWMIDI_MODE_FRAMING_NONE && clock_type != SNDRV_RAWMIDI_MODE_CLOCK_NONE) err = -EINVAL; else if (clock_type > SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC_RAW) @@ -802,7 +777,6 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream, substream->framing = framing; substream->clock_type = clock_type; } - mutex_unlock(&substream->rmidi->open_mutex); return 0; } EXPORT_SYMBOL(snd_rawmidi_input_params); @@ -814,9 +788,8 @@ static int snd_rawmidi_output_status(struct snd_rawmidi_substream *substream, memset(status, 0, sizeof(*status)); status->stream = SNDRV_RAWMIDI_STREAM_OUTPUT; - spin_lock_irq(&substream->lock); + guard(spinlock_irq)(&substream->lock); status->avail = runtime->avail; - spin_unlock_irq(&substream->lock); return 0; } @@ -827,11 +800,10 @@ static int snd_rawmidi_input_status(struct snd_rawmidi_substream *substream, memset(status, 0, sizeof(*status)); status->stream = SNDRV_RAWMIDI_STREAM_INPUT; - spin_lock_irq(&substream->lock); + guard(spinlock_irq)(&substream->lock); status->avail = runtime->avail; status->xruns = runtime->xruns; runtime->xruns = 0; - spin_unlock_irq(&substream->lock); return 0; } @@ -1025,19 +997,19 @@ static int snd_rawmidi_next_device(struct snd_card *card, int __user *argp, return -EFAULT; if (device >= SNDRV_RAWMIDI_DEVICES) /* next device is -1 */ device = SNDRV_RAWMIDI_DEVICES - 1; - mutex_lock(®ister_mutex); - device = device < 0 ? 0 : device + 1; - for (; device < SNDRV_RAWMIDI_DEVICES; device++) { - rmidi = snd_rawmidi_search(card, device); - if (!rmidi) - continue; - is_ump = rawmidi_is_ump(rmidi); - if (find_ump == is_ump) - break; + scoped_guard(mutex, ®ister_mutex) { + device = device < 0 ? 0 : device + 1; + for (; device < SNDRV_RAWMIDI_DEVICES; device++) { + rmidi = snd_rawmidi_search(card, device); + if (!rmidi) + continue; + is_ump = rawmidi_is_ump(rmidi); + if (find_ump == is_ump) + break; + } + if (device == SNDRV_RAWMIDI_DEVICES) + device = -1; } - if (device == SNDRV_RAWMIDI_DEVICES) - device = -1; - mutex_unlock(®ister_mutex); if (put_user(device, argp)) return -EFAULT; return 0; @@ -1050,18 +1022,16 @@ static int snd_rawmidi_call_ump_ioctl(struct snd_card *card, int cmd, { struct snd_ump_endpoint_info __user *info = argp; struct snd_rawmidi *rmidi; - int device, ret; + int device; if (get_user(device, &info->device)) return -EFAULT; - mutex_lock(®ister_mutex); + guard(mutex)(®ister_mutex); rmidi = snd_rawmidi_search(card, device); if (rmidi && rmidi->ops && rmidi->ops->ioctl) - ret = rmidi->ops->ioctl(rmidi, cmd, argp); + return rmidi->ops->ioctl(rmidi, cmd, argp); else - ret = -ENXIO; - mutex_unlock(®ister_mutex); - return ret; + return -ENXIO; } #endif @@ -1168,27 +1138,23 @@ static struct timespec64 get_framing_tstamp(struct snd_rawmidi_substream *substr int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, const unsigned char *buffer, int count) { - unsigned long flags; struct timespec64 ts64 = get_framing_tstamp(substream); int result = 0, count1; struct snd_rawmidi_runtime *runtime; - spin_lock_irqsave(&substream->lock, flags); - if (!substream->opened) { - result = -EBADFD; - goto unlock; - } + guard(spinlock_irqsave)(&substream->lock); + if (!substream->opened) + return -EBADFD; runtime = substream->runtime; if (!runtime || !runtime->buffer) { rmidi_dbg(substream->rmidi, "snd_rawmidi_receive: input is not active!!!\n"); - result = -EINVAL; - goto unlock; + return -EINVAL; } count = get_aligned_size(runtime, count); if (!count) - goto unlock; + return result; if (substream->framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) { result = receive_with_tstamp_framing(substream, buffer, count, &ts64); @@ -1211,7 +1177,7 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, count1 = runtime->buffer_size - runtime->avail; count1 = get_aligned_size(runtime, count1); if (!count1) - goto unlock; + return result; memcpy(runtime->buffer + runtime->hw_ptr, buffer, count1); runtime->hw_ptr += count1; runtime->hw_ptr %= runtime->buffer_size; @@ -1239,8 +1205,6 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream, else if (__snd_rawmidi_ready(runtime)) wake_up(&runtime->sleep); } - unlock: - spin_unlock_irqrestore(&substream->lock, flags); return result; } EXPORT_SYMBOL(snd_rawmidi_receive); @@ -1362,20 +1326,15 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun int snd_rawmidi_transmit_empty(struct snd_rawmidi_substream *substream) { struct snd_rawmidi_runtime *runtime; - int result; - unsigned long flags; - spin_lock_irqsave(&substream->lock, flags); + guard(spinlock_irqsave)(&substream->lock); runtime = substream->runtime; if (!substream->opened || !runtime || !runtime->buffer) { rmidi_dbg(substream->rmidi, "snd_rawmidi_transmit_empty: output is not active!!!\n"); - result = 1; - } else { - result = runtime->avail >= runtime->buffer_size; + return 1; } - spin_unlock_irqrestore(&substream->lock, flags); - return result; + return (runtime->avail >= runtime->buffer_size); } EXPORT_SYMBOL(snd_rawmidi_transmit_empty); @@ -1449,16 +1408,10 @@ static int __snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, int snd_rawmidi_transmit_peek(struct snd_rawmidi_substream *substream, unsigned char *buffer, int count) { - int result; - unsigned long flags; - - spin_lock_irqsave(&substream->lock, flags); + guard(spinlock_irqsave)(&substream->lock); if (!substream->opened || !substream->runtime) - result = -EBADFD; - else - result = __snd_rawmidi_transmit_peek(substream, buffer, count); - spin_unlock_irqrestore(&substream->lock, flags); - return result; + return -EBADFD; + return __snd_rawmidi_transmit_peek(substream, buffer, count); } EXPORT_SYMBOL(snd_rawmidi_transmit_peek); @@ -1505,16 +1458,10 @@ static int __snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, */ int snd_rawmidi_transmit_ack(struct snd_rawmidi_substream *substream, int count) { - int result; - unsigned long flags; - - spin_lock_irqsave(&substream->lock, flags); + guard(spinlock_irqsave)(&substream->lock); if (!substream->opened || !substream->runtime) - result = -EBADFD; - else - result = __snd_rawmidi_transmit_ack(substream, count); - spin_unlock_irqrestore(&substream->lock, flags); - return result; + return -EBADFD; + return __snd_rawmidi_transmit_ack(substream, count); } EXPORT_SYMBOL(snd_rawmidi_transmit_ack); @@ -1531,21 +1478,13 @@ EXPORT_SYMBOL(snd_rawmidi_transmit_ack); int snd_rawmidi_transmit(struct snd_rawmidi_substream *substream, unsigned char *buffer, int count) { - int result; - unsigned long flags; - - spin_lock_irqsave(&substream->lock, flags); + guard(spinlock_irqsave)(&substream->lock); if (!substream->opened) - result = -EBADFD; - else { - count = __snd_rawmidi_transmit_peek(substream, buffer, count); - if (count <= 0) - result = count; - else - result = __snd_rawmidi_transmit_ack(substream, count); - } - spin_unlock_irqrestore(&substream->lock, flags); - return result; + return -EBADFD; + count = __snd_rawmidi_transmit_peek(substream, buffer, count); + if (count <= 0) + return count; + return __snd_rawmidi_transmit_ack(substream, count); } EXPORT_SYMBOL(snd_rawmidi_transmit); @@ -1558,17 +1497,15 @@ EXPORT_SYMBOL(snd_rawmidi_transmit); int snd_rawmidi_proceed(struct snd_rawmidi_substream *substream) { struct snd_rawmidi_runtime *runtime; - unsigned long flags; int count = 0; - spin_lock_irqsave(&substream->lock, flags); + guard(spinlock_irqsave)(&substream->lock); runtime = substream->runtime; if (substream->opened && runtime && runtime->avail < runtime->buffer_size) { count = runtime->buffer_size - runtime->avail; __snd_rawmidi_transmit_ack(substream, count); } - spin_unlock_irqrestore(&substream->lock, flags); return count; } EXPORT_SYMBOL(snd_rawmidi_proceed); @@ -1772,7 +1709,7 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, rawmidi_is_ump(rmidi) ? "UMP" : "Legacy"); if (rmidi->ops && rmidi->ops->proc_read) rmidi->ops->proc_read(entry, buffer); - mutex_lock(&rmidi->open_mutex); + guard(mutex)(&rmidi->open_mutex); if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT) { list_for_each_entry(substream, &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams, @@ -1787,10 +1724,10 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, " Owner PID : %d\n", pid_vnr(substream->pid)); runtime = substream->runtime; - spin_lock_irq(&substream->lock); - buffer_size = runtime->buffer_size; - avail = runtime->avail; - spin_unlock_irq(&substream->lock); + scoped_guard(spinlock_irq, &substream->lock) { + buffer_size = runtime->buffer_size; + avail = runtime->avail; + } snd_iprintf(buffer, " Mode : %s\n" " Buffer size : %lu\n" @@ -1814,11 +1751,11 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, " Owner PID : %d\n", pid_vnr(substream->pid)); runtime = substream->runtime; - spin_lock_irq(&substream->lock); - buffer_size = runtime->buffer_size; - avail = runtime->avail; - xruns = runtime->xruns; - spin_unlock_irq(&substream->lock); + scoped_guard(spinlock_irq, &substream->lock) { + buffer_size = runtime->buffer_size; + avail = runtime->avail; + xruns = runtime->xruns; + } snd_iprintf(buffer, " Buffer size : %lu\n" " Avail : %lu\n" @@ -1835,7 +1772,6 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, } } } - mutex_unlock(&rmidi->open_mutex); } /* @@ -2024,12 +1960,12 @@ static int snd_rawmidi_dev_register(struct snd_device *device) if (rmidi->device >= SNDRV_RAWMIDI_DEVICES) return -ENOMEM; err = 0; - mutex_lock(®ister_mutex); - if (snd_rawmidi_search(rmidi->card, rmidi->device)) - err = -EBUSY; - else - list_add_tail(&rmidi->list, &snd_rawmidi_devices); - mutex_unlock(®ister_mutex); + scoped_guard(mutex, ®ister_mutex) { + if (snd_rawmidi_search(rmidi->card, rmidi->device)) + err = -EBUSY; + else + list_add_tail(&rmidi->list, &snd_rawmidi_devices); + } if (err < 0) return err; @@ -2102,9 +2038,8 @@ static int snd_rawmidi_dev_register(struct snd_device *device) error_unregister: snd_unregister_device(rmidi->dev); error: - mutex_lock(®ister_mutex); - list_del(&rmidi->list); - mutex_unlock(®ister_mutex); + scoped_guard(mutex, ®ister_mutex) + list_del(&rmidi->list); return err; } @@ -2113,8 +2048,8 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device) struct snd_rawmidi *rmidi = device->device_data; int dir; - mutex_lock(®ister_mutex); - mutex_lock(&rmidi->open_mutex); + guard(mutex)(®ister_mutex); + guard(mutex)(&rmidi->open_mutex); wake_up(&rmidi->open_wait); list_del_init(&rmidi->list); for (dir = 0; dir < 2; dir++) { @@ -2140,8 +2075,6 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device) } #endif /* CONFIG_SND_OSSEMUL */ snd_unregister_device(rmidi->dev); - mutex_unlock(&rmidi->open_mutex); - mutex_unlock(®ister_mutex); return 0; } -- cgit 1.2.3-korg From 7234795b59f7b0b14569ec46dce56300a4988067 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Feb 2024 09:52:52 +0100 Subject: ALSA: jack: Use guard() for locking We can simplify the code gracefully with new guard() macro and co for automatic cleanup of locks. Only the code refactoring, and no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240227085306.9764-11-tiwai@suse.de --- sound/core/jack.c | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/core/jack.c b/sound/core/jack.c index e0f034e7275cd..e08b2c4fbd1a5 100644 --- a/sound/core/jack.c +++ b/sound/core/jack.c @@ -42,11 +42,9 @@ static int snd_jack_dev_disconnect(struct snd_device *device) #ifdef CONFIG_SND_JACK_INPUT_DEV struct snd_jack *jack = device->device_data; - mutex_lock(&jack->input_dev_lock); - if (!jack->input_dev) { - mutex_unlock(&jack->input_dev_lock); + guard(mutex)(&jack->input_dev_lock); + if (!jack->input_dev) return 0; - } /* If the input device is registered with the input subsystem * then we need to use a different deallocator. */ @@ -55,7 +53,6 @@ static int snd_jack_dev_disconnect(struct snd_device *device) else input_free_device(jack->input_dev); jack->input_dev = NULL; - mutex_unlock(&jack->input_dev_lock); #endif /* CONFIG_SND_JACK_INPUT_DEV */ return 0; } @@ -92,11 +89,9 @@ static int snd_jack_dev_register(struct snd_device *device) snprintf(jack->name, sizeof(jack->name), "%s %s", card->shortname, jack->id); - mutex_lock(&jack->input_dev_lock); - if (!jack->input_dev) { - mutex_unlock(&jack->input_dev_lock); + guard(mutex)(&jack->input_dev_lock); + if (!jack->input_dev) return 0; - } jack->input_dev->name = jack->name; @@ -121,7 +116,6 @@ static int snd_jack_dev_register(struct snd_device *device) if (err == 0) jack->registered = 1; - mutex_unlock(&jack->input_dev_lock); return err; } #endif /* CONFIG_SND_JACK_INPUT_DEV */ @@ -586,14 +580,9 @@ EXPORT_SYMBOL(snd_jack_new); void snd_jack_set_parent(struct snd_jack *jack, struct device *parent) { WARN_ON(jack->registered); - mutex_lock(&jack->input_dev_lock); - if (!jack->input_dev) { - mutex_unlock(&jack->input_dev_lock); - return; - } - - jack->input_dev->dev.parent = parent; - mutex_unlock(&jack->input_dev_lock); + guard(mutex)(&jack->input_dev_lock); + if (jack->input_dev) + jack->input_dev->dev.parent = parent; } EXPORT_SYMBOL(snd_jack_set_parent); -- cgit 1.2.3-korg From 742ecf3ce1acdbcd0bc936178e1eaf346a0fd376 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Feb 2024 09:52:53 +0100 Subject: ALSA: core: Use guard() for locking We can simplify the code gracefully with new guard() macro and co for automatic cleanup of locks. Only the code refactoring, and no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240227085306.9764-12-tiwai@suse.de --- sound/core/init.c | 193 ++++++++++++++++++++++--------------------------- sound/core/sound.c | 28 +++---- sound/core/sound_oss.c | 17 ++--- 3 files changed, 104 insertions(+), 134 deletions(-) (limited to 'sound') diff --git a/sound/core/init.c b/sound/core/init.c index 22c0d217b8608..4ed5037d8693b 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -284,30 +284,31 @@ static int snd_card_init(struct snd_card *card, struct device *parent, if (xid) strscpy(card->id, xid, sizeof(card->id)); err = 0; - mutex_lock(&snd_card_mutex); - if (idx < 0) /* first check the matching module-name slot */ - idx = get_slot_from_bitmask(idx, module_slot_match, module); - if (idx < 0) /* if not matched, assign an empty slot */ - idx = get_slot_from_bitmask(idx, check_empty_slot, module); - if (idx < 0) - err = -ENODEV; - else if (idx < snd_ecards_limit) { - if (test_bit(idx, snd_cards_lock)) - err = -EBUSY; /* invalid */ - } else if (idx >= SNDRV_CARDS) - err = -ENODEV; + scoped_guard(mutex, &snd_card_mutex) { + if (idx < 0) /* first check the matching module-name slot */ + idx = get_slot_from_bitmask(idx, module_slot_match, module); + if (idx < 0) /* if not matched, assign an empty slot */ + idx = get_slot_from_bitmask(idx, check_empty_slot, module); + if (idx < 0) + err = -ENODEV; + else if (idx < snd_ecards_limit) { + if (test_bit(idx, snd_cards_lock)) + err = -EBUSY; /* invalid */ + } else if (idx >= SNDRV_CARDS) + err = -ENODEV; + if (!err) { + set_bit(idx, snd_cards_lock); /* lock it */ + if (idx >= snd_ecards_limit) + snd_ecards_limit = idx + 1; /* increase the limit */ + } + } if (err < 0) { - mutex_unlock(&snd_card_mutex); dev_err(parent, "cannot find the slot for index %d (range 0-%i), error: %d\n", - idx, snd_ecards_limit - 1, err); + idx, snd_ecards_limit - 1, err); if (!card->managed) kfree(card); /* manually free here, as no destructor called */ return err; } - set_bit(idx, snd_cards_lock); /* lock it */ - if (idx >= snd_ecards_limit) - snd_ecards_limit = idx + 1; /* increase the limit */ - mutex_unlock(&snd_card_mutex); card->dev = parent; card->number = idx; #ifdef MODULE @@ -386,11 +387,10 @@ struct snd_card *snd_card_ref(int idx) { struct snd_card *card; - mutex_lock(&snd_card_mutex); + guard(mutex)(&snd_card_mutex); card = snd_cards[idx]; if (card) get_device(&card->card_dev); - mutex_unlock(&snd_card_mutex); return card; } EXPORT_SYMBOL_GPL(snd_card_ref); @@ -398,12 +398,8 @@ EXPORT_SYMBOL_GPL(snd_card_ref); /* return non-zero if a card is already locked */ int snd_card_locked(int card) { - int locked; - - mutex_lock(&snd_card_mutex); - locked = test_bit(card, snd_cards_lock); - mutex_unlock(&snd_card_mutex); - return locked; + guard(mutex)(&snd_card_mutex); + return test_bit(card, snd_cards_lock); } static loff_t snd_disconnect_llseek(struct file *file, loff_t offset, int orig) @@ -427,15 +423,15 @@ static int snd_disconnect_release(struct inode *inode, struct file *file) { struct snd_monitor_file *df = NULL, *_df; - spin_lock(&shutdown_lock); - list_for_each_entry(_df, &shutdown_files, shutdown_list) { - if (_df->file == file) { - df = _df; - list_del_init(&df->shutdown_list); - break; + scoped_guard(spinlock, &shutdown_lock) { + list_for_each_entry(_df, &shutdown_files, shutdown_list) { + if (_df->file == file) { + df = _df; + list_del_init(&df->shutdown_list); + break; + } } } - spin_unlock(&shutdown_lock); if (likely(df)) { if ((file->f_flags & FASYNC) && df->disconnected_f_op->fasync) @@ -501,27 +497,24 @@ void snd_card_disconnect(struct snd_card *card) if (!card) return; - spin_lock(&card->files_lock); - if (card->shutdown) { - spin_unlock(&card->files_lock); - return; - } - card->shutdown = 1; + scoped_guard(spinlock, &card->files_lock) { + if (card->shutdown) + return; + card->shutdown = 1; - /* replace file->f_op with special dummy operations */ - list_for_each_entry(mfile, &card->files_list, list) { - /* it's critical part, use endless loop */ - /* we have no room to fail */ - mfile->disconnected_f_op = mfile->file->f_op; + /* replace file->f_op with special dummy operations */ + list_for_each_entry(mfile, &card->files_list, list) { + /* it's critical part, use endless loop */ + /* we have no room to fail */ + mfile->disconnected_f_op = mfile->file->f_op; - spin_lock(&shutdown_lock); - list_add(&mfile->shutdown_list, &shutdown_files); - spin_unlock(&shutdown_lock); + scoped_guard(spinlock, &shutdown_lock) + list_add(&mfile->shutdown_list, &shutdown_files); - mfile->file->f_op = &snd_shutdown_f_ops; - fops_get(mfile->file->f_op); + mfile->file->f_op = &snd_shutdown_f_ops; + fops_get(mfile->file->f_op); + } } - spin_unlock(&card->files_lock); /* notify all connected devices about disconnection */ /* at this point, they cannot respond to any calls except release() */ @@ -544,10 +537,10 @@ void snd_card_disconnect(struct snd_card *card) } /* disable fops (user space) operations for ALSA API */ - mutex_lock(&snd_card_mutex); - snd_cards[card->number] = NULL; - clear_bit(card->number, snd_cards_lock); - mutex_unlock(&snd_card_mutex); + scoped_guard(mutex, &snd_card_mutex) { + snd_cards[card->number] = NULL; + clear_bit(card->number, snd_cards_lock); + } #ifdef CONFIG_PM wake_up(&card->power_sleep); @@ -569,11 +562,10 @@ void snd_card_disconnect_sync(struct snd_card *card) { snd_card_disconnect(card); - spin_lock_irq(&card->files_lock); + guard(spinlock_irq)(&card->files_lock); wait_event_lock_irq(card->remove_sleep, list_empty(&card->files_list), card->files_lock); - spin_unlock_irq(&card->files_lock); } EXPORT_SYMBOL_GPL(snd_card_disconnect_sync); @@ -767,9 +759,8 @@ void snd_card_set_id(struct snd_card *card, const char *nid) /* check if user specified own card->id */ if (card->id[0] != '\0') return; - mutex_lock(&snd_card_mutex); + guard(mutex)(&snd_card_mutex); snd_card_set_id_no_lock(card, nid, nid); - mutex_unlock(&snd_card_mutex); } EXPORT_SYMBOL(snd_card_set_id); @@ -797,14 +788,11 @@ static ssize_t id_store(struct device *dev, struct device_attribute *attr, } memcpy(buf1, buf, copy); buf1[copy] = '\0'; - mutex_lock(&snd_card_mutex); - if (!card_id_ok(NULL, buf1)) { - mutex_unlock(&snd_card_mutex); + guard(mutex)(&snd_card_mutex); + if (!card_id_ok(NULL, buf1)) return -EEXIST; - } strcpy(card->id, buf1); snd_info_card_id_change(card); - mutex_unlock(&snd_card_mutex); return count; } @@ -897,26 +885,27 @@ int snd_card_register(struct snd_card *card) err = snd_device_register_all(card); if (err < 0) return err; - mutex_lock(&snd_card_mutex); - if (snd_cards[card->number]) { - /* already registered */ - mutex_unlock(&snd_card_mutex); - return snd_info_card_register(card); /* register pending info */ - } - if (*card->id) { - /* make a unique id name from the given string */ - char tmpid[sizeof(card->id)]; - memcpy(tmpid, card->id, sizeof(card->id)); - snd_card_set_id_no_lock(card, tmpid, tmpid); - } else { - /* create an id from either shortname or longname */ - const char *src; - src = *card->shortname ? card->shortname : card->longname; - snd_card_set_id_no_lock(card, src, - retrieve_id_from_card_name(src)); + scoped_guard(mutex, &snd_card_mutex) { + if (snd_cards[card->number]) { + /* already registered */ + return snd_info_card_register(card); /* register pending info */ + } + if (*card->id) { + /* make a unique id name from the given string */ + char tmpid[sizeof(card->id)]; + + memcpy(tmpid, card->id, sizeof(card->id)); + snd_card_set_id_no_lock(card, tmpid, tmpid); + } else { + /* create an id from either shortname or longname */ + const char *src; + + src = *card->shortname ? card->shortname : card->longname; + snd_card_set_id_no_lock(card, src, + retrieve_id_from_card_name(src)); + } + snd_cards[card->number] = card; } - snd_cards[card->number] = card; - mutex_unlock(&snd_card_mutex); err = snd_info_card_register(card); if (err < 0) return err; @@ -937,7 +926,7 @@ static void snd_card_info_read(struct snd_info_entry *entry, struct snd_card *card; for (idx = count = 0; idx < SNDRV_CARDS; idx++) { - mutex_lock(&snd_card_mutex); + guard(mutex)(&snd_card_mutex); card = snd_cards[idx]; if (card) { count++; @@ -949,7 +938,6 @@ static void snd_card_info_read(struct snd_info_entry *entry, snd_iprintf(buffer, " %s\n", card->longname); } - mutex_unlock(&snd_card_mutex); } if (!count) snd_iprintf(buffer, "--- no soundcards ---\n"); @@ -962,13 +950,12 @@ void snd_card_info_read_oss(struct snd_info_buffer *buffer) struct snd_card *card; for (idx = count = 0; idx < SNDRV_CARDS; idx++) { - mutex_lock(&snd_card_mutex); + guard(mutex)(&snd_card_mutex); card = snd_cards[idx]; if (card) { count++; snd_iprintf(buffer, "%s\n", card->longname); } - mutex_unlock(&snd_card_mutex); } if (!count) { snd_iprintf(buffer, "--- no soundcards ---\n"); @@ -985,12 +972,11 @@ static void snd_card_module_info_read(struct snd_info_entry *entry, struct snd_card *card; for (idx = 0; idx < SNDRV_CARDS; idx++) { - mutex_lock(&snd_card_mutex); + guard(mutex)(&snd_card_mutex); card = snd_cards[idx]; if (card) snd_iprintf(buffer, "%2i %s\n", idx, card->module->name); - mutex_unlock(&snd_card_mutex); } } #endif @@ -1072,15 +1058,13 @@ int snd_card_file_add(struct snd_card *card, struct file *file) mfile->file = file; mfile->disconnected_f_op = NULL; INIT_LIST_HEAD(&mfile->shutdown_list); - spin_lock(&card->files_lock); + guard(spinlock)(&card->files_lock); if (card->shutdown) { - spin_unlock(&card->files_lock); kfree(mfile); return -ENODEV; } list_add(&mfile->list, &card->files_list); get_device(&card->card_dev); - spin_unlock(&card->files_lock); return 0; } EXPORT_SYMBOL(snd_card_file_add); @@ -1102,22 +1086,21 @@ int snd_card_file_remove(struct snd_card *card, struct file *file) { struct snd_monitor_file *mfile, *found = NULL; - spin_lock(&card->files_lock); - list_for_each_entry(mfile, &card->files_list, list) { - if (mfile->file == file) { - list_del(&mfile->list); - spin_lock(&shutdown_lock); - list_del(&mfile->shutdown_list); - spin_unlock(&shutdown_lock); - if (mfile->disconnected_f_op) - fops_put(mfile->disconnected_f_op); - found = mfile; - break; + scoped_guard(spinlock, &card->files_lock) { + list_for_each_entry(mfile, &card->files_list, list) { + if (mfile->file == file) { + list_del(&mfile->list); + scoped_guard(spinlock, &shutdown_lock) + list_del(&mfile->shutdown_list); + if (mfile->disconnected_f_op) + fops_put(mfile->disconnected_f_op); + found = mfile; + break; + } } + if (list_empty(&card->files_list)) + wake_up_all(&card->remove_sleep); } - if (list_empty(&card->files_list)) - wake_up_all(&card->remove_sleep); - spin_unlock(&card->files_lock); if (!found) { dev_err(card->dev, "card file remove problem (%p)\n", file); return -ENOENT; diff --git a/sound/core/sound.c b/sound/core/sound.c index df5571d986295..b9db9aa0bfcb5 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -103,7 +103,7 @@ void *snd_lookup_minor_data(unsigned int minor, int type) if (minor >= ARRAY_SIZE(snd_minors)) return NULL; - mutex_lock(&sound_mutex); + guard(mutex)(&sound_mutex); mreg = snd_minors[minor]; if (mreg && mreg->type == type) { private_data = mreg->private_data; @@ -111,7 +111,6 @@ void *snd_lookup_minor_data(unsigned int minor, int type) get_device(&mreg->card_ptr->card_dev); } else private_data = NULL; - mutex_unlock(&sound_mutex); return private_data; } EXPORT_SYMBOL(snd_lookup_minor_data); @@ -150,17 +149,15 @@ static int snd_open(struct inode *inode, struct file *file) if (minor >= ARRAY_SIZE(snd_minors)) return -ENODEV; - mutex_lock(&sound_mutex); - mptr = snd_minors[minor]; - if (mptr == NULL) { - mptr = autoload_device(minor); - if (!mptr) { - mutex_unlock(&sound_mutex); - return -ENODEV; + scoped_guard(mutex, &sound_mutex) { + mptr = snd_minors[minor]; + if (mptr == NULL) { + mptr = autoload_device(minor); + if (!mptr) + return -ENODEV; } + new_fops = fops_get(mptr->f_ops); } - new_fops = fops_get(mptr->f_ops); - mutex_unlock(&sound_mutex); if (!new_fops) return -ENODEV; replace_fops(file, new_fops); @@ -269,7 +266,7 @@ int snd_register_device(int type, struct snd_card *card, int dev, preg->f_ops = f_ops; preg->private_data = private_data; preg->card_ptr = card; - mutex_lock(&sound_mutex); + guard(mutex)(&sound_mutex); minor = snd_find_free_minor(type, card, dev); if (minor < 0) { err = minor; @@ -284,7 +281,6 @@ int snd_register_device(int type, struct snd_card *card, int dev, snd_minors[minor] = preg; error: - mutex_unlock(&sound_mutex); if (err < 0) kfree(preg); return err; @@ -305,7 +301,7 @@ int snd_unregister_device(struct device *dev) int minor; struct snd_minor *preg; - mutex_lock(&sound_mutex); + guard(mutex)(&sound_mutex); for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) { preg = snd_minors[minor]; if (preg && preg->dev == dev) { @@ -315,7 +311,6 @@ int snd_unregister_device(struct device *dev) break; } } - mutex_unlock(&sound_mutex); if (minor >= ARRAY_SIZE(snd_minors)) return -ENOENT; return 0; @@ -355,7 +350,7 @@ static void snd_minor_info_read(struct snd_info_entry *entry, struct snd_info_bu int minor; struct snd_minor *mptr; - mutex_lock(&sound_mutex); + guard(mutex)(&sound_mutex); for (minor = 0; minor < SNDRV_OS_MINORS; ++minor) { mptr = snd_minors[minor]; if (!mptr) @@ -373,7 +368,6 @@ static void snd_minor_info_read(struct snd_info_entry *entry, struct snd_info_bu snd_iprintf(buffer, "%3i: : %s\n", minor, snd_device_type_name(mptr->type)); } - mutex_unlock(&sound_mutex); } int __init snd_minor_info_init(void) diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c index 2751bf2ff61bc..d65cc6fee2e60 100644 --- a/sound/core/sound_oss.c +++ b/sound/core/sound_oss.c @@ -29,7 +29,7 @@ void *snd_lookup_oss_minor_data(unsigned int minor, int type) if (minor >= ARRAY_SIZE(snd_oss_minors)) return NULL; - mutex_lock(&sound_oss_mutex); + guard(mutex)(&sound_oss_mutex); mreg = snd_oss_minors[minor]; if (mreg && mreg->type == type) { private_data = mreg->private_data; @@ -37,7 +37,6 @@ void *snd_lookup_oss_minor_data(unsigned int minor, int type) get_device(&mreg->card_ptr->card_dev); } else private_data = NULL; - mutex_unlock(&sound_oss_mutex); return private_data; } EXPORT_SYMBOL(snd_lookup_oss_minor_data); @@ -106,7 +105,7 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev, preg->f_ops = f_ops; preg->private_data = private_data; preg->card_ptr = card; - mutex_lock(&sound_oss_mutex); + guard(mutex)(&sound_oss_mutex); snd_oss_minors[minor] = preg; minor_unit = SNDRV_MINOR_OSS_DEVICE(minor); switch (minor_unit) { @@ -130,7 +129,6 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev, goto __end; snd_oss_minors[track2] = preg; } - mutex_unlock(&sound_oss_mutex); return 0; __end: @@ -139,7 +137,6 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev, if (register1 >= 0) unregister_sound_special(register1); snd_oss_minors[minor] = NULL; - mutex_unlock(&sound_oss_mutex); kfree(preg); return -EBUSY; } @@ -156,12 +153,10 @@ int snd_unregister_oss_device(int type, struct snd_card *card, int dev) return 0; if (minor < 0) return minor; - mutex_lock(&sound_oss_mutex); + guard(mutex)(&sound_oss_mutex); mptr = snd_oss_minors[minor]; - if (mptr == NULL) { - mutex_unlock(&sound_oss_mutex); + if (mptr == NULL) return -ENOENT; - } switch (SNDRV_MINOR_OSS_DEVICE(minor)) { case SNDRV_MINOR_OSS_PCM: track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_AUDIO); @@ -176,7 +171,6 @@ int snd_unregister_oss_device(int type, struct snd_card *card, int dev) if (track2 >= 0) snd_oss_minors[track2] = NULL; snd_oss_minors[minor] = NULL; - mutex_unlock(&sound_oss_mutex); /* call unregister_sound_special() outside sound_oss_mutex; * otherwise may deadlock, as it can trigger the release of a card @@ -220,7 +214,7 @@ static void snd_minor_info_oss_read(struct snd_info_entry *entry, int minor; struct snd_minor *mptr; - mutex_lock(&sound_oss_mutex); + guard(mutex)(&sound_oss_mutex); for (minor = 0; minor < SNDRV_OSS_MINORS; ++minor) { mptr = snd_oss_minors[minor]; if (!mptr) @@ -233,7 +227,6 @@ static void snd_minor_info_oss_read(struct snd_info_entry *entry, snd_iprintf(buffer, "%3i: : %s\n", minor, snd_oss_device_type_name(mptr->type)); } - mutex_unlock(&sound_oss_mutex); } -- cgit 1.2.3-korg From 68f014a58b6540847b0939a9a4023ed6eb834608 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Feb 2024 09:52:54 +0100 Subject: ALSA: seq: fifo: Use guard() for locking We can simplify the code gracefully with new guard() macro and co for automatic cleanup of locks. Only the code refactoring, and no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240227085306.9764-13-tiwai@suse.de --- sound/core/seq/seq_fifo.c | 55 +++++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 31 deletions(-) (limited to 'sound') diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c index f8e02e98709ab..3a10b081f129c 100644 --- a/sound/core/seq/seq_fifo.c +++ b/sound/core/seq/seq_fifo.c @@ -88,12 +88,11 @@ void snd_seq_fifo_clear(struct snd_seq_fifo *f) atomic_set(&f->overflow, 0); snd_use_lock_sync(&f->use_lock); - spin_lock_irq(&f->lock); + guard(spinlock_irq)(&f->lock); /* drain the fifo */ while ((cell = fifo_cell_out(f)) != NULL) { snd_seq_cell_free(cell); } - spin_unlock_irq(&f->lock); } @@ -102,7 +101,6 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f, struct snd_seq_event *event) { struct snd_seq_event_cell *cell; - unsigned long flags; int err; if (snd_BUG_ON(!f)) @@ -118,15 +116,15 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f, } /* append new cells to fifo */ - spin_lock_irqsave(&f->lock, flags); - if (f->tail != NULL) - f->tail->next = cell; - f->tail = cell; - if (f->head == NULL) - f->head = cell; - cell->next = NULL; - f->cells++; - spin_unlock_irqrestore(&f->lock, flags); + scoped_guard(spinlock_irqsave, &f->lock) { + if (f->tail != NULL) + f->tail->next = cell; + f->tail = cell; + if (f->head == NULL) + f->head = cell; + cell->next = NULL; + f->cells++; + } /* wakeup client */ if (waitqueue_active(&f->input_sleep)) @@ -199,16 +197,13 @@ int snd_seq_fifo_cell_out(struct snd_seq_fifo *f, void snd_seq_fifo_cell_putback(struct snd_seq_fifo *f, struct snd_seq_event_cell *cell) { - unsigned long flags; - if (cell) { - spin_lock_irqsave(&f->lock, flags); + guard(spinlock_irqsave)(&f->lock); cell->next = f->head; f->head = cell; if (!f->tail) f->tail = cell; f->cells++; - spin_unlock_irqrestore(&f->lock, flags); } } @@ -239,17 +234,17 @@ int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize) return -ENOMEM; } - spin_lock_irq(&f->lock); - /* remember old pool */ - oldpool = f->pool; - oldhead = f->head; - /* exchange pools */ - f->pool = newpool; - f->head = NULL; - f->tail = NULL; - f->cells = 0; - /* NOTE: overflow flag is not cleared */ - spin_unlock_irq(&f->lock); + scoped_guard(spinlock_irq, &f->lock) { + /* remember old pool */ + oldpool = f->pool; + oldhead = f->head; + /* exchange pools */ + f->pool = newpool; + f->head = NULL; + f->tail = NULL; + f->cells = 0; + /* NOTE: overflow flag is not cleared */ + } /* close the old pool and wait until all users are gone */ snd_seq_pool_mark_closing(oldpool); @@ -268,16 +263,14 @@ int snd_seq_fifo_resize(struct snd_seq_fifo *f, int poolsize) /* get the number of unused cells safely */ int snd_seq_fifo_unused_cells(struct snd_seq_fifo *f) { - unsigned long flags; int cells; if (!f) return 0; snd_use_lock_use(&f->use_lock); - spin_lock_irqsave(&f->lock, flags); - cells = snd_seq_unused_cells(f->pool); - spin_unlock_irqrestore(&f->lock, flags); + scoped_guard(spinlock_irqsave, &f->lock) + cells = snd_seq_unused_cells(f->pool); snd_use_lock_free(&f->use_lock); return cells; } -- cgit 1.2.3-korg From 6768bd100081298a3fbbceba785adb004de41674 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Feb 2024 09:52:55 +0100 Subject: ALSA: seq: memory: Use guard() for locking We can simplify the code gracefully with new guard() macro and co for automatic cleanup of locks. Only the code refactoring, and no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240227085306.9764-14-tiwai@suse.de --- sound/core/seq/seq_memory.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c index e705e75381189..20155e3e87c6a 100644 --- a/sound/core/seq/seq_memory.c +++ b/sound/core/seq/seq_memory.c @@ -232,7 +232,6 @@ static inline void free_cell(struct snd_seq_pool *pool, void snd_seq_cell_free(struct snd_seq_event_cell * cell) { - unsigned long flags; struct snd_seq_pool *pool; if (snd_BUG_ON(!cell)) @@ -241,7 +240,7 @@ void snd_seq_cell_free(struct snd_seq_event_cell * cell) if (snd_BUG_ON(!pool)) return; - spin_lock_irqsave(&pool->lock, flags); + guard(spinlock_irqsave)(&pool->lock); free_cell(pool, cell); if (snd_seq_ev_is_variable(&cell->event)) { if (cell->event.data.ext.len & SNDRV_SEQ_EXT_CHAINED) { @@ -259,7 +258,6 @@ void snd_seq_cell_free(struct snd_seq_event_cell * cell) if (snd_seq_output_ok(pool)) wake_up(&pool->output_sleep); } - spin_unlock_irqrestore(&pool->lock, flags); } @@ -449,9 +447,8 @@ int snd_seq_pool_init(struct snd_seq_pool *pool) return -ENOMEM; /* add new cells to the free cell list */ - spin_lock_irq(&pool->lock); + guard(spinlock_irq)(&pool->lock); if (pool->ptr) { - spin_unlock_irq(&pool->lock); kvfree(cellptr); return 0; } @@ -470,20 +467,16 @@ int snd_seq_pool_init(struct snd_seq_pool *pool) /* init statistics */ pool->max_used = 0; pool->total_elements = pool->size; - spin_unlock_irq(&pool->lock); return 0; } /* refuse the further insertion to the pool */ void snd_seq_pool_mark_closing(struct snd_seq_pool *pool) { - unsigned long flags; - if (snd_BUG_ON(!pool)) return; - spin_lock_irqsave(&pool->lock, flags); + guard(spinlock_irqsave)(&pool->lock); pool->closing = 1; - spin_unlock_irqrestore(&pool->lock, flags); } /* remove events */ @@ -502,18 +495,17 @@ int snd_seq_pool_done(struct snd_seq_pool *pool) schedule_timeout_uninterruptible(1); /* release all resources */ - spin_lock_irq(&pool->lock); - ptr = pool->ptr; - pool->ptr = NULL; - pool->free = NULL; - pool->total_elements = 0; - spin_unlock_irq(&pool->lock); + scoped_guard(spinlock_irq, &pool->lock) { + ptr = pool->ptr; + pool->ptr = NULL; + pool->free = NULL; + pool->total_elements = 0; + } kvfree(ptr); - spin_lock_irq(&pool->lock); + guard(spinlock_irq)(&pool->lock); pool->closing = 0; - spin_unlock_irq(&pool->lock); return 0; } -- cgit 1.2.3-korg From a02f7a170fc10255e405149c4ddf92bdfbe4ac1c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Feb 2024 09:52:56 +0100 Subject: ALSA: seq: ports: Use guard() for locking We can simplify the code gracefully with new guard() macro and co for automatic cleanup of locks. Only the code refactoring, and no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240227085306.9764-15-tiwai@suse.de --- sound/core/seq/seq_ports.c | 114 +++++++++++++++++++-------------------------- 1 file changed, 49 insertions(+), 65 deletions(-) (limited to 'sound') diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index f3f14ff0f80f0..ca631ca4f2c64 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c @@ -48,17 +48,15 @@ struct snd_seq_client_port *snd_seq_port_use_ptr(struct snd_seq_client *client, if (client == NULL) return NULL; - read_lock(&client->ports_lock); + guard(read_lock)(&client->ports_lock); list_for_each_entry(port, &client->ports_list_head, list) { if (port->addr.port == num) { if (port->closing) break; /* deleting now */ snd_use_lock_use(&port->use_lock); - read_unlock(&client->ports_lock); return port; } } - read_unlock(&client->ports_lock); return NULL; /* not found */ } @@ -73,7 +71,7 @@ struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *cl num = pinfo->addr.port; found = NULL; - read_lock(&client->ports_lock); + guard(read_lock)(&client->ports_lock); list_for_each_entry(port, &client->ports_list_head, list) { if ((port->capability & SNDRV_SEQ_PORT_CAP_INACTIVE) && !check_inactive) @@ -93,7 +91,6 @@ struct snd_seq_client_port *snd_seq_port_query_nearest(struct snd_seq_client *cl else snd_use_lock_use(&found->use_lock); } - read_unlock(&client->ports_lock); return found; } @@ -145,13 +142,12 @@ int snd_seq_create_port(struct snd_seq_client *client, int port, snd_use_lock_use(&new_port->use_lock); num = max(port, 0); - mutex_lock(&client->ports_mutex); - write_lock_irq(&client->ports_lock); + guard(mutex)(&client->ports_mutex); + guard(write_lock_irq)(&client->ports_lock); list_for_each_entry(p, &client->ports_list_head, list) { if (p->addr.port == port) { kfree(new_port); - num = -EBUSY; - goto unlock; + return -EBUSY; } if (p->addr.port > num) break; @@ -164,9 +160,6 @@ int snd_seq_create_port(struct snd_seq_client *client, int port, new_port->addr.port = num; /* store the port number in the port */ sprintf(new_port->name, "port-%d", num); *port_ret = new_port; - unlock: - write_unlock_irq(&client->ports_lock); - mutex_unlock(&client->ports_mutex); return num; } @@ -281,19 +274,18 @@ int snd_seq_delete_port(struct snd_seq_client *client, int port) { struct snd_seq_client_port *found = NULL, *p; - mutex_lock(&client->ports_mutex); - write_lock_irq(&client->ports_lock); - list_for_each_entry(p, &client->ports_list_head, list) { - if (p->addr.port == port) { - /* ok found. delete from the list at first */ - list_del(&p->list); - client->num_ports--; - found = p; - break; + scoped_guard(mutex, &client->ports_mutex) { + guard(write_lock_irq)(&client->ports_lock); + list_for_each_entry(p, &client->ports_list_head, list) { + if (p->addr.port == port) { + /* ok found. delete from the list at first */ + list_del(&p->list); + client->num_ports--; + found = p; + break; + } } } - write_unlock_irq(&client->ports_lock); - mutex_unlock(&client->ports_mutex); if (found) return port_delete(client, found); else @@ -309,16 +301,16 @@ int snd_seq_delete_all_ports(struct snd_seq_client *client) /* move the port list to deleted_list, and * clear the port list in the client data. */ - mutex_lock(&client->ports_mutex); - write_lock_irq(&client->ports_lock); - if (! list_empty(&client->ports_list_head)) { - list_add(&deleted_list, &client->ports_list_head); - list_del_init(&client->ports_list_head); - } else { - INIT_LIST_HEAD(&deleted_list); + guard(mutex)(&client->ports_mutex); + scoped_guard(write_lock_irq, &client->ports_lock) { + if (!list_empty(&client->ports_list_head)) { + list_add(&deleted_list, &client->ports_list_head); + list_del_init(&client->ports_list_head); + } else { + INIT_LIST_HEAD(&deleted_list); + } + client->num_ports = 0; } - client->num_ports = 0; - write_unlock_irq(&client->ports_lock); /* remove each port in deleted_list */ list_for_each_entry_safe(port, tmp, &deleted_list, list) { @@ -326,7 +318,6 @@ int snd_seq_delete_all_ports(struct snd_seq_client *client) snd_seq_system_client_ev_port_exit(port->addr.client, port->addr.port); port_delete(client, port); } - mutex_unlock(&client->ports_mutex); return 0; } @@ -506,42 +497,37 @@ static int check_and_subscribe_port(struct snd_seq_client *client, int err; grp = is_src ? &port->c_src : &port->c_dest; - err = -EBUSY; - down_write(&grp->list_mutex); + guard(rwsem_write)(&grp->list_mutex); if (exclusive) { if (!list_empty(&grp->list_head)) - goto __error; + return -EBUSY; } else { if (grp->exclusive) - goto __error; + return -EBUSY; /* check whether already exists */ list_for_each(p, &grp->list_head) { s = get_subscriber(p, is_src); if (match_subs_info(&subs->info, &s->info)) - goto __error; + return -EBUSY; } } err = subscribe_port(client, port, grp, &subs->info, ack); if (err < 0) { grp->exclusive = 0; - goto __error; + return err; } /* add to list */ - write_lock_irq(&grp->list_lock); + guard(write_lock_irq)(&grp->list_lock); if (is_src) list_add_tail(&subs->src_list, &grp->list_head); else list_add_tail(&subs->dest_list, &grp->list_head); grp->exclusive = exclusive; atomic_inc(&subs->ref_count); - write_unlock_irq(&grp->list_lock); - err = 0; - __error: - up_write(&grp->list_mutex); - return err; + return 0; } /* called with grp->list_mutex held */ @@ -556,12 +542,12 @@ static void __delete_and_unsubscribe_port(struct snd_seq_client *client, grp = is_src ? &port->c_src : &port->c_dest; list = is_src ? &subs->src_list : &subs->dest_list; - write_lock_irq(&grp->list_lock); - empty = list_empty(list); - if (!empty) - list_del_init(list); - grp->exclusive = 0; - write_unlock_irq(&grp->list_lock); + scoped_guard(write_lock_irq, &grp->list_lock) { + empty = list_empty(list); + if (!empty) + list_del_init(list); + grp->exclusive = 0; + } if (!empty) unsubscribe_port(client, port, grp, &subs->info, ack); @@ -575,9 +561,8 @@ static void delete_and_unsubscribe_port(struct snd_seq_client *client, struct snd_seq_port_subs_info *grp; grp = is_src ? &port->c_src : &port->c_dest; - down_write(&grp->list_mutex); + guard(rwsem_write)(&grp->list_mutex); __delete_and_unsubscribe_port(client, port, subs, is_src, ack); - up_write(&grp->list_mutex); } /* connect two ports */ @@ -639,18 +624,18 @@ int snd_seq_port_disconnect(struct snd_seq_client *connector, /* always start from deleting the dest port for avoiding concurrent * deletions */ - down_write(&dest->list_mutex); - /* look for the connection */ - list_for_each_entry(subs, &dest->list_head, dest_list) { - if (match_subs_info(info, &subs->info)) { - __delete_and_unsubscribe_port(dest_client, dest_port, - subs, false, - connector->number != dest_client->number); - err = 0; - break; + scoped_guard(rwsem_write, &dest->list_mutex) { + /* look for the connection */ + list_for_each_entry(subs, &dest->list_head, dest_list) { + if (match_subs_info(info, &subs->info)) { + __delete_and_unsubscribe_port(dest_client, dest_port, + subs, false, + connector->number != dest_client->number); + err = 0; + break; + } } } - up_write(&dest->list_mutex); if (err < 0) return err; @@ -669,7 +654,7 @@ int snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp, struct snd_seq_subscribers *s; int err = -ENOENT; - down_read(&src_grp->list_mutex); + guard(rwsem_read)(&src_grp->list_mutex); list_for_each_entry(s, &src_grp->list_head, src_list) { if (addr_match(dest_addr, &s->info.dest)) { *subs = s->info; @@ -677,7 +662,6 @@ int snd_seq_port_get_subscription(struct snd_seq_port_subs_info *src_grp, break; } } - up_read(&src_grp->list_mutex); return err; } -- cgit 1.2.3-korg From 7c2e98218c56b6a51d628dcd388389080b7279a7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Feb 2024 09:52:57 +0100 Subject: ALSA: seq: queue: Use guard() for locking We can simplify the code gracefully with new guard() macro and co for automatic cleanup of locks. Only the code refactoring, and no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240227085306.9764-16-tiwai@suse.de --- sound/core/seq/seq_queue.c | 78 +++++++++++++++++----------------------------- 1 file changed, 28 insertions(+), 50 deletions(-) (limited to 'sound') diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c index bc933104c3eea..500ee6b19c717 100644 --- a/sound/core/seq/seq_queue.c +++ b/sound/core/seq/seq_queue.c @@ -50,43 +50,35 @@ int snd_seq_queue_get_cur_queues(void) static int queue_list_add(struct snd_seq_queue *q) { int i; - unsigned long flags; - spin_lock_irqsave(&queue_list_lock, flags); + guard(spinlock_irqsave)(&queue_list_lock); for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) { if (! queue_list[i]) { queue_list[i] = q; q->queue = i; num_queues++; - spin_unlock_irqrestore(&queue_list_lock, flags); return i; } } - spin_unlock_irqrestore(&queue_list_lock, flags); return -1; } static struct snd_seq_queue *queue_list_remove(int id, int client) { struct snd_seq_queue *q; - unsigned long flags; - spin_lock_irqsave(&queue_list_lock, flags); + guard(spinlock_irqsave)(&queue_list_lock); q = queue_list[id]; if (q) { - spin_lock(&q->owner_lock); + guard(spinlock)(&q->owner_lock); if (q->owner == client) { /* found */ q->klocked = 1; - spin_unlock(&q->owner_lock); queue_list[id] = NULL; num_queues--; - spin_unlock_irqrestore(&queue_list_lock, flags); return q; } - spin_unlock(&q->owner_lock); } - spin_unlock_irqrestore(&queue_list_lock, flags); return NULL; } @@ -203,15 +195,13 @@ int snd_seq_queue_delete(int client, int queueid) struct snd_seq_queue *queueptr(int queueid) { struct snd_seq_queue *q; - unsigned long flags; if (queueid < 0 || queueid >= SNDRV_SEQ_MAX_QUEUES) return NULL; - spin_lock_irqsave(&queue_list_lock, flags); + guard(spinlock_irqsave)(&queue_list_lock); q = queue_list[queueid]; if (q) snd_use_lock_use(&q->use_lock); - spin_unlock_irqrestore(&queue_list_lock, flags); return q; } @@ -239,7 +229,6 @@ struct snd_seq_queue *snd_seq_queue_find_name(char *name) void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop) { - unsigned long flags; struct snd_seq_event_cell *cell; snd_seq_tick_time_t cur_tick; snd_seq_real_time_t cur_time; @@ -249,14 +238,13 @@ void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop) return; /* make this function non-reentrant */ - spin_lock_irqsave(&q->check_lock, flags); - if (q->check_blocked) { - q->check_again = 1; - spin_unlock_irqrestore(&q->check_lock, flags); - return; /* other thread is already checking queues */ + scoped_guard(spinlock_irqsave, &q->check_lock) { + if (q->check_blocked) { + q->check_again = 1; + return; /* other thread is already checking queues */ + } + q->check_blocked = 1; } - q->check_blocked = 1; - spin_unlock_irqrestore(&q->check_lock, flags); __again: /* Process tick queue... */ @@ -283,16 +271,14 @@ void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop) out: /* free lock */ - spin_lock_irqsave(&q->check_lock, flags); - if (q->check_again) { - q->check_again = 0; - if (processed < MAX_CELL_PROCESSES_IN_QUEUE) { - spin_unlock_irqrestore(&q->check_lock, flags); - goto __again; + scoped_guard(spinlock_irqsave, &q->check_lock) { + if (q->check_again) { + q->check_again = 0; + if (processed < MAX_CELL_PROCESSES_IN_QUEUE) + goto __again; } + q->check_blocked = 0; } - q->check_blocked = 0; - spin_unlock_irqrestore(&q->check_lock, flags); } @@ -361,25 +347,20 @@ static inline int check_access(struct snd_seq_queue *q, int client) */ static int queue_access_lock(struct snd_seq_queue *q, int client) { - unsigned long flags; int access_ok; - spin_lock_irqsave(&q->owner_lock, flags); + guard(spinlock_irqsave)(&q->owner_lock); access_ok = check_access(q, client); if (access_ok) q->klocked = 1; - spin_unlock_irqrestore(&q->owner_lock, flags); return access_ok; } /* unlock the queue */ static inline void queue_access_unlock(struct snd_seq_queue *q) { - unsigned long flags; - - spin_lock_irqsave(&q->owner_lock, flags); + guard(spinlock_irqsave)(&q->owner_lock); q->klocked = 0; - spin_unlock_irqrestore(&q->owner_lock, flags); } /* exported - only checking permission */ @@ -387,13 +368,11 @@ int snd_seq_queue_check_access(int queueid, int client) { struct snd_seq_queue *q = queueptr(queueid); int access_ok; - unsigned long flags; if (! q) return 0; - spin_lock_irqsave(&q->owner_lock, flags); - access_ok = check_access(q, client); - spin_unlock_irqrestore(&q->owner_lock, flags); + scoped_guard(spinlock_irqsave, &q->owner_lock) + access_ok = check_access(q, client); queuefree(q); return access_ok; } @@ -406,7 +385,6 @@ int snd_seq_queue_check_access(int queueid, int client) int snd_seq_queue_set_owner(int queueid, int client, int locked) { struct snd_seq_queue *q = queueptr(queueid); - unsigned long flags; if (q == NULL) return -EINVAL; @@ -416,10 +394,10 @@ int snd_seq_queue_set_owner(int queueid, int client, int locked) return -EPERM; } - spin_lock_irqsave(&q->owner_lock, flags); - q->locked = locked ? 1 : 0; - q->owner = client; - spin_unlock_irqrestore(&q->owner_lock, flags); + scoped_guard(spinlock_irqsave, &q->owner_lock) { + q->locked = locked ? 1 : 0; + q->owner = client; + } queue_access_unlock(q); queuefree(q); @@ -750,10 +728,10 @@ void snd_seq_info_queues_read(struct snd_info_entry *entry, else bpm = 0; - spin_lock_irq(&q->owner_lock); - locked = q->locked; - owner = q->owner; - spin_unlock_irq(&q->owner_lock); + scoped_guard(spinlock_irq, &q->owner_lock) { + locked = q->locked; + owner = q->owner; + } snd_iprintf(buffer, "queue %d: [%s]\n", q->queue, q->name); snd_iprintf(buffer, "owned by client : %d\n", owner); -- cgit 1.2.3-korg From aa75a2229219caee5dbee7574ccddeaf8b8f67f6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Feb 2024 09:52:58 +0100 Subject: ALSA: seq: timer: Use guard() for locking We can simplify the code gracefully with new guard() macro and co for automatic cleanup of locks. Only the code refactoring, and no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240227085306.9764-17-tiwai@suse.de --- sound/core/seq/seq_timer.c | 155 ++++++++++++++++----------------------------- 1 file changed, 54 insertions(+), 101 deletions(-) (limited to 'sound') diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index 9863be6fd43e1..ad2b97e2762d9 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c @@ -75,9 +75,7 @@ void snd_seq_timer_delete(struct snd_seq_timer **tmr) void snd_seq_timer_defaults(struct snd_seq_timer * tmr) { - unsigned long flags; - - spin_lock_irqsave(&tmr->lock, flags); + guard(spinlock_irqsave)(&tmr->lock); /* setup defaults */ tmr->ppq = 96; /* 96 PPQ */ tmr->tempo = 500000; /* 120 BPM */ @@ -93,7 +91,6 @@ void snd_seq_timer_defaults(struct snd_seq_timer * tmr) tmr->preferred_resolution = seq_default_timer_resolution; tmr->skew = tmr->skew_base = SKEW_BASE; - spin_unlock_irqrestore(&tmr->lock, flags); } static void seq_timer_reset(struct snd_seq_timer *tmr) @@ -108,11 +105,8 @@ static void seq_timer_reset(struct snd_seq_timer *tmr) void snd_seq_timer_reset(struct snd_seq_timer *tmr) { - unsigned long flags; - - spin_lock_irqsave(&tmr->lock, flags); + guard(spinlock_irqsave)(&tmr->lock); seq_timer_reset(tmr); - spin_unlock_irqrestore(&tmr->lock, flags); } @@ -121,7 +115,6 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri, unsigned long resolution, unsigned long ticks) { - unsigned long flags; struct snd_seq_queue *q = timeri->callback_data; struct snd_seq_timer *tmr; @@ -130,29 +123,27 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri, tmr = q->timer; if (tmr == NULL) return; - spin_lock_irqsave(&tmr->lock, flags); - if (!tmr->running) { - spin_unlock_irqrestore(&tmr->lock, flags); - return; - } - resolution *= ticks; - if (tmr->skew != tmr->skew_base) { - /* FIXME: assuming skew_base = 0x10000 */ - resolution = (resolution >> 16) * tmr->skew + - (((resolution & 0xffff) * tmr->skew) >> 16); - } + scoped_guard(spinlock_irqsave, &tmr->lock) { + if (!tmr->running) + return; - /* update timer */ - snd_seq_inc_time_nsec(&tmr->cur_time, resolution); + resolution *= ticks; + if (tmr->skew != tmr->skew_base) { + /* FIXME: assuming skew_base = 0x10000 */ + resolution = (resolution >> 16) * tmr->skew + + (((resolution & 0xffff) * tmr->skew) >> 16); + } - /* calculate current tick */ - snd_seq_timer_update_tick(&tmr->tick, resolution); + /* update timer */ + snd_seq_inc_time_nsec(&tmr->cur_time, resolution); - /* register actual time of this timer update */ - ktime_get_ts64(&tmr->last_update); + /* calculate current tick */ + snd_seq_timer_update_tick(&tmr->tick, resolution); - spin_unlock_irqrestore(&tmr->lock, flags); + /* register actual time of this timer update */ + ktime_get_ts64(&tmr->last_update); + } /* check queues and dispatch events */ snd_seq_check_queue(q, 1, 0); @@ -161,18 +152,15 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri, /* set current tempo */ int snd_seq_timer_set_tempo(struct snd_seq_timer * tmr, int tempo) { - unsigned long flags; - if (snd_BUG_ON(!tmr)) return -EINVAL; if (tempo <= 0) return -EINVAL; - spin_lock_irqsave(&tmr->lock, flags); + guard(spinlock_irqsave)(&tmr->lock); if ((unsigned int)tempo != tmr->tempo) { tmr->tempo = tempo; snd_seq_timer_set_tick_resolution(tmr); } - spin_unlock_irqrestore(&tmr->lock, flags); return 0; } @@ -180,17 +168,15 @@ int snd_seq_timer_set_tempo(struct snd_seq_timer * tmr, int tempo) int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq) { int changed; - unsigned long flags; if (snd_BUG_ON(!tmr)) return -EINVAL; if (tempo <= 0 || ppq <= 0) return -EINVAL; - spin_lock_irqsave(&tmr->lock, flags); + guard(spinlock_irqsave)(&tmr->lock); if (tmr->running && (ppq != tmr->ppq)) { /* refuse to change ppq on running timers */ /* because it will upset the song position (ticks) */ - spin_unlock_irqrestore(&tmr->lock, flags); pr_debug("ALSA: seq: cannot change ppq of a running timer\n"); return -EBUSY; } @@ -199,7 +185,6 @@ int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq) tmr->ppq = ppq; if (changed) snd_seq_timer_set_tick_resolution(tmr); - spin_unlock_irqrestore(&tmr->lock, flags); return 0; } @@ -207,15 +192,12 @@ int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq) int snd_seq_timer_set_position_tick(struct snd_seq_timer *tmr, snd_seq_tick_time_t position) { - unsigned long flags; - if (snd_BUG_ON(!tmr)) return -EINVAL; - spin_lock_irqsave(&tmr->lock, flags); + guard(spinlock_irqsave)(&tmr->lock); tmr->tick.cur_tick = position; tmr->tick.fraction = 0; - spin_unlock_irqrestore(&tmr->lock, flags); return 0; } @@ -223,15 +205,12 @@ int snd_seq_timer_set_position_tick(struct snd_seq_timer *tmr, int snd_seq_timer_set_position_time(struct snd_seq_timer *tmr, snd_seq_real_time_t position) { - unsigned long flags; - if (snd_BUG_ON(!tmr)) return -EINVAL; snd_seq_sanity_real_time(&position); - spin_lock_irqsave(&tmr->lock, flags); + guard(spinlock_irqsave)(&tmr->lock); tmr->cur_time = position; - spin_unlock_irqrestore(&tmr->lock, flags); return 0; } @@ -239,8 +218,6 @@ int snd_seq_timer_set_position_time(struct snd_seq_timer *tmr, int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew, unsigned int base) { - unsigned long flags; - if (snd_BUG_ON(!tmr)) return -EINVAL; @@ -249,9 +226,8 @@ int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew, pr_debug("ALSA: seq: invalid skew base 0x%x\n", base); return -EINVAL; } - spin_lock_irqsave(&tmr->lock, flags); + guard(spinlock_irqsave)(&tmr->lock); tmr->skew = skew; - spin_unlock_irqrestore(&tmr->lock, flags); return 0; } @@ -296,12 +272,12 @@ int snd_seq_timer_open(struct snd_seq_queue *q) snd_timer_instance_free(t); return err; } - spin_lock_irq(&tmr->lock); - if (tmr->timeri) - err = -EBUSY; - else - tmr->timeri = t; - spin_unlock_irq(&tmr->lock); + scoped_guard(spinlock_irq, &tmr->lock) { + if (tmr->timeri) + err = -EBUSY; + else + tmr->timeri = t; + } if (err < 0) { snd_timer_close(t); snd_timer_instance_free(t); @@ -318,10 +294,10 @@ int snd_seq_timer_close(struct snd_seq_queue *q) tmr = q->timer; if (snd_BUG_ON(!tmr)) return -EINVAL; - spin_lock_irq(&tmr->lock); - t = tmr->timeri; - tmr->timeri = NULL; - spin_unlock_irq(&tmr->lock); + scoped_guard(spinlock_irq, &tmr->lock) { + t = tmr->timeri; + tmr->timeri = NULL; + } if (t) { snd_timer_close(t); snd_timer_instance_free(t); @@ -342,13 +318,8 @@ static int seq_timer_stop(struct snd_seq_timer *tmr) int snd_seq_timer_stop(struct snd_seq_timer *tmr) { - unsigned long flags; - int err; - - spin_lock_irqsave(&tmr->lock, flags); - err = seq_timer_stop(tmr); - spin_unlock_irqrestore(&tmr->lock, flags); - return err; + guard(spinlock_irqsave)(&tmr->lock); + return seq_timer_stop(tmr); } static int initialize_timer(struct snd_seq_timer *tmr) @@ -398,13 +369,8 @@ static int seq_timer_start(struct snd_seq_timer *tmr) int snd_seq_timer_start(struct snd_seq_timer *tmr) { - unsigned long flags; - int err; - - spin_lock_irqsave(&tmr->lock, flags); - err = seq_timer_start(tmr); - spin_unlock_irqrestore(&tmr->lock, flags); - return err; + guard(spinlock_irqsave)(&tmr->lock); + return seq_timer_start(tmr); } static int seq_timer_continue(struct snd_seq_timer *tmr) @@ -426,13 +392,8 @@ static int seq_timer_continue(struct snd_seq_timer *tmr) int snd_seq_timer_continue(struct snd_seq_timer *tmr) { - unsigned long flags; - int err; - - spin_lock_irqsave(&tmr->lock, flags); - err = seq_timer_continue(tmr); - spin_unlock_irqrestore(&tmr->lock, flags); - return err; + guard(spinlock_irqsave)(&tmr->lock); + return seq_timer_continue(tmr); } /* return current 'real' time. use timeofday() to get better granularity. */ @@ -440,9 +401,8 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr, bool adjust_ktime) { snd_seq_real_time_t cur_time; - unsigned long flags; - spin_lock_irqsave(&tmr->lock, flags); + guard(spinlock_irqsave)(&tmr->lock); cur_time = tmr->cur_time; if (adjust_ktime && tmr->running) { struct timespec64 tm; @@ -453,7 +413,6 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr, cur_time.tv_sec += tm.tv_sec; snd_seq_sanity_real_time(&cur_time); } - spin_unlock_irqrestore(&tmr->lock, flags); return cur_time; } @@ -461,13 +420,8 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr, high PPQ values) */ snd_seq_tick_time_t snd_seq_timer_get_cur_tick(struct snd_seq_timer *tmr) { - snd_seq_tick_time_t cur_tick; - unsigned long flags; - - spin_lock_irqsave(&tmr->lock, flags); - cur_tick = tmr->tick.cur_tick; - spin_unlock_irqrestore(&tmr->lock, flags); - return cur_tick; + guard(spinlock_irqsave)(&tmr->lock); + return tmr->tick.cur_tick; } @@ -486,19 +440,18 @@ void snd_seq_info_timer_read(struct snd_info_entry *entry, q = queueptr(idx); if (q == NULL) continue; - mutex_lock(&q->timer_mutex); - tmr = q->timer; - if (!tmr) - goto unlock; - ti = tmr->timeri; - if (!ti) - goto unlock; - snd_iprintf(buffer, "Timer for queue %i : %s\n", q->queue, ti->timer->name); - resolution = snd_timer_resolution(ti) * tmr->ticks; - snd_iprintf(buffer, " Period time : %lu.%09lu\n", resolution / 1000000000, resolution % 1000000000); - snd_iprintf(buffer, " Skew : %u / %u\n", tmr->skew, tmr->skew_base); -unlock: - mutex_unlock(&q->timer_mutex); + scoped_guard(mutex, &q->timer_mutex) { + tmr = q->timer; + if (!tmr) + break; + ti = tmr->timeri; + if (!ti) + break; + snd_iprintf(buffer, "Timer for queue %i : %s\n", q->queue, ti->timer->name); + resolution = snd_timer_resolution(ti) * tmr->ticks; + snd_iprintf(buffer, " Period time : %lu.%09lu\n", resolution / 1000000000, resolution % 1000000000); + snd_iprintf(buffer, " Skew : %u / %u\n", tmr->skew, tmr->skew_base); + } queuefree(q); } } -- cgit 1.2.3-korg From 45bab301d80b94790c1d9e98ac903aeb373d5f36 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Feb 2024 09:52:59 +0100 Subject: ALSA: seq: midi: Use guard() for locking We can simplify the code gracefully with new guard() macro and co for automatic cleanup of locks. Only the code refactoring, and no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240227085306.9764-18-tiwai@suse.de --- sound/core/seq/seq_midi.c | 16 ++++------------ sound/core/seq/seq_midi_event.c | 14 +++----------- 2 files changed, 7 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index 0594269d92abc..ba52a77eda382 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c @@ -302,22 +302,19 @@ snd_seq_midisynth_probe(struct device *_dev) if (ports > (256 / SNDRV_RAWMIDI_DEVICES)) ports = 256 / SNDRV_RAWMIDI_DEVICES; - mutex_lock(®ister_mutex); + guard(mutex)(®ister_mutex); client = synths[card->number]; if (client == NULL) { newclient = 1; client = kzalloc(sizeof(*client), GFP_KERNEL); - if (client == NULL) { - mutex_unlock(®ister_mutex); + if (client == NULL) return -ENOMEM; - } client->seq_client = snd_seq_create_kernel_client( card, 0, "%s", card->shortname[0] ? (const char *)card->shortname : "External MIDI"); if (client->seq_client < 0) { kfree(client); - mutex_unlock(®ister_mutex); return -ENOMEM; } } @@ -398,7 +395,6 @@ snd_seq_midisynth_probe(struct device *_dev) client->num_ports++; if (newclient) synths[card->number] = client; - mutex_unlock(®ister_mutex); return 0; /* success */ __nomem: @@ -411,7 +407,6 @@ snd_seq_midisynth_probe(struct device *_dev) snd_seq_delete_kernel_client(client->seq_client); kfree(client); } - mutex_unlock(®ister_mutex); return -ENOMEM; } @@ -425,12 +420,10 @@ snd_seq_midisynth_remove(struct device *_dev) struct snd_card *card = dev->card; int device = dev->device, p, ports; - mutex_lock(®ister_mutex); + guard(mutex)(®ister_mutex); client = synths[card->number]; - if (client == NULL || client->ports[device] == NULL) { - mutex_unlock(®ister_mutex); + if (client == NULL || client->ports[device] == NULL) return -ENODEV; - } ports = client->ports_per_device[device]; client->ports_per_device[device] = 0; msynth = client->ports[device]; @@ -444,7 +437,6 @@ snd_seq_midisynth_remove(struct device *_dev) synths[card->number] = NULL; kfree(client); } - mutex_unlock(®ister_mutex); return 0; } diff --git a/sound/core/seq/seq_midi_event.c b/sound/core/seq/seq_midi_event.c index 7511462fe0718..fa9dfc53c3fcc 100644 --- a/sound/core/seq/seq_midi_event.c +++ b/sound/core/seq/seq_midi_event.c @@ -144,21 +144,15 @@ static inline void reset_encode(struct snd_midi_event *dev) void snd_midi_event_reset_encode(struct snd_midi_event *dev) { - unsigned long flags; - - spin_lock_irqsave(&dev->lock, flags); + guard(spinlock_irqsave)(&dev->lock); reset_encode(dev); - spin_unlock_irqrestore(&dev->lock, flags); } EXPORT_SYMBOL(snd_midi_event_reset_encode); void snd_midi_event_reset_decode(struct snd_midi_event *dev) { - unsigned long flags; - - spin_lock_irqsave(&dev->lock, flags); + guard(spinlock_irqsave)(&dev->lock); dev->lastcmd = 0xff; - spin_unlock_irqrestore(&dev->lock, flags); } EXPORT_SYMBOL(snd_midi_event_reset_decode); @@ -177,7 +171,6 @@ bool snd_midi_event_encode_byte(struct snd_midi_event *dev, unsigned char c, struct snd_seq_event *ev) { bool rc = false; - unsigned long flags; if (c >= MIDI_CMD_COMMON_CLOCK) { /* real-time event */ @@ -187,7 +180,7 @@ bool snd_midi_event_encode_byte(struct snd_midi_event *dev, unsigned char c, return ev->type != SNDRV_SEQ_EVENT_NONE; } - spin_lock_irqsave(&dev->lock, flags); + guard(spinlock_irqsave)(&dev->lock); if ((c & 0x80) && (c != MIDI_CMD_COMMON_SYSEX_END || dev->type != ST_SYSEX)) { /* new command */ @@ -236,7 +229,6 @@ bool snd_midi_event_encode_byte(struct snd_midi_event *dev, unsigned char c, } } - spin_unlock_irqrestore(&dev->lock, flags); return rc; } EXPORT_SYMBOL(snd_midi_event_encode_byte); -- cgit 1.2.3-korg From 6487e363714c28c4b62ac149e7d907cfeeedb3ad Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Feb 2024 09:53:00 +0100 Subject: ALSA: seq: ump: Use guard() for locking We can simplify the code gracefully with new guard() macro and co for automatic cleanup of locks. Only the code refactoring, and no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240227085306.9764-19-tiwai@suse.de --- sound/core/seq/seq_ump_client.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/core/seq/seq_ump_client.c b/sound/core/seq/seq_ump_client.c index ccac2d3a9fbcb..c627d72f7fe20 100644 --- a/sound/core/seq/seq_ump_client.c +++ b/sound/core/seq/seq_ump_client.c @@ -115,21 +115,19 @@ static int seq_ump_process_event(struct snd_seq_event *ev, int direct, static int seq_ump_client_open(struct seq_ump_client *client, int dir) { struct snd_ump_endpoint *ump = client->ump; - int err = 0; + int err; - mutex_lock(&ump->open_mutex); + guard(mutex)(&ump->open_mutex); if (dir == STR_OUT && !client->opened[dir]) { err = snd_rawmidi_kernel_open(&ump->core, 0, SNDRV_RAWMIDI_LFLG_OUTPUT | SNDRV_RAWMIDI_LFLG_APPEND, &client->out_rfile); if (err < 0) - goto unlock; + return err; } client->opened[dir]++; - unlock: - mutex_unlock(&ump->open_mutex); - return err; + return 0; } /* close the rawmidi */ @@ -137,11 +135,10 @@ static int seq_ump_client_close(struct seq_ump_client *client, int dir) { struct snd_ump_endpoint *ump = client->ump; - mutex_lock(&ump->open_mutex); + guard(mutex)(&ump->open_mutex); if (!--client->opened[dir]) if (dir == STR_OUT) snd_rawmidi_kernel_release(&client->out_rfile); - mutex_unlock(&ump->open_mutex); return 0; } -- cgit 1.2.3-korg From a04f2c396031a33a1df51c9c6012650a40ba9d7e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Feb 2024 09:53:01 +0100 Subject: ALSA: seq: virmidi: Use guard() for locking We can simplify the code gracefully with new guard() macro and co for automatic cleanup of locks. Only the code refactoring, and no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240227085306.9764-20-tiwai@suse.de --- sound/core/seq/seq_virmidi.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 35f93b43dd2ac..b4672613c2613 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -199,11 +199,10 @@ static int snd_virmidi_input_open(struct snd_rawmidi_substream *substream) vmidi->client = rdev->client; vmidi->port = rdev->port; runtime->private_data = vmidi; - down_write(&rdev->filelist_sem); - write_lock_irq(&rdev->filelist_lock); - list_add_tail(&vmidi->list, &rdev->filelist); - write_unlock_irq(&rdev->filelist_lock); - up_write(&rdev->filelist_sem); + scoped_guard(rwsem_write, &rdev->filelist_sem) { + guard(write_lock_irq)(&rdev->filelist_lock); + list_add_tail(&vmidi->list, &rdev->filelist); + } vmidi->rdev = rdev; return 0; } @@ -243,11 +242,10 @@ static int snd_virmidi_input_close(struct snd_rawmidi_substream *substream) struct snd_virmidi_dev *rdev = substream->rmidi->private_data; struct snd_virmidi *vmidi = substream->runtime->private_data; - down_write(&rdev->filelist_sem); - write_lock_irq(&rdev->filelist_lock); - list_del(&vmidi->list); - write_unlock_irq(&rdev->filelist_lock); - up_write(&rdev->filelist_sem); + scoped_guard(rwsem_write, &rdev->filelist_sem) { + guard(write_lock_irq)(&rdev->filelist_lock); + list_del(&vmidi->list); + } snd_midi_event_free(vmidi->parser); substream->runtime->private_data = NULL; kfree(vmidi); -- cgit 1.2.3-korg From 1affe7bb50c9bda4d4ada1ecab90ce6d27e77b00 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Feb 2024 09:53:02 +0100 Subject: ALSA: seq: prioq: Use guard() for locking We can simplify the code gracefully with new guard() macro and co for automatic cleanup of locks. Only the code refactoring, and no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240227085306.9764-21-tiwai@suse.de --- sound/core/seq/seq_prioq.c | 59 ++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 33 deletions(-) (limited to 'sound') diff --git a/sound/core/seq/seq_prioq.c b/sound/core/seq/seq_prioq.c index e062df7610e1d..e649485a87722 100644 --- a/sound/core/seq/seq_prioq.c +++ b/sound/core/seq/seq_prioq.c @@ -132,7 +132,6 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f, struct snd_seq_event_cell * cell) { struct snd_seq_event_cell *cur, *prev; - unsigned long flags; int count; int prior; @@ -142,7 +141,7 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f, /* check flags */ prior = (cell->event.flags & SNDRV_SEQ_PRIORITY_MASK); - spin_lock_irqsave(&f->lock, flags); + guard(spinlock_irqsave)(&f->lock); /* check if this element needs to inserted at the end (ie. ordered data is inserted) This will be very likeley if a sequencer @@ -154,7 +153,6 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f, f->tail = cell; cell->next = NULL; f->cells++; - spin_unlock_irqrestore(&f->lock, flags); return 0; } } @@ -179,7 +177,6 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f, prev = cur; cur = cur->next; if (! --count) { - spin_unlock_irqrestore(&f->lock, flags); pr_err("ALSA: seq: cannot find a pointer.. infinite loop?\n"); return -EINVAL; } @@ -195,7 +192,6 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f, if (cur == NULL) /* reached end of the list */ f->tail = cell; f->cells++; - spin_unlock_irqrestore(&f->lock, flags); return 0; } @@ -213,14 +209,13 @@ struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f, void *current_time) { struct snd_seq_event_cell *cell; - unsigned long flags; if (f == NULL) { pr_debug("ALSA: seq: snd_seq_prioq_cell_in() called with NULL prioq\n"); return NULL; } - spin_lock_irqsave(&f->lock, flags); + guard(spinlock_irqsave)(&f->lock); cell = f->head; if (cell && current_time && !event_is_ready(&cell->event, current_time)) cell = NULL; @@ -235,7 +230,6 @@ struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f, f->cells--; } - spin_unlock_irqrestore(&f->lock, flags); return cell; } @@ -256,37 +250,36 @@ static void prioq_remove_cells(struct snd_seq_prioq *f, void *arg) { register struct snd_seq_event_cell *cell, *next; - unsigned long flags; struct snd_seq_event_cell *prev = NULL; struct snd_seq_event_cell *freefirst = NULL, *freeprev = NULL, *freenext; /* collect all removed cells */ - spin_lock_irqsave(&f->lock, flags); - for (cell = f->head; cell; cell = next) { - next = cell->next; - if (!match(cell, arg)) { - prev = cell; - continue; - } - - /* remove cell from prioq */ - if (cell == f->head) - f->head = cell->next; - else - prev->next = cell->next; - if (cell == f->tail) - f->tail = cell->next; - f->cells--; + scoped_guard(spinlock_irqsave, &f->lock) { + for (cell = f->head; cell; cell = next) { + next = cell->next; + if (!match(cell, arg)) { + prev = cell; + continue; + } + + /* remove cell from prioq */ + if (cell == f->head) + f->head = cell->next; + else + prev->next = cell->next; + if (cell == f->tail) + f->tail = cell->next; + f->cells--; - /* add cell to free list */ - cell->next = NULL; - if (freefirst == NULL) - freefirst = cell; - else - freeprev->next = cell; - freeprev = cell; + /* add cell to free list */ + cell->next = NULL; + if (freefirst == NULL) + freefirst = cell; + else + freeprev->next = cell; + freeprev = cell; + } } - spin_unlock_irqrestore(&f->lock, flags); /* remove selected cells */ while (freefirst) { -- cgit 1.2.3-korg From dd0da75b9a2768710366a599c9bd70058e67e2ea Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Feb 2024 09:53:03 +0100 Subject: ALSA: pcm: Use guard() for locking We can simplify the code gracefully with new guard() macro and co for automatic cleanup of locks. Only the code refactoring, and no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240227085306.9764-22-tiwai@suse.de --- sound/core/pcm.c | 90 +++++++++++++++++-------------------------------- sound/core/pcm_memory.c | 30 +++++++---------- sound/core/pcm_native.c | 48 +++++++++----------------- 3 files changed, 59 insertions(+), 109 deletions(-) (limited to 'sound') diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 87d27fbdfe5c8..dc37f3508dc7a 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -91,9 +91,8 @@ static int snd_pcm_control_ioctl(struct snd_card *card, if (get_user(device, (int __user *)arg)) return -EFAULT; - mutex_lock(®ister_mutex); - device = snd_pcm_next(card, device); - mutex_unlock(®ister_mutex); + scoped_guard(mutex, ®ister_mutex) + device = snd_pcm_next(card, device); if (put_user(device, (int __user *)arg)) return -EFAULT; return 0; @@ -106,7 +105,6 @@ static int snd_pcm_control_ioctl(struct snd_card *card, struct snd_pcm *pcm; struct snd_pcm_str *pstr; struct snd_pcm_substream *substream; - int err; info = (struct snd_pcm_info __user *)arg; if (get_user(device, &info->device)) @@ -118,35 +116,23 @@ static int snd_pcm_control_ioctl(struct snd_card *card, stream = array_index_nospec(stream, 2); if (get_user(subdevice, &info->subdevice)) return -EFAULT; - mutex_lock(®ister_mutex); + guard(mutex)(®ister_mutex); pcm = snd_pcm_get(card, device); - if (pcm == NULL) { - err = -ENXIO; - goto _error; - } + if (pcm == NULL) + return -ENXIO; pstr = &pcm->streams[stream]; - if (pstr->substream_count == 0) { - err = -ENOENT; - goto _error; - } - if (subdevice >= pstr->substream_count) { - err = -ENXIO; - goto _error; - } + if (pstr->substream_count == 0) + return -ENOENT; + if (subdevice >= pstr->substream_count) + return -ENXIO; for (substream = pstr->substream; substream; substream = substream->next) if (substream->number == (int)subdevice) break; - if (substream == NULL) { - err = -ENXIO; - goto _error; - } - mutex_lock(&pcm->open_mutex); - err = snd_pcm_info_user(substream, info); - mutex_unlock(&pcm->open_mutex); - _error: - mutex_unlock(®ister_mutex); - return err; + if (substream == NULL) + return -ENXIO; + guard(mutex)(&pcm->open_mutex); + return snd_pcm_info_user(substream, info); } case SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE: { @@ -389,15 +375,15 @@ static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry, struct snd_pcm_substream *substream = entry->private_data; struct snd_pcm_runtime *runtime; - mutex_lock(&substream->pcm->open_mutex); + guard(mutex)(&substream->pcm->open_mutex); runtime = substream->runtime; if (!runtime) { snd_iprintf(buffer, "closed\n"); - goto unlock; + return; } if (runtime->state == SNDRV_PCM_STATE_OPEN) { snd_iprintf(buffer, "no setup\n"); - goto unlock; + return; } snd_iprintf(buffer, "access: %s\n", snd_pcm_access_name(runtime->access)); snd_iprintf(buffer, "format: %s\n", snd_pcm_format_name(runtime->format)); @@ -416,8 +402,6 @@ static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry, snd_iprintf(buffer, "OSS period frames: %lu\n", (unsigned long)runtime->oss.period_frames); } #endif - unlock: - mutex_unlock(&substream->pcm->open_mutex); } static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry, @@ -426,15 +410,15 @@ static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry, struct snd_pcm_substream *substream = entry->private_data; struct snd_pcm_runtime *runtime; - mutex_lock(&substream->pcm->open_mutex); + guard(mutex)(&substream->pcm->open_mutex); runtime = substream->runtime; if (!runtime) { snd_iprintf(buffer, "closed\n"); - goto unlock; + return; } if (runtime->state == SNDRV_PCM_STATE_OPEN) { snd_iprintf(buffer, "no setup\n"); - goto unlock; + return; } snd_iprintf(buffer, "tstamp_mode: %s\n", snd_pcm_tstamp_mode_name(runtime->tstamp_mode)); snd_iprintf(buffer, "period_step: %u\n", runtime->period_step); @@ -444,8 +428,6 @@ static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry, snd_iprintf(buffer, "silence_threshold: %lu\n", runtime->silence_threshold); snd_iprintf(buffer, "silence_size: %lu\n", runtime->silence_size); snd_iprintf(buffer, "boundary: %lu\n", runtime->boundary); - unlock: - mutex_unlock(&substream->pcm->open_mutex); } static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry, @@ -456,17 +438,17 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry, struct snd_pcm_status64 status; int err; - mutex_lock(&substream->pcm->open_mutex); + guard(mutex)(&substream->pcm->open_mutex); runtime = substream->runtime; if (!runtime) { snd_iprintf(buffer, "closed\n"); - goto unlock; + return; } memset(&status, 0, sizeof(status)); err = snd_pcm_status64(substream, &status); if (err < 0) { snd_iprintf(buffer, "error %d\n", err); - goto unlock; + return; } snd_iprintf(buffer, "state: %s\n", snd_pcm_state_name(status.state)); snd_iprintf(buffer, "owner_pid : %d\n", pid_vnr(substream->pid)); @@ -480,8 +462,6 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry, snd_iprintf(buffer, "-----\n"); snd_iprintf(buffer, "hw_ptr : %ld\n", runtime->status->hw_ptr); snd_iprintf(buffer, "appl_ptr : %ld\n", runtime->control->appl_ptr); - unlock: - mutex_unlock(&substream->pcm->open_mutex); } #ifdef CONFIG_SND_PCM_XRUN_DEBUG @@ -1009,9 +989,8 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream) kfree(runtime->hw_constraints.rules); /* Avoid concurrent access to runtime via PCM timer interface */ if (substream->timer) { - spin_lock_irq(&substream->timer->lock); - substream->runtime = NULL; - spin_unlock_irq(&substream->timer->lock); + scoped_guard(spinlock_irq, &substream->timer->lock) + substream->runtime = NULL; } else { substream->runtime = NULL; } @@ -1068,10 +1047,10 @@ static int snd_pcm_dev_register(struct snd_device *device) return -ENXIO; pcm = device->device_data; - mutex_lock(®ister_mutex); + guard(mutex)(®ister_mutex); err = snd_pcm_add(pcm); if (err) - goto unlock; + return err; for (cidx = 0; cidx < 2; cidx++) { int devtype = -1; if (pcm->streams[cidx].substream == NULL) @@ -1090,7 +1069,7 @@ static int snd_pcm_dev_register(struct snd_device *device) pcm->streams[cidx].dev); if (err < 0) { list_del_init(&pcm->list); - goto unlock; + return err; } for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) @@ -1098,9 +1077,6 @@ static int snd_pcm_dev_register(struct snd_device *device) } pcm_call_notify(pcm, n_register); - - unlock: - mutex_unlock(®ister_mutex); return err; } @@ -1110,8 +1086,8 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) struct snd_pcm_substream *substream; int cidx; - mutex_lock(®ister_mutex); - mutex_lock(&pcm->open_mutex); + guard(mutex)(®ister_mutex); + guard(mutex)(&pcm->open_mutex); wake_up(&pcm->open_wait); list_del_init(&pcm->list); @@ -1138,8 +1114,6 @@ static int snd_pcm_dev_disconnect(struct snd_device *device) snd_unregister_device(pcm->streams[cidx].dev); free_chmap(&pcm->streams[cidx]); } - mutex_unlock(&pcm->open_mutex); - mutex_unlock(®ister_mutex); return 0; } @@ -1164,7 +1138,7 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree) !notify->n_unregister || !notify->n_disconnect)) return -EINVAL; - mutex_lock(®ister_mutex); + guard(mutex)(®ister_mutex); if (nfree) { list_del(¬ify->list); list_for_each_entry(pcm, &snd_pcm_devices, list) @@ -1174,7 +1148,6 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree) list_for_each_entry(pcm, &snd_pcm_devices, list) notify->n_register(pcm); } - mutex_unlock(®ister_mutex); return 0; } EXPORT_SYMBOL(snd_pcm_notify); @@ -1190,7 +1163,7 @@ static void snd_pcm_proc_read(struct snd_info_entry *entry, { struct snd_pcm *pcm; - mutex_lock(®ister_mutex); + guard(mutex)(®ister_mutex); list_for_each_entry(pcm, &snd_pcm_devices, list) { snd_iprintf(buffer, "%02i-%02i: %s : %s", pcm->card->number, pcm->device, pcm->id, pcm->name); @@ -1202,7 +1175,6 @@ static void snd_pcm_proc_read(struct snd_info_entry *entry, pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count); snd_iprintf(buffer, "\n"); } - mutex_unlock(®ister_mutex); } static struct snd_info_entry *snd_pcm_proc_entry; diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index a0b9514716995..506386959f084 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -38,17 +38,15 @@ static void __update_allocated_size(struct snd_card *card, ssize_t bytes) static void update_allocated_size(struct snd_card *card, ssize_t bytes) { - mutex_lock(&card->memory_mutex); + guard(mutex)(&card->memory_mutex); __update_allocated_size(card, bytes); - mutex_unlock(&card->memory_mutex); } static void decrease_allocated_size(struct snd_card *card, size_t bytes) { - mutex_lock(&card->memory_mutex); + guard(mutex)(&card->memory_mutex); WARN_ON(card->total_pcm_alloc_bytes < bytes); __update_allocated_size(card, -(ssize_t)bytes); - mutex_unlock(&card->memory_mutex); } static int do_alloc_pages(struct snd_card *card, int type, struct device *dev, @@ -58,14 +56,12 @@ static int do_alloc_pages(struct snd_card *card, int type, struct device *dev, int err; /* check and reserve the requested size */ - mutex_lock(&card->memory_mutex); - if (max_alloc_per_card && - card->total_pcm_alloc_bytes + size > max_alloc_per_card) { - mutex_unlock(&card->memory_mutex); - return -ENOMEM; + scoped_guard(mutex, &card->memory_mutex) { + if (max_alloc_per_card && + card->total_pcm_alloc_bytes + size > max_alloc_per_card) + return -ENOMEM; + __update_allocated_size(card, size); } - __update_allocated_size(card, size); - mutex_unlock(&card->memory_mutex); if (str == SNDRV_PCM_STREAM_PLAYBACK) dir = DMA_TO_DEVICE; @@ -191,20 +187,20 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry, size_t size; struct snd_dma_buffer new_dmab; - mutex_lock(&substream->pcm->open_mutex); + guard(mutex)(&substream->pcm->open_mutex); if (substream->runtime) { buffer->error = -EBUSY; - goto unlock; + return; } if (!snd_info_get_line(buffer, line, sizeof(line))) { snd_info_get_str(str, line, sizeof(str)); size = simple_strtoul(str, NULL, 10) * 1024; if ((size != 0 && size < 8192) || size > substream->dma_max) { buffer->error = -EINVAL; - goto unlock; + return; } if (substream->dma_buffer.bytes == size) - goto unlock; + return; memset(&new_dmab, 0, sizeof(new_dmab)); new_dmab.dev = substream->dma_buffer.dev; if (size > 0) { @@ -218,7 +214,7 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry, substream->pcm->card->number, substream->pcm->device, substream->stream ? 'c' : 'p', substream->number, substream->pcm->name, size); - goto unlock; + return; } substream->buffer_bytes_max = size; } else { @@ -230,8 +226,6 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry, } else { buffer->error = -EINVAL; } - unlock: - mutex_unlock(&substream->pcm->open_mutex); } static inline void preallocate_info_init(struct snd_pcm_substream *substream) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 0e84de4b484db..f2a0cbb25bb74 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1398,17 +1398,15 @@ static int snd_pcm_action_nonatomic(const struct action_ops *ops, int res; /* Guarantee the group members won't change during non-atomic action */ - down_read(&snd_pcm_link_rwsem); + guard(rwsem_read)(&snd_pcm_link_rwsem); res = snd_pcm_buffer_access_lock(substream->runtime); if (res < 0) - goto unlock; + return res; if (snd_pcm_stream_linked(substream)) res = snd_pcm_action_group(ops, substream, state, false); else res = snd_pcm_action_single(ops, substream, state); snd_pcm_buffer_access_unlock(substream->runtime); - unlock: - up_read(&snd_pcm_link_rwsem); return res; } @@ -2259,7 +2257,6 @@ static bool is_pcm_file(struct file *file) */ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) { - int res = 0; struct snd_pcm_file *pcm_file; struct snd_pcm_substream *substream1; struct snd_pcm_group *group __free(kfree) = NULL; @@ -2281,20 +2278,15 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) group = kzalloc(sizeof(*group), GFP_KERNEL); if (!group) return -ENOMEM; - snd_pcm_group_init(group); - down_write(&snd_pcm_link_rwsem); + guard(rwsem_write)(&snd_pcm_link_rwsem); if (substream->runtime->state == SNDRV_PCM_STATE_OPEN || substream->runtime->state != substream1->runtime->state || - substream->pcm->nonatomic != substream1->pcm->nonatomic) { - res = -EBADFD; - goto _end; - } - if (snd_pcm_stream_linked(substream1)) { - res = -EALREADY; - goto _end; - } + substream->pcm->nonatomic != substream1->pcm->nonatomic) + return -EBADFD; + if (snd_pcm_stream_linked(substream1)) + return -EALREADY; snd_pcm_stream_lock_irq(substream); if (!snd_pcm_stream_linked(substream)) { @@ -2310,9 +2302,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) refcount_inc(&target_group->refs); snd_pcm_stream_unlock(substream1); snd_pcm_group_unlock_irq(target_group, nonatomic); - _end: - up_write(&snd_pcm_link_rwsem); - return res; + return 0; } static void relink_to_local(struct snd_pcm_substream *substream) @@ -2327,14 +2317,11 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream) struct snd_pcm_group *group; bool nonatomic = substream->pcm->nonatomic; bool do_free = false; - int res = 0; - down_write(&snd_pcm_link_rwsem); + guard(rwsem_write)(&snd_pcm_link_rwsem); - if (!snd_pcm_stream_linked(substream)) { - res = -EALREADY; - goto _end; - } + if (!snd_pcm_stream_linked(substream)) + return -EALREADY; group = substream->group; snd_pcm_group_lock_irq(group, nonatomic); @@ -2353,10 +2340,7 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream) snd_pcm_group_unlock_irq(group, nonatomic); if (do_free) kfree(group); - - _end: - up_write(&snd_pcm_link_rwsem); - return res; + return 0; } /* @@ -2929,10 +2913,10 @@ static int snd_pcm_release(struct inode *inode, struct file *file) /* block until the device gets woken up as it may touch the hardware */ snd_power_wait(pcm->card); - mutex_lock(&pcm->open_mutex); - snd_pcm_release_substream(substream); - kfree(pcm_file); - mutex_unlock(&pcm->open_mutex); + scoped_guard(mutex, &pcm->open_mutex) { + snd_pcm_release_substream(substream); + kfree(pcm_file); + } wake_up(&pcm->open_wait); module_put(pcm->card->module); snd_card_file_remove(pcm->card, file); -- cgit 1.2.3-korg From 650224fe8d5f6dbe6cc5875d14bf80da60dd56f8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Feb 2024 09:53:04 +0100 Subject: ALSA: pcm: Use guard() for PCM stream locks Define guard() usage for PCM stream locking and use it in appropriate places. The pair of snd_pcm_stream_lock() and snd_pcm_stream_unlock() can be presented with guard(pcm_stream_lock) now. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240227085306.9764-23-tiwai@suse.de --- include/sound/pcm.h | 12 ++ sound/core/oss/pcm_oss.c | 29 +++-- sound/core/pcm_compat.c | 66 ++++++----- sound/core/pcm_lib.c | 10 +- sound/core/pcm_native.c | 292 +++++++++++++++++++++-------------------------- 5 files changed, 191 insertions(+), 218 deletions(-) (limited to 'sound') diff --git a/include/sound/pcm.h b/include/sound/pcm.h index cc175c623dac7..210096f124eed 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -659,6 +659,18 @@ void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream, flags = _snd_pcm_stream_lock_irqsave_nested(substream); \ } while (0) +/* definitions for guard(); use like guard(pcm_stream_lock) */ +DEFINE_LOCK_GUARD_1(pcm_stream_lock, struct snd_pcm_substream, + snd_pcm_stream_lock(_T->lock), + snd_pcm_stream_unlock(_T->lock)) +DEFINE_LOCK_GUARD_1(pcm_stream_lock_irq, struct snd_pcm_substream, + snd_pcm_stream_lock_irq(_T->lock), + snd_pcm_stream_unlock_irq(_T->lock)) +DEFINE_LOCK_GUARD_1(pcm_stream_lock_irqsave, struct snd_pcm_substream, + snd_pcm_stream_lock_irqsave(_T->lock, _T->flags), + snd_pcm_stream_unlock_irqrestore(_T->lock, _T->flags), + unsigned long flags) + /** * snd_pcm_group_for_each_entry - iterate over the linked substreams * @s: the iterator diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index e4e292b2db06e..49ea092e90f96 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -1623,9 +1623,8 @@ static int snd_pcm_oss_sync1(struct snd_pcm_substream *substream, size_t size) break; result = 0; set_current_state(TASK_INTERRUPTIBLE); - snd_pcm_stream_lock_irq(substream); - state = runtime->state; - snd_pcm_stream_unlock_irq(substream); + scoped_guard(pcm_stream_lock_irq, substream) + state = runtime->state; if (state != SNDRV_PCM_STATE_RUNNING) { set_current_state(TASK_RUNNING); break; @@ -2840,23 +2839,23 @@ static __poll_t snd_pcm_oss_poll(struct file *file, poll_table * wait) if (psubstream != NULL) { struct snd_pcm_runtime *runtime = psubstream->runtime; poll_wait(file, &runtime->sleep, wait); - snd_pcm_stream_lock_irq(psubstream); - if (runtime->state != SNDRV_PCM_STATE_DRAINING && - (runtime->state != SNDRV_PCM_STATE_RUNNING || - snd_pcm_oss_playback_ready(psubstream))) - mask |= EPOLLOUT | EPOLLWRNORM; - snd_pcm_stream_unlock_irq(psubstream); + scoped_guard(pcm_stream_lock_irq, psubstream) { + if (runtime->state != SNDRV_PCM_STATE_DRAINING && + (runtime->state != SNDRV_PCM_STATE_RUNNING || + snd_pcm_oss_playback_ready(psubstream))) + mask |= EPOLLOUT | EPOLLWRNORM; + } } if (csubstream != NULL) { struct snd_pcm_runtime *runtime = csubstream->runtime; snd_pcm_state_t ostate; poll_wait(file, &runtime->sleep, wait); - snd_pcm_stream_lock_irq(csubstream); - ostate = runtime->state; - if (ostate != SNDRV_PCM_STATE_RUNNING || - snd_pcm_oss_capture_ready(csubstream)) - mask |= EPOLLIN | EPOLLRDNORM; - snd_pcm_stream_unlock_irq(csubstream); + scoped_guard(pcm_stream_lock_irq, csubstream) { + ostate = runtime->state; + if (ostate != SNDRV_PCM_STATE_RUNNING || + snd_pcm_oss_capture_ready(csubstream)) + mask |= EPOLLIN | EPOLLRDNORM; + } if (ostate != SNDRV_PCM_STATE_RUNNING && runtime->oss.trigger) { struct snd_pcm_oss_file ofile; memset(&ofile, 0, sizeof(ofile)); diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index ef3c0d1775104..a42ec7f5a1daf 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c @@ -432,22 +432,22 @@ static int snd_pcm_ioctl_sync_ptr_x32(struct snd_pcm_substream *substream, boundary = recalculate_boundary(runtime); if (!boundary) boundary = 0x7fffffff; - snd_pcm_stream_lock_irq(substream); - /* FIXME: we should consider the boundary for the sync from app */ - if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) - control->appl_ptr = scontrol.appl_ptr; - else - scontrol.appl_ptr = control->appl_ptr % boundary; - if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) - control->avail_min = scontrol.avail_min; - else - scontrol.avail_min = control->avail_min; - sstatus.state = status->state; - sstatus.hw_ptr = status->hw_ptr % boundary; - sstatus.tstamp = status->tstamp; - sstatus.suspended_state = status->suspended_state; - sstatus.audio_tstamp = status->audio_tstamp; - snd_pcm_stream_unlock_irq(substream); + scoped_guard(pcm_stream_lock_irq, substream) { + /* FIXME: we should consider the boundary for the sync from app */ + if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) + control->appl_ptr = scontrol.appl_ptr; + else + scontrol.appl_ptr = control->appl_ptr % boundary; + if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) + control->avail_min = scontrol.avail_min; + else + scontrol.avail_min = control->avail_min; + sstatus.state = status->state; + sstatus.hw_ptr = status->hw_ptr % boundary; + sstatus.tstamp = status->tstamp; + sstatus.suspended_state = status->suspended_state; + sstatus.audio_tstamp = status->audio_tstamp; + } if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE); if (put_user(sstatus.state, &src->s.status.state) || @@ -510,26 +510,24 @@ static int snd_pcm_ioctl_sync_ptr_buggy(struct snd_pcm_substream *substream, if (err < 0) return err; } - snd_pcm_stream_lock_irq(substream); - if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) { - err = pcm_lib_apply_appl_ptr(substream, sync_cp->appl_ptr); - if (err < 0) { - snd_pcm_stream_unlock_irq(substream); - return err; + scoped_guard(pcm_stream_lock_irq, substream) { + if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) { + err = pcm_lib_apply_appl_ptr(substream, sync_cp->appl_ptr); + if (err < 0) + return err; + } else { + sync_cp->appl_ptr = control->appl_ptr; } - } else { - sync_cp->appl_ptr = control->appl_ptr; + if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) + control->avail_min = sync_cp->avail_min; + else + sync_cp->avail_min = control->avail_min; + sync_ptr.s.status.state = status->state; + sync_ptr.s.status.hw_ptr = status->hw_ptr; + sync_ptr.s.status.tstamp = status->tstamp; + sync_ptr.s.status.suspended_state = status->suspended_state; + sync_ptr.s.status.audio_tstamp = status->audio_tstamp; } - if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) - control->avail_min = sync_cp->avail_min; - else - sync_cp->avail_min = control->avail_min; - sync_ptr.s.status.state = status->state; - sync_ptr.s.status.hw_ptr = status->hw_ptr; - sync_ptr.s.status.tstamp = status->tstamp; - sync_ptr.s.status.suspended_state = status->suspended_state; - sync_ptr.s.status.audio_tstamp = status->audio_tstamp; - snd_pcm_stream_unlock_irq(substream); if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE); if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr))) diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 41103e5c43ce5..6f73b3c2c205e 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1744,8 +1744,8 @@ static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream, void *arg) { struct snd_pcm_runtime *runtime = substream->runtime; - unsigned long flags; - snd_pcm_stream_lock_irqsave(substream, flags); + + guard(pcm_stream_lock_irqsave)(substream); if (snd_pcm_running(substream) && snd_pcm_update_hw_ptr(substream) >= 0) runtime->status->hw_ptr %= runtime->buffer_size; @@ -1753,7 +1753,6 @@ static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream, runtime->status->hw_ptr = 0; runtime->hw_ptr_wrap = 0; } - snd_pcm_stream_unlock_irqrestore(substream, flags); return 0; } @@ -1899,14 +1898,11 @@ EXPORT_SYMBOL(snd_pcm_period_elapsed_under_stream_lock); */ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream) { - unsigned long flags; - if (snd_BUG_ON(!substream)) return; - snd_pcm_stream_lock_irqsave(substream, flags); + guard(pcm_stream_lock_irqsave)(substream); snd_pcm_period_elapsed_under_stream_lock(substream); - snd_pcm_stream_unlock_irqrestore(substream, flags); } EXPORT_SYMBOL(snd_pcm_period_elapsed); diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index f2a0cbb25bb74..c1396c8024091 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -604,10 +604,9 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime) static void snd_pcm_set_state(struct snd_pcm_substream *substream, snd_pcm_state_t state) { - snd_pcm_stream_lock_irq(substream); + guard(pcm_stream_lock_irq)(substream); if (substream->runtime->state != SNDRV_PCM_STATE_DISCONNECTED) __snd_pcm_set_state(substream->runtime, state); - snd_pcm_stream_unlock_irq(substream); } static inline void snd_pcm_timer_notify(struct snd_pcm_substream *substream, @@ -733,20 +732,20 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, err = snd_pcm_buffer_access_lock(runtime); if (err < 0) return err; - snd_pcm_stream_lock_irq(substream); - switch (runtime->state) { - case SNDRV_PCM_STATE_OPEN: - case SNDRV_PCM_STATE_SETUP: - case SNDRV_PCM_STATE_PREPARED: - if (!is_oss_stream(substream) && - atomic_read(&substream->mmap_count)) + scoped_guard(pcm_stream_lock_irq, substream) { + switch (runtime->state) { + case SNDRV_PCM_STATE_OPEN: + case SNDRV_PCM_STATE_SETUP: + case SNDRV_PCM_STATE_PREPARED: + if (!is_oss_stream(substream) && + atomic_read(&substream->mmap_count)) + err = -EBADFD; + break; + default: err = -EBADFD; - break; - default: - err = -EBADFD; - break; + break; + } } - snd_pcm_stream_unlock_irq(substream); if (err) goto unlock; @@ -896,18 +895,18 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream) result = snd_pcm_buffer_access_lock(runtime); if (result < 0) return result; - snd_pcm_stream_lock_irq(substream); - switch (runtime->state) { - case SNDRV_PCM_STATE_SETUP: - case SNDRV_PCM_STATE_PREPARED: - if (atomic_read(&substream->mmap_count)) + scoped_guard(pcm_stream_lock_irq, substream) { + switch (runtime->state) { + case SNDRV_PCM_STATE_SETUP: + case SNDRV_PCM_STATE_PREPARED: + if (atomic_read(&substream->mmap_count)) + result = -EBADFD; + break; + default: result = -EBADFD; - break; - default: - result = -EBADFD; - break; + break; + } } - snd_pcm_stream_unlock_irq(substream); if (result) goto unlock; result = do_hw_free(substream); @@ -927,12 +926,10 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; runtime = substream->runtime; - snd_pcm_stream_lock_irq(substream); - if (runtime->state == SNDRV_PCM_STATE_OPEN) { - snd_pcm_stream_unlock_irq(substream); - return -EBADFD; + scoped_guard(pcm_stream_lock_irq, substream) { + if (runtime->state == SNDRV_PCM_STATE_OPEN) + return -EBADFD; } - snd_pcm_stream_unlock_irq(substream); if (params->tstamp_mode < 0 || params->tstamp_mode > SNDRV_PCM_TSTAMP_LAST) @@ -952,24 +949,24 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, return -EINVAL; } err = 0; - snd_pcm_stream_lock_irq(substream); - runtime->tstamp_mode = params->tstamp_mode; - if (params->proto >= SNDRV_PROTOCOL_VERSION(2, 0, 12)) - runtime->tstamp_type = params->tstamp_type; - runtime->period_step = params->period_step; - runtime->control->avail_min = params->avail_min; - runtime->start_threshold = params->start_threshold; - runtime->stop_threshold = params->stop_threshold; - runtime->silence_threshold = params->silence_threshold; - runtime->silence_size = params->silence_size; - params->boundary = runtime->boundary; - if (snd_pcm_running(substream)) { - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && - runtime->silence_size > 0) - snd_pcm_playback_silence(substream, ULONG_MAX); - err = snd_pcm_update_state(substream, runtime); + scoped_guard(pcm_stream_lock_irq, substream) { + runtime->tstamp_mode = params->tstamp_mode; + if (params->proto >= SNDRV_PROTOCOL_VERSION(2, 0, 12)) + runtime->tstamp_type = params->tstamp_type; + runtime->period_step = params->period_step; + runtime->control->avail_min = params->avail_min; + runtime->start_threshold = params->start_threshold; + runtime->stop_threshold = params->stop_threshold; + runtime->silence_threshold = params->silence_threshold; + runtime->silence_size = params->silence_size; + params->boundary = runtime->boundary; + if (snd_pcm_running(substream)) { + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && + runtime->silence_size > 0) + snd_pcm_playback_silence(substream, ULONG_MAX); + err = snd_pcm_update_state(substream, runtime); + } } - snd_pcm_stream_unlock_irq(substream); return err; } @@ -1003,7 +1000,7 @@ int snd_pcm_status64(struct snd_pcm_substream *substream, { struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_stream_lock_irq(substream); + guard(pcm_stream_lock_irq)(substream); snd_pcm_unpack_audio_tstamp_config(status->audio_tstamp_data, &runtime->audio_tstamp_config); @@ -1024,7 +1021,7 @@ int snd_pcm_status64(struct snd_pcm_substream *substream, status->state = runtime->state; status->suspended_state = runtime->suspended_state; if (status->state == SNDRV_PCM_STATE_OPEN) - goto _end; + return 0; status->trigger_tstamp_sec = runtime->trigger_tstamp.tv_sec; status->trigger_tstamp_nsec = runtime->trigger_tstamp.tv_nsec; if (snd_pcm_running(substream)) { @@ -1069,8 +1066,6 @@ int snd_pcm_status64(struct snd_pcm_substream *substream, status->overrange = runtime->overrange; runtime->avail_max = 0; runtime->overrange = 0; - _end: - snd_pcm_stream_unlock_irq(substream); return 0; } @@ -1155,12 +1150,10 @@ static int snd_pcm_channel_info(struct snd_pcm_substream *substream, channel = info->channel; runtime = substream->runtime; - snd_pcm_stream_lock_irq(substream); - if (runtime->state == SNDRV_PCM_STATE_OPEN) { - snd_pcm_stream_unlock_irq(substream); - return -EBADFD; + scoped_guard(pcm_stream_lock_irq, substream) { + if (runtime->state == SNDRV_PCM_STATE_OPEN) + return -EBADFD; } - snd_pcm_stream_unlock_irq(substream); if (channel >= runtime->channels) return -EINVAL; memset(info, 0, sizeof(*info)); @@ -1381,12 +1374,8 @@ static int snd_pcm_action_lock_irq(const struct action_ops *ops, struct snd_pcm_substream *substream, snd_pcm_state_t state) { - int res; - - snd_pcm_stream_lock_irq(substream); - res = snd_pcm_action(ops, substream, state); - snd_pcm_stream_unlock_irq(substream); - return res; + guard(pcm_stream_lock_irq)(substream); + return snd_pcm_action(ops, substream, state); } /* @@ -1576,12 +1565,9 @@ int snd_pcm_drain_done(struct snd_pcm_substream *substream) */ int snd_pcm_stop_xrun(struct snd_pcm_substream *substream) { - unsigned long flags; - - snd_pcm_stream_lock_irqsave(substream, flags); + guard(pcm_stream_lock_irqsave)(substream); if (substream->runtime && snd_pcm_running(substream)) __snd_pcm_xrun(substream); - snd_pcm_stream_unlock_irqrestore(substream, flags); return 0; } EXPORT_SYMBOL_GPL(snd_pcm_stop_xrun); @@ -1733,14 +1719,9 @@ static const struct action_ops snd_pcm_action_suspend = { */ static int snd_pcm_suspend(struct snd_pcm_substream *substream) { - int err; - unsigned long flags; - - snd_pcm_stream_lock_irqsave(substream, flags); - err = snd_pcm_action(&snd_pcm_action_suspend, substream, - ACTION_ARG_IGNORE); - snd_pcm_stream_unlock_irqrestore(substream, flags); - return err; + guard(pcm_stream_lock_irqsave)(substream); + return snd_pcm_action(&snd_pcm_action_suspend, substream, + ACTION_ARG_IGNORE); } /** @@ -1856,22 +1837,17 @@ static int snd_pcm_resume(struct snd_pcm_substream *substream) static int snd_pcm_xrun(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - int result; - snd_pcm_stream_lock_irq(substream); + guard(pcm_stream_lock_irq)(substream); switch (runtime->state) { case SNDRV_PCM_STATE_XRUN: - result = 0; /* already there */ - break; + return 0; /* already there */ case SNDRV_PCM_STATE_RUNNING: __snd_pcm_xrun(substream); - result = 0; - break; + return 0; default: - result = -EBADFD; + return -EBADFD; } - snd_pcm_stream_unlock_irq(substream); - return result; } /* @@ -1900,13 +1876,12 @@ static int snd_pcm_do_reset(struct snd_pcm_substream *substream, int err = snd_pcm_ops_ioctl(substream, SNDRV_PCM_IOCTL1_RESET, NULL); if (err < 0) return err; - snd_pcm_stream_lock_irq(substream); + guard(pcm_stream_lock_irq)(substream); runtime->hw_ptr_base = 0; runtime->hw_ptr_interrupt = runtime->status->hw_ptr - runtime->status->hw_ptr % runtime->period_size; runtime->silence_start = runtime->status->hw_ptr; runtime->silence_filled = 0; - snd_pcm_stream_unlock_irq(substream); return 0; } @@ -1914,12 +1889,11 @@ static void snd_pcm_post_reset(struct snd_pcm_substream *substream, snd_pcm_state_t state) { struct snd_pcm_runtime *runtime = substream->runtime; - snd_pcm_stream_lock_irq(substream); + guard(pcm_stream_lock_irq)(substream); runtime->control->appl_ptr = runtime->status->hw_ptr; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0) snd_pcm_playback_silence(substream, ULONG_MAX); - snd_pcm_stream_unlock_irq(substream); } static const struct action_ops snd_pcm_action_reset = { @@ -1995,16 +1969,16 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream, else f_flags = substream->f_flags; - snd_pcm_stream_lock_irq(substream); - switch (substream->runtime->state) { - case SNDRV_PCM_STATE_PAUSED: - snd_pcm_pause(substream, false); - fallthrough; - case SNDRV_PCM_STATE_SUSPENDED: - snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); - break; + scoped_guard(pcm_stream_lock_irq, substream) { + switch (substream->runtime->state) { + case SNDRV_PCM_STATE_PAUSED: + snd_pcm_pause(substream, false); + fallthrough; + case SNDRV_PCM_STATE_SUSPENDED: + snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); + break; + } } - snd_pcm_stream_unlock_irq(substream); return snd_pcm_action_nonatomic(&snd_pcm_action_prepare, substream, @@ -2221,14 +2195,13 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream) runtime->state == SNDRV_PCM_STATE_DISCONNECTED) return -EBADFD; - snd_pcm_stream_lock_irq(substream); + guard(pcm_stream_lock_irq)(substream); /* resume pause */ if (runtime->state == SNDRV_PCM_STATE_PAUSED) snd_pcm_pause(substream, false); snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); /* runtime->control->appl_ptr = runtime->status->hw_ptr; */ - snd_pcm_stream_unlock_irq(substream); return result; } @@ -2288,13 +2261,13 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) if (snd_pcm_stream_linked(substream1)) return -EALREADY; - snd_pcm_stream_lock_irq(substream); - if (!snd_pcm_stream_linked(substream)) { - snd_pcm_group_assign(substream, group); - group = NULL; /* assigned, don't free this one below */ + scoped_guard(pcm_stream_lock_irq, substream) { + if (!snd_pcm_stream_linked(substream)) { + snd_pcm_group_assign(substream, group); + group = NULL; /* assigned, don't free this one below */ + } + target_group = substream->group; } - target_group = substream->group; - snd_pcm_stream_unlock_irq(substream); snd_pcm_group_lock_irq(target_group, nonatomic); snd_pcm_stream_lock_nested(substream1); @@ -3000,12 +2973,12 @@ static snd_pcm_sframes_t snd_pcm_rewind(struct snd_pcm_substream *substream, if (frames == 0) return 0; - snd_pcm_stream_lock_irq(substream); - ret = do_pcm_hwsync(substream); - if (!ret) - ret = rewind_appl_ptr(substream, frames, - snd_pcm_hw_avail(substream)); - snd_pcm_stream_unlock_irq(substream); + scoped_guard(pcm_stream_lock_irq, substream) { + ret = do_pcm_hwsync(substream); + if (!ret) + ret = rewind_appl_ptr(substream, frames, + snd_pcm_hw_avail(substream)); + } if (ret >= 0) snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE); return ret; @@ -3019,12 +2992,12 @@ static snd_pcm_sframes_t snd_pcm_forward(struct snd_pcm_substream *substream, if (frames == 0) return 0; - snd_pcm_stream_lock_irq(substream); - ret = do_pcm_hwsync(substream); - if (!ret) - ret = forward_appl_ptr(substream, frames, - snd_pcm_avail(substream)); - snd_pcm_stream_unlock_irq(substream); + scoped_guard(pcm_stream_lock_irq, substream) { + ret = do_pcm_hwsync(substream); + if (!ret) + ret = forward_appl_ptr(substream, frames, + snd_pcm_avail(substream)); + } if (ret >= 0) snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE); return ret; @@ -3035,11 +3008,11 @@ static int snd_pcm_delay(struct snd_pcm_substream *substream, { int err; - snd_pcm_stream_lock_irq(substream); - err = do_pcm_hwsync(substream); - if (delay && !err) - *delay = snd_pcm_calc_delay(substream); - snd_pcm_stream_unlock_irq(substream); + scoped_guard(pcm_stream_lock_irq, substream) { + err = do_pcm_hwsync(substream); + if (delay && !err) + *delay = snd_pcm_calc_delay(substream); + } snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_CPU); return err; @@ -3071,27 +3044,25 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream, if (err < 0) return err; } - snd_pcm_stream_lock_irq(substream); - if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) { - err = pcm_lib_apply_appl_ptr(substream, - sync_ptr.c.control.appl_ptr); - if (err < 0) { - snd_pcm_stream_unlock_irq(substream); - return err; + scoped_guard(pcm_stream_lock_irq, substream) { + if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) { + err = pcm_lib_apply_appl_ptr(substream, + sync_ptr.c.control.appl_ptr); + if (err < 0) + return err; + } else { + sync_ptr.c.control.appl_ptr = control->appl_ptr; } - } else { - sync_ptr.c.control.appl_ptr = control->appl_ptr; + if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) + control->avail_min = sync_ptr.c.control.avail_min; + else + sync_ptr.c.control.avail_min = control->avail_min; + sync_ptr.s.status.state = status->state; + sync_ptr.s.status.hw_ptr = status->hw_ptr; + sync_ptr.s.status.tstamp = status->tstamp; + sync_ptr.s.status.suspended_state = status->suspended_state; + sync_ptr.s.status.audio_tstamp = status->audio_tstamp; } - if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) - control->avail_min = sync_ptr.c.control.avail_min; - else - sync_ptr.c.control.avail_min = control->avail_min; - sync_ptr.s.status.state = status->state; - sync_ptr.s.status.hw_ptr = status->hw_ptr; - sync_ptr.s.status.tstamp = status->tstamp; - sync_ptr.s.status.suspended_state = status->suspended_state; - sync_ptr.s.status.audio_tstamp = status->audio_tstamp; - snd_pcm_stream_unlock_irq(substream); if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE); if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr))) @@ -3169,27 +3140,25 @@ static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream, boundary = recalculate_boundary(runtime); if (! boundary) boundary = 0x7fffffff; - snd_pcm_stream_lock_irq(substream); - /* FIXME: we should consider the boundary for the sync from app */ - if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) { - err = pcm_lib_apply_appl_ptr(substream, - scontrol.appl_ptr); - if (err < 0) { - snd_pcm_stream_unlock_irq(substream); - return err; - } - } else - scontrol.appl_ptr = control->appl_ptr % boundary; - if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) - control->avail_min = scontrol.avail_min; - else - scontrol.avail_min = control->avail_min; - sstatus.state = status->state; - sstatus.hw_ptr = status->hw_ptr % boundary; - sstatus.tstamp = status->tstamp; - sstatus.suspended_state = status->suspended_state; - sstatus.audio_tstamp = status->audio_tstamp; - snd_pcm_stream_unlock_irq(substream); + scoped_guard(pcm_stream_lock_irq, substream) { + /* FIXME: we should consider the boundary for the sync from app */ + if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) { + err = pcm_lib_apply_appl_ptr(substream, + scontrol.appl_ptr); + if (err < 0) + return err; + } else + scontrol.appl_ptr = control->appl_ptr % boundary; + if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) + control->avail_min = scontrol.avail_min; + else + scontrol.avail_min = control->avail_min; + sstatus.state = status->state; + sstatus.hw_ptr = status->hw_ptr % boundary; + sstatus.tstamp = status->tstamp; + sstatus.suspended_state = status->suspended_state; + sstatus.audio_tstamp = status->audio_tstamp; + } if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE); if (put_user(sstatus.state, &src->s.status.state) || @@ -3628,7 +3597,7 @@ static __poll_t snd_pcm_poll(struct file *file, poll_table *wait) poll_wait(file, &runtime->sleep, wait); mask = 0; - snd_pcm_stream_lock_irq(substream); + guard(pcm_stream_lock_irq)(substream); avail = snd_pcm_avail(substream); switch (runtime->state) { case SNDRV_PCM_STATE_RUNNING: @@ -3648,7 +3617,6 @@ static __poll_t snd_pcm_poll(struct file *file, poll_table *wait) mask = ok | EPOLLERR; break; } - snd_pcm_stream_unlock_irq(substream); return mask; } -- cgit 1.2.3-korg From 3923de04c81733b30b8ed667569632272fdfed9a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Feb 2024 09:53:05 +0100 Subject: ALSA: pcm: oss: Use guard() for setup The setup_mutex in PCM oss code can be simplified with guard(). (params_lock is tough and not trivial to covert, though.) Only the code refactoring, and no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240227085306.9764-24-tiwai@suse.de --- sound/core/oss/pcm_oss.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 49ea092e90f96..7386982cf40ed 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -2333,7 +2333,7 @@ static void snd_pcm_oss_look_for_setup(struct snd_pcm *pcm, int stream, { struct snd_pcm_oss_setup *setup; - mutex_lock(&pcm->streams[stream].oss.setup_mutex); + guard(mutex)(&pcm->streams[stream].oss.setup_mutex); do { for (setup = pcm->streams[stream].oss.setup_list; setup; setup = setup->next) { @@ -2344,7 +2344,6 @@ static void snd_pcm_oss_look_for_setup(struct snd_pcm *pcm, int stream, out: if (setup) *rsetup = *setup; - mutex_unlock(&pcm->streams[stream].oss.setup_mutex); } static void snd_pcm_oss_release_substream(struct snd_pcm_substream *substream) @@ -2950,7 +2949,7 @@ static void snd_pcm_oss_proc_read(struct snd_info_entry *entry, { struct snd_pcm_str *pstr = entry->private_data; struct snd_pcm_oss_setup *setup = pstr->oss.setup_list; - mutex_lock(&pstr->oss.setup_mutex); + guard(mutex)(&pstr->oss.setup_mutex); while (setup) { snd_iprintf(buffer, "%s %u %u%s%s%s%s%s%s\n", setup->task_name, @@ -2964,7 +2963,6 @@ static void snd_pcm_oss_proc_read(struct snd_info_entry *entry, setup->nosilence ? " no-silence" : ""); setup = setup->next; } - mutex_unlock(&pstr->oss.setup_mutex); } static void snd_pcm_oss_proc_free_setup_list(struct snd_pcm_str * pstr) @@ -2990,12 +2988,11 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry, struct snd_pcm_oss_setup *setup, *setup1, template; while (!snd_info_get_line(buffer, line, sizeof(line))) { - mutex_lock(&pstr->oss.setup_mutex); + guard(mutex)(&pstr->oss.setup_mutex); memset(&template, 0, sizeof(template)); ptr = snd_info_get_str(task_name, line, sizeof(task_name)); if (!strcmp(task_name, "clear") || !strcmp(task_name, "erase")) { snd_pcm_oss_proc_free_setup_list(pstr); - mutex_unlock(&pstr->oss.setup_mutex); continue; } for (setup = pstr->oss.setup_list; setup; setup = setup->next) { @@ -3035,7 +3032,6 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry, setup = kmalloc(sizeof(*setup), GFP_KERNEL); if (! setup) { buffer->error = -ENOMEM; - mutex_unlock(&pstr->oss.setup_mutex); return; } if (pstr->oss.setup_list == NULL) @@ -3049,12 +3045,10 @@ static void snd_pcm_oss_proc_write(struct snd_info_entry *entry, if (! template.task_name) { kfree(setup); buffer->error = -ENOMEM; - mutex_unlock(&pstr->oss.setup_mutex); return; } } *setup = template; - mutex_unlock(&pstr->oss.setup_mutex); } } -- cgit 1.2.3-korg From 7dba48a474e68dcdda2b212cea131b4c9ddc7d89 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Feb 2024 09:53:06 +0100 Subject: ALSA: control_led: Use guard() for locking We can simplify the code gracefully with new guard() macro and co for automatic cleanup of locks. A couple of functions that use snd_card_ref() and *_unref() are also cleaned up with a defined class, too. Only the code refactoring, and no functional changes. Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240227085306.9764-25-tiwai@suse.de --- sound/core/control_led.c | 150 ++++++++++++++++++++--------------------------- 1 file changed, 65 insertions(+), 85 deletions(-) (limited to 'sound') diff --git a/sound/core/control_led.c b/sound/core/control_led.c index a78eb48927c7b..3d37e9fa7b9c2 100644 --- a/sound/core/control_led.c +++ b/sound/core/control_led.c @@ -147,29 +147,27 @@ static void snd_ctl_led_set_state(struct snd_card *card, unsigned int access, return; route = -1; found = false; - mutex_lock(&snd_ctl_led_mutex); - /* the card may not be registered (active) at this point */ - if (card && !snd_ctl_led_card_valid[card->number]) { - mutex_unlock(&snd_ctl_led_mutex); - return; - } - list_for_each_entry(lctl, &led->controls, list) { - if (lctl->kctl == kctl && lctl->index_offset == ioff) - found = true; - UPDATE_ROUTE(route, snd_ctl_led_get(lctl)); - } - if (!found && kctl && card) { - lctl = kzalloc(sizeof(*lctl), GFP_KERNEL); - if (lctl) { - lctl->card = card; - lctl->access = access; - lctl->kctl = kctl; - lctl->index_offset = ioff; - list_add(&lctl->list, &led->controls); + scoped_guard(mutex, &snd_ctl_led_mutex) { + /* the card may not be registered (active) at this point */ + if (card && !snd_ctl_led_card_valid[card->number]) + return; + list_for_each_entry(lctl, &led->controls, list) { + if (lctl->kctl == kctl && lctl->index_offset == ioff) + found = true; UPDATE_ROUTE(route, snd_ctl_led_get(lctl)); } + if (!found && kctl && card) { + lctl = kzalloc(sizeof(*lctl), GFP_KERNEL); + if (lctl) { + lctl->card = card; + lctl->access = access; + lctl->kctl = kctl; + lctl->index_offset = ioff; + list_add(&lctl->list, &led->controls); + UPDATE_ROUTE(route, snd_ctl_led_get(lctl)); + } + } } - mutex_unlock(&snd_ctl_led_mutex); switch (led->mode) { case MODE_OFF: route = 1; break; case MODE_ON: route = 0; break; @@ -201,14 +199,13 @@ static unsigned int snd_ctl_led_remove(struct snd_kcontrol *kctl, unsigned int i struct snd_ctl_led_ctl *lctl; unsigned int ret = 0; - mutex_lock(&snd_ctl_led_mutex); + guard(mutex)(&snd_ctl_led_mutex); lctl = snd_ctl_led_find(kctl, ioff); if (lctl && (access == 0 || access != lctl->access)) { ret = lctl->access; list_del(&lctl->list); kfree(lctl); } - mutex_unlock(&snd_ctl_led_mutex); return ret; } @@ -239,44 +236,36 @@ static void snd_ctl_led_notify(struct snd_card *card, unsigned int mask, } } +DEFINE_FREE(snd_card_unref, struct snd_card *, if (_T) snd_card_unref(_T)) + static int snd_ctl_led_set_id(int card_number, struct snd_ctl_elem_id *id, unsigned int group, bool set) { - struct snd_card *card; + struct snd_card *card __free(snd_card_unref) = NULL; struct snd_kcontrol *kctl; struct snd_kcontrol_volatile *vd; unsigned int ioff, access, new_access; - int err = 0; card = snd_card_ref(card_number); - if (card) { - down_write(&card->controls_rwsem); - kctl = snd_ctl_find_id_locked(card, id); - if (kctl) { - ioff = snd_ctl_get_ioff(kctl, id); - vd = &kctl->vd[ioff]; - access = vd->access & SNDRV_CTL_ELEM_ACCESS_LED_MASK; - if (access != 0 && access != group_to_access(group)) { - err = -EXDEV; - goto unlock; - } - new_access = vd->access & ~SNDRV_CTL_ELEM_ACCESS_LED_MASK; - if (set) - new_access |= group_to_access(group); - if (new_access != vd->access) { - vd->access = new_access; - snd_ctl_led_notify(card, SNDRV_CTL_EVENT_MASK_INFO, kctl, ioff); - } - } else { - err = -ENOENT; - } -unlock: - up_write(&card->controls_rwsem); - snd_card_unref(card); - } else { - err = -ENXIO; + if (!card) + return -ENXIO; + guard(rwsem_write)(&card->controls_rwsem); + kctl = snd_ctl_find_id_locked(card, id); + if (!kctl) + return -ENOENT; + ioff = snd_ctl_get_ioff(kctl, id); + vd = &kctl->vd[ioff]; + access = vd->access & SNDRV_CTL_ELEM_ACCESS_LED_MASK; + if (access != 0 && access != group_to_access(group)) + return -EXDEV; + new_access = vd->access & ~SNDRV_CTL_ELEM_ACCESS_LED_MASK; + if (set) + new_access |= group_to_access(group); + if (new_access != vd->access) { + vd->access = new_access; + snd_ctl_led_notify(card, SNDRV_CTL_EVENT_MASK_INFO, kctl, ioff); } - return err; + return 0; } static void snd_ctl_led_refresh(void) @@ -312,7 +301,7 @@ repeat: static int snd_ctl_led_reset(int card_number, unsigned int group) { - struct snd_card *card; + struct snd_card *card __free(snd_card_unref) = NULL; struct snd_ctl_led *led; struct snd_ctl_led_ctl *lctl; struct snd_kcontrol_volatile *vd; @@ -322,26 +311,22 @@ static int snd_ctl_led_reset(int card_number, unsigned int group) if (!card) return -ENXIO; - mutex_lock(&snd_ctl_led_mutex); - if (!snd_ctl_led_card_valid[card_number]) { - mutex_unlock(&snd_ctl_led_mutex); - snd_card_unref(card); - return -ENXIO; - } - led = &snd_ctl_leds[group]; + scoped_guard(mutex, &snd_ctl_led_mutex) { + if (!snd_ctl_led_card_valid[card_number]) + return -ENXIO; + led = &snd_ctl_leds[group]; repeat: - list_for_each_entry(lctl, &led->controls, list) - if (lctl->card == card) { - vd = &lctl->kctl->vd[lctl->index_offset]; - vd->access &= ~group_to_access(group); - snd_ctl_led_ctl_destroy(lctl); - change = true; - goto repeat; - } - mutex_unlock(&snd_ctl_led_mutex); + list_for_each_entry(lctl, &led->controls, list) + if (lctl->card == card) { + vd = &lctl->kctl->vd[lctl->index_offset]; + vd->access &= ~group_to_access(group); + snd_ctl_led_ctl_destroy(lctl); + change = true; + goto repeat; + } + } if (change) snd_ctl_led_set_state(NULL, group_to_access(group), NULL, 0); - snd_card_unref(card); return 0; } @@ -353,9 +338,8 @@ static void snd_ctl_led_register(struct snd_card *card) if (snd_BUG_ON(card->number < 0 || card->number >= ARRAY_SIZE(snd_ctl_led_card_valid))) return; - mutex_lock(&snd_ctl_led_mutex); - snd_ctl_led_card_valid[card->number] = true; - mutex_unlock(&snd_ctl_led_mutex); + scoped_guard(mutex, &snd_ctl_led_mutex) + snd_ctl_led_card_valid[card->number] = true; /* the register callback is already called with held card->controls_rwsem */ list_for_each_entry(kctl, &card->controls, list) for (ioff = 0; ioff < kctl->count; ioff++) @@ -367,10 +351,10 @@ static void snd_ctl_led_register(struct snd_card *card) static void snd_ctl_led_disconnect(struct snd_card *card) { snd_ctl_led_sysfs_remove(card); - mutex_lock(&snd_ctl_led_mutex); - snd_ctl_led_card_valid[card->number] = false; - snd_ctl_led_clean(card); - mutex_unlock(&snd_ctl_led_mutex); + scoped_guard(mutex, &snd_ctl_led_mutex) { + snd_ctl_led_card_valid[card->number] = false; + snd_ctl_led_clean(card); + } snd_ctl_led_refresh(); } @@ -430,9 +414,8 @@ static ssize_t mode_store(struct device *dev, else return count; - mutex_lock(&snd_ctl_led_mutex); - led->mode = mode; - mutex_unlock(&snd_ctl_led_mutex); + scoped_guard(mutex, &snd_ctl_led_mutex) + led->mode = mode; snd_ctl_led_set_state(NULL, group_to_access(led->group), NULL, 0); return count; @@ -615,15 +598,15 @@ static ssize_t list_show(struct device *dev, struct device_attribute *attr, char *buf) { struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev); - struct snd_card *card; + struct snd_card *card __free(snd_card_unref) = NULL; struct snd_ctl_led_ctl *lctl; size_t l = 0; card = snd_card_ref(led_card->number); if (!card) return -ENXIO; - down_read(&card->controls_rwsem); - mutex_lock(&snd_ctl_led_mutex); + guard(rwsem_read)(&card->controls_rwsem); + guard(mutex)(&snd_ctl_led_mutex); if (snd_ctl_led_card_valid[led_card->number]) { list_for_each_entry(lctl, &led_card->led->controls, list) { if (lctl->card != card) @@ -634,9 +617,6 @@ static ssize_t list_show(struct device *dev, lctl->kctl->id.numid + lctl->index_offset); } } - mutex_unlock(&snd_ctl_led_mutex); - up_read(&card->controls_rwsem); - snd_card_unref(card); return l; } -- cgit 1.2.3-korg From 72165c867f21d0724a9c900ff6e8bb5ba10cd8a8 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Fri, 1 Mar 2024 10:08:22 -0700 Subject: ALSA: hwdep: Move put_user() call out of scoped_guard() in snd_hwdep_control_ioctl() Clang prior to 17.0.0 has a bug in its asm goto jump scope analysis to determine that no variables with the cleanup attribute are skipped by an indirect jump. Instead of only checking the scope of each label that is a possible target of each asm goto statement, it checks the scope of every label, which can cause an error when a variable with the cleanup attribute is used between two asm goto statements with different scopes, even if they have completely different label targets: sound/core/hwdep.c:273:8: error: cannot jump from this asm goto statement to one of its possible targets if (get_user(device, (int __user *)arg)) ^ arch/powerpc/include/asm/uaccess.h:295:5: note: expanded from macro 'get_user' __get_user(x, _gu_addr) : \ ^ arch/powerpc/include/asm/uaccess.h:283:2: note: expanded from macro '__get_user' __get_user_size_allowed(__gu_val, __gu_addr, __gu_size, __gu_err); \ ^ arch/powerpc/include/asm/uaccess.h:199:3: note: expanded from macro '__get_user_size_allowed' __get_user_size_goto(x, ptr, size, __gus_failed); \ ^ arch/powerpc/include/asm/uaccess.h:187:10: note: expanded from macro '__get_user_size_goto' case 1: __get_user_asm_goto(x, (u8 __user *)ptr, label, "lbz"); break; \ ^ arch/powerpc/include/asm/uaccess.h:158:2: note: expanded from macro '__get_user_asm_goto' asm_volatile_goto( \ ^ include/linux/compiler_types.h:366:33: note: expanded from macro 'asm_volatile_goto' #define asm_volatile_goto(x...) asm goto(x) ^ sound/core/hwdep.c:291:9: note: possible target of asm goto statement if (put_user(device, (int __user *)arg)) ^ arch/powerpc/include/asm/uaccess.h:66:5: note: expanded from macro 'put_user' __put_user(x, _pu_addr) : -EFAULT; \ ^ arch/powerpc/include/asm/uaccess.h:52:9: note: expanded from macro '__put_user' \ ^ sound/core/hwdep.c:276:4: note: jump bypasses initialization of variable with __attribute__((cleanup)) scoped_guard(mutex, ®ister_mutex) { ^ include/linux/cleanup.h:169:20: note: expanded from macro 'scoped_guard' for (CLASS(_name, scope)(args), \ To avoid this issue, move the put_user() call out of the scoped_guard() scope, which allows the asm goto scope analysis to see that the variable with the cleanup attribute will never be skipped by the asm goto statements. There should be no functional change because prior to the refactoring, put_user() was not called under register_mutex, so this call does not even need to be in the scoped_guard() in the first place. Fixes: e6684d08cc19 ("ALSA: hwdep: Use guard() for locking") Closes: https://github.com/ClangBuiltLinux/linux/issues/2003 Signed-off-by: Nathan Chancellor Link: https://lore.kernel.org/r/20240301-fix-snd-hwdep-guard-v1-1-6aab033f3f83@kernel.org Signed-off-by: Takashi Iwai --- sound/core/hwdep.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index 9d7e5039c8930..09200df2932c7 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c @@ -288,11 +288,10 @@ static int snd_hwdep_control_ioctl(struct snd_card *card, } if (device >= SNDRV_MINOR_HWDEPS) device = -1; - if (put_user(device, (int __user *)arg)) - return -EFAULT; - return 0; } - break; + if (put_user(device, (int __user *)arg)) + return -EFAULT; + return 0; } case SNDRV_CTL_IOCTL_HWDEP_INFO: { -- cgit 1.2.3-korg From 1601cd53c7e3197181277326dbfc131d20a74e46 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 2 Mar 2024 00:11:07 +0100 Subject: ALSA: usb-audio: Name feature ctl using output if input is PCM When building feature controls from a unit without a name, we try to derive a name first from the feature unit's input, then fall back to the output terminal. If a feature unit connects directly to a "USB Streaming" input terminal rather than a mixer or other virtual type, the control receives the somewhat meaningless name "PCM", even if the output had a descriptive type such as "Headset" or "Speaker". Here is an example of such AudioControl descriptor from a USB headset which ends up named "PCM Playback" and is therefore not recognized as headphones by userspace: AudioControl Interface Descriptor: bLength 12 bDescriptorType 36 bDescriptorSubtype 2 (INPUT_TERMINAL) bTerminalID 4 wTerminalType 0x0101 USB Streaming bAssocTerminal 5 bNrChannels 2 wChannelConfig 0x0003 Left Front (L) Right Front (R) iChannelNames 0 iTerminal 0 AudioControl Interface Descriptor: bLength 9 bDescriptorType 36 bDescriptorSubtype 3 (OUTPUT_TERMINAL) bTerminalID 5 wTerminalType 0x0402 Headset bAssocTerminal 4 bSourceID 6 iTerminal 0 AudioControl Interface Descriptor: bLength 13 bDescriptorType 36 bDescriptorSubtype 6 (FEATURE_UNIT) bUnitID 6 bSourceID 4 bControlSize 2 bmaControls(0) 0x0002 Volume Control bmaControls(1) 0x0000 bmaControls(2) 0x0000 iFeature 0 Other headsets and DACs I tried that used their output terminal for naming only did so due to their input being an unnamed sidetone mixer. Instead of always starting with the input terminal, check the type of it first. If it seems uninteresting, invert the order and use the output terminal first for naming. This makes userspace recognize headsets with simple controls as headphones, and leads to more consistent naming of playback devices based on their outputs irrespective of sidetone mixers. Signed-off-by: Kenny Levinsen Link: https://lore.kernel.org/r/20240301231107.42679-1-kl@kl.wtf Signed-off-by: Takashi Iwai --- sound/usb/mixer.c | 49 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 409fc11646948..81256ab56835e 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -1652,6 +1652,34 @@ static const struct usb_feature_control_info *get_feature_control_info(int contr return NULL; } +static int feature_unit_mutevol_ctl_name(struct usb_mixer_interface *mixer, + struct snd_kcontrol *kctl, + struct usb_audio_term *iterm, + struct usb_audio_term *oterm) +{ + struct usb_audio_term *aterm, *bterm; + bool output_first; + int len = 0; + + /* + * If the input terminal is USB Streaming, we try getting the name of + * the output terminal first in hopes of getting something more + * descriptive than "PCM". + */ + output_first = iterm && !(iterm->type >> 16) && (iterm->type & 0xff00) == 0x0100; + + aterm = output_first ? oterm : iterm; + bterm = output_first ? iterm : oterm; + + if (aterm) + len = get_term_name(mixer->chip, aterm, kctl->id.name, + sizeof(kctl->id.name), 1); + if (!len && bterm) + len = get_term_name(mixer->chip, bterm, kctl->id.name, + sizeof(kctl->id.name), 1); + return len; +} + static void __build_feature_ctl(struct usb_mixer_interface *mixer, const struct usbmix_name_map *imap, unsigned int ctl_mask, int control, @@ -1733,22 +1761,15 @@ static void __build_feature_ctl(struct usb_mixer_interface *mixer, case UAC_FU_MUTE: case UAC_FU_VOLUME: /* - * determine the control name. the rule is: - * - if a name id is given in descriptor, use it. - * - if the connected input can be determined, then use the name - * of terminal type. - * - if the connected output can be determined, use it. - * - otherwise, anonymous name. + * Determine the control name: + * - If a name id is given in descriptor, use it. + * - If input and output terminals are present, try to derive + * the name from either of these. + * - Otherwise, make up a name using the feature unit ID. */ if (!len) { - if (iterm) - len = get_term_name(mixer->chip, iterm, - kctl->id.name, - sizeof(kctl->id.name), 1); - if (!len && oterm) - len = get_term_name(mixer->chip, oterm, - kctl->id.name, - sizeof(kctl->id.name), 1); + len = feature_unit_mutevol_ctl_name(mixer, kctl, iterm, + oterm); if (!len) snprintf(kctl->id.name, sizeof(kctl->id.name), "Feature %d", unitid); -- cgit 1.2.3-korg From bd6e4c4a7060c7b994ccf808bf177c57ddde233e Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Mon, 26 Feb 2024 13:44:28 +0100 Subject: ALSA: hda: Skip i915 initialization on CNL/LKF-based platforms Commit 78f613ba1efb ("drm/i915: finish removal of CNL") and its friends removed support for i915 for all CNL-based platforms. HDAudio library, however, still treats such platforms as valid candidates for i915 binding. Update query mechanism to reflect changes made in drm tree. At the same time, i915 support for LKF-based platforms has not been provided so remove them from valid binding candidates. Link: https://lore.kernel.org/all/20210728215946.1573015-1-lucas.demarchi@intel.com/ Reviewed-by: Rodrigo Vivi Signed-off-by: Cezary Rojewski Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240226124432.1203798-2-cezary.rojewski@intel.com --- sound/hda/hdac_i915.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c index 365c36fdf2058..e9425213320ea 100644 --- a/sound/hda/hdac_i915.c +++ b/sound/hda/hdac_i915.c @@ -127,15 +127,41 @@ static int i915_component_master_match(struct device *dev, int subcomponent, /* check whether Intel graphics is present and reachable */ static int i915_gfx_present(struct pci_dev *hdac_pci) { + /* List of known platforms with no i915 support. */ + static const struct pci_device_id denylist[] = { + /* CNL */ + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a40), 0x030000, 0xff0000 }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a41), 0x030000, 0xff0000 }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a42), 0x030000, 0xff0000 }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a44), 0x030000, 0xff0000 }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a49), 0x030000, 0xff0000 }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a4a), 0x030000, 0xff0000 }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a4c), 0x030000, 0xff0000 }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a50), 0x030000, 0xff0000 }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a51), 0x030000, 0xff0000 }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a52), 0x030000, 0xff0000 }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a54), 0x030000, 0xff0000 }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a59), 0x030000, 0xff0000 }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a5a), 0x030000, 0xff0000 }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x5a5c), 0x030000, 0xff0000 }, + /* LKF */ + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x9840), 0x030000, 0xff0000 }, + {} + }; struct pci_dev *display_dev = NULL; if (!gpu_bind || (gpu_bind < 0 && video_firmware_drivers_only())) return false; for_each_pci_dev(display_dev) { - if (display_dev->vendor == PCI_VENDOR_ID_INTEL && - (display_dev->class >> 16) == PCI_BASE_CLASS_DISPLAY && - connectivity_check(display_dev, hdac_pci)) { + if (display_dev->vendor != PCI_VENDOR_ID_INTEL || + (display_dev->class >> 16) != PCI_BASE_CLASS_DISPLAY) + continue; + + if (pci_match_id(denylist, display_dev)) + continue; + + if (connectivity_check(display_dev, hdac_pci)) { pci_dev_put(display_dev); return true; } -- cgit 1.2.3-korg From cf9c19df2755d57501ce3922bb22ff0734d8bed5 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Mon, 26 Feb 2024 13:44:29 +0100 Subject: ASoC: codecs: hda: Skip HDMI/DP registration if i915 is missing If i915 does not support given platform but the hardware i.e.: HDAudio codec is still there, the codec-probing procedure will succeed for such device but the follow up initialization will always end up with -ENODEV. While bus could filter out address '2' which Intel's HDMI/DP codecs always enumerate on, more robust approach is to check for i915 presence before registering display codecs. Signed-off-by: Cezary Rojewski Acked-by: Mark Brown Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240226124432.1203798-3-cezary.rojewski@intel.com --- sound/soc/codecs/hda.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c index d2117e36ddd10..7c6bedeceaa2f 100644 --- a/sound/soc/codecs/hda.c +++ b/sound/soc/codecs/hda.c @@ -350,6 +350,11 @@ static int hda_hdev_attach(struct hdac_device *hdev) struct hda_codec *codec = dev_to_hda_codec(&hdev->dev); struct snd_soc_component_driver *comp_drv; + if (hda_codec_is_display(codec) && !hdev->bus->audio_component) { + dev_dbg(&hdev->dev, "no i915, skip registration for 0x%08x\n", hdev->vendor_id); + return -ENODEV; + } + comp_drv = devm_kzalloc(&hdev->dev, sizeof(*comp_drv), GFP_KERNEL); if (!comp_drv) return -ENOMEM; -- cgit 1.2.3-korg From b9f706f9ef468754d35a459eaff12cc0594b6e5d Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Mon, 26 Feb 2024 13:44:30 +0100 Subject: ASoC: Intel: avs: Ignore codecs with no suppoting driver HDMI codecs which are present and functional from audio perspective lack i915 support on drm side what results in -ENODEV during the probing sequence. There is no reason to perform recovery procedure e.g.: reset the HDAudio controller if this is the case. Signed-off-by: Cezary Rojewski Acked-by: Mark Brown Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240226124432.1203798-4-cezary.rojewski@intel.com --- sound/soc/intel/avs/core.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c index db78eb2f01080..565878eb42cd2 100644 --- a/sound/soc/intel/avs/core.c +++ b/sound/soc/intel/avs/core.c @@ -144,7 +144,7 @@ static int probe_codec(struct hdac_bus *bus, int addr) /* configure effectively creates new ASoC component */ ret = snd_hda_codec_configure(codec); if (ret < 0) { - dev_err(bus->dev, "failed to config codec %d\n", ret); + dev_warn(bus->dev, "failed to config codec #%d: %d\n", addr, ret); return ret; } @@ -153,15 +153,16 @@ static int probe_codec(struct hdac_bus *bus, int addr) static void avs_hdac_bus_probe_codecs(struct hdac_bus *bus) { - int c; + int ret, c; /* First try to probe all given codec slots */ for (c = 0; c < HDA_MAX_CODECS; c++) { if (!(bus->codec_mask & BIT(c))) continue; - if (!probe_codec(bus, c)) - /* success, continue probing */ + ret = probe_codec(bus, c); + /* Ignore codecs with no supporting driver. */ + if (!ret || ret == -ENODEV) continue; /* -- cgit 1.2.3-korg From 3adb233ec8777fd3a37441e363b91b9de6a9c2d2 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Mon, 26 Feb 2024 13:44:31 +0100 Subject: ASoC: codecs: hda: Cleanup error messages Be cohesive and use same pattern in each error message. Signed-off-by: Cezary Rojewski Acked-by: Mark Brown Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240226124432.1203798-5-cezary.rojewski@intel.com --- sound/soc/codecs/hda.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c index 7c6bedeceaa2f..5a58723dc0e96 100644 --- a/sound/soc/codecs/hda.c +++ b/sound/soc/codecs/hda.c @@ -198,19 +198,19 @@ static int hda_codec_probe(struct snd_soc_component *component) ret = snd_hda_codec_device_new(codec->bus, component->card->snd_card, hdev->addr, codec, false); if (ret < 0) { - dev_err(&hdev->dev, "create hda codec failed: %d\n", ret); + dev_err(&hdev->dev, "codec create failed: %d\n", ret); goto device_new_err; } ret = snd_hda_codec_set_name(codec, codec->preset->name); if (ret < 0) { - dev_err(&hdev->dev, "name failed %s\n", codec->preset->name); + dev_err(&hdev->dev, "set name: %s failed: %d\n", codec->preset->name, ret); goto err; } ret = snd_hdac_regmap_init(&codec->core); if (ret < 0) { - dev_err(&hdev->dev, "regmap init failed\n"); + dev_err(&hdev->dev, "regmap init failed: %d\n", ret); goto err; } @@ -223,13 +223,13 @@ static int hda_codec_probe(struct snd_soc_component *component) ret = patch(codec); if (ret < 0) { - dev_err(&hdev->dev, "patch failed %d\n", ret); + dev_err(&hdev->dev, "codec init failed: %d\n", ret); goto err; } ret = snd_hda_codec_parse_pcms(codec); if (ret < 0) { - dev_err(&hdev->dev, "unable to map pcms to dai %d\n", ret); + dev_err(&hdev->dev, "unable to map pcms to dai: %d\n", ret); goto parse_pcms_err; } -- cgit 1.2.3-korg From ee14bad1d3e3461fddffba280dd1caeb1b3c7a1d Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Mon, 26 Feb 2024 13:44:32 +0100 Subject: ALSA: hda: Reuse for_each_pcm_streams() Use the macro to improve readability. Signed-off-by: Cezary Rojewski Signed-off-by: Takashi Iwai Link: https://lore.kernel.org/r/20240226124432.1203798-6-cezary.rojewski@intel.com --- sound/pci/hda/hda_codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 12f02cdc96594..2cac337f52632 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -3313,7 +3313,7 @@ int snd_hda_codec_parse_pcms(struct hda_codec *codec) list_for_each_entry(cpcm, &codec->pcm_list_head, list) { int stream; - for (stream = 0; stream < 2; stream++) { + for_each_pcm_streams(stream) { struct hda_pcm_stream *info = &cpcm->stream[stream]; if (!info->substreams) -- cgit 1.2.3-korg From cecc34aeb714df8c61cb5423c3dd4efe14b9c6f9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 4 Mar 2024 09:21:58 +0100 Subject: ALSA: ac97: More cleanup with snd_ctl_find_id_mixer() There was one overlooked place to be replaced with snd_ctl_find_id_mixer() for code simplification. No functional change, only code refactoring. Link: https://lore.kernel.org/r/20240304082158.8583-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- sound/pci/ac97/ac97_patch.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 1d786bd5ce3e3..cd83aa864ea3e 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -41,12 +41,9 @@ static int patch_build_controls(struct snd_ac97 * ac97, const struct snd_kcontro static void reset_tlv(struct snd_ac97 *ac97, const char *name, const unsigned int *tlv) { - struct snd_ctl_elem_id sid; struct snd_kcontrol *kctl; - memset(&sid, 0, sizeof(sid)); - strcpy(sid.name, name); - sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - kctl = snd_ctl_find_id(ac97->bus->card, &sid); + + kctl = snd_ctl_find_id_mixer(ac97->bus->card, name); if (kctl && kctl->tlv.p) kctl->tlv.p = tlv; } -- cgit 1.2.3-korg From 27219a5b3285dffb6e2e1b915a0ccdbf07f9a3a0 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Thu, 7 Mar 2024 11:12:15 +0000 Subject: ALSA: hda: hda_component: Add missing #include guards Add the conventional include guards around the content of the hda_component.h header file. This prevents double-declaration of struct hda_component if the header gets included multiple times. This isn't causing any problems with current code, so no need to backport to older kernels. Signed-off-by: Richard Fitzgerald Message-ID: <20240307111216.45053-1-rf@opensource.cirrus.com> Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_component.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/hda_component.h b/sound/pci/hda/hda_component.h index deae9dea01b4e..a0fcc723483d3 100644 --- a/sound/pci/hda/hda_component.h +++ b/sound/pci/hda/hda_component.h @@ -6,6 +6,9 @@ * Cirrus Logic International Semiconductor Ltd. */ +#ifndef __HDA_COMPONENT_H__ +#define __HDA_COMPONENT_H__ + #include #include @@ -82,3 +85,5 @@ static inline void hda_component_manager_unbind(struct hda_codec *cdc, { component_unbind_all(hda_codec_dev(cdc), comps); } + +#endif /* ifndef __HDA_COMPONENT_H__ */ -- cgit 1.2.3-korg From 85b4f2a6efc933b742e447604df88f1f098ec080 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Thu, 7 Mar 2024 11:12:16 +0000 Subject: ALSA: hda: hda_component: Include sound/hda_codec.h hda_component.h uses hda_codec_dev from sound/hda_codec.h. Include sound/hda_codec.h instead of assuming that it has already been included by the parent .c file. This isn't causing any problems with current code, so no need to backport to older kernels. Signed-off-by: Richard Fitzgerald Message-ID: <20240307111216.45053-2-rf@opensource.cirrus.com> Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_component.h | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/hda_component.h b/sound/pci/hda/hda_component.h index a0fcc723483d3..c80a66691b5d8 100644 --- a/sound/pci/hda/hda_component.h +++ b/sound/pci/hda/hda_component.h @@ -11,6 +11,7 @@ #include #include +#include #define HDA_MAX_COMPONENTS 4 #define HDA_MAX_NAME_SIZE 50 -- cgit 1.2.3-korg From afd17e6debf9494af778a58ec7706da05ede0730 Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Fri, 8 Mar 2024 13:58:58 +0000 Subject: ASoC: cs35l56: Add support for CS35L54 and CS35L57 The CS35L54 and CS35L57 are Boosted Smart Amplifiers. The CS35L54 has I2C/SPI control and I2S/TDM audio. The CS35L57 also has SoundWire control and audio. The hardware differences between L54, L56 and L57 do not affect the driver control interface so they can all be handled by the same driver. Signed-off-by: Simon Trimmer Signed-off-by: Richard Fitzgerald Acked-by: Mark Brown Signed-off-by: Takashi Iwai Message-ID: <20240308135900.603192-2-rf@opensource.cirrus.com> --- include/sound/cs35l56.h | 1 + sound/soc/codecs/cs35l56-sdw.c | 3 ++- sound/soc/codecs/cs35l56-shared.c | 8 ++++++-- sound/soc/codecs/cs35l56.c | 14 +++++++++++++- 4 files changed, 22 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h index b24716ab27504..5fda814776b95 100644 --- a/include/sound/cs35l56.h +++ b/include/sound/cs35l56.h @@ -257,6 +257,7 @@ struct cs35l56_base { struct regmap *regmap; int irq; struct mutex irq_lock; + u8 type; u8 rev; bool init_done; bool fw_patched; diff --git a/sound/soc/codecs/cs35l56-sdw.c b/sound/soc/codecs/cs35l56-sdw.c index ab960a1c171e6..abd296da6dbd8 100644 --- a/sound/soc/codecs/cs35l56-sdw.c +++ b/sound/soc/codecs/cs35l56-sdw.c @@ -366,7 +366,7 @@ static int cs35l56_sdw_bus_config(struct sdw_slave *peripheral, dev_dbg(cs35l56->base.dev, "%s: sclk=%u c=%u r=%u\n", __func__, sclk, params->col, params->row); - if (cs35l56->base.rev < 0xb0) + if ((cs35l56->base.type == 0x56) && (cs35l56->base.rev < 0xb0)) return cs35l56_a1_kick_divider(cs35l56, peripheral); return 0; @@ -543,6 +543,7 @@ static const struct dev_pm_ops cs35l56_sdw_pm = { static const struct sdw_device_id cs35l56_sdw_id[] = { SDW_SLAVE_ENTRY(0x01FA, 0x3556, 0), + SDW_SLAVE_ENTRY(0x01FA, 0x3557, 0), {}, }; MODULE_DEVICE_TABLE(sdw, cs35l56_sdw_id); diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c index 995d979b6d87e..aa550db02c16d 100644 --- a/sound/soc/codecs/cs35l56-shared.c +++ b/sound/soc/codecs/cs35l56-shared.c @@ -692,13 +692,17 @@ int cs35l56_hw_init(struct cs35l56_base *cs35l56_base) devid &= CS35L56_DEVID_MASK; switch (devid) { + case 0x35A54: case 0x35A56: + case 0x35A57: break; default: dev_err(cs35l56_base->dev, "Unknown device %x\n", devid); return ret; } + cs35l56_base->type = devid & 0xFF; + ret = regmap_read(cs35l56_base->regmap, CS35L56_DSP_RESTRICT_STS1, &secured); if (ret) { dev_err(cs35l56_base->dev, "Get Secure status failed\n"); @@ -719,8 +723,8 @@ int cs35l56_hw_init(struct cs35l56_base *cs35l56_base) if (ret) return ret; - dev_info(cs35l56_base->dev, "Cirrus Logic CS35L56%s Rev %02X OTP%d fw:%d.%d.%d (patched=%u)\n", - cs35l56_base->secured ? "s" : "", cs35l56_base->rev, otpid, + dev_info(cs35l56_base->dev, "Cirrus Logic CS35L%02X%s Rev %02X OTP%d fw:%d.%d.%d (patched=%u)\n", + cs35l56_base->type, cs35l56_base->secured ? "s" : "", cs35l56_base->rev, otpid, fw_ver >> 16, (fw_ver >> 8) & 0xff, fw_ver & 0xff, !fw_missing); /* Wake source and *_BLOCKED interrupts default to unmasked, so mask them */ diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index 2c1313e34cce4..beb51c87c6e97 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -972,6 +972,10 @@ static int cs35l56_component_probe(struct snd_soc_component *component) return -ENODEV; } + cs35l56->dsp.part = kasprintf(GFP_KERNEL, "cs35l%02x", cs35l56->base.type); + if (!cs35l56->dsp.part) + return -ENOMEM; + cs35l56->component = component; wm_adsp2_component_probe(&cs35l56->dsp, component); @@ -1002,6 +1006,9 @@ static void cs35l56_component_remove(struct snd_soc_component *component) wm_adsp2_component_remove(&cs35l56->dsp, component); + kfree(cs35l56->dsp.part); + cs35l56->dsp.part = NULL; + kfree(cs35l56->dsp.fwf_name); cs35l56->dsp.fwf_name = NULL; @@ -1221,7 +1228,12 @@ static int cs35l56_dsp_init(struct cs35l56_private *cs35l56) dsp = &cs35l56->dsp; cs35l56_init_cs_dsp(&cs35l56->base, &dsp->cs_dsp); - dsp->part = "cs35l56"; + + /* + * dsp->part is filled in later as it is based on the DEVID. In a + * SoundWire system that cannot be read until enumeration has occurred + * and the device has attached. + */ dsp->fw = 12; dsp->wmfw_optional = true; -- cgit 1.2.3-korg From 769dca2316d69f8e86b7761d7072752cba710f58 Mon Sep 17 00:00:00 2001 From: Simon Trimmer Date: Fri, 8 Mar 2024 13:58:59 +0000 Subject: ALSA: hda: cs35l56: Add support for CS35L54 and CS35L57 Add the HID for the CS35L54 and CS35L57 Boosted Smart Amplifiers. These have the same control interface as the CS35L56 so are handled by the cs35l56-hda driver. Signed-off-by: Simon Trimmer Signed-off-by: Richard Fitzgerald Signed-off-by: Takashi Iwai Message-ID: <20240308135900.603192-3-rf@opensource.cirrus.com> --- sound/pci/hda/cs35l56_hda.c | 16 ++++++++++------ sound/pci/hda/cs35l56_hda.h | 2 +- sound/pci/hda/cs35l56_hda_i2c.c | 7 +++++-- sound/pci/hda/cs35l56_hda_spi.c | 7 +++++-- 4 files changed, 21 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c index 75a14ba54fcd1..1fae241642b12 100644 --- a/sound/pci/hda/cs35l56_hda.c +++ b/sound/pci/hda/cs35l56_hda.c @@ -458,13 +458,15 @@ static void cs35l56_hda_request_firmware_files(struct cs35l56_hda *cs35l56, if (preloaded_fw_ver) { snprintf(base_name, sizeof(base_name), - "cirrus/cs35l56-%02x%s-%06x-dsp1-misc", + "cirrus/cs35l%02x-%02x%s-%06x-dsp1-misc", + cs35l56->base.type, cs35l56->base.rev, cs35l56->base.secured ? "-s" : "", preloaded_fw_ver & 0xffffff); } else { snprintf(base_name, sizeof(base_name), - "cirrus/cs35l56-%02x%s-dsp1-misc", + "cirrus/cs35l%02x-%02x%s-dsp1-misc", + cs35l56->base.type, cs35l56->base.rev, cs35l56->base.secured ? "-s" : ""); } @@ -834,9 +836,10 @@ static int cs35l56_hda_system_resume(struct device *dev) return 0; } -static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int id) +static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id) { u32 values[HDA_MAX_COMPONENTS]; + char hid_string[8]; struct acpi_device *adev; const char *property, *sub; size_t nval; @@ -847,7 +850,8 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int id) * the serial-multi-instantiate driver, so lookup the node by HID */ if (!ACPI_COMPANION(cs35l56->base.dev)) { - adev = acpi_dev_get_first_match_dev("CSC3556", NULL, -1); + snprintf(hid_string, sizeof(hid_string), "CSC%04X", hid); + adev = acpi_dev_get_first_match_dev(hid_string, NULL, -1); if (!adev) { dev_err(cs35l56->base.dev, "Failed to find an ACPI device for %s\n", dev_name(cs35l56->base.dev)); @@ -935,14 +939,14 @@ err: return ret; } -int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int id) +int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id) { int ret; mutex_init(&cs35l56->base.irq_lock); dev_set_drvdata(cs35l56->base.dev, cs35l56); - ret = cs35l56_hda_read_acpi(cs35l56, id); + ret = cs35l56_hda_read_acpi(cs35l56, hid, id); if (ret) goto err; diff --git a/sound/pci/hda/cs35l56_hda.h b/sound/pci/hda/cs35l56_hda.h index 6e5bc5397db5f..464e4aa63cd1b 100644 --- a/sound/pci/hda/cs35l56_hda.h +++ b/sound/pci/hda/cs35l56_hda.h @@ -42,7 +42,7 @@ struct cs35l56_hda { extern const struct dev_pm_ops cs35l56_hda_pm_ops; -int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int id); +int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id); void cs35l56_hda_remove(struct device *dev); #endif /*__CS35L56_HDA_H__*/ diff --git a/sound/pci/hda/cs35l56_hda_i2c.c b/sound/pci/hda/cs35l56_hda_i2c.c index a9ef6d86de839..13beee807308f 100644 --- a/sound/pci/hda/cs35l56_hda_i2c.c +++ b/sound/pci/hda/cs35l56_hda_i2c.c @@ -13,6 +13,7 @@ static int cs35l56_hda_i2c_probe(struct i2c_client *clt) { + const struct i2c_device_id *id = i2c_client_get_device_id(clt); struct cs35l56_hda *cs35l56; int ret; @@ -33,7 +34,7 @@ static int cs35l56_hda_i2c_probe(struct i2c_client *clt) return ret; } - ret = cs35l56_hda_common_probe(cs35l56, clt->addr); + ret = cs35l56_hda_common_probe(cs35l56, id->driver_data, clt->addr); if (ret) return ret; ret = cs35l56_irq_request(&cs35l56->base, clt->irq); @@ -49,7 +50,9 @@ static void cs35l56_hda_i2c_remove(struct i2c_client *clt) } static const struct i2c_device_id cs35l56_hda_i2c_id[] = { - { "cs35l56-hda", 0 }, + { "cs35l54-hda", 0x3554 }, + { "cs35l56-hda", 0x3556 }, + { "cs35l57-hda", 0x3557 }, {} }; diff --git a/sound/pci/hda/cs35l56_hda_spi.c b/sound/pci/hda/cs35l56_hda_spi.c index 080426de90830..a3b2fa76663d3 100644 --- a/sound/pci/hda/cs35l56_hda_spi.c +++ b/sound/pci/hda/cs35l56_hda_spi.c @@ -13,6 +13,7 @@ static int cs35l56_hda_spi_probe(struct spi_device *spi) { + const struct spi_device_id *id = spi_get_device_id(spi); struct cs35l56_hda *cs35l56; int ret; @@ -33,7 +34,7 @@ static int cs35l56_hda_spi_probe(struct spi_device *spi) return ret; } - ret = cs35l56_hda_common_probe(cs35l56, spi_get_chipselect(spi, 0)); + ret = cs35l56_hda_common_probe(cs35l56, id->driver_data, spi_get_chipselect(spi, 0)); if (ret) return ret; ret = cs35l56_irq_request(&cs35l56->base, spi->irq); @@ -49,7 +50,9 @@ static void cs35l56_hda_spi_remove(struct spi_device *spi) } static const struct spi_device_id cs35l56_hda_spi_id[] = { - { "cs35l56-hda", 0 }, + { "cs35l54-hda", 0x3554 }, + { "cs35l56-hda", 0x3556 }, + { "cs35l57-hda", 0x3557 }, {} }; -- cgit 1.2.3-korg