Commit 2112aa03 authored by Jaroslav Kysela's avatar Jaroslav Kysela Committed by Takashi Iwai
Browse files

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: default avatarMark Brown <broonie@kernel.org>
Signed-off-by: default avatarJaroslav Kysela <perex@perex.cz>
Co-developed-by: default avatarCezary Rojewski <cezary.rojewski@intel.com>
Signed-off-by: default avatarCezary Rojewski <cezary.rojewski@intel.com>
Link: https://lore.kernel.org/r/20231117120610.1755254-2-cezary.rojewski@intel.com


Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 26257869
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -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;
+5 −2
Original line number Diff line number Diff line
@@ -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 */
+3 −0
Original line number Diff line number Diff line
@@ -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[] = {
+53 −2
Original line number Diff line number Diff line
@@ -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;

+5 −2
Original line number Diff line number Diff line
@@ -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 */