第4篇 sound.c分析(应用层如何调用到内核层的)

charlie12345 / 2023-09-04 / 原文

原文链接:https://blog.csdn.net/yangguoyu8023/article/details/122114620

1. alsa_sound_init

alsa的核心入口函数是sound\core\sound.c中的alsa_sound_init

static struct snd_minor *snd_minors[SNDRV_OS_MINORS];
static int snd_open(struct inode *inode, struct file *file)
{
	unsigned int minor = iminor(inode);
	struct snd_minor *mptr = NULL;
	const struct file_operations *new_fops;
	mptr = snd_minors[minor];
    .......
	new_fops = fops_get(mptr->f_ops);
    .....
	if (file->f_op->open)
		err = file->f_op->open(inode, file);
}

static const struct file_operations snd_fops =
{
	.open =		snd_open,
	.llseek =	noop_llseek,
};

static int major = CONFIG_SND_MAJOR;
static int __init alsa_sound_init(void)
{
	snd_major = major;
	snd_ecards_limit = cards_limit;
	if (register_chrdev(major, "alsa", &snd_fops)) 
}

subsys_initcall(alsa_sound_init);

1.1 snd_minors

最终会通过次设备号来匹配snd_minors,并且调用它的open函数。我们看看全局变量snd_minors在哪注册的,它是静态变量,所以在sound.c文件中搜索,发现其注册为snd_register_device。

 
/**
 * snd_register_device - Register the ALSA device file for the card
 */
int snd_register_device(int type, struct snd_card *card, int dev,
			const struct file_operations *f_ops,
			void *private_data, struct device *device)
{
	int minor;
	struct snd_minor *preg;

	preg = kmalloc(sizeof *preg, GFP_KERNEL);
	preg->type = type;
	preg->card = card ? card->number : -1;
	preg->device = dev;
	preg->f_ops = f_ops;
	preg->private_data = private_data;
	preg->card_ptr = card;
	minor = snd_find_free_minor(type, card, dev);

	device->devt = MKDEV(major, minor);
	err = device_add(device);
	snd_minors[minor] = preg;
}

1.2 snd_register_device

搜索snd_register_device,看谁调用了该函数,发现有如下函数调用了。
snd_pcm_dev_register
snd_ctl_dev_register

2 以pcm和clt的调用关系来分析如何注册snd_minors

2.1 pcm注册snd_minors

snd_pcm_new->_snd_pcm_new->snd_pcm_dev_register->snd_register_device

2.1.1 snd_pcm_new

snd_pcm_new
	|
	|_snd_pcm_new(card, id, device, playback_count, capture_count, false, rpcm);
	
	 
static int _snd_pcm_new(struct snd_card *card, const char *id, int device,
		int playback_count, int capture_count, bool internal,
		struct snd_pcm **rpcm)
{
	struct snd_pcm *pcm;
	static struct snd_device_ops ops = {
		.dev_free = snd_pcm_dev_free,
		.dev_register =	snd_pcm_dev_register,
		.dev_disconnect = snd_pcm_dev_disconnect,
	};
........
	err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count);
	err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_CAPTURE, capture_count);

	err = snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops);
}

 
static int snd_pcm_dev_register(struct snd_device *device)
{
..............
	err = snd_pcm_add(pcm);

	for (cidx = 0; cidx < 2; cidx++) {
		int devtype = -1;
		if (pcm->streams[cidx].substream == NULL)
			continue;
		switch (cidx) {
		case SNDRV_PCM_STREAM_PLAYBACK:
			devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK;
			break;
		case SNDRV_PCM_STREAM_CAPTURE:
			devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;
			break;
		}
		/* register pcm */
		err = snd_register_device(devtype, pcm->card, pcm->device, &snd_pcm_f_ops[cidx], pcm,
        .............
	}
 
	pcm_call_notify(pcm, n_register);

}