1. ALSA驱动框架初探
任务目标
编写一个最小的虚拟声卡驱动,完成以下功能:
- 注册一个
snd_card实例 - 在声卡上创建一个 PCM 播放设备
- 驱动加载后,通过
/proc/asound/cards能看到新声卡条目
环境与依赖
- Linux 内核源码树(本案例基于 5.15 版本验证)
- 已安装内核头文件与编译工具链(
make、gcc) - 内核配置需启用 ALSA 支持(
CONFIG_SND)
核心实现
驱动通过 snd_card_new 创建声卡,注册 PCM 设备后调用 snd_card_register 使声卡在 ALSA 核心中可见。PCM 设备的 open/close 回调仅做空操作,用于满足设备创建的最小要求。
#include <linux/module.h>
#include <linux/platform_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
static struct snd_card *card;
static struct snd_pcm *pcm;
static int dummy_pcm_open(struct snd_pcm_substream *substream)
{
return 0;
}
static int dummy_pcm_close(struct snd_pcm_substream *substream)
{
return 0;
}
static const struct snd_pcm_ops dummy_pcm_ops = {
.open = dummy_pcm_open,
.close = dummy_pcm_close,
};
static int dummy_snd_probe(struct platform_device *pdev)
{
int ret;
ret = snd_card_new(&pdev->dev, -1, "dummycard", THIS_MODULE,
sizeof(struct snd_card *), &card);
if (ret < 0)
return ret;
ret = snd_pcm_new(card, "dummy PCM", 0, 1, 0, &pcm);
if (ret < 0)
goto fail_pcm;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &dummy_pcm_ops);
strcpy(pcm->name, "Dummy PCM Device");
ret = snd_card_register(card);
if (ret < 0)
goto fail_register;
platform_set_drvdata(pdev, card);
return 0;
fail_register:
fail_pcm:
snd_card_free(card);
return ret;
}
static int dummy_snd_remove(struct platform_device *pdev)
{
card = platform_get_drvdata(pdev);
if (card)
snd_card_free(card);
return 0;
}
static struct platform_driver dummy_snd_driver = {
.probe = dummy_snd_probe,
.remove = dummy_snd_remove,
.driver = {
.name = "dummy_alsa_card",
},
};
static struct platform_device *dummy_snd_device;
static int __init dummy_snd_init(void)
{
int ret;
ret = platform_driver_register(&dummy_snd_driver);
if (ret < 0)
return ret;
dummy_snd_device = platform_device_register_simple("dummy_alsa_card",
-1, NULL, 0);
if (IS_ERR(dummy_snd_device)) {
platform_driver_unregister(&dummy_snd_driver);
return PTR_ERR(dummy_snd_device);
}
return 0;
}
static void __exit dummy_snd_exit(void)
{
platform_device_unregister(dummy_snd_device);
platform_driver_unregister(&dummy_snd_driver);
}
module_init(dummy_snd_init);
module_exit(dummy_snd_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ALSA Course");
MODULE_DESCRIPTION("Minimal dummy ALSA sound card driver");
Makefile
obj-m := dummy_alsa.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean
编译与加载
# 编译
make
# 加载驱动
sudo insmod dummy_alsa.ko
# 查看声卡是否注册成功
cat /proc/asound/cards
验证方法
执行 cat /proc/asound/cards 后,预期输出中应包含类似以下条目:
1 [dummycard ]: dummycard - dummycard
dummycard
其中 dummycard 为驱动中通过 snd_card_new 设置的声卡名称。同时执行 ls /proc/asound/ 应能看到对应的声卡目录(如 card1)。若上述条目出现,则说明声卡注册成功,PCM 设备已创建。
卸载驱动
sudo rmmod dummy_alsa
卸载后再次执行 cat /proc/asound/cards,确认对应条目消失。