alsa結構體流程2

來源:互聯網
上載者:User

Control介面主要讓使用者空間的應用程式(alsa-lib)可以訪問和控制音頻codec晶片中的多路開關,滑動控制項等。

我們需要在我們的驅動程式初始化時主動調用snd_pcm_new()函數建立pcm裝置,而control裝置則在snd_card_create()內被建立,

snd_card_create()通過調用snd_ctl_create()函數建立control裝置節點。所以我們無需顯式地建立control裝置,只要建立音效卡,control裝置被自動地建立。

同樣,它有一個snd_ctl_dev_register,它調用:

  1. snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,   &snd_ctl_f_ops, card, name)

/*
 *  INIT PART
 */

static const struct file_operations snd_ctl_f_ops =
{
    .owner =    THIS_MODULE,
    .read =        snd_ctl_read,
    .open =        snd_ctl_open,
    .release =    snd_ctl_release,
    .llseek =    no_llseek,
    .poll =        snd_ctl_poll,
    .unlocked_ioctl =    snd_ctl_ioctl,
    .compat_ioctl =    snd_ctl_ioctl_compat,
    .fasync =    snd_ctl_fasync,

};

使用者程式需要開啟control裝置時,驅動程式通過snd_minors[]全域數組和此裝置號,可以獲得snd_ctl_f_ops結構中的各個回呼函數,

然後通過這些回呼函數訪問control中的資訊和資料(最終會調用control的幾個回呼函數get,put,info)。可以讀一下代碼:/sound/core/control.c。

ASoC--ALSA System on Chip ,是建立在標準ALSA驅動層上,為了更好地支援嵌入式處理器和行動裝置中的音頻Codec的一套軟體體系。

目前已經被整合至核心的代碼樹中:sound/soc。ASoC不能單獨存在,他只是建立在標準ALSA驅動上的一個它必須和標準的ALSA驅動架構相結合才能工作。

通常,就像軟體領域裡的抽象和重用一樣,嵌入式裝置的音頻系統可以被劃分為板載硬體(Machine)、Soc(Platform)、Codec三大部分,如所示:

                                        音頻系統結構

ASoC中重要的資料結構之間的關聯方式:

                                                                                                      Kernel-2.6.35-ASoC中各個結構的靜態關係

                                                                                             Kernel 3.0中的ASoC資料結構

3.0中的資料結構更為合理和清晰,取消了snd_soc_device結構,直接用snd_soc_card取代了它,並且強化了snd_soc_pcm_runtime的作用,同時還增加了另外兩個資料結構snd_soc_codec_driver和snd_soc_platform_driver,用於明確代表Codec驅動和Platform驅動。

/* SoC audio ops */
struct snd_soc_ops {
    int (*startup)(struct snd_pcm_substream *);
    void (*shutdown)(struct snd_pcm_substream *);
    int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *);
    int (*hw_free)(struct snd_pcm_substream *);
    int (*prepare)(struct snd_pcm_substream *);
    int (*trigger)(struct snd_pcm_substream *, int);
};

它的作用是什麼呢???

通過snd_soc_card結構,又引出了Machine驅動的另外兩個個資料結構:

  • snd_soc_dai_link(執行個體:smdk_dai[] )
  • snd_soc_ops(執行個體:smdk_ops )

其中,snd_soc_dai_link中,指定了Platform、Codec、codec_dai、cpu_dai的名字,稍後Machine驅動將會利用這些名字去匹配已經在系統中註冊的platform,codec,dai,這些註冊的組件都是在另外相應的Platform驅動和Codec驅動的代碼檔案中定義的,這樣看來,Machine驅動的裝置初始化代碼無非就是選擇合適Platform和Codec以及dai,用他們填充以上幾個資料結構,然後註冊Platform裝置即可。當然還要實現串連Platform和Codec的dai_link對應的ops實現,本例就是smdk_ops,它只實現了hw_params函數:smdk_hw_params。

platform_driver通過其probe串連了snd_soc_card,其中的dai_link(snd_soc_dai_link類型)串連了snd_soc_ops結構體。

snd_soc_card的prope函數在platform匯流排匹配platform_device和platform_driver時會被調用,它調用snd_soc_register_card,通過snd_soc_register_card,。。。,大部分的工作都在snd_soc_instantiate_card中實現。

該函數首先利用card->instantiated來判斷該卡是否已經執行個體化,如果已經執行個體化則直接返回,否則遍曆每一對dai_link,進行codec、platform、dai的綁定工作:

/* bind DAIs */
    for (i = 0; i < card->num_links; i++)
        soc_bind_dai_link(card, i);

ASoC定義了三個全域的鏈表頭變數:codec_list、dai_list、platform_list,系統中所有的Codec、DAI、Platform都在註冊時串連到這三個全域鏈表上。soc_bind_dai_link函數逐個掃描這三個鏈表,根據card->dai_link[]中的名稱進行匹配,匹配後把相應的codec,dai和platform執行個體賦值到card->rtd[]中(snd_soc_pcm_runtime)。經過這個過程後,snd_soc_pcm_runtime:(card->rtd)中儲存了本Machine中使用的Codec,DAI和Platform驅動的資訊。

/* SoC machine DAI configuration, glues a codec and cpu DAI together */
struct snd_soc_pcm_runtime  {
    struct device dev;
    struct snd_soc_card *card;
    struct snd_soc_dai_link *dai_link;

    unsigned int complete:1;
    unsigned int dev_registered:1;

    /* Symmetry data - only valid if symmetry is being enforced */
    unsigned int rate;
    long pmdown_time;

    /* runtime devices */
    struct snd_pcm *pcm;
    struct snd_soc_codec *codec;
    struct snd_soc_platform *platform;
    struct snd_soc_dai *codec_dai;
    struct snd_soc_dai *cpu_dai;

    struct delayed_work delayed_work;
};

snd_soc_instantiate_card接著初始化Codec的寄存器緩衝,然後調用標準的alsa函數建立音效卡執行個體: 


  1. /* card bind complete so register a sound card */  
  2. ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,  card->owner, 0, &card->snd_card);  
  3. card->snd_card->dev = card->dev;  
  4. card->dapm.bias_level = SND_SOC_BIAS_OFF;  
  5. card->dapm.dev = card->dev;  
  6. card->dapm.card = card;  
  7. list_add(&card->dapm.list, &card->dapm_list); 

然後,依次調用各個子結構的probe函數:

/* initialise the sound card only once */
    if (card->probe) {
        ret = card->probe(card); //可能是空的
        if (ret < 0)
            goto card_probe_error;
    }

    for (i = 0; i < card->num_links; i++) {
        ret = soc_probe_dai_link(card, i);
        if (ret < 0) {
            pr_err("asoc: failed to instantiate card %s: %d\n",
                   card->name, ret);
            goto probe_dai_err;
        }
    }

在上面的soc_probe_dai_link()函數中做了比較多的事情,該函數除了挨個調用了codec,dai和platform驅動的probe函數外,

在最後還調用了soc_new_pcm()函數用於建立標準alsa驅動的pcm邏輯裝置。(它會調用:

ret = snd_pcm_new(rtd->card->snd_card, new_name,
            num, playback, capture, &pcm);

)

調用標準alsa驅動中的建立pcm的函數snd_pcm_new()建立音效卡的pcm執行個體,pcm的private_data欄位設定為該runtime變數rtd,然後用platform驅動中的snd_pcm_ops替換部分pcm中的snd_pcm_ops欄位,最後,調用platform驅動的pcm_new回調,該回調實現該platform下的dma記憶體申請和dma初始化等相關工作。到這裡,音效卡和他的pcm執行個體建立完成。

回到snd_soc_instantiate_card函數,完成snd_card和snd_pcm的建立後,接著對dapm和dai支援的格式做出一些初始化合設定工作後,調用了 card->late_probe(card)進行一些最後的初始化合設定工作,最後則是調用標準alsa驅動的音效卡註冊函數對音效卡進行註冊:

//damp controls
    if (card->dapm_widgets)
        snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets,
                      card->num_dapm_widgets);
    if (card->dapm_routes)
        snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes,
                    card->num_dapm_routes);

。。。

     //in init.c
    //create card device, register all the devices on the card.
    ret = snd_card_register(card->snd_card);
    if (ret < 0) {
        printk(KERN_ERR "asoc: failed to register soundcard for %s\n", card->name);
        goto probe_aux_dev_err;
    }

至此,整個Machine驅動的初始化已經完成,通過各個子結構的probe調用,實際上,也完成了部分Platfrom驅動和Codec驅動的初始化工作,整個過程可以用一下的順序圖表表示:

                                                                               基於3.0核心  soc_probe順序圖表

                                                                              基於2.6.35  soc_probe順序圖表

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.