static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm,
struct snd_pcm_hw_params *params,
snd_pcm_hw_param_t var, unsigned int best,
int *dir)
{
struct snd_pcm_hw_params *save = NULL;
int v;
unsigned int saved_min;
int last = 0;
int min, max;
int mindir, maxdir;
int valdir = dir ? *dir : 0;
// 调用函数为:choose_rate,所以dir=NULL,所以valdir将等于0
// 下面以var等于SNDRV_PCM_HW_PARAM_RATE
// best等于8000为例
/* FIXME */
if (best > INT_MAX)
best = INT_MAX;
min = max = best;
mindir = maxdir = valdir; // 将等于0,所以查找的是值为best的integer整型值[luther.gliethttp]
if (maxdir > 0)
maxdir = 0;
else if (maxdir == 0)
maxdir = -1;
else {
maxdir = 1;
max--;
}
save = kmalloc(sizeof(*save), GFP_KERNEL);
if (save == NULL)
return -ENOMEM;
*save = *params; // 和choose_rate中一样,预存*params到save,如果下面对params设置失败,那么
saved_min = min; // 将save中的数据回滚到params,以恢复params[luther.gliethttp].
// 尝试将params中var量的最小值i->min设置为min, 如果想设置成功,就必须保证i->min小于min,
// 这样才能有进一步缩小i->min数值的硬性条件,该操作没有与i->max进行任何关联,所以
// min大于i->min的情况下,甚至可以大于i->max[luther.gliethttp]
min = snd_pcm_hw_param_min(pcm, params, var, min, &mindir);
if (min >= 0) {
struct snd_pcm_hw_params *params1;
if (max < 0)
goto _end;
if ((unsigned int)min == saved_min && mindir == valdir)
goto _end; // 如果成功设置了i->min为saved_min,那么太好了[luther.gliethttp]
params1 = kmalloc(sizeof(*params1), GFP_KERNEL);
if (params1 == NULL) {
kfree(save);
return -ENOMEM;
}
*params1 = *save; // 这里将save内存拷贝一份到params1,对params1进行参数修改,如果成功,那么
// *params = *params1;对params彻底赋值,一切顺利[luther.gliethttp]
// 和上面的i->min进一步缩小一样,
// i->max必须max才能设置成功,这样才能进一步缩小i->max的数值到max[luther.gliethttp]
max = snd_pcm_hw_param_max(pcm, params1, var, max, &maxdir);
if (max < 0) {
kfree(params1);
goto _end;
}
// 好,执行到这里说明i->max也进一步缩小成功
// boundary_nearer Return 1 if min is nearer to best than max
// 函数用来计算究竟best - min小还是max - best小,
// 即:best这个数值更靠近min端还是max端
// 返回1表示best更靠近min端[luther.gliethttp]
if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) {
*params = *params1;
last = 1;
}
kfree(params1);
} else {
// 执行到这里说明i->min大于min
// 和上面的i->min进一步缩小一样,
// i->max必须max才能设置成功,这样才能进一步缩小i->max的数值到max[luther.gliethttp]
*params = *save;
max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir);
if (max < 0)
return max;
// 好了最能匹配上的数值位于i->max那端[luther.gliethttp]
last = 1;
}
_end:
kfree(save);
// 调用snd_pcm_hw_refine执行一次配置更新
《浅析alsa声卡驱动snd_pcm_hw_refine函数》 if (last) // snd_pcm_hw_param_last - refine config space and return maximum value
v = snd_pcm_hw_param_last(pcm, params, var, dir); // last等于1表示更靠近max,所以返回max
else // snd_pcm_hw_param_first - refine config space and return minimum value
v = snd_pcm_hw_param_first(pcm, params, var, dir);
snd_BUG_ON(v < 0);
return v;
}