}
return 0;
}2.2 指定sound_class类的创建设备节点方法sound_devnode
[cpp]
static char *sound_devnode(struct device *dev, mode_t *mode)
{
if (MAJOR(dev->devt) == SOUND_MAJOR) //主设备号14 oss子系统
return NULL;
return kasprintf(GFP_KERNEL, "snd/%s", dev_name(dev)); //alsa子系统 "/dev/sndX/"
}
static char *sound_devnode(struct device *dev, mode_t *mode)
{
if (MAJOR(dev->devt) == SOUND_MAJOR) //主设备号14 oss子系统
return NULL;
return kasprintf(GFP_KERNEL, "snd/%s", dev_name(dev)); //alsa子系统 "/dev/sndX/"
}所以alsa子系统的音频设备会出现在/dev/snd/目录下
这里我们可以得知alsa架构的设备节点在/dev/snd/目录下,oss架构的设备节点在/dev下
alsa的主设备号为116,oss架构的主设备号为14
alsa的主设备号在/sound/core/sound.c中定义
[cpp]
static int major = CONFIG_SND_MAJOR;
static int major = CONFIG_SND_MAJOR;[cpp] view plaincopyprint #define CONFIG_SND_MAJOR 116
#define CONFIG_SND_MAJOR 116
第八部分 声卡控制设备浅析
前面讲到每个声卡都有一个声卡控制设备对象,所以研究下声卡控制设备
在声卡创建函数snd_card_create中调用了snd_ctl_create函数创建声卡控制设备,并将声卡对象作为参数传递进来
1.创建声卡控制设备
[cpp]
int snd_ctl_create(struct snd_card *card)
{
static struct snd_device_ops ops = {//静态初始化snd_device_ops声卡设备操作函数集结构体
.dev_free = snd_ctl_dev_free,//释放方法
.dev_register = snd_ctl_dev_register,//注册方法
.dev_disconnect = snd_ctl_dev_disconnect,//断开连接方法
};
if (snd_BUG_ON(!card))
return -ENXIO;
return snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops);//创建声卡控制设备
}
int snd_ctl_create(struct snd_card *card)
{
static struct snd_device_ops ops = {//静态初始化snd_device_ops声卡设备操作函数集结构体
.dev_free = snd_ctl_dev_free,//释放方法
.dev_register = snd_ctl_dev_register,//注册方法
.dev_disconnect = snd_ctl_dev_disconnect,//断开连接方法
};
if (snd_BUG_ON(!card))
return -ENXIO;
return snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops);//创建声卡控制设备
}这里还需注意一下snd_device_new函数的参数,发现声卡控制设备的device_data是指向声卡对象的
在注册声卡过程中会调用snd_device_register_all函数,该函数则调用声卡控制设备dev_register方法,既snd_ctl_dev_register函数
2.注册声卡控制设备
[cpp]
static int snd_ctl_dev_register(struct snd_device *device)
{
struct snd_card *card = device->device_data; //获取声卡对象
int err, cardnum;
char name[16];
if (snd_BUG_ON(!card))
return -ENXIO;
cardnum = card->number; //获取声卡索引号
if (snd_BUG_ON(cardnum < 0 || cardnum >= SNDRV_CARDS))
return -ENXIO;
sprintf(name, "controlC%i", cardnum); //设置名字-->"/dev/snd/controlCx"
if ((err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,&snd_ctl_f_ops, card, name)) < 0) //注册声卡控制设备
return err;
return 0;
}
static int snd_ctl_dev_register(struct snd_device *device)
{
struct snd_card *card = device->device_data; //获取声卡对象
int err, cardnum;
char name[16];
if (snd_BUG_ON(!card))
return -ENXIO;
cardnum = card->number; //获取声卡索引号
if (snd_BUG_ON(cardnum < 0 || cardnum >= SNDRV_CARDS))
return -ENXIO;
sprintf(name, "controlC%i", cardnum); //设置名字-->"/dev/snd/controlCx"
if ((err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,&snd_ctl_f_ops, card, name)) < 0) //注册声卡控制设备
return err;
return 0;
}通过snd_register_device创建了/dev/snd/controlC0设备文件,假设是0号声卡吧!并捆绑了snd_ctl_f_ops设备文件操作函数集
3.声卡控制设备对应的设备文件操作函数集
[cpp]
static const struct file_operations snd_ctl_f_ops =
{
.owner = THIS_MODULE,
.read = snd_ctl_read, //读方法
.open = snd_ctl_open, //打开方法
.release = snd_ctl_release, //释放方法
.llseek =