diff options
Diffstat (limited to 'sound/core/pcm_native.c')
| -rw-r--r-- | sound/core/pcm_native.c | 64 | 
1 files changed, 41 insertions, 23 deletions
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index ac2150e0670..59e5fbe6af5 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1343,8 +1343,6 @@ 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->f_flags & O_NONBLOCK) -		return -EAGAIN;  	substream->runtime->trigger_master = substream;  	return 0;  } @@ -1392,7 +1390,6 @@ static struct action_ops snd_pcm_action_drain_init = {  struct drain_rec {  	struct snd_pcm_substream *substream;  	wait_queue_t wait; -	snd_pcm_uframes_t stop_threshold;  };  static int snd_pcm_drop(struct snd_pcm_substream *substream); @@ -1404,13 +1401,15 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream);   * After this call, all streams are supposed to be either SETUP or DRAINING   * (capture only) state.   */ -static int snd_pcm_drain(struct snd_pcm_substream *substream) +static int snd_pcm_drain(struct snd_pcm_substream *substream, +			 struct file *file)  {  	struct snd_card *card;  	struct snd_pcm_runtime *runtime;  	struct snd_pcm_substream *s;  	int result = 0;  	int i, num_drecs; +	int nonblock = 0;  	struct drain_rec *drec, drec_tmp, *d;  	card = substream->pcm->card; @@ -1428,6 +1427,15 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream)  		}  	} +	if (file) { +		if (file->f_flags & O_NONBLOCK) +			nonblock = 1; +	} else if (substream->f_flags & O_NONBLOCK) +		nonblock = 1; + +	if (nonblock) +		goto lock; /* no need to allocate waitqueues */ +  	/* allocate temporary record for drain sync */  	down_read(&snd_pcm_link_rwsem);  	if (snd_pcm_stream_linked(substream)) { @@ -1449,16 +1457,11 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream)  			d->substream = s;  			init_waitqueue_entry(&d->wait, current);  			add_wait_queue(&runtime->sleep, &d->wait); -			/* stop_threshold fixup to avoid endless loop when -			 * stop_threshold > buffer_size -			 */ -			d->stop_threshold = runtime->stop_threshold; -			if (runtime->stop_threshold > runtime->buffer_size) -				runtime->stop_threshold = runtime->buffer_size;  		}  	}  	up_read(&snd_pcm_link_rwsem); + lock:  	snd_pcm_stream_lock_irq(substream);  	/* resume pause */  	if (substream->runtime->status->state == SNDRV_PCM_STATE_PAUSED) @@ -1466,9 +1469,12 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream)  	/* pre-start/stop - all running streams are changed to DRAINING state */  	result = snd_pcm_action(&snd_pcm_action_drain_init, substream, 0); -	if (result < 0) { -		snd_pcm_stream_unlock_irq(substream); -		goto _error; +	if (result < 0) +		goto unlock; +	/* in non-blocking, we don't wait in ioctl but let caller poll */ +	if (nonblock) { +		result = -EAGAIN; +		goto unlock;  	}  	for (;;) { @@ -1504,18 +1510,18 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream)  		}  	} + unlock:  	snd_pcm_stream_unlock_irq(substream); - _error: -	for (i = 0; i < num_drecs; i++) { -		d = &drec[i]; -		runtime = d->substream->runtime; -		remove_wait_queue(&runtime->sleep, &d->wait); -		runtime->stop_threshold = d->stop_threshold; +	if (!nonblock) { +		for (i = 0; i < num_drecs; i++) { +			d = &drec[i]; +			runtime = d->substream->runtime; +			remove_wait_queue(&runtime->sleep, &d->wait); +		} +		if (drec != &drec_tmp) +			kfree(drec);  	} - -	if (drec != &drec_tmp) -		kfree(drec);  	snd_power_unlock(card);  	return result; @@ -2208,6 +2214,9 @@ static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *subst  	case SNDRV_PCM_STATE_XRUN:  		ret = -EPIPE;  		goto __end; +	case SNDRV_PCM_STATE_SUSPENDED: +		ret = -ESTRPIPE; +		goto __end;  	default:  		ret = -EBADFD;  		goto __end; @@ -2253,6 +2262,9 @@ static snd_pcm_sframes_t snd_pcm_capture_rewind(struct snd_pcm_substream *substr  	case SNDRV_PCM_STATE_XRUN:  		ret = -EPIPE;  		goto __end; +	case SNDRV_PCM_STATE_SUSPENDED: +		ret = -ESTRPIPE; +		goto __end;  	default:  		ret = -EBADFD;  		goto __end; @@ -2299,6 +2311,9 @@ static snd_pcm_sframes_t snd_pcm_playback_forward(struct snd_pcm_substream *subs  	case SNDRV_PCM_STATE_XRUN:  		ret = -EPIPE;  		goto __end; +	case SNDRV_PCM_STATE_SUSPENDED: +		ret = -ESTRPIPE; +		goto __end;  	default:  		ret = -EBADFD;  		goto __end; @@ -2345,6 +2360,9 @@ static snd_pcm_sframes_t snd_pcm_capture_forward(struct snd_pcm_substream *subst  	case SNDRV_PCM_STATE_XRUN:  		ret = -EPIPE;  		goto __end; +	case SNDRV_PCM_STATE_SUSPENDED: +		ret = -ESTRPIPE; +		goto __end;  	default:  		ret = -EBADFD;  		goto __end; @@ -2544,7 +2562,7 @@ static int snd_pcm_common_ioctl1(struct file *file,  		return snd_pcm_hw_params_old_user(substream, arg);  #endif  	case SNDRV_PCM_IOCTL_DRAIN: -		return snd_pcm_drain(substream); +		return snd_pcm_drain(substream, file);  	case SNDRV_PCM_IOCTL_DROP:  		return snd_pcm_drop(substream);  	case SNDRV_PCM_IOCTL_PAUSE:  |