\
以wolfsen的wm8900 codec为例,在wm8900.c中可以看到
struct snd_soc_codec_device soc_codec_dev_wm8900 = {
.probe = wm8900_probe,
.remove = wm8900_remove,
.suspend = wm8900_suspend,
.resume = wm8900_resume,
};\
EXPORT_SYMBOL_GPL(soc_codec_dev_wm8900);
\
本文先介绍第一个回调函数probe
probe函数传入的只有一个参数是struct platform_device *pdev,结构体在platform_device.h中定义,
函数platform_get_drvdata()从probe的参数获取SoC Device,得到的socdev会在后面设备驱动注册使用\
\
1、snd_soc_new_pcms\
接下来是Register pcms,函数snd_soc_new_pcms()有三个参数struct snd_soc_device *socdev、 int idx、 const char *xid,
第一个socdev就是上一步获得到的SoC Device;后面的 int型idx 和 指针型 xid,会在注册声卡时使用,函数是snd_card_create()
\
(1)snd_card_create
声卡注册函数snd_card_create先调用kzalloc分配一块专有内存,如果分配不到,注册失败返回;
然后拷贝声卡的ID字符串
- if (xid)
- strlcpy(card->id, xid, sizeof(card->id));
接下来是在slot中,为新建声卡分配一个索引号,这一部分的操作用mutex_lock、mutex_unlock保护起来
分配索引的代码
-
if (idx < 0) { //idx == -1,表示自动分配索引号
-
for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++)
-
if (~snd_cards_lock & idx & 1<<idx2) {
-
if (module_slot_match(module, idx2)) {
-
idx = idx2;
-
break;
-
}
-
}
-
}
-
if (idx < 0) { //idx == -1,表示自动分配索引号
-
for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++)
-
if (~snd_cards_lock & idx & 1<<idx2) {
-
if (!slots[idx2] || !*slots[idx2]) {
-
idx = idx2;
-
break;
-
}
-
}
-
}
-
其中,SNDRV_CARDS定义在croe.h中,表示最多支持声卡数目
- #ifdef CONFIG_SND_DYNAMIC_MINORS
- #define SNDRV_CARDS 32
- #else
- #define SNDRV_CARDS 8
- #endif
for循环里面的if (~snd_cards_lock & idx & 1<<idx2),是在slots中查找当前没有被使用的id,
snd_cards_lock 在/sound/core的init.c中定义
static unsigned int snd_cards_lock;/* locked for registering/using */
for循环结束后如果id还是-1,直接返回,注册失败;
-
if (idx < 0)
-
err = -ENODEV;
-
else if (idx < snd_ecards_limit) {
-
if (snd_cards_lock & (1 << idx))
-
err = -EBUSY;/* invalid */
-
} else if (idx >= SNDRV_CARDS)
-
err = -ENODEV;
snd_ecards_limit在sound/core的sound.c中被赋值snd_ecards_limit = cards_limit,而static int cards_limit = 1;\
所以第二个if是判别如果idx为0,再次检查该id的声卡是否在被使用,处于busy状态;
第三个是检查id号是否超过最大支持声卡数目,这个在上面提到过。
\
到此,如果没有被返回,说明已经成功自动分配了一个id给字符设备了,接下来把snd_cards_lock这个全局变量赋值相应的id位,
表示这个id已经被使用了,如果id刚好是最大的临界值,把id上限加1。
\
后面是初始化snd_card结构中必要的字段,
- 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
- /* 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
- err = snd_info_card_create(card);
把第一步分配的内存指针放入private_data字段中:
- if (extra_size > 0)
- card->private_data = (char *)card + sizeof(struct snd_card);
\
(2)soc_new_pcm
下