我是靠谱客的博主 细腻枫叶,最近开发中收集的这篇文章主要介绍ALSA驱动分析,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

1,概述

2,ALSA框架介绍

3,ALSA声卡注册过程

4,ALSA设备节点创建

5,tinyalsa调用流程

 

1,概述

声卡创建过程:

1, 创建声卡实例. snd_card_create
2, 创建逻辑设备. snd_device_new
3, 设置PCM逻辑设备的substream的操作函数(cpu_dai的操作方法)
4, snd_card_register,将声卡实例注册进ALSA框架内. 生成第二步创建的设备节点 /dev/snd/下的play与cap节点

前三部分是系统初始化部分,最后一部分是将audio注册到ALSA框架,是核心部分

 

2,ALSA框架介绍

ALSA将整个框架分为三个模块 platform/machine/codec

模块作用:

Platform:SOC芯片部分,与平台本身相关。例如:平台支持I2S与PCM,I2S具体又细分为I2S0,I2S1,SPDIF等。平台最理想情况是可以适配任何的codec

例如:sound/snd/amlogic下的代码,代表amlogic平台;其下面的code都是与其平台相关的

Codec:绝大多数的codec芯片,都是外置的;sound/soc/codec/ 不多做解释

Machine:这个就是电路板,将SOC芯片和Codec芯片适配集成在一块;一般在device tree下或者在 平台路径下指定文件(例如tv)进行配置   eg: sound/soc/amlogic/meson

注册声卡的入口:snd_soc_register_card or devm_snd_soc_register_card 

工作:

       解析device tree,将platform/cpu_dai/codec_dai/codec注册进ASoC对应的各个组件链表中,填充snd_soc_dai_link

然后执行snd_soc_register_card,最终生成pcm与control设备节点。

       从device tree上可以看出,alsa的几部分结构: platform_list;cup_list(即cpu_dai);codec_list; codec 

aml_snd_tv {
		compatible = "amlogic, txlx-snd-tv";
		status = "okay";
		aml-sound-card,format = "i2s";
		aml_sound_card,name = "AML-TVAUDIO";
		pinctrl-names = "audio_i2s";
		pinctrl-0 = <&aml_audio_i2s>;
		aux_dev = <&tas5731>;
		cpu_list = <&cpudai0 &cpudai1 &cpudai2 &cpudai3>;
		codec_list = <&codec0 &codec1 &codec2 &codec3>;
		plat_list = <&i2s_plat &i2s_plat &pcm_plat &i2s_plat>;
		cpudai0: cpudai0 {
			sound-dai = <&i2s_dai>;
		};
		cpudai1: cpudai1 {
			sound-dai = <&spdif_dai>;
		};
		cpudai2: cpudai2 {
			sound-dai = <&pcm_dai>;
		};
		cpudai3: cpudai3 {
			sound-dai = <&i2s2_dai>;
		};
		codec0: codec0 {
			sound-dai = <&amlogic_codec>;
		};
		codec1: codec1 {
			sound-dai = <&spdif_codec>;
		};
		codec2: codec2 {
			sound-dai = <&pcm_codec>;
		};
		codec3: codec3 {
			sound-dai = <&dummy_codec>;
		};
	};

platform部分:

填充一个结构struct snd_soc_platform ,然后把这个结构填充到platform_list中

snd_soc_register_component() //将struct snd_soc_dai添加进dai_list链表中!

codec部分:

snd_soc_register_codec()

codec、codec_dai注册进codec_list和dai_list中

codec_list前者负责codec的逻辑配置(可控tinymix下的属性)。dai_list是codec接口部分描述,如i2s or pcm

machine分析:

把具体电路板上的platform和codec指定到一块

结构snd_soc_dai_link来指定,这个结构会把platform与codec适配到一起。把platform、cpu_dai、codec_dai以及codec 适配到一起,形成一条audio in/out的通路   <device tree里面存在对应的框架>

注意: platform与codec的dai都会放到dai_list链表中

 

3,ALSA声卡注册过程

注册入口:devm_snd_soc_register_card 或者 snd_soc_register_card
 

snd_soc_register_card()
devm_snd_soc_register_card
    snd_soc_register_card —— 注册声卡
        snd_soc_instantiate_card —— 声卡初始化
            soc_bind_dai_link —— 检查struct snd_soc_dai_link中,dai_list/codec_list/platform_list中是否存在;
            snd_card_create —— ALSA核心函数,创建声卡,同时内部自动创建了control逻辑设备;
            snd_soc_dapm_new_controls():DAPM音频电源动态管理;
            soc_probe_link_components():调用soc_probe_codec/soc_probe_platform,分别初始化snd_soc_dai_link中指定的codec和platform驱动代码里的东西,包括DAPM,但不包括cpu_dai/codec_dai;
            soc_probe_link_dais():初始化snd_soc_dai_link中指定的cpu_dai和codec_dai驱动里的东西;调用soc_new_pcm(),这个函数首先创建了pcm逻辑设备,调用的是snd_device_new()的PCM类型的封装函数snd_pcm_new(),接着调用snd_pcm_set_ops()来给创建的pcm逻辑设备的substream提供pcm操作,最后调用platform中的pcm_new()函数,这个函数用来分配初始化dma;
            snd_soc_dai_set_fmt():如果提供回调,分别设置snd_soc_dai_link中的cpu_dai、codec_dai中的接口格式;
            snd_card_regster():ALSA核心函数,注册声卡;

整个ALSA的架构,当用户在操作alsa设备节点时,通过ALSA架构,最终调用pcm逻辑设备的substream的pcm操作,这些操作是我们之前在调用soc_probe_link_dais()中,调用ALSA核心函数snd_pcm_set_ops()设置的,这些设置的回调函数,最终有分别调用了snd_soc_dai_link中指定的platform/cpu_dai/codec_dai的同名函数。

 

4,ALSA设备节点创建

/dev/snd/下面的设备节点是字符设备,kernel中注册字符设备需要两个函数:
register_chrdev():alsa_sound_init()中调用,主要用来向kernel注册一个主设备为116,次设备号范围从0-255的字符设备;
device_create():snd_card_register()中调用snd_register_device_all(),遍历snd_card中的devices链表,调用每个组件的回调函数,回调函数中调用了device_create()来产生设备节点;

说明:pcm逻辑设备在一般情况下,会创建两种设备节点,分别是playback类型的substream的设备节点和capture类型的substream的设备节点,也就是我们看到的/dev/snd/pcmc0d*p和/dev/snd/pcmc0d*c;substream数量可以有多个,但是大多数情况只有一个;snd_card的devices链表中的组件是通过snd_device_new()加入的,而snd_pcm_new()/snd_ctl_create()对snd_device_new()进行了封装;
 

5,tinyalsa调用流程

以pcm_open为例:
1,open字符设备节点,找到真正注册的设备open方法soc_pcm_open(来自/sound/soc/soc-pcm.c )

snd_pcm_open
    snd_pcm_open_file
        snd_pcm_open_substream
            substream->ops->open
这个open函数是调用snd_pcm_set_ops()时设置的,soc_pcm_open(来自sound/soc/soc-pcm.c )
这个函数会分别调用cpu_dai、platform、codec_dai、dai_link中的start/open

2,类似的pcm_prepare():
实际上就是一个ioctl调用;
到内核代码中找snd_pcm_f_ops结构数组,找到unlocked_ioctl的函数指针snd_pcm_playback_ioctl,
    snd_pcm_prepare
        snd_pcm_action_prepare
            snd_pcm_do_prepare
                substream->ops->prepare()

最终调用soc_pcm_prepare(),进去后,会发现分别调用了:
platform->driver->ops->prepare():platform驱动中的snd_soc_platform_driver结构体中对应的接口;
codec_dai->driver->ops->prepare():platform驱动中的cpu_dai接口的snd_soc_dai_driver结构体中对应的接口;
cpu_dai->driver->ops->prepare():codec驱动中的codec_dai接口的snd_soc_dai_driver结构体中对应的接口;

 

so, tinyalsa上的控制修改,完全可以通过修改sound/soc/soc-pcm.c里面对应的函数,实现需求上的特殊修改。

最后,附kernel里面的sound源码路径:alsa分析源码路径kernel/sound

 

最后

以上就是细腻枫叶为你收集整理的ALSA驱动分析的全部内容,希望文章能够帮你解决ALSA驱动分析所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(57)

评论列表共有 0 条评论

立即
投稿
返回
顶部