[alsa-devel] [RFC PATCH v2 2/7] sound: core: Avoid using timespec for struct snd_pcm_status

Takashi Iwai tiwai at suse.de
Sun Nov 5 11:23:27 CET 2017


On Thu, 02 Nov 2017 12:06:52 +0100,
Baolin Wang wrote:
> 
> The struct snd_pcm_status will use 'timespec' type variables to record
> timestamp, which is not year 2038 safe on 32bits system.
> 
> Userspace will use SNDRV_PCM_IOCTL_STATUS and SNDRV_PCM_IOCTL_STATUS_EXT
> as commands to issue ioctl() to fill the 'snd_pcm_status' structure in
> userspace. The command number is always defined through _IOR/_IOW/IORW,
> so when userspace changes the definition of 'struct timespec' to use
> 64-bit types, the command number also changes.
> 
> Thus in the kernel, we now need to define two versions of each such ioctl
> and corresponding ioctl commands to handle 32bit time_t and 64bit time_t
> in native mode:
> struct snd_pcm_status32 {
> 	......
> 	struct { s32 tv_sec; s32 tv_nsec; } trigger_tstamp;
> 	struct { s32 tv_sec; s32 tv_nsec; } tstamp;
> 	......
> }
> 
> struct snd_pcm_status64 {
> 	......
> 	struct { s64 tv_sec; s64 tv_nsec; } trigger_tstamp;
> 	struct { s64 tv_sec; s64 tv_nsec; } tstamp;
> 	......
> }
> 
> Moreover in compat file, we renamed or introduced new structures to handle
> 32bit/64bit time_t in compatible mode. 'struct compat_snd_pcm_status32' and
> snd_pcm_status_user_compat() are used to handle 32bit time_t in compat mode.
> 'struct compat_snd_pcm_status64' and snd_pcm_status_user_compat64() are used
> to handle 64bit time_t with 64bit alignment. 'struct compat_snd_pcm_status64_x86_32'
> and snd_pcm_status_user_compat64_x86_32() are used to handle 64bit time_t with
> 32bit alignment.

Hmm...  I don't get why you need to redefine these in
include/sound/pcm.h and define even IOCTLs there.  These are the
things for ABI, no?  If yes, we don't need to have it globally in the
public header but define/convert them locally.  And, renaming
snd_pcm_status64 allover the places for internal doesn't look good.


thanks,

Takashi

> 
> Finally we can replace SNDRV_PCM_IOCTL_STATUS and SNDRV_PCM_IOCTL_STATUS_EXT
> with new commands and introduce new functions to fill new 'struct snd_pcm_status64'
> instead of using unsafe 'struct snd_pcm_status'. Then in future, the new
> commands can be matched when userspace changes 'timespec' to 64bit type
> to make a size change of 'struct snd_pcm_status'. When glibc changes time_t
> to 64-bit, any recompiled program will issue ioctl commands that the kernel
> does not understand without this patch.
> 
> Signed-off-by: Baolin Wang <baolin.wang at linaro.org>
> ---
>  include/sound/pcm.h     |   57 +++++++++++-
>  sound/core/pcm.c        |   12 +--
>  sound/core/pcm_compat.c |  236 +++++++++++++++++++++++++++++++++++------------
>  sound/core/pcm_native.c |  100 ++++++++++++++++----
>  4 files changed, 319 insertions(+), 86 deletions(-)
> 
> diff --git a/include/sound/pcm.h b/include/sound/pcm.h
> index cd1ecd6..7524b54 100644
> --- a/include/sound/pcm.h
> +++ b/include/sound/pcm.h
> @@ -58,6 +58,7 @@ struct snd_pcm_hardware {
>  	size_t fifo_size;		/* fifo size in bytes */
>  };
>  
> +struct snd_pcm_status64;
>  struct snd_pcm_substream;
>  
>  struct snd_pcm_audio_tstamp_config; /* definitions further down */
> @@ -565,8 +566,8 @@ struct snd_pcm_notify {
>  int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info);
>  int snd_pcm_info_user(struct snd_pcm_substream *substream,
>  		      struct snd_pcm_info __user *info);
> -int snd_pcm_status(struct snd_pcm_substream *substream,
> -		   struct snd_pcm_status *status);
> +int snd_pcm_status64(struct snd_pcm_substream *substream,
> +		     struct snd_pcm_status64 *status);
>  int snd_pcm_start(struct snd_pcm_substream *substream);
>  int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t status);
>  int snd_pcm_drain_done(struct snd_pcm_substream *substream);
> @@ -1440,4 +1441,56 @@ static inline u64 pcm_format_to_bits(snd_pcm_format_t pcm_format)
>  #define pcm_dbg(pcm, fmt, args...) \
>  	dev_dbg((pcm)->card->dev, fmt, ##args)
>  
> +struct snd_pcm_status64 {
> +	snd_pcm_state_t state;		/* stream state */
> +	s64 trigger_tstamp_sec;		/* time when stream was started/stopped/paused */
> +	s64 trigger_tstamp_nsec;
> +	s64 tstamp_sec;			/* reference timestamp */
> +	s64 tstamp_nsec;
> +	snd_pcm_uframes_t appl_ptr;	/* appl ptr */
> +	snd_pcm_uframes_t hw_ptr;	/* hw ptr */
> +	snd_pcm_sframes_t delay;	/* current delay in frames */
> +	snd_pcm_uframes_t avail;	/* number of frames available */
> +	snd_pcm_uframes_t avail_max;	/* max frames available on hw since last status */
> +	snd_pcm_uframes_t overrange;	/* count of ADC (capture) overrange detections from last status */
> +	snd_pcm_state_t suspended_state; /* suspended stream state */
> +	__u32 audio_tstamp_data;	 /* needed for 64-bit alignment, used for configs/report to/from userspace */
> +	s64 audio_tstamp_sec;		/* sample counter, wall clock, PHC or on-demand sync'ed */
> +	s64 audio_tstamp_nsec;
> +	s64 driver_tstamp_sec;		/* useful in case reference system tstamp is reported with delay */
> +	s64 driver_tstamp_nsec;
> +	__u32 audio_tstamp_accuracy;	/* in ns units, only valid if indicated in audio_tstamp_data */
> +	unsigned char reserved[52-4*sizeof(s64)]; /* must be filled with zero */
> +};
> +
> +#define SNDRV_PCM_IOCTL_STATUS64	_IOR('A', 0x20, struct snd_pcm_status64)
> +#define SNDRV_PCM_IOCTL_STATUS_EXT64	_IOWR('A', 0x24, struct snd_pcm_status64)
> +
> +#if __BITS_PER_LONG == 32
> +struct snd_pcm_status32 {
> +	snd_pcm_state_t state;		/* stream state */
> +	s32 trigger_tstamp_sec;		/* time when stream was started/stopped/paused */
> +	s32 trigger_tstamp_nsec;
> +	s32 tstamp_sec;			/* reference timestamp */
> +	s32 tstamp_nsec;
> +	snd_pcm_uframes_t appl_ptr;	/* appl ptr */
> +	snd_pcm_uframes_t hw_ptr;	/* hw ptr */
> +	snd_pcm_sframes_t delay;	/* current delay in frames */
> +	snd_pcm_uframes_t avail;	/* number of frames available */
> +	snd_pcm_uframes_t avail_max;	/* max frames available on hw since last status */
> +	snd_pcm_uframes_t overrange;	/* count of ADC (capture) overrange detections from last status */
> +	snd_pcm_state_t suspended_state; /* suspended stream state */
> +	__u32 audio_tstamp_data;	 /* needed for 64-bit alignment, used for configs/report to/from userspace */
> +	s32 audio_tstamp_sec;		/* sample counter, wall clock, PHC or on-demand sync'ed */
> +	s32 audio_tstamp_nsec;
> +	s32 driver_tstamp_sec;		/* useful in case reference system tstamp is reported with delay */
> +	s32 driver_tstamp_nsec;
> +	__u32 audio_tstamp_accuracy;	/* in ns units, only valid if indicated in audio_tstamp_data */
> +	unsigned char reserved[52-4*sizeof(s32)]; /* must be filled with zero */
> +};
> +
> +#define SNDRV_PCM_IOCTL_STATUS32	_IOR('A', 0x20, struct snd_pcm_status32)
> +#define SNDRV_PCM_IOCTL_STATUS_EXT32	_IOWR('A', 0x24, struct snd_pcm_status32)
> +#endif
> +
>  #endif /* __SOUND_PCM_H */
> diff --git a/sound/core/pcm.c b/sound/core/pcm.c
> index 7eadb7f..c19e656 100644
> --- a/sound/core/pcm.c
> +++ b/sound/core/pcm.c
> @@ -453,7 +453,7 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
>  {
>  	struct snd_pcm_substream *substream = entry->private_data;
>  	struct snd_pcm_runtime *runtime;
> -	struct snd_pcm_status status;
> +	struct snd_pcm_status64 status;
>  	int err;
>  
>  	mutex_lock(&substream->pcm->open_mutex);
> @@ -463,17 +463,17 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
>  		goto unlock;
>  	}
>  	memset(&status, 0, sizeof(status));
> -	err = snd_pcm_status(substream, &status);
> +	err = snd_pcm_status64(substream, &status);
>  	if (err < 0) {
>  		snd_iprintf(buffer, "error %d\n", err);
>  		goto unlock;
>  	}
>  	snd_iprintf(buffer, "state: %s\n", snd_pcm_state_name(status.state));
>  	snd_iprintf(buffer, "owner_pid   : %d\n", pid_vnr(substream->pid));
> -	snd_iprintf(buffer, "trigger_time: %ld.%09ld\n",
> -		status.trigger_tstamp.tv_sec, status.trigger_tstamp.tv_nsec);
> -	snd_iprintf(buffer, "tstamp      : %ld.%09ld\n",
> -		status.tstamp.tv_sec, status.tstamp.tv_nsec);
> +	snd_iprintf(buffer, "trigger_time: %lld.%09lld\n",
> +		status.trigger_tstamp_sec, status.trigger_tstamp_nsec);
> +	snd_iprintf(buffer, "tstamp      : %lld.%09lld\n",
> +		status.tstamp_sec, status.tstamp_nsec);
>  	snd_iprintf(buffer, "delay       : %ld\n", status.delay);
>  	snd_iprintf(buffer, "avail       : %ld\n", status.avail);
>  	snd_iprintf(buffer, "avail_max   : %ld\n", status.avail_max);
> diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c
> index b719d0b..53b83d4 100644
> --- a/sound/core/pcm_compat.c
> +++ b/sound/core/pcm_compat.c
> @@ -187,10 +187,12 @@ static int snd_pcm_channel_info_user(struct snd_pcm_substream *substream,
>  	snd_pcm_channel_info_user(s, p)
>  #endif /* CONFIG_X86_X32 */
>  
> -struct snd_pcm_status32 {
> +struct compat_snd_pcm_status32 {
>  	s32 state;
> -	struct compat_timespec trigger_tstamp;
> -	struct compat_timespec tstamp;
> +	s32 trigger_tstamp_sec;
> +	s32 trigger_tstamp_nsec;
> +	s32 tstamp_sec;
> +	s32 tstamp_nsec;
>  	u32 appl_ptr;
>  	u32 hw_ptr;
>  	s32 delay;
> @@ -199,21 +201,25 @@ struct snd_pcm_status32 {
>  	u32 overrange;
>  	s32 suspended_state;
>  	u32 audio_tstamp_data;
> -	struct compat_timespec audio_tstamp;
> -	struct compat_timespec driver_tstamp;
> +	s32 audio_tstamp_sec;
> +	s32 audio_tstamp_nsec;
> +	s32 driver_tstamp_sec;
> +	s32 driver_tstamp_nsec;
>  	u32 audio_tstamp_accuracy;
> -	unsigned char reserved[52-2*sizeof(struct compat_timespec)];
> +	unsigned char reserved[52-4*sizeof(s32)];
>  } __attribute__((packed));
>  
>  
>  static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream,
> -				      struct snd_pcm_status32 __user *src,
> +				      struct compat_snd_pcm_status32 __user *src,
>  				      bool ext)
>  {
> -	struct snd_pcm_status status;
> +	struct snd_pcm_status64 status;
> +	struct compat_snd_pcm_status32 compat_status32;
>  	int err;
>  
>  	memset(&status, 0, sizeof(status));
> +	memset(&compat_status32, 0, sizeof(compat_status32));
>  	/*
>  	 * with extension, parameters are read/write,
>  	 * get audio_tstamp_data from user,
> @@ -222,38 +228,47 @@ static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream,
>  	if (ext && get_user(status.audio_tstamp_data,
>  				(u32 __user *)(&src->audio_tstamp_data)))
>  		return -EFAULT;
> -	err = snd_pcm_status(substream, &status);
> +	err = snd_pcm_status64(substream, &status);
>  	if (err < 0)
>  		return err;
>  
>  	if (clear_user(src, sizeof(*src)))
>  		return -EFAULT;
> -	if (put_user(status.state, &src->state) ||
> -	    compat_put_timespec(&status.trigger_tstamp, &src->trigger_tstamp) ||
> -	    compat_put_timespec(&status.tstamp, &src->tstamp) ||
> -	    put_user(status.appl_ptr, &src->appl_ptr) ||
> -	    put_user(status.hw_ptr, &src->hw_ptr) ||
> -	    put_user(status.delay, &src->delay) ||
> -	    put_user(status.avail, &src->avail) ||
> -	    put_user(status.avail_max, &src->avail_max) ||
> -	    put_user(status.overrange, &src->overrange) ||
> -	    put_user(status.suspended_state, &src->suspended_state) ||
> -	    put_user(status.audio_tstamp_data, &src->audio_tstamp_data) ||
> -	    compat_put_timespec(&status.audio_tstamp, &src->audio_tstamp) ||
> -	    compat_put_timespec(&status.driver_tstamp, &src->driver_tstamp) ||
> -	    put_user(status.audio_tstamp_accuracy, &src->audio_tstamp_accuracy))
> +
> +	compat_status32 = (struct compat_snd_pcm_status32) {
> +		.state = status.state,
> +		.trigger_tstamp_sec = status.trigger_tstamp_sec,
> +		.trigger_tstamp_nsec = status.trigger_tstamp_nsec,
> +		.tstamp_sec = status.tstamp_sec,
> +		.tstamp_nsec = status.tstamp_nsec,
> +		.appl_ptr = status.appl_ptr,
> +		.hw_ptr = status.hw_ptr,
> +		.delay = status.delay,
> +		.avail = status.avail,
> +		.avail_max = status.avail_max,
> +		.overrange = status.overrange,
> +		.suspended_state = status.suspended_state,
> +		.audio_tstamp_data = status.audio_tstamp_data,
> +		.audio_tstamp_sec = status.audio_tstamp_sec,
> +		.audio_tstamp_nsec = status.audio_tstamp_nsec,
> +		.driver_tstamp_sec = status.audio_tstamp_sec,
> +		.driver_tstamp_nsec = status.audio_tstamp_nsec,
> +		.audio_tstamp_accuracy = status.audio_tstamp_accuracy,
> +	};
> +
> +	if (copy_to_user(src, &compat_status32, sizeof(compat_status32)))
>  		return -EFAULT;
>  
>  	return err;
>  }
>  
> -#ifdef CONFIG_X86_X32
> -/* X32 ABI has 64bit timespec and 64bit alignment */
> -struct snd_pcm_status_x32 {
> +struct compat_snd_pcm_status64 {
>  	s32 state;
>  	u32 rsvd; /* alignment */
> -	struct timespec trigger_tstamp;
> -	struct timespec tstamp;
> +	s64 trigger_tstamp_sec;
> +	s64 trigger_tstamp_nsec;
> +	s64 tstamp_sec;
> +	s64 tstamp_nsec;
>  	u32 appl_ptr;
>  	u32 hw_ptr;
>  	s32 delay;
> @@ -262,22 +277,26 @@ struct snd_pcm_status_x32 {
>  	u32 overrange;
>  	s32 suspended_state;
>  	u32 audio_tstamp_data;
> -	struct timespec audio_tstamp;
> -	struct timespec driver_tstamp;
> +	s64 audio_tstamp_sec;
> +	s64 audio_tstamp_nsec;
> +	s64 driver_tstamp_sec;
> +	s64 driver_tstamp_nsec;
>  	u32 audio_tstamp_accuracy;
> -	unsigned char reserved[52-2*sizeof(struct timespec)];
> +	unsigned char reserved[52-4*sizeof(s64)];
>  } __packed;
>  
>  #define put_timespec(src, dst) copy_to_user(dst, src, sizeof(*dst))
>  
> -static int snd_pcm_status_user_x32(struct snd_pcm_substream *substream,
> -				   struct snd_pcm_status_x32 __user *src,
> -				   bool ext)
> +static int snd_pcm_status_user_compat64(struct snd_pcm_substream *substream,
> +					struct compat_snd_pcm_status64 __user *src,
> +					bool ext)
>  {
> -	struct snd_pcm_status status;
> +	struct snd_pcm_status64 status;
> +	struct compat_snd_pcm_status64 compat_status64;
>  	int err;
>  
>  	memset(&status, 0, sizeof(status));
> +	memset(&compat_status64, 0, sizeof(compat_status64));
>  	/*
>  	 * with extension, parameters are read/write,
>  	 * get audio_tstamp_data from user,
> @@ -286,31 +305,116 @@ static int snd_pcm_status_user_x32(struct snd_pcm_substream *substream,
>  	if (ext && get_user(status.audio_tstamp_data,
>  				(u32 __user *)(&src->audio_tstamp_data)))
>  		return -EFAULT;
> -	err = snd_pcm_status(substream, &status);
> +	err = snd_pcm_status64(substream, &status);
>  	if (err < 0)
>  		return err;
>  
>  	if (clear_user(src, sizeof(*src)))
>  		return -EFAULT;
> -	if (put_user(status.state, &src->state) ||
> -	    put_timespec(&status.trigger_tstamp, &src->trigger_tstamp) ||
> -	    put_timespec(&status.tstamp, &src->tstamp) ||
> -	    put_user(status.appl_ptr, &src->appl_ptr) ||
> -	    put_user(status.hw_ptr, &src->hw_ptr) ||
> -	    put_user(status.delay, &src->delay) ||
> -	    put_user(status.avail, &src->avail) ||
> -	    put_user(status.avail_max, &src->avail_max) ||
> -	    put_user(status.overrange, &src->overrange) ||
> -	    put_user(status.suspended_state, &src->suspended_state) ||
> -	    put_user(status.audio_tstamp_data, &src->audio_tstamp_data) ||
> -	    put_timespec(&status.audio_tstamp, &src->audio_tstamp) ||
> -	    put_timespec(&status.driver_tstamp, &src->driver_tstamp) ||
> -	    put_user(status.audio_tstamp_accuracy, &src->audio_tstamp_accuracy))
> +
> +	compat_status64 = (struct compat_snd_pcm_status64) {
> +		.state = status.state,
> +		.trigger_tstamp_sec = status.trigger_tstamp_sec,
> +		.trigger_tstamp_nsec = status.trigger_tstamp_nsec,
> +		.tstamp_sec = status.tstamp_sec,
> +		.tstamp_nsec = status.tstamp_nsec,
> +		.appl_ptr = status.appl_ptr,
> +		.hw_ptr = status.hw_ptr,
> +		.delay = status.delay,
> +		.avail = status.avail,
> +		.avail_max = status.avail_max,
> +		.overrange = status.overrange,
> +		.suspended_state = status.suspended_state,
> +		.audio_tstamp_data = status.audio_tstamp_data,
> +		.audio_tstamp_sec = status.audio_tstamp_sec,
> +		.audio_tstamp_nsec = status.audio_tstamp_nsec,
> +		.driver_tstamp_sec = status.audio_tstamp_sec,
> +		.driver_tstamp_nsec = status.audio_tstamp_nsec,
> +		.audio_tstamp_accuracy = status.audio_tstamp_accuracy,
> +	};
> +
> +	if (copy_to_user(src, &compat_status64, sizeof(compat_status64)))
>  		return -EFAULT;
>  
>  	return err;
>  }
> -#endif /* CONFIG_X86_X32 */
> +
> +#ifdef IA32_EMULATION
> +struct compat_snd_pcm_status64_x86_32 {
> +	s32 state;
> +	s64 trigger_tstamp_sec;
> +	s64 trigger_tstamp_nsec;
> +	s64 tstamp_sec;
> +	s64 tstamp_nsec;
> +	u32 appl_ptr;
> +	u32 hw_ptr;
> +	s32 delay;
> +	u32 avail;
> +	u32 avail_max;
> +	u32 overrange;
> +	s32 suspended_state;
> +	u32 audio_tstamp_data;
> +	s64 audio_tstamp_sec;
> +	s64 audio_tstamp_nsec;
> +	s64 driver_tstamp_sec;
> +	s64 driver_tstamp_nsec;
> +	u32 audio_tstamp_accuracy;
> +	unsigned char reserved[52-4*sizeof(s64)];
> +} __packed;
> +
> +static int
> +snd_pcm_status_user_compat64_x86_32(struct snd_pcm_substream *substream,
> +				    struct compat_snd_pcm_status64_x86_32 __user *src,
> +				    bool ext)
> +{
> +	struct snd_pcm_status64 status;
> +	struct compat_snd_pcm_status64_x86_32 status_x86_32;
> +	int err;
> +
> +	memset(&status, 0, sizeof(status));
> +	memset(&status_x86_32, 0, sizeof(status_x86_32));
> +	/*
> +	 * 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 *)(&src->audio_tstamp_data)))
> +		return -EFAULT;
> +	err = snd_pcm_status64(substream, &status);
> +	if (err < 0)
> +		return err;
> +
> +	if (clear_user(src, sizeof(*src)))
> +		return -EFAULT;
> +
> +	status_x86_32 = (struct compat_snd_pcm_status64_x86_32) {
> +		.state = status.state,
> +		.trigger_tstamp_sec = status.trigger_tstamp_sec,
> +		.trigger_tstamp_nsec = status.trigger_tstamp_nsec,
> +		.tstamp_sec = status.tstamp_sec,
> +		.tstamp_nsec = status.tstamp_nsec,
> +		.appl_ptr = status.appl_ptr,
> +		.hw_ptr = status.hw_ptr,
> +		.delay = status.delay,
> +		.avail = status.avail,
> +		.avail_max = status.avail_max,
> +		.overrange = status.overrange,
> +		.suspended_state = status.suspended_state,
> +		.audio_tstamp_data = status.audio_tstamp_data,
> +		.audio_tstamp_sec = status.audio_tstamp_sec,
> +		.audio_tstamp_nsec = status.audio_tstamp_nsec,
> +		.driver_tstamp_sec = status.audio_tstamp_sec,
> +		.driver_tstamp_nsec = status.audio_tstamp_nsec,
> +		.audio_tstamp_accuracy = status.audio_tstamp_accuracy,
> +	};
> +
> +	if (copy_to_user(src, &status_x86_32, sizeof(status_x86_32)))
> +		return -EFAULT;
> +
> +	return err;
> +}
> +#endif
>  
>  /* both for HW_PARAMS and HW_REFINE */
>  static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream,
> @@ -633,8 +737,8 @@ enum {
>  	SNDRV_PCM_IOCTL_HW_REFINE32 = _IOWR('A', 0x10, struct snd_pcm_hw_params32),
>  	SNDRV_PCM_IOCTL_HW_PARAMS32 = _IOWR('A', 0x11, struct snd_pcm_hw_params32),
>  	SNDRV_PCM_IOCTL_SW_PARAMS32 = _IOWR('A', 0x13, struct snd_pcm_sw_params32),
> -	SNDRV_PCM_IOCTL_STATUS32 = _IOR('A', 0x20, struct snd_pcm_status32),
> -	SNDRV_PCM_IOCTL_STATUS_EXT32 = _IOWR('A', 0x24, struct snd_pcm_status32),
> +	SNDRV_PCM_IOCTL_STATUS_COMPAT32 = _IOR('A', 0x20, struct compat_snd_pcm_status32),
> +	SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT32 = _IOWR('A', 0x24, struct compat_snd_pcm_status32),
>  	SNDRV_PCM_IOCTL_DELAY32 = _IOR('A', 0x21, s32),
>  	SNDRV_PCM_IOCTL_CHANNEL_INFO32 = _IOR('A', 0x32, struct snd_pcm_channel_info32),
>  	SNDRV_PCM_IOCTL_REWIND32 = _IOW('A', 0x46, u32),
> @@ -644,10 +748,14 @@ enum {
>  	SNDRV_PCM_IOCTL_WRITEN_FRAMES32 = _IOW('A', 0x52, struct snd_xfern32),
>  	SNDRV_PCM_IOCTL_READN_FRAMES32 = _IOR('A', 0x53, struct snd_xfern32),
>  	SNDRV_PCM_IOCTL_SYNC_PTR32 = _IOWR('A', 0x23, struct snd_pcm_sync_ptr32),
> +	SNDRV_PCM_IOCTL_STATUS_COMPAT64 = _IOR('A', 0x20, struct compat_snd_pcm_status64),
> +	SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT64 = _IOWR('A', 0x24, struct compat_snd_pcm_status64),
> +#ifdef IA32_EMULATION
> +	SNDRV_PCM_IOCTL_STATUS_COMPAT64_X86_32 = _IOR('A', 0x20, struct compat_snd_pcm_status64_x86_32),
> +	SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT64_X86_32 = _IOWR('A', 0x24, struct compat_snd_pcm_status64_x86_32),
> +#endif
>  #ifdef CONFIG_X86_X32
>  	SNDRV_PCM_IOCTL_CHANNEL_INFO_X32 = _IOR('A', 0x32, struct snd_pcm_channel_info),
> -	SNDRV_PCM_IOCTL_STATUS_X32 = _IOR('A', 0x20, struct snd_pcm_status_x32),
> -	SNDRV_PCM_IOCTL_STATUS_EXT_X32 = _IOWR('A', 0x24, struct snd_pcm_status_x32),
>  	SNDRV_PCM_IOCTL_SYNC_PTR_X32 = _IOWR('A', 0x23, struct snd_pcm_sync_ptr_x32),
>  #endif /* CONFIG_X86_X32 */
>  };
> @@ -697,9 +805,9 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
>  		return snd_pcm_ioctl_hw_params_compat(substream, 0, argp);
>  	case SNDRV_PCM_IOCTL_SW_PARAMS32:
>  		return snd_pcm_ioctl_sw_params_compat(substream, argp);
> -	case SNDRV_PCM_IOCTL_STATUS32:
> +	case SNDRV_PCM_IOCTL_STATUS_COMPAT32:
>  		return snd_pcm_status_user_compat(substream, argp, false);
> -	case SNDRV_PCM_IOCTL_STATUS_EXT32:
> +	case SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT32:
>  		return snd_pcm_status_user_compat(substream, argp, true);
>  	case SNDRV_PCM_IOCTL_SYNC_PTR32:
>  		return snd_pcm_ioctl_sync_ptr_compat(substream, argp);
> @@ -719,11 +827,17 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
>  		return snd_pcm_ioctl_rewind_compat(substream, argp);
>  	case SNDRV_PCM_IOCTL_FORWARD32:
>  		return snd_pcm_ioctl_forward_compat(substream, argp);
> +	case SNDRV_PCM_IOCTL_STATUS_COMPAT64:
> +		return snd_pcm_status_user_compat64(substream, argp, false);
> +	case SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT64:
> +		return snd_pcm_status_user_compat64(substream, argp, true);
> +#ifdef IA32_EMULATION
> +	case SNDRV_PCM_IOCTL_STATUS_COMPAT64_X86_32:
> +		return snd_pcm_status_user_compat64_x86_32(substream, argp, false);
> +	case SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT64_X86_32:
> +		return snd_pcm_status_user_compat64_x86_32(substream, argp, true);
> +#endif
>  #ifdef CONFIG_X86_X32
> -	case SNDRV_PCM_IOCTL_STATUS_X32:
> -		return snd_pcm_status_user_x32(substream, argp, false);
> -	case SNDRV_PCM_IOCTL_STATUS_EXT_X32:
> -		return snd_pcm_status_user_x32(substream, argp, true);
>  	case SNDRV_PCM_IOCTL_SYNC_PTR_X32:
>  		return snd_pcm_ioctl_sync_ptr_x32(substream, argp);
>  	case SNDRV_PCM_IOCTL_CHANNEL_INFO_X32:
> diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
> index 60bc303..7a70848 100644
> --- a/sound/core/pcm_native.c
> +++ b/sound/core/pcm_native.c
> @@ -854,8 +854,8 @@ static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream,
>  	return err;
>  }
>  
> -int snd_pcm_status(struct snd_pcm_substream *substream,
> -		   struct snd_pcm_status *status)
> +int snd_pcm_status64(struct snd_pcm_substream *substream,
> +		     struct snd_pcm_status64 *status)
>  {
>  	struct snd_pcm_runtime *runtime = substream->runtime;
>  
> @@ -881,14 +881,22 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
>  	status->suspended_state = runtime->status->suspended_state;
>  	if (status->state == SNDRV_PCM_STATE_OPEN)
>  		goto _end;
> -	status->trigger_tstamp = timespec64_to_timespec(runtime->trigger_tstamp);
> +	status->trigger_tstamp_sec = runtime->trigger_tstamp.tv_sec;
> +	status->trigger_tstamp_nsec = runtime->trigger_tstamp.tv_nsec;
>  	if (snd_pcm_running(substream)) {
>  		snd_pcm_update_hw_ptr(substream);
>  		if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
> -			status->tstamp = runtime->status->tstamp;
> -			status->driver_tstamp = timespec64_to_timespec(runtime->driver_tstamp);
> -			status->audio_tstamp =
> -				runtime->status->audio_tstamp;
> +			status->tstamp_sec = runtime->status->tstamp.tv_sec;
> +			status->tstamp_nsec =
> +				runtime->status->tstamp.tv_nsec;
> +			status->driver_tstamp_sec =
> +				runtime->driver_tstamp.tv_sec;
> +			status->driver_tstamp_nsec =
> +				runtime->driver_tstamp.tv_nsec;
> +			status->audio_tstamp_sec =
> +				runtime->status->audio_tstamp.tv_sec;
> +			status->audio_tstamp_nsec =
> +				runtime->status->audio_tstamp.tv_nsec;
>  			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,
> @@ -903,7 +911,8 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
>  			struct timespec64 tstamp;
>  
>  			snd_pcm_gettime(runtime, &tstamp);
> -			status->tstamp = timespec64_to_timespec(tstamp);
> +			status->tstamp_sec = tstamp.tv_sec;
> +			status->tstamp_nsec = tstamp.tv_nsec;
>  		}
>  	}
>   _tstamp_end:
> @@ -933,11 +942,11 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
>  	return 0;
>  }
>  
> -static int snd_pcm_status_user(struct snd_pcm_substream *substream,
> -			       struct snd_pcm_status __user * _status,
> -			       bool ext)
> +static int snd_pcm_status_user64(struct snd_pcm_substream *substream,
> +				 struct snd_pcm_status64 __user * _status,
> +				 bool ext)
>  {
> -	struct snd_pcm_status status;
> +	struct snd_pcm_status64 status;
>  	int res;
>  
>  	memset(&status, 0, sizeof(status));
> @@ -949,7 +958,7 @@ static int snd_pcm_status_user(struct snd_pcm_substream *substream,
>  	if (ext && get_user(status.audio_tstamp_data,
>  				(u32 __user *)(&_status->audio_tstamp_data)))
>  		return -EFAULT;
> -	res = snd_pcm_status(substream, &status);
> +	res = snd_pcm_status64(substream, &status);
>  	if (res < 0)
>  		return res;
>  	if (copy_to_user(_status, &status, sizeof(status)))
> @@ -957,6 +966,57 @@ static int snd_pcm_status_user(struct snd_pcm_substream *substream,
>  	return 0;
>  }
>  
> +#if __BITS_PER_LONG == 32
> +static int snd_pcm_status_user32(struct snd_pcm_substream *substream,
> +				 struct snd_pcm_status32 __user * _status,
> +				 bool ext)
> +{
> +	struct snd_pcm_status64 status64;
> +	struct snd_pcm_status32 status32;
> +	int res;
> +
> +	memset(&status64, 0, sizeof(status64));
> +	memset(&status32, 0, sizeof(status32));
> +	/*
> +	 * with extension, parameters are read/write,
> +	 * get audio_tstamp_data from user,
> +	 * ignore rest of status structure
> +	 */
> +	if (ext && get_user(status64.audio_tstamp_data,
> +			    (u32 __user *)(&_status->audio_tstamp_data)))
> +		return -EFAULT;
> +	res = snd_pcm_status64(substream, &status64);
> +	if (res < 0)
> +		return res;
> +
> +	status32 = (struct snd_pcm_status32) {
> +		.state = status64.state,
> +		.trigger_tstamp_sec = status64.trigger_tstamp_sec,
> +		.trigger_tstamp_nsec = status64.trigger_tstamp_nsec,
> +		.tstamp_sec = status64.tstamp_sec,
> +		.tstamp_nsec = status64.tstamp_nsec,
> +		.appl_ptr = status64.appl_ptr,
> +		.hw_ptr = status64.hw_ptr,
> +		.delay = status64.delay,
> +		.avail = status64.avail,
> +		.avail_max = status64.avail_max,
> +		.overrange = status64.overrange,
> +		.suspended_state = status64.suspended_state,
> +		.audio_tstamp_data = status64.audio_tstamp_data,
> +		.audio_tstamp_sec = status64.audio_tstamp_sec,
> +		.audio_tstamp_nsec = status64.audio_tstamp_nsec,
> +		.driver_tstamp_sec = status64.audio_tstamp_sec,
> +		.driver_tstamp_nsec = status64.audio_tstamp_nsec,
> +		.audio_tstamp_accuracy = status64.audio_tstamp_accuracy,
> +	};
> +
> +	if (copy_to_user(_status, &status32, sizeof(status32)))
> +		return -EFAULT;
> +
> +	return 0;
> +}
> +#endif
> +
>  static int snd_pcm_channel_info(struct snd_pcm_substream *substream,
>  				struct snd_pcm_channel_info * info)
>  {
> @@ -2888,10 +2948,16 @@ static int snd_pcm_common_ioctl(struct file *file,
>  		return snd_pcm_hw_free(substream);
>  	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, false);
> -	case SNDRV_PCM_IOCTL_STATUS_EXT:
> -		return snd_pcm_status_user(substream, arg, true);
> +#if __BITS_PER_LONG == 32
> +	case SNDRV_PCM_IOCTL_STATUS32:
> +		return snd_pcm_status_user32(substream, arg, false);
> +	case SNDRV_PCM_IOCTL_STATUS_EXT32:
> +		return snd_pcm_status_user32(substream, arg, true);
> +#endif
> +	case SNDRV_PCM_IOCTL_STATUS64:
> +		return snd_pcm_status_user64(substream, arg, false);
> +	case SNDRV_PCM_IOCTL_STATUS_EXT64:
> +		return snd_pcm_status_user64(substream, arg, true);
>  	case SNDRV_PCM_IOCTL_CHANNEL_INFO:
>  		return snd_pcm_channel_info_user(substream, arg);
>  	case SNDRV_PCM_IOCTL_PREPARE:
> -- 
> 1.7.9.5
> 
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel at alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
> 


More information about the Alsa-devel mailing list