Chinaunix首页 | 论坛 | 博客
  • 博客访问: 288930
  • 博文数量: 68
  • 博客积分: 1121
  • 博客等级: 少尉
  • 技术积分: 634
  • 用 户 组: 普通用户
  • 注册时间: 2011-04-01 09:43
文章分类
文章存档

2014年(1)

2013年(8)

2012年(37)

2011年(22)

分类: LINUX

2011-07-06 16:19:13

转载地址:http://blog.chinaunix.net/space.php?uid=20564848&do=blog&id=74735

谈谈amixer controls命令以及widget微件controls数据合成

widget微件
# amixer controls执行命令

应用层
alsa-lib库
amixer controls
controls
snd_hctl_load
snd_ctl_elem_list(hctl->ctl, &list); 第一次hctl->space等于NULL,所以只是返回list.count个数,之后calloc list.count个空间,再次读取实际数据[luther.gliethttp]
ctl->ops->element_list(ctl, list); 也就是snd_ctl_hw_ops.snd_ctl_hw_elem_list
snd_ctl_hw_elem_list
ioctl(hw->fd, SNDRV_CTL_IOCTL_ELEM_LIST, list);
show_control_id // 打印显示比如:numid=12,iface=MIXER,name='Master Playback Switch'
    printf("numid=%u,iface=%s,name='%s'",
           snd_ctl_elem_id_get_numid(id),
           control_iface(id),

内核层
core/control.c
snd_ctl_f_ops.snd_ctl_ioctl
{
snd_soc_new_pcms
snd_card_create
snd_ctl_create
snd_ctl_dev_register 创建"controlC%i"声卡对应的控制节点,
他的fops为snd_ctl_f_ops
}
snd_ctl_ioctl
    case SNDRV_CTL_IOCTL_ELEM_LIST:
        return snd_ctl_elem_list(card, argp);
snd_ctl_elem_list
    while (space > 0 && plist != &card->controls) { // 遍历card->controls链表上的所有登记数据,当然包括微件widget合成的数据
            kctl = snd_kcontrol(plist);
            for (jidx = offset; space > 0 && jidx < kctl->count; jidx++) {
                snd_ctl_build_ioff(id, kctl, jidx);
                id++;
                space--;
                list.used++;
            }
            plist = plist->next;
            offset = 0;
        }

看看codec特有的controls都在什么时候登记到card->controls链表上的
wm8991_codec_probe
wm8991_add_controls // 将wm8991_snd_controls[]数组中的所有control条目添加到card->controls链表上
for (i = 0; i < ARRAY_SIZE(wm8991_snd_controls); i++) {
    snd_ctl_add(codec->card, snd_soc_cnew(&wm8991_snd_controls[i],codec, NULL))
    // 最终list_add_tail(&kcontrol->list, &card->controls);
}

关于widget微件control数据的添加[luther.gliethttp]
wm8991_add_widgets
    for (i = 0; i < ARRAY_SIZE(wm8991_dapm_widgets); i++)
        snd_soc_dapm_new_control(codec, &wm8991_dapm_widgets[i]); // 添加自己的widget微件到codec->dapm_widgets链表
    /* set up the WM8991 audio map */
====================
/* dapm widget types */
enum snd_soc_dapm_type {
    snd_soc_dapm_input = 0,        /* input pin */
    snd_soc_dapm_output,        /* output pin */
    snd_soc_dapm_mux,            /* selects 1 analog signal from many inputs */
    snd_soc_dapm_mixer,            /* mixes several analog signals together */
    snd_soc_dapm_pga,            /* programmable gain/attenuation (volume) */
    snd_soc_dapm_adc,            /* analog to digital converter */
    snd_soc_dapm_dac,            /* digital to analog converter */
    snd_soc_dapm_micbias,        /* microphone bias (power) */
    snd_soc_dapm_mic,            /* microphone */
    snd_soc_dapm_hp,            /* headphones */
    snd_soc_dapm_spk,            /* speaker */
    snd_soc_dapm_line,            /* line input/output */
    snd_soc_dapm_switch,        /* analog switch */
    snd_soc_dapm_vmid,            /* codec bias/vmid - to minimise pops */
    snd_soc_dapm_pre,            /* machine specific pre widget - exec first */
    snd_soc_dapm_post,            /* machine specific post widget - exec last */
};
static const char *audio_map[][3] = {
    ......
    {"LOMIX", "LOMIX Left DAC Switch", "Left DAC"},
    ......
};
====================
// 加入类似link软连接的机制
    for (i = 0; audio_map[i][0] != NULL; i++) {
        snd_soc_dapm_connect_input(codec, audio_map[i][0],
                audio_map[i][1], audio_map[i][2]);
    }
/**
 * snd_soc_dapm_connect_input - connect dapm widgets
 * @codec: audio codec
 * @sink: name of target widget
 * @control: mixer control name
 * @source: name of source name
 *
 * Connects 2 dapm widgets together via a named audio path. The sink is
 * the widget receiving the audio signal, whilst the source is the sender
 * of the audio signal.
 *
 * Returns 0 for success else error.
 */
int snd_soc_dapm_connect_input(struct snd_soc_codec *codec, const char *sink,
    const char * control, const char *source);

wm8991_add_widgets
snd_soc_dapm_new_widgets
dapm_new_mixer // 将上面snd_soc_dapm_connect_input合成的widget微件连接信息添加到card->controls链表上的合成控制通道[luther.gliethttp]
/* create new dapm mixer control */
static int dapm_new_mixer(struct snd_soc_codec *codec,
    struct snd_soc_dapm_widget *w)
{
    int i, ret = 0;
    char name[32];
    struct snd_soc_dapm_path *path;

    /* add kcontrol */
    for (i = 0; i < w->num_kcontrols; i++) {
        /* match name */
        list_for_each_entry(path, &w->sources, list_sink) {
            /* mixer/mux paths name must match control name */
            if (path->name != (char*)w->kcontrols[i].name)
                continue;
            /* add dapm control with long name */
            snprintf(name, 32, "%s %s", w->name, w->kcontrols[i].name); // 合成出来的name,不能超过32字节
            path->long_name = kstrdup (name, GFP_KERNEL);
            if (path->long_name == NULL)
                return -ENOMEM;
            path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w,
                path->long_name);
            ret = snd_ctl_add(codec->card, path->kcontrol); // 将该合成出来的control添加到card->controls链表上
            // 同时通过snd_ctl_find_hole(card, kcontrol->count);函数[luther.gliethttp]
            // 生成kcontrol->id.numid = card->last_numid + 1;这个numid标识号
            if (ret < 0) {
                printk(KERN_ERR "asoc: failed to add dapm kcontrol %s\n",
                        path->long_name);
                kfree(path->long_name);
                path->long_name = NULL;
                return ret;
            }
        }
    }
    return ret;
}
===下面是2.6.34内核中的实现===========================
/* create new dapm mixer control */
static int dapm_new_mixer(struct snd_soc_codec *codec,
    struct snd_soc_dapm_widget *w)
{
    int i, ret = 0;
    size_t name_len;
    struct snd_soc_dapm_path *path;

    /* add kcontrol */
    for (i = 0; i < w->num_kcontrols; i++) { // 遍历当前widget微件包含的所有w->kcontrols[]

        /* match name */
        list_for_each_entry(path, &w->sources, list_sink) { 
// 因为所有使用本微件w的->kcontrols[i]的地方都都主动的调用list_add(&path->list_sink, &dest->sources);
// 将自己生成的path的list_sink添加到了本微件w的->sources链表上,这样也便于通过path来追踪当前正在使用
// w->kcontrols[i]控制通道的所有应用程序[luther.gliethttp]

            /* mixer/mux paths name must match control name */
            if (path->name != (char*)w->kcontrols[i].name) // 地址不一致,说明不match
                continue;

            /* add dapm control with long name.
             * for dapm_mixer this is the concatenation of the
             * mixer and kcontrol name.
             * for dapm_mixer_named_ctl this is simply the
             * kcontrol name.
             */
            name_len = strlen(w->kcontrols[i].name) + 1;
            if (w->id != snd_soc_dapm_mixer_named_ctl) // 是否不进行name合成
                name_len += 1 + strlen(w->name);

            path->long_name = kmalloc(name_len, GFP_KERNEL);

            if (path->long_name == NULL)
                return -ENOMEM;

            switch (w->id) {
            default:
                snprintf(path->long_name, name_len, "%s %s",
                     w->name, w->kcontrols[i].name); // 将widget和kcontrols[i]的名字合成为登记注册时使用的新的kcontrol名字
                break;
            case snd_soc_dapm_mixer_named_ctl:
                snprintf(path->long_name, name_len, "%s",
                     w->kcontrols[i].name); // 强制使用kcontrols[i]的名字[luther.gliehttp]
                break;
            }

            path->long_name[name_len - 1] = '\0';

            path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w,
                path->long_name); // 创建一个名为path->long_name的kcontrol.
            ret = snd_ctl_add(codec->card, path->kcontrol); 
// 将其添加到card->controls链表上list_add_tail(&kcontrol->list, &card->controls);
// 这样path->long_name就是我们执行amixer controls看到的名字了
            if (ret < 0) {
                printk(KERN_ERR "asoc: failed to add dapm kcontrol %s: %d\n",
                       path->long_name,
                       ret);
                kfree(path->long_name);
                path->long_name = NULL;
                return ret;
            }
        }
    }
    return ret;
}
阅读(2935) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~