audio子系统笔记(二)

 1、系统调用过程:

snd_pcm_ioctl
    snd_pcm_common_ioctl
        snd_pcm_hw_params_user
            snd_pcm_hw_params
                //hw_params指向soc_pcm_hw_params函数
                substream->ops->hw_params(substream, params);
                soc_pcm_hw_params
                    soc_dai_hw_params
                         dai->driver->ops->hw_params(substream, params, dai);
                    

2、dapm context: 

3、is_connected_output_ep函数和is_connected_input_ep函数分析:

      函数返回值是指定widget分别到输入、输出端点的完整路径的条数。

static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,                 
  struct list_head *list,
  bool (*custom_stop_condition)(struct snd_soc_dapm_widget *i,enum snd_soc_dapm_direction))
{
	return is_connected_ep(widget, list, SND_SOC_DAPM_DIR_OUT,
			is_connected_output_ep, custom_stop_condition);
}
static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
  struct list_head *list,
  bool (*custom_stop_condition)(struct snd_soc_dapm_widget *i,enum snd_soc_dapm_direction))
{
	return is_connected_ep(widget, list, SND_SOC_DAPM_DIR_IN,
			is_connected_input_ep, custom_stop_condition);
}

从中看出无论是is_connected_output_ep函数还是is_connected_input_ep函数都调用了is_connected_ep函数;其中,is_connected_ep函数的第四个参数传入的是一个父函数,用于函数的递归调用,第五个参数是一个可选的用于判断什么时候停止的一个条件函数,既然是可选的,这里不分析它。

is_connected_ep函数:

int is_connected_ep(struct snd_soc_dapm_widget *widget,struct list_head *list, 
    enum snd_soc_dapm_direction dir,
	int (*fn)(struct snd_soc_dapm_widget *, struct list_head *,
		  bool (*custom_stop_condition)(struct snd_soc_dapm_widget *,
						enum snd_soc_dapm_direction)),
	bool (*custom_stop_condition)(struct snd_soc_dapm_widget *,
				      enum snd_soc_dapm_direction))
{
    //SND_SOC_DAPM_DIR_REVERSE:用于方向的取反,如果输入就是输出,输出就是输入
	enum snd_soc_dapm_direction rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
	struct snd_soc_dapm_path *path;
	int con = 0;

	/* do we need to add this widget to the list ? */
    /*work_list用于widget加入的完整路径链表*/
	if (list)
		list_add_tail(&widget->work_list, list);

    ......

    //判断该widget是否是端点等
	if ((widget->is_ep & SND_SOC_DAPM_DIR_TO_EP(dir)) && widget->connected) {
		widget->endpoints[dir] = snd_soc_dapm_suspend_check(widget);
		return widget->endpoints[dir];
	}

    //注意:这里是rdir,和dir值相反
    //以is_connected_output_ep函数功能为例,dir是SND_SOC_DAPM_DIR_OUT,
    //rdir是SND_SOC_DAPM_DIR_IN,path连接着源点widget输出和目的widget输入,
    //相当于导线(path)连接着两个器件(widget);另外,这里的所有的方向都是从path 
    //的角度出发的,源点widget为输入,目的widget为输出,源点widget到path为输入,path到
    //目的widget为输出,现在以某个widget为起点遍历其上方向为输入的所有路径,即从该widget
    //发出的路径,然后再以这些路径上的输出widget为起点进行递归遍历
	snd_soc_dapm_widget_for_each_path(widget, rdir, path) {
        ......
		if (path->connect) {
            //从前往后遍历,把每个path的walking值都置1
			path->walking = 1;
            //fn函数回调,也是函数递归调用
            //注意:这里是dir,和rdir值相反
			con += fn(path->node[dir], list, custom_stop_condition);
            //从后往前遍历,把每个path的walking值都置0
			path->walking = 0;
		}
	}
    //从该widget出发到输入或输出端点有几个,也就是有几条路径
	widget->endpoints[dir] = con;

	return con;
}

4、audio path路径添加

snd_soc_instantiate_card(struct snd_soc_card *card)
	soc_probe_link_components(card, i, order);
		soc_probe_component(card, component);
			snd_soc_dapm_add_routes(dapm, component->dapm_routes,component->num_dapm_routes);
					

snd_soc_dapm_add_routes函数:

int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
			    const struct snd_soc_dapm_route *route, int num)
{
	int i= 0;

	for (i = 0; i < num; i++) {
        //route指针指向一个snd_soc_dapm_route结构的数组,每次访问一个数组元素
		snd_soc_dapm_add_route(dapm, route);
		route++;
	}

}

snd_soc_dapm_add_route函数:

static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
				  const struct snd_soc_dapm_route *route)
{
	struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
	struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
	const char *sink;
	const char *source;
	int ret;

	sink = route->sink;
	source = route->source;

	list_for_each_entry(w, &dapm->card->widgets, list) {
		if (!wsink && !(strcmp(w->name, sink))) {
			wtsink = w;
			if (w->dapm == dapm) {
				wsink = w;
				if (wsource)
					break;
			}
			continue;
		}
		if (!wsource && !(strcmp(w->name, source))) {
			wtsource = w;
			if (w->dapm == dapm) {
				wsource = w;
				if (wsink)
					break;
			}
		}
	}

	/* use widget from another DAPM context if not found from this */
	if (!wsink)
		wsink = wtsink;
	if (!wsource)
		wsource = wtsource;

	ret = snd_soc_dapm_add_path(dapm, wsource, wsink, route->control,route->connected);

	return 0;

}

 struct snd_soc_dapm_route结构体定义:

struct snd_soc_dapm_route {
	const char *sink;
	const char *control;
	const char *source;

	int (*connected)(struct snd_soc_dapm_widget *source,
			 struct snd_soc_dapm_widget *sink);
};

snd_soc_dapm_add_path函数:根据传进来的route创建对应的path,每个path都是唯一的(widget A和B直接相连的路径只有一条,如果两条,A和B之间直接划"=".),普通的path都是没有path名,包括有明确控件名的,只有mux和mixer有。

static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
	struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
	const char *control,
	int (*connected)(struct snd_soc_dapm_widget *source,
			 struct snd_soc_dapm_widget *sink))
{
	struct snd_soc_dapm_widget *widgets[2];
	enum snd_soc_dapm_direction dir;
	struct snd_soc_dapm_path *path;

	path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
    
    //path连接着源点widget输出和目的widget输入,相当于导线(path)连接着两个器件(widget);
    //另外,这里的所有的方向都是从path的角度出发的,源点widget为输入,目的widget为输出, 
    //源点widget到path为输入,path到目的widget为输出
	path->node[SND_SOC_DAPM_DIR_IN] = wsource;
	path->node[SND_SOC_DAPM_DIR_OUT] = wsink;
	widgets[SND_SOC_DAPM_DIR_IN] = wsource;
	widgets[SND_SOC_DAPM_DIR_OUT] = wsink;

	path->connected = connected;
	INIT_LIST_HEAD(&path->list);

	//根据route中的control值和sink widget的类型等条件赋值path->connect变量
	if (cont
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值