* 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. *
* Returns zero if successful or a negative error code. */
int snd_card_create(int idx, const char *xid, struct module *module, int extra_size, struct snd_card **card_ret)
首先,根据extra_size参数的大小分配内存,该内存区可以作为芯片的专有数据使用(见前面的介绍):
view plaincopy to clipboardprint?
card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL); if (!card)
return -ENOMEM; card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL); if (!card) return -ENOMEM;
拷贝声卡的ID字符串:
view plaincopy to clipboardprint? if (xid)
strlcpy(card->id, xid, sizeof(card->id)); if (xid) strlcpy(card->id, xid, sizeof(card->id));
如果传入的声卡编号为-1,自动分配一个索引编号:
view plaincopy to clipboardprint? if (idx < 0) {
for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++)
/* idx == -1 == 0xffff means: take any free slot */ if (~snd_cards_lock & idx & 1< if (module_slot_match(module, idx2)) { idx = idx2; break; } } } if (idx < 0) { for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) /* idx == -1 == 0xffff means: take any free slot */ if (~snd_cards_lock & idx & 1< 初始化snd_card结构中必要的字段: view plaincopy to clipboardprint? 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); init_waitqueue_head(&card->shutdown_sleep); #ifdef CONFIG_PM mutex_init(&card->power_lock); init_waitqueue_head(&card->power_sleep); #endif 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); init_waitqueue_head(&card->shutdown_sleep); #ifdef CONFIG_PM mutex_init(&card->power_lock); init_waitqueue_head(&card->power_sleep); #endif 建立逻辑设备:Control view plaincopy to clipboardprint? /* 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); /* 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文件中的info节点:通常就是/proc/asound/card0 view plaincopy to clipboardprint? err = snd_info_card_create(card); err = snd_info_card_create(card); 把第一步分配的内存指针放入private_data字段中: view plaincopy to clipboardprint? if (extra_size > 0) card->private_data = (char *)card + sizeof(struct snd_card); if (extra_size > 0) card->private_data = (char *)card + sizeof(struct snd_card); 4. snd_card_register() snd_card_create()在/sound/core/init.c中定义。 view plaincopy to clipboardprint? /** * 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. * * Returns zero otherwise a negative error code if the registrain failed. */ int snd_card_register(struct snd_card *card) /** * 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. * * Returns zero otherwise a negative error code if the registrain failed. */ int snd_card_register(struct snd_card *card) 首先,创建sysfs下的设备: view plaincopy to clipboardprint? if (!card->card_dev) { card->card_dev = device_create(sound_class, card->dev, MKDEV(0, 0), card, \ if (IS_ERR(card->card_dev)) card->card_dev = NULL; } if (!card->card_dev) { } card->card_dev = device_create(sound_class, card->dev, MKDEV(0, 0), card, \if (IS_ERR(card->card_dev)) card->card_dev = NULL; 其中,sound_class是在/sound/sound_core.c中创建的: view plaincopy to clipboardprint? static char *sound_devnode(struct device *dev, mode_t *mode) { if (MAJOR(dev->devt) == SOUND_MAJOR) return NULL; return kasprintf(GFP_KERNEL, \ } static int __init init_soundcore(void) { int rc; rc = init_oss_soundcore(); if (rc) return rc; sound_class = class_create(THIS_MODULE, \ if (IS_ERR(sound_class)) { cleanup_oss_soundcore(); return PTR_ERR(sound_class); } sound_class->devnode = sound_devnode; return 0; } static char *sound_devnode(struct device *dev, mode_t *mode) { if (MAJOR(dev->devt) == SOUND_MAJOR) return NULL; return kasprintf(GFP_KERNEL, \} static int __init init_soundcore(void) { int rc; } rc = init_oss_soundcore(); if (rc) return rc; sound_class = class_create(THIS_MODULE, \if (IS_ERR(sound_class)) { cleanup_oss_soundcore(); return PTR_ERR(sound_class); } sound_class->devnode = sound_devnode; return 0; 由此可见,声卡的class将会出现在文件系统的/sys/class/sound/下面,并且,sound_devnode()也决定了相应的设备节点也将会出现在/dev/snd/下面。 接下来的步骤,通过snd_device_register_all()注册所有挂在该声卡下的逻辑设备,snd_device_register_all()实际上是通过snd_card的devices链表,遍历所有的snd_device,并且调用snd_device的ops->dev_register()来实现各自设备的注册的。 view plaincopy to clipboardprint? if ((err = snd_device_register_all(card)) < 0) return err; if ((err = snd_device_register_all(card)) < 0) return err; 最后就是建立一些相应的proc和sysfs下的文件或属性节点,代码就不贴了。 至此,整个声卡完成了建立过程。 本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/DroidPhone/archive/2011/03/30/6289712.aspx