zoukankan      html  css  js  c++  java
  • route_path添加过程分析

    本篇博客主要分析如何将audio_paths添加到内核中

    首先看一下,audio_paths的定义:

    static const struct snd_soc_dapm_route audio_paths[] = {
        { "Left Boost Mixer", "LINPUT1 Switch", "LINPUT1" },
        { "Left Boost Mixer", "LINPUT2 Switch", "LINPUT2" },
        { "Left Boost Mixer", "LINPUT3 Switch", "LINPUT3" },
    
        { "Left Input Mixer", "Boost Switch", "Left Boost Mixer", },
        { "Left Input Mixer", NULL, "LINPUT1", },  /* Really Boost Switch */
        { "Left Input Mixer", NULL, "LINPUT2" },
        { "Left Input Mixer", NULL, "LINPUT3" },
       .....
    };

    在代码中,使用函数snd_soc_dapm_add_routes将route添加到内核中,如下所示:

    snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths));
    /**
     * snd_soc_dapm_add_routes - Add routes between DAPM widgets
     * @dapm: DAPM context
     * @route: audio routes
     * @num: number of routes
     *
     * 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. On error all resources can be freed
     * with a call to snd_soc_card_free().
     */
    int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
                    const struct snd_soc_dapm_route *route, int num)
    {
        int i, ret;
    
        for (i = 0; i < num; i++) {
            ret = snd_soc_dapm_add_route(dapm, route);
            .....
            route++;
        }
    
        return 0;
    }
    EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);

    这个函数的关键就是snd_soc_dapm_add_route,在分析该函数之前,我们首先看一下route的种类:

    1)常规route

    {"sink" NULL "source"}

    表示由route构造出来的path->connect = 1
    2)sink widget是Mixer

    {"Mixer", name1, "source1"}
    {"Mixer", name2, "source2"}
    即:
    source1----->name1------>Mixer
    source2----->name2------>Mixer

    name1和name2代表两个snd_kcontrol_new,这两个kcontrol在Mixer widget中,该wiget含有:
    a.Mixer本身的信息
    b.2个snd_kcontrol_new: name1和name2
    可以通过操作某个kcontrol来打开某条path
    3)sink widget是Mux

    {"Mux"  value1, "source1"}
    {"Mux"  value2, "source2"}
    source1 ---------value1
                      
                       
                        -----------Mux 
    
    
    source2 --------- value2   

    Mux widget含有:
    a.Mux本身信息
    b.1个snd_kcontrol_new,它有两种取值:value和value2

    这三种route是如何转换成path的呢?
    猜测:
    1)首先要找出source widget和sink widget,至于kcontrol,这个地方不会去找。为什么?
    上篇博客中已经介绍,widget中kcontrol的创建是在machine驱动中,而这个地方只是codec驱动,还没有创建kcontrol,因此它在这个地方是不会去找的。
    2)构造path

    path->source = wsource;
    path->sink = wsink;

    3)设置
    path->connect的值:
    a.如果kcontrol = NULL,则它是一条static path,此时path->connect=1.
    b.如果kcontrol !=NULL,则它是一条dynamic path,它的path->connect是如何设置呢?
    这个地方是根据widget sink的类型决定的,
    b.1 sink widget为ADC、DAC等的path,该path一般来说都是直连的(无开关)

    snd_soc_dapm_adc
    snd_soc_dapm_dac
    snd_soc_dapm_pga
    snd_soc_dapm_out_drv
    snd_soc_dapm_input
    snd_soc_dapm_output
    snd_soc_dapm_siggen
    snd_soc_dapm_micbias
    snd_soc_dapm_vmid
    snd_soc_dapm_pre
    snd_soc_dapm_post
    snd_soc_dapm_supply
    snd_soc_dapm_regulator_supply
    snd_soc_dapm_aif_in
    snd_soc_dapm_aif_out
    snd_soc_dapm_dai
    
    //将path放入dapm->card->paths链表中
    list_add(&path->list, &dapm->card->paths);
    
    //将path的sink放入到widget的sources链表中。如何理解:
    //在widget中,source就是source,sink就是sink。而在audio_routes,即形成的path中,格式是sink---->source.
    //因此path中的sink刚好对应的是widget中的source
    list_add(&path->list_sink, &wsink->sources);
    list_add(&path->list_source, &wsource->sinks);
    path->connect = 1;

    b.2 对于sink widget是Mixer的path,path->connect 需要根据寄存器的值进行确定

    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);
                    dapm_set_path_status

    b.3 对于sink widget是Mux的path,path->connect需要根据寄存器的值进行确定

    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]);
                    dapm_set_path_status//读寄存器,通过读出来的值再去判断该path是否连通

    b.4 对于sink widget可以动态拔插的headphone、mic、line、speaker,它默认将path->connect设置为0。以后再根据实际情况,将path->connect设置为1.
    比如说,插上耳机,对应的path设置为1

    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;

    snd_soc_dapm_add_routes会导致path的创建,以及链表关系的形成,path->connect值的设置。但是注意一点:
    Mux和Mixer中snd_kcontrol此时还没有被创建,snd_kcontrol的创建是在函数snd_soc_dapm_new_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 || wsink == NULL)
            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_aif_in:
        case snd_soc_dapm_aif_out:
        case snd_soc_dapm_dai:
            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;
        }
        return 0;
    
    err:
        dev_warn(dapm->dev, "asoc: no dapm match for %s --> %s --> %s
    ",
             source, control, sink);
        kfree(path);
        return ret;
    }
    View Code
  • 相关阅读:
    SQL Server 文件规划 位置规划
    在VS2008中使用WSE 3.0过程全记录
    关于CDC功能的答疑
    SQL Server 2008 : 基于策略的管理(PolicyBased Management)
    使用 Google Gears 开发离线应用
    SQL Server 2008 :安装
    WCF 之UserName身份验证全记录
    SQL Server 文件规划 文件组
    不可思议的SQLite
    使用Trigger让UpdatePanel外部的控件也支持无刷新异步调用
  • 原文地址:https://www.cnblogs.com/-glb/p/14414358.html
Copyright © 2011-2022 走看看