程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> alsa音頻架構2--ASoc

alsa音頻架構2--ASoc

編輯:C++入門知識

設計ASoc的目的是為嵌入式系統片上處理器音頻單元或外部的音頻解碼芯片提供更好的ALSA支持

ASoC有多個組件組成snd_soc_platform/snd_soc_codec/snd_soc_dai/snd_soc_card以及ALSA的snd_pcm

snd_soc_platform和snd_soc_codec就行平台與設備的關系缺一不可,snd_soc_card是它們實例化的一個對象

snd_soc_dai是snd_soc_platform和snd_soc_codec的數字音頻接口,snd_soc_codec的dai為codec_dai,snd_soc_platform的dai為cpu_dai

snd_pcm是snd_soc_card實例化後注冊的聲卡類型

在sound/soc/soc-core.c中初始化了上面提到的4個重要結構體的鏈表頭

[cpp]  static LIST_HEAD(card_list); 
static LIST_HEAD(dai_list); 
static LIST_HEAD(platform_list); 
static LIST_HEAD(codec_list); 

static LIST_HEAD(card_list);
static LIST_HEAD(dai_list);
static LIST_HEAD(platform_list);
static LIST_HEAD(codec_list);

第九部分 soc聲卡設備snd_soc_card

1.soc聲卡設備

[cpp] struct snd_soc_card { 
    const char *name;   //設備名  
    struct device *dev; //設備文件  
    struct snd_card *snd_card;  //所屬聲卡  
    struct module *owner; 
    struct list_head list; 
    struct mutex mutex; 
    bool instantiated;  //實例化標志  
    int (*probe)(struct platform_device *pdev); 
    int (*remove)(struct platform_device *pdev); 
    /* the pre and post PM functions are used to do any PM work before and after the codec and DAI's do any PM work. */ 
    int (*suspend_pre)(struct platform_device *pdev, pm_message_t state); 
    int (*suspend_post)(struct platform_device *pdev, pm_message_t state); 
    int (*resume_pre)(struct platform_device *pdev); 
    int (*resume_post)(struct platform_device *pdev); 
    /* callbacks */ 
    int (*set_bias_level)(struct snd_soc_card *,enum snd_soc_bias_level level); 
    long pmdown_time; 
    /* CPU <--> Codec DAI links  */ 
    struct snd_soc_dai_link *dai_link;  //dai link  
    int num_links; 
    struct snd_soc_pcm_runtime *rtd; 
    int num_rtd; 
    struct work_struct deferred_resume_work; 
    /* lists of probed devices belonging to this card */ 
    struct list_head codec_dev_list; 
    struct list_head platform_dev_list; 
    struct list_head dai_dev_list; 
}; 

struct snd_soc_card {
 const char *name; //設備名
 struct device *dev; //設備文件
 struct snd_card *snd_card; //所屬聲卡
 struct module *owner;
 struct list_head list;
 struct mutex mutex;
 bool instantiated; //實例化標志
 int (*probe)(struct platform_device *pdev);
 int (*remove)(struct platform_device *pdev);
 /* the pre and post PM functions are used to do any PM work before and after the codec and DAI's do any PM work. */
 int (*suspend_pre)(struct platform_device *pdev, pm_message_t state);
 int (*suspend_post)(struct platform_device *pdev, pm_message_t state);
 int (*resume_pre)(struct platform_device *pdev);
 int (*resume_post)(struct platform_device *pdev);
 /* callbacks */
 int (*set_bias_level)(struct snd_soc_card *,enum snd_soc_bias_level level);
 long pmdown_time;
 /* CPU <--> Codec DAI links  */
 struct snd_soc_dai_link *dai_link; //dai link
 int num_links;
 struct snd_soc_pcm_runtime *rtd;
 int num_rtd;
 struct work_struct deferred_resume_work;
 /* lists of probed devices belonging to this card */
 struct list_head codec_dev_list;
 struct list_head platform_dev_list;
 struct list_head dai_dev_list;
};

snd_soc_card包含了snd_card,可以理解為聲卡驅動的一個封裝.

2.soc pcm

[cpp]  struct snd_soc_pcm_runtime  { 
    struct device dev;          //設備文件  
    struct snd_soc_card *card;  //soc聲卡設備  
    struct snd_soc_dai_link *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;    //pcm結構體  
    struct snd_soc_codec *codec;    //codec設備  
    struct snd_soc_platform *platform;  //soc平台設備  
    struct snd_soc_dai *codec_dai;  //dai設備 codec  
    struct snd_soc_dai *cpu_dai;    //dai設備 cpu  
    struct delayed_work delayed_work; 
}; 

struct snd_soc_pcm_runtime  {
 struct device dev;   //設備文件
 struct snd_soc_card *card; //soc聲卡設備
 struct snd_soc_dai_link *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; //pcm結構體
 struct snd_soc_codec *codec; //codec設備
 struct snd_soc_platform *platform; //soc平台設備
 struct snd_soc_dai *codec_dai; //dai設備 codec
 struct snd_soc_dai *cpu_dai; //dai設備 cpu
 struct delayed_work delayed_work;
};

snd_soc_pcm_runtime結構體中包含一個snd_pcm結構體,所以可以認為它是pcm聲卡設備的一個封裝,其次他也是Asoc各個組件的一個關系網點

3.soc聲卡設備的匹配過程

在sound/soc/soc-core.c中定義了一個平台設備驅動

[cpp]  static struct platform_driver soc_driver = { 
    .driver     = { 
        .name       = "soc-audio", 
        .owner      = THIS_MODULE, 
        .pm     = &soc_pm_ops, 
    }, 
    .probe      = soc_probe, 
    .remove     = soc_remove, 
}; 

static struct platform_driver soc_driver = {
 .driver  = {
  .name  = "soc-audio",
  .owner  = THIS_MODULE,
  .pm  = &soc_pm_ops,
 },
 .probe  = soc_probe,
 .remove  = soc_remove,
};我們知道平台設備驅動和平台設備的匹配靠.driver.name名字,也就是在另一處代碼中必須定義了平台設備platform_device且設備名必須為"soc-audio",

這樣平台設備和驅動才能匹配,才會調用平台驅動的probe方法,既soc_probe

所以一般聲卡的驅動程序中會按以下格式設計平台設備

[cpp]  int ret; 
static struct platform_device *xxx; 
xxx=platform_device_alloc("soc-audio", 0);  //分配平台驅動  
//平台資源的添加  
ret=platform_device_add(xxx);   //添加平台設備  
if(ret) 
    platform_device_put(xxx);   //增加引用計數 

int ret;
static struct platform_device *xxx;
xxx=platform_device_alloc("soc-audio", 0); //分配平台驅動
//平台資源的添加
ret=platform_device_add(xxx); //添加平台設備
if(ret)
 platform_device_put(xxx); //增加引用計數

4.匹配調用的probe方法soc_probe

[cpp]  static int soc_probe(struct platform_device *pdev) 

    struct snd_soc_card *card = platform_get_drvdata(pdev); //獲取soc聲卡設備  
    int ret = 0; 
    /* Bodge while we unpick instantiation */ 
    card->dev = &pdev->dev; 
    INIT_LIST_HEAD(&card->dai_dev_list);     //初始化dai_dev_list鏈表  
    INIT_LIST_HEAD(&card->codec_dev_list);       //初始化codec_dev_list鏈表  
    INIT_LIST_HEAD(&card->platform_dev_list);    //初始化platform_dev_list鏈表  
    ret = snd_soc_register_card(card);  //注冊soc聲卡設備  
    if (ret != 0) { 
        dev_err(&pdev->dev, "Failed to register card\n"); 
        return ret; 
    } 
    return 0; 

static int soc_probe(struct platform_device *pdev)
{
 struct snd_soc_card *card = platform_get_drvdata(pdev); //獲取soc聲卡設備
 int ret = 0;
 /* Bodge while we unpick instantiation */
 card->dev = &pdev->dev;
 INIT_LIST_HEAD(&card->dai_dev_list);  //初始化dai_dev_list鏈表
 INIT_LIST_HEAD(&card->codec_dev_list);  //初始化codec_dev_list鏈表
 INIT_LIST_HEAD(&card->platform_dev_list); //初始化platform_dev_list鏈表
 ret = snd_soc_register_card(card); //注冊soc聲卡設備
 if (ret != 0) {
  dev_err(&pdev->dev, "Failed to register card\n");
  return ret;
 }
 return 0;
}這裡調用了snd_soc_register_card注冊了soc聲卡設備

5.注冊soc聲卡設備


[cpp] static int snd_soc_register_card(struct snd_soc_card *card) 

    int i; 
    if (!card->name || !card->dev) 
        return -EINVAL; 
    card->rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime) * card->num_links,GFP_KERNEL); //分配多個soc pcm內存  
    if (card->rtd == NULL) 
        return -ENOMEM; 
    for (i = 0; i < card->num_links; i++) 
        card->rtd[i].dai_link = &card->dai_link[i];   //dai link數組  
    INIT_LIST_HEAD(&card->list);  
    card->instantiated = 0;  //soc聲卡實例化標志設置為0  
    mutex_init(&card->mutex); 
 
    mutex_lock(&client_mutex); 
    list_add(&card->list, &card_list);   //添加soc聲卡到全局card_list鏈表  
    snd_soc_instantiate_cards();    //實例化所有soc聲卡  
    mutex_unlock(&client_mutex); 
    dev_dbg(card->dev, "Registered card '%s'\n", card->name); 
    return 0; 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved