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

ALSA: firewire-lib: add PCM rules to obsolete PCM constraints based on LCM of SYT_INTERVAL

In blocking mode of IEC 61883-1/6, when one isochronous packet includes
data for events, the data is for the same number of events as
SYT_INTERVAL decided according to sampling transmission frequency (SFC).

IEC 61883-1/6 engine of ALSA firewire stack applies constraints of
period and buffer size of PCM intermediate buffer of PCM substream.
At present, this constraint is designed to round the size up/down to
32 frames. This value comes from the least common multiple (LCM) of
SYT_INTERVAL. Although this looks to work well, in lower sampling
rate, applications are not allowed to set size of period quite near
period time constraint (at present 5 msec per period).

This commit adds PCM rules for period/buffer size and rate to obsoletes
the constraints based on LCM.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>

authored by

Takashi Sakamoto and committed by
Takashi Iwai
59502295 96395e86

+71 -7
+71 -7
sound/firewire/amdtp-stream.c
··· 140 140 }; 141 141 EXPORT_SYMBOL(amdtp_rate_table); 142 142 143 + static int apply_constraint_to_size(struct snd_pcm_hw_params *params, 144 + struct snd_pcm_hw_rule *rule) 145 + { 146 + struct snd_interval *s = hw_param_interval(params, rule->var); 147 + const struct snd_interval *r = 148 + hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); 149 + struct snd_interval t = { 150 + .min = s->min, .max = s->max, .integer = 1, 151 + }; 152 + int i; 153 + 154 + for (i = 0; i < CIP_SFC_COUNT; ++i) { 155 + unsigned int rate = amdtp_rate_table[i]; 156 + unsigned int step = amdtp_syt_intervals[i]; 157 + 158 + if (!snd_interval_test(r, rate)) 159 + continue; 160 + 161 + t.min = roundup(t.min, step); 162 + t.max = rounddown(t.max, step); 163 + } 164 + 165 + if (snd_interval_checkempty(&t)) 166 + return -EINVAL; 167 + 168 + return snd_interval_refine(s, &t); 169 + } 170 + 171 + static int apply_constraint_to_rate(struct snd_pcm_hw_params *params, 172 + struct snd_pcm_hw_rule *rule) 173 + { 174 + struct snd_interval *r = 175 + hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 176 + const struct snd_interval *s = hw_param_interval_c(params, rule->deps[0]); 177 + struct snd_interval t = { 178 + .min = UINT_MAX, .max = 0, .integer = 1, 179 + }; 180 + int i; 181 + 182 + for (i = 0; i < CIP_SFC_COUNT; ++i) { 183 + unsigned int step = amdtp_syt_intervals[i]; 184 + unsigned int rate = amdtp_rate_table[i]; 185 + 186 + if (s->min % step || s->max % step) 187 + continue; 188 + 189 + t.min = min(t.min, rate); 190 + t.max = max(t.max, rate); 191 + } 192 + 193 + return snd_interval_refine(r, &t); 194 + } 195 + 143 196 /** 144 197 * amdtp_stream_add_pcm_hw_constraints - add hw constraints for PCM substream 145 198 * @s: the AMDTP stream, which must be initialized. ··· 247 194 * number equals to SYT_INTERVAL. So the number is 8, 16 or 32, 248 195 * depending on its sampling rate. For accurate period interrupt, it's 249 196 * preferrable to align period/buffer sizes to current SYT_INTERVAL. 250 - * 251 - * TODO: These constraints can be improved with proper rules. 252 - * Currently apply LCM of SYT_INTERVALs. 253 197 */ 254 - err = snd_pcm_hw_constraint_step(runtime, 0, 255 - SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 32); 198 + err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 199 + apply_constraint_to_size, NULL, 200 + SNDRV_PCM_HW_PARAM_RATE, -1); 256 201 if (err < 0) 257 202 goto end; 258 - err = snd_pcm_hw_constraint_step(runtime, 0, 259 - SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 32); 203 + err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 204 + apply_constraint_to_rate, NULL, 205 + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1); 206 + if (err < 0) 207 + goto end; 208 + err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 209 + apply_constraint_to_size, NULL, 210 + SNDRV_PCM_HW_PARAM_RATE, -1); 211 + if (err < 0) 212 + goto end; 213 + err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 214 + apply_constraint_to_rate, NULL, 215 + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1); 216 + if (err < 0) 217 + goto end; 260 218 end: 261 219 return err; 262 220 }