Android/Linux音频架构开发ALSA-篇4

接上篇文章我们介绍了声卡的创建流程,下面我们深入源码来进一步理解这其中的过程。

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;

后面我们来讲解逻辑设备该如何创建,他的源码流程又是什么样的。

需要了解更多文章的朋友,可以关注我得微信公众号【快乐程序猿】里面会更新的比这里要快。

你可能感兴趣的:(audio-alsa系列详解,linux,音视频,运维)