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

Commit 3bf75f9b authored by Takashi Iwai's avatar Takashi Iwai Committed by Jaroslav Kysela
Browse files

[ALSA] Clean up PCM codes (take 2)



- Clean up initialization and destruction of substream instance
  Now snd_pcm_open_substream() alone does most initialization jobs.
  Add pcm_release callback for cleaning up at snd_pcm_release_substream()
- Tidy up PCM oss code

Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent bf1bbb5a
Loading
Loading
Loading
Loading
+7 −5
Original line number Diff line number Diff line
@@ -369,6 +369,7 @@ struct snd_pcm_substream {
	/* -- assigned files -- */
	struct snd_pcm_file *file;
	struct file *ffile;
	void (*pcm_release)(struct snd_pcm_substream *);
#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
	/* -- OSS things -- */
	struct snd_pcm_oss_substream oss;
@@ -381,13 +382,10 @@ struct snd_pcm_substream {
	struct snd_info_entry *proc_prealloc_entry;
	/* misc flags */
	unsigned int no_mmap_ctrl: 1;
	unsigned int hw_opened: 1;
};

#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
#define SUBSTREAM_BUSY(substream) ((substream)->file != NULL || ((substream)->oss.file != NULL))
#else
#define SUBSTREAM_BUSY(substream) ((substream)->file != NULL)
#endif


struct snd_pcm_str {
@@ -468,8 +466,12 @@ int snd_pcm_suspend(struct snd_pcm_substream *substream);
int snd_pcm_suspend_all(struct snd_pcm *pcm);
#endif
int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg);
int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, struct snd_pcm_substream **rsubstream);
int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, struct file *file,
			   struct snd_pcm_substream **rsubstream);
void snd_pcm_release_substream(struct snd_pcm_substream *substream);
int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, struct file *file,
			     struct snd_pcm_substream **rsubstream);
void snd_pcm_detach_substream(struct snd_pcm_substream *substream);
void snd_pcm_vma_notify_data(void *client, void *data);
int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, struct vm_area_struct *area);

+0 −1
Original line number Diff line number Diff line
@@ -70,7 +70,6 @@ struct snd_pcm_oss_file {
struct snd_pcm_oss_substream {
	unsigned oss: 1;			/* oss mode */
	struct snd_pcm_oss_setup *setup;		/* active setup */
	struct snd_pcm_oss_file *file;
};

struct snd_pcm_oss_stream {
+44 −107
Original line number Diff line number Diff line
@@ -1671,6 +1671,18 @@ static struct snd_pcm_oss_setup *snd_pcm_oss_look_for_setup(struct snd_pcm *pcm,
	return NULL;
}

static void snd_pcm_oss_release_substream(struct snd_pcm_substream *substream)
{
	struct snd_pcm_runtime *runtime;
	runtime = substream->runtime;
	vfree(runtime->oss.buffer);
	runtime->oss.buffer = NULL;
#ifdef CONFIG_SND_PCM_OSS_PLUGINS
	snd_pcm_oss_plugin_clear(substream);
#endif
	substream->oss.oss = 0;
}

static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream,
				       struct snd_pcm_oss_setup *setup,
				       int minor)
@@ -1679,6 +1691,10 @@ static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream,

	substream->oss.oss = 1;
	substream->oss.setup = setup;
	if (setup->nonblock)
		substream->ffile->f_flags |= O_NONBLOCK;
	else
		substream->ffile->f_flags &= ~O_NONBLOCK;
	runtime = substream->runtime;
	runtime->oss.params = 1;
	runtime->oss.trigger = 1;
@@ -1697,18 +1713,7 @@ static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream,
	runtime->oss.fragshift = 0;
	runtime->oss.maxfrags = 0;
	runtime->oss.subdivision = 0;
}

static void snd_pcm_oss_release_substream(struct snd_pcm_substream *substream)
{
	struct snd_pcm_runtime *runtime;
	runtime = substream->runtime;
	vfree(runtime->oss.buffer);
#ifdef CONFIG_SND_PCM_OSS_PLUGINS
	snd_pcm_oss_plugin_clear(substream);
#endif
	substream->oss.file = NULL;
	substream->oss.oss = 0;
	substream->pcm_release = snd_pcm_oss_release_substream;
}

static int snd_pcm_oss_release_file(struct snd_pcm_oss_file *pcm_oss_file)
@@ -1717,22 +1722,7 @@ static int snd_pcm_oss_release_file(struct snd_pcm_oss_file *pcm_oss_file)
	snd_assert(pcm_oss_file != NULL, return -ENXIO);
	for (cidx = 0; cidx < 2; ++cidx) {
		struct snd_pcm_substream *substream = pcm_oss_file->streams[cidx];
		struct snd_pcm_runtime *runtime;
		if (substream == NULL)
			continue;
		runtime = substream->runtime;
		
		snd_pcm_stream_lock_irq(substream);
		if (snd_pcm_running(substream))
			snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
		snd_pcm_stream_unlock_irq(substream);
		if (substream->ffile != NULL) {
			if (substream->ops->hw_free != NULL)
				substream->ops->hw_free(substream);
			substream->ops->close(substream);
			substream->ffile = NULL;
		}
		snd_pcm_oss_release_substream(substream);
		if (substream)
			snd_pcm_release_substream(substream);
	}
	kfree(pcm_oss_file);
@@ -1743,12 +1733,11 @@ static int snd_pcm_oss_open_file(struct file *file,
				 struct snd_pcm *pcm,
				 struct snd_pcm_oss_file **rpcm_oss_file,
				 int minor,
				 struct snd_pcm_oss_setup *psetup,
				 struct snd_pcm_oss_setup *csetup)
				 struct snd_pcm_oss_setup **setup)
{
	int err = 0;
	int idx, err;
	struct snd_pcm_oss_file *pcm_oss_file;
	struct snd_pcm_substream *psubstream = NULL, *csubstream = NULL;
	struct snd_pcm_substream *substream;
	unsigned int f_mode = file->f_mode;

	snd_assert(rpcm_oss_file != NULL, return -EINVAL);
@@ -1761,72 +1750,30 @@ static int snd_pcm_oss_open_file(struct file *file,
	if ((f_mode & (FMODE_WRITE|FMODE_READ)) == (FMODE_WRITE|FMODE_READ) &&
	    (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX))
		f_mode = FMODE_WRITE;
	if ((f_mode & FMODE_WRITE) && !(psetup && psetup->disable)) {
		if ((err = snd_pcm_open_substream(pcm, SNDRV_PCM_STREAM_PLAYBACK,
					       &psubstream)) < 0) {
			snd_pcm_oss_release_file(pcm_oss_file);
			return err;
		}
		pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK] = psubstream;
	}
	if ((f_mode & FMODE_READ) && !(csetup && csetup->disable)) {
		if ((err = snd_pcm_open_substream(pcm, SNDRV_PCM_STREAM_CAPTURE, 
					       &csubstream)) < 0) {
			if (!(f_mode & FMODE_WRITE) || err != -ENODEV) {
				snd_pcm_oss_release_file(pcm_oss_file);
				return err;
			} else {
				csubstream = NULL;
			}
		}
		pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE] = csubstream;
	}

	if (psubstream == NULL && csubstream == NULL) {
		snd_pcm_oss_release_file(pcm_oss_file);
		return -EINVAL;
	}
	if (psubstream != NULL) {
		psubstream->oss.file = pcm_oss_file;
		err = snd_pcm_hw_constraints_init(psubstream);
		if (err < 0) {
			snd_printd("snd_pcm_hw_constraint_init failed\n");
			snd_pcm_oss_release_file(pcm_oss_file);
			return err;
		}
		if ((err = psubstream->ops->open(psubstream)) < 0) {
			snd_pcm_oss_release_file(pcm_oss_file);
			return err;
		}
		psubstream->ffile = file;
		err = snd_pcm_hw_constraints_complete(psubstream);
		if (err < 0) {
			snd_printd("snd_pcm_hw_constraint_complete failed\n");
			snd_pcm_oss_release_file(pcm_oss_file);
			return err;
		}
		snd_pcm_oss_init_substream(psubstream, psetup, minor);
	for (idx = 0; idx < 2; idx++) {
		if (! setup[idx] || setup[idx]->disable)
			continue;
		if (idx == SNDRV_PCM_STREAM_PLAYBACK) {
			if (! (f_mode & FMODE_WRITE))
				continue;
		} else {
			if (! (f_mode & FMODE_READ))
				continue;
		}
	if (csubstream != NULL) {
		csubstream->oss.file = pcm_oss_file;
		err = snd_pcm_hw_constraints_init(csubstream);
		err = snd_pcm_open_substream(pcm, idx, file, &substream);
		if (err < 0) {
			snd_printd("snd_pcm_hw_constraint_init failed\n");
			snd_pcm_oss_release_file(pcm_oss_file);
			return err;
		}
		if ((err = csubstream->ops->open(csubstream)) < 0) {
			snd_pcm_oss_release_file(pcm_oss_file);
			return err;

		pcm_oss_file->streams[idx] = substream;
		snd_pcm_oss_init_substream(substream, setup[idx], minor);
	}
		csubstream->ffile = file;
		err = snd_pcm_hw_constraints_complete(csubstream);
		if (err < 0) {
			snd_printd("snd_pcm_hw_constraint_complete failed\n");
	
	if (! pcm_oss_file->streams[0] && pcm_oss_file->streams[1]) {
		snd_pcm_oss_release_file(pcm_oss_file);
			return err;
		}
		snd_pcm_oss_init_substream(csubstream, csetup, minor);
		return -EINVAL;
	}

	file->private_data = pcm_oss_file;
@@ -1852,7 +1799,7 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
	char task_name[32];
	struct snd_pcm *pcm;
	struct snd_pcm_oss_file *pcm_oss_file;
	struct snd_pcm_oss_setup *psetup = NULL, *csetup = NULL;
	struct snd_pcm_oss_setup *setup[2];
	int nonblock;
	wait_queue_t wait;

@@ -1873,23 +1820,13 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
		err = -EFAULT;
		goto __error;
	}
	memset(setup, 0, sizeof(*setup));
	if (file->f_mode & FMODE_WRITE)
		psetup = snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_PLAYBACK, task_name);
		setup[0] = snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_PLAYBACK, task_name);
	if (file->f_mode & FMODE_READ)
		csetup = snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_CAPTURE, task_name);
		setup[1] = snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_CAPTURE, task_name);

	nonblock = !!(file->f_flags & O_NONBLOCK);
	if (psetup && !psetup->disable) {
		if (psetup->nonblock)
			nonblock = 1;
		else if (psetup->block)
			nonblock = 0;
	} else if (csetup && !csetup->disable) {
		if (csetup->nonblock)
			nonblock = 1;
		else if (csetup->block)
			nonblock = 0;
	}
	if (!nonblock)
		nonblock = nonblock_open;

@@ -1898,7 +1835,7 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
	mutex_lock(&pcm->open_mutex);
	while (1) {
		err = snd_pcm_oss_open_file(file, pcm, &pcm_oss_file,
					    iminor(inode), psetup, csetup);
					    iminor(inode), setup);
		if (err >= 0)
			break;
		if (err == -EAGAIN) {
+6 −6
Original line number Diff line number Diff line
@@ -777,7 +777,8 @@ static void snd_pcm_tick_timer_func(unsigned long data)
	snd_pcm_tick_elapsed(substream);
}

int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
			     struct file *file,
			     struct snd_pcm_substream **rsubstream)
{
	struct snd_pcm_str * pstr;
@@ -793,7 +794,7 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
	*rsubstream = NULL;
	snd_assert(pcm != NULL, return -ENXIO);
	pstr = &pcm->streams[stream];
	if (pstr->substream == NULL)
	if (pstr->substream == NULL || pstr->substream_count == 0)
		return -ENODEV;

	card = pcm->card;
@@ -807,8 +808,6 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
	}
	up_read(&card->controls_rwsem);

	if (pstr->substream_count == 0)
		return -ENODEV;
	switch (stream) {
	case SNDRV_PCM_STREAM_PLAYBACK:
		if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) {
@@ -874,12 +873,13 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,

	substream->runtime = runtime;
	substream->private_data = pcm->private_data;
	substream->ffile = file;
	pstr->substream_opened++;
	*rsubstream = substream;
	return 0;
}

void snd_pcm_release_substream(struct snd_pcm_substream *substream)
void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
{
	struct snd_pcm_runtime *runtime;
	substream->file = NULL;
+0 −49
Original line number Diff line number Diff line
@@ -2299,19 +2299,7 @@ snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const v
	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
		return -EBADFD;

	snd_assert(substream->ffile != NULL, return -ENXIO);
	nonblock = !!(substream->ffile->f_flags & O_NONBLOCK);
#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
	if (substream->oss.oss) {
		struct snd_pcm_oss_setup *setup = substream->oss.setup;
		if (setup != NULL) {
			if (setup->nonblock)
				nonblock = 1;
			else if (setup->block)
				nonblock = 0;
		}
	}
#endif

	if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED &&
	    runtime->channels > 1)
@@ -2374,19 +2362,7 @@ snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream,
	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
		return -EBADFD;

	snd_assert(substream->ffile != NULL, return -ENXIO);
	nonblock = !!(substream->ffile->f_flags & O_NONBLOCK);
#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
	if (substream->oss.oss) {
		struct snd_pcm_oss_setup *setup = substream->oss.setup;
		if (setup != NULL) {
			if (setup->nonblock)
				nonblock = 1;
			else if (setup->block)
				nonblock = 0;
		}
	}
#endif

	if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
		return -EINVAL;
@@ -2596,19 +2572,7 @@ snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __u
	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
		return -EBADFD;

	snd_assert(substream->ffile != NULL, return -ENXIO);
	nonblock = !!(substream->ffile->f_flags & O_NONBLOCK);
#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
	if (substream->oss.oss) {
		struct snd_pcm_oss_setup *setup = substream->oss.setup;
		if (setup != NULL) {
			if (setup->nonblock)
				nonblock = 1;
			else if (setup->block)
				nonblock = 0;
		}
	}
#endif
	if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED)
		return -EINVAL;
	return snd_pcm_lib_read1(substream, (unsigned long)buf, size, nonblock, snd_pcm_lib_read_transfer);
@@ -2665,20 +2629,7 @@ snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream,
	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
		return -EBADFD;

	snd_assert(substream->ffile != NULL, return -ENXIO);
	nonblock = !!(substream->ffile->f_flags & O_NONBLOCK);
#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
	if (substream->oss.oss) {
		struct snd_pcm_oss_setup *setup = substream->oss.setup;
		if (setup != NULL) {
			if (setup->nonblock)
				nonblock = 1;
			else if (setup->block)
				nonblock = 0;
		}
	}
#endif

	if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
		return -EINVAL;
	return snd_pcm_lib_read1(substream, (unsigned long)bufs, frames, nonblock, snd_pcm_lib_readv_transfer);
Loading