Asoc dapm(四) - dapm widgets & dapm route注册
2015-12-05 19:12
656 查看
dapm widgets和dapm route数组
codec driver那边一般都有dapm widgets,dapm route数组,platform driver和machine driver那边可能也会有dapm widgets,dapm route数组。有两种方式可以注册dapm widgets和dapm route数组
1) 可以通过在struct snd_soc_codec_driver soc_codec_dev_rt5658结构体中初始化dapm widgets数组和dapm route数组,如下:
static struct snd_soc_codec_driver soc_codec_dev_rt5658 = { .probe = rt5658_probe, .remove = rt5658_remove, .suspend = rt5658_suspend, .resume = rt5658_resume, .set_bias_level = rt5658_set_bias_level, .idle_bias_off = true, .controls = rt5658_snd_controls, .num_controls = ARRAY_SIZE(rt5658_snd_controls), .dapm_widgets = rt5658_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(rt5658_dapm_widgets), .dapm_routes = rt5658_dapm_routes, .num_dapm_routes = ARRAY_SIZE(rt5658_dapm_routes), };
2) 也可以在struct snd_soc_codec_driver的probe函数中注册
static int rt5645_probe(struct snd_soc_codec *codec) { ... snd_soc_add_codec_controls(codec, rt5645_snd_controls, ARRAY_SIZE(rt5645_snd_controls)); snd_soc_dapm_new_controls(&codec->dapm, rt5645_dapm_widgets, ARRAY_SIZE(rt5645_dapm_widgets)); snd_soc_dapm_add_routes(&codec->dapm, rt5645_dapm_routes, ARRAY_SIZE(rt5645_dapm_routes)); ... } static struct snd_soc_codec_driver soc_codec_dev_rt5645 = { .probe = rt5645_probe, .remove = rt5645_remove, .suspend = rt5645_suspend, .resume = rt5645_resume, .set_bias_level = rt5645_set_bias_level, .reg_cache_size = RT5645_VENDOR_ID2 + 1, .reg_word_size = sizeof(u16), .reg_cache_default = rt5645_reg, .volatile_register = rt5645_volatile_register, .readable_register = rt5645_readable_register, .reg_cache_step = 1, };
方式一虽然没有显示的调用snd_soc_dapm_new_controls和snd_soc_dapm_add_routes注册dapm widgets和dapm route,但是在将struct snd_soc_codec_driver注册到asoc core里的时候会通过这两个函数注册。
snd_soc_dapm_new_control
static struct snd_soc_dapm_widget * snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_widget *widget) { struct snd_soc_dapm_widget *w; size_t name_len; int ret; if ((w = dapm_cnew_widget(widget)) == NULL) return NULL; switch (w->id) { case snd_soc_dapm_regulator_supply: w->regulator = devm_regulator_get(dapm->dev, w->name); if (IS_ERR(w->regulator)) { ret = PTR_ERR(w->regulator); dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n", w->name, ret); return NULL; } if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) { ret = regulator_allow_bypass(w->regulator, true); if (ret != 0) dev_warn(w->dapm->dev, "ASoC: Failed to unbypass %s: %d\n", w->name, ret); } break; case snd_soc_dapm_clock_supply: #ifdef CONFIG_CLKDEV_LOOKUP w->clk = devm_clk_get(dapm->dev, w->name); if (IS_ERR(w->clk)) { ret = PTR_ERR(w->clk); dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n", w->name, ret); return NULL; } #else return NULL; #endif break; default: break; } name_len = strlen(widget->name) + 1; if (dapm->codec && dapm->codec->name_prefix) name_len += 1 + strlen(dapm->codec->name_prefix); w->name = kmalloc(name_len, GFP_KERNEL); if (w->name == NULL) { kfree(w); return NULL; } if (dapm->codec && dapm->codec->name_prefix) snprintf((char *)w->name, name_len, "%s %s", dapm->codec->name_prefix, widget->name); else snprintf((char *)w->name, name_len, "%s", widget->name); switch (w->id) { case snd_soc_dapm_switch: case snd_soc_dapm_mixer: case snd_soc_dapm_mixer_named_ctl: w->power_check = dapm_generic_check_power; break; case snd_soc_dapm_mux: case snd_soc_dapm_virt_mux: case snd_soc_dapm_value_mux: w->power_check = dapm_generic_check_power; break; case snd_soc_dapm_adc: case snd_soc_dapm_aif_out: case snd_soc_dapm_dai_out: w->power_check = dapm_adc_check_power; break; case snd_soc_dapm_dac: case snd_soc_dapm_aif_in: case snd_soc_dapm_dai_in: w->power_check = dapm_dac_check_power; break; case snd_soc_dapm_pga: case snd_soc_dapm_out_drv: case snd_soc_dapm_input: case snd_soc_dapm_output: case snd_soc_dapm_micbias: case snd_soc_dapm_spk: case snd_soc_dapm_hp: case snd_soc_dapm_mic: case snd_soc_dapm_line: case snd_soc_dapm_dai_link: w->power_check = dapm_generic_check_power; break; case snd_soc_dapm_supply: case snd_soc_dapm_regulator_supply: case snd_soc_dapm_clock_supply: w->power_check = dapm_supply_check_power; break; default: w->power_check = dapm_always_on_check_power; break; } w->dapm = dapm; w->codec = dapm->codec; w->platform = dapm->platform; INIT_LIST_HEAD(&w->sources); INIT_LIST_HEAD(&w->sinks); INIT_LIST_HEAD(&w->list); INIT_LIST_HEAD(&w->dirty); list_add(&w->list, &dapm->card->widgets); /* machine layer set ups unconnected pins and insertions */ w->connected = 1; return w; }
在这个函数中主要做了以下几件事:
1) 初始化struct snd_soc_dapm_widget *w
2) 如果w->id为snd_soc_dapm_regulator_supply或者snd_soc_dapm_clock_supply则获取w->regulator和w->clk,以便后面对regulator和clk进行设置。
3) 设置w->power_check回调函数
4) list_add(&w->list, &dapm->card->widgets);将此widget添加到card->widgets链表中
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_path *path; struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL; const char *sink; const char *control = route->control; const char *source; char prefixed_sink[80]; char prefixed_source[80]; int ret = 0; if (dapm->codec && dapm->codec->name_prefix) { snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s", dapm->codec->name_prefix, route->sink); sink = prefixed_sink; snprintf(prefixed_source, sizeof(prefixed_source), "%s %s", dapm->codec->name_prefix, route->source); source = prefixed_source; } else { sink = route->sink; source = route->source; } /* * find src and dest widgets over all widgets but favor a widget from * current DAPM context */ list_for_each_entry(w, &dapm->card->widgets, list) { if (!wsink && !(strcmp(w->name, sink))) { wtsink = w; if (w->dapm == dapm) wsink = w; continue; } if (!wsource && !(strcmp(w->name, source))) { wtsource = w; if (w->dapm == dapm) wsource = w; } } /* use widget from another DAPM context if not found from this */ if (!wsink) wsink = wtsink; if (!wsource) wsource = wtsource; if (wsource == NULL) { dev_err(dapm->dev, "ASoC: no source widget found for %s\n", route->source); return -ENODEV; } if (wsink == NULL) { dev_err(dapm->dev, "ASoC: no sink widget found for %s\n", route->sink); return -ENODEV; } path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL); if (!path) return -ENOMEM; path->source = wsource; path->sink = wsink; path->connected = route->connected; INIT_LIST_HEAD(&path->list); INIT_LIST_HEAD(&path->list_source); INIT_LIST_HEAD(&path->list_sink); /* check for external widgets */ if (wsink->id == snd_soc_dapm_input) { if (wsource->id == snd_soc_dapm_micbias || wsource->id == snd_soc_dapm_mic || wsource->id == snd_soc_dapm_line || wsource->id == snd_soc_dapm_output) wsink->ext = 1; } if (wsource->id == snd_soc_dapm_output) { if (wsink->id == snd_soc_dapm_spk || wsink->id == snd_soc_dapm_hp || wsink->id == snd_soc_dapm_line || wsink->id == snd_soc_dapm_input) wsource->ext = 1; } /* connect static paths */ if (control == NULL) { list_add(&path->list, &dapm->card->paths); list_add(&path->list_sink, &wsink->sources); list_add(&path->list_source, &wsource->sinks); path->connect = 1; return 0; } /* connect dynamic paths */ switch (wsink->id) { case snd_soc_dapm_adc: case snd_soc_dapm_dac: case snd_soc_dapm_pga: case snd_soc_dapm_out_drv: case snd_soc_dapm_input: case snd_soc_dapm_output: case snd_soc_dapm_siggen: case snd_soc_dapm_micbias: case snd_soc_dapm_vmid: case snd_soc_dapm_pre: case snd_soc_dapm_post: case snd_soc_dapm_supply: case snd_soc_dapm_regulator_supply: case snd_soc_dapm_clock_supply: case snd_soc_dapm_aif_in: case snd_soc_dapm_aif_out: case snd_soc_dapm_dai_in: case snd_soc_dapm_dai_out: case snd_soc_dapm_dai_link: list_add(&path->list, &dapm->card->paths); list_add(&path->list_sink, &wsink->sources); list_add(&path->list_source, &wsource->sinks); path->connect = 1; return 0; case snd_soc_dapm_mux: case snd_soc_dapm_virt_mux: case snd_soc_dapm_value_mux: ret = dapm_connect_mux(dapm, wsource, wsink, path, control, &wsink->kcontrol_news[0]); if (ret != 0) goto err; break; case snd_soc_dapm_switch: case snd_soc_dapm_mixer: case snd_soc_dapm_mixer_named_ctl: ret = dapm_connect_mixer(dapm, wsource, wsink, path, control); if (ret != 0) goto err; break; case snd_soc_dapm_hp: case snd_soc_dapm_mic: case snd_soc_dapm_line: case snd_soc_dapm_spk: list_add(&path->list, &dapm->card->paths); list_add(&path->list_sink, &wsink->sources); list_add(&path->list_source, &wsource->sinks); path->connect = 0; return 0; } dapm_mark_dirty(wsource, "Route added"); dapm_mark_dirty(wsink, "Route added"); return 0; err: dev_warn(dapm->dev, "ASoC: no dapm match for %s --> %s --> %s\n", source, control, sink); kfree(path); return ret; }
这个函数做了以下几件事:
1) 根据route中source和sink的name在card->widgets链表中找到对应的source widget和sink widget,并分别赋值给path的wsource和wsink赋值。
2) 对于没有kcontrol的path
将path添加到card->paths链表中
将path添加到wsink->sources链表中
将path添加到wsource->sinks链表中
之后就直接返回了,比后面有kcontrol的path少执行两个函数dapm_mark_dirty(wsource, “Route added”);和dapm_mark_dirty(wsink, “Route added”);
3) 对于有kcontrol的path,同样
将path添加到card->paths链表中
将path添加到wsink->sources链表中
将path添加到wsource->sinks链表中
但是在这里,mux和mixer比较特别,分别会调用dapm_connect_mux和dapm_connect_mixer,这两个函数除了像上面一样需要添加path到card->path, wsink->sources,wsource->sinks链表中之外,还会执行dapm_set_path_status函数,dapm_set_path_status读取codec寄存器的值,并更新path的connect状态
snd_soc_dapm_new_widgets
函数snd_soc_dapm_new_widgets和函数snd_soc_dapm_new_controls在名字上有点让人混淆,在前面所讲的snd_soc_dapm_new_controls其实是添加dapm_widgets到card->widgets链表中,而这里的snd_soc_dapm_new_widgets主要作用是将这个dapm_widgets中的kcontrol添加card->kcontrol链表中,采用和之前添加普通kcontrol一样的方法snd_ctl_add来添加。int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) { struct snd_soc_dapm_widget *w; unsigned int val; mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); list_for_each_entry(w, &dapm->card->widgets, list) { if (w->new) continue; if (w->num_kcontrols) { w->kcontrols = kzalloc(w->num_kcontrols * sizeof(struct snd_kcontrol *), GFP_KERNEL); if (!w->kcontrols) { mutex_unlock(&dapm->card->dapm_mutex); return -ENOMEM; } } switch(w->id) { case snd_soc_dapm_switch: case snd_soc_dapm_mixer: case snd_soc_dapm_mixer_named_ctl: dapm_new_mixer(w); break; case snd_soc_dapm_mux: case snd_soc_dapm_virt_mux: case snd_soc_dapm_value_mux: dapm_new_mux(w); break; case snd_soc_dapm_pga: case snd_soc_dapm_out_drv: dapm_new_pga(w); break; default: break; } /* Read the initial power state from the device */ if (w->reg >= 0) { val = soc_widget_read(w, w->reg); val &= 1 << w->shift; if (w->invert) val = !val; if (val) w->power = 1; } w->new = 1; dapm_mark_dirty(w, "new widget"); dapm_debugfs_add_widget(w); } dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP); mutex_unlock(&dapm->card->dapm_mutex); return 0; } EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
这个函数还是比较好理解的
1) 遍历card->widgets链表中的所有widget,对于每个widget,mixer或者mux分别会调用dapm_new_mixer(w);和dapm_new_mux(w);来讲widget下面的所有kcontrol添加到card->kcontrol链表中
2) 调用dapm_power_widgets统一处理widgets链表上的widget状态的改变
附上几篇文章的链接
1. Asoc dapm(一) - kcontrol
2. Asoc dapm(二) - kcontrol注册与使用
3. Asoc dapm(三) - dapm widgets & dapm kcontrol & dapm route
4. Asoc dapm(四) - dapm widgets & dapm route注册
5. Asoc dapm(五) - dapm widget链表更新
相关文章推荐
- TS科普22 PAT PMT PES关系
- CCBPM中流程回滚的介绍
- CCBPM流程变更处理解决方案与对策
- CCBPM多表单流程中关于绑定表单的设计步骤
- CCBPM关于工作流引擎取回审批的设计方案与实现过程
- CCBPM高级开发之类设计与数据库设计命名规则
- CCBPM高级开发之类设计与数据库设计命名规则
- CCBPM关于工作流引擎授权功能说明
- CCBPM关于工作流引擎授权功能说明
- CCBPM关于工作流引擎取回审批的设计方案与实现过程
- [置顶] Google Development
- Samba服务器rpm安装
- 如何卸载rpm包
- mysql rpm安装,以及修改charset
- rhel配置163、epel、rpmforge的yum源
- 2015伦敦深度学习峰会笔记:来自DeepMind、Clarifai等大神的分享
- 浅析JBPM工作流引擎
- TS科普18 节目映射表PMT
- 产品经理--工具篇
- 程序员和 PM 通常不会一见钟情