162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
262306a36Sopenharmony_ci#ifndef __SOUND_PCM_PARAMS_H
362306a36Sopenharmony_ci#define __SOUND_PCM_PARAMS_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci/*
662306a36Sopenharmony_ci *  PCM params helpers
762306a36Sopenharmony_ci *  Copyright (c) by Abramo Bagnara <abramo@alsa-project.org>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <sound/pcm.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ciint snd_pcm_hw_param_first(struct snd_pcm_substream *pcm,
1362306a36Sopenharmony_ci			   struct snd_pcm_hw_params *params,
1462306a36Sopenharmony_ci			   snd_pcm_hw_param_t var, int *dir);
1562306a36Sopenharmony_ciint snd_pcm_hw_param_last(struct snd_pcm_substream *pcm,
1662306a36Sopenharmony_ci			  struct snd_pcm_hw_params *params,
1762306a36Sopenharmony_ci			  snd_pcm_hw_param_t var, int *dir);
1862306a36Sopenharmony_ciint snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params,
1962306a36Sopenharmony_ci			   snd_pcm_hw_param_t var, int *dir);
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define SNDRV_MASK_BITS	64	/* we use so far 64bits only */
2262306a36Sopenharmony_ci#define SNDRV_MASK_SIZE	(SNDRV_MASK_BITS / 32)
2362306a36Sopenharmony_ci#define MASK_OFS(i)	((i) >> 5)
2462306a36Sopenharmony_ci#define MASK_BIT(i)	(1U << ((i) & 31))
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic inline void snd_mask_none(struct snd_mask *mask)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	memset(mask, 0, sizeof(*mask));
2962306a36Sopenharmony_ci}
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic inline void snd_mask_any(struct snd_mask *mask)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	memset(mask, 0xff, SNDRV_MASK_SIZE * sizeof(u_int32_t));
3462306a36Sopenharmony_ci}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic inline int snd_mask_empty(const struct snd_mask *mask)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	int i;
3962306a36Sopenharmony_ci	for (i = 0; i < SNDRV_MASK_SIZE; i++)
4062306a36Sopenharmony_ci		if (mask->bits[i])
4162306a36Sopenharmony_ci			return 0;
4262306a36Sopenharmony_ci	return 1;
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic inline unsigned int snd_mask_min(const struct snd_mask *mask)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	int i;
4862306a36Sopenharmony_ci	for (i = 0; i < SNDRV_MASK_SIZE; i++) {
4962306a36Sopenharmony_ci		if (mask->bits[i])
5062306a36Sopenharmony_ci			return __ffs(mask->bits[i]) + (i << 5);
5162306a36Sopenharmony_ci	}
5262306a36Sopenharmony_ci	return 0;
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic inline unsigned int snd_mask_max(const struct snd_mask *mask)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	int i;
5862306a36Sopenharmony_ci	for (i = SNDRV_MASK_SIZE - 1; i >= 0; i--) {
5962306a36Sopenharmony_ci		if (mask->bits[i])
6062306a36Sopenharmony_ci			return __fls(mask->bits[i]) + (i << 5);
6162306a36Sopenharmony_ci	}
6262306a36Sopenharmony_ci	return 0;
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic inline void snd_mask_set(struct snd_mask *mask, unsigned int val)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	mask->bits[MASK_OFS(val)] |= MASK_BIT(val);
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci/* Most of drivers need only this one */
7162306a36Sopenharmony_cistatic inline void snd_mask_set_format(struct snd_mask *mask,
7262306a36Sopenharmony_ci				       snd_pcm_format_t format)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	snd_mask_set(mask, (__force unsigned int)format);
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic inline void snd_mask_reset(struct snd_mask *mask, unsigned int val)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	mask->bits[MASK_OFS(val)] &= ~MASK_BIT(val);
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic inline void snd_mask_set_range(struct snd_mask *mask,
8362306a36Sopenharmony_ci				      unsigned int from, unsigned int to)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	unsigned int i;
8662306a36Sopenharmony_ci	for (i = from; i <= to; i++)
8762306a36Sopenharmony_ci		mask->bits[MASK_OFS(i)] |= MASK_BIT(i);
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic inline void snd_mask_reset_range(struct snd_mask *mask,
9162306a36Sopenharmony_ci					unsigned int from, unsigned int to)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	unsigned int i;
9462306a36Sopenharmony_ci	for (i = from; i <= to; i++)
9562306a36Sopenharmony_ci		mask->bits[MASK_OFS(i)] &= ~MASK_BIT(i);
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistatic inline void snd_mask_leave(struct snd_mask *mask, unsigned int val)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	unsigned int v;
10162306a36Sopenharmony_ci	v = mask->bits[MASK_OFS(val)] & MASK_BIT(val);
10262306a36Sopenharmony_ci	snd_mask_none(mask);
10362306a36Sopenharmony_ci	mask->bits[MASK_OFS(val)] = v;
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic inline void snd_mask_intersect(struct snd_mask *mask,
10762306a36Sopenharmony_ci				      const struct snd_mask *v)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	int i;
11062306a36Sopenharmony_ci	for (i = 0; i < SNDRV_MASK_SIZE; i++)
11162306a36Sopenharmony_ci		mask->bits[i] &= v->bits[i];
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic inline int snd_mask_eq(const struct snd_mask *mask,
11562306a36Sopenharmony_ci			      const struct snd_mask *v)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	return ! memcmp(mask, v, SNDRV_MASK_SIZE * sizeof(u_int32_t));
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic inline void snd_mask_copy(struct snd_mask *mask,
12162306a36Sopenharmony_ci				 const struct snd_mask *v)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	*mask = *v;
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistatic inline int snd_mask_test(const struct snd_mask *mask, unsigned int val)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	return mask->bits[MASK_OFS(val)] & MASK_BIT(val);
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci/* Most of drivers need only this one */
13262306a36Sopenharmony_cistatic inline int snd_mask_test_format(const struct snd_mask *mask,
13362306a36Sopenharmony_ci				       snd_pcm_format_t format)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	return snd_mask_test(mask, (__force unsigned int)format);
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_cistatic inline int snd_mask_single(const struct snd_mask *mask)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	int i, c = 0;
14162306a36Sopenharmony_ci	for (i = 0; i < SNDRV_MASK_SIZE; i++) {
14262306a36Sopenharmony_ci		if (! mask->bits[i])
14362306a36Sopenharmony_ci			continue;
14462306a36Sopenharmony_ci		if (mask->bits[i] & (mask->bits[i] - 1))
14562306a36Sopenharmony_ci			return 0;
14662306a36Sopenharmony_ci		if (c)
14762306a36Sopenharmony_ci			return 0;
14862306a36Sopenharmony_ci		c++;
14962306a36Sopenharmony_ci	}
15062306a36Sopenharmony_ci	return 1;
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_cistatic inline int snd_mask_refine(struct snd_mask *mask,
15462306a36Sopenharmony_ci				  const struct snd_mask *v)
15562306a36Sopenharmony_ci{
15662306a36Sopenharmony_ci	struct snd_mask old;
15762306a36Sopenharmony_ci	snd_mask_copy(&old, mask);
15862306a36Sopenharmony_ci	snd_mask_intersect(mask, v);
15962306a36Sopenharmony_ci	if (snd_mask_empty(mask))
16062306a36Sopenharmony_ci		return -EINVAL;
16162306a36Sopenharmony_ci	return !snd_mask_eq(mask, &old);
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_cistatic inline int snd_mask_refine_first(struct snd_mask *mask)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	if (snd_mask_single(mask))
16762306a36Sopenharmony_ci		return 0;
16862306a36Sopenharmony_ci	snd_mask_leave(mask, snd_mask_min(mask));
16962306a36Sopenharmony_ci	return 1;
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_cistatic inline int snd_mask_refine_last(struct snd_mask *mask)
17362306a36Sopenharmony_ci{
17462306a36Sopenharmony_ci	if (snd_mask_single(mask))
17562306a36Sopenharmony_ci		return 0;
17662306a36Sopenharmony_ci	snd_mask_leave(mask, snd_mask_max(mask));
17762306a36Sopenharmony_ci	return 1;
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistatic inline int snd_mask_refine_min(struct snd_mask *mask, unsigned int val)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	if (snd_mask_min(mask) >= val)
18362306a36Sopenharmony_ci		return 0;
18462306a36Sopenharmony_ci	snd_mask_reset_range(mask, 0, val - 1);
18562306a36Sopenharmony_ci	if (snd_mask_empty(mask))
18662306a36Sopenharmony_ci		return -EINVAL;
18762306a36Sopenharmony_ci	return 1;
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic inline int snd_mask_refine_max(struct snd_mask *mask, unsigned int val)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	if (snd_mask_max(mask) <= val)
19362306a36Sopenharmony_ci		return 0;
19462306a36Sopenharmony_ci	snd_mask_reset_range(mask, val + 1, SNDRV_MASK_BITS);
19562306a36Sopenharmony_ci	if (snd_mask_empty(mask))
19662306a36Sopenharmony_ci		return -EINVAL;
19762306a36Sopenharmony_ci	return 1;
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic inline int snd_mask_refine_set(struct snd_mask *mask, unsigned int val)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	int changed;
20362306a36Sopenharmony_ci	changed = !snd_mask_single(mask);
20462306a36Sopenharmony_ci	snd_mask_leave(mask, val);
20562306a36Sopenharmony_ci	if (snd_mask_empty(mask))
20662306a36Sopenharmony_ci		return -EINVAL;
20762306a36Sopenharmony_ci	return changed;
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistatic inline int snd_mask_value(const struct snd_mask *mask)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	return snd_mask_min(mask);
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cistatic inline void snd_interval_any(struct snd_interval *i)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	i->min = 0;
21862306a36Sopenharmony_ci	i->openmin = 0;
21962306a36Sopenharmony_ci	i->max = UINT_MAX;
22062306a36Sopenharmony_ci	i->openmax = 0;
22162306a36Sopenharmony_ci	i->integer = 0;
22262306a36Sopenharmony_ci	i->empty = 0;
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic inline void snd_interval_none(struct snd_interval *i)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	i->empty = 1;
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic inline int snd_interval_checkempty(const struct snd_interval *i)
23162306a36Sopenharmony_ci{
23262306a36Sopenharmony_ci	return (i->min > i->max ||
23362306a36Sopenharmony_ci		(i->min == i->max && (i->openmin || i->openmax)));
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistatic inline int snd_interval_empty(const struct snd_interval *i)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	return i->empty;
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic inline int snd_interval_single(const struct snd_interval *i)
24262306a36Sopenharmony_ci{
24362306a36Sopenharmony_ci	return (i->min == i->max ||
24462306a36Sopenharmony_ci		(i->min + 1 == i->max && (i->openmin || i->openmax)));
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cistatic inline int snd_interval_value(const struct snd_interval *i)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	if (i->openmin && !i->openmax)
25062306a36Sopenharmony_ci		return i->max;
25162306a36Sopenharmony_ci	return i->min;
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic inline int snd_interval_min(const struct snd_interval *i)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	return i->min;
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_cistatic inline int snd_interval_max(const struct snd_interval *i)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	unsigned int v;
26262306a36Sopenharmony_ci	v = i->max;
26362306a36Sopenharmony_ci	if (i->openmax)
26462306a36Sopenharmony_ci		v--;
26562306a36Sopenharmony_ci	return v;
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_cistatic inline int snd_interval_test(const struct snd_interval *i, unsigned int val)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	return !((i->min > val || (i->min == val && i->openmin) ||
27162306a36Sopenharmony_ci		  i->max < val || (i->max == val && i->openmax)));
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_cistatic inline void snd_interval_copy(struct snd_interval *d, const struct snd_interval *s)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	*d = *s;
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cistatic inline int snd_interval_setinteger(struct snd_interval *i)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	if (i->integer)
28262306a36Sopenharmony_ci		return 0;
28362306a36Sopenharmony_ci	if (i->openmin && i->openmax && i->min == i->max)
28462306a36Sopenharmony_ci		return -EINVAL;
28562306a36Sopenharmony_ci	i->integer = 1;
28662306a36Sopenharmony_ci	return 1;
28762306a36Sopenharmony_ci}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_cistatic inline int snd_interval_eq(const struct snd_interval *i1, const struct snd_interval *i2)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	if (i1->empty)
29262306a36Sopenharmony_ci		return i2->empty;
29362306a36Sopenharmony_ci	if (i2->empty)
29462306a36Sopenharmony_ci		return i1->empty;
29562306a36Sopenharmony_ci	return i1->min == i2->min && i1->openmin == i2->openmin &&
29662306a36Sopenharmony_ci		i1->max == i2->max && i1->openmax == i2->openmax;
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci/**
30062306a36Sopenharmony_ci * params_access - get the access type from the hw params
30162306a36Sopenharmony_ci * @p: hw params
30262306a36Sopenharmony_ci */
30362306a36Sopenharmony_cistatic inline snd_pcm_access_t params_access(const struct snd_pcm_hw_params *p)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	return (__force snd_pcm_access_t)snd_mask_min(hw_param_mask_c(p,
30662306a36Sopenharmony_ci		SNDRV_PCM_HW_PARAM_ACCESS));
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci/**
31062306a36Sopenharmony_ci * params_format - get the sample format from the hw params
31162306a36Sopenharmony_ci * @p: hw params
31262306a36Sopenharmony_ci */
31362306a36Sopenharmony_cistatic inline snd_pcm_format_t params_format(const struct snd_pcm_hw_params *p)
31462306a36Sopenharmony_ci{
31562306a36Sopenharmony_ci	return (__force snd_pcm_format_t)snd_mask_min(hw_param_mask_c(p,
31662306a36Sopenharmony_ci		SNDRV_PCM_HW_PARAM_FORMAT));
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci/**
32062306a36Sopenharmony_ci * params_subformat - get the sample subformat from the hw params
32162306a36Sopenharmony_ci * @p: hw params
32262306a36Sopenharmony_ci */
32362306a36Sopenharmony_cistatic inline snd_pcm_subformat_t
32462306a36Sopenharmony_ciparams_subformat(const struct snd_pcm_hw_params *p)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	return (__force snd_pcm_subformat_t)snd_mask_min(hw_param_mask_c(p,
32762306a36Sopenharmony_ci		SNDRV_PCM_HW_PARAM_SUBFORMAT));
32862306a36Sopenharmony_ci}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci/**
33162306a36Sopenharmony_ci * params_period_bytes - get the period size (in bytes) from the hw params
33262306a36Sopenharmony_ci * @p: hw params
33362306a36Sopenharmony_ci */
33462306a36Sopenharmony_cistatic inline unsigned int
33562306a36Sopenharmony_ciparams_period_bytes(const struct snd_pcm_hw_params *p)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	return hw_param_interval_c(p, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)->min;
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci/**
34162306a36Sopenharmony_ci * params_width - get the number of bits of the sample format from the hw params
34262306a36Sopenharmony_ci * @p: hw params
34362306a36Sopenharmony_ci *
34462306a36Sopenharmony_ci * This function returns the number of bits per sample that the selected sample
34562306a36Sopenharmony_ci * format of the hw params has.
34662306a36Sopenharmony_ci */
34762306a36Sopenharmony_cistatic inline int params_width(const struct snd_pcm_hw_params *p)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	return snd_pcm_format_width(params_format(p));
35062306a36Sopenharmony_ci}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci/*
35362306a36Sopenharmony_ci * params_physical_width - get the storage size of the sample format from the hw params
35462306a36Sopenharmony_ci * @p: hw params
35562306a36Sopenharmony_ci *
35662306a36Sopenharmony_ci * This functions returns the number of bits per sample that the selected sample
35762306a36Sopenharmony_ci * format of the hw params takes up in memory. This will be equal or larger than
35862306a36Sopenharmony_ci * params_width().
35962306a36Sopenharmony_ci */
36062306a36Sopenharmony_cistatic inline int params_physical_width(const struct snd_pcm_hw_params *p)
36162306a36Sopenharmony_ci{
36262306a36Sopenharmony_ci	return snd_pcm_format_physical_width(params_format(p));
36362306a36Sopenharmony_ci}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_cistatic inline void
36662306a36Sopenharmony_ciparams_set_format(struct snd_pcm_hw_params *p, snd_pcm_format_t fmt)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	snd_mask_set_format(hw_param_mask(p, SNDRV_PCM_HW_PARAM_FORMAT), fmt);
36962306a36Sopenharmony_ci}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci#endif /* __SOUND_PCM_PARAMS_H */
372