【问题标题】:Passing params from alsa application to kernel driver将参数从 alsa 应用程序传递到内核驱动程序
【发布时间】:2019-10-12 13:21:23
【问题描述】:

我尝试按照从 linux 用户空间 (arecord/aplay) 到内核驱动程序的参数设置路径。我们以 arecords --period-size 为例。

一切都始于aplay.c中的set_params函数:

if (period_time > 0)
    err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, 0);
else
    err = snd_pcm_hw_params_set_period_size_near(handle, params, &period_frames, 0);

函数 snd_pcm_hw_params_set_period_size_near() 定义在 [pcm.c : 5186](alsa-lib https://github.com/alsa-project/alsa-lib/blob/master/src/pcm/pcm.c#L5186) 中,我的头疼开始了……这个函数启动了对其他函数的调用链对我来说很有意义,似乎并没有导致司机的任何结束。

_end 标签,所以我跳过了snd_pcm_hw_param_set_min()snd_pcm_hw_param_set_max() 之类的所有调用,然后转到snd_pcm_hw_param_set_last(),希望调用一些驱动程序,例如:

drv->hw_params_set(...);

但我找到了一个结束调用:

MASK_INLINE unsigned int snd_mask_min(const snd_mask_t *mask)
{
    int i;
    assert(!snd_mask_empty(mask));
    for (i = 0; i < MASK_SIZE; i++) {
        if (mask->bits[i])
            return ffs(mask->bits[i]) - 1 + (i << 5);
    }
    return 0;
}

其中返回值应为参数集。

总而言之,我发现 alsa-lib 很难阅读和理解。也许我缺乏一些知识。我的问题很简单,用户空间参数如何传递给内核驱动程序。能否提供一个显示接口的软件路径?

谢谢。

【问题讨论】:

    标签: linux kernel driver alsa


    【解决方案1】:

    hw_params 结构包含一个配置空间,它是对设备可以支持的所有可能配置的描述。数字参数被描述为间隔(即最小值和最大值),访问和格式为位掩码。

    当您更改一个参数时,库调用内核驱动程序 (SNDRV_PCM_IOCTL_HW_REFINE) 来调整 hw_params 结构中依赖于更改参数的所有其他参数。

    在您将配置空间缩小到您真正想要的配置后,您调用snd_pcm_hw_params() (→ SNDRV_PCM_IOCTL_HW_PARAMS) 为这些参数实际配置设备。 (如果某些参数没有被缩减为单个值,snd_pcm_hw_params() 会随机选择一个。)


    snd_pcm_hw_params_set_xxx_near() 更复杂,因为没有SET_NEAR ioctl。此函数尝试调整间隔,使其最大值或最小值为所需值,然后检查实际最大值或最小值是否更接近。

    例如,假设设备支持 1024、2048、4096 和 8192 帧的周期大小。最初,该区间被描述为 [1024, 8192]。当您调用 snd_pcm_hw_params_set_period_size_near(4000) 时,snd_pcm_hw_param_set_near() 辅助函数会调用 set_min(4000)set_max(4000)(在 hw_params 结构的单独副本上),因此间隔是 [1024, 4000] 和 [4000, 8192];精炼后,驱动程序返回区间 [1024, 2048] 和 [4096, 8192]。 snd_pcm_hw_param_set_near() 然后看到 4096 最接近所需的值,因此它在第二个间隔调用 set_first,结果是 [4096, 4096]。

    【讨论】:

    • 这回答了我的问题,但只是部分回答。我仍然没有看到对内核驱动程序接口的结束调用。在你提到的_snd_pcm_hw_param_set_first() 里面,除了一些掩码设置之外什么都没有。所以还是不明白这个新传的参数是怎么下发给驱动的?
    • 内核调用发生在_refine
    • 你的意思是snd_mask_refine_first()?除了 snd_mask_empty(mask)snd_mask_leave(mask, snd_mask_min(mask)); 之类的掩码操作之外,什么都没有
    • snd_pcm_hw_refine()snd_pcm_hw_hw_refine()hw_refine_call()
    • 现在我明白了,非常感谢!虽然我仍然觉得它过于复杂。顺便说一句:我在hw_refine_call() 中看到他们使用ioctl(pcm_hw-&gt;fd, SNDRV_PCM_IOCTL_HW_REFINE, params); 你能告诉驱动程序之前是如何注册自己的,所以现在应用程序可以使用pcm_hw-&gt;fd 与之交谈吗?
    猜你喜欢
    • 2013-12-10
    • 1970-01-01
    • 2023-01-11
    • 2022-08-19
    • 1970-01-01
    • 2018-05-07
    • 1970-01-01
    • 2020-02-03
    • 1970-01-01
    相关资源
    最近更新 更多