Linux ALSA驱动之二:声卡的创建流程 下
3、snd_card_new函数详解
用于创建并初始化一个声卡的结构体
/** * 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 * * 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) { struct snd_card *card; int err; if (snd_BUG_ON(!card_ret)) return -EINVAL; *card_ret = NULL; if (extra_size < 0) extra_size = 0; /* 1. 分配snd_card和private_data的空间 在snd_card后面的空间分配,card->private_data指向该空间 */ card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL); if (!card) return -ENOMEM; err = snd_card_init(card, parent, idx, xid, module, extra_size); if (err < 0) { kfree(card); return err; } *card_ret = card; return 0; } static int snd_card_init(struct snd_card *card, struct device *parent, int idx, const char *xid, struct module *module, size_t extra_size) { int err; #ifdef CONFIG_SND_DEBUG char name[8]; #endif /* 1、根据传入的参数赋值xid, idx, module, parent */ /* (1). 为 card->private_datad 赋值 */ if (extra_size > 0) card->private_data = (char *)card + sizeof(struct snd_card); /* (2). 为 card->id 赋值 */ if (xid) strscpy(card->id, xid, sizeof(card->id)); err = 0; mutex_lock(&snd_card_mutex); 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); if (idx < 0) err = -ENODEV; else if (idx < snd_ecards_limit) { if (test_bit(idx, snd_cards_lock)) err = -EBUSY; /* invalid */ } else if (idx >= SNDRV_CARDS) err = -ENODEV; if (err < 0) { mutex_unlock(&snd_card_mutex); dev_err(parent, "cannot find the slot for index %d (range 0-%i), error: %d\n", idx, snd_ecards_limit - 1, err); return err; } set_bit(idx, snd_cards_lock); /* lock it */ if (idx >= snd_ecards_limit) snd_ecards_limit = idx + 1; /* increase the limit */ mutex_unlock(&snd_card_mutex); /* (3). 赋值parent */ card->dev = parent; /* (4). 分配snd_card的序号 */ card->number = idx; #ifdef MODULE WARN_ON(!module); /* (5). 赋值module */ card->module = module; #endif /* 2、初始化结构体和变量 */ 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); mutex_init(&card->memory_mutex); #ifdef CONFIG_PM init_waitqueue_head(&card->power_sleep); init_waitqueue_head(&card->power_ref_sleep); atomic_set(&card->power_ref, 0); #endif init_waitqueue_head(&card->remove_sleep); card->sync_irq = -1; /* 设置设备文件节点的名字 */ 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; err = kobject_set_name(&card->card_dev.kobj, "card%d", idx); if (err < 0) goto __error; snprintf(card->irq_descr, sizeof(card->irq_descr), "%s:%s", dev_driver_string(card->dev), dev_name(&card->card_dev)); /* the control interface cannot be accessed from the user space until */ /* snd_cards_bitmask and snd_cards are set with snd_card_register */ /* 创建一个control设备 */ err = snd_ctl_create(card); if (err < 0) { dev_err(parent, "unable to register control minors\n"); goto __error; } /* 生成声卡的proc文件 */ err = snd_info_card_create(card); if (err < 0) { dev_err(parent, "unable to create card info\n"); goto __error_ctl; } #ifdef CONFIG_SND_DEBUG sprintf(name, "card%d", idx); card->debugfs_root = debugfs_create_dir(name, sound_debugfs_root); #endif return 0; __error_ctl: snd_device_free_all(card); __error: put_device(&card->card_dev); return err; }
这函数会执行如下操作:
1、分配snd_card和private_data的空间。
2、初始化结构体、变量、创建control设备、生成声卡的proc文件等全部都在snd_card_init函数中完成。
3、获取private_data的地址等。
4、sound_class会在init_soundcore中做初始化操作。
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; }
5、创建card的control设备。根据注释control接口在snd_card_register之后,用户空间才可以访问。
6、调用snd_info_card_create函数在proc下创建card0目录,最終会根据entry的mode,创建目录。
/* * create a card proc file * called from init.c */ int snd_info_card_create(struct snd_card *card) { char str[8]; struct snd_info_entry *entry; if (snd_BUG_ON(!card)) return -ENXIO; sprintf(str, "card%i", card->number); entry = create_subdir(card->module, str); if (!entry) return -ENOMEM; card->proc_root = entry; return snd_card_ro_proc_new(card, "id", card, snd_card_id_read); }
4、snd_card_register函数详解
用来注册声卡,主要完成了如下操作:
1、创建声卡的设备节点。
2、注册所有的逻辑设备。
3、添加当前的声卡到声卡数组。
4、注册声卡的proc文件
/** * 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) { int err; /* 合法性判断,如果此处card不存在,panic。 */ if (snd_BUG_ON(!card)) return -EINVAL; /* 1、根据card的registered判断是否已经注册,如果注册继续。否则调用device_add添加设备,设置registered标志。创建声卡的sysfs设备节点。其中card->card_dev在创建声卡结构体的时候被赋值。 card->card_dev.class = sound_class; sound_class在sound模块被加载的时候创建 设备节点:/dev/snd/cartd%i */ if (!card->registered) { err = device_add(&card->card_dev); if (err < 0) return err; card->registered = true; } else { if (card->managed) devm_remove_action(card->dev, trigger_card_free, card); } if (card->managed) { err = devm_add_action(card->dev, trigger_card_free, card); if (err < 0) return err; } /* 2、调用snd_device_register_all注册所有card的设备,包括pcm, control等 */ err = snd_device_register_all(card); if (err < 0) return err; mutex_lock(&snd_card_mutex); /* 3、添加当前的声卡到声卡数组 */ if (snd_cards[card->number]) { /* already registered */ mutex_unlock(&snd_card_mutex); return snd_info_card_register(card); /* register pending info */ } if (*card->id) { /* make a unique id name from the given string */ char tmpid[sizeof(card->id)]; memcpy(tmpid, card->id, sizeof(card->id)); snd_card_set_id_no_lock(card, tmpid, tmpid); } else { /* create an id from either shortname or longname */ const char *src; src = *card->shortname ? card->shortname : card->longname; snd_card_set_id_no_lock(card, src, retrieve_id_from_card_name(src)); } snd_cards[card->number] = card; mutex_unlock(&snd_card_mutex); /* 4、注册声卡的proc文件 */ err = snd_info_card_register(card); if (err < 0) return err; #if IS_ENABLED(CONFIG_SND_MIXER_OSS) if (snd_mixer_oss_notify_callback) snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_REGISTER); #endif return 0; } /* * register all the devices on the card. * called from init.c */ int snd_device_register_all(struct snd_card *card) { struct snd_device *dev; int err; if (snd_BUG_ON(!card)) return -ENXIO; /* 遍历注册所有的snd_device,调用__snd_device_register函数完成注册 */ list_for_each_entry(dev, &card->devices, list) { err = __snd_device_register(dev); if (err < 0) return err; } return 0; }
static int __snd_device_register(struct snd_device *dev) { if (dev->state == SNDRV_DEV_BUILD) { if (dev->ops->dev_register) { int err = dev->ops->dev_register(dev); if (err < 0) return err; } dev->state = SNDRV_DEV_REGISTERED; } return 0; }
此函数最终会调用各个devices的snd_device_ops中的dev_register函数。
声卡注册完成之后,声卡的软件逻辑结果如下: