ALSA中Widget、route、kcontrol 命名規則

 

對於上面的命名規則,我一直很疑惑,那天我仔細的研究了下:

Kcontrol:

對於struct snd_kcontrol_new結構體裏面有以下主要成員:

1、  iface:是定義了kcontrol 的類型,有很多的類型通常以SND_CTL_ELEM_IFACE_xxx定義,有muxmixercardmaster等一些類型

2、  aceee:設置訪問的權限,也是有宏實現好的,SNDRV_CTL_ELEM_ACESS_READ是值讀的,這個時候,在結構體裏面的put函數就沒有必要實現了,如果是SNDRV_CTL_ELEM_ACESS_WRITE就意味着是隻寫的,這個時候get函數就沒有必要實現了。加入control 的值頻繁的變化的話,那麼就設置acess的值是VOLATILE。當control 的值處於非激活狀態的時候應設置INACTIVE標誌

3、  private_value:是包含一個長整型的值,這個值裏面很重要,這個裏面的值會傳遞給info()get()put()這些callback function使用,這個private_value裏面有很多的成員,下面我會舉例說明下

4、  name:這個成員也是非常重要的成員,因爲kcontrol的作用是由名稱來區分的,對於相同名稱的kcontrol 則用index 區分的,對於mixer通路就是通過和route.control_namewidget中找到合適的kcontrol ,對於mux 是根據route.control_namekcontrolprivate_data裏面的txt數組裏面的名字匹配的

這個private_data有很多的宏可以定義,定義的成員有主要有以下幾個:

         4.1:reg_left指的是register的值,這個代表是左聲道的register

         4.2:reg_right指的是register的值,這個代表是右聲道的register

         4.3:xshift指的控制的位偏移,其實就是的功能的那個位開始,爲頭

         4.4:max:指的是控制的功能在codec register中時由幾位控制的

         4.5:invert:看英文的意思就是反轉的意思,o代表是不反轉的意思,1代表反轉的意思,如果反轉的話,那麼設置的值越大結構也就越大,如果是不反轉的話,那麼效果和反轉是相反的。

5、  這個name 的定義還有一些標準的規則,”SOURCE,DIRECTION,FUNCTION” 中文的定義是源,方向,功能”SOURCE是定義控制的源,例如PCMMasterDIRECTION

控制的方向如:captureplayback,如果FUNCTION省略的話,那麼就代表是雙向的。FUNCTION是功能:switchVolumeroute

6、  put:kcontrol 對於很多的switch slider應用廣泛,它可以被用戶控件進行存取,從而達到讀寫codec register的作用,當上層需要寫codec register的時候,就會最終調用到這個put函數

7、  get:根據名字也可以看出,get是得到數據就從codec中得到數據,就是read ,上層如果要從codec 中讀取數據的時候,最終就會調用到這個read 函數

snd_soc_dapm_add_routes

上面的函數會進行route 的添加和path 的創建

Route 的命名規則是:route(sink,control,source),sink 是目的的widget,control control 的名字,這個control其實就是sink裏面的control 就是sink 裏面的controlsource是源widget,上面route的定義的意思是:通過sink中的kcontrol控制達到source---àsinkpath 的控制

snd_soc_dapm_add_routes函數裏面會進行如下動作

1、  會根據route 裏面的sink source的名字找到名字相同的widget,然後創建path ,將找到的widget賦值給path

2、  設置widget是否是extern widget,path connect 的狀態,主要分爲幾種類型:static dynamic、兩種類型,有的widget開始就是處於connect status,就不需要自己去通過kcontrol 去連接,下面去講解下muxmixer着兩種case

Case mux:

dapm_connect_mux函數

staticint dapm_connect_mux(struct snd_soc_dapm_context *dapm,

    struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,

    struct snd_soc_dapm_path *path, constchar *control_name,

    conststruct snd_kcontrol_new *kcontrol)

{

    struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;

    int i;

 

    for (i = 0; i < e->max; i++) {

        if (!(strcmp(control_name, e->texts[i]))) {

            list_add(&path->list, &dapm->card->paths);

            list_add(&path->list_sink, &dest->sources);

            list_add(&path->list_source, &src->sinks);

            path->name = (char*)e->texts[i];

            dapm_set_path_status(dest, path, 0);

            return 0;

        }

    }

 

    return -ENODEV;

}

看上面的代碼,我們就會發現,我們會將route 中的control_name和這個widget.private_data.txt[i]中的名字數組進行對比,如果一樣的話,就代表這個widget中的kcontrol 可以控制這個path 的通路的

接下來我們再看兩外一個函數:

Case: mixer

dapm_connect_mixer:會創建關於mixer相關的path

/* connect mixer widget to its interconnecting audio paths */

staticint dapm_connect_mixer(struct snd_soc_dapm_context *dapm,

    struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,

    struct snd_soc_dapm_path *path, constchar *control_name)

{

    int i;

 

    /* search for mixer kcontrol */

    for (i = 0; i < dest->num_kcontrols; i++) {

        if (!strcmp(control_name, dest->kcontrols[i].name)) {

            list_add(&path->list, &dapm->card->paths);

            list_add(&path->list_sink, &dest->sources);

            list_add(&path->list_source, &src->sinks);

            path->name = dest->kcontrols[i].name;

            dapm_set_path_status(dest, path, i);

            return 0;

        }

    }

    return -ENODEV;

}

看了上面的代碼,你會發現我們會發現我們的widget裏面有很多的kcontrol 數組,我們再創建path 的時候,我們會根據route control name mixer widget中的kcontrol 數組裏面的kocntrol .name 進行匹配,如果成功的話,那麼纔會創建這個path

接下來我們再看另外一個函數:

dapm_set_path_status:這個函數會判斷我們的創建的path 的通路的狀態

/* set up initial codec paths */

staticvoid dapm_set_path_status(struct snd_soc_dapm_widget *w,

    struct snd_soc_dapm_path *p, int i)

{

    switch (w->id) {

    case snd_soc_dapm_switch:

    case snd_soc_dapm_mixer:

    case snd_soc_dapm_mixer_named_ctl: {

        int val;

        struct soc_mixer_control *mc = (struct soc_mixer_control *)

            w->kcontrols[i].private_value;

        unsignedint reg = mc->reg;

        unsignedint shift = mc->shift;

        int max = mc->max;

        unsignedint mask = (1 << fls(max)) - 1;

        unsignedint invert = mc->invert;

 

        val = snd_soc_read(w->codec, reg);

        val = (val >> shift) & mask;

 

        if ((invert && !val) || (!invert && val))

            p->connect = 1;

        else

            p->connect = 0;

    }

    break;

    case snd_soc_dapm_mux: {

        struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value;

        int val, item, bitmask;

 

        for (bitmask = 1; bitmask < e->max; bitmask <<= 1)

        ;

        val = snd_soc_read(w->codec, e->reg);

        item = (val >> e->shift_l) & (bitmask - 1);

 

        p->connect = 0;

        for (i = 0; i < e->max; i++) {

            if (!(strcmp(p->name, e->texts[i])) && item == i)

                p->connect = 1;

        }

    }

    break;

    case snd_soc_dapm_virt_mux: {

        struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value;

 

        p->connect = 0;

        /* since a virtual mux has no backing registers to

         * decide which path to connect, it will try to match

         * with the first enumeration.  This is to ensure

         * that the default mux choice (the first) will be

         * correctly powered up during initialization.

         */

        if (!strcmp(p->name, e->texts[0]))

            p->connect = 1;

    }

    break;

    case snd_soc_dapm_value_mux: {

        struct soc_enum *e = (struct soc_enum *)

            w->kcontrols[i].private_value;

        int val, item;

 

        val = snd_soc_read(w->codec, e->reg);

        val = (val >> e->shift_l) & e->mask;

        for (item = 0; item < e->max; item++) {

            if (val == e->values[item])

                break;

        }

 

        p->connect = 0;

        for (i = 0; i < e->max; i++) {

            if (!(strcmp(p->name, e->texts[i])) && item == i)

                p->connect = 1;

        }

    }

    break;

    /* does not effect routing - always connected */

    case snd_soc_dapm_pga:

    case snd_soc_dapm_out_drv:

    case snd_soc_dapm_output:

    case snd_soc_dapm_adc:

    case snd_soc_dapm_input:

    case snd_soc_dapm_dac:

    case snd_soc_dapm_micbias:

    case snd_soc_dapm_vmid:

    case snd_soc_dapm_supply:

    case snd_soc_dapm_aif_in:

    case snd_soc_dapm_aif_out:

        p->connect = 1;

    break;

    /* does effect routing - dynamically connected */

    case snd_soc_dapm_hp:

    case snd_soc_dapm_mic:

    case snd_soc_dapm_spk:

    case snd_soc_dapm_line:

    case snd_soc_dapm_pre:

    case snd_soc_dapm_post:

        p->connect = 0;

    break;

    }

}

這個函數,我自我感覺重要性還是很強的,我講解下兩種情況:

1case snd_soc_dapm_switch:

    case snd_soc_dapm_mixer:

    case snd_soc_dapm_mixer_named_ctl:

這個case 我們會根據shiftinvertmaxreg的值,找出控制這個控制這個path kcontrol register的某幾位,然後根據這幾位的值,判斷path 的狀態,我們再定義widget的時候,也是需要按照datasheet中的值進行定義widget

2case snd_soc_dapm_mux: {

        struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value;

        int val, item, bitmask;

 

        for (bitmask = 1; bitmask < e->max; bitmask <<= 1)

        ;

        val = snd_soc_read(w->codec, e->reg);

        item = (val >> e->shift_l) & (bitmask - 1);

 

        p->connect = 0;

        for (i = 0; i < e->max; i++) {

            if (!(strcmp(p->name, e->texts[i])) && item == i)

                p->connect = 1;

        }

對於上面的case ,我們會會讀取出reg的值,將讀取出來的值獲取到item 的值,我們會將path.name widget.private_data.txt[i]中的name數組進行對比,首先是必須相等,然後就是從reg中的item必須和匹配i的值是相等的,這就要求我們在定義這個txt檔的時候,必須和datasheet中定義的順序是一致的;舉例如下:

staticconstchar *linput_mux_text[] = {

    "IN1L", "IN2L", "IN3L"

};

 

看到上面的datasheet中值的順序嗎。這也是按照這種順序過來的,不然我們的item 的匹配時不會成功的

發佈了18 篇原創文章 · 獲贊 11 · 訪問量 37萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章