diff options
Diffstat (limited to 'sound/core/pcm_native.c')
| -rw-r--r-- | sound/core/pcm_native.c | 84 | 
1 files changed, 61 insertions, 23 deletions
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index b03a638b420c..d126c03361ae 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -25,7 +25,6 @@  #include <linux/slab.h>  #include <linux/time.h>  #include <linux/pm_qos.h> -#include <linux/aio.h>  #include <linux/io.h>  #include <linux/dma-mapping.h>  #include <sound/core.h> @@ -35,6 +34,7 @@  #include <sound/pcm_params.h>  #include <sound/timer.h>  #include <sound/minors.h> +#include <linux/uio.h>  /*   *  Compatibility @@ -707,6 +707,23 @@ int snd_pcm_status(struct snd_pcm_substream *substream,  	struct snd_pcm_runtime *runtime = substream->runtime;  	snd_pcm_stream_lock_irq(substream); + +	snd_pcm_unpack_audio_tstamp_config(status->audio_tstamp_data, +					&runtime->audio_tstamp_config); + +	/* backwards compatible behavior */ +	if (runtime->audio_tstamp_config.type_requested == +		SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT) { +		if (runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK) +			runtime->audio_tstamp_config.type_requested = +				SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK; +		else +			runtime->audio_tstamp_config.type_requested = +				SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT; +		runtime->audio_tstamp_report.valid = 0; +	} else +		runtime->audio_tstamp_report.valid = 1; +  	status->state = runtime->status->state;  	status->suspended_state = runtime->status->suspended_state;  	if (status->state == SNDRV_PCM_STATE_OPEN) @@ -716,8 +733,15 @@ int snd_pcm_status(struct snd_pcm_substream *substream,  		snd_pcm_update_hw_ptr(substream);  		if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {  			status->tstamp = runtime->status->tstamp; +			status->driver_tstamp = runtime->driver_tstamp;  			status->audio_tstamp =  				runtime->status->audio_tstamp; +			if (runtime->audio_tstamp_report.valid == 1) +				/* backwards compatibility, no report provided in COMPAT mode */ +				snd_pcm_pack_audio_tstamp_report(&status->audio_tstamp_data, +								&status->audio_tstamp_accuracy, +								&runtime->audio_tstamp_report); +  			goto _tstamp_end;  		}  	} else { @@ -753,12 +777,21 @@ int snd_pcm_status(struct snd_pcm_substream *substream,  }  static int snd_pcm_status_user(struct snd_pcm_substream *substream, -			       struct snd_pcm_status __user * _status) +			       struct snd_pcm_status __user * _status, +			       bool ext)  {  	struct snd_pcm_status status;  	int res; -	 +  	memset(&status, 0, sizeof(status)); +	/* +	 * with extension, parameters are read/write, +	 * get audio_tstamp_data from user, +	 * ignore rest of status structure +	 */ +	if (ext && get_user(status.audio_tstamp_data, +				(u32 __user *)(&_status->audio_tstamp_data))) +		return -EFAULT;  	res = snd_pcm_status(substream, &status);  	if (res < 0)  		return res; @@ -1552,6 +1585,8 @@ static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, int state)  			if (! snd_pcm_playback_empty(substream)) {  				snd_pcm_do_start(substream, SNDRV_PCM_STATE_DRAINING);  				snd_pcm_post_start(substream, SNDRV_PCM_STATE_DRAINING); +			} else { +				runtime->status->state = SNDRV_PCM_STATE_SETUP;  			}  			break;  		case SNDRV_PCM_STATE_RUNNING: @@ -2723,7 +2758,9 @@ static int snd_pcm_common_ioctl1(struct file *file,  	case SNDRV_PCM_IOCTL_SW_PARAMS:  		return snd_pcm_sw_params_user(substream, arg);  	case SNDRV_PCM_IOCTL_STATUS: -		return snd_pcm_status_user(substream, arg); +		return snd_pcm_status_user(substream, arg, false); +	case SNDRV_PCM_IOCTL_STATUS_EXT: +		return snd_pcm_status_user(substream, arg, true);  	case SNDRV_PCM_IOCTL_CHANNEL_INFO:  		return snd_pcm_channel_info_user(substream, arg);  	case SNDRV_PCM_IOCTL_PREPARE: @@ -3031,9 +3068,7 @@ static ssize_t snd_pcm_write(struct file *file, const char __user *buf,  	return result;  } -static ssize_t snd_pcm_aio_read(struct kiocb *iocb, const struct iovec *iov, -			     unsigned long nr_segs, loff_t pos) - +static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to)  {  	struct snd_pcm_file *pcm_file;  	struct snd_pcm_substream *substream; @@ -3050,16 +3085,18 @@ static ssize_t snd_pcm_aio_read(struct kiocb *iocb, const struct iovec *iov,  	runtime = substream->runtime;  	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)  		return -EBADFD; -	if (nr_segs > 1024 || nr_segs != runtime->channels) +	if (!iter_is_iovec(to)) +		return -EINVAL; +	if (to->nr_segs > 1024 || to->nr_segs != runtime->channels)  		return -EINVAL; -	if (!frame_aligned(runtime, iov->iov_len)) +	if (!frame_aligned(runtime, to->iov->iov_len))  		return -EINVAL; -	frames = bytes_to_samples(runtime, iov->iov_len); -	bufs = kmalloc(sizeof(void *) * nr_segs, GFP_KERNEL); +	frames = bytes_to_samples(runtime, to->iov->iov_len); +	bufs = kmalloc(sizeof(void *) * to->nr_segs, GFP_KERNEL);  	if (bufs == NULL)  		return -ENOMEM; -	for (i = 0; i < nr_segs; ++i) -		bufs[i] = iov[i].iov_base; +	for (i = 0; i < to->nr_segs; ++i) +		bufs[i] = to->iov[i].iov_base;  	result = snd_pcm_lib_readv(substream, bufs, frames);  	if (result > 0)  		result = frames_to_bytes(runtime, result); @@ -3067,8 +3104,7 @@ static ssize_t snd_pcm_aio_read(struct kiocb *iocb, const struct iovec *iov,  	return result;  } -static ssize_t snd_pcm_aio_write(struct kiocb *iocb, const struct iovec *iov, -			      unsigned long nr_segs, loff_t pos) +static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from)  {  	struct snd_pcm_file *pcm_file;  	struct snd_pcm_substream *substream; @@ -3085,15 +3121,17 @@ static ssize_t snd_pcm_aio_write(struct kiocb *iocb, const struct iovec *iov,  	runtime = substream->runtime;  	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)  		return -EBADFD; -	if (nr_segs > 128 || nr_segs != runtime->channels || -	    !frame_aligned(runtime, iov->iov_len)) +	if (!iter_is_iovec(from)) +		return -EINVAL; +	if (from->nr_segs > 128 || from->nr_segs != runtime->channels || +	    !frame_aligned(runtime, from->iov->iov_len))  		return -EINVAL; -	frames = bytes_to_samples(runtime, iov->iov_len); -	bufs = kmalloc(sizeof(void *) * nr_segs, GFP_KERNEL); +	frames = bytes_to_samples(runtime, from->iov->iov_len); +	bufs = kmalloc(sizeof(void *) * from->nr_segs, GFP_KERNEL);  	if (bufs == NULL)  		return -ENOMEM; -	for (i = 0; i < nr_segs; ++i) -		bufs[i] = iov[i].iov_base; +	for (i = 0; i < from->nr_segs; ++i) +		bufs[i] = from->iov[i].iov_base;  	result = snd_pcm_lib_writev(substream, bufs, frames);  	if (result > 0)  		result = frames_to_bytes(runtime, result); @@ -3631,7 +3669,7 @@ const struct file_operations snd_pcm_f_ops[2] = {  	{  		.owner =		THIS_MODULE,  		.write =		snd_pcm_write, -		.aio_write =		snd_pcm_aio_write, +		.write_iter =		snd_pcm_writev,  		.open =			snd_pcm_playback_open,  		.release =		snd_pcm_release,  		.llseek =		no_llseek, @@ -3645,7 +3683,7 @@ const struct file_operations snd_pcm_f_ops[2] = {  	{  		.owner =		THIS_MODULE,  		.read =			snd_pcm_read, -		.aio_read =		snd_pcm_aio_read, +		.read_iter =		snd_pcm_readv,  		.open =			snd_pcm_capture_open,  		.release =		snd_pcm_release,  		.llseek =		no_llseek,  |