android 下的声卡设备节点
ALSA由以下文件提供了接口规范,ASOC框架依赖ALSA框架,创建soundcard 设备
1、sound/core/sound.c //实现了snd_fops 它起中转作用
2、sound/core/control.c //实现了snd_ctl_f_ops 控制接口
3、sound/core/pcm_native.c //实现了snd_pcm_f_ops pcm中的 playback capture接口
alsa框架属于分层结构,如下图
--------------------------struct file_operations snd_fops(sound.c)----------------------------------
|
control (control.c snd_ctl_f_ops) device.(pcm c0d0p pcm c0d0c)(pcm_naive.c &snd_pcm_f_ops).......file_operations
-----------------------------------------------------------------------------------------------------
|
硬件相关代码
-----------------------------------------------------------------------------------------------------
上层定义了一套file_operations供用户调用,其实只是起一个中转作用。
1、sound/core/sound.c //实现了snd_fops 它起中转作用
static int __init alsa_sound_init(void)
{
snd_major = major;
snd_ecards_limit = cards_limit;
if (register_chrdev(major, "alsa", &snd_fops)) {
snd_printk(KERN_ERR "unable to register native major device number %d\n", major);
return -EIO;
}
if (snd_info_init() < 0) {
unregister_chrdev(major, "alsa");
return -ENOMEM;
}
snd_info_minor_register();
#ifndef MODULE
printk(KERN_INFO "Advanced Linux Sound Architecture Driver Initialized.\n");
#endif
return 0;
}
static const struct file_operations snd_fops =
{
.owner = THIS_MODULE,
.open = snd_open,
.llseek = noop_llseek,
};
上面代码初始化的时候 向内核注册了一个alsa的设备节点,对应ops为snd_fops,内部只有一个open函数,user空间的用户调用时,将会通过次设备号,转到对应的设备的open函数。
2、sound/core/control.c //实现了snd_ctl_f_ops 控制接口
在sound/core/init.c 中,snd_ctl_create函数创建control节点,
调用snd_ctl_dev_register->snd_ctl_f_ops(sound/core/contrlo.c)
int snd_card_create(int idx, const char *xid,
struct module *module, int extra_size,
struct snd_card **card_ret)
{
........
err = snd_ctl_create(card); /*此处创建control节点*/
........
}
/*
* create control core:
* called from init.c
*/
int snd_ctl_create(struct snd_card *card)
{
static struct snd_device_ops ops = {
.dev_free = snd_ctl_dev_free,
.dev_register = snd_ctl_dev_register,/*当snd_device_new调用后会回调register函数*/
.dev_disconnect = snd_ctl_dev_disconnect,
};
if (snd_BUG_ON(!card))
return -ENXIO;
return snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops);
}
/*
* registration of the control device
*/
static int snd_ctl_dev_register(struct snd_device *device)
{
.......
if ((err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,
&snd_ctl_f_ops, card, name)) < 0)
return err;
return 0;
}
/*
* INIT PART
*/
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 = no_llseek,
.poll = snd_ctl_poll,
.unlocked_ioctl = snd_ctl_ioctl,
.compat_ioctl = snd_ctl_ioctl_compat,
.fasync = snd_ctl_fasync,
};
3、sound/core/pcm_native.c //实现了snd_pcm_f_ops pcm中的 playback capture接口
snd_pcm_new
snd_pcm_dev_register
snd_pcm_f_ops
/*
* Register section
*/
const struct file_operations snd_pcm_f_ops[2] = {
{
.owner = THIS_MODULE,
.write = snd_pcm_write,
.aio_write = snd_pcm_aio_write,
.open = snd_pcm_playback_open,
.release = snd_pcm_release,
.llseek = no_llseek,
.poll = snd_pcm_playback_poll,
.unlocked_ioctl = snd_pcm_playback_ioctl,
.compat_ioctl = snd_pcm_ioctl_compat,
.mmap = snd_pcm_mmap,
.fasync = snd_pcm_fasync,
.get_unmapped_area = snd_pcm_get_unmapped_area,
},
{
.owner = THIS_MODULE,
.read = snd_pcm_read,
.aio_read = snd_pcm_aio_read,
.open = snd_pcm_capture_open,
.release = snd_pcm_release,
.llseek = no_llseek,
.poll = snd_pcm_capture_poll,
.unlocked_ioctl = snd_pcm_capture_ioctl,
.compat_ioctl = snd_pcm_ioctl_compat,
.mmap = snd_pcm_mmap,
.fasync = snd_pcm_fasync,
.get_unmapped_area = snd_pcm_get_unmapped_area,
}
};