audio驱动之machine

本文深入探讨Linux内核音频驱动中的Machine驱动,讲述了如何处理特定硬件的音频事件,如电源管理。从入口函数开始,分析了平台设备注册、结构体设置、声卡绑定及注册过程。详细讲解了关键函数的功能,如声卡注册、链表初始化、DAI绑定等,揭示了音频处理的底层机制。
摘要由CSDN通过智能技术生成

文章目录

平台 os版本 内核
MT6765 Android 9.0 kernel-4.9

Machine驱动负责处理机器特有的一些控件和音频事件(例如,当播放音频时,需要先行打开一个PA(即功率放大器);单独的PlatformCodec驱动是不能工作的,它必须由Machine驱动把它们结合在一起才能完成整个设备的音频处理工作。

ASoC的一切都从Machine驱动开始,包括声卡的注册,绑定PlatformCodec驱动等等。
在这里插入图片描述

audio驱动相关结构体 注释
snd_soc_dai_link 音频链路描述及板级操作函数

入口函数所在文件:
./kernel-4.4/sound/soc/mediatek/common_int/mtk-soc-machine.c

module_init(mt_soc_snd_init);

static int __init mt_soc_snd_init(void)
{
   
	int ret;

	pr_debug("%s\n", __func__);

	... /* 省略部分代码 */

	ret = platform_driver_register(&mt_audio_driver);
	pr_debug("-%s\n", __func__);

	return ret;
}

模块初始化时,在入口函数mt_soc_snd_init中通过platform_driver_register注册了一个名字为"mtk-audio"的平台设备。

/* ASoC platform driver */
#ifdef CONFIG_OF
static const struct of_device_id mt_audio_driver_dt_match[] = {
   
	{
   
		.compatible = "mediatek,audio",
	},
	{
   } };
#endif

static struct platform_driver mt_audio_driver = {
   
	.driver = {
   

			.name = "mtk-audio",
			.owner = THIS_MODULE,
#ifdef CONFIG_OF
			.of_match_table = mt_audio_driver_dt_match,
#endif
		},
	.probe = mt_soc_snd_probe,
	.remove = mt_soc_snd_remove,
};

of_match_table./kernel-4.9/arch/arm/boot/dts/mt6765.dts文件中的

audio: audio@11220000 {
   
        compatible = "mediatek,audio", "syscon";
        reg = <0 0x11220000 0 0x1000>;
        /* interrupts = <GIC_SPI 153 IRQ_TYPE_LEVEL_LOW>; */
        #clock-cells = <1>;
        mediatek,btcvsd_snd = <&btcvsd_snd>;
};

compatible中的字符串匹配成功后,会调用到相应的probe函数。

/* probes a new socdev */
static int mt_soc_snd_probe(struct platform_device *pdev)
{
   
	struct snd_soc_card *card = &mt_snd_soc_card_mt;
	struct device_node *btcvsd_node;
	int ret;
	int daiLinkNum = 0;

	/* 更新喇叭对应的 codec dai 名字和 codec 的名字 */
	ret = mtk_spk_update_dai_link(mt_soc_extspk_dai, pdev);
	if (ret) {
   
		dev_err(&pdev->dev, "%s(), mtk_spk_update_dai_link error\n",
			__func__);
		return -EINVAL;
	}

	/* 获取外置的codec_dai的名字 */
	get_ext_dai_codec_name();
	pr_debug("mt_soc_snd_probe dai_link = %p\n",
		mt_snd_soc_card_mt.dai_link);

	/* DEAL WITH DAI LINK */
	/* 将mt_soc_dai_common结构体中的内容拷贝给mt_soc_dai_component结构体 */
	memcpy(mt_soc_dai_component, mt_soc_dai_common,
	       sizeof(mt_soc_dai_common));
	/* 统计mt_soc_dai_common结构体中包含的dai link的数目 */
	daiLinkNum += ARRAY_SIZE(mt_soc_dai_common);

#ifdef CONFIG_SND_SOC_MTK_BTCVSD
	/* assign btcvsd platform_node */
	/* 通过设备树获取btcvsd_node这个节点 */
	btcvsd_node = of_parse_phandle(pdev->dev.of_node,
				       "mediatek,btcvsd_snd", 0);
	if (!btcvsd_node) {
   
		dev_err(&pdev->dev, "Property 'btcvsd_snd' missing or invalid\n");
		return -EINVAL;
	}
	/* 将获取的节点保存到mt_soc_btcvsd_dai的platform_of_node 中作为平台节点 */
	mt_soc_btcvsd_dai[0].platform_of_node = btcvsd_node;

	/* 将mt_soc_btcvsd_dai添加到mt_soc_dai_component结构体中作为最后一个元素 */
	memcpy(mt_soc_dai_component + daiLinkNum,
	mt_soc_btcvsd_dai, sizeof(mt_soc_btcvsd_dai));
	/* 重新统计 daiLinkNum 的数目 */
	daiLinkNum += ARRAY_SIZE(mt_soc_btcvsd_dai);
#endif

	/* 将mt_soc_exthp_dai添加到mt_soc_dai_component结构体中作为最后一个元素 */
	memcpy(mt_soc_dai_component + daiLinkNum, mt_soc_exthp_dai,
	       sizeof(mt_soc_exthp_dai));
	/* 重新统计 daiLinkNum 的数目 */
	daiLinkNum += ARRAY_SIZE(mt_soc_exthp_dai);

	/* 将mt_soc_extspk_dai添加到mt_soc_dai_component结构体中作为最后一个元素 */
	memcpy(mt_soc_dai_component + daiLinkNum, mt_soc_extspk_dai,
	       sizeof(mt_soc_extspk_dai));
	/* 重新统计 daiLinkNum 的数目 */
	daiLinkNum += ARRAY_SIZE(mt_soc_extspk_dai);

	/************************************************************
	 * 将已经保存了所有需要的 dai link 的 mt_soc_dai_component 结构体
	 * 放入 mt_snd_soc_card_mt 结构体的 dai_link 成员变量中
	 ************************************************************/
	mt_snd_soc_card_mt.dai_link = mt_soc_dai_component;
	/*****************************************************
	 * 将已经保存了所有需要的 dai link 数量的变量daiLinkNum
	 * 放入 mt_snd_soc_card_mt 结构体的 num_links 成员变量中
	 *****************************************************/
	mt_snd_soc_card_mt.num_links = daiLinkNum;

	card->dev = &pdev->dev;
	platform_set_drvdata(pdev, card);

	/* 调用alsa框架的标准函数来注册声卡,这里开始就是ALSA框架的那一套东西了 */
	ret = devm_snd_soc_register_card(
  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值