1. 车载音频系统ALSA驱动开发环境搭建
任务目标
编写一个最小化的ALSA驱动模块,向内核注册一个虚拟声卡(card),加载后能在 /proc/asound/cards 中看到该声卡条目,卸载后条目消失。本案例不涉及PCM数据通路,仅完成声卡设备的注册与注销,用于理解ALSA驱动的基本骨架。
环境与依赖
- Linux内核源码树(版本需与运行内核匹配),已配置好内核模块编译环境
- 内核需开启
CONFIG_SND与CONFIG_SND_DYNAMIC_MINORS(通常默认开启) - 目标板或开发机可加载/卸载内核模块(root权限)
核心实现
驱动通过 snd_card_new 创建声卡对象,设置驱动名称和ID后调用 snd_card_register 注册。模块加载时执行创建与注册,卸载时执行注销与释放。完整代码如下:
#include <linux/module.h>
#include <linux/slab.h>
#include <sound/core.h>
static int my_card_index = -1; // 由内核自动分配
static struct snd_card *card;
static int __init my_alsa_init(void)
{
int err;
// 第一步:创建声卡对象
// idx=-1 表示由内核自动选择编号;id 为声卡标识字符串
err = snd_card_new(&platform_device, my_card_index, "mycard",
THIS_MODULE, 0, &card);
if (err < 0) {
pr_err("myalsa: snd_card_new failed: %d\n", err);
return err;
}
// 第二步:注册声卡到 ALSA 核心
err = snd_card_register(card);
if (err < 0) {
pr_err("myalsa: snd_card_register failed: %d\n", err);
snd_card_free(card);
return err;
}
pr_info("myalsa: virtual sound card registered\n");
return 0;
}
static void __exit my_alsa_exit(void)
{
if (card) {
snd_card_unregister(card); // 注销声卡
snd_card_free(card); // 释放声卡对象
card = NULL;
}
pr_info("myalsa: virtual sound card unregistered\n");
}
module_init(my_alsa_init);
module_exit(my_alsa_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Minimal ALSA virtual sound card driver");
注意:snd_card_new 的第一个参数需要传入一个有效的 struct device *。在无具体硬件总线的情况下,可使用 platform_device 或直接传 NULL(内核版本较新时允许)。若编译报错,请包含 <linux/platform_device.h> 并定义一个全局 struct platform_device *pdev,在 snd_card_new 前调用 platform_device_register_simple("myalsa", -1, NULL, 0) 获取设备指针。
编译与加载
创建 Makefile:
obj-m := myalsa.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 myalsa.ko
验证方法
加载模块后执行以下命令,观察输出:
cat /proc/asound/cards
预期能看到类似条目:
1 [mycard ]: myalsa - myalsa
myalsa
其中编号可能不同,但 mycard 标识和 myalsa 驱动名必须出现。同时执行 ls /dev/snd/ 应能看到 controlC1(编号与cards中一致)设备节点。卸载模块:
sudo rmmod myalsa
cat /proc/asound/cards # mycard 条目消失
判定通过条件:加载后 /proc/asound/cards 出现 mycard 条目,/dev/snd/ 下生成对应 controlC* 节点;卸载后两者均消失,且 dmesg 无错误日志。
常见问题
- insmod报错“Unknown symbol snd_card_new”:说明内核未加载ALSA核心模块,先执行
modprobe snd或确认内核配置CONFIG_SND已开启。 - snd_card_new传入NULL编译失败:内核版本较老要求非空device指针,按上文说明注册一个platform device即可。
- 声卡编号不连续:属正常现象,内核按空闲编号分配,不影响功能验证。