Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Cezary Rojewski and committed by
Takashi Iwai
d24f1a09 4a6ba09e

+165
+5
include/sound/hdaudio.h
··· 140 140 hda_nid_t *conn_list, int max_conns); 141 141 int snd_hdac_get_sub_nodes(struct hdac_device *codec, hda_nid_t nid, 142 142 hda_nid_t *start_id); 143 + unsigned int snd_hdac_stream_format_bits(snd_pcm_format_t format, snd_pcm_subformat_t subformat, 144 + unsigned int maxbits); 145 + unsigned int snd_hdac_stream_format(unsigned int channels, unsigned int bits, unsigned int rate); 146 + unsigned int snd_hdac_spdif_stream_format(unsigned int channels, unsigned int bits, 147 + unsigned int rate, unsigned short spdif_ctls); 143 148 unsigned int snd_hdac_calc_stream_format(unsigned int rate, 144 149 unsigned int channels, 145 150 snd_pcm_format_t format,
+2
include/sound/pcm_params.h
··· 362 362 return snd_pcm_format_physical_width(params_format(p)); 363 363 } 364 364 365 + int snd_pcm_hw_params_bits(const struct snd_pcm_hw_params *p); 366 + 365 367 static inline void 366 368 params_set_format(struct snd_pcm_hw_params *p, snd_pcm_format_t fmt) 367 369 {
+34
sound/core/pcm_lib.c
··· 1706 1706 } 1707 1707 EXPORT_SYMBOL(snd_pcm_hw_param_last); 1708 1708 1709 + /** 1710 + * snd_pcm_hw_params_bits - Get the number of bits per the sample. 1711 + * @p: hardware parameters 1712 + * 1713 + * Return: The number of bits per sample based on the format, 1714 + * subformat and msbits the specified hw params has. 1715 + */ 1716 + int snd_pcm_hw_params_bits(const struct snd_pcm_hw_params *p) 1717 + { 1718 + snd_pcm_subformat_t subformat = params_subformat(p); 1719 + snd_pcm_format_t format = params_format(p); 1720 + 1721 + switch (format) { 1722 + case SNDRV_PCM_FORMAT_S32_LE: 1723 + case SNDRV_PCM_FORMAT_U32_LE: 1724 + case SNDRV_PCM_FORMAT_S32_BE: 1725 + case SNDRV_PCM_FORMAT_U32_BE: 1726 + switch (subformat) { 1727 + case SNDRV_PCM_SUBFORMAT_MSBITS_20: 1728 + return 20; 1729 + case SNDRV_PCM_SUBFORMAT_MSBITS_24: 1730 + return 24; 1731 + case SNDRV_PCM_SUBFORMAT_MSBITS_MAX: 1732 + case SNDRV_PCM_SUBFORMAT_STD: 1733 + default: 1734 + break; 1735 + } 1736 + fallthrough; 1737 + default: 1738 + return snd_pcm_format_width(format); 1739 + } 1740 + } 1741 + EXPORT_SYMBOL(snd_pcm_hw_params_bits); 1742 + 1709 1743 static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream, 1710 1744 void *arg) 1711 1745 {
+124
sound/hda/hdac_device.c
··· 13 13 #include <sound/hdaudio.h> 14 14 #include <sound/hda_regmap.h> 15 15 #include <sound/pcm.h> 16 + #include <sound/pcm_params.h> 16 17 #include "local.h" 17 18 18 19 static void setup_fg_nodes(struct hdac_device *codec); ··· 725 724 726 725 { 0 } /* terminator */ 727 726 }; 727 + 728 + static snd_pcm_format_t snd_hdac_format_normalize(snd_pcm_format_t format) 729 + { 730 + switch (format) { 731 + case SNDRV_PCM_FORMAT_S20_LE: 732 + case SNDRV_PCM_FORMAT_S24_LE: 733 + return SNDRV_PCM_FORMAT_S32_LE; 734 + 735 + case SNDRV_PCM_FORMAT_U20_LE: 736 + case SNDRV_PCM_FORMAT_U24_LE: 737 + return SNDRV_PCM_FORMAT_U32_LE; 738 + 739 + case SNDRV_PCM_FORMAT_S20_BE: 740 + case SNDRV_PCM_FORMAT_S24_BE: 741 + return SNDRV_PCM_FORMAT_S32_BE; 742 + 743 + case SNDRV_PCM_FORMAT_U20_BE: 744 + case SNDRV_PCM_FORMAT_U24_BE: 745 + return SNDRV_PCM_FORMAT_U32_BE; 746 + 747 + default: 748 + return format; 749 + } 750 + } 751 + 752 + /** 753 + * snd_hdac_stream_format_bits - obtain bits per sample value. 754 + * @format: the PCM format. 755 + * @subformat: the PCM subformat. 756 + * @maxbits: the maximum bits per sample. 757 + * 758 + * Return: The number of bits per sample. 759 + */ 760 + unsigned int snd_hdac_stream_format_bits(snd_pcm_format_t format, snd_pcm_subformat_t subformat, 761 + unsigned int maxbits) 762 + { 763 + struct snd_pcm_hw_params params; 764 + unsigned int bits; 765 + 766 + memset(&params, 0, sizeof(params)); 767 + 768 + params_set_format(&params, snd_hdac_format_normalize(format)); 769 + snd_mask_set(hw_param_mask(&params, SNDRV_PCM_HW_PARAM_SUBFORMAT), 770 + (__force unsigned int)subformat); 771 + 772 + bits = snd_pcm_hw_params_bits(&params); 773 + if (maxbits) 774 + return min(bits, maxbits); 775 + return bits; 776 + } 777 + EXPORT_SYMBOL_GPL(snd_hdac_stream_format_bits); 778 + 779 + /** 780 + * snd_hdac_stream_format - convert format parameters to SDxFMT value. 781 + * @channels: the number of channels. 782 + * @bits: bits per sample. 783 + * @rate: the sample rate. 784 + * 785 + * Return: The format bitset or zero if invalid. 786 + */ 787 + unsigned int snd_hdac_stream_format(unsigned int channels, unsigned int bits, unsigned int rate) 788 + { 789 + unsigned int val = 0; 790 + int i; 791 + 792 + for (i = 0; rate_bits[i].hz; i++) { 793 + if (rate_bits[i].hz == rate) { 794 + val = rate_bits[i].hda_fmt; 795 + break; 796 + } 797 + } 798 + 799 + if (!rate_bits[i].hz) 800 + return 0; 801 + 802 + if (channels == 0 || channels > 8) 803 + return 0; 804 + val |= channels - 1; 805 + 806 + switch (bits) { 807 + case 8: 808 + val |= AC_FMT_BITS_8; 809 + break; 810 + case 16: 811 + val |= AC_FMT_BITS_16; 812 + break; 813 + case 20: 814 + val |= AC_FMT_BITS_20; 815 + break; 816 + case 24: 817 + val |= AC_FMT_BITS_24; 818 + break; 819 + case 32: 820 + val |= AC_FMT_BITS_32; 821 + break; 822 + default: 823 + return 0; 824 + } 825 + 826 + return val; 827 + } 828 + EXPORT_SYMBOL_GPL(snd_hdac_stream_format); 829 + 830 + /** 831 + * snd_hdac_spdif_stream_format - convert format parameters to SDxFMT value. 832 + * @channels: the number of channels. 833 + * @bits: bits per sample. 834 + * @rate: the sample rate. 835 + * @spdif_ctls: HD-audio SPDIF status bits (0 if irrelevant). 836 + * 837 + * Return: The format bitset or zero if invalid. 838 + */ 839 + unsigned int snd_hdac_spdif_stream_format(unsigned int channels, unsigned int bits, 840 + unsigned int rate, unsigned short spdif_ctls) 841 + { 842 + unsigned int val = snd_hdac_stream_format(channels, bits, rate); 843 + 844 + if (val && spdif_ctls & AC_DIG1_NONAUDIO) 845 + val |= AC_FMT_TYPE_NON_PCM; 846 + 847 + return val; 848 + } 849 + EXPORT_SYMBOL_GPL(snd_hdac_spdif_stream_format); 728 850 729 851 /** 730 852 * snd_hdac_calc_stream_format - calculate the format bitset