linux-alsa详解5 ASOC-platform

1 Platform驱动在ASoC中的作用

前面几章内容已经说过,ASoC被分为Machine,Platform和Codec三大部件,Platform驱动的主要作用是完成音频数据的管理,最终通过CPU的数字音频接口(DAI)把音频数据传送给Codec进行处理,最终由Codec输出驱动耳机或者是喇叭的音信信号.在具体实现上,ASoC有把Platform驱动分为两个部分:snd_soc_platform_driver和snd_soc_dai_driver.其中,platform_driver负责管理音频数据,把音频数据通过dma或其他操作传送至cpu dai中,dai_driver则主要完成cpu一侧的dai的参数配置,同时也会通过一定的途径把必要的dma等参数与snd_soc_platform_driver进行交互。

2 snd_soc_platform_driver的注册

通常,ASoC把snd_soc_platform_driver注册为一个系统的platform_driver,不要被这两个相像的术语所迷惑,前者只是针对ASoC子系统的,后者是来自Linux的设备驱动模型.我们要做的就是:

(1)定义一个snd_soc_platform_driver结构的实例;

(2)在platform_driver的probe回调中利用ASoC的API:snd_soc_register_platform()注册上面定义的实例;

(3)实现snd_soc_platform_driver中的各个回调函数;

先看snd_soc_platform_driver的注册函数,定义位于sound\soc\soc-core.c

 1 /**
 2  * snd_soc_register_platform - Register a platform with the ASoC core
 3  *
 4  * @dev: The device for the platform
 5  * @platform_drv: The driver for the platform
 6  */
 7 int snd_soc_register_platform(struct device *dev,
 8         const struct snd_soc_platform_driver *platform_drv)
 9 {
10     struct snd_soc_platform *platform;// 建立platfrom结构体
11     int ret;
12 
13     dev_dbg(dev, "ASoC: platform register %s\n", dev_name(dev));
14 
15     platform = kzalloc(sizeof(struct snd_soc_platform), GFP_KERNEL);//分配platform结构体
16     if (platform == NULL)
17         return -ENOMEM;
18 
19     ret = snd_soc_add_platform(dev, platform, platform_drv);//向soc添加platfrom
20     if (ret)
21         kfree(platform);
22 
23     return ret;
24 }

 其中platfrom结构体定义位于include\sound\soc.h,如下:

1 struct snd_soc_platform {
2     struct device *dev;
3     const struct snd_soc_platform_driver *driver;
4 
5     struct list_head list;//链表,用于将该platfrom挂载到platfrom_list中
6 
7     struct snd_soc_component component;//component单元,连接platfrom和codec的桥梁
8 }

第二个参数为结构体snd_soc_platform_driver,platfrom对应的driver,定义位于:

 1 /* SoC platform interface */
 2 struct snd_soc_platform_driver {
 3 
 4     int (*probe)(struct snd_soc_platform *);
 5     int (*remove)(struct snd_soc_platform *);
 6     struct snd_soc_component_driver component_driver;
 7 
 8     /* pcm creation and destruction */
 9     int (*pcm_new)(struct snd_soc_pcm_runtime *);
10     void (*pcm_free)(struct snd_pcm *);
11 
12     /*
13      * For platform caused delay reporting.
14      * Optional.
15      */
16     snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *,
17         struct snd_soc_dai *);
18 
19     /* platform stream pcm ops */
20     const struct snd_pcm_ops *ops;
21 
22     /* platform stream compress ops */
23     const struct snd_compr_ops *compr_ops;
24 
25     int (*bespoke_trigger)(struct snd_pcm_substream *, int);
26 }

2.2 函数snd_soc_add_platform

下面建立初始化的第一个component是struct snd_soc_platform

 1 /**
 2  * snd_soc_add_platform - Add a platform to the ASoC core
 3  * @dev: The parent device for the platform
 4  * @platform: The platform to add
 5  * @platform_drv: The driver for the platform
 6  */
 7 int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform,
 8         const struct snd_soc_platform_driver *platform_drv)
 9 {
10     int ret;
11 
12     ret = snd_soc_component_initialize(&platform->component,//初始化component,注意是platform结构体中的。
13             &platform_drv->component_driver, dev);
14     if (ret)
15         return ret;
16 
17     platform->dev = dev;
18     platform->driver = platform_drv;
19 
20     if (platform_drv->probe)
21         platform->component.probe = snd_soc_platform_drv_probe;
22     if (platform_drv->remove)
23         platform->component.remove = snd_soc_platform_drv_remove;
24 
25 #ifdef CONFIG_DEBUG_FS
26     platform->component.debugfs_prefix = "platform";
27 #endif
28 
29     mutex_lock(&client_mutex);
30     snd_soc_component_add_unlocked(&platform->component);
31     list_add(&platform->list, &platform_list);//
32     mutex_unlock(&client_mutex);
33 
34     dev_dbg(dev, "ASoC: Registered platform '%s'\n",
35         platform->component.name);
36 
37     return 0;
38 }

主要作用:(1)初始化snd_soc_platform和snd_soc_platform_driver

(2)将初始化的platfrom加入到链表platfrom_list中

platfrom_list是一个全局链表,定义位于:sound\soc\soc-core.c

1 static LIST_HEAD(platform_list);
2 static LIST_HEAD(codec_list);
3 static LIST_HEAD(component_list);

2.3 函数 snd_soc_component_initialize

用于初始化snd_soc_component和snd_soc_component->driver,同上platfrom,driver也是嵌入在component结构体中

snd_soc_component_driver是由platform_drv->component_driver获取的。

 1 static int snd_soc_component_initialize(struct snd_soc_component *component,
 2     const struct snd_soc_component_driver *driver, struct device *dev)
 3 {
 4     struct snd_soc_dapm_context *dapm;
 5 
 6     component->name = fmt_single_name(dev, &component->id);
 7     if (!component->name) {
 8         dev_err(dev, "ASoC: Failed to allocate name\n");
 9         return -ENOMEM;
10     }
11 
12     component->dev = dev;
13     component->driver = driver;
14     component->probe = component->driver->probe;
15     component->remove = component->driver->remove;
16 
17     dapm = &component->dapm;
18     dapm->dev = dev;
19     dapm->component = component;
20     dapm->bias_level = SND_SOC_BIAS_OFF;
21     dapm->idle_bias_off = true;
22     if (driver->seq_notifier)
23         dapm->seq_notifier = snd_soc_component_seq_notifier;
24     if (driver->stream_event)
25         dapm->stream_event = snd_soc_component_stream_event;
26 
27     component->controls = driver->controls;
28     component->num_controls = driver->num_controls;
29     component->dapm_widgets = driver->dapm_widgets;
30     component->num_dapm_widgets = driver->num_dapm_widgets;
31     component->dapm_routes = driver->dapm_routes;
32     component->num_dapm_routes = driver->num_dapm_routes;
33 
34     INIT_LIST_HEAD(&component->dai_list);//初始化component中的dai_list,dai_list用于挂载cpu_dai和codec_dai
35     mutex_init(&component->io_mutex);
36 
37     return 0;
38 }

结构体snd_soc_component 

 1 struct snd_soc_component {
 2     const char *name;
 3     int id;
 4     const char *name_prefix;
 5     struct device *dev;
 6     struct snd_soc_card *card;
 7 
 8     unsigned int active;
 9 
10     unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */
11     unsigned int registered_as_component:1;
12 
13     struct list_head list;
14     struct list_head list_aux; /* for auxiliary component of the card */
15 
16     struct snd_soc_dai_driver *dai_drv;
17     int num_dai;
18 
19     const struct snd_soc_component_driver *driver;
20 
21     struct list_head dai_list;//用于挂载cpu_dai和codec_dai
22 
23     int (*read)(struct snd_soc_component *, unsigned int, unsigned int *);
24     int (*write)(struct snd_soc_component *, unsigned int, unsigned int);
25 
26     struct regmap *regmap;
27     int val_bytes;
28 
29     struct mutex io_mutex;
30 
31     /* attached dynamic objects */
32     struct list_head dobj_list;
33 
34 #ifdef CONFIG_DEBUG_FS
35     struct dentry *debugfs_root;
36 #endif
37 
38     /*
39     * DO NOT use any of the fields below in drivers, they are temporary and
40     * are going to be removed again soon. If you use them in driver code the
41     * driver will be marked as BROKEN when these fields are removed.
42     */
43 
44     /* Don't use these, use snd_soc_component_get_dapm() */
45     struct snd_soc_dapm_context dapm;
46 
47     const struct snd_kcontrol_new *controls;
48     unsigned int num_controls;
49     const struct snd_soc_dapm_widget *dapm_widgets;
50     unsigned int num_dapm_widgets;
51     const struct snd_soc_dapm_route *dapm_routes;
52     unsigned int num_dapm_routes;
53     struct snd_soc_codec *codec;
54 
55     int (*probe)(struct snd_soc_component *);
56     void (*remove)(struct snd_soc_component *);
57 
58     /* machine specific init */
59     int (*init)(struct snd_soc_component *component);
60 
61 #ifdef CONFIG_DEBUG_FS
62     void (*init_debugfs)(struct snd_soc_component *component);
63     const char *debugfs_prefix;
64 #endif
65 }

结构体snd_soc_component_driver 

 1 /* component interface */
 2 struct snd_soc_component_driver {
 3     const char *name;
 4 
 5     /* Default control and setup, added after probe() is run */
 6     const struct snd_kcontrol_new *controls;
 7     unsigned int num_controls;
 8     const struct snd_soc_dapm_widget *dapm_widgets;
 9     unsigned int num_dapm_widgets;
10     const struct snd_soc_dapm_route *dapm_routes;
11     unsigned int num_dapm_routes;
12 
13     int (*probe)(struct snd_soc_component *);
14     void (*remove)(struct snd_soc_component *);
15 
16     /* DT */
17     int (*of_xlate_dai_name)(struct snd_soc_component *component,
18                  struct of_phandle_args *args,
19                  const char **dai_name);
20     void (*seq_notifier)(struct snd_soc_component *, enum snd_soc_dapm_type,
21         int subseq);
22     int (*stream_event)(struct snd_soc_component *, int event);
23 
24     /* probe ordering - for components with runtime dependencies */
25     int probe_order;
26     int remove_order;
27 }

2.4 函数 snd_soc_component_add_unlocked

将上文中初始化的component加入链表component_list。

component_list是一个全局链表,定义位于snd_soc.c中

 1 static void snd_soc_component_add_unlocked(struct snd_soc_component *component)
 2 {
 3     if (!component->write && !component->read) {
 4         if (!component->regmap)
 5             component->regmap = dev_get_regmap(component->dev, NULL);
 6         if (component->regmap)
 7             snd_soc_component_setup_regmap(component);
 8     }
 9 
10     list_add(&component->list, &component_list);
11     INIT_LIST_HEAD(&component->dobj_list);
12 }

3 实例

接下来以sound/soc/samsung/pcm.c为例来讲解。

把platfrom封装成设备驱动模型中的platfrom总线模型。

3.1 platfrom总线中的platform_driver定义

1 static struct platform_driver s3c_pcm_driver = {
2     .probe  = s3c_pcm_dev_probe,
3     .remove = s3c_pcm_dev_remove,
4     .driver = {
5         .name = "samsung-pcm",
6     },
7 };

3.2 probe函数

  1 static int s3c_pcm_dev_probe(struct platform_device *pdev)
  2 {
  3     struct s3c_pcm_info *pcm;
  4     struct resource *mem_res;
  5     struct s3c_audio_pdata *pcm_pdata;
  6     dma_filter_fn filter;
  7     int ret;
  8 
  9     /* Check for valid device index */
 10     if ((pdev->id < 0) || pdev->id >= ARRAY_SIZE(s3c_pcm)) {
 11         dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
 12         return -EINVAL;
 13     }
 14 
 15     pcm_pdata = pdev->dev.platform_data;
 16 
 17     /* Check for availability of necessary resource */
 18     mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 19     if (!mem_res) {
 20         dev_err(&pdev->dev, "Unable to get register resource\n");
 21         return -ENXIO;
 22     }
 23 
 24     if (pcm_pdata && pcm_pdata->cfg_gpio && pcm_pdata->cfg_gpio(pdev)) {
 25         dev_err(&pdev->dev, "Unable to configure gpio\n");
 26         return -EINVAL;
 27     }
 28 
 29     pcm = &s3c_pcm[pdev->id];
 30     pcm->dev = &pdev->dev;
 31 
 32     spin_lock_init(&pcm->lock);
 33 
 34     /* Default is 128fs */
 35     pcm->sclk_per_fs = 128;
 36 
 37     pcm->cclk = devm_clk_get(&pdev->dev, "audio-bus");
 38     if (IS_ERR(pcm->cclk)) {
 39         dev_err(&pdev->dev, "failed to get audio-bus\n");
 40         ret = PTR_ERR(pcm->cclk);
 41         goto err1;
 42     }
 43     clk_prepare_enable(pcm->cclk);
 44 
 45     /* record our pcm structure for later use in the callbacks */
 46     dev_set_drvdata(&pdev->dev, pcm);
 47 
 48     if (!request_mem_region(mem_res->start,
 49                 resource_size(mem_res), "samsung-pcm")) {
 50         dev_err(&pdev->dev, "Unable to request register region\n");
 51         ret = -EBUSY;
 52         goto err2;
 53     }
 54 
 55     pcm->regs = ioremap(mem_res->start, 0x100);
 56     if (pcm->regs == NULL) {
 57         dev_err(&pdev->dev, "cannot ioremap registers\n");
 58         ret = -ENXIO;
 59         goto err3;
 60     }
 61 
 62     pcm->pclk = devm_clk_get(&pdev->dev, "pcm");
 63     if (IS_ERR(pcm->pclk)) {
 64         dev_err(&pdev->dev, "failed to get pcm_clock\n");
 65         ret = -ENOENT;
 66         goto err4;
 67     }
 68     clk_prepare_enable(pcm->pclk);
 69 
 70     s3c_pcm_stereo_in[pdev->id].addr = mem_res->start + S3C_PCM_RXFIFO;
 71     s3c_pcm_stereo_out[pdev->id].addr = mem_res->start + S3C_PCM_TXFIFO;
 72 
 73     filter = NULL;
 74     if (pcm_pdata) {
 75         s3c_pcm_stereo_in[pdev->id].filter_data = pcm_pdata->dma_capture;
 76         s3c_pcm_stereo_out[pdev->id].filter_data = pcm_pdata->dma_playback;
 77         filter = pcm_pdata->dma_filter;
 78     }
 79 
 80     pcm->dma_capture = &s3c_pcm_stereo_in[pdev->id];
 81     pcm->dma_playback = &s3c_pcm_stereo_out[pdev->id];
 82 
 83     ret = samsung_asoc_dma_platform_register(&pdev->dev, filter,
 84                          NULL, NULL);
 85     if (ret) {
 86         dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret);
 87         goto err5;
 88     }
 89 
 90     pm_runtime_enable(&pdev->dev);
 91 
 92     ret = devm_snd_soc_register_component(&pdev->dev, &s3c_pcm_component,
 93                      &s3c_pcm_dai[pdev->id], 1);
 94     if (ret != 0) {
 95         dev_err(&pdev->dev, "failed to get register DAI: %d\n", ret);
 96         goto err6;
 97     }
 98 
 99     return 0;
100 err6:
101     pm_runtime_disable(&pdev->dev);
102 err5:
103     clk_disable_unprepare(pcm->pclk);
104 err4:
105     iounmap(pcm->regs);
106 err3:
107     release_mem_region(mem_res->start, resource_size(mem_res));
108 err2:
109     clk_disable_unprepare(pcm->cclk);
110 err1:
111     return ret;
112 }

3.3 函数samsung_asoc_dma_platform_register

向soc注册platfrom。

 1 int samsung_asoc_dma_platform_register(struct device *dev, dma_filter_fn filter,
 2                        const char *tx, const char *rx)
 3 {
 4     unsigned int flags = SND_DMAENGINE_PCM_FLAG_COMPAT;
 5     struct snd_dmaengine_pcm_config *pcm_conf;
 6 
 7     pcm_conf = devm_kzalloc(dev, sizeof(*pcm_conf), GFP_KERNEL);
 8     if (!pcm_conf)
 9         return -ENOMEM;
10 
11     pcm_conf->prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config;
12     pcm_conf->compat_filter_fn = filter;
13 
14     if (dev->of_node) {
15         pcm_conf->chan_names[SNDRV_PCM_STREAM_PLAYBACK] = tx;
16         pcm_conf->chan_names[SNDRV_PCM_STREAM_CAPTURE] = rx;
17     } else {
18         flags |= SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME;
19     }
20 
21     return devm_snd_dmaengine_pcm_register(dev, pcm_conf, flags);
22 }

中间省略,知道会调用snd_dmaengine_pcm_register

 1 int snd_dmaengine_pcm_register(struct device *dev,
 2     const struct snd_dmaengine_pcm_config *config, unsigned int flags)
 3 {
 4     struct dmaengine_pcm *pcm;
 5     int ret;
 6 
 7     pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
 8     if (!pcm)
 9         return -ENOMEM;
10 
11     pcm->config = config;
12     pcm->flags = flags;
13 
14     ret = dmaengine_pcm_request_chan_of(pcm, dev, config);
15     if (ret)
16         goto err_free_dma;
17 
18     ret = snd_soc_add_platform(dev, &pcm->platform,//向soc注册platfrom,详解见上述分析
19         &dmaengine_pcm_platform);
20     if (ret)
21         goto err_free_dma;
22 
23     return 0;
24 
25 err_free_dma:
26     dmaengine_pcm_release_chan(pcm);
27     kfree(pcm);
28     return ret;
29 }

调用函数snd_soc_add_platform连个作用:

(1)向soc注册snd_soc_component

(2)初始化结构体snd_soc_platfrom中的component

3.4 函数devm_snd_soc_register_component

probe中调用的第二个函数。作用:

(1)新建一个snd_soc_component

(2)注册component和dai

sound\soc\soc-devres.c

 1 int devm_snd_soc_register_component(struct device *dev,
 2              const struct snd_soc_component_driver *cmpnt_drv,
 3              struct snd_soc_dai_driver *dai_drv, int num_dai)
 4 {
 5     struct device **ptr;
 6     int ret;
 7 
 8     ptr = devres_alloc(devm_component_release, sizeof(*ptr), GFP_KERNEL);
 9     if (!ptr)
10         return -ENOMEM;
11 
12     ret = snd_soc_register_component(dev, cmpnt_drv, dai_drv, num_dai);
13     if (ret == 0) {
14         *ptr = dev;
15         devres_add(dev, ptr);
16     } else {
17         devres_free(ptr);
18     }
19 
20     return ret;
21 }

结构体snd_soc_component_driver和snd_soc_dai_driver的初始化定义:

 1 static const struct snd_soc_component_driver s3c_pcm_component = {
 2     .name        = "s3c-pcm",
 3 };
 4 
 5 static struct snd_soc_dai_driver s3c_pcm_dai[] = {
 6     [0] = {
 7         .name    = "samsung-pcm.0",
 8         S3C_PCM_DAI_DECLARE,
 9     },
10     [1] = {
11         .name    = "samsung-pcm.1",
12         S3C_PCM_DAI_DECLARE,
13     },
14 };

紧接着调用函数snd_soc_register_component

3.5 函数snd_soc_register_component

该函数创建并初始化第二个component,即cpu component。第一个是platfrom->component,如上2.2 所述。

 1 int snd_soc_register_component(struct device *dev,
 2                    const struct snd_soc_component_driver *cmpnt_drv,
 3                    struct snd_soc_dai_driver *dai_drv,
 4                    int num_dai)
 5 {
 6     struct snd_soc_component *cmpnt;//创建第二个component
 7     int ret;
 8 
 9     cmpnt = kzalloc(sizeof(*cmpnt), GFP_KERNEL);
10     if (!cmpnt) {
11         dev_err(dev, "ASoC: Failed to allocate memory\n");
12         return -ENOMEM;
13     }
14 
15     ret = snd_soc_component_initialize(cmpnt, cmpnt_drv, dev);//如上2.3中,初始化component
16     if (ret)
17         goto err_free;
18 
19     cmpnt->ignore_pmdown_time = true;
20     cmpnt->registered_as_component = true;
21 
22     ret = snd_soc_register_dais(cmpnt, dai_drv, num_dai, true);//注册dai
23     if (ret < 0) {
24         dev_err(dev, "ASoC: Failed to register DAIs: %d\n", ret);
25         goto err_cleanup;
26     }
27 
28     snd_soc_component_add(cmpnt);
29 
30     return 0;
31 
32 err_cleanup:
33     snd_soc_component_cleanup(cmpnt);
34 err_free:
35     kfree(cmpnt);
36     return ret;
37 }

紧接着调用函数snd_soc_register_dais和snd_soc_component_add

3.6 函数snd_soc_component_add

调用snd_soc_component_add_unlocked初始化的component加入链表component_list。详解见上述2.4.

1 static void snd_soc_component_add(struct snd_soc_component *component)
2 {
3     mutex_lock(&client_mutex);
4     snd_soc_component_add_unlocked(component);
5     mutex_unlock(&client_mutex);
6 }

3.7 函数snd_soc_register_dais

(1)新建了一个结构体snd_soc_dai

(2)调用函数soc_add_dai,初始化并返回snd_soc_dai。

 1 static int snd_soc_register_dais(struct snd_soc_component *component,
 2     struct snd_soc_dai_driver *dai_drv, size_t count,
 3     bool legacy_dai_naming)
 4 {
 5     struct device *dev = component->dev;
 6     struct snd_soc_dai *dai;
 7     unsigned int i;
 8     int ret;
 9 
10     dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count);
11 
12     component->dai_drv = dai_drv;
13 
14     for (i = 0; i < count; i++) {
15 
16         dai = soc_add_dai(component, dai_drv + i,
17                 count == 1 && legacy_dai_naming);
18         if (dai == NULL) {
19             ret = -ENOMEM;
20             goto err;
21         }
22     }
23 
24     return 0;
25 
26 err:
27     snd_soc_unregister_dais(component);
28 
29     return ret;
30 }

3.8 函数soc_add_dai

作用(1):初始化结构体snd_soc_dai

(2)将初始化的dai加入component->dai_list中

 1 /* Create a DAI and add it to the component's DAI list */
 2 static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component,
 3     struct snd_soc_dai_driver *dai_drv,
 4     bool legacy_dai_naming)
 5 {
 6     struct device *dev = component->dev;
 7     struct snd_soc_dai *dai;
 8 
 9     dev_dbg(dev, "ASoC: dynamically register DAI %s\n", dev_name(dev));
10 
11     dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
12     if (dai == NULL)
13         return NULL;
14 
15     /*
16      * Back in the old days when we still had component-less DAIs,
17      * instead of having a static name, component-less DAIs would
18      * inherit the name of the parent device so it is possible to
19      * register multiple instances of the DAI. We still need to keep
20      * the same naming style even though those DAIs are not
21      * component-less anymore.
22      */
23     if (legacy_dai_naming &&
24        (dai_drv->id == 0 || dai_drv->name == NULL)) {
25         dai->name = fmt_single_name(dev, &dai->id);
26     } else {
27         dai->name = fmt_multiple_name(dev, dai_drv);
28         if (dai_drv->id)
29             dai->id = dai_drv->id;
30         else
31             dai->id = component->num_dai;
32     }
33     if (dai->name == NULL) {
34         kfree(dai);
35         return NULL;
36     }
37 
38     dai->component = component;
39     dai->dev = dev;
40     dai->driver = dai_drv;
41     if (!dai->driver->ops)
42         dai->driver->ops = &null_dai_ops;
43 
44     list_add(&dai->list, &component->dai_list);
45     component->num_dai++;
46 
47     dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
48     return dai;
49 }

 结构体snd_soc_dai和snd_soc_dai_driver的定义位于:include\sound\soc-dai.h

 1 /*
 2  * Digital Audio Interface runtime data.
 3  *
 4  * Holds runtime data for a DAI.
 5  */
 6 struct snd_soc_dai {
 7     const char *name;
 8     int id;
 9     struct device *dev;
10 
11     /* driver ops */
12     struct snd_soc_dai_driver *driver;
13 
14     /* DAI runtime info */
15     unsigned int capture_active:1;        /* stream is in use */
16     unsigned int playback_active:1;        /* stream is in use */
17     unsigned int symmetric_rates:1;
18     unsigned int symmetric_channels:1;
19     unsigned int symmetric_samplebits:1;
20     unsigned int active;
21     unsigned char probed:1;
22 
23     struct snd_soc_dapm_widget *playback_widget;
24     struct snd_soc_dapm_widget *capture_widget;
25 
26     /* DAI DMA data */
27     void *playback_dma_data;
28     void *capture_dma_data;
29 
30     /* Symmetry data - only valid if symmetry is being enforced */
31     unsigned int rate;
32     unsigned int channels;
33     unsigned int sample_bits;
34 
35     /* parent platform/codec */
36     struct snd_soc_codec *codec;
37     struct snd_soc_component *component;
38 
39     /* CODEC TDM slot masks and params (for fixup) */
40     unsigned int tx_mask;
41     unsigned int rx_mask;
42 
43     struct list_head list;
44 }

snd_soc_dai_driver

 1 /*
 2  * Digital Audio Interface Driver.
 3  *
 4  * Describes the Digital Audio Interface in terms of its ALSA, DAI and AC97
 5  * operations and capabilities. Codec and platform drivers will register this
 6  * structure for every DAI they have.
 7  *
 8  * This structure covers the clocking, formating and ALSA operations for each
 9  * interface.
10  */
11 struct snd_soc_dai_driver {
12     /* DAI description */
13     const char *name;
14     unsigned int id;
15     unsigned int base;
16     struct snd_soc_dobj dobj;
17 
18     /* DAI driver callbacks */
19     int (*probe)(struct snd_soc_dai *dai);
20     int (*remove)(struct snd_soc_dai *dai);
21     int (*suspend)(struct snd_soc_dai *dai);
22     int (*resume)(struct snd_soc_dai *dai);
23     /* compress dai */
24     int (*compress_new)(struct snd_soc_pcm_runtime *rtd, int num);
25     /* DAI is also used for the control bus */
26     bool bus_control;
27 
28     /* ops */
29     const struct snd_soc_dai_ops *ops;
30 
31     /* DAI capabilities */
32     struct snd_soc_pcm_stream capture;
33     struct snd_soc_pcm_stream playback;
34     unsigned int symmetric_rates:1;
35     unsigned int symmetric_channels:1;
36     unsigned int symmetric_samplebits:1;
37 
38     /* probe ordering - for components with runtime dependencies */
39     int probe_order;
40     int remove_order;
41 }

4 总结

上述涉及了三组结构体

(1)snd_soc_platform和snd_soc_platform_driver

(2)snd_soc_component和snd_soc_component_driver

(3)snd_soc_dai和snd_soc_dai_driver的定义位于:include\sound\soc-dai.h

总结之间关系

参考博文:https://www.cnblogs.com/jason-lu/archive/2013/06/07/3124217.html

posted @ 2020-06-17 22:58  Action_er  阅读(1713)  评论(0编辑  收藏  举报