alsa音频架构2-ASoc

本文深入介绍了ASoC(Advanced Linux Sound Architecture - Controller)架构,特别是其在嵌入式系统中的应用。ASoC由snd_soc_platform、snd_soc_codec、snd_soc_dai和snd_soc_card等组件构成,这些组件共同作用于ALSA以提供音频支持。文章详细阐述了各组件的作用和关系,如snd_soc_dai作为平台和编解码器之间的数字音频接口,以及如何通过snd_soc_register_card进行声卡注册。此外,还讨论了平台设备、codec设备、DAI驱动的注册与注销过程,以及ASoC声卡的实例化。开发者需要完成的工作包括平台设备创建、codec和DAI驱动的定义与注册等。
摘要由CSDN通过智能技术生成

设计ASoc的目的是为嵌入式系统片上处理器音频单元或外部的音频解码芯片提供更好的ALSA支持

ASoC有多个组件组成snd_soc_platform/snd_soc_codec/snd_soc_dai/snd_soc_card以及ALSA的snd_pcm

snd_soc_platform和snd_soc_codec就行平台与设备的关系缺一不可,snd_soc_card是它们实例化的一个对象

snd_soc_dai是snd_soc_platform和snd_soc_codec的数字音频接口,snd_soc_codec的dai为codec_dai,snd_soc_platform的dai为cpu_dai

snd_pcm是snd_soc_card实例化后注册的声卡类型

在sound/soc/soc-core.c中初始化了上面提到的4个重要结构体的链表头

static LIST_HEAD(card_list);
static LIST_HEAD(dai_list);
static LIST_HEAD(platform_list);
static LIST_HEAD(codec_list);

 

第九部分 soc声卡设备snd_soc_card

1.soc声卡设备

struct snd_soc_card {
	const char *name;	//设备名
	struct device *dev;	//设备文件
	struct snd_card *snd_card;	//所属声卡
	struct module *owner;
	struct list_head list;
	struct mutex mutex;
	bool instantiated;	//实例化标志
	int (*probe)(struct platform_device *pdev);
	int (*remove)(struct platform_device *pdev);
	/* the pre and post PM functions are used to do any PM work before and after the codec and DAI's do any PM work. */
	int (*suspend_pre)(struct platform_device *pdev, pm_message_t state);
	int (*suspend_post)(struct platform_device *pdev, pm_message_t state);
	int (*resume_pre)(struct platform_device *pdev);
	int (*resume_post)(struct platform_device *pdev);
	/* callbacks */
	int (*set_bias_level)(struct snd_soc_card *,enum snd_soc_bias_level level);
	long pmdown_time;
	/* CPU <--> Codec DAI links  */
	struct snd_soc_dai_link *dai_link;	//dai link
	int num_links;
	struct snd_soc_pcm_runtime *rtd;
	int num_rtd;
	struct work_struct deferred_resume_work;
	/* lists of probed devices belonging to this card */
	struct list_head codec_dev_list;
	struct list_head platform_dev_list;
	struct list_head dai_dev_list;
};

snd_soc_card包含了snd_card,可以理解为声卡驱动的一个封装.

2.soc pcm

struct snd_soc_pcm_runtime  {
	struct device dev;			//设备文件
	struct snd_soc_card *card;	//soc声卡设备
	struct snd_soc_dai_link *dai_link;	//dai link
	unsigned int complete:1;
	unsigned int dev_registered:1;
	/* Symmetry data - only valid if symmetry is being enforced */
	unsigned int rate;
	long pmdown_time;
	/* runtime devices */
	struct snd_pcm *pcm;	//pcm结构体
	struct snd_soc_codec *codec;	//codec设备
	struct snd_soc_platform *platform;	//soc平台设备
	struct snd_soc_dai *codec_dai;	//dai设备 codec
	struct snd_soc_dai *cpu_dai;	//dai设备 cpu
	struct delayed_work delayed_work;
};

snd_soc_pcm_runtime结构体中包含一个snd_pcm结构体,所以可以认为它是pcm声卡设备的一个封装,其次他也是Asoc各个组件的一个关系网点

3.soc声卡设备的匹配过程

在sound/soc/soc-core.c中定义了一个平台设备驱动

static struct platform_driver soc_driver = {
	.driver		= {
		.name		= "soc-audio",
		.owner		= THIS_MODULE,
		.pm		= &soc_pm_ops,
	},
	.probe		= soc_probe,
	.remove		= soc_remove,
};

我们知道平台设备驱动和平台设备的匹配靠.driver.name名字,也就是在另一处代码中必须定义了平台设备platform_device且设备名必须为"soc-audio",

这样平台设备和驱动才能匹配,才会调用平台驱动的probe方法,既soc_probe

所以一般声卡的驱动程序中会按以下格式设计平台设备

int ret;
static struct platform_device *xxx;
xxx=platform_device_alloc("soc-audio", 0);	//分配平台驱动
//平台资源的添加
ret=platform_device_add(xxx);	//添加平台设备
if(ret)
	platform_device_put(xxx);	//增加引用计数

 

4.匹配调用的probe方法soc_probe

static int soc_probe(struct platform_device *pdev)
{
	struct snd_soc_card *card = platform_get_drvdata(pdev);	//获取soc声卡设备
	int ret = 0;
	/* Bodge while we unpick instantiation */
	card->dev = &pdev->dev;
	INIT_LIST_HEAD(&card->dai_dev_list);		//初始化dai_dev_list链表
	INIT_LIST_HEAD(&card->codec_dev_list);		//初始化codec_dev_list链表
	INIT_LIST_HEAD(&card->platform_dev_list);	//初始化platform_dev_list链表
	ret = snd_soc_register_card(card);	//注册soc声卡设备
	if (ret != 0) {
		dev_err(&pdev->dev, "Failed to register card\n");
		return ret;
	}
	return 0;
}

这里调用了snd_soc_register_card注册了soc声卡设备

5.注册soc声卡设备

static int snd_soc_register_card(struct snd_soc_card *card)
{
	int i;
	if (!card->name || !card->dev)
		return -EINVAL;
	card->rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime) * card->num_links,GFP_KERNEL);	//分配多个soc pcm内存
	if (card->rtd == NULL)
		return -ENOMEM;
	for (i = 0; i < card->num_links; i++)
		card->rtd[i].dai_link = &card->dai_link[i];	//dai link数组
	INIT_LIST_HEAD(&card->list);	
	card->instantiated = 0;	//soc声卡实例化标志设置为0
	mutex_init(&card->mutex);

	mutex_lock(&client_mutex);
	list_add(&card->list, &card_list);	//添加soc声卡到全局card_list链表
	snd_soc_instantiate_cards();	//实例化所有soc声卡
	mutex_unlock(&client_mutex);
	dev_dbg(card->dev, "Registered card '%s'\n", card->name);
	return 0;
}




最终调用snd_soc_instantiate_cards实例化所有声卡

 

第十部分 soc平台 snd_soc_platform

1.soc平台设备

struct snd_soc_platform {
	const char *name;	//设备名
	int id;	//设备id
	struct device *dev;	//设备文件
	struct snd_soc_platform_driver *driver;	//soc平台驱动
	unsigned int suspended:1; /* platform is suspended */
	unsigned int probed:1;	//"probe"标志
	struct snd_soc_card *card;	//soc声卡设备
	struct list_head list;
	struct list_head card_list;
};

2.soc平台驱动

struct snd_soc_platform_driver {
	int (*probe)(struct snd_soc_platform *);
	int (*remove)(struct snd_soc_platform *);
	int (*suspend)(struct snd_soc_dai *dai);
	int (*resume)(struct snd_soc_dai *dai);
	/* pcm creation and destruction */
	int (*pcm_new)(struct snd_card *, struct snd_soc_dai *,struct snd_pcm *);
	void (*pcm_free)(struct snd_pcm *);
	snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *,struct snd_soc_dai *);
	/* platform stream ops */
	struct snd_pcm_ops *ops;
};

3.注册soc平台驱动

int snd_soc_register_platform(struct device *dev,struct snd_soc_platform_driver *platform_drv)
{
	struct snd_soc_platform *platform;	//声明soc平台设备
	dev_dbg(dev, "platform register %s\n", dev_name(dev));
	platform = kzalloc(sizeof(struct snd_soc_platform), GFP_KERNEL);	//分配soc平台内存
	if (platform == NULL)
			return -ENOMEM;
	/* create platform component name */
	platform->name = fmt_single_name(dev, &platform->id);	//设置soc平台设备名及id
	if (platform->name == NULL) {
		kfree(platform);
		return -ENOMEM;
	}
	platform->dev = dev;	//设备文件
	platform->driver = platform_drv;	//捆绑soc平台设备驱动
	mutex_lock(&client_mutex);
	list_add(&platform->list, &platform_list);	//添加到全局platform_list链表
	snd_soc_instantiate_cards();	//实例化所有soc声卡设备
	mutex_unlock(&client_mutex);
	pr_debug("Registered platform '%s'\n", platform->name);
	return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_register_platform);

注册soc平台驱动需要驱动自己去调用snd_soc_register_platform注册.


最终调用snd_soc_instantiate_cards实例化所有声卡

4.注销soc平台驱动

void snd_
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值