ALSA驱动源码之devm_snd_soc_register_component源码分析
  qrJHiMhufrJ3 2023年11月02日 45 0


一、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);

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  tprTMCWDkFAR   2023年12月07日   31   0   0 头文件#include初始化
  bWLIE0wKp9lo   2024年05月31日   86   0   0 Linux硬件
qrJHiMhufrJ3