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

[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
...@@ -369,6 +369,7 @@ struct snd_pcm_substream { ...@@ -369,6 +369,7 @@ struct snd_pcm_substream {
/* -- assigned files -- */ /* -- assigned files -- */
struct snd_pcm_file *file; struct snd_pcm_file *file;
struct file *ffile; struct file *ffile;
void (*pcm_release)(struct snd_pcm_substream *);
#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
/* -- OSS things -- */ /* -- OSS things -- */
struct snd_pcm_oss_substream oss; struct snd_pcm_oss_substream oss;
...@@ -381,13 +382,10 @@ struct snd_pcm_substream { ...@@ -381,13 +382,10 @@ struct snd_pcm_substream {
struct snd_info_entry *proc_prealloc_entry; struct snd_info_entry *proc_prealloc_entry;
/* misc flags */ /* misc flags */
unsigned int no_mmap_ctrl: 1; 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) #define SUBSTREAM_BUSY(substream) ((substream)->file != NULL)
#endif
struct snd_pcm_str { struct snd_pcm_str {
...@@ -468,8 +466,12 @@ int snd_pcm_suspend(struct snd_pcm_substream *substream); ...@@ -468,8 +466,12 @@ int snd_pcm_suspend(struct snd_pcm_substream *substream);
int snd_pcm_suspend_all(struct snd_pcm *pcm); int snd_pcm_suspend_all(struct snd_pcm *pcm);
#endif #endif
int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg); 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); 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); 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); int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, struct vm_area_struct *area);
......
...@@ -70,7 +70,6 @@ struct snd_pcm_oss_file { ...@@ -70,7 +70,6 @@ struct snd_pcm_oss_file {
struct snd_pcm_oss_substream { struct snd_pcm_oss_substream {
unsigned oss: 1; /* oss mode */ unsigned oss: 1; /* oss mode */
struct snd_pcm_oss_setup *setup; /* active setup */ struct snd_pcm_oss_setup *setup; /* active setup */
struct snd_pcm_oss_file *file;
}; };
struct snd_pcm_oss_stream { struct snd_pcm_oss_stream {
......
...@@ -1671,6 +1671,18 @@ static struct snd_pcm_oss_setup *snd_pcm_oss_look_for_setup(struct snd_pcm *pcm, ...@@ -1671,6 +1671,18 @@ static struct snd_pcm_oss_setup *snd_pcm_oss_look_for_setup(struct snd_pcm *pcm,
return NULL; 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, static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream,
struct snd_pcm_oss_setup *setup, struct snd_pcm_oss_setup *setup,
int minor) int minor)
...@@ -1679,6 +1691,10 @@ static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream, ...@@ -1679,6 +1691,10 @@ static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream,
substream->oss.oss = 1; substream->oss.oss = 1;
substream->oss.setup = setup; substream->oss.setup = setup;
if (setup->nonblock)
substream->ffile->f_flags |= O_NONBLOCK;
else
substream->ffile->f_flags &= ~O_NONBLOCK;
runtime = substream->runtime; runtime = substream->runtime;
runtime->oss.params = 1; runtime->oss.params = 1;
runtime->oss.trigger = 1; runtime->oss.trigger = 1;
...@@ -1697,18 +1713,7 @@ static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream, ...@@ -1697,18 +1713,7 @@ static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream,
runtime->oss.fragshift = 0; runtime->oss.fragshift = 0;
runtime->oss.maxfrags = 0; runtime->oss.maxfrags = 0;
runtime->oss.subdivision = 0; runtime->oss.subdivision = 0;
} substream->pcm_release = snd_pcm_oss_release_substream;
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;
} }
static int snd_pcm_oss_release_file(struct snd_pcm_oss_file *pcm_oss_file) 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) ...@@ -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); snd_assert(pcm_oss_file != NULL, return -ENXIO);
for (cidx = 0; cidx < 2; ++cidx) { for (cidx = 0; cidx < 2; ++cidx) {
struct snd_pcm_substream *substream = pcm_oss_file->streams[cidx]; struct snd_pcm_substream *substream = pcm_oss_file->streams[cidx];
struct snd_pcm_runtime *runtime; if (substream)
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);
snd_pcm_release_substream(substream); snd_pcm_release_substream(substream);
} }
kfree(pcm_oss_file); kfree(pcm_oss_file);
...@@ -1743,12 +1733,11 @@ static int snd_pcm_oss_open_file(struct file *file, ...@@ -1743,12 +1733,11 @@ static int snd_pcm_oss_open_file(struct file *file,
struct snd_pcm *pcm, struct snd_pcm *pcm,
struct snd_pcm_oss_file **rpcm_oss_file, struct snd_pcm_oss_file **rpcm_oss_file,
int minor, int minor,
struct snd_pcm_oss_setup *psetup, struct snd_pcm_oss_setup **setup)
struct snd_pcm_oss_setup *csetup)
{ {
int err = 0; int idx, err;
struct snd_pcm_oss_file *pcm_oss_file; 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; unsigned int f_mode = file->f_mode;
snd_assert(rpcm_oss_file != NULL, return -EINVAL); snd_assert(rpcm_oss_file != NULL, return -EINVAL);
...@@ -1761,72 +1750,30 @@ static int snd_pcm_oss_open_file(struct file *file, ...@@ -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) && if ((f_mode & (FMODE_WRITE|FMODE_READ)) == (FMODE_WRITE|FMODE_READ) &&
(pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX)) (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX))
f_mode = FMODE_WRITE; 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) { for (idx = 0; idx < 2; idx++) {
snd_pcm_oss_release_file(pcm_oss_file); if (! setup[idx] || setup[idx]->disable)
return -EINVAL; continue;
} if (idx == SNDRV_PCM_STREAM_PLAYBACK) {
if (psubstream != NULL) { if (! (f_mode & FMODE_WRITE))
psubstream->oss.file = pcm_oss_file; continue;
err = snd_pcm_hw_constraints_init(psubstream); } else {
if (err < 0) { if (! (f_mode & FMODE_READ))
snd_printd("snd_pcm_hw_constraint_init failed\n"); continue;
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);
} }
if (csubstream != NULL) { err = snd_pcm_open_substream(pcm, idx, file, &substream);
csubstream->oss.file = pcm_oss_file;
err = snd_pcm_hw_constraints_init(csubstream);
if (err < 0) { if (err < 0) {
snd_printd("snd_pcm_hw_constraint_init failed\n");
snd_pcm_oss_release_file(pcm_oss_file); snd_pcm_oss_release_file(pcm_oss_file);
return err; return err;
} }
if ((err = csubstream->ops->open(csubstream)) < 0) {
snd_pcm_oss_release_file(pcm_oss_file); pcm_oss_file->streams[idx] = substream;
return err; snd_pcm_oss_init_substream(substream, setup[idx], minor);
} }
csubstream->ffile = file;
err = snd_pcm_hw_constraints_complete(csubstream); if (! pcm_oss_file->streams[0] && pcm_oss_file->streams[1]) {
if (err < 0) {
snd_printd("snd_pcm_hw_constraint_complete failed\n");
snd_pcm_oss_release_file(pcm_oss_file); snd_pcm_oss_release_file(pcm_oss_file);
return err; return -EINVAL;
}
snd_pcm_oss_init_substream(csubstream, csetup, minor);
} }
file->private_data = pcm_oss_file; file->private_data = pcm_oss_file;
...@@ -1852,7 +1799,7 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file) ...@@ -1852,7 +1799,7 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
char task_name[32]; char task_name[32];
struct snd_pcm *pcm; struct snd_pcm *pcm;
struct snd_pcm_oss_file *pcm_oss_file; 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; int nonblock;
wait_queue_t wait; wait_queue_t wait;
...@@ -1873,23 +1820,13 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file) ...@@ -1873,23 +1820,13 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
err = -EFAULT; err = -EFAULT;
goto __error; goto __error;
} }
memset(setup, 0, sizeof(*setup));
if (file->f_mode & FMODE_WRITE) 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) 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); 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) if (!nonblock)
nonblock = nonblock_open; nonblock = nonblock_open;
...@@ -1898,7 +1835,7 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file) ...@@ -1898,7 +1835,7 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
mutex_lock(&pcm->open_mutex); mutex_lock(&pcm->open_mutex);
while (1) { while (1) {
err = snd_pcm_oss_open_file(file, pcm, &pcm_oss_file, err = snd_pcm_oss_open_file(file, pcm, &pcm_oss_file,
iminor(inode), psetup, csetup); iminor(inode), setup);
if (err >= 0) if (err >= 0)
break; break;
if (err == -EAGAIN) { if (err == -EAGAIN) {
......
...@@ -777,7 +777,8 @@ static void snd_pcm_tick_timer_func(unsigned long data) ...@@ -777,7 +777,8 @@ static void snd_pcm_tick_timer_func(unsigned long data)
snd_pcm_tick_elapsed(substream); 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_substream **rsubstream)
{ {
struct snd_pcm_str * pstr; struct snd_pcm_str * pstr;
...@@ -793,7 +794,7 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, ...@@ -793,7 +794,7 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
*rsubstream = NULL; *rsubstream = NULL;
snd_assert(pcm != NULL, return -ENXIO); snd_assert(pcm != NULL, return -ENXIO);
pstr = &pcm->streams[stream]; pstr = &pcm->streams[stream];
if (pstr->substream == NULL) if (pstr->substream == NULL || pstr->substream_count == 0)
return -ENODEV; return -ENODEV;
card = pcm->card; card = pcm->card;
...@@ -807,8 +808,6 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, ...@@ -807,8 +808,6 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
} }
up_read(&card->controls_rwsem); up_read(&card->controls_rwsem);
if (pstr->substream_count == 0)
return -ENODEV;
switch (stream) { switch (stream) {
case SNDRV_PCM_STREAM_PLAYBACK: case SNDRV_PCM_STREAM_PLAYBACK:
if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) { if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) {
...@@ -874,12 +873,13 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, ...@@ -874,12 +873,13 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
substream->runtime = runtime; substream->runtime = runtime;
substream->private_data = pcm->private_data; substream->private_data = pcm->private_data;
substream->ffile = file;
pstr->substream_opened++; pstr->substream_opened++;
*rsubstream = substream; *rsubstream = substream;
return 0; 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; struct snd_pcm_runtime *runtime;
substream->file = NULL; substream->file = NULL;
......
...@@ -2299,19 +2299,7 @@ snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const v ...@@ -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) if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD; return -EBADFD;
snd_assert(substream->ffile != NULL, return -ENXIO);
nonblock = !!(substream->ffile->f_flags & O_NONBLOCK); 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 && if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED &&
runtime->channels > 1) runtime->channels > 1)
...@@ -2374,19 +2362,7 @@ snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream, ...@@ -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) if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD; return -EBADFD;
snd_assert(substream->ffile != NULL, return -ENXIO);
nonblock = !!(substream->ffile->f_flags & O_NONBLOCK); 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) if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
return -EINVAL; return -EINVAL;
...@@ -2596,19 +2572,7 @@ snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __u ...@@ -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) if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD; return -EBADFD;
snd_assert(substream->ffile != NULL, return -ENXIO);
nonblock = !!(substream->ffile->f_flags & O_NONBLOCK); 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) if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED)
return -EINVAL; return -EINVAL;
return snd_pcm_lib_read1(substream, (unsigned long)buf, size, nonblock, snd_pcm_lib_read_transfer); 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, ...@@ -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) if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD; return -EBADFD;
snd_assert(substream->ffile != NULL, return -ENXIO);
nonblock = !!(substream->ffile->f_flags & O_NONBLOCK); 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) if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
return -EINVAL; return -EINVAL;
return snd_pcm_lib_read1(substream, (unsigned long)bufs, frames, nonblock, snd_pcm_lib_readv_transfer); return snd_pcm_lib_read1(substream, (unsigned long)bufs, frames, nonblock, snd_pcm_lib_readv_transfer);
......
...@@ -1995,28 +1995,63 @@ static void snd_pcm_remove_file(struct snd_pcm_str *str, ...@@ -1995,28 +1995,63 @@ static void snd_pcm_remove_file(struct snd_pcm_str *str,
} }
} }
static int snd_pcm_release_file(struct snd_pcm_file * pcm_file) static void pcm_release_private(struct snd_pcm_substream *substream)
{ {
struct snd_pcm_substream *substream; struct snd_pcm_file *pcm_file = substream->file;
struct snd_pcm_runtime *runtime;
struct snd_pcm_str * str;
snd_assert(pcm_file != NULL, return -ENXIO);
substream = pcm_file->substream;
snd_assert(substream != NULL, return -ENXIO);
runtime = substream->runtime;
str = substream->pstr;
snd_pcm_unlink(substream); snd_pcm_unlink(substream);
if (substream->ffile != NULL) { snd_pcm_remove_file(substream->pstr, pcm_file);
kfree(pcm_file);
}
void snd_pcm_release_substream(struct snd_pcm_substream *substream)
{
snd_pcm_drop(substream);
if (substream->pcm_release)
substream->pcm_release(substream);
if (substream->hw_opened) {
if (substream->ops->hw_free != NULL) if (substream->ops->hw_free != NULL)
substream->ops->hw_free(substream); substream->ops->hw_free(substream);
substream->ops->close(substream); substream->ops->close(substream);
substream->ffile = NULL; substream->hw_opened = 0;
} }
snd_pcm_remove_file(str, pcm_file); snd_pcm_detach_substream(substream);
snd_pcm_release_substream(substream); }
kfree(pcm_file);
int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
struct file *file,
struct snd_pcm_substream **rsubstream)
{
struct snd_pcm_substream *substream;
int err;
err = snd_pcm_attach_substream(pcm, stream, file, &substream);
if (err < 0)
return err;
substream->no_mmap_ctrl = 0;
err = snd_pcm_hw_constraints_init(substream);
if (err < 0) {
snd_printd("snd_pcm_hw_constraints_init failed\n");
goto error;
}
if ((err = substream->ops->open(substream)) < 0)
goto error;
substream->hw_opened = 1;
err = snd_pcm_hw_constraints_complete(substream);
if (err < 0) {
snd_printd("snd_pcm_hw_constraints_complete failed\n");
goto error;
}
*rsubstream = substream;
return 0; return 0;
error:
snd_pcm_release_substream(substream);
return err;
} }
static int snd_pcm_open_file(struct file *file, static int snd_pcm_open_file(struct file *file,
...@@ -2024,52 +2059,29 @@ static int snd_pcm_open_file(struct file *file, ...@@ -2024,52 +2059,29 @@ static int snd_pcm_open_file(struct file *file,
int stream, int stream,
struct snd_pcm_file **rpcm_file) struct snd_pcm_file **rpcm_file)
{ {
int err = 0;
struct snd_pcm_file *pcm_file; struct snd_pcm_file *pcm_file;
struct snd_pcm_substream *substream; struct snd_pcm_substream *substream;
struct snd_pcm_str *str; struct snd_pcm_str *str;
int err;
snd_assert(rpcm_file != NULL, return -EINVAL); snd_assert(rpcm_file != NULL, return -EINVAL);
*rpcm_file = NULL; *rpcm_file = NULL;
err = snd_pcm_open_substream(pcm, stream, file, &substream);
if (err < 0)
return err;
pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL); pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL);
if (pcm_file == NULL) { if (pcm_file == NULL) {
snd_pcm_release_substream(substream);
return -ENOMEM; return -ENOMEM;
} }
if ((err = snd_pcm_open_substream(pcm, stream, &substream)) < 0) {
kfree(pcm_file);
return err;
}
str = substream->pstr; str = substream->pstr;
substream->file = pcm_file; substream->file = pcm_file;
substream->no_mmap_ctrl = 0; substream->pcm_release = pcm_release_private;
pcm_file->substream = substream; pcm_file->substream = substream;
snd_pcm_add_file(str, pcm_file); snd_pcm_add_file(str, pcm_file);
err = snd_pcm_hw_constraints_init(substream);
if (err < 0) {
snd_printd("snd_pcm_hw_constraints_init failed\n");
snd_pcm_release_file(pcm_file);
return err;
}
if ((err = substream->ops->open(substream)) < 0) {
snd_pcm_release_file(pcm_file);
return err;
}
substream->ffile = file;
err = snd_pcm_hw_constraints_complete(substream);
if (err < 0) {
snd_printd("snd_pcm_hw_constraints_complete failed\n");
snd_pcm_release_file(pcm_file);
return err;
}
file->private_data = pcm_file; file->private_data = pcm_file;
*rpcm_file = pcm_file; *rpcm_file = pcm_file;
return 0; return 0;
...@@ -2158,10 +2170,9 @@ static int snd_pcm_release(struct inode *inode, struct file *file) ...@@ -2158,10 +2170,9 @@ static int snd_pcm_release(struct inode *inode, struct file *file)
snd_assert(substream != NULL, return -ENXIO); snd_assert(substream != NULL, return -ENXIO);
snd_assert(!atomic_read(&substream->runtime->mmap_count), ); snd_assert(!atomic_read(&substream->runtime->mmap_count), );
pcm = substream->pcm; pcm = substream->pcm;
snd_pcm_drop(substream);
fasync_helper(-1, file, 0, &substream->runtime->fasync); fasync_helper(-1, file, 0, &substream->runtime->fasync);
mutex_lock(&pcm->open_mutex); mutex_lock(&pcm->open_mutex);
snd_pcm_release_file(pcm_file); snd_pcm_release_substream(substream);
mutex_unlock(&pcm->open_mutex); mutex_unlock(&pcm->open_mutex);
wake_up(&pcm->open_wait); wake_up(&pcm->open_wait);
module_put(pcm->card->module); module_put(pcm->card->module);
...@@ -2480,11 +2491,6 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream, ...@@ -2480,11 +2491,6 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,
return 0; return 0;
} }
static int snd_pcm_playback_ioctl1(struct snd_pcm_substream *substream,
unsigned int cmd, void __user *arg);
static int snd_pcm_capture_ioctl1(struct snd_pcm_substream *substream,
unsigned int cmd, void __user *arg);
static int snd_pcm_common_ioctl1(struct snd_pcm_substream *substream, static int snd_pcm_common_ioctl1(struct snd_pcm_substream *substream,
unsigned int cmd, void __user *arg) unsigned int cmd, void __user *arg)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment