ALSA声卡驱动详解(9)

2019-08-31 00:43

\rol %s\\n\,

widget->name); ret = -ENOMEM; break; } widget++; }

......

return ret; }

该函数只是简单的一个循环,为传入的widget模板数组依次调用

snd_soc_dapm_new_control函数,实际的工作由snd_soc_dapm_new_control完成,继续进入该函数,看看它做了那些工作。

我们之前已经说过,驱动中定义的snd_soc_dapm_widget数组,只是作为一个模板,所以,snd_soc_dapm_new_control所做的第一件事,就是为该widget重新分配内存,并把模板的内容拷贝过来:

[cpp] view plaincopy

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; int ret;

if ((w = dapm_cnew_widget(widget)) == NULL) return NULL;

由dapm_cnew_widget完成内存申请和拷贝模板的动作。接下来,根据widget的类型做不同的处理: [cpp] view plaincopy

switch (w->id) {

case snd_soc_dapm_regulator_supply:

w->regulator = devm_regulator_get(dapm->dev, w->name);

......

if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {

ret = regulator_allow_bypass(w->regulator, true);

......

41

}

break;

case snd_soc_dapm_clock_supply: #ifdef CONFIG_CLKDEV_LOOKUP

w->clk = devm_clk_get(dapm->dev, w->name); ...... #else

return NULL; #endif

break; default:

break; }

对于snd_soc_dapm_regulator_supply类型的widget,根据widget的名称获取对应的regulator结构,对于snd_soc_dapm_clock_supply类型的widget,根据widget的名称,获取对应的clock结构。接下来,根据需要,在widget的名称前加入必要的前缀:

[cpp] view plaincopy widget的power_check回调函数 widget类型 power_check回调函数 mixer类: snd_soc_dapm_switch dapm_generic_check_power snd_soc_dapm_mixer snd_soc_dapm_mixer_named_ctl mux类: snd_soc_dapm_mux snd_soc_dapm_mux snd_soc_dapm_mux snd_soc_dapm_dai_out snd_soc_dapm_dai_in 端点类: snd_soc_dapm_adc snd_soc_dapm_aif_out snd_soc_dapm_dac snd_soc_dapm_aif_in snd_soc_dapm_pga snd_soc_dapm_out_drv snd_soc_dapm_input snd_soc_dapm_output snd_soc_dapm_micbias dapm_generic_check_power dapm_adc_check_power dapm_dac_check_power dapm_generic_check_power 42

snd_soc_dapm_spk snd_soc_dapm_hp snd_soc_dapm_mic snd_soc_dapm_line snd_soc_dapm_dai_link 电源/时钟/影子widget: snd_soc_dapm_supply snd_soc_dapm_regulator_supply dapm_supply_check_power snd_soc_dapm_clock_supply snd_soc_dapm_kcontrol dapm_always_on_check_power 其它类型 if (dapm->codec && dapm->codec->name_prefix) w->name = kasprintf(GFP_KERNEL, \,

dapm->codec->name_prefix, widget->name); else

w->name = kasprintf(GFP_KERNEL, \, widget->name); 然后,为不同类型的widget设置合适的power_check电源状态回调函数,widget类型和对应的power_check回调函数设置如下表所示:

当音频路径发生变化时,power_check回调会被调用,用于检查该widget的电源状态是否需要更新。power_check设置完成后,需要设置widget所属的codec、platform和dapm context,几个用于音频路径的链表也需要初始化,然后,把该widget加入到声卡的widgets链表中: [cpp] view plaincopy 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); 几个链表的作用如下:

sources 用于链接所有连接到该widget输入端的snd_soc_path结构 sinks 用于链接所有连接到该widget输出端的snd_soc_path结构 list 用于链接到声卡的widgets链表

dirty 用于链接到声卡的dapm_dirty链表 最后,把widget设置为connect状态: [cpp] view plaincopy

/* machine layer set ups unconnected pins and insertions */ w->connected = 1; return w;

43

connected字段代表着引脚的连接状态,目前,只有以下这些widget使用connected字段:

snd_soc_dapm_output snd_soc_dapm_input snd_soc_dapm_hp snd_soc_dapm_spk snd_soc_dapm_line snd_soc_dapm_vmid snd_soc_dapm_mic snd_soc_dapm_siggen

驱动程序可以使用以下这些api来设置引脚的连接状态: snd_soc_dapm_enable_pin

snd_soc_dapm_force_enable_pin snd_soc_dapm_disable_pin snd_soc_dapm_nc_pin

到此,widget已经被正确地创建并初始化,而且被挂在声卡的widgets链表中,以后我们就可以通过声卡的widgets链表来遍历所有的widget,再次强调一下snd_soc_dapm_new_controls函数所完成的主要功能:

为widget分配内存,并拷贝参数中传入的在驱动中定义好的模板 设置power_check回调函数

把widget挂在声卡的widgets链表中 为widget建立dapm kcontrol

定义一个widget,我们需要指定两个很重要的内容:一个是用于控制widget的电源状态的reg/shift等寄存器信息,另一个是用于控制音频路径切换的dapm kcontrol信息,这些dapm kcontrol有它们自己的reg/shift寄存器信息用于切换widget的路径连接方式。前一节的内容中,我们只是创建了widget的实例,并把它们注册到声卡的widgts链表中,但是到目前为止,包含在widget中的dapm kcontrol并没有建立起来,dapm框架在声卡的初始化阶段,等所有的widget(包括machine、platform、codec)都创建好之后,通过

snd_soc_dapm_new_widgets函数,创建widget内包含的dapm kcontrol,并初始化widget的初始电源状态和音频路径的初始连接状态。我们看看声卡的初始化函数,都有那些初始化与dapm有关: [cpp] view plaincopy

static int snd_soc_instantiate_card(struct snd_soc_card *card) {

......

/* card bind complete so register a sound card */

ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,

card->owner, 0, &card->snd_card); ......

44

card->dapm.bias_level = SND_SOC_BIAS_OFF; card->dapm.dev = card->dev; card->dapm.card = card;

list_add(&card->dapm.list, &card->dapm_list);

#ifdef CONFIG_DEBUG_FS

snd_soc_dapm_debugfs_init(&card->dapm, card->debugfs_card_root); #endif

......

if (card->dapm_widgets) /* 创建machine级别的widget */

snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets,

card->num_dapm_widgets); ......

snd_soc_dapm_link_dai_widgets(card); /* 连接dai widget */

if (card->controls) /* 建立machine级别的普通kcontrol控件 */

snd_soc_add_card_controls(card, card->controls, card->num_controls);

if (card->dapm_routes) /* 注册machine级别的路径连接信息 */

snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes,

card->num_dapm_routes); ......

if (card->fully_routed) /* 如果该标志被置位,自动把codec中没有路径连接信息的引脚设置为无用widget */ list_for_each_entry(codec, &card->codec_dev_list, card_list)

snd_soc_dapm_auto_nc_codec_pins(codec);

snd_soc_dapm_new_widgets(card); /*初始化widget包含的dapm kcontrol、电源状态和连接状态*/

ret = snd_card_register(card->snd_card); ......

card->instantiated = 1;

45


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

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

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

马上注册会员

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