ALSA驱动源码之devm_snd_soc_register_component源码分析

简介: ALSA驱动源码之devm_snd_soc_register_component源码分析

ALSA驱动源码之devm_snd_soc_register_component源码分析


一、devm_snd_soc_register_component

/**
 * devm_snd_soc_register_component - resource managed component registration
 * @dev: Device used to manage component
 * @cmpnt_drv: Component driver
 * @dai_drv: DAI driver
 * @num_dai: Number of DAIs to register
 *
 * Register a component with automatic unregistration when the device is
 * unregistered.
 */
int devm_snd_soc_register_component(struct device *dev,
       const struct snd_soc_component_driver *cmpnt_drv,
       struct snd_soc_dai_driver *dai_drv, int num_dai)
{
  const struct snd_soc_component_driver **ptr;
  int ret;
  ptr = devres_alloc(devm_component_release, sizeof(*ptr), GFP_KERNEL);
  if (!ptr)
    return -ENOMEM;
  ret = snd_soc_register_component(dev, cmpnt_drv, dai_drv, num_dai);
  if (ret == 0) {
    *ptr = cmpnt_drv;
    devres_add(dev, ptr);
  } else {
    devres_free(ptr);
  }
  return ret;
}
EXPORT_SYMBOL_GPL(devm_snd_soc_register_component);

通过devm_snd_soc_register_component源码可知,此函数主要通过devres_alloc函数完成了devm_component_release的注册,并申请了资源,然后通过snd_soc_register_component完成了snd_soc_component_driver和snd_soc_dai_driver完成了dai的注册。

1.1、devres_alloc宏

       我么来看一下devres_alloc这个宏,它是通过调研__devres_alloc_node来完成资源的申请,具体实现如下:

#define devres_alloc(release, size, gfp) \
  __devres_alloc_node(release, size, gfp, NUMA_NO_NODE, #release)

1.2、snd_soc_register_component

       此处来看一下snd_soc_register_component函数,此函数中主要通过devm_kzalloc函数来完成了资源的申请,然后通过snd_soc_component_initialize函数来完成component组件的初始化,最后通过snd_soc_add_component函数将component添加到component->list当中,具体代码实现如下:

int snd_soc_register_component(struct device *dev,
      const struct snd_soc_component_driver *component_driver,
      struct snd_soc_dai_driver *dai_drv,
      int num_dai)
{
  struct snd_soc_component *component;
  int ret;
  component = devm_kzalloc(dev, sizeof(*component), GFP_KERNEL);
  if (!component)
    return -ENOMEM;
  ret = snd_soc_component_initialize(component, component_driver, dev);
  if (ret < 0)
    return ret;
  return snd_soc_add_component(component, dai_drv, num_dai);
}
EXPORT_SYMBOL_GPL(snd_soc_register_component);

1.2.1、snd_soc_component_initialize

       再来看一下snd_soc_component_initialize函数,此函数通过INIT_LIST_HEAD这宏完成了四个list的初始化,有component->dai_list、component->dobj_list、component->card_list和component->list,然后通过fmt_single_name函数来完成component->id的component组件的匹配工作,具体源码实现如下:

int snd_soc_component_initialize(struct snd_soc_component *component,
         const struct snd_soc_component_driver *driver,
         struct device *dev)
{
  INIT_LIST_HEAD(&component->dai_list);
  INIT_LIST_HEAD(&component->dobj_list);
  INIT_LIST_HEAD(&component->card_list);
  INIT_LIST_HEAD(&component->list);
  mutex_init(&component->io_mutex);
  component->name = fmt_single_name(dev, &component->id);
  if (!component->name) {
    dev_err(dev, "ASoC: Failed to allocate name\n");
    return -ENOMEM;
  }
  component->dev    = dev;
  component->driver = driver;
#ifdef CONFIG_DEBUG_FS
  if (!component->debugfs_prefix)
    component->debugfs_prefix = driver->debugfs_prefix;
#endif
  return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_component_initialize);

1.2.2、snd_soc_add_component

       我们再来看一下snd_soc_add_component函数,此函数主要是通过snd_soc_register_dais函数来完成snd_soc_dai_driver的注册,并将component来添加到component->list里面去,具体源码实现如下:

int snd_soc_add_component(struct snd_soc_component *component,
        struct snd_soc_dai_driver *dai_drv,
        int num_dai)
{
  int ret;
  int i;
  mutex_lock(&client_mutex);
  if (component->driver->endianness) {
    for (i = 0; i < num_dai; i++) {
      convert_endianness_formats(&dai_drv[i].playback);
      convert_endianness_formats(&dai_drv[i].capture);
    }
  }
  ret = snd_soc_register_dais(component, dai_drv, num_dai);
  if (ret < 0) {
    dev_err(component->dev, "ASoC: Failed to register DAIs: %d\n",
      ret);
    goto err_cleanup;
  }
  if (!component->driver->write && !component->driver->read) {
    if (!component->regmap)
      component->regmap = dev_get_regmap(component->dev,
                 NULL);
    if (component->regmap)
      snd_soc_component_setup_regmap(component);
  }
  /* see for_each_component */
  list_add(&component->list, &component_list);
err_cleanup:
  if (ret < 0)
    snd_soc_del_component_unlocked(component);
  mutex_unlock(&client_mutex);
  if (ret == 0)
    snd_soc_try_rebind_card();
  return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_add_component);

此处一块来看一下snd_soc_add_component函数中的异常处理函数,snd_soc_del_component_unlocked函数中通过snd_soc_unregister_dais来完成snd_soc_dai_driver的反注册过程,然后通过snd_soc_unbind_card函数将card从list中删除,最后通过list_del将component组件的component->list销毁掉,具体函数实现如下:

static void snd_soc_del_component_unlocked(struct snd_soc_component *component)
{
  struct snd_soc_card *card = component->card;
  snd_soc_unregister_dais(component);
  if (card)
    snd_soc_unbind_card(card, false);
  list_del(&component->list);
}

一块再看一下snd_soc_unregister_dais函数,此函数中通过for_each_component_dais_safe(component, dai, _dai)遍历dai->list,如果发现匹配的snd_soc_dai_driver则调用snd_soc_unregister_dai函数完成snd_soc_dai_driver的反初始化操作,具体的snd_soc_unregister_dais和snd_soc_unregister_dai源码实现如下:

/**
 * snd_soc_unregister_dais - Unregister DAIs from the ASoC core
 *
 * @component: The component for which the DAIs should be unregistered
 */
static void snd_soc_unregister_dais(struct snd_soc_component *component)
{
  struct snd_soc_dai *dai, *_dai;
  for_each_component_dais_safe(component, dai, _dai)
    snd_soc_unregister_dai(dai);
}

snd_soc_unregister_dai源码是直接调用list_del函数将dai->list删除。

void snd_soc_unregister_dai(struct snd_soc_dai *dai)
{
  dev_dbg(dai->dev, "ASoC: Unregistered DAI '%s'\n", dai->name);
  list_del(&dai->list);
}
EXPORT_SYMBOL_GPL(snd_soc_unregister_dai);
相关文章
|
1月前
|
存储 Linux 开发工具
Rockchip系列之浅度分析UART接口系列(1)
Rockchip系列之浅度分析UART接口系列(1)
115 1
|
1月前
|
存储 Java Android开发
Rockchip系列之UART 新增framework系统jni+service接口访问(2)
Rockchip系列之UART 新增framework系统jni+service接口访问(2)
29 1
|
1月前
|
存储 Android开发
Rockchip系列之客制化GPIO接口Driver部分(2)
Rockchip系列之客制化GPIO接口Driver部分(2)
32 0
|
1月前
|
安全 Java Android开发
Rockchip系列之客制化GPIO接口jni+service接口访问(4)
Rockchip系列之客制化GPIO接口jni+service接口访问(4)
25 0
|
1月前
|
内存技术
【HARDWARE】 --- SPI接口协议介绍与应用说明
【HARDWARE】 --- SPI接口协议介绍与应用说明
111 3
|
1月前
|
存储 芯片
Rockchip 自定义vendorstorages数据再u-boot通过cmdline给kernel传递数据
Rockchip 自定义vendorstorages数据再u-boot通过cmdline给kernel传递数据
59 1
|
11月前
|
存储 算法 芯片
IMX6ULL的I2C驱动详细分析
IMX6ULL的I2C驱动详细分析
191 0
IMX6ULL的I2C驱动详细分析
|
编解码 Linux API
Linux ALSA驱动之Platform源码分析(wm8350.c)
Linux ALSA驱动之Platform源码分析(wm8350.c)
|
JavaScript 物联网 芯片
AliOS Things 硬件抽象层(HAL)对接系列2 — SPI driver porting
HAL层(Hardware abstraction layer) 的目的是为了屏蔽底层不同芯片平台的差异,从而使驱动层上面的软件不会随芯片平台而改变。AliOS Things定义了全面的HAL抽象层,这个系列主要介绍AliOS ThingsHAL层与不同芯片平台对接的poring要点,并举例说明。
2891 0
|
JavaScript 物联网 芯片
AliOS Things 硬件抽象层(HAL)对接系列3 — I2C driver porting
HAL层(Hardware abstraction layer) 的目的是为了屏蔽底层不同芯片平台的差异,从而使驱动层上面的软件不会随芯片平台而改变。AliOS Things定义了全面的HAL抽象层,这个系列主要介绍AliOS ThingsHAL层与不同芯片平台对接的poring要点,并举例说明。
3268 0