0


Linux ALSA驱动之Platform源码分析(wm8350.c)

1、Platform概述

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

cpu_dai_driver 部分:
在嵌入式系统里面通常指SoC的I2S、PCM总线控制器,负责把音频数据从I2S tx FIFO搬运到CODEC(这是音频播放的情形,录制则方向相反)。cpu_dai通过snd_soc_register_dai()/devm_snd_soc_register_component()来注册。

  1. **注:DAI**是 Digital Audio Interface的简称,分为cpu_daicodec_dai,这两者通过 I2S/PCM 总线连接,AIF Audio Interface 的简称,嵌入式系统中一般是I2SPCM接口。

platform_driver部分:
负责把dma buffer中的音频数据搬运到I2S tx FIFO。音频DMA驱动通过 platform_driver_register()/module_platform_driver() 来注册,故也常用platform来指代音频DMA驱动(这里的 platform 需要与 SoC Platform 区分开)。

2、snd_soc_dai_driver

2.1、snd_soc_dai_driver注册流程

  1. DAI驱动通常对应cpu的一个或几个I2S/PCM接口,实现一个DAI驱动大致可以分为以下几个步骤:
  2. 1、定义一个snd_soc_dai_driver结构的实例;
  3. 2、在对应的platform_driver中的probe回调中通过API: snd_soc_register_dai或者snd_soc_register_dais注册snd_soc_dai实例;
  4. 3、实现snd_soc_dai_driver结构中的probesuspend等回调;
  5. 4、实现snd_soc_dai_driver结构中的snd_soc_dai_ops字段中的回调函数;
  6. 具体代码流程如下(sound/soc/codecs/wm8350.c
  1. /* snd_soc_dai_ops 结构体实例 */
  2. static const struct snd_soc_dai_ops wm8350_dai_ops = {
  3. .hw_params = wm8350_pcm_hw_params,
  4. .mute_stream = wm8350_mute,
  5. .set_fmt = wm8350_set_dai_fmt,
  6. .set_sysclk = wm8350_set_dai_sysclk,
  7. .set_pll = wm8350_set_fll,
  8. .set_clkdiv = wm8350_set_clkdiv,
  9. .no_capture_mute = 1,
  10. };
  11. /* snd_soc_dai_driver结构体实例 */
  12. static struct snd_soc_dai_driver wm8350_dai = {
  13. .name = "wm8350-hifi",
  14. .playback = {
  15. .stream_name = "Playback",
  16. .channels_min = 1,
  17. .channels_max = 2,
  18. .rates = WM8350_RATES,
  19. .formats = WM8350_FORMATS,
  20. },
  21. .capture = {
  22. .stream_name = "Capture",
  23. .channels_min = 1,
  24. .channels_max = 2,
  25. .rates = WM8350_RATES,
  26. .formats = WM8350_FORMATS,
  27. },
  28. .ops = &wm8350_dai_ops,
  29. };
  30. /* platform平台probe函数 */
  31. static int wm8350_probe(struct platform_device *pdev)
  32. {
  33. /* 注册component组件参数为soc_component_dev_wm8350 wm8350_dai*/
  34. return devm_snd_soc_register_component(&pdev->dev,
  35. &soc_component_dev_wm8350,
  36. &wm8350_dai, 1);
  37. }
  38. /**
  39. * devm_snd_soc_register_component - resource managed component registration
  40. * @dev: Device used to manage component
  41. * @cmpnt_drv: Component driver
  42. * @dai_drv: DAI driver
  43. * @num_dai: Number of DAIs to register
  44. *
  45. * Register a component with automatic unregistration when the device is
  46. * unregistered.
  47. */
  48. /* 进入devm_snd_soc_register_component函数 */
  49. int devm_snd_soc_register_component(struct device *dev,
  50. const struct snd_soc_component_driver *cmpnt_drv,
  51. struct snd_soc_dai_driver *dai_drv, int num_dai)
  52. {
  53. const struct snd_soc_component_driver **ptr;
  54. int ret;
  55. /* 申请devm_component_release空间 */
  56. ptr = devres_alloc(devm_component_release, sizeof(*ptr), GFP_KERNEL);
  57. if (!ptr)
  58. return -ENOMEM;
  59. /*调用snd_soc_register_component注册cmpnt_drv、 dai_drv */
  60. ret = snd_soc_register_component(dev, cmpnt_drv, dai_drv, num_dai);
  61. if (ret == 0) {
  62. *ptr = cmpnt_drv;
  63. devres_add(dev, ptr);
  64. } else {
  65. devres_free(ptr);
  66. }
  67. return ret;
  68. }
  69. EXPORT_SYMBOL_GPL(devm_snd_soc_register_component);
  70. /* 进入snd_soc_register_component函数 */
  71. int snd_soc_register_component(struct device *dev,
  72. const struct snd_soc_component_driver *component_driver,
  73. struct snd_soc_dai_driver *dai_drv,
  74. int num_dai)
  75. {
  76. struct snd_soc_component *component;
  77. int ret;
  78. /* 申请component空间 */
  79. component = devm_kzalloc(dev, sizeof(*component), GFP_KERNEL);
  80. if (!component)
  81. return -ENOMEM;
  82. /* 调用snd_soc_component_initialize函数注册component_driver */
  83. ret = snd_soc_component_initialize(component, component_driver, dev);
  84. if (ret < 0)
  85. return ret;
  86. /* 调用snd_soc_add_component注册 dai_drv */
  87. return snd_soc_add_component(component, dai_drv, num_dai);
  88. }
  89. EXPORT_SYMBOL_GPL(snd_soc_register_component);
  90. /* 进入snd_soc_add_component函数 */
  91. int snd_soc_add_component(struct snd_soc_component *component,
  92. struct snd_soc_dai_driver *dai_drv,
  93. int num_dai)
  94. {
  95. int ret;
  96. int i;
  97. mutex_lock(&client_mutex);
  98. if (component->driver->endianness) {
  99. for (i = 0; i < num_dai; i++) {
  100. convert_endianness_formats(&dai_drv[i].playback);
  101. convert_endianness_formats(&dai_drv[i].capture);
  102. }
  103. }
  104. /* 调用snd_soc_register_dais函数注册dai_drv */
  105. ret = snd_soc_register_dais(component, dai_drv, num_dai);
  106. if (ret < 0) {
  107. dev_err(component->dev, "ASoC: Failed to register DAIs: %d\n",
  108. ret);
  109. goto err_cleanup;
  110. }
  111. if (!component->driver->write && !component->driver->read) {
  112. if (!component->regmap)
  113. component->regmap = dev_get_regmap(component->dev,
  114. NULL);
  115. if (component->regmap)
  116. snd_soc_component_setup_regmap(component);
  117. }
  118. /* see for_each_component */
  119. list_add(&component->list, &component_list);
  120. err_cleanup:
  121. if (ret < 0)
  122. snd_soc_del_component_unlocked(component);
  123. mutex_unlock(&client_mutex);
  124. if (ret == 0)
  125. snd_soc_try_rebind_card();
  126. return ret;
  127. }
  128. EXPORT_SYMBOL_GPL(snd_soc_add_component);
  129. /**
  130. * snd_soc_register_dais - Register a DAI with the ASoC core
  131. *
  132. * @component: The component the DAIs are registered for
  133. * @dai_drv: DAI driver to use for the DAIs
  134. * @count: Number of DAIs
  135. */
  136. /* 进入snd_soc_register_dais函数 */
  137. static int snd_soc_register_dais(struct snd_soc_component *component,
  138. struct snd_soc_dai_driver *dai_drv,
  139. size_t count)
  140. {
  141. struct snd_soc_dai *dai;
  142. unsigned int i;
  143. int ret;
  144. for (i = 0; i < count; i++) {
  145. /* 最终调用snd_soc_register_dai函数注册dai_drv */
  146. dai = snd_soc_register_dai(component, dai_drv + i, count == 1 &&
  147. !component->driver->non_legacy_dai_naming);
  148. if (dai == NULL) {
  149. ret = -ENOMEM;
  150. goto err;
  151. }
  152. }
  153. return 0;
  154. err:
  155. snd_soc_unregister_dais(component);
  156. return ret;
  157. }
  158. /**
  159. * snd_soc_register_dai - Register a DAI dynamically & create its widgets
  160. *
  161. * @component: The component the DAIs are registered for
  162. * @dai_drv: DAI driver to use for the DAI
  163. * @legacy_dai_naming: if %true, use legacy single-name format;
  164. * if %false, use multiple-name format;
  165. *
  166. * Topology can use this API to register DAIs when probing a component.
  167. * These DAIs's widgets will be freed in the card cleanup and the DAIs
  168. * will be freed in the component cleanup.
  169. */
  170. /* 进入到snd_soc_register_dai函数 */
  171. struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component,
  172. struct snd_soc_dai_driver *dai_drv,
  173. bool legacy_dai_naming)
  174. {
  175. struct device *dev = component->dev;
  176. struct snd_soc_dai *dai;
  177. dev_dbg(dev, "ASoC: dynamically register DAI %s\n", dev_name(dev));
  178. lockdep_assert_held(&client_mutex);
  179. /* 申请dai空间 */
  180. dai = devm_kzalloc(dev, sizeof(*dai), GFP_KERNEL);
  181. if (dai == NULL)
  182. return NULL;
  183. /*
  184. * Back in the old days when we still had component-less DAIs,
  185. * instead of having a static name, component-less DAIs would
  186. * inherit the name of the parent device so it is possible to
  187. * register multiple instances of the DAI. We still need to keep
  188. * the same naming style even though those DAIs are not
  189. * component-less anymore.
  190. */
  191. if (legacy_dai_naming &&
  192. (dai_drv->id == 0 || dai_drv->name == NULL)) {
  193. dai->name = fmt_single_name(dev, &dai->id);
  194. } else {
  195. dai->name = fmt_multiple_name(dev, dai_drv);
  196. if (dai_drv->id)
  197. dai->id = dai_drv->id;
  198. else
  199. dai->id = component->num_dai;
  200. }
  201. if (!dai->name)
  202. return NULL;
  203. dai->component = component;
  204. dai->dev = dev;
  205. dai->driver = dai_drv;
  206. /* see for_each_component_dais */
  207. /* 将dai->list添加到component->dai_list中 */
  208. list_add_tail(&dai->list, &component->dai_list);
  209. component->num_dai++;
  210. dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name);
  211. return dai;
  212. }
  213. EXPORT_SYMBOL_GPL(snd_soc_register_dai);
  214. /* 至此cpu_dai添加完成 */

2.2、snd_soc_dai结构体

  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. /* driver ops */
  11. struct snd_soc_dai_driver *driver;
  12. /* DAI runtime info */
  13. unsigned int stream_active[SNDRV_PCM_STREAM_LAST + 1]; /* usage count */
  14. struct snd_soc_dapm_widget *playback_widget;
  15. struct snd_soc_dapm_widget *capture_widget;
  16. /* DAI DMA data */
  17. void *playback_dma_data;
  18. void *capture_dma_data;
  19. /* Symmetry data - only valid if symmetry is being enforced */
  20. unsigned int rate;
  21. unsigned int channels;
  22. unsigned int sample_bits;
  23. /* parent platform/codec */
  24. struct snd_soc_component *component;
  25. /* CODEC TDM slot masks and params (for fixup) */
  26. unsigned int tx_mask;
  27. unsigned int rx_mask;
  28. struct list_head list;
  29. /* function mark */
  30. struct snd_pcm_substream *mark_startup;
  31. struct snd_pcm_substream *mark_hw_params;
  32. struct snd_pcm_substream *mark_trigger;
  33. struct snd_compr_stream *mark_compr_startup;
  34. /* bit field */
  35. unsigned int probed:1;
  36. };
  1. **snd_soc_dai**该结构在snd_soc_register_dai函数中通过动态内存申请获得.简要介绍一下几个重要字段:
  2. 1、**driver**指向关联的snd_soc_dai_driver结构,由注册时通过参数传入。
  3. 2、**playback_dma_data **用于保存该dai播放streamdma信息目标地址,dma传送单元大小和通道号等。
  4. 3、**capture_dma_data **同上,用于录音stream
  5. 4、**component**指向关联的snd_soc_component结构体中。

2.3、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. /* DAI driver callbacks */
  18. int (*probe)(struct snd_soc_dai *dai);
  19. int (*remove)(struct snd_soc_dai *dai);
  20. /* compress dai */
  21. int (*compress_new)(struct snd_soc_pcm_runtime *rtd, int num);
  22. /* Optional Callback used at pcm creation*/
  23. int (*pcm_new)(struct snd_soc_pcm_runtime *rtd,
  24. struct snd_soc_dai *dai);
  25. /* ops */
  26. const struct snd_soc_dai_ops *ops;
  27. const struct snd_soc_cdai_ops *cops;
  28. /* DAI capabilities */
  29. struct snd_soc_pcm_stream capture;
  30. struct snd_soc_pcm_stream playback;
  31. unsigned int symmetric_rate:1;
  32. unsigned int symmetric_channels:1;
  33. unsigned int symmetric_sample_bits:1;
  34. /* probe ordering - for components with runtime dependencies */
  35. int probe_order;
  36. int remove_order;
  37. };
  1. **snd_soc_dai_driver**结构体需要自己根据不同的soc芯片进行定义,这里只介绍几个关键字段:
  2. 1、**proberemove**回调函数,分别在声卡加载和卸载时被调用。
  3. 2、**ops**指向**snd_soc_dai_ops**结构,用于配置和控制该dai,后面细讲。
  4. 3、**playback snd_soc_pcm_stream**结构,用于指出该dai支持的声道数,码率,数据格式等能力。
  5. 4、**capture snd_soc_pcm_stream**结构,用于指出该dai支持的声道数,码率,数据格式等能力。

2.4、snd_soc_dai_ops结构体

** snd_soc_dai_driver结构体中的ops字段指向一个snd_soc_dai_ops**结构体,该结构体实际上是一组回调函数的集合,dai的配置和控制几乎都是通过这些回调函数来实现的,这些回调函数基本可以分为3大类,驱动程序可以根据实际情况实现其中的一部分:

  1. struct snd_soc_dai_ops {
  2. /*
  3. * DAI clocking configuration, all optional.
  4. * Called by soc_card drivers, normally in their hw_params.
  5. */
  6. int (*set_sysclk)(struct snd_soc_dai *dai,
  7. int clk_id, unsigned int freq, int dir);
  8. int (*set_pll)(struct snd_soc_dai *dai, int pll_id, int source,
  9. unsigned int freq_in, unsigned int freq_out);
  10. int (*set_clkdiv)(struct snd_soc_dai *dai, int div_id, int div);
  11. int (*set_bclk_ratio)(struct snd_soc_dai *dai, unsigned int ratio);
  12. /*
  13. * DAI format configuration
  14. * Called by soc_card drivers, normally in their hw_params.
  15. */
  16. int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt);
  17. int (*xlate_tdm_slot_mask)(unsigned int slots,
  18. unsigned int *tx_mask, unsigned int *rx_mask);
  19. int (*set_tdm_slot)(struct snd_soc_dai *dai,
  20. unsigned int tx_mask, unsigned int rx_mask,
  21. int slots, int slot_width);
  22. int (*set_channel_map)(struct snd_soc_dai *dai,
  23. unsigned int tx_num, unsigned int *tx_slot,
  24. unsigned int rx_num, unsigned int *rx_slot);
  25. int (*get_channel_map)(struct snd_soc_dai *dai,
  26. unsigned int *tx_num, unsigned int *tx_slot,
  27. unsigned int *rx_num, unsigned int *rx_slot);
  28. int (*set_tristate)(struct snd_soc_dai *dai, int tristate);
  29. int (*set_stream)(struct snd_soc_dai *dai,
  30. void *stream, int direction);
  31. void *(*get_stream)(struct snd_soc_dai *dai, int direction);
  32. /*
  33. * DAI digital mute - optional.
  34. * Called by soc-core to minimise any pops.
  35. */
  36. int (*mute_stream)(struct snd_soc_dai *dai, int mute, int stream);
  37. /*
  38. * ALSA PCM audio operations - all optional.
  39. * Called by soc-core during audio PCM operations.
  40. */
  41. int (*startup)(struct snd_pcm_substream *,
  42. struct snd_soc_dai *);
  43. void (*shutdown)(struct snd_pcm_substream *,
  44. struct snd_soc_dai *);
  45. int (*hw_params)(struct snd_pcm_substream *,
  46. struct snd_pcm_hw_params *, struct snd_soc_dai *);
  47. int (*hw_free)(struct snd_pcm_substream *,
  48. struct snd_soc_dai *);
  49. int (*prepare)(struct snd_pcm_substream *,
  50. struct snd_soc_dai *);
  51. /*
  52. * NOTE: Commands passed to the trigger function are not necessarily
  53. * compatible with the current state of the dai. For example this
  54. * sequence of commands is possible: START STOP STOP.
  55. * So do not unconditionally use refcounting functions in the trigger
  56. * function, e.g. clk_enable/disable.
  57. */
  58. int (*trigger)(struct snd_pcm_substream *, int,
  59. struct snd_soc_dai *);
  60. int (*bespoke_trigger)(struct snd_pcm_substream *, int,
  61. struct snd_soc_dai *);
  62. /*
  63. * For hardware based FIFO caused delay reporting.
  64. * Optional.
  65. */
  66. snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *,
  67. struct snd_soc_dai *);
  68. /*
  69. * Format list for auto selection.
  70. * Format will be increased if priority format was
  71. * not selected.
  72. * see
  73. * snd_soc_dai_get_fmt()
  74. */
  75. u64 *auto_selectable_formats;
  76. int num_auto_selectable_formats;
  77. /* bit field */
  78. unsigned int no_capture_mute:1;
  79. };
  1. 工作时钟配置函数通常由machine驱动调用:
  2. 1、**set_sysclk**设置dai的主时钟。
  3. 2、**set_pll**设置PLL参数。
  4. 3、**set_clkdiv**设置分频系数。
  5. dai的格式配置参数,通常也由machine驱动调用:
  6. 1、**set_fmt**设置dai的格式。
  7. 2、**set_tdm_slot**如果dai支持时分复用,用于设置时分复用的slotset_channel_map声道的时分复用映射设置。
  8. 3、**set_tristate**设置dai引脚的状态,当与其他dai并联使用同一引脚时需要使用该回调。
  9. 标准的snd_soc_ops回调通常由soc-core在进行PCM操作时调用:
  10. 1、**startup**:打开设备,设备开始工作的时候回调

** 2、shutdown:关闭设备前调用
3、
hw_params:设置硬件的相关参数
4、
trigger**:DAM开始时传输,结束传输,暂停传世,恢复传输的时候被回调。

3、platform_driver

3.1、platform_driver注册流程

  1. /* snd_soc_component_driver结构体实例化 */
  2. static const struct snd_soc_component_driver soc_component_dev_wm8350 = {
  3. .probe = wm8350_component_probe,
  4. .remove = wm8350_component_remove,
  5. .set_bias_level = wm8350_set_bias_level,
  6. .controls = wm8350_snd_controls,
  7. .num_controls = ARRAY_SIZE(wm8350_snd_controls),
  8. .dapm_widgets = wm8350_dapm_widgets,
  9. .num_dapm_widgets = ARRAY_SIZE(wm8350_dapm_widgets),
  10. .dapm_routes = wm8350_dapm_routes,
  11. .num_dapm_routes = ARRAY_SIZE(wm8350_dapm_routes),
  12. .suspend_bias_off = 1,
  13. .idle_bias_on = 1,
  14. .use_pmdown_time = 1,
  15. .endianness = 1,
  16. .non_legacy_dai_naming = 1,
  17. };
  18. /* 进入到wm8350_probe函数 */
  19. static int wm8350_probe(struct platform_device *pdev)
  20. {
  21. /* 通过devm_snd_soc_register_component函数注册soc_component_dev_wm8350 */
  22. return devm_snd_soc_register_component(&pdev->dev,
  23. &soc_component_dev_wm8350,
  24. &wm8350_dai, 1);
  25. }
  26. /* 进入platform_driver函数 */
  27. static struct platform_driver wm8350_codec_driver = {
  28. .driver = {
  29. .name = "wm8350-codec",
  30. },
  31. .probe = wm8350_probe,
  32. };
  33. /* 通过module_platform_driver宏来注册platform_driver */
  34. module_platform_driver(wm8350_codec_driver);

3.2、platform_driver结构体

  1. 在编写 platform 驱动的时候,首先定义一个**platform_driver**结构体变量,然后实现结构体中的各个成员变量,重点是实现匹配方法以及probe函数。当驱动和设备匹配成功以后 probe函数就会执行,具体的驱动程序在 probe 函数里面编写,比如字符设备驱动等等。
  1. struct platform_driver {
  2. int (*probe)(struct platform_device *);
  3. int (*remove)(struct platform_device *);
  4. void (*shutdown)(struct platform_device *);
  5. int (*suspend)(struct platform_device *, pm_message_t state);
  6. int (*resume)(struct platform_device *);
  7. struct device_driver driver;
  8. const struct platform_device_id *id_table;
  9. bool prevent_deferred_probe;
  10. /*
  11. * For most device drivers, no need to care about this flag as long as
  12. * all DMAs are handled through the kernel DMA API. For some special
  13. * ones, for example VFIO drivers, they know how to manage the DMA
  14. * themselves and set this flag so that the IOMMU layer will allow them
  15. * to setup and manage their own I/O address space.
  16. */
  17. bool driver_managed_dma;
  18. };
  1. **platform_driver**结构体用于注册驱动到Platform总线,此处只讲几个重点字段:
  2. 1、**probe**:当驱动与设备匹配成功以后probe函数就会执行。一般驱动的提供者会编写,如果自己要编写一个全新的驱动,那么 probe 就需要自行实现。
  3. 2、**driver**:device_driver 结构体变量,Linux 内核里面大量使用到了面向对象的思维, device_driver相当于基类,提供了最基础的驱动框架。 plaform_driver继承了这个基类,然后在此基础上又添加了一些特有的成员变量。

3.3、snd_soc_component结构体

  1. struct snd_soc_component {
  2. /* device_driver->name 和snd_soc_component_driver->id有关, */
  3. const char *name;
  4. int id;
  5. const char *name_prefix;
  6. struct device *dev;
  7. struct snd_soc_card *card;
  8. unsigned int active;
  9. unsigned int suspended:1; /* is in suspend PM state */
  10. /* 用于把自己挂载到全局链表component_list下, component_list在soc-core中保持的全局变量 */
  11. struct list_head list;
  12. struct list_head card_aux_list; /* for auxiliary bound components */
  13. struct list_head card_list;
  14. /* 指向下属的snd_soc_component_driver, 该结构体一般由底层平台驱动实现 */
  15. const struct snd_soc_component_driver *driver;
  16. /* 链表头, 挂接snd_soc_dai->list list_add(&dai->list, &component->dai_list) */
  17. struct list_head dai_list;
  18. int num_dai;
  19. struct regmap *regmap;
  20. int val_bytes;
  21. struct mutex io_mutex;
  22. /* attached dynamic objects */
  23. struct list_head dobj_list;
  24. /*
  25. * DO NOT use any of the fields below in drivers, they are temporary and
  26. * are going to be removed again soon. If you use them in driver code
  27. * the driver will be marked as BROKEN when these fields are removed.
  28. */
  29. /* Don't use these, use snd_soc_component_get_dapm() */
  30. struct snd_soc_dapm_context dapm;
  31. /* machine specific init */
  32. int (*init)(struct snd_soc_component *component);
  33. /* function mark */
  34. void *mark_module;
  35. struct snd_pcm_substream *mark_open;
  36. struct snd_pcm_substream *mark_hw_params;
  37. struct snd_pcm_substream *mark_trigger;
  38. struct snd_compr_stream *mark_compr_open;
  39. void *mark_pm;
  40. struct dentry *debugfs_root;
  41. const char *debugfs_prefix;
  42. };

3.4、snd_soc_component_driver结构体

  1. struct snd_soc_component_driver {
  2. const char *name;
  3. /* Default control and setup, added after probe() is run */
  4. const struct snd_kcontrol_new *controls;
  5. unsigned int num_controls;
  6. const struct snd_soc_dapm_widget *dapm_widgets;
  7. unsigned int num_dapm_widgets;
  8. const struct snd_soc_dapm_route *dapm_routes;
  9. unsigned int num_dapm_routes;
  10. int (*probe)(struct snd_soc_component *component);
  11. void (*remove)(struct snd_soc_component *component);
  12. int (*suspend)(struct snd_soc_component *component);
  13. int (*resume)(struct snd_soc_component *component);
  14. unsigned int (*read)(struct snd_soc_component *component,
  15. unsigned int reg);
  16. int (*write)(struct snd_soc_component *component,
  17. unsigned int reg, unsigned int val);
  18. /* pcm creation and destruction */
  19. int (*pcm_construct)(struct snd_soc_component *component,
  20. struct snd_soc_pcm_runtime *rtd);
  21. void (*pcm_destruct)(struct snd_soc_component *component,
  22. struct snd_pcm *pcm);
  23. /* component wide operations */
  24. int (*set_sysclk)(struct snd_soc_component *component,
  25. int clk_id, int source, unsigned int freq, int dir);
  26. int (*set_pll)(struct snd_soc_component *component, int pll_id,
  27. int source, unsigned int freq_in, unsigned int freq_out);
  28. int (*set_jack)(struct snd_soc_component *component,
  29. struct snd_soc_jack *jack, void *data);
  30. /* DT */
  31. int (*of_xlate_dai_name)(struct snd_soc_component *component,
  32. const struct of_phandle_args *args,
  33. const char **dai_name);
  34. int (*of_xlate_dai_id)(struct snd_soc_component *comment,
  35. struct device_node *endpoint);
  36. void (*seq_notifier)(struct snd_soc_component *component,
  37. enum snd_soc_dapm_type type, int subseq);
  38. int (*stream_event)(struct snd_soc_component *component, int event);
  39. int (*set_bias_level)(struct snd_soc_component *component,
  40. enum snd_soc_bias_level level);
  41. int (*open)(struct snd_soc_component *component,
  42. struct snd_pcm_substream *substream);
  43. int (*close)(struct snd_soc_component *component,
  44. struct snd_pcm_substream *substream);
  45. int (*ioctl)(struct snd_soc_component *component,
  46. struct snd_pcm_substream *substream,
  47. unsigned int cmd, void *arg);
  48. int (*hw_params)(struct snd_soc_component *component,
  49. struct snd_pcm_substream *substream,
  50. struct snd_pcm_hw_params *params);
  51. int (*hw_free)(struct snd_soc_component *component,
  52. struct snd_pcm_substream *substream);
  53. int (*prepare)(struct snd_soc_component *component,
  54. struct snd_pcm_substream *substream);
  55. int (*trigger)(struct snd_soc_component *component,
  56. struct snd_pcm_substream *substream, int cmd);
  57. int (*sync_stop)(struct snd_soc_component *component,
  58. struct snd_pcm_substream *substream);
  59. snd_pcm_uframes_t (*pointer)(struct snd_soc_component *component,
  60. struct snd_pcm_substream *substream);
  61. int (*get_time_info)(struct snd_soc_component *component,
  62. struct snd_pcm_substream *substream, struct timespec64 *system_ts,
  63. struct timespec64 *audio_ts,
  64. struct snd_pcm_audio_tstamp_config *audio_tstamp_config,
  65. struct snd_pcm_audio_tstamp_report *audio_tstamp_report);
  66. int (*copy_user)(struct snd_soc_component *component,
  67. struct snd_pcm_substream *substream, int channel,
  68. unsigned long pos, void __user *buf,
  69. unsigned long bytes);
  70. struct page *(*page)(struct snd_soc_component *component,
  71. struct snd_pcm_substream *substream,
  72. unsigned long offset);
  73. int (*mmap)(struct snd_soc_component *component,
  74. struct snd_pcm_substream *substream,
  75. struct vm_area_struct *vma);
  76. int (*ack)(struct snd_soc_component *component,
  77. struct snd_pcm_substream *substream);
  78. snd_pcm_sframes_t (*delay)(struct snd_soc_component *component,
  79. struct snd_pcm_substream *substream);
  80. const struct snd_compress_ops *compress_ops;
  81. /* probe ordering - for components with runtime dependencies */
  82. int probe_order;
  83. int remove_order;
  84. /*
  85. * signal if the module handling the component should not be removed
  86. * if a pcm is open. Setting this would prevent the module
  87. * refcount being incremented in probe() but allow it be incremented
  88. * when a pcm is opened and decremented when it is closed.
  89. */
  90. unsigned int module_get_upon_open:1;
  91. /* bits */
  92. unsigned int idle_bias_on:1;
  93. unsigned int suspend_bias_off:1;
  94. unsigned int use_pmdown_time:1; /* care pmdown_time at stop */
  95. /*
  96. * Indicates that the component does not care about the endianness of
  97. * PCM audio data and the core will ensure that both LE and BE variants
  98. * of each used format are present. Typically this is because the
  99. * component sits behind a bus that abstracts away the endian of the
  100. * original data, ie. one for which the transmission endian is defined
  101. * (I2S/SLIMbus/SoundWire), or the concept of endian doesn't exist (PDM,
  102. * analogue).
  103. */
  104. unsigned int endianness:1;
  105. unsigned int non_legacy_dai_naming:1;
  106. /* this component uses topology and ignore machine driver FEs */
  107. const char *ignore_machine;
  108. const char *topology_name_prefix;
  109. int (*be_hw_params_fixup)(struct snd_soc_pcm_runtime *rtd,
  110. struct snd_pcm_hw_params *params);
  111. bool use_dai_pcm_id; /* use DAI link PCM ID as PCM device number */
  112. int be_pcm_base; /* base device ID for all BE PCMs */
  113. #ifdef CONFIG_DEBUG_FS
  114. const char *debugfs_prefix;
  115. #endif
  116. };
  1. module_platform_driver函数的详解请参考《module_platform_driver源码分析》
标签: linux 音频 音视频

本文转载自: https://blog.csdn.net/code_lyb/article/details/126583717
版权归原作者 Coder个人博客 所有, 如有侵权,请联系我们删除。

“Linux ALSA驱动之Platform源码分析(wm8350.c)”的评论:

还没有评论