ALSA: pcm: Introduce MSBITS subformat interface
commit 2112aa034907c428785e1a5730927181276ee45b upstream. 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 <broonie@kernel.org> Signed-off-by: Jaroslav Kysela <perex@perex.cz> Co-developed-by: Cezary Rojewski <cezary.rojewski@intel.com> Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com> Link: https://lore.kernel.org/r/20231117120610.1755254-2-cezary.rojewski@intel.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
200d690f9c
commit
b3cf9bddf3
|
@ -31,6 +31,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 */
|
||||
|
@ -219,6 +220,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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -266,6 +266,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[] = {
|
||||
|
|
|
@ -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)) {
|
||||
|
@ -2481,6 +2498,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;
|
||||
|
@ -2632,8 +2684,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;
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue