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