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 <broonie@kernel.org> Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com> Acked-by: Jaroslav Kysela <perex@perex.cz> Link: https://lore.kernel.org/r/20231117120610.1755254-5-cezary.rojewski@intel.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
4a6ba09e89
commit
d24f1a090d
@ -140,6 +140,11 @@ int snd_hdac_get_connections(struct hdac_device *codec, hda_nid_t nid,
|
||||
hda_nid_t *conn_list, int max_conns);
|
||||
int snd_hdac_get_sub_nodes(struct hdac_device *codec, hda_nid_t nid,
|
||||
hda_nid_t *start_id);
|
||||
unsigned int snd_hdac_stream_format_bits(snd_pcm_format_t format, snd_pcm_subformat_t subformat,
|
||||
unsigned int maxbits);
|
||||
unsigned int snd_hdac_stream_format(unsigned int channels, unsigned int bits, unsigned int rate);
|
||||
unsigned int snd_hdac_spdif_stream_format(unsigned int channels, unsigned int bits,
|
||||
unsigned int rate, unsigned short spdif_ctls);
|
||||
unsigned int snd_hdac_calc_stream_format(unsigned int rate,
|
||||
unsigned int channels,
|
||||
snd_pcm_format_t format,
|
||||
|
@ -362,6 +362,8 @@ static inline int params_physical_width(const struct snd_pcm_hw_params *p)
|
||||
return snd_pcm_format_physical_width(params_format(p));
|
||||
}
|
||||
|
||||
int snd_pcm_hw_params_bits(const struct snd_pcm_hw_params *p);
|
||||
|
||||
static inline void
|
||||
params_set_format(struct snd_pcm_hw_params *p, snd_pcm_format_t fmt)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <sound/hdaudio.h>
|
||||
#include <sound/hda_regmap.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include "local.h"
|
||||
|
||||
static void setup_fg_nodes(struct hdac_device *codec);
|
||||
@ -725,6 +726,129 @@ static const struct hda_rate_tbl rate_bits[] = {
|
||||
{ 0 } /* terminator */
|
||||
};
|
||||
|
||||
static snd_pcm_format_t snd_hdac_format_normalize(snd_pcm_format_t format)
|
||||
{
|
||||
switch (format) {
|
||||
case SNDRV_PCM_FORMAT_S20_LE:
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
return SNDRV_PCM_FORMAT_S32_LE;
|
||||
|
||||
case SNDRV_PCM_FORMAT_U20_LE:
|
||||
case SNDRV_PCM_FORMAT_U24_LE:
|
||||
return SNDRV_PCM_FORMAT_U32_LE;
|
||||
|
||||
case SNDRV_PCM_FORMAT_S20_BE:
|
||||
case SNDRV_PCM_FORMAT_S24_BE:
|
||||
return SNDRV_PCM_FORMAT_S32_BE;
|
||||
|
||||
case SNDRV_PCM_FORMAT_U20_BE:
|
||||
case SNDRV_PCM_FORMAT_U24_BE:
|
||||
return SNDRV_PCM_FORMAT_U32_BE;
|
||||
|
||||
default:
|
||||
return format;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_hdac_stream_format_bits - obtain bits per sample value.
|
||||
* @format: the PCM format.
|
||||
* @subformat: the PCM subformat.
|
||||
* @maxbits: the maximum bits per sample.
|
||||
*
|
||||
* Return: The number of bits per sample.
|
||||
*/
|
||||
unsigned int snd_hdac_stream_format_bits(snd_pcm_format_t format, snd_pcm_subformat_t subformat,
|
||||
unsigned int maxbits)
|
||||
{
|
||||
struct snd_pcm_hw_params params;
|
||||
unsigned int bits;
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
|
||||
params_set_format(¶ms, snd_hdac_format_normalize(format));
|
||||
snd_mask_set(hw_param_mask(¶ms, SNDRV_PCM_HW_PARAM_SUBFORMAT),
|
||||
(__force unsigned int)subformat);
|
||||
|
||||
bits = snd_pcm_hw_params_bits(¶ms);
|
||||
if (maxbits)
|
||||
return min(bits, maxbits);
|
||||
return bits;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_stream_format_bits);
|
||||
|
||||
/**
|
||||
* snd_hdac_stream_format - convert format parameters to SDxFMT value.
|
||||
* @channels: the number of channels.
|
||||
* @bits: bits per sample.
|
||||
* @rate: the sample rate.
|
||||
*
|
||||
* Return: The format bitset or zero if invalid.
|
||||
*/
|
||||
unsigned int snd_hdac_stream_format(unsigned int channels, unsigned int bits, unsigned int rate)
|
||||
{
|
||||
unsigned int val = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; rate_bits[i].hz; i++) {
|
||||
if (rate_bits[i].hz == rate) {
|
||||
val = rate_bits[i].hda_fmt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!rate_bits[i].hz)
|
||||
return 0;
|
||||
|
||||
if (channels == 0 || channels > 8)
|
||||
return 0;
|
||||
val |= channels - 1;
|
||||
|
||||
switch (bits) {
|
||||
case 8:
|
||||
val |= AC_FMT_BITS_8;
|
||||
break;
|
||||
case 16:
|
||||
val |= AC_FMT_BITS_16;
|
||||
break;
|
||||
case 20:
|
||||
val |= AC_FMT_BITS_20;
|
||||
break;
|
||||
case 24:
|
||||
val |= AC_FMT_BITS_24;
|
||||
break;
|
||||
case 32:
|
||||
val |= AC_FMT_BITS_32;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_stream_format);
|
||||
|
||||
/**
|
||||
* snd_hdac_spdif_stream_format - convert format parameters to SDxFMT value.
|
||||
* @channels: the number of channels.
|
||||
* @bits: bits per sample.
|
||||
* @rate: the sample rate.
|
||||
* @spdif_ctls: HD-audio SPDIF status bits (0 if irrelevant).
|
||||
*
|
||||
* Return: The format bitset or zero if invalid.
|
||||
*/
|
||||
unsigned int snd_hdac_spdif_stream_format(unsigned int channels, unsigned int bits,
|
||||
unsigned int rate, unsigned short spdif_ctls)
|
||||
{
|
||||
unsigned int val = snd_hdac_stream_format(channels, bits, rate);
|
||||
|
||||
if (val && spdif_ctls & AC_DIG1_NONAUDIO)
|
||||
val |= AC_FMT_TYPE_NON_PCM;
|
||||
|
||||
return val;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_hdac_spdif_stream_format);
|
||||
|
||||
/**
|
||||
* snd_hdac_calc_stream_format - calculate the format bitset
|
||||
* @rate: the sample rate
|
||||
|
Loading…
Reference in New Issue
Block a user