ALSA声卡驱动详解(10)

2019-08-31 00:43

snd_soc_dapm_sync(&card->dapm); ...... return 0; }

正如我添加的注释中所示,在完成machine级别的widget和route处理之后,调用的snd_soc_dapm_new_widgets函数,来为所有已经注册的widget初始化他们所包含的dapm kcontrol,并初始化widget的电源状态和路径连接状态。下面我们看看snd_soc_dapm_new_widgets函数的工作过程。 snd_soc_dapm_new_widgets函数

该函数通过声卡的widgets链表,遍历所有已经注册了的widget,其中的new字段用于判断该widget是否已经执行过snd_soc_dapm_new_widgets函数,如果num_kcontrols字段有数值,表明该widget包含有若干个dapm kcontrol,那么就需要为这些kcontrol分配一个指针数组,并把数组的首地址赋值给widget的kcontrols字段,该数组存放着指向这些kcontrol的指针,当然现在这些都是空指针,因为实际的kcontrol现在还没有被创建: [cpp] view plaincopy

int snd_soc_dapm_new_widgets(struct snd_soc_card *card) {

......

list_for_each_entry(w, &card->widgets, list) {

if (w->new) continue;

if (w->num_kcontrols) {

w->kcontrols = kzalloc(w->num_kcontrols *

sizeof(struct snd_kcontrol *),

GFP_KERNEL); ...... }

接着,对几种能影响音频路径的widget,创建并初始化它们所包含的dapm kcontrol:

[cpp] view plaincopy 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:

46

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; }

需要用到的创建函数分别是:

dapm_new_mixer() 对于mixer类型,用该函数创建dapm kcontrol; dapm_new_mux() 对于mux类型,用该函数创建dapm kcontrol; dapm_new_pga() 对于pga类型,用该函数创建dapm kcontrol;

然后,根据widget寄存器的当前值,初始化widget的电源状态,并设置到power字段中:

[cpp] view plaincopy

/* Read the initial power state from the device */ if (w->reg >= 0) {

val = soc_widget_read(w, w->reg) >> w->shift; val &= w->mask;

if (val == w->on_val) w->power = 1; }

接着,设置new字段,表明该widget已经初始化完成,我们还要吧该widget加入到声卡的dapm_dirty链表中,表明该widget的状态发生了变化,稍后在合适的时刻,dapm框架会扫描dapm_dirty链表,统一处理所有已经变化的widget。为什么要统一处理?因为dapm要控制各种widget的上下电顺序,同时也是为了减少寄存器的读写次数(多个widget可能使用同一个寄存器): [cpp] view plaincopy w->new = 1;

dapm_mark_dirty(w, \); dapm_debugfs_add_widget(w);

最后,通过dapm_power_widgets函数,统一处理所有位于dapm_dirty链表上的widget的状态改变: [cpp] view plaincopy

dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP); ...... return 0;

dapm mixer kcontrol

47

上一节中,我们提到,对于mixer类型的dapm kcontrol,我们会使用dapm_new_mixer来完成具体的创建工作,先看代码后分析: [cpp] view plaincopy

static int dapm_new_mixer(struct snd_soc_dapm_widget *w) {

int i, ret;

struct snd_soc_dapm_path *path;

/* add kcontrol */

(1) for (i = 0; i < w->num_kcontrols; i++) { /* match name */

(2) list_for_each_entry(path, &w->sources, list_sink) {

/* mixer/mux paths name must match control name */

(3) if (path->name != (char *)w->kcontrol_news[i].name)

continue;

(4) if (w->kcontrols[i]) {

dapm_kcontrol_add_path(w->kcontrols[i], path);

continue; }

(5) ret = dapm_create_or_share_mixmux_kcontrol(w, i);

if (ret < 0)

return ret;

(6) dapm_kcontrol_add_path(w->kcontrols[i], path); } }

return 0; }

(1) 因为一个mixer是由多个kcontrol组成的,每个kcontrol控制着mixer的一个输入端的开启和关闭,所以,该函数会根据kcontrol的数量做循环,逐个建立对应的kcontrol。

48

(2)(3) 之前多次提到,widget之间使用snd_soc_path进行连接,widget的sources链表保存着所有和输入端连接的snd_soc_path结构,所以我们可以用kcontrol模板中指定的名字来匹配对应的snd_soc_path结构。

(4) 因为一个输入脚可能会连接多个输入源,所以可能在上一个输入源的path关联时已经创建了这个kcontrol,所以这里判断kcontrols指针数组中对应索引中的指针值,如果已经赋值,说明kcontrol已经在之前创建好了,所以我们只要简单地把连接该输入端的path加入到kcontrol的path_list链表中,并且增加一个虚拟的影子widget,该影子widget连接和输入端对应的源widget,因为使用了

kcontrol本身的reg/shift等寄存器信息,所以实际上控制的是该kcontrol的开和关,这个影子widget只有在kcontrol的autodisable字段被设置的情况下才会被创建,该特性使得source的关闭时,与之连接的mixer的输入端也可以自动关闭,这个特性通过dapm_kcontrol_add_path来实现这一点: [cpp] view plaincopy

static void dapm_kcontrol_add_path(const struct snd_kcontrol *kcontrol,

struct snd_soc_dapm_path *path) {

struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);

/* 把kcontrol连接的path加入到paths链表中 */

/* paths链表所在的dapm_kcontrol_data结构会保存在kcontrol的private_data字段中 */

list_add_tail(&path->list_kcontrol, &data->paths);

if (data->widget) {

snd_soc_dapm_add_path(data->widget->dapm, data->widget,

path->source, NULL, NULL); } }

(5) 如果kcontrol之前没有被创建,则通过

dapm_create_or_share_mixmux_kcontrol创建这个输入端的kcontrol,同理,kcontrol对应的影子widget也会通过dapm_kcontrol_add_path判断是否需要创建。

dapm mux kcontrol

因为一个widget最多只会包含一个mux类型的damp kcontrol,所以他的创建方法稍有不同,dapm框架使用dapm_new_mux函数来创建mux类型的dapm kcontrol:

[cpp] view plaincopy

static int dapm_new_mux(struct snd_soc_dapm_widget *w) {

49

struct snd_soc_dapm_context *dapm = w->dapm; struct snd_soc_dapm_path *path; int ret;

(1) if (w->num_kcontrols != 1) { dev_err(dapm->dev,

\trols\\n\,

w->name); return -EINVAL; }

if (list_empty(&w->sources)) { dev_err(dapm->dev, \, w->name); return -EINVAL; }

(2) ret = dapm_create_or_share_mixmux_kcontrol(w, 0); if (ret < 0)

return ret;

(3) list_for_each_entry(path, &w->sources, list_sink) dapm_kcontrol_add_path(w->kcontrols[0], path); return 0; }

(1) 对于mux类型的widget,因为只会有一个kcontrol,所以在这里做一下判断。

(2) 同样地,和mixer类型一样,也使用

dapm_create_or_share_mixmux_kcontrol来创建这个kcontrol。

(3) 对每个输入端所连接的path都加入dapm_kcontrol_data结构的paths链表中,并且创建一个影子widget,用于支持autodisable特性。 dapm pga kcontrol

目前对于pga类型的widget,kcontrol的创建函数是个空函数,所以我们不用太关注它:

[cpp] view plaincopy

static int dapm_new_pga(struct snd_soc_dapm_widget *w) {

if (w->num_kcontrols)

dev_err(w->dapm->dev,

\\, w->name);

return 0;

50


ALSA声卡驱动详解(10).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:龙虎山风景区上清镇水生态文明自主创建项目实施方案 - 图文

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: