diff options
Diffstat (limited to 'sound/core/pcm_native.c')
| -rw-r--r-- | sound/core/pcm_native.c | 81 | 
1 files changed, 55 insertions, 26 deletions
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 7b5729c4b21..36d6765618a 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1284,13 +1284,16 @@ static int snd_pcm_reset(struct snd_pcm_substream *substream)  /*   * prepare ioctl   */ -static int snd_pcm_pre_prepare(struct snd_pcm_substream *substream, int state) +/* we use the second argument for updating f_flags */ +static int snd_pcm_pre_prepare(struct snd_pcm_substream *substream, +			       int f_flags)  {  	struct snd_pcm_runtime *runtime = substream->runtime;  	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)  		return -EBADFD;  	if (snd_pcm_running(substream))  		return -EBUSY; +	substream->f_flags = f_flags;  	return 0;  } @@ -1319,17 +1322,26 @@ static struct action_ops snd_pcm_action_prepare = {  /**   * snd_pcm_prepare   * @substream: the PCM substream instance + * @file: file to refer f_flags   *   * Prepare the PCM substream to be triggerable.   */ -static int snd_pcm_prepare(struct snd_pcm_substream *substream) +static int snd_pcm_prepare(struct snd_pcm_substream *substream, +			   struct file *file)  {  	int res;  	struct snd_card *card = substream->pcm->card; +	int f_flags; + +	if (file) +		f_flags = file->f_flags; +	else +		f_flags = substream->f_flags;  	snd_power_lock(card);  	if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0) -		res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare, substream, 0); +		res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare, +					       substream, f_flags);  	snd_power_unlock(card);  	return res;  } @@ -1340,7 +1352,7 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream)  static int snd_pcm_pre_drain_init(struct snd_pcm_substream *substream, int state)  { -	if (substream->ffile->f_flags & O_NONBLOCK) +	if (substream->f_flags & O_NONBLOCK)  		return -EAGAIN;  	substream->runtime->trigger_master = substream;  	return 0; @@ -2015,6 +2027,10 @@ static void pcm_release_private(struct snd_pcm_substream *substream)  void snd_pcm_release_substream(struct snd_pcm_substream *substream)  { +	substream->ref_count--; +	if (substream->ref_count > 0) +		return; +  	snd_pcm_drop(substream);  	if (substream->hw_opened) {  		if (substream->ops->hw_free != NULL) @@ -2041,6 +2057,11 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,  	err = snd_pcm_attach_substream(pcm, stream, file, &substream);  	if (err < 0)  		return err; +	if (substream->ref_count > 1) { +		*rsubstream = substream; +		return 0; +	} +  	substream->no_mmap_ctrl = 0;  	err = snd_pcm_hw_constraints_init(substream);  	if (err < 0) { @@ -2086,17 +2107,20 @@ static int snd_pcm_open_file(struct file *file,  	if (err < 0)  		return err; -	pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL); -	if (pcm_file == NULL) { -		snd_pcm_release_substream(substream); -		return -ENOMEM; +	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; +		} +		str = substream->pstr; +		substream->file = pcm_file; +		substream->pcm_release = pcm_release_private; +		pcm_file->substream = substream; +		snd_pcm_add_file(str, pcm_file);  	} -	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;  	return 0; @@ -2506,7 +2530,8 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,  	return 0;  } -static int snd_pcm_common_ioctl1(struct snd_pcm_substream *substream, +static int snd_pcm_common_ioctl1(struct file *file, +				 struct snd_pcm_substream *substream,  				 unsigned int cmd, void __user *arg)  {  	snd_assert(substream != NULL, return -ENXIO); @@ -2531,7 +2556,7 @@ static int snd_pcm_common_ioctl1(struct snd_pcm_substream *substream,  	case SNDRV_PCM_IOCTL_CHANNEL_INFO:  		return snd_pcm_channel_info_user(substream, arg);  	case SNDRV_PCM_IOCTL_PREPARE: -		return snd_pcm_prepare(substream); +		return snd_pcm_prepare(substream, file);  	case SNDRV_PCM_IOCTL_RESET:  		return snd_pcm_reset(substream);  	case SNDRV_PCM_IOCTL_START: @@ -2573,7 +2598,8 @@ static int snd_pcm_common_ioctl1(struct snd_pcm_substream *substream,  	return -ENOTTY;  } -static int snd_pcm_playback_ioctl1(struct snd_pcm_substream *substream, +static int snd_pcm_playback_ioctl1(struct file *file, +				   struct snd_pcm_substream *substream,  				   unsigned int cmd, void __user *arg)  {  	snd_assert(substream != NULL, return -ENXIO); @@ -2649,10 +2675,11 @@ static int snd_pcm_playback_ioctl1(struct snd_pcm_substream *substream,  		return result < 0 ? result : 0;  	}  	} -	return snd_pcm_common_ioctl1(substream, cmd, arg); +	return snd_pcm_common_ioctl1(file, substream, cmd, arg);  } -static int snd_pcm_capture_ioctl1(struct snd_pcm_substream *substream, +static int snd_pcm_capture_ioctl1(struct file *file, +				  struct snd_pcm_substream *substream,  				  unsigned int cmd, void __user *arg)  {  	snd_assert(substream != NULL, return -ENXIO); @@ -2728,7 +2755,7 @@ static int snd_pcm_capture_ioctl1(struct snd_pcm_substream *substream,  		return result < 0 ? result : 0;  	}  	} -	return snd_pcm_common_ioctl1(substream, cmd, arg); +	return snd_pcm_common_ioctl1(file, substream, cmd, arg);  }  static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd, @@ -2741,7 +2768,8 @@ static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd,  	if (((cmd >> 8) & 0xff) != 'A')  		return -ENOTTY; -	return snd_pcm_playback_ioctl1(pcm_file->substream, cmd, (void __user *)arg); +	return snd_pcm_playback_ioctl1(file, pcm_file->substream, cmd, +				       (void __user *)arg);  }  static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd, @@ -2754,7 +2782,8 @@ static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd,  	if (((cmd >> 8) & 0xff) != 'A')  		return -ENOTTY; -	return snd_pcm_capture_ioctl1(pcm_file->substream, cmd, (void __user *)arg); +	return snd_pcm_capture_ioctl1(file, pcm_file->substream, cmd, +				      (void __user *)arg);  }  int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, @@ -2766,12 +2795,12 @@ int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream,  	fs = snd_enter_user();  	switch (substream->stream) {  	case SNDRV_PCM_STREAM_PLAYBACK: -		result = snd_pcm_playback_ioctl1(substream, -						 cmd, (void __user *)arg); +		result = snd_pcm_playback_ioctl1(NULL, substream, cmd, +						 (void __user *)arg);  		break;  	case SNDRV_PCM_STREAM_CAPTURE: -		result = snd_pcm_capture_ioctl1(substream, -						cmd, (void __user *)arg); +		result = snd_pcm_capture_ioctl1(NULL, substream, cmd, +						(void __user *)arg);  		break;  	default:  		result = -EINVAL;  |