接上篇文章我们介绍了声卡的创建流程,下面我们深入源码来进一步理解这其中的过程。
1、snd_card_new
snd_card_new定义在了linux\sound\core\init.c文件中,读源码的时候我们可以i看到每个关键函数的上面都会有一段注释,里面介绍了每个参数的意思,同时也介绍了这个函数的作用,我们可以多去看看。
/**
* snd_card_new - create and initialize a soundcard structure
* @parent: the parent device object
* @idx: card index (address) [0 ... (SNDRV_CARDS-1)]
* @xid: card identification (ASCII string)
* @module: top level module for locking
* @extra_size: allocate this extra size after the main soundcard structure
* @card_ret: the pointer to store the created card instance
*
* Creates and initializes a soundcard structure.
*
* The function allocates snd_card instance via kzalloc with the given
* space for the driver to use freely. The allocated struct is stored
* in the given card_ret pointer.
*
* Return: Zero if successful or a negative error code.
*/
int snd_card_new(struct device *parent, int idx, const char *xid,
struct module *module, int extra_size,
struct snd_card **card_ret)
首先,创建了一个snd_card指针,并分配了内存空间
struct snd_card *card;
int err;
...
card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL);
根据extra_size 分配私有数据空间
if (extra_size > 0)
card->private_data = (char *)card + sizeof(struct snd_card);
如果用户设置了xid就不需要系统分配,直接设置为声卡id,如果用户没有设置就会调用get_slot_from_bitmask和get_slot_from_bitmask来进行分配。
if (xid)
strlcpy(card->id, xid, sizeof(card->id));
if (idx < 0) /* first check the matching module-name slot */
idx = get_slot_from_bitmask(idx, module_slot_match, module);
if (idx < 0) /* if not matched, assign an empty slot */
idx = get_slot_from_bitmask(idx, check_empty_slot, module);
初始化声卡中的一起必要字段,这里可以参考我们篇2对于snd_card结构体的讲解。
card->dev = parent;
card->number = idx;
card->module = module;
INIT_LIST_HEAD(&card->devices);
init_rwsem(&card->controls_rwsem);
rwlock_init(&card->ctl_files_rwlock);
INIT_LIST_HEAD(&card->controls);
INIT_LIST_HEAD(&card->ctl_files);
spin_lock_init(&card->files_lock);
INIT_LIST_HEAD(&card->files_list);
#ifdef CONFIG_PM
init_waitqueue_head(&card->power_sleep);
#endif
init_waitqueue_head(&card->remove_sleep);
device_initialize(&card->card_dev);
card->card_dev.parent = parent;
card->card_dev.class = sound_class;
card->card_dev.release = release_card_device;
card->card_dev.groups = card->dev_groups;
card->dev_groups[0] = &card_dev_attr_group;
根据声卡id在文件系统中创建card目录。
err = kobject_set_name(&card->card_dev.kobj, "card%d", idx);
创建声卡的control逻辑设备。
/* the control interface cannot be accessed from the user space until */
/* snd_cards_bitmask and snd_cards are set with snd_card_register */
err = snd_ctl_create(card);
创建和注册与声卡相关的信息节点,这个信息节点通常在 /proc/asound 或 /sys/class/sound/ 文件系统中显示,用于提供声卡的详细信息。该函数有助于在内核中管理和提供有关声卡设备的信息。
err = snd_info_card_create(card);
2、snd_card_register
同样定义在定义在了linux\sound\core\init.c文件中
/**
* snd_card_register - register the soundcard
* @card: soundcard structure
*
* This function registers all the devices assigned to the soundcard.
* Until calling this, the ALSA control interface is blocked from the
* external accesses. Thus, you should call this function at the end
* of the initialization of the card.
*
* Return: Zero otherwise a negative error code if the registration failed.
*/
int snd_card_register(struct snd_card *card)
在文件系统中创建设备,这里的card_dev在之前的snd_card_new函数中做了初始化,包括sound_class。
if (!card->registered) {
err = device_add(&card->card_dev);
if (err < 0)
return err;
card->registered = true;
}
sound_class的创建在linux\sound\sound_core.c文件中。
这里创建了sound_class,声卡的class将会出现在/sys/class/sound/下面,定义的sound_class->devnode = sound_devnode;说明相应的设备节点也将会出现在/dev/snd/下面。
static char *sound_devnode(struct device *dev, umode_t *mode)
{
if (MAJOR(dev->devt) == SOUND_MAJOR)
return NULL;
return kasprintf(GFP_KERNEL, "snd/%s", dev_name(dev));
}
static int __init init_soundcore(void)
{
int rc;
rc = init_oss_soundcore();
if (rc)
return rc;
sound_class = class_create(THIS_MODULE, "sound");
if (IS_ERR(sound_class)) {
cleanup_oss_soundcore();
return PTR_ERR(sound_class);
}
sound_class->devnode = sound_devnode;
return 0;
}
subsys_initcall(init_soundcore);
最后就是注册所有的逻辑设备,当然创建逻辑设备的篇章我们单独进行讲解。这里就是遍历devices链表,调用dev_register来注册设备。
if ((err = snd_device_register_all(card)) < 0)
return err;
后面我们来讲解逻辑设备该如何创建,他的源码流程又是什么样的。
需要了解更多文章的朋友,可以关注我得微信公众号【快乐程序猿】里面会更新的比这里要快。