声音子系统的入口
kernel\sound\core\sound.c
/* Alsa 逻辑设备节点的 file_operation 结构体,只有一个 open 函数,可以看出
这个 open 只是一个中转作用,类似于输入子系统 input.c 中对各种输入事件支持的架构
对应到声音系统,会有 pcm 设备和 control 设备
*/
static const struct file_operations snd_fops =
{
.owner = THIS_MODULE,
.open = snd_open,
.llseek = noop_llseek,
};
alsa_sound_init
register_chrdev(major, "alsa", &snd_fops) //注册为字符设备
----------------------------------------------------------
User Space app: open
----------------------------------------------------------
Kernel Space driver:snd_open
/* 根据此设备号进行 file_operation 的替换,并执行新的 open 函数*/
mptr = snd_minors[minor];
old_fops = file->f_op;
file->f_op = fops_get(mptr->f_ops);
file->f_op->open()
Q1:如何构造 snd_minors 结构?
snd_register_device_for_dev 函数构造 snd_minors 结构
Q2:哪些地方调用 snd_register_device_for_dev ?
pcm.c :snd_pcm_dev_register
snd_register_device_for_dev
device_create //创建设备文件
control.c:snd_ctl_dev_register
snd_register_device
snd_register_device_for_dev
device_create //这里才创建设备文件
这几个文件都会去调用 snd_register_device 给声卡注册 ALSA 设备文件
Control.c (kernel\sound\core):
Hwdep.c (kernel\sound\core):
Rawmidi.c (kernel\sound\core):
Seq_clientmgr.c (kernel\sound\core\seq):
Timer.c (kernel\sound\core):
Q3:Alsa Lib(TinyAlsa)应用层跟 Driver 如何交互?
1. Set HW Params:
ioctl(pcm->fd, SNDRV_PCM_IOCTL_HW_PARAMS, ¶ms)
snd_pcm_playback_ioctl
snd_pcm_playback_ioctl1
snd_pcm_common_ioctl1
case SNDRV_PCM_IOCTL_HW_PARAMS:
return snd_pcm_hw_params_user(substream, arg);
{
snd_pcm_hw_params()
substream->ops->hw_params
//相当于调用
soc_pcm_hw_params
{
/*Machine */
Machine 驱动: rtd->dai_link->ops->hw_params(substream, params);
codec_dai->driver->ops->hw_params
cpu_dai->driver->ops->hw_params
}
copy_to_user(_params, params, sizeof(*params))
}
2. Playback: Write Pcm Data
pcm_write
snd_pcm_write
snd_pcm_lib_write
snd_pcm_lib_write1(substream, (unsigned long)buf, size, nonblock,snd_pcm_lib_write_transfer);
{
//从用户空间把数据拷贝考内核空间
snd_pcm_lib_write_transfer:copy_from_user(hwbuf, buf, frames_to_bytes(runtime, frames))
// 启动处理器的DMA通道发送音频数据到外围接口 i2s 控制器
snd_pcm_lib_write1:
snd_pcm_start
snd_pcm_action(&snd_pcm_action_start, substream, SNDRV_PCM_STATE_RUNNING);
snd_pcm_do_start
//相当于调用 rk29_pcm.c 中的rockchip_pcm_trigger
substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_START);
cpu: platform->driver->ops->trigger(substream, cmd);
cpu Dai:cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai);
Codec Dai: codec_dai->driver->ops->trigger()
case SNDRV_PCM_TRIGGER_START:
rk29_dma_ctrl(prtd->params->channel, RK29_DMAOP_START);
}
以下是主要结构体描述:
/* ASoC PCM operations 间接操作 Driver 里的 rockchip_pcm_ops:即soc_pcm_ops ->rockchip_pcm_ops
PCM 播放和录音的数据流的操作接口
*/
static struct snd_pcm_ops soc_pcm_ops = {
.open = soc_pcm_open,
.close = soc_codec_close,
.hw_params = soc_pcm_hw_params,
.hw_free = soc_pcm_hw_free,
.prepare = soc_pcm_prepare,
.trigger = soc_pcm_trigger,
.pointer = soc_pcm_pointer,
};
/* 直接进行 PCM 的驱动操作,把 PCM 数据送到 DMA */
static struct snd_pcm_ops rockchip_pcm_ops = {
.open = rockchip_pcm_open,
.close = rockchip_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = rockchip_pcm_hw_params,
.hw_free = rockchip_pcm_hw_free,
.prepare = rockchip_pcm_prepare,
.trigger = rockchip_pcm_trigger,
.pointer = rockchip_pcm_pointer,
.mmap = rockchip_pcm_mmap,
};
/* 设备节点的 file_operation 结构体的 snd_pcm_write 会调用到 snd_pcm_action_start 结构中的传输函数
snd_pcm_action_start 又调用到 soc_pcm_ops 的trigger 函数
最终调用到底层的 rockchip_pcm_ops 中的 trigger 函数
文件系统的节点操作接口
*/
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,
}
};
static struct action_ops snd_pcm_action_start = {
.pre_action = snd_pcm_pre_start,
.do_action = snd_pcm_do_start,
.undo_action = snd_pcm_undo_start,
.post_action = snd_pcm_post_start
};
阅读(4518) | 评论(0) | 转发(0) |