Linux 音频子系统分析2(基于Linux6.6)---ALSA Framework介绍
一、ALSA架构
1.1、ALSA架构概述
ALSA 的架构可以分为几个关键组件,它们协同工作以提供全面的音频功能:
1. 硬件抽象层 (Hardware Abstraction Layer, HAL)
- ALSA 通过硬件抽象层将不同音频硬件的细节封装起来,为上层应用提供统一的接口。这样应用程序和用户空间的音频工具就可以与硬件解耦,避免了与具体硬件的耦合。
2. 内核驱动 (Kernel Driver)
- ALSA 内核驱动与硬件设备进行直接交互。每个音频硬件通常有一个相应的内核模块来支持 ALSA 的音频接口。音频设备通过设备文件与用户空间进行通信。常见的音频设备如声卡、USB 音频设备、虚拟音频设备等,都可以通过相应的 ALSA 驱动进行管理。
- 驱动层包含以下几类:
- PCM 驱动:处理音频数据的播放与录制。
- MIDI 驱动:处理 MIDI 数据。
- 混音驱动:提供多个音频流的混合功能。
- 音量控制:管理音量、静音等操作。
3. ALSA库 (ALSA Library)
- ALSA 库提供了一个用户空间的接口,简化了应用程序与 ALSA 驱动的交互。应用程序可以通过该库来控制音频设备,进行音频播放、录制等操作。
- 主要库函数包括:
snd_pcm_*(用于PCM数据流的控制),snd_mixer_*(用于音量和音频效果控制),snd_seq_*(用于 MIDI 数据流)。
4. 音频应用接口 (Audio Application Interface)
- ALSA 提供了对不同音频应用程序的支持。应用程序可以通过 ALSA API(如
snd_pcm、snd_mixer等)来进行音频数据的读取、写入、音量控制等操作。常见的音频应用程序包括音频播放器、录音软件、音频编辑器等。 - PCM(Pulse Code Modulation):ALSA 支持 PCM 数据流,是大多数音频应用程序的基本音频格式。它允许应用程序直接读取或写入数字音频数据流。
- MIDI:ALSA 提供对 MIDI 数据的支持,使得应用程序可以通过 MIDI 协议与外部 MIDI 设备进行通信。
5. 声卡设备接口
- ALSA 提供了标准的设备文件接口,通常位于
/dev/snd/目录下。常见的设备文件包括:- /dev/snd/pcmC0D0p:音频播放设备(PCM playback)
- /dev/snd/pcmC0D0c:音频录制设备(PCM capture)
- /dev/snd/controlC0:控制设备(例如音量控制)
- /dev/snd/seq:MIDI 设备文件
这些设备文件通过用户空间应用访问硬件进行音频数据的读写。
6. ALSA Mixer
- ALSA 提供了一个音量混音器接口,允许用户控制音量、增益、音频效果等。混音器允许管理多个音频流的混合,支持硬件和软件混音。
amixer命令行工具可用于与混音器交互,调节音量、选择输入源等。
7. ALSA 的多通道支持
- ALSA 提供了对多声道音频的支持,允许在同一时间进行多路音频数据的传输。通过 PCM 驱动,用户可以同时播放或录制多个音频通道(例如,5.1 声道或 7.1 声道音频)。
- 支持硬件和软件的多通道配置。
8. 中间层(例如,PulseAudio 或 JACK)
- 虽然 ALSA 本身是一个低层次的音频框架,但许多现代音频应用和桌面环境使用中间层(例如 PulseAudio 或 JACK)来提供更高层次的音频管理功能。
- PulseAudio:通常作为 ALSA 的上层音频服务器,提供更高层次的音频流管理、音频设备的虚拟化以及更丰富的网络音频功能。
- JACK:一个专业级的低延迟音频服务器,适用于实时音频应用,特别是音频制作和实时音频处理。
1.2、ALSA 工作流程示意
- 应用程序:通过 ALSA 库与内核驱动进行交互,发出音频播放、录制等操作请求。
- ALSA 库:将应用程序的请求转换为适当的系统调用,管理 PCM 数据流、MIDI、音量控制等。
- 内核驱动:驱动与硬件音频设备通信,将音频数据传输到硬件或从硬件中读取音频数据。
- 硬件设备:执行实际的音频数据传输,输出声音或接收音频信号。
1.3、ALSA 特性总结
- 低延迟:ALSA 提供较低的音频延迟,非常适合实时音频应用。
- 硬件兼容性:支持多种音频硬件,包括 PCI 声卡、USB 声卡、蓝牙音频设备等。
- 多通道音频:ALSA 支持多声道音频数据流的处理,可以处理高达 7.1 声道的音频。
- 灵活的音频控制:ALSA 提供了对音量、混音、增益、特效等音频控制的支持。
- MIDI 支持:ALSA 支持 MIDI 数据的传输,适用于音频制作和合成器控制。
二、ALSA框架

-
User空间:主要由Alsa Libray API对应用程序提供统一的API接口,各个APP应用程序只要调用 alsa-lib 提供的 API接口来实现放音、录音、控制。现在提供了两套基本的库,tinyalsa是一个简化的alsa-lib库,现在Android的系统中主要使用它。
-
Kernel空间
| 组件 | 描述 | 功能 | 重用性 |
|---|---|---|---|
| ASOC Core | ALSA SoC(System on Chip)核心框架 | 提供通用方法和数据结构,用于音频设备驱动的实现,为音频驱动提供 ALSA Driver API。 | 为音频驱动提供标准框架,能被多种硬件平台使用。 |
| ALSA Core | ALSA 核心层 | 向上提供逻辑设备(PCM、CTL、MIDI、TIMER 等)的系统调用,向下驱动硬件设备,管理音频硬件和虚拟设备之间的交互。 | ALSA 核心层为上层应用提供了统一的接口,支持多种硬件设备。 |
| Hardware Driver | 音频硬件设备驱动 | 包含 Machine、Platform 和 Codec 三大部分,提供 ALSA Driver API,进行音频设备的初始化和工作流程管理。 | 需要根据特定的硬件平台来实现,但其中的 Machine 和 Platform 类可以在不同硬件之间共享。 |
| Codec 类 | 编解码芯片驱动 | 提供音频控制接口、音频读写 I/O 接口,支持 DAPM(动态音频路径管理)。Codec 驱动是平台无关的,并可以用于如 BT、FM、MODEM 模块。 | 可在不同的 SoC(System on Chip)中复用,增强了驱动模块的灵活性。 |
| Platform 类 | SOC 平台驱动 | 包含音频 DMA 引擎驱动、数字接口驱动(I2S、AC97、PCM)及平台特定的音频 DSP 驱动。 | 可在多个 Machine 类中重用,不依赖特定机器。 |
| Machine 类 | 作为 Codec 和 Platform 之间的桥梁 | 在 Codec 和 Platform 之间建立联系,指定具体的 Platform 和 Codec,实现这两者的协调工作。 | 每种机器(例如设备或 SoC)需要指定自己的 Machine 类,因此 Machine 类为硬件平台特定的实现。 |
2.1、Hardware Driver三者关系:
| 组件 | 描述 | 功能 | 关键特性 | 重用性 |
|---|---|---|---|---|
| Platform | 指某款 SoC 平台的音频模块,如 QCOM、OMAP、Amlogic、ATMEL 等。可以进一步细分为 CPU DAI 和 PCM DMA。 | 1. CPU DAI:负责将音频数据通过 I2S 或 PCM 总线从 TX FIFO 传输到 Codec(或反向)。<br>2. PCM DMA:负责将音频数据从 DMA 缓冲区搬运到 I2S TX FIFO。 | 1. CPU DAI:通常指 SoC 的 I2S、PCM 总线控制器。<br>2. PCM DMA:在一些场景下,某些硬件如调制解调器(modem)可能不需要 DMA。<br>3. 通过 snd_soc_register_platform() 注册音频 DMA 驱动。 | CPU DAI 和 PCM DMA 是特定于平台的,因此不能在不同硬件间通用;但通常可以通过修改 dai_link 和 platform_name 来实现一定程度的复用。 |
| Codec | 音频编解码器,处理数字和模拟音频信号转换。 | 1. DAC(数字到模拟转换):将数字音频信号转换为模拟信号,输出到扬声器或耳机。<br>2. ADC(模拟到数字转换):将模拟信号转换为数字信号。<br>3. 提供多种音频处理部件,如混音器、音量控制、EQ、DSP 等。 | 1. 常见功能:AIF(音频接口)、DAC、ADC、Mixer、PGA(功率放大器)、Line-in/out 等。<br>2. 高端 Codec 芯片支持更多处理模块:EQ、DSP、AGC(自动增益控制)、噪声抑制等。 | Codec 驱动 是平台无关的,可在多种 SoC 平台上复用。 |
| Machine | 某款设备的音频驱动配置,通过 dai_link 将 CPU DAI、Codec DAI 等音频接口串联起来,最终注册 snd_soc_card。 | 1. 配置并连接多个音频接口(如 CPU DAI、Codec DAI 等),并指定硬件特性。<br>2. 注册 snd_soc_card,使音频硬件配置生效。<br>3. 处理硬件特性,如 GPIO 控制、时钟源选择等。 | 1. 硬件特性:例如不同平台与 Codec 的差异、DAI 接口连接方式、GPIO 控制 Amplifier、耳机插拔检测、时钟源(MCLK 或 External-OSC)等。<br>2. 针对特定硬件平台配置,因此不具有通用性。 | Machine 配置是特定于某款设备或 SoC 平台的,几乎不可重用。 |

三、ALSA核心层
核心层为用户空间提供逻辑设备接口, 同时为驱动提供接口来驱动硬件设备, 主要位于sound/core目录下。

分析是谁调用snd_register_device_for_dev函数来注册sound设备的。

3.1、字符设备注册
sound/core/sound.c
/*
* INIT PART
*/
static int __init alsa_sound_init(void)
{
snd_major = major;
snd_ecards_limit = cards_limit;
if (register_chrdev(major, "alsa", &snd_fops)) {
pr_err("ALSA core: unable to register native major device number %d\n", major);
return -EIO;
}
if (snd_info_init() < 0) {
unregister_chrdev(major, "alsa");
return -ENOMEM;
}
#ifdef CONFIG_SND_DEBUG
sound_debugfs_root = debugfs_create_dir("sound", NULL);
#endif
#ifndef MODULE
pr_info("Advanced Linux Sound Architecture Driver Initialized.\n");
#endif
return 0;
}
文件操作是snd_fops,snd_open接口比较重要,snd_open接口通过文件节点inode得到了次设备号,通过snd_minors数组得到对应的声音逻辑设备的文件操作,调用对应的open接口,并调用fops_put替换成了对应的逻辑设备的文件操作。
snd_info_init创建proc目录下的asound,并在该目录下分别建立version EVM card0 cards device pcm timers,用来查看相关的信息。
sound/core/sound.c
static const struct file_operations snd_fops =
{
.owner = THIS_MODULE,
.open = snd_open,
.llseek = noop_llseek,
}
alsa驱动设备文件结构:

- controlC0 :用于声卡的控制,例如通道选择,混音,麦克风的控制等
- pcmC0D0c:用于录音的pcm设备
- pcmC0D0p:用于播放的pcm设备
- seq :音序器
- timer :定时器
其中, C0D0代表的是声卡0中的设备0, pcmC0D0c最后一个c代表capture, pcmC0D0p最后一个p代表playback,这些都是alsa-driver中的命名规则。

- cards : 可显示系统中存在多少个声卡
- card0 : 代表某个声卡
- devices : 可显示系统中存在多少个逻辑设备
/proc/asound/card0:该节点提供该card的一些info.

3.2、数据结构

在 ALSA(Advanced Linux Sound Architecture)中,音频驱动的结构通常由多个层次组成,每个层次都有对应的关键数据结构。这些数据结构用于描述声卡、设备、PCM 流、控制以及相关的操作和功能。下面是一些常见的结构及其描述:
主要数据结构解释:
| 数据结构 | 描述 | 作用 |
|---|---|---|
| snd_card | 表示一个声卡实例,包含多个声卡设备。 | 它是 ALSA 中的顶层数据结构,负责表示整个声卡,包含该声卡的硬件和设备信息。每个声卡通常由多个设备组成。通过 snd_card_new() 创建并注册。 |
| snd_device | 表示一个声卡设备部件。 | 声卡设备可以有多个不同的部件(例如 PCM、控制设备等),每个部件由 snd_device 数据结构表示。它与硬件设备直接对应。 |
| snd_pcm | 表示一个 PCM 设备,通常用于播放和录制音频数据。它是声卡的一个设备,用于管理 PCM 流。 | 用于描述 PCM 接口和硬件的功能。通常包括播放(playback)和录制(capture)两个方向。snd_pcm 通过 snd_pcm_new() 创建并与硬件关联。 |
| snd_control | 表示控制设备,通常用于控制声卡的一些设置,如音量控制、均衡器设置等。 | 控制设备通过 snd_control_new() 创建,允许应用程序与硬件交互,进行音量调节、静音控制等操作。它是 ALSA 音频驱动中非常重要的组成部分。 |
| snd_pcm_str | 表示 PCM 流,分为播放流(playback)和捕获流(capture)。 | 在 snd_pcm 内部,PCM 流(snd_pcm_str)用于描述音频数据流,通常分为播放和录制两个子流。这两个子流分别处理音频播放和录制的不同数据方向。 |
| snd_pcm_substream | 表示 PCM 子流,通常是 PCM 流的一个方向(播放或录制)。 | 一个 snd_pcm_substream 对象对应一个 PCM 流的子流,用于描述播放流(playback)或录制流(capture)。它保存与音频数据流相关的具体信息,如缓冲区、硬件状态等。 |
| snd_pcm_ops | PCM 流操作集,包含与 PCM 设备交互的操作函数。 | 这是一个函数指针集合,用于处理 PCM 设备的常见操作,如打开、关闭、准备、写入、读取等操作。每个 PCM 设备都需要实现该操作集。 |
各个数据结构的详细解释:
-
snd_card(声卡实例):- 功能:
snd_card是 ALSA 中用于表示一个声卡的顶层结构,它通常包含多个音频设备(如 PCM 设备、控制设备等)。通过snd_card_register()注册声卡实例。每个声卡实例可能有多个设备和子设备。 - 成员:它包含有关声卡的各种信息,如名称、ID、功能等,还包含对其他设备的引用。
- 功能:
-
snd_device(设备部件):- 功能:
snd_device用于表示声卡中的每个具体部件或设备,例如 PCM 设备、控制设备、MIDI 设备等。它通常由声卡的其他设备驱动来管理。 - 成员:它包含设备类型、状态等信息,可以通过
snd_device_new()创建。
- 功能:
-
snd_pcm(PCM 设备):- 功能:
snd_pcm用于描述 PCM 接口及其相关硬件操作,如音频播放和录制。它表示一个具体的音频流(playback 或 capture)以及其操作。 - 成员:包括 PCM 流的配置(采样率、位深度等)、缓冲区、状态和相关的操作函数等。
- 功能:
-
snd_control(控制设备):- 功能:控制设备用于设置和管理声卡的控制接口,如音量调节、静音、均衡器设置等。
snd_control通过接口来控制硬件的各种参数。 - 成员:包括与控制相关的各种操作,如设置、获取音量、修改均衡器设置等。
- 功能:控制设备用于设置和管理声卡的控制接口,如音量调节、静音、均衡器设置等。
-
snd_pcm_str(PCM 流):- 功能:
snd_pcm_str用于描述 PCM 设备中的一个音频数据流。每个 PCM 设备有两个方向:播放(playback)和录制(capture),这两个方向由不同的snd_pcm_str表示。 - 成员:包含与 PCM 流相关的信息,如数据缓冲区、数据流方向(播放或录制)、采样率等。
- 功能:
-
snd_pcm_substream(PCM 子流):- 功能:
snd_pcm_substream用于描述单一的 PCM 流(即播放或录制),每个子流对应一个方向的数据传输。一个snd_pcm设备通常会有多个snd_pcm_substream。 - 成员:包括与该子流相关的缓冲区、状态信息、操作函数等。
- 功能:
-
snd_pcm_ops(PCM 流操作集):- 功能:
snd_pcm_ops是 PCM 流的操作集合,包含处理 PCM 流操作的函数指针。例如,用于打开、关闭、准备、读取和写入 PCM 流等操作。 - 成员:包括许多函数指针,例如
open、close、prepare、trigger、hw_params、hw_free等。
- 功能:

snd_card主要字段如下:
include/sound/core.h
struct snd_card {
int number; /* number of soundcard (index to
snd_cards) */
char id[16]; /* id string of this card */
char driver[16]; /* driver name */
char shortname[32]; /* short name of this soundcard */
char longname[80]; /* name of this soundcard */
char irq_descr[32]; /* Interrupt description */
char mixername[80]; /* mixer name */
char components[128]; /* card components delimited with
space */
struct module *module; /* top-level module */
void *private_data; /* private data for soundcard */
void (*private_free) (struct snd_card *card); /* callback for freeing of
private data */
struct list_head devices; /* devices */
struct device ctl_dev; /* control device */
unsigned int last_numid; /* last used numeric ID */
struct rw_semaphore controls_rwsem; /* controls list lock */
rwlock_t ctl_files_rwlock; /* ctl_files list lock */
int controls_count; /* count of all controls */
size_t user_ctl_alloc_size; // current memory allocation by user controls.
struct list_head controls; /* all controls for this card */
struct list_head ctl_files; /* active control files */
#ifdef CONFIG_SND_CTL_FAST_LOOKUP
struct xarray ctl_numids; /* hash table for numids */
struct xarray ctl_hash; /* hash table for ctl id matching */
bool ctl_hash_collision; /* ctl_hash collision seen? */
#endif
struct snd_info_entry *proc_root; /* root for soundcard specific files */
struct proc_dir_entry *proc_root_link; /* number link to real id */
struct list_head files_list; /* all files associated to this card */
struct snd_shutdown_f_ops *s_f_ops; /* file operations in the shutdown
state */
spinlock_t files_lock; /* lock the files for this card */
int shutdown; /* this card is going down */
struct completion *release_completion;
struct device *dev; /* device assigned to this card */
struct device card_dev; /* cardX object for sysfs */
const struct attribute_group *dev_groups[4]; /* assigned sysfs attr */
bool registered; /* card_dev is registered? */
bool managed; /* managed via devres */
bool releasing; /* during card free process */
int sync_irq; /* assigned irq, used for PCM sync */
wait_queue_head_t remove_sleep;
size_t total_pcm_alloc_bytes; /* total amount of allocated buffers */
struct mutex memory_mutex; /* protection for the above */
#ifdef CONFIG_SND_DEBUG
struct dentry *debugfs_root; /* debugfs root for card */
#endif
#ifdef CONFIG_PM
unsigned int power_state; /* power state */
atomic_t power_ref;
wait_queue_head_t power_sleep;
wait_queue_head_t power_ref_sleep;
#endif
#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
struct snd_mixer_oss *mixer_oss;
int mixer_oss_change_count;
#endif
};
snd_device主要字段如下:
include/sound/core.h
struct snd_device {
struct list_head list; /* list of registered devices */
struct snd_card *card; /* card which holds this device */
enum snd_device_state state; /* state of the device */
enum snd_device_type type; /* device type */
void *device_data; /* device structure */
const struct snd_device_ops *ops; /* operations */
};
snd_pcm主要字段如下:
include/sound/pcm.h
struct snd_pcm {
struct snd_card *card;
struct list_head list;
int device; /* device number */
unsigned int info_flags;
unsigned short dev_class;
unsigned short dev_subclass;
char id[64];
char name[80];
struct snd_pcm_str streams[2];
struct mutex open_mutex;
wait_queue_head_t open_wait;
void *private_data;
void (*private_free) (struct snd_pcm *pcm);
bool internal; /* pcm is for internal use only */
bool nonatomic; /* whole PCM operations are in non-atomic context */
bool no_device_suspend; /* don't invoke device PM suspend */
#if IS_ENABLED(CONFIG_SND_PCM_OSS)
struct snd_pcm_oss oss;
#endif
};
3.3、APIs
该层主要接口如下:
/* 创建和初始化声卡结构体 */
int snd_card_new(struct device *parent, int idx, const char *xid, struct module *, int extra_size, struct snd_card **card_ret);
/* 释放声卡结构体 */
int snd_card_free(struct snd_card * card);
/* 注册声卡 */
int snd_card_register(struct snd_card * card);
/* 创建声卡设备部件, 通常由snd_pcm_new和snd_card_new自动完成 */
int snd_device_new(struct snd_card *, enum snd_device_type type, void *device_data, struct snd_device_ops *ops);
/* 注册声卡设备部件, 通常由snd_card_register自动完成 */
int snd_device_register(struct snd_card *card, void *device_data);
/* 创建PCM设备 */
int snd_pcm_new(struct snd_card *, const char *id, int device, int playback_count, int capture_count, struct snd_pcm **rpcm);
/* 创建PCM流, 通常snd_pcm_new会自动创建capture和playback两个PCM流 */
int snd_pcm_new_stream(struct snd_pcm * pcm, int stream, int substream_count);
/* 设置PCM设备操作集 */
void snd_pcm_set_ops(struct snd_pcm *, int direction, const struct snd_pcm_ops *ops);
四、card的创建与注册
struct snd_card可以说是整个ALSA音频驱动最顶层的一个结构, 整个声卡的软件逻辑结构开始于该结构, 几乎所有与声音相关的逻辑设备都是在snd_card的管理之下, 声卡驱动的第一个动作通常就是创建一个snd_card结构体。
4.1、snd_card_new
┌──────────────────────────────────────────┐
│ 1. 分配 snd_card + extra_size 空间大小 │
└──────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────┐
│ 2. 如果 extra_size > 0, │
│ 将 private_data 指向 extra_size 首地址 │
└────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────┐
│ 3. 如果指定了 xid, │
│ 将 xid 拷贝至 snd_card::id │
└────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────┐
│ 4. 根据 idx 获取可用的声卡索引并赋值给 │
│ snd_card::number │
└────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────┐
│ 5. 将 parent、module 赋值给 snd_card::dev │
│ 和 snd_card::module │
└────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────┐
│ 6. 初始化链表 snd_card::devices、 │
│ snd_card::controls、 │
│ snd_card::ctl_files、 │
│ snd_card::files_list │
└────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────┐
│ 7. 调用 device_initialize() 初始化 snd_card::card_dev │
│ 并设置相关成员变量用于 sysfs │
└────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────┐
│ 8. 调用 snd_ctl_create() 创建控制接口 │
└────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────┐
│ 8.1 调用 snd_device_initialize() 初始化 │
│ snd_card::ctl_dev, 并设置相关成员变量 │
└────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────┐
│ 8.2 调用 snd_device_new(SNDRV_DEV_CONTROL, │
│ ops) 创建声卡控制设备部件 │
└────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────┐
│ 9. 调用 snd_info_card_create() 创建 proc │
│ 对应的文件系统 │
└────────────────────────────────────────────┘
4.2、snd_card_register
函数的主要目的是注册card下面挂载的所有device; 另外只有该函数成功返回后, 用户空间才能通过control interface来访问底层。
┌──────────────────────────────────────────────────┐
│ 1. 检查 snd_card 是否为空,若为空则返回错误 │
└──────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────┐
│ 2. 检查是否已经注册过该卡,若已注册则返回错误 │
└──────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────┐
│ 3. 遍历并注册所有与 snd_card 相关联的设备 │
│ - 注册控制设备接口 │
│ - 注册其他相关设备 │
└──────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────┐
│ 4. 调用 device_register 注册每个设备,确认设备 │
│ 成功挂载到 snd_card 中 │
└──────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────┐
│ 5. 注册成功后,将 snd_card 的状态设置为已注册 │
└──────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────┐
│ 6. 成功返回,用户空间可通过 control interface │
│ 来访问底层硬件 │
└──────────────────────────────────────────────────┘
│
▼
┌─────────────────────────┐
│ 结束 │
└─────────────────────────┘
4.3、struct snd_device
一个struct snd_device用于描述一个逻辑设备,每个逻辑设备都有一个对应的snd_device_ops, 我们在新增一个逻辑设备时, 需要为此设备准备好该数据结构。
1.snd_device_new
该API用于创建一个逻辑设备, 主要内容是分配一个struct snd_device空间, 初始化相关字段, 并把该逻辑设备添加到card->devices链表下。注意在添加新设备到card->devices链表时, 采用的是有序插入方式: type小的在前、type大的在后。
2.snd_device_register
一般在注册声卡时(snd_card_register)会自动调用此处的API; 不过也可以在card注册完毕后, 在手动调用此API注册一个新的逻辑设备。
该API的实现很简单: 首先回调snd_device_ops->dev_register, 然后把核心层的状态标记为SNDRV_DEV_REGISTERED。
1529

被折叠的 条评论
为什么被折叠?



