Asoc dapm(五) - dapm widget链表更新
2015-12-06 18:52
393 查看
有几个操作和dapm widget链表更新相关
1) 初始化的时候,snd_soc_instantiate_card里调用snd_soc_dapm_new_widgets,最终会调用dapm_power_widgets
2) 在用户空间通过tinymix设置路径,在SOC_DAPM_ENUM中的put或者get函数最终会调用dapm_power_widgets
3) 在用户空间通过tinyplay播放或者录音是的soc_pcm_prepare和soc_pcm_close,最终会调用dapm_power_widgets
以上3个地方最终会引发dapm widget链表的更新,都会调用一个很关键的函数dapm_power_widgets
SOC_DAPM_ENUM
snd_soc_dapm_put_enum_double
soc_dapm_mux_update_power
在soc_dapm_mux_update_power中,
1) 在card->path链表中找到与要设置的kcontrol匹配的path
2) 令path->connect=1,并且dapm_mark_dirty(path->source, “mux connection”);将path->source对应的widget添加到card->dapm_dirty链表中
3) dapm_mark_dirty(widget, “mux change”);将此widget添加到card->dapm_dirty链表中
4) dapm_power_widgets
1) dapm_reset
对card->widgets链表中所有的widget
w->power_checked = false;
w->inputs = -1;
w->outputs = -1;
2) dapm_power_one_widget
将card->dapm_dirty链表中的widget按照不同的情况分别加入到up_list和down_list中。
dapm_seq_insert函数里面的dapm_seq_compare比较上电先后顺序,看上图,如果new widget->id < widget->id,则将new widget添加到widget之前。这样dapm_seq_insert就可按照一定的顺序将widget添加到power_up链表或者power_down链表中
3) dapm_seq_run(dapm, &down_list, event, false);
在下电链表中,调用各个widget的event回调函数来实现下电
4) dapm_widget_update
更新widget中kcontrol,这个kcontrol是触发本次状态改变的触发源
5) dapm_seq_run(dapm, &up_list, event, true);
在上电链表中,调用各个widget的event回调函数来实现上电
ALSA声卡驱动中的DAPM详解之七:dapm事件机制(dapm event)
附上几篇文章的链接
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链表更新
1) 初始化的时候,snd_soc_instantiate_card里调用snd_soc_dapm_new_widgets,最终会调用dapm_power_widgets
2) 在用户空间通过tinymix设置路径,在SOC_DAPM_ENUM中的put或者get函数最终会调用dapm_power_widgets
3) 在用户空间通过tinyplay播放或者录音是的soc_pcm_prepare和soc_pcm_close,最终会调用dapm_power_widgets
以上3个地方最终会引发dapm widget链表的更新,都会调用一个很关键的函数dapm_power_widgets
以下几个操作会引起dapm widget链表更新
snd_soc_dapm_new_widgets
snd_soc_dapm_new_widgets在snd_soc_instantiate_card的时候会被调用,主要的作用是将card->widgets链表中widget的所有control添加到card->kcontrol链表中,最后会调用dapm_power_widgetsint 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);
SOC_DAPM_ENUM
tinymix对kcontrol进行设置的时候,调用的就是SOC_DAPM_ENUM中的put或者get函数,最终会执行dapm_power_widgetsSOC_DAPM_ENUM
#define SOC_DAPM_ENUM(xname, xenum) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ .info = snd_soc_info_enum_double, \ .get = snd_soc_dapm_get_enum_double, \ .put = snd_soc_dapm_put_enum_double, \ .private_value = (unsigned long)&xenum }
snd_soc_dapm_put_enum_double
int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { kcontrol->private_value是struct soc_enum类型,包含此kcontrol对应寄存器及在寄存器中的偏移 ucontrol->vallue.enumerated.item[0]/[1] 用户空间对kcontrol对应寄存器设定的值 soc_dapm_mux_update_power(widget, kcontrol, mux, e); }
soc_dapm_mux_update_power
在soc_dapm_mux_update_power中,
1) 在card->path链表中找到与要设置的kcontrol匹配的path
2) 令path->connect=1,并且dapm_mark_dirty(path->source, “mux connection”);将path->source对应的widget添加到card->dapm_dirty链表中
3) dapm_mark_dirty(widget, “mux change”);将此widget添加到card->dapm_dirty链表中
4) dapm_power_widgets
soc_pcm_prepare & soc_pcm_close
dapm_power_widgets
static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) { struct snd_soc_card *card = dapm->card; struct snd_soc_dapm_widget *w; struct snd_soc_dapm_context *d; LIST_HEAD(up_list); LIST_HEAD(down_list); ASYNC_DOMAIN_EXCLUSIVE(async_domain); enum snd_soc_bias_level bias; list_for_each_entry(d, &card->dapm_list, list) { if (d->idle_bias_off) d->target_bias_level = SND_SOC_BIAS_OFF; else d->target_bias_level = SND_SOC_BIAS_STANDBY; } dapm_reset(card); list_for_each_entry(w, &card->dapm_dirty, dirty) { dapm_power_one_widget(w, &up_list, &down_list); } list_for_each_entry(w, &card->widgets, list) { switch (w->id) { case snd_soc_dapm_pre: case snd_soc_dapm_post: /* These widgets always need to be powered */ break; default: list_del_init(&w->dirty); break; } if (w->power) { d = w->dapm; switch (w->id) { case snd_soc_dapm_siggen: break; case snd_soc_dapm_supply: case snd_soc_dapm_regulator_supply: case snd_soc_dapm_clock_supply: case snd_soc_dapm_micbias: if (d->target_bias_level < SND_SOC_BIAS_STANDBY) d->target_bias_level = SND_SOC_BIAS_STANDBY; break; default: d->target_bias_level = SND_SOC_BIAS_ON; break; } } } /* Force all contexts in the card to the same bias state if * they're not ground referenced. */ bias = SND_SOC_BIAS_OFF; list_for_each_entry(d, &card->dapm_list, list) if (d->target_bias_level > bias) bias = d->target_bias_level; list_for_each_entry(d, &card->dapm_list, list) if (!d->idle_bias_off) d->target_bias_level = bias; /* Run all the bias changes in parallel */ list_for_each_entry(d, &dapm->card->dapm_list, list) async_schedule_domain(dapm_pre_sequence_async, d, &async_domain); async_synchronize_full_domain(&async_domain); /* Power down widgets first; try to avoid amplifying pops. */ dapm_seq_run(dapm, &down_list, event, false); dapm_widget_update(dapm); /* Now power up. */ dapm_seq_run(dapm, &up_list, event, true); /* Run all the bias changes in parallel */ list_for_each_entry(d, &dapm->card->dapm_list, list) async_schedule_domain(dapm_post_sequence_async, d, &async_domain); async_synchronize_full_domain(&async_domain); /* do we need to notify any clients that DAPM event is complete */ list_for_each_entry(d, &card->dapm_list, list) { if (d->stream_event) d->stream_event(d, event); } pop_dbg(dapm->dev, card->pop_time, "DAPM sequencing finished, waiting %dms\n", card->pop_time); pop_wait(card->pop_time); return 0; }
1) dapm_reset
对card->widgets链表中所有的widget
w->power_checked = false;
w->inputs = -1;
w->outputs = -1;
2) dapm_power_one_widget
list_for_each_entry(w, &card->dapm_dirty, dirty) { dapm_power_one_widget(w, &up_list, &down_list); } static void dapm_power_one_widget(struct snd_soc_dapm_widget *w, struct list_head *up_list, struct list_head *down_list) { int power; switch (w->id) { case snd_soc_dapm_pre: dapm_seq_insert(w, down_list, false); break; case snd_soc_dapm_post: dapm_seq_insert(w, up_list, true); break; default: power = dapm_widget_power_check(w); dapm_widget_set_power(w, power, up_list, down_list); break; } }
将card->dapm_dirty链表中的widget按照不同的情况分别加入到up_list和down_list中。
dapm_seq_insert函数里面的dapm_seq_compare比较上电先后顺序,看上图,如果new widget->id < widget->id,则将new widget添加到widget之前。这样dapm_seq_insert就可按照一定的顺序将widget添加到power_up链表或者power_down链表中
3) dapm_seq_run(dapm, &down_list, event, false);
在下电链表中,调用各个widget的event回调函数来实现下电
4) dapm_widget_update
更新widget中kcontrol,这个kcontrol是触发本次状态改变的触发源
5) dapm_seq_run(dapm, &up_list, event, true);
在上电链表中,调用各个widget的event回调函数来实现上电
参考文章
ALSA声卡驱动中的DAPM详解之六:精髓所在,牵一发而动全身ALSA声卡驱动中的DAPM详解之七:dapm事件机制(dapm event)
附上几篇文章的链接
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链表更新
相关文章推荐
- PM 3
- MipMap介绍&算法
- Asoc dapm(四) - dapm widgets & dapm route注册
- 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工作流引擎