Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 548a648b authored by Takashi Iwai's avatar Takashi Iwai Committed by Jaroslav Kysela
Browse files

[ALSA] Fix control/status mmap with shared PCM substream



The flag to avoid 32bit-incompatible mmap for control/status records
should be outside the pcm substream instance since a substream can be
shared among multiple opens.  Now it's flagged in pcm_file list that
is directly assigned to file->private_data.
Also, removed snd_pcm_add_file() and remove_file() functions and
substream.files field that are not really used in the code.

Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarJaroslav Kysela <perex@suse.cz>
parent 1c398558
Loading
Loading
Loading
Loading
+1 −3
Original line number Diff line number Diff line
@@ -190,7 +190,7 @@ struct snd_pcm_ops {

struct snd_pcm_file {
	struct snd_pcm_substream *substream;
	struct snd_pcm_file *next;
	int no_compat_mmap;
};

struct snd_pcm_hw_rule;
@@ -384,7 +384,6 @@ struct snd_pcm_substream {
	struct snd_info_entry *proc_prealloc_entry;
#endif
	/* misc flags */
	unsigned int no_mmap_ctrl: 1;
	unsigned int hw_opened: 1;
};

@@ -402,7 +401,6 @@ struct snd_pcm_str {
	/* -- OSS things -- */
	struct snd_pcm_oss_stream oss;
#endif
	struct snd_pcm_file *files;
#ifdef CONFIG_SND_VERBOSE_PROCFS
	struct snd_info_entry *proc_root;
	struct snd_info_entry *proc_info_entry;
+1 −1
Original line number Diff line number Diff line
@@ -478,7 +478,7 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
	 * mmap of PCM status/control records because of the size
	 * incompatibility.
	 */
	substream->no_mmap_ctrl = 1;
	pcm_file->no_compat_mmap = 1;

	switch (cmd) {
	case SNDRV_PCM_IOCTL_PVERSION:
+10 −39
Original line number Diff line number Diff line
@@ -1992,35 +1992,9 @@ int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream)
	return 0;
}

static void snd_pcm_add_file(struct snd_pcm_str *str,
			     struct snd_pcm_file *pcm_file)
{
	pcm_file->next = str->files;
	str->files = pcm_file;
}

static void snd_pcm_remove_file(struct snd_pcm_str *str,
				struct snd_pcm_file *pcm_file)
{
	struct snd_pcm_file * pcm_file1;
	if (str->files == pcm_file) {
		str->files = pcm_file->next;
	} else {
		pcm_file1 = str->files;
		while (pcm_file1 && pcm_file1->next != pcm_file)
			pcm_file1 = pcm_file1->next;
		if (pcm_file1 != NULL)
			pcm_file1->next = pcm_file->next;
	}
}

static void pcm_release_private(struct snd_pcm_substream *substream)
{
	struct snd_pcm_file *pcm_file = substream->file;

	snd_pcm_unlink(substream);
	snd_pcm_remove_file(substream->pstr, pcm_file);
	kfree(pcm_file);
}

void snd_pcm_release_substream(struct snd_pcm_substream *substream)
@@ -2060,7 +2034,6 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
		return 0;
	}

	substream->no_mmap_ctrl = 0;
	err = snd_pcm_hw_constraints_init(substream);
	if (err < 0) {
		snd_printd("snd_pcm_hw_constraints_init failed\n");
@@ -2105,19 +2078,16 @@ static int snd_pcm_open_file(struct file *file,
	if (err < 0)
		return err;

	if (substream->ref_count > 1)
		pcm_file = substream->file;
	else {
	pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL);
	if (pcm_file == NULL) {
		snd_pcm_release_substream(substream);
		return -ENOMEM;
	}
	pcm_file->substream = substream;
	if (substream->ref_count == 1) {
		str = substream->pstr;
		substream->file = pcm_file;
		substream->pcm_release = pcm_release_private;
		pcm_file->substream = substream;
		snd_pcm_add_file(str, pcm_file);
	}
	file->private_data = pcm_file;
	*rpcm_file = pcm_file;
@@ -2209,6 +2179,7 @@ static int snd_pcm_release(struct inode *inode, struct file *file)
	fasync_helper(-1, file, 0, &substream->runtime->fasync);
	mutex_lock(&pcm->open_mutex);
	snd_pcm_release_substream(substream);
	kfree(pcm_file);
	mutex_unlock(&pcm->open_mutex);
	wake_up(&pcm->open_wait);
	module_put(pcm->card->module);
@@ -3270,11 +3241,11 @@ static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)
	offset = area->vm_pgoff << PAGE_SHIFT;
	switch (offset) {
	case SNDRV_PCM_MMAP_OFFSET_STATUS:
		if (substream->no_mmap_ctrl)
		if (pcm_file->no_compat_mmap)
			return -ENXIO;
		return snd_pcm_mmap_status(substream, file, area);
	case SNDRV_PCM_MMAP_OFFSET_CONTROL:
		if (substream->no_mmap_ctrl)
		if (pcm_file->no_compat_mmap)
			return -ENXIO;
		return snd_pcm_mmap_control(substream, file, area);
	default: