【RK3568】dummy.c
阶段1主要是注册 platform_driver创建设备static struct platform_driver snd_dummy_driver { .probe snd_dummy_probe, .remove snd_dummy_remove, .driver { .name SND_DUMMY_DRIVER, .pm SND_DUMMY_PM_OPS, }, };module_init( alsa_card_dummy_init )↓alsa_card_dummy_init()↓platform_driver_register() ← 注册平台驱动↓platform_device_register_simple() ← 创建设备↓snd_dummy_probe() ← 探针函数被调用阶段2snd_dummy_probe()↓snd_card_new() // 创建声卡实例↓snd_card_dummy_pcm() // 创建PCM设备↓snd_card_dummy_new_mixer() // 创建混音器↓snd_card_register() // 注册声卡系统PCMsnd_card_dummy_pcm()↓snd_pcm_new() // 创建 PCM 实例↓snd_pcm_set_ops() // 设置操作函数-----// 设置播放操作集snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, ops);// 设置捕获操作集snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, ops);------↓returnPCM操作函数static struct snd_pcm_ops dummy_pcm_ops { .open dummy_pcm_open, .close dummy_pcm_close, .ioctl snd_pcm_lib_ioctl, .hw_params dummy_pcm_hw_params, .hw_free dummy_pcm_hw_free, .prepare dummy_pcm_prepare, .trigger dummy_pcm_trigger, .pointer dummy_pcm_pointer, };open当用户空间应用程序打开一个 PCM 设备如 /dev/snd/pcmC0D0p 时ALSA 框架会调用此函数来初始化 PCM 子流。close当用户空间应用程序关闭 PCM 设备如调用 snd_pcm_close() 或进程退出时ALSA 框架会调用此函数来清理 PCM 子流占用的资源。hw_params当用户空间应用程序通过 snd_pcm_hw_params() 设置 PCM 硬件参数缓冲区大小、周期大小、格式等时ALSA 框架会调用此函数来分配音频缓冲区。应用程序调用流程snd_pcm_open() → 调用 dummy_pcm_open()↓snd_pcm_hw_params() → 调用 dummy_pcm_hw_params() [本函数]↓snd_pcm_prepare() → 调用 dummy_pcm_prepare()↓snd_pcm_writei() → 音频数据传输...hw_free当 PCM 流需要释放硬件资源时如应用程序调用 snd_pcm_hw_free() 或准备重新配置硬件参数时ALSA 框架会调用此函数来释放之前分配的音频缓冲区。应用程序调用流程┌─────────────────────────────────────┐↓ │snd_pcm_open() → dummy_pcm_open() │↓ │snd_pcm_hw_params() → dummy_pcm_hw_params() [分配缓冲区] │↓ │音频播放/录制... │↓ │snd_pcm_hw_free() → dummy_pcm_hw_free() [释放缓冲区] ────────┘↓snd_pcm_hw_params() → 可重新配置参数再次分配缓冲区prepare当 PCM 流准备好开始数据传输时如应用程序调用 snd_pcm_prepare() ALSA 框架会调用此函数来初始化硬件状态为即将开始的音频传输做准备。应用程序调用流程snd_pcm_open() → dummy_pcm_open() [打开设备]↓snd_pcm_hw_params() → dummy_pcm_hw_params() [配置参数分配缓冲区]↓snd_pcm_prepare() → dummy_pcm_prepare() [准备传输 ← 本函数]↓snd_pcm_writei/readi → 开始音频数据传输↓snd_pcm_drop/drain() → dummy_pcm_trigger(STOP) [停止传输]↓snd_pcm_prepare() → dummy_pcm_prepare() [再次准备可重复]trigger当需要控制音频流的启动、停止、暂停或恢复时ALSA 框架会调用此函数。它是音频数据传输的 控制中心 负责将应用程序的控制命令转换为硬件操作。命令 含义 触发场景SNDRV_PCM_TRIGGER_START 开始传输 首次开始播放/录制SNDRV_PCM_TRIGGER_RESUME 恢复传输 从暂停状态恢复SNDRV_PCM_TRIGGER_STOP 停止传输 正常停止播放SNDRV_PCM_TRIGGER_SUSPEND 挂起传输 系统挂起/休眠应用程序调用流程【开始播放】snd_pcm_writei() 数据写入 → 内部调用 snd_pcm_start()↓SNDRV_PCM_TRIGGER_START↓dummy_pcm_trigger(START)↓启动定时器 → 开始音频传输【停止播放】snd_pcm_drop() 或 snd_pcm_drain()↓SNDRV_PCM_TRIGGER_STOP↓dummy_pcm_trigger(STOP)↓停止定时器 → 停止音频传输【暂停/恢复】snd_pcm_pause() → SNDRV_PCM_TRIGGER_SUSPEND → 停止定时器↓snd_pcm_pause(0) → SNDRV_PCM_TRIGGER_RESUME → 启动定时器pointerALSA 框架通过此函数获取当前音频硬件在 DMA 缓冲区中的位置指针。这个指针表示硬件已经处理播放或录制了多少帧音频数据。为什么需要 pointer 函数1. 缓冲区管理ALSA 使用环形缓冲区ring buffer进行音频数据传输┌────────────────────────────────────────────────────────┐│ DMA 缓冲区 (环形) │├────────────────────────────────────────────────────────┤│ 已播放区域 │ 当前播放位置 │ 待播放区域 ││ (可写入) │ hw_ptr (硬件读位置) ▼ │ (应用程序写入) │├────────────┼─────────────────┼─────────────────────────┤│ │ │ ││ -- appl_ptr ││ (应用写位置) ││ │ │ │└────────────┴─────────────────┴─────────────────────────┘- hw_ptr (硬件指针) : 硬件当前读取/写入的位置- appl_ptr (应用指针) : 应用程序当前读取/写入的位置2. 流程控制ALSA 通过比较 hw_ptr 和 appl_ptr 来- 计算可用空间应用程序可以写入多少数据- 检测溢出/欠载XRUN- 决定何时唤醒等待的应用程序