linux音频子系统 - 驱动框架

音频相关术语

  • PCM(Pulse Code Modulation)
    脉冲编码调制,对连续变化的模拟信号进行抽样、量化和编码,在驱动中一般音频流设备都称为pcm设备

  • I2S
    I2S是对PCM格式的数据进行规范化,可以说是PCM的子集,I2S只有左右两通道数据

  • TDM(Time Division Multiplexing)
    时分复用,可以用单根线传送多通道数据

  • midi(Musical Instrument Digital Interface)
    MIDI是编曲界最广泛的音乐标准格式,可称为“计算机能理解的乐谱”。它用音符的数字控制信号来记录音乐。一首完整的MIDI音乐只有几十KB大,而能包含数十条音乐轨道。几乎所有的现代音乐都是用MIDI加上音色库来制作合成的。MIDI 传输的不是声音信号, 而是音符、控制参数等指令, 它指示MIDI 设备要做什么,怎么做, 如演奏哪个音符、多大音量等。

  • timer(音序器)
    音序器,又称声音序列发生器,可将所有MIDI通道中的演奏信息同时自动播放演奏

驱动架构图

OSS(Open Sound System),linux以前的驱动架构,现在已废弃不用

linux目前的音频框架为ALSA(Advanced Linux Sound Architecture),框架如下图所示,分三层,其中ASoc适用于目前的嵌入式设备,在ALSA-core基础上又分出一个小架构

这里写图片描述

其中alsa-core层的主要结构如下,一个声卡用snd_card来表示,在一个声卡上可能集成了好几个子设备,每个子设备负责不用的功能,分为pcm/control/midi/timer等

这里写图片描述

声卡结构体

一个声卡下是由多个设备的,总声卡用结构体snd_card来表示,各个子设备用结构体snd_device来抽象,当然对于具体的子设备,还会有相应的结构体来表示,这个会在子设备的文章中详细介绍

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 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 */---------snd_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 */
	int user_ctl_count;		/* count of all user controls */
	struct list_head controls;	/* all controls for this card */---控制设备snd_device加入此链表
	struct list_head ctl_files;	/* active control files */
	struct mutex user_ctl_lock;	/* protects user controls against
					   concurrent access */

	struct snd_info_entry *proc_root;	/* root for soundcard specific files */
	struct snd_info_entry *proc_id;	/* the card id */
	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 */
	int free_on_last_close;		/* free in context of file_release */
	wait_queue_head_t shutdown_sleep;
	atomic_t refcount;		/* refcount for disconnection */
	struct device *dev;		/* device assigned to this card */
	struct device *card_dev;	/* cardX object for sysfs */

#ifdef CONFIG_PM
	unsigned int power_state;	/* power state */
	struct mutex power_lock;	/* power lock */
	wait_queue_head_t power_sleep;
#endif

#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
	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 */-对应的声卡
	snd_device_state_t state;	/* state of the device */
	snd_device_type_t type;		/* device type */
	void *device_data;		/* device structure */------------对于具体子设备的私有数据
	struct snd_device_ops *ops;	/* operations */------------------对子设备注册的操作
};

声卡注册

snd_card_register

(sound/core/init.c)

int snd_card_register(struct snd_card *card)
{
	int err;

	if (snd_BUG_ON(!card))
		return -EINVAL;

	if (!card->card_dev) {
		card->card_dev = device_create(sound_class, card->dev,
					       MKDEV(0, 0), card,
					       "card%i", card->number);---注册声卡
		if (IS_ERR(card->card_dev))
			card->card_dev = NULL;
	}

	if ((err = snd_device_register_all(card)) < 0)-----注册声卡下的所有子设备
		return err;
	mutex_lock(&snd_card_mutex);
	if (snd_cards[card->number]) {
		/* already registered */
		mutex_unlock(&snd_card_mutex);
		return 0;
	}
	if (*card->id) {
		/* make a unique id name from the given string */
		char tmpid[sizeof(card->id)];
		memcpy(tmpid, card->id, sizeof(card->id));
		snd_card_set_id_no_lock(card, tmpid, tmpid);
	} else {
		/* create an id from either shortname or longname */
		const char *src;
		src = *card->shortname ? card->shortname : card->longname;
		snd_card_set_id_no_lock(card, src,
					retrieve_id_from_card_name(src));
	}
	snd_cards[card->number] = card;
	mutex_unlock(&snd_card_mutex);
	init_info_for_card(card);
#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
	if (snd_mixer_oss_notify_callback)
		snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_REGISTER);
#endif
	if (card->card_dev) {
		err = device_create_file(card->card_dev, &card_id_attrs);
		if (err < 0)
			return err;
		err = device_create_file(card->card_dev, &card_number_attrs);
		if (err < 0)
			return err;
	}

	return 0;
}

snd_device_register_all

int snd_device_register_all(struct snd_card *card)
{
	struct snd_device *dev;
	int err;
	
	if (snd_BUG_ON(!card))
		return -ENXIO;
	list_for_each_entry(dev, &card->devices, list) {----遍历声卡的设备链表
		if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) {
			if ((err = dev->ops->dev_register(dev)) < 0)
				return err;-----------------调用每个设备注册函数,进行注册
			dev->state = SNDRV_DEV_REGISTERED;
		}
	}
	return 0;
}

change log

datecontentlinux version
2017/11/20originlinux 3.10
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值