]> Git Repo - linux.git/commitdiff
ALSA: pcm: Introduce MSBITS subformat interface
authorJaroslav Kysela <[email protected]>
Fri, 17 Nov 2023 12:05:55 +0000 (13:05 +0100)
committerTakashi Iwai <[email protected]>
Mon, 27 Nov 2023 16:24:26 +0000 (17:24 +0100)
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 <[email protected]>
Signed-off-by: Jaroslav Kysela <[email protected]>
Co-developed-by: Cezary Rojewski <[email protected]>
Signed-off-by: Cezary Rojewski <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Takashi Iwai <[email protected]>
include/sound/pcm.h
include/uapi/sound/asound.h
sound/core/pcm.c
sound/core/pcm_native.c
tools/include/uapi/sound/asound.h

index 2a815373dac1d9841d1cfac74606b4929030c349..cc175c623dac71d63062beb2441f5b94ec35d346 100644 (file)
@@ -32,6 +32,7 @@
 struct snd_pcm_hardware {
        unsigned int info;              /* SNDRV_PCM_INFO_* */
        u64 formats;                    /* SNDRV_PCM_FMTBIT_* */
+       u32 subformats;                 /* for S32_LE, SNDRV_PCM_SUBFMTBIT_* */
        unsigned int rates;             /* SNDRV_PCM_RATE_* */
        unsigned int rate_min;          /* min rate */
        unsigned int rate_max;          /* max rate */
@@ -217,6 +218,12 @@ struct snd_pcm_ops {
 #define SNDRV_PCM_FMTBIT_U20           SNDRV_PCM_FMTBIT_U20_BE
 #endif
 
+#define _SNDRV_PCM_SUBFMTBIT(fmt)      BIT((__force int)SNDRV_PCM_SUBFORMAT_##fmt)
+#define SNDRV_PCM_SUBFMTBIT_STD                _SNDRV_PCM_SUBFMTBIT(STD)
+#define SNDRV_PCM_SUBFMTBIT_MSBITS_MAX _SNDRV_PCM_SUBFMTBIT(MSBITS_MAX)
+#define SNDRV_PCM_SUBFMTBIT_MSBITS_20  _SNDRV_PCM_SUBFMTBIT(MSBITS_20)
+#define SNDRV_PCM_SUBFMTBIT_MSBITS_24  _SNDRV_PCM_SUBFMTBIT(MSBITS_24)
+
 struct snd_pcm_file {
        struct snd_pcm_substream *substream;
        int no_compat_mmap;
index f9939da4112272d43b674d99de3e6f56793e014b..d5b9cfbd9ceac69323d0fe487cc49ab388a2e523 100644 (file)
@@ -142,7 +142,7 @@ struct snd_hwdep_dsp_image {
  *                                                                           *
  *****************************************************************************/
 
-#define SNDRV_PCM_VERSION              SNDRV_PROTOCOL_VERSION(2, 0, 15)
+#define SNDRV_PCM_VERSION              SNDRV_PROTOCOL_VERSION(2, 0, 16)
 
 typedef unsigned long snd_pcm_uframes_t;
 typedef signed long snd_pcm_sframes_t;
@@ -267,7 +267,10 @@ typedef int __bitwise snd_pcm_format_t;
 
 typedef int __bitwise snd_pcm_subformat_t;
 #define        SNDRV_PCM_SUBFORMAT_STD         ((__force snd_pcm_subformat_t) 0)
-#define        SNDRV_PCM_SUBFORMAT_LAST        SNDRV_PCM_SUBFORMAT_STD
+#define        SNDRV_PCM_SUBFORMAT_MSBITS_MAX  ((__force snd_pcm_subformat_t) 1)
+#define        SNDRV_PCM_SUBFORMAT_MSBITS_20   ((__force snd_pcm_subformat_t) 2)
+#define        SNDRV_PCM_SUBFORMAT_MSBITS_24   ((__force snd_pcm_subformat_t) 3)
+#define        SNDRV_PCM_SUBFORMAT_LAST        SNDRV_PCM_SUBFORMAT_MSBITS_24
 
 #define SNDRV_PCM_INFO_MMAP            0x00000001      /* hardware supports mmap */
 #define SNDRV_PCM_INFO_MMAP_VALID      0x00000002      /* period data are valid during transfer */
index 20bb2d7c8d4bf6cde42153cdbb7a16a0cd2bbb75..c4bc15f048b69fb933333568dddb7b86bf9ad4d5 100644 (file)
@@ -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[] = {
index f610b08f5a2bb525617a9aa1491e47e703b4a78e..f5ff00f99788a80135e2832f0cdb64650e3122d7 100644 (file)
@@ -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;
 
index f9939da4112272d43b674d99de3e6f56793e014b..d5b9cfbd9ceac69323d0fe487cc49ab388a2e523 100644 (file)
@@ -142,7 +142,7 @@ struct snd_hwdep_dsp_image {
  *                                                                           *
  *****************************************************************************/
 
-#define SNDRV_PCM_VERSION              SNDRV_PROTOCOL_VERSION(2, 0, 15)
+#define SNDRV_PCM_VERSION              SNDRV_PROTOCOL_VERSION(2, 0, 16)
 
 typedef unsigned long snd_pcm_uframes_t;
 typedef signed long snd_pcm_sframes_t;
@@ -267,7 +267,10 @@ typedef int __bitwise snd_pcm_format_t;
 
 typedef int __bitwise snd_pcm_subformat_t;
 #define        SNDRV_PCM_SUBFORMAT_STD         ((__force snd_pcm_subformat_t) 0)
-#define        SNDRV_PCM_SUBFORMAT_LAST        SNDRV_PCM_SUBFORMAT_STD
+#define        SNDRV_PCM_SUBFORMAT_MSBITS_MAX  ((__force snd_pcm_subformat_t) 1)
+#define        SNDRV_PCM_SUBFORMAT_MSBITS_20   ((__force snd_pcm_subformat_t) 2)
+#define        SNDRV_PCM_SUBFORMAT_MSBITS_24   ((__force snd_pcm_subformat_t) 3)
+#define        SNDRV_PCM_SUBFORMAT_LAST        SNDRV_PCM_SUBFORMAT_MSBITS_24
 
 #define SNDRV_PCM_INFO_MMAP            0x00000001      /* hardware supports mmap */
 #define SNDRV_PCM_INFO_MMAP_VALID      0x00000002      /* period data are valid during transfer */
This page took 0.078842 seconds and 4 git commands to generate.