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

ALSA: iec958: Split status creation and fill

In some situations, like a codec probe, we need to provide an IEC status
default but don't have access to the sampling rate and width yet since
no stream has been configured yet.

Each and every driver has its own default, whereas the core iec958 code
also has some buried in the snd_pcm_create_iec958_consumer functions.

Let's split these functions in two to provide a default that doesn't
rely on the sampling rate and width, and another function to fill them
when available.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Takashi Iwai <tiwai@suse.de>
Link: https://lore.kernel.org/r/20210525132354.297468-3-maxime@cerno.tech

+141 -43
+8
include/sound/pcm_iec958.h
··· 4 4 5 5 #include <linux/types.h> 6 6 7 + int snd_pcm_create_iec958_consumer_default(u8 *cs, size_t len); 8 + 9 + int snd_pcm_fill_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, 10 + size_t len); 11 + 12 + int snd_pcm_fill_iec958_consumer_hw_params(struct snd_pcm_hw_params *params, 13 + u8 *cs, size_t len); 14 + 7 15 int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, 8 16 size_t len); 9 17
+133 -43
sound/core/pcm_iec958.c
··· 9 9 #include <sound/pcm_params.h> 10 10 #include <sound/pcm_iec958.h> 11 11 12 - static int create_iec958_consumer(uint rate, uint sample_width, 13 - u8 *cs, size_t len) 12 + /** 13 + * snd_pcm_create_iec958_consumer_default - create default consumer format IEC958 channel status 14 + * @cs: channel status buffer, at least four bytes 15 + * @len: length of channel status buffer 16 + * 17 + * Create the consumer format channel status data in @cs of maximum size 18 + * @len. When relevant, the configuration-dependant bits will be set as 19 + * unspecified. 20 + * 21 + * Drivers should then call einter snd_pcm_fill_iec958_consumer() or 22 + * snd_pcm_fill_iec958_consumer_hw_params() to replace these unspecified 23 + * bits by their actual values. 24 + * 25 + * Drivers may wish to tweak the contents of the buffer after creation. 26 + * 27 + * Returns: length of buffer, or negative error code if something failed. 28 + */ 29 + int snd_pcm_create_iec958_consumer_default(u8 *cs, size_t len) 14 30 { 15 - unsigned int fs, ws; 16 - 17 31 if (len < 4) 18 32 return -EINVAL; 19 33 20 - switch (rate) { 21 - case 32000: 22 - fs = IEC958_AES3_CON_FS_32000; 23 - break; 24 - case 44100: 25 - fs = IEC958_AES3_CON_FS_44100; 26 - break; 27 - case 48000: 28 - fs = IEC958_AES3_CON_FS_48000; 29 - break; 30 - case 88200: 31 - fs = IEC958_AES3_CON_FS_88200; 32 - break; 33 - case 96000: 34 - fs = IEC958_AES3_CON_FS_96000; 35 - break; 36 - case 176400: 37 - fs = IEC958_AES3_CON_FS_176400; 38 - break; 39 - case 192000: 40 - fs = IEC958_AES3_CON_FS_192000; 41 - break; 42 - default: 34 + memset(cs, 0, len); 35 + 36 + cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE; 37 + cs[1] = IEC958_AES1_CON_GENERAL; 38 + cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC; 39 + cs[3] = IEC958_AES3_CON_CLOCK_1000PPM | IEC958_AES3_CON_FS_NOTID; 40 + 41 + if (len > 4) 42 + cs[4] = IEC958_AES4_CON_WORDLEN_NOTID; 43 + 44 + return len; 45 + } 46 + EXPORT_SYMBOL_GPL(snd_pcm_create_iec958_consumer_default); 47 + 48 + static int fill_iec958_consumer(uint rate, uint sample_width, 49 + u8 *cs, size_t len) 50 + { 51 + if (len < 4) 43 52 return -EINVAL; 53 + 54 + if ((cs[3] & IEC958_AES3_CON_FS) == IEC958_AES3_CON_FS_NOTID) { 55 + unsigned int fs; 56 + 57 + switch (rate) { 58 + case 32000: 59 + fs = IEC958_AES3_CON_FS_32000; 60 + break; 61 + case 44100: 62 + fs = IEC958_AES3_CON_FS_44100; 63 + break; 64 + case 48000: 65 + fs = IEC958_AES3_CON_FS_48000; 66 + break; 67 + case 88200: 68 + fs = IEC958_AES3_CON_FS_88200; 69 + break; 70 + case 96000: 71 + fs = IEC958_AES3_CON_FS_96000; 72 + break; 73 + case 176400: 74 + fs = IEC958_AES3_CON_FS_176400; 75 + break; 76 + case 192000: 77 + fs = IEC958_AES3_CON_FS_192000; 78 + break; 79 + default: 80 + return -EINVAL; 81 + } 82 + 83 + cs[3] &= ~IEC958_AES3_CON_FS; 84 + cs[3] |= fs; 44 85 } 45 86 46 - if (len > 4) { 87 + if (len > 4 && 88 + (cs[4] & IEC958_AES4_CON_WORDLEN) == IEC958_AES4_CON_WORDLEN_NOTID) { 89 + unsigned int ws; 90 + 47 91 switch (sample_width) { 48 92 case 16: 49 93 ws = IEC958_AES4_CON_WORDLEN_20_16; ··· 108 64 default: 109 65 return -EINVAL; 110 66 } 67 + 68 + cs[4] &= ~IEC958_AES4_CON_WORDLEN; 69 + cs[4] |= ws; 111 70 } 112 - 113 - memset(cs, 0, len); 114 - 115 - cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE; 116 - cs[1] = IEC958_AES1_CON_GENERAL; 117 - cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC; 118 - cs[3] = IEC958_AES3_CON_CLOCK_1000PPM | fs; 119 - 120 - if (len > 4) 121 - cs[4] = ws; 122 71 123 72 return len; 124 73 } 74 + 75 + /** 76 + * snd_pcm_fill_iec958_consumer - Fill consumer format IEC958 channel status 77 + * @runtime: pcm runtime structure with ->rate filled in 78 + * @cs: channel status buffer, at least four bytes 79 + * @len: length of channel status buffer 80 + * 81 + * Fill the unspecified bits in an IEC958 status bits array using the 82 + * parameters of the PCM runtime @runtime. 83 + * 84 + * Drivers may wish to tweak the contents of the buffer after its been 85 + * filled. 86 + * 87 + * Returns: length of buffer, or negative error code if something failed. 88 + */ 89 + int snd_pcm_fill_iec958_consumer(struct snd_pcm_runtime *runtime, 90 + u8 *cs, size_t len) 91 + { 92 + return fill_iec958_consumer(runtime->rate, 93 + snd_pcm_format_width(runtime->format), 94 + cs, len); 95 + } 96 + EXPORT_SYMBOL_GPL(snd_pcm_fill_iec958_consumer); 97 + 98 + /** 99 + * snd_pcm_fill_iec958_consumer_hw_params - Fill consumer format IEC958 channel status 100 + * @params: the hw_params instance for extracting rate and sample format 101 + * @cs: channel status buffer, at least four bytes 102 + * @len: length of channel status buffer 103 + * 104 + * Fill the unspecified bits in an IEC958 status bits array using the 105 + * parameters of the PCM hardware parameters @params. 106 + * 107 + * Drivers may wish to tweak the contents of the buffer after its been 108 + * filled.. 109 + * 110 + * Returns: length of buffer, or negative error code if something failed. 111 + */ 112 + int snd_pcm_fill_iec958_consumer_hw_params(struct snd_pcm_hw_params *params, 113 + u8 *cs, size_t len) 114 + { 115 + return fill_iec958_consumer(params_rate(params), params_width(params), cs, len); 116 + } 117 + EXPORT_SYMBOL_GPL(snd_pcm_fill_iec958_consumer_hw_params); 125 118 126 119 /** 127 120 * snd_pcm_create_iec958_consumer - create consumer format IEC958 channel status ··· 176 95 int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, 177 96 size_t len) 178 97 { 179 - return create_iec958_consumer(runtime->rate, 180 - snd_pcm_format_width(runtime->format), 181 - cs, len); 98 + int ret; 99 + 100 + ret = snd_pcm_create_iec958_consumer_default(cs, len); 101 + if (ret < 0) 102 + return ret; 103 + 104 + return snd_pcm_fill_iec958_consumer(runtime, cs, len); 182 105 } 183 106 EXPORT_SYMBOL(snd_pcm_create_iec958_consumer); 184 107 ··· 202 117 int snd_pcm_create_iec958_consumer_hw_params(struct snd_pcm_hw_params *params, 203 118 u8 *cs, size_t len) 204 119 { 205 - return create_iec958_consumer(params_rate(params), params_width(params), 206 - cs, len); 120 + int ret; 121 + 122 + ret = snd_pcm_create_iec958_consumer_default(cs, len); 123 + if (ret < 0) 124 + return ret; 125 + 126 + return fill_iec958_consumer(params_rate(params), params_width(params), cs, len); 207 127 } 208 128 EXPORT_SYMBOL(snd_pcm_create_iec958_consumer_hw_params);