From 2112aa034907c428785e1a5730927181276ee45b Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 17 Nov 2023 13:05:55 +0100 Subject: ALSA: pcm: Introduce MSBITS subformat interface Improve granularity of format selection for S32/U32 formats by adding constants representing 20, 24 and MAX most significant bits. The MAX means the maximum number of significant bits which can the physical format hold. For 32-bit formats, MAX is related to 32 bits. For 8-bit formats, MAX is related to 8 bits etc. As there is only one user currently (format S32_LE), subformat is represented by a simple u32 and stores flags only for that one user alone. The approach of subformat being part of struct snd_pcm_hardware is a compromise between ALSA and ASoC allowing for hw_params-intersection code to be alloc/free-less while not adding any new responsibilities to ASoC runtime structures. Acked-by: Mark Brown Signed-off-by: Jaroslav Kysela Co-developed-by: Cezary Rojewski Signed-off-by: Cezary Rojewski Link: https://lore.kernel.org/r/20231117120610.1755254-2-cezary.rojewski@intel.com Signed-off-by: Takashi Iwai --- sound/core/pcm.c | 3 +++ sound/core/pcm_native.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 56 insertions(+), 2 deletions(-) (limited to 'sound/core') diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 20bb2d7c8d4b..c4bc15f048b6 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -265,6 +265,9 @@ static const char * const snd_pcm_access_names[] = { static const char * const snd_pcm_subformat_names[] = { SUBFORMAT(STD), + SUBFORMAT(MSBITS_MAX), + SUBFORMAT(MSBITS_20), + SUBFORMAT(MSBITS_24), }; static const char * const snd_pcm_tstamp_mode_names[] = { diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index f610b08f5a2b..f5ff00f99788 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -479,6 +479,7 @@ static int fixup_unreferenced_params(struct snd_pcm_substream *substream, { const struct snd_interval *i; const struct snd_mask *m; + struct snd_mask *m_rw; int err; if (!params->msbits) { @@ -487,6 +488,22 @@ static int fixup_unreferenced_params(struct snd_pcm_substream *substream, params->msbits = snd_interval_value(i); } + if (params->msbits) { + m = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT); + if (snd_mask_single(m)) { + snd_pcm_format_t format = (__force snd_pcm_format_t)snd_mask_min(m); + + if (snd_pcm_format_linear(format) && + snd_pcm_format_width(format) != params->msbits) { + m_rw = hw_param_mask(params, SNDRV_PCM_HW_PARAM_SUBFORMAT); + snd_mask_reset(m_rw, + (__force unsigned)SNDRV_PCM_SUBFORMAT_MSBITS_MAX); + if (snd_mask_empty(m_rw)) + return -EINVAL; + } + } + } + if (!params->rate_den) { i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); if (snd_interval_single(i)) { @@ -2483,6 +2500,41 @@ static int snd_pcm_hw_rule_buffer_bytes_max(struct snd_pcm_hw_params *params, return snd_interval_refine(hw_param_interval(params, rule->var), &t); } +static int snd_pcm_hw_rule_subformats(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + struct snd_mask *sfmask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_SUBFORMAT); + struct snd_mask *fmask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + u32 *subformats = rule->private; + snd_pcm_format_t f; + struct snd_mask m; + + snd_mask_none(&m); + /* All PCMs support at least the default STD subformat. */ + snd_mask_set(&m, (__force unsigned)SNDRV_PCM_SUBFORMAT_STD); + + pcm_for_each_format(f) { + if (!snd_mask_test(fmask, (__force unsigned)f)) + continue; + + if (f == SNDRV_PCM_FORMAT_S32_LE && *subformats) + m.bits[0] |= *subformats; + else if (snd_pcm_format_linear(f)) + snd_mask_set(&m, (__force unsigned)SNDRV_PCM_SUBFORMAT_MSBITS_MAX); + } + + return snd_mask_refine(sfmask, &m); +} + +static int snd_pcm_hw_constraint_subformats(struct snd_pcm_runtime *runtime, + unsigned int cond, u32 *subformats) +{ + return snd_pcm_hw_rule_add(runtime, cond, -1, + snd_pcm_hw_rule_subformats, (void *)subformats, + SNDRV_PCM_HW_PARAM_SUBFORMAT, + SNDRV_PCM_HW_PARAM_FORMAT, -1); +} + static int snd_pcm_hw_constraints_init(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -2634,8 +2686,7 @@ static int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream) if (err < 0) return err; - err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_SUBFORMAT, - PARAM_MASK_BIT(SNDRV_PCM_SUBFORMAT_STD)); + err = snd_pcm_hw_constraint_subformats(runtime, 0, &hw->subformats); if (err < 0) return err; -- cgit v1.2.3 From d24f1a090d3f2a5c86a8782afeda71c2d2539966 Mon Sep 17 00:00:00 2001 From: Cezary Rojewski Date: Fri, 17 Nov 2023 13:05:58 +0100 Subject: ALSA: hda: Upgrade stream-format infrastructure Introduce a set of functions that ultimately facilite SDxFMT-related calculations in atomic manner: First, introduce snd_pcm_subformat_width() and snd_pcm_hw_params_bits() helpers that separate the base functionality from the HDAudio-specific one. snd_hdac_format_normalize() - format converter. S20_LE, S24_LE and their unsigned and BE friends are invalid from HDAudio perspective but still can be specified as function argument due to compatibility reasons. snd_hdac_stream_format_bits() - obtain just the bits-per-sample value. Does not ignore subformat and msbits parameters. snd_hdac_stream_format() and snd_hdac_spdif_stream_format() - obtain the SDxFMT value given the audio format parameters. The former is stripped away of spdif-related information. Useful for users that do not care about them. Acked-by: Mark Brown Signed-off-by: Cezary Rojewski Acked-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20231117120610.1755254-5-cezary.rojewski@intel.com Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'sound/core') diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index a11cd7d6295f..41103e5c43ce 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1706,6 +1706,40 @@ int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm, } EXPORT_SYMBOL(snd_pcm_hw_param_last); +/** + * snd_pcm_hw_params_bits - Get the number of bits per the sample. + * @p: hardware parameters + * + * Return: The number of bits per sample based on the format, + * subformat and msbits the specified hw params has. + */ +int snd_pcm_hw_params_bits(const struct snd_pcm_hw_params *p) +{ + snd_pcm_subformat_t subformat = params_subformat(p); + snd_pcm_format_t format = params_format(p); + + switch (format) { + case SNDRV_PCM_FORMAT_S32_LE: + case SNDRV_PCM_FORMAT_U32_LE: + case SNDRV_PCM_FORMAT_S32_BE: + case SNDRV_PCM_FORMAT_U32_BE: + switch (subformat) { + case SNDRV_PCM_SUBFORMAT_MSBITS_20: + return 20; + case SNDRV_PCM_SUBFORMAT_MSBITS_24: + return 24; + case SNDRV_PCM_SUBFORMAT_MSBITS_MAX: + case SNDRV_PCM_SUBFORMAT_STD: + default: + break; + } + fallthrough; + default: + return snd_pcm_format_width(format); + } +} +EXPORT_SYMBOL(snd_pcm_hw_params_bits); + static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream, void *arg) { -- cgit v1.2.3 From 126c18a4bb6460c3d82b57c56941104ed34b7ba6 Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Thu, 21 Dec 2023 12:16:00 +0300 Subject: ALSA: seq: fix kvmalloc_array() arguments order When compiling with gcc version 14.0.0 20231220 (experimental) and W=1, I've noticed the following warning: sound/core/seq/seq_memory.c: In function 'snd_seq_pool_init': sound/core/seq/seq_memory.c:445:41: warning: 'kvmalloc_array' sizes specified with 'sizeof' in the earlier argument and not in the later argument [-Wcalloc-transposed-args] 445 | cellptr = kvmalloc_array(sizeof(struct snd_seq_event_cell), pool->size, | ^~~~~~ Since 'n' and 'size' arguments of 'kvmalloc_array()' are multiplied to calculate the final size, their actual order doesn't affect the result and so this is not a bug. But it's still worth to fix it. Signed-off-by: Dmitry Antipov Link: https://lore.kernel.org/r/20231221091605.14660-1-dmantipov@yandex.ru Signed-off-by: Takashi Iwai --- sound/core/seq/seq_memory.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound/core') diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c index b603bb93f896..e705e7538118 100644 --- a/sound/core/seq/seq_memory.c +++ b/sound/core/seq/seq_memory.c @@ -442,7 +442,8 @@ int snd_seq_pool_init(struct snd_seq_pool *pool) if (snd_BUG_ON(!pool)) return -EINVAL; - cellptr = kvmalloc_array(sizeof(struct snd_seq_event_cell), pool->size, + cellptr = kvmalloc_array(pool->size, + sizeof(struct snd_seq_event_cell), GFP_KERNEL); if (!cellptr) return -ENOMEM; -- cgit v1.2.3