Commit df1d6ea0 authored by Takashi Iwai's avatar Takashi Iwai

Merge tag 'y2038-alsa-v8-signed' of...

Merge tag 'y2038-alsa-v8-signed' of git://git.kernel.org:/pub/scm/linux/kernel/git/arnd/playground into for-next

ALSA: Fix year 2038 issue for sound subsystem

This is a series I worked on with Baolin in 2017 and 2018, but we
never quite managed to finish up the last pieces. During the
ALSA developer meetup at ELC-E 2018 in Edinburgh, a decision was
made to go with this approach for keeping best compatibility
with existing source code, and then I failed to follow up by
resending the patches.

Now I have patches for all remaining time_t uses in the kernel,
so it's absolutely time to revisit them. I have done more
review of the patches myself and found a couple of minor issues
that I have fixed up, otherwise the series is still the same as
before.

Conceptually, the idea of these patches is:

- 64-bit applications should see no changes at all, neither
  compile-time nor run-time.

- 32-bit code compiled with a 64-bit time_t currently
  does not work with ALSA, and requires kernel changes and/or
  sound/asound.h changes

- Most 32-bit code using these interfaces will work correctly
  on a modified kernel, with or without the uapi header changes.

- 32-bit code using SNDRV_TIMER_IOCTL_TREAD requires the
  updated header file for 64-bit time_t support

- 32-bit i386 user space with 64-bit time_t is broken for
  SNDRV_PCM_IOCTL_STATUS, SNDRV_RAWMIDI_IOCTL_STATUS and
  SNDRV_PCM_IOCTL_SYNC_PTR because of i386 alignment. This is also
  addressed by the updated uapi header.

- PCM mmap is currently supported on native x86 kernels
  (both 32-bit and 64-bit) but not for compat mode. This series breaks
  the 32-bit native mmap support for 32-bit time_t, but instead allows
  it for 64-bit time_t on both native and compat kernels. This seems to
  be the best trade-off, as mmap support is optional already, and most
  32-bit code runs in compat mode anyway.

- I've tried to avoid breaking compilation of 32-bit code
  as much as possible. Anything that does break however is likely code
  that is already broken on 64-bit time_t and needs source changes to
  fix them.

[1] https://git.kernel.org/pub/scm/linux/kernel/git/arnd/playground.git y2038-alsa-v8
[2] https://lore.kernel.org/lkml/CAK8P3a2Os66+iwQYf97qh05W2JP8rmWao8zmKoHiXqVHvyYAJA@mail.gmail.com/T/#m6519cb07cfda08adf1dedea6596bb98892b4d5dcSigned-off-by: default avatarArnd Bergmann <arnd@arndb.de>

Changes since v7: (Arnd):
 - Fix a typo found by Ben Hutchings

Changes since v6: (Arnd):
 - Add a patch to update the API versions
 - Hide a timespec reference in #ifndef __KERNEL__ to remove the
   last reference to time_t
 - Use a more readable way to do padding and describe it in the
   changelog
 - Rebase to linux-5.5-rc1, changing include/sound/soc-component.h
   and sound/drivers/aloop.c as needed.

Changes since v5 (Arnd):
 - Rebased to linux-5.4-rc4
 - Updated to completely remove timespec and time_t references from alsa
 - found and fixed a few bugs

Changes since v4 (Baolin):
 - Add patch 5 to change trigger_tstamp member of struct snd_pcm_runtime.
 - Add patch 8 to change internal timespec.
 - Add more explanation in commit message.
 - Use ktime_get_real_ts64() in patch 6.
 - Split common code out into a separate function in patch 6.
 - Fix tu->tread bug in patch 6 and remove #if __BITS_PER_LONG == 64 macro.

Changes since v3:
 - Move struct snd_pcm_status32 to pcm.h file.
 - Modify comments and commit message.
 - Add new patch2 ~ patch6.

Changes since v2:
 - Renamed all structures to make clear.
 - Remove CONFIG_X86_X32 macro and introduced new compat_snd_pcm_status64_x86_32.

Changes since v1:
 - Add one macro for struct snd_pcm_status_32 which only active in 32bits kernel.
 - Convert pcm_compat.c to use struct snd_pcm_status_64.
 - Convert pcm_native.c to use struct snd_pcm_status_64.
parents d8cac620 1cfaef96
...@@ -44,6 +44,7 @@ struct snd_pcm_hardware { ...@@ -44,6 +44,7 @@ struct snd_pcm_hardware {
size_t fifo_size; /* fifo size in bytes */ size_t fifo_size; /* fifo size in bytes */
}; };
struct snd_pcm_status64;
struct snd_pcm_substream; struct snd_pcm_substream;
struct snd_pcm_audio_tstamp_config; /* definitions further down */ struct snd_pcm_audio_tstamp_config; /* definitions further down */
...@@ -62,7 +63,7 @@ struct snd_pcm_ops { ...@@ -62,7 +63,7 @@ struct snd_pcm_ops {
int (*sync_stop)(struct snd_pcm_substream *substream); int (*sync_stop)(struct snd_pcm_substream *substream);
snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *substream); snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *substream);
int (*get_time_info)(struct snd_pcm_substream *substream, int (*get_time_info)(struct snd_pcm_substream *substream,
struct timespec *system_ts, struct timespec *audio_ts, struct timespec64 *system_ts, struct timespec64 *audio_ts,
struct snd_pcm_audio_tstamp_config *audio_tstamp_config, struct snd_pcm_audio_tstamp_config *audio_tstamp_config,
struct snd_pcm_audio_tstamp_report *audio_tstamp_report); struct snd_pcm_audio_tstamp_report *audio_tstamp_report);
int (*fill_silence)(struct snd_pcm_substream *substream, int channel, int (*fill_silence)(struct snd_pcm_substream *substream, int channel,
...@@ -343,7 +344,7 @@ static inline void snd_pcm_pack_audio_tstamp_report(__u32 *data, __u32 *accuracy ...@@ -343,7 +344,7 @@ static inline void snd_pcm_pack_audio_tstamp_report(__u32 *data, __u32 *accuracy
struct snd_pcm_runtime { struct snd_pcm_runtime {
/* -- Status -- */ /* -- Status -- */
struct snd_pcm_substream *trigger_master; struct snd_pcm_substream *trigger_master;
struct timespec trigger_tstamp; /* trigger timestamp */ struct timespec64 trigger_tstamp; /* trigger timestamp */
bool trigger_tstamp_latched; /* trigger timestamp latched in low-level driver/hardware */ bool trigger_tstamp_latched; /* trigger timestamp latched in low-level driver/hardware */
int overrange; int overrange;
snd_pcm_uframes_t avail_max; snd_pcm_uframes_t avail_max;
...@@ -421,7 +422,7 @@ struct snd_pcm_runtime { ...@@ -421,7 +422,7 @@ struct snd_pcm_runtime {
/* -- audio timestamp config -- */ /* -- audio timestamp config -- */
struct snd_pcm_audio_tstamp_config audio_tstamp_config; struct snd_pcm_audio_tstamp_config audio_tstamp_config;
struct snd_pcm_audio_tstamp_report audio_tstamp_report; struct snd_pcm_audio_tstamp_report audio_tstamp_report;
struct timespec driver_tstamp; struct timespec64 driver_tstamp;
#if IS_ENABLED(CONFIG_SND_PCM_OSS) #if IS_ENABLED(CONFIG_SND_PCM_OSS)
/* -- OSS things -- */ /* -- OSS things -- */
...@@ -558,8 +559,8 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree); ...@@ -558,8 +559,8 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree);
int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info); int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info);
int snd_pcm_info_user(struct snd_pcm_substream *substream, int snd_pcm_info_user(struct snd_pcm_substream *substream,
struct snd_pcm_info __user *info); struct snd_pcm_info __user *info);
int snd_pcm_status(struct snd_pcm_substream *substream, int snd_pcm_status64(struct snd_pcm_substream *substream,
struct snd_pcm_status *status); struct snd_pcm_status64 *status);
int snd_pcm_start(struct snd_pcm_substream *substream); 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_stop(struct snd_pcm_substream *substream, snd_pcm_state_t status);
int snd_pcm_drain_done(struct snd_pcm_substream *substream); int snd_pcm_drain_done(struct snd_pcm_substream *substream);
...@@ -1155,22 +1156,22 @@ static inline void snd_pcm_set_runtime_buffer(struct snd_pcm_substream *substrea ...@@ -1155,22 +1156,22 @@ static inline void snd_pcm_set_runtime_buffer(struct snd_pcm_substream *substrea
} }
/** /**
* snd_pcm_gettime - Fill the timespec depending on the timestamp mode * snd_pcm_gettime - Fill the timespec64 depending on the timestamp mode
* @runtime: PCM runtime instance * @runtime: PCM runtime instance
* @tv: timespec to fill * @tv: timespec64 to fill
*/ */
static inline void snd_pcm_gettime(struct snd_pcm_runtime *runtime, static inline void snd_pcm_gettime(struct snd_pcm_runtime *runtime,
struct timespec *tv) struct timespec64 *tv)
{ {
switch (runtime->tstamp_type) { switch (runtime->tstamp_type) {
case SNDRV_PCM_TSTAMP_TYPE_MONOTONIC: case SNDRV_PCM_TSTAMP_TYPE_MONOTONIC:
ktime_get_ts(tv); ktime_get_ts64(tv);
break; break;
case SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW: case SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW:
getrawmonotonic(tv); ktime_get_raw_ts64(tv);
break; break;
default: default:
getnstimeofday(tv); ktime_get_real_ts64(tv);
break; break;
} }
} }
...@@ -1422,4 +1423,55 @@ static inline u64 pcm_format_to_bits(snd_pcm_format_t pcm_format) ...@@ -1422,4 +1423,55 @@ static inline u64 pcm_format_to_bits(snd_pcm_format_t pcm_format)
#define pcm_dbg(pcm, fmt, args...) \ #define pcm_dbg(pcm, fmt, args...) \
dev_dbg((pcm)->card->dev, fmt, ##args) dev_dbg((pcm)->card->dev, fmt, ##args)
struct snd_pcm_status64 {
snd_pcm_state_t state; /* stream state */
u8 rsvd[4];
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)
struct snd_pcm_status32 {
s32 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;
u32 appl_ptr; /* appl ptr */
u32 hw_ptr; /* hw ptr */
s32 delay; /* current delay in frames */
u32 avail; /* number of frames available */
u32 avail_max; /* max frames available on hw since last status */
u32 overrange; /* count of ADC (capture) overrange detections from last status */
s32 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 /* __SOUND_PCM_H */ #endif /* __SOUND_PCM_H */
...@@ -93,8 +93,8 @@ struct snd_soc_component_driver { ...@@ -93,8 +93,8 @@ struct snd_soc_component_driver {
snd_pcm_uframes_t (*pointer)(struct snd_soc_component *component, snd_pcm_uframes_t (*pointer)(struct snd_soc_component *component,
struct snd_pcm_substream *substream); struct snd_pcm_substream *substream);
int (*get_time_info)(struct snd_soc_component *component, int (*get_time_info)(struct snd_soc_component *component,
struct snd_pcm_substream *substream, struct timespec *system_ts, struct snd_pcm_substream *substream, struct timespec64 *system_ts,
struct timespec *audio_ts, struct timespec64 *audio_ts,
struct snd_pcm_audio_tstamp_config *audio_tstamp_config, struct snd_pcm_audio_tstamp_config *audio_tstamp_config,
struct snd_pcm_audio_tstamp_report *audio_tstamp_report); struct snd_pcm_audio_tstamp_report *audio_tstamp_report);
int (*copy_user)(struct snd_soc_component *component, int (*copy_user)(struct snd_soc_component *component,
......
...@@ -89,7 +89,7 @@ struct snd_timer_instance { ...@@ -89,7 +89,7 @@ struct snd_timer_instance {
unsigned long ticks, unsigned long resolution); unsigned long ticks, unsigned long resolution);
void (*ccallback) (struct snd_timer_instance * timeri, void (*ccallback) (struct snd_timer_instance * timeri,
int event, int event,
struct timespec * tstamp, struct timespec64 * tstamp,
unsigned long resolution); unsigned long resolution);
void (*disconnect)(struct snd_timer_instance *timeri); void (*disconnect)(struct snd_timer_instance *timeri);
void *callback_data; void *callback_data;
...@@ -113,7 +113,7 @@ struct snd_timer_instance { ...@@ -113,7 +113,7 @@ struct snd_timer_instance {
*/ */
int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid, struct snd_timer **rtimer); int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid, struct snd_timer **rtimer);
void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstamp); void snd_timer_notify(struct snd_timer *timer, int event, struct timespec64 *tstamp);
int snd_timer_global_new(char *id, int device, struct snd_timer **rtimer); int snd_timer_global_new(char *id, int device, struct snd_timer **rtimer);
int snd_timer_global_free(struct snd_timer *timer); int snd_timer_global_free(struct snd_timer *timer);
int snd_timer_global_register(struct snd_timer *timer); int snd_timer_global_register(struct snd_timer *timer);
......
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
#include <time.h> #include <time.h>
#endif #endif
#include <asm/byteorder.h>
/* /*
* protocol version * protocol version
*/ */
...@@ -154,7 +156,7 @@ struct snd_hwdep_dsp_image { ...@@ -154,7 +156,7 @@ struct snd_hwdep_dsp_image {
* * * *
*****************************************************************************/ *****************************************************************************/
#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 14) #define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 15)
typedef unsigned long snd_pcm_uframes_t; typedef unsigned long snd_pcm_uframes_t;
typedef signed long snd_pcm_sframes_t; typedef signed long snd_pcm_sframes_t;
...@@ -301,7 +303,9 @@ typedef int __bitwise snd_pcm_subformat_t; ...@@ -301,7 +303,9 @@ typedef int __bitwise snd_pcm_subformat_t;
#define SNDRV_PCM_INFO_DRAIN_TRIGGER 0x40000000 /* internal kernel flag - trigger in drain */ #define SNDRV_PCM_INFO_DRAIN_TRIGGER 0x40000000 /* internal kernel flag - trigger in drain */
#define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000 /* internal kernel flag - FIFO size is in frames */ #define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000 /* internal kernel flag - FIFO size is in frames */
#if (__BITS_PER_LONG == 32 && defined(__USE_TIME_BITS64)) || defined __KERNEL__
#define __SND_STRUCT_TIME64
#endif
typedef int __bitwise snd_pcm_state_t; typedef int __bitwise snd_pcm_state_t;
#define SNDRV_PCM_STATE_OPEN ((__force snd_pcm_state_t) 0) /* stream is open */ #define SNDRV_PCM_STATE_OPEN ((__force snd_pcm_state_t) 0) /* stream is open */
...@@ -317,8 +321,17 @@ typedef int __bitwise snd_pcm_state_t; ...@@ -317,8 +321,17 @@ typedef int __bitwise snd_pcm_state_t;
enum { enum {
SNDRV_PCM_MMAP_OFFSET_DATA = 0x00000000, SNDRV_PCM_MMAP_OFFSET_DATA = 0x00000000,
SNDRV_PCM_MMAP_OFFSET_STATUS = 0x80000000, SNDRV_PCM_MMAP_OFFSET_STATUS_OLD = 0x80000000,
SNDRV_PCM_MMAP_OFFSET_CONTROL = 0x81000000, SNDRV_PCM_MMAP_OFFSET_CONTROL_OLD = 0x81000000,
SNDRV_PCM_MMAP_OFFSET_STATUS_NEW = 0x82000000,
SNDRV_PCM_MMAP_OFFSET_CONTROL_NEW = 0x83000000,
#ifdef __SND_STRUCT_TIME64
SNDRV_PCM_MMAP_OFFSET_STATUS = SNDRV_PCM_MMAP_OFFSET_STATUS_NEW,
SNDRV_PCM_MMAP_OFFSET_CONTROL = SNDRV_PCM_MMAP_OFFSET_CONTROL_NEW,
#else
SNDRV_PCM_MMAP_OFFSET_STATUS = SNDRV_PCM_MMAP_OFFSET_STATUS_OLD,
SNDRV_PCM_MMAP_OFFSET_CONTROL = SNDRV_PCM_MMAP_OFFSET_CONTROL_OLD,
#endif
}; };
union snd_pcm_sync_id { union snd_pcm_sync_id {
...@@ -456,8 +469,13 @@ enum { ...@@ -456,8 +469,13 @@ enum {
SNDRV_PCM_AUDIO_TSTAMP_TYPE_LAST = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED SNDRV_PCM_AUDIO_TSTAMP_TYPE_LAST = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED
}; };
#ifndef __KERNEL__
/* explicit padding avoids incompatibility between i386 and x86-64 */
typedef struct { unsigned char pad[sizeof(time_t) - sizeof(int)] __time_pad;
struct snd_pcm_status { struct snd_pcm_status {
snd_pcm_state_t state; /* stream state */ snd_pcm_state_t state; /* stream state */
__time_pad pad1; /* align to timespec */
struct timespec trigger_tstamp; /* time when stream was started/stopped/paused */ struct timespec trigger_tstamp; /* time when stream was started/stopped/paused */
struct timespec tstamp; /* reference timestamp */ struct timespec tstamp; /* reference timestamp */
snd_pcm_uframes_t appl_ptr; /* appl ptr */ snd_pcm_uframes_t appl_ptr; /* appl ptr */
...@@ -473,17 +491,48 @@ struct snd_pcm_status { ...@@ -473,17 +491,48 @@ struct snd_pcm_status {
__u32 audio_tstamp_accuracy; /* in ns units, only valid if indicated in audio_tstamp_data */ __u32 audio_tstamp_accuracy; /* in ns units, only valid if indicated in audio_tstamp_data */
unsigned char reserved[52-2*sizeof(struct timespec)]; /* must be filled with zero */ unsigned char reserved[52-2*sizeof(struct timespec)]; /* must be filled with zero */
}; };
#endif
struct snd_pcm_mmap_status { /*
* For mmap operations, we need the 64-bit layout, both for compat mode,
* and for y2038 compatibility. For 64-bit applications, the two definitions
* are identical, so we keep the traditional version.
*/
#ifdef __SND_STRUCT_TIME64
#define __snd_pcm_mmap_status64 snd_pcm_mmap_status
#define __snd_pcm_mmap_control64 snd_pcm_mmap_control
#define __snd_pcm_sync_ptr64 snd_pcm_sync_ptr
#ifdef __KERNEL__
#define __snd_timespec64 __kernel_timespec
#else
#define __snd_timespec64 timespec
#endif
struct __snd_timespec {
__s32 tv_sec;
__s32 tv_nsec;
};
#else
#define __snd_pcm_mmap_status snd_pcm_mmap_status
#define __snd_pcm_mmap_control snd_pcm_mmap_control
#define __snd_pcm_sync_ptr snd_pcm_sync_ptr
#define __snd_timespec timespec
struct __snd_timespec64 {
__s64 tv_sec;
__s64 tv_nsec;
};
#endif
struct __snd_pcm_mmap_status {
snd_pcm_state_t state; /* RO: state - SNDRV_PCM_STATE_XXXX */ snd_pcm_state_t state; /* RO: state - SNDRV_PCM_STATE_XXXX */
int pad1; /* Needed for 64 bit alignment */ int pad1; /* Needed for 64 bit alignment */
snd_pcm_uframes_t hw_ptr; /* RO: hw ptr (0...boundary-1) */ snd_pcm_uframes_t hw_ptr; /* RO: hw ptr (0...boundary-1) */
struct timespec tstamp; /* Timestamp */ struct __snd_timespec tstamp; /* Timestamp */
snd_pcm_state_t suspended_state; /* RO: suspended stream state */ snd_pcm_state_t suspended_state; /* RO: suspended stream state */
struct timespec audio_tstamp; /* from sample counter or wall clock */ struct __snd_timespec audio_tstamp; /* from sample counter or wall clock */
}; };
struct snd_pcm_mmap_control { struct __snd_pcm_mmap_control {
snd_pcm_uframes_t appl_ptr; /* RW: appl ptr (0...boundary-1) */ snd_pcm_uframes_t appl_ptr; /* RW: appl ptr (0...boundary-1) */
snd_pcm_uframes_t avail_min; /* RW: min available frames for wakeup */ snd_pcm_uframes_t avail_min; /* RW: min available frames for wakeup */
}; };
...@@ -492,14 +541,59 @@ struct snd_pcm_mmap_control { ...@@ -492,14 +541,59 @@ struct snd_pcm_mmap_control {
#define SNDRV_PCM_SYNC_PTR_APPL (1<<1) /* get appl_ptr from driver (r/w op) */ #define SNDRV_PCM_SYNC_PTR_APPL (1<<1) /* get appl_ptr from driver (r/w op) */
#define SNDRV_PCM_SYNC_PTR_AVAIL_MIN (1<<2) /* get avail_min from driver */ #define SNDRV_PCM_SYNC_PTR_AVAIL_MIN (1<<2) /* get avail_min from driver */
struct snd_pcm_sync_ptr { struct __snd_pcm_sync_ptr {
unsigned int flags; unsigned int flags;
union { union {
struct snd_pcm_mmap_status status; struct __snd_pcm_mmap_status status;
unsigned char reserved[64];
} s;
union {
struct __snd_pcm_mmap_control control;
unsigned char reserved[64];
} c;
};
#if defined(__BYTE_ORDER) ? __BYTE_ORDER == __BIG_ENDIAN : defined(__BIG_ENDIAN)
typedef char __pad_before_uframe[sizeof(__u64) - sizeof(snd_pcm_uframes_t)];
typedef char __pad_after_uframe[0];
#endif
#if defined(__BYTE_ORDER) ? __BYTE_ORDER == __LITTLE_ENDIAN : defined(__LITTLE_ENDIAN)
typedef char __pad_before_uframe[0];
typedef char __pad_after_uframe[sizeof(__u64) - sizeof(snd_pcm_uframes_t)];
#endif
struct __snd_pcm_mmap_status64 {
__s32 state; /* RO: state - SNDRV_PCM_STATE_XXXX */
__u32 pad1; /* Needed for 64 bit alignment */
__pad_before_uframe __pad1;
snd_pcm_uframes_t hw_ptr; /* RO: hw ptr (0...boundary-1) */
__pad_after_uframe __pad2;
struct __snd_timespec64 tstamp; /* Timestamp */
__s32 suspended_state; /* RO: suspended stream state */
__u32 pad3; /* Needed for 64 bit alignment */
struct __snd_timespec64 audio_tstamp; /* sample counter or wall clock */
};
struct __snd_pcm_mmap_control64 {
__pad_before_uframe __pad1;
snd_pcm_uframes_t appl_ptr; /* RW: appl ptr (0...boundary-1) */
__pad_before_uframe __pad2;
__pad_before_uframe __pad3;
snd_pcm_uframes_t avail_min; /* RW: min available frames for wakeup */
__pad_after_uframe __pad4;
};
struct __snd_pcm_sync_ptr64 {
__u32 flags;
__u32 pad1;
union {
struct __snd_pcm_mmap_status64 status;
unsigned char reserved[64]; unsigned char reserved[64];
} s; } s;
union { union {
struct snd_pcm_mmap_control control; struct __snd_pcm_mmap_control64 control;
unsigned char reserved[64]; unsigned char reserved[64];
} c; } c;
}; };
...@@ -584,6 +678,8 @@ enum { ...@@ -584,6 +678,8 @@ enum {
#define SNDRV_PCM_IOCTL_STATUS _IOR('A', 0x20, struct snd_pcm_status) #define SNDRV_PCM_IOCTL_STATUS _IOR('A', 0x20, struct snd_pcm_status)
#define SNDRV_PCM_IOCTL_DELAY _IOR('A', 0x21, snd_pcm_sframes_t) #define SNDRV_PCM_IOCTL_DELAY _IOR('A', 0x21, snd_pcm_sframes_t)
#define SNDRV_PCM_IOCTL_HWSYNC _IO('A', 0x22) #define SNDRV_PCM_IOCTL_HWSYNC _IO('A', 0x22)
#define __SNDRV_PCM_IOCTL_SYNC_PTR _IOWR('A', 0x23, struct __snd_pcm_sync_ptr)
#define __SNDRV_PCM_IOCTL_SYNC_PTR64 _IOWR('A', 0x23, struct __snd_pcm_sync_ptr64)
#define SNDRV_PCM_IOCTL_SYNC_PTR _IOWR('A', 0x23, struct snd_pcm_sync_ptr) #define SNDRV_PCM_IOCTL_SYNC_PTR _IOWR('A', 0x23, struct snd_pcm_sync_ptr)
#define SNDRV_PCM_IOCTL_STATUS_EXT _IOWR('A', 0x24, struct snd_pcm_status) #define SNDRV_PCM_IOCTL_STATUS_EXT _IOWR('A', 0x24, struct snd_pcm_status)
#define SNDRV_PCM_IOCTL_CHANNEL_INFO _IOR('A', 0x32, struct snd_pcm_channel_info) #define SNDRV_PCM_IOCTL_CHANNEL_INFO _IOR('A', 0x32, struct snd_pcm_channel_info)
...@@ -614,7 +710,7 @@ enum { ...@@ -614,7 +710,7 @@ enum {
* Raw MIDI section - /dev/snd/midi?? * Raw MIDI section - /dev/snd/midi??
*/ */
#define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 0) #define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 1)
enum { enum {
SNDRV_RAWMIDI_STREAM_OUTPUT = 0, SNDRV_RAWMIDI_STREAM_OUTPUT = 0,
...@@ -648,13 +744,16 @@ struct snd_rawmidi_params { ...@@ -648,13 +744,16 @@ struct snd_rawmidi_params {
unsigned char reserved[16]; /* reserved for future use */ unsigned char reserved[16]; /* reserved for future use */
}; };
#ifndef __KERNEL__
struct snd_rawmidi_status { struct snd_rawmidi_status {
int stream; int stream;
__time_pad pad1;
struct timespec tstamp; /* Timestamp */ struct timespec tstamp; /* Timestamp */
size_t avail; /* available bytes */ size_t avail; /* available bytes */
size_t xruns; /* count of overruns since last status (in bytes) */ size_t xruns; /* count of overruns since last status (in bytes) */
unsigned char reserved[16]; /* reserved for future use */ unsigned char reserved[16]; /* reserved for future use */
}; };
#endif
#define SNDRV_RAWMIDI_IOCTL_PVERSION _IOR('W', 0x00, int) #define SNDRV_RAWMIDI_IOCTL_PVERSION _IOR('W', 0x00, int)
#define SNDRV_RAWMIDI_IOCTL_INFO _IOR('W', 0x01, struct snd_rawmidi_info) #define SNDRV_RAWMIDI_IOCTL_INFO _IOR('W', 0x01, struct snd_rawmidi_info)
...@@ -667,7 +766,7 @@ struct snd_rawmidi_status { ...@@ -667,7 +766,7 @@ struct snd_rawmidi_status {
* Timer section - /dev/snd/timer * Timer section - /dev/snd/timer
*/ */
#define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 6) #define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 7)
enum { enum {
SNDRV_TIMER_CLASS_NONE = -1, SNDRV_TIMER_CLASS_NONE = -1,
...@@ -761,6 +860,7 @@ struct snd_timer_params { ...@@ -761,6 +860,7 @@ struct snd_timer_params {
unsigned char reserved[60]; /* reserved */ unsigned char reserved[60]; /* reserved */
}; };
#ifndef __KERNEL__
struct snd_timer_status { struct snd_timer_status {
struct timespec tstamp; /* Timestamp - last update */ struct timespec tstamp; /* Timestamp - last update */
unsigned int resolution; /* current period resolution in ns */ unsigned int resolution; /* current period resolution in ns */
...@@ -769,10 +869,11 @@ struct snd_timer_status { ...@@ -769,10 +869,11 @@ struct snd_timer_status {
unsigned int queue; /* used queue size */ unsigned int queue; /* used queue size */
unsigned char reserved[64]; /* reserved */ unsigned char reserved[64]; /* reserved */
}; };
#endif
#define SNDRV_TIMER_IOCTL_PVERSION _IOR('T', 0x00, int) #define SNDRV_TIMER_IOCTL_PVERSION _IOR('T', 0x00, int)
#define SNDRV_TIMER_IOCTL_NEXT_DEVICE _IOWR('T', 0x01, struct snd_timer_id) #define SNDRV_TIMER_IOCTL_NEXT_DEVICE _IOWR('T', 0x01, struct snd_timer_id)
#define SNDRV_TIMER_IOCTL_TREAD _IOW('T', 0x02, int) #define SNDRV_TIMER_IOCTL_TREAD_OLD _IOW('T', 0x02, int)
#define SNDRV_TIMER_IOCTL_GINFO _IOWR('T', 0x03, struct snd_timer_ginfo) #define SNDRV_TIMER_IOCTL_GINFO _IOWR('T', 0x03, struct snd_timer_ginfo)
#define SNDRV_TIMER_IOCTL_GPARAMS _IOW('T', 0x04, struct snd_timer_gparams) #define SNDRV_TIMER_IOCTL_GPARAMS _IOW('T', 0x04, struct snd_timer_gparams)
#define SNDRV_TIMER_IOCTL_GSTATUS _IOWR('T', 0x05, struct snd_timer_gstatus) #define SNDRV_TIMER_IOCTL_GSTATUS _IOWR('T', 0x05, struct snd_timer_gstatus)
...@@ -785,6 +886,15 @@ struct snd_timer_status { ...@@ -785,6 +886,15 @@ struct snd_timer_status {
#define SNDRV_TIMER_IOCTL_STOP _IO('T', 0xa1) #define SNDRV_TIMER_IOCTL_STOP _IO('T', 0xa1)
#define SNDRV_TIMER_IOCTL_CONTINUE _IO('T', 0xa2) #define SNDRV_TIMER_IOCTL_CONTINUE _IO('T', 0xa2)
#define SNDRV_TIMER_IOCTL_PAUSE _IO('T', 0xa3) #define SNDRV_TIMER_IOCTL_PAUSE _IO('T', 0xa3)
#define SNDRV_TIMER_IOCTL_TREAD64 _IOW('T', 0xa4, int)
#if __BITS_PER_LONG == 64
#define SNDRV_TIMER_IOCTL_TREAD SNDRV_TIMER_IOCTL_TREAD_OLD
#else
#define SNDRV_TIMER_IOCTL_TREAD ((sizeof(__kernel_long_t) >= sizeof(time_t)) ? \
SNDRV_TIMER_IOCTL_TREAD_OLD : \
SNDRV_TIMER_IOCTL_TREAD64)
#endif
struct snd_timer_read { struct snd_timer_read {
unsigned int resolution; unsigned int resolution;
...@@ -810,11 +920,15 @@ enum { ...@@ -810,11 +920,15 @@ enum {
SNDRV_TIMER_EVENT_MRESUME = SNDRV_TIMER_EVENT_RESUME + 10, SNDRV_TIMER_EVENT_MRESUME = SNDRV_TIMER_EVENT_RESUME + 10,
}; };
#ifndef __KERNEL__
struct snd_timer_tread { struct snd_timer_tread {
int event; int event;
__time_pad pad1;
struct timespec tstamp; struct timespec tstamp;
unsigned int val; unsigned int val;
__time_pad pad2;
}; };
#endif
/**************************************************************************** /****************************************************************************
* * * *
...@@ -955,8 +1069,7 @@ struct snd_ctl_elem_value { ...@@ -955,8 +1069,7 @@ struct snd_ctl_elem_value {
} bytes; } bytes;
struct snd_aes_iec958 iec958; struct snd_aes_iec958 iec958;
} value; /* RO */ } value; /* RO */
struct timespec tstamp; unsigned char reserved[128];
unsigned char reserved[128-sizeof(struct timespec)];
}; };
struct snd_ctl_tlv { struct snd_ctl_tlv {
......
...@@ -443,7 +443,7 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry, ...@@ -443,7 +443,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_substream *substream = entry->private_data;
struct snd_pcm_runtime *runtime; struct snd_pcm_runtime *runtime;
struct snd_pcm_status status; struct snd_pcm_status64 status;
int err; int err;
mutex_lock(&substream->pcm->open_mutex); mutex_lock(&substream->pcm->open_mutex);
...@@ -453,17 +453,17 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry, ...@@ -453,17 +453,17 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
goto unlock; goto unlock;
} }
memset(&status, 0, sizeof(status)); memset(&status, 0, sizeof(status));
err = snd_pcm_status(substream, &status); err = snd_pcm_status64(substream, &status);
if (err < 0) { if (err < 0) {
snd_iprintf(buffer, "error %d\n", err); snd_iprintf(buffer, "error %d\n", err);
goto unlock; goto unlock;
} }
snd_iprintf(buffer, "state: %s\n", snd_pcm_state_name(status.state)); 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, "owner_pid : %d\n", pid_vnr(substream->pid));
snd_iprintf(buffer, "trigger_time: %ld.%09ld\n", snd_iprintf(buffer, "trigger_time: %lld.%09lld\n",
status.trigger_tstamp.tv_sec, status.trigger_tstamp.tv_nsec); status.trigger_tstamp_sec, status.trigger_tstamp_nsec);
snd_iprintf(buffer, "tstamp : %ld.%09ld\n", snd_iprintf(buffer, "tstamp : %lld.%09lld\n",
status.tstamp.tv_sec, status.tstamp.tv_nsec); status.tstamp_sec, status.tstamp_nsec);
snd_iprintf(buffer, "delay : %ld\n", status.delay); snd_iprintf(buffer, "delay : %ld\n", status.delay);
snd_iprintf(buffer, "avail : %ld\n", status.avail); snd_iprintf(buffer, "avail : %ld\n", status.avail);
snd_iprintf(buffer, "avail_max : %ld\n", status.avail_max); snd_iprintf(buffer, "avail_max : %ld\n", status.avail_max);
......
This diff is collapsed.
...@@ -144,8 +144,13 @@ void __snd_pcm_xrun(struct snd_pcm_substream *substream) ...@@ -144,8 +144,13 @@ void __snd_pcm_xrun(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
trace_xrun(substream); trace_xrun(substream);
if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); struct timespec64 tstamp;
snd_pcm_gettime(runtime, &tstamp);
runtime->status->tstamp.tv_sec = tstamp.tv_sec;
runtime->status->tstamp.tv_nsec = tstamp.tv_nsec;
}
snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { if (xrun_debug(substream, XRUN_DEBUG_BASIC)) {
char name[16]; char name[16];
...@@ -200,12 +205,12 @@ int snd_pcm_update_state(struct snd_pcm_substream *substream, ...@@ -200,12 +205,12 @@ int snd_pcm_update_state(struct snd_pcm_substream *substream,
} }
static void update_audio_tstamp(struct snd_pcm_substream *substream, static void update_audio_tstamp(struct snd_pcm_substream *substream,
struct timespec *curr_tstamp, struct timespec64 *curr_tstamp,
struct timespec *audio_tstamp) struct timespec64 *audio_tstamp)
{ {
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
u64 audio_frames, audio_nsecs; u64 audio_frames, audio_nsecs;
struct timespec driver_tstamp; struct timespec64 driver_tstamp;
if (runtime->tstamp_mode != SNDRV_PCM_TSTAMP_ENABLE) if (runtime->tstamp_mode != SNDRV_PCM_TSTAMP_ENABLE)
return; return;
...@@ -229,18 +234,23 @@ static void update_audio_tstamp(struct snd_pcm_substream *substream, ...@@ -229,18 +234,23 @@ static void update_audio_tstamp(struct snd_pcm_substream *substream,
} }
audio_nsecs = div_u64(audio_frames * 1000000000LL, audio_nsecs = div_u64(audio_frames * 1000000000LL,
runtime->rate); runtime->rate);
*audio_tstamp = ns_to_timespec(audio_nsecs); *audio_tstamp = ns_to_timespec64(audio_nsecs);
} }
if (!timespec_equal(&runtime->status->audio_tstamp, audio_tstamp)) {
runtime->status->audio_tstamp = *audio_tstamp; if (runtime->status->audio_tstamp.tv_sec != audio_tstamp->tv_sec ||
runtime->status->tstamp = *curr_tstamp; runtime->status->audio_tstamp.tv_nsec != audio_tstamp->tv_nsec) {
runtime->status->audio_tstamp.tv_sec = audio_tstamp->tv_sec;
runtime->status->audio_tstamp.tv_nsec = audio_tstamp->tv_nsec;
runtime->status->tstamp.tv_sec = curr_tstamp->tv_sec;
runtime->status->tstamp.tv_nsec = curr_tstamp->tv_nsec;
} }
/* /*
* re-take a driver timestamp to let apps detect if the reference tstamp * re-take a driver timestamp to let apps detect if the reference tstamp
* read by low-level hardware was provided with a delay * read by low-level hardware was provided with a delay
*/ */
snd_pcm_gettime(substream->runtime, (struct timespec *)&driver_tstamp); snd_pcm_gettime(substream->runtime, &driver_tstamp);
runtime->driver_tstamp = driver_tstamp; runtime->driver_tstamp = driver_tstamp;
} }
...@@ -253,8 +263,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, ...@@ -253,8 +263,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
snd_pcm_sframes_t hdelta, delta; snd_pcm_sframes_t hdelta, delta;
unsigned long jdelta; unsigned long jdelta;
unsigned long curr_jiffies; unsigned long curr_jiffies;
struct timespec curr_tstamp; struct timespec64 curr_tstamp;
struct timespec audio_tstamp; struct timespec64 audio_tstamp;
int crossed_boundary = 0; int crossed_boundary = 0;
old_hw_ptr = runtime->status->hw_ptr; old_hw_ptr = runtime->status->hw_ptr;
...@@ -277,9 +287,9 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, ...@@ -277,9 +287,9 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
/* re-test in case tstamp type is not supported in hardware and was demoted to DEFAULT */ /* re-test in case tstamp type is not supported in hardware and was demoted to DEFAULT */
if (runtime->audio_tstamp_report.actual_type == SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT) if (runtime->audio_tstamp_report.actual_type == SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT)
snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp); snd_pcm_gettime(runtime, &curr_tstamp);
} else } else
snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp); snd_pcm_gettime(runtime, &curr_tstamp);
} }
if (pos == SNDRV_PCM_POS_XRUN) { if (pos == SNDRV_PCM_POS_XRUN) {
......
This diff is collapsed.
...@@ -50,6 +50,29 @@ static DEFINE_MUTEX(register_mutex); ...@@ -50,6 +50,29 @@ static DEFINE_MUTEX(register_mutex);
#define rmidi_dbg(rmidi, fmt, args...) \ #define rmidi_dbg(rmidi, fmt, args...) \
dev_dbg(&(rmidi)->dev, fmt, ##args) dev_dbg(&(rmidi)->dev, fmt, ##args)
struct snd_rawmidi_status32 {
s32 stream;
s32 tstamp_sec; /* Timestamp */
s32 tstamp_nsec;
u32 avail; /* available bytes */
u32 xruns; /* count of overruns since last status (in bytes) */
unsigned char reserved[16]; /* reserved for future use */
};
#define SNDRV_RAWMIDI_IOCTL_STATUS32 _IOWR('W', 0x20, struct snd_rawmidi_status32)
struct snd_rawmidi_status64 {
int stream;
u8 rsvd[4]; /* alignment */
s64 tstamp_sec; /* Timestamp */
s64 tstamp_nsec;
size_t avail; /* available bytes */
size_t xruns; /* count of overruns since last status (in bytes) */
unsigned char reserved[16]; /* reserved for future use */
};
#define SNDRV_RAWMIDI_IOCTL_STATUS64 _IOWR('W', 0x20, struct snd_rawmidi_status64)
static struct snd_rawmidi *snd_rawmidi_search(struct snd_card *card, int device) static struct snd_rawmidi *snd_rawmidi_search(struct snd_card *card, int device)
{ {
struct snd_rawmidi *rawmidi; struct snd_rawmidi *rawmidi;
...@@ -677,7 +700,7 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream, ...@@ -677,7 +700,7 @@ int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
EXPORT_SYMBOL(snd_rawmidi_input_params); EXPORT_SYMBOL(snd_rawmidi_input_params);
static int snd_rawmidi_output_status(struct snd_rawmidi_substream *substream, static int snd_rawmidi_output_status(struct snd_rawmidi_substream *substream,
struct snd_rawmidi_status *status) struct snd_rawmidi_status64 *status)
{ {
struct snd_rawmidi_runtime *runtime = substream->runtime; struct snd_rawmidi_runtime *runtime = substream->runtime;
...@@ -690,7 +713,7 @@ static int snd_rawmidi_output_status(struct snd_rawmidi_substream *substream, ...@@ -690,7 +713,7 @@ static int snd_rawmidi_output_status(struct snd_rawmidi_substream *substream,
} }
static int snd_rawmidi_input_status(struct snd_rawmidi_substream *substream, static int snd_rawmidi_input_status(struct snd_rawmidi_substream *substream,
struct snd_rawmidi_status *status) struct snd_rawmidi_status64 *status)
{ {
struct snd_rawmidi_runtime *runtime = substream->runtime; struct snd_rawmidi_runtime *runtime = substream->runtime;
...@@ -704,6 +727,80 @@ static int snd_rawmidi_input_status(struct snd_rawmidi_substream *substream, ...@@ -704,6 +727,80 @@ static int snd_rawmidi_input_status(struct snd_rawmidi_substream *substream,
return 0; return 0;
} }
static int snd_rawmidi_ioctl_status32(struct snd_rawmidi_file *rfile,
struct snd_rawmidi_status32 __user *argp)
{
int err = 0;
struct snd_rawmidi_status32 __user *status = argp;
struct snd_rawmidi_status32 status32;
struct snd_rawmidi_status64 status64;
if (copy_from_user(&status32, argp,
sizeof(struct snd_rawmidi_status32)))
return -EFAULT;
switch (status32.stream) {
case SNDRV_RAWMIDI_STREAM_OUTPUT:
if (rfile->output == NULL)
return -EINVAL;
err = snd_rawmidi_output_status(rfile->output, &status64);
break;
case SNDRV_RAWMIDI_STREAM_INPUT:
if (rfile->input == NULL)
return -EINVAL;
err = snd_rawmidi_input_status(rfile->input, &status64);
break;
default:
return -EINVAL;
}
if (err < 0)
return err;
status32 = (struct snd_rawmidi_status32) {
.stream = status64.stream,
.tstamp_sec = status64.tstamp_sec,
.tstamp_nsec = status64.tstamp_nsec,
.avail = status64.avail,
.xruns = status64.xruns,
};
if (copy_to_user(status, &status32, sizeof(*status)))
return -EFAULT;
return 0;
}
static int snd_rawmidi_ioctl_status64(struct snd_rawmidi_file *rfile,
struct snd_rawmidi_status64 __user *argp)
{
int err = 0;
struct snd_rawmidi_status64 status;
if (copy_from_user(&status, argp, sizeof(struct snd_rawmidi_status64)))
return -EFAULT;
switch (status.stream) {
case SNDRV_RAWMIDI_STREAM_OUTPUT:
if (rfile->output == NULL)
return -EINVAL;
err = snd_rawmidi_output_status(rfile->output, &status);
break;
case SNDRV_RAWMIDI_STREAM_INPUT:
if (rfile->input == NULL)
return -EINVAL;
err = snd_rawmidi_input_status(rfile->input, &status);
break;
default:
return -EINVAL;
}
if (err < 0)
return err;
if (copy_to_user(argp, &status,
sizeof(struct snd_rawmidi_status64)))
return -EFAULT;
return 0;
}
static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{ {
struct snd_rawmidi_file *rfile; struct snd_rawmidi_file *rfile;
...@@ -750,33 +847,10 @@ static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long ...@@ -750,33 +847,10 @@ static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long
return -EINVAL; return -EINVAL;
} }
} }
case SNDRV_RAWMIDI_IOCTL_STATUS: case SNDRV_RAWMIDI_IOCTL_STATUS32:
{ return snd_rawmidi_ioctl_status32(rfile, argp);
int err = 0; case SNDRV_RAWMIDI_IOCTL_STATUS64:
struct snd_rawmidi_status status; return snd_rawmidi_ioctl_status64(rfile, argp);
if (copy_from_user(&status, argp, sizeof(struct snd_rawmidi_status)))
return -EFAULT;
switch (status.stream) {
case SNDRV_RAWMIDI_STREAM_OUTPUT:
if (rfile->output == NULL)
return -EINVAL;
err = snd_rawmidi_output_status(rfile->output, &status);
break;
case SNDRV_RAWMIDI_STREAM_INPUT:
if (rfile->input == NULL)
return -EINVAL;
err = snd_rawmidi_input_status(rfile->input, &status);
break;
default:
return -EINVAL;
}
if (err < 0)
return err;
if (copy_to_user(argp, &status, sizeof(struct snd_rawmidi_status)))
return -EFAULT;
return 0;
}
case SNDRV_RAWMIDI_IOCTL_DROP: case SNDRV_RAWMIDI_IOCTL_DROP:
{ {
int val; int val;
......
...@@ -41,19 +41,22 @@ static int snd_rawmidi_ioctl_params_compat(struct snd_rawmidi_file *rfile, ...@@ -41,19 +41,22 @@ static int snd_rawmidi_ioctl_params_compat(struct snd_rawmidi_file *rfile,
return -EINVAL; return -EINVAL;
} }
struct snd_rawmidi_status32 { struct compat_snd_rawmidi_status64 {
s32 stream; s32 stream;
struct compat_timespec tstamp; u8 rsvd[4]; /* alignment */
s64 tstamp_sec;
s64 tstamp_nsec;
u32 avail; u32 avail;
u32 xruns; u32 xruns;
unsigned char reserved[16]; unsigned char reserved[16];
} __attribute__((packed)); } __attribute__((packed));
static int snd_rawmidi_ioctl_status_compat(struct snd_rawmidi_file *rfile, static int snd_rawmidi_ioctl_status_compat64(struct snd_rawmidi_file *rfile,
struct snd_rawmidi_status32 __user *src) struct compat_snd_rawmidi_status64 __user *src)
{ {
int err; int err;
struct snd_rawmidi_status status; struct snd_rawmidi_status64 status;
struct compat_snd_rawmidi_status64 compat_status;
if (get_user(status.stream, &src->stream)) if (get_user(status.stream, &src->stream))
return -EFAULT; return -EFAULT;
...@@ -75,68 +78,24 @@ static int snd_rawmidi_ioctl_status_compat(struct snd_rawmidi_file *rfile, ...@@ -75,68 +78,24 @@ static int snd_rawmidi_ioctl_status_compat(struct snd_rawmidi_file *rfile,
if (err < 0) if (err < 0)
return err; return err;
if (compat_put_timespec(&status.tstamp, &src->tstamp) || compat_status = (struct compat_snd_rawmidi_status64) {
put_user(status.avail, &src->avail) || .stream = status.stream,
put_user(status.xruns, &src->xruns)) .tstamp_sec = status.tstamp_sec,
return -EFAULT; .tstamp_nsec = status.tstamp_nsec,
.avail = status.avail,
return 0; .xruns = status.xruns,
} };
#ifdef CONFIG_X86_X32
/* X32 ABI has 64bit timespec and 64bit alignment */
struct snd_rawmidi_status_x32 {
s32 stream;
u32 rsvd; /* alignment */
struct timespec tstamp;
u32 avail;
u32 xruns;
unsigned char reserved[16];
} __attribute__((packed));
#define put_timespec(src, dst) copy_to_user(dst, src, sizeof(*dst))
static int snd_rawmidi_ioctl_status_x32(struct snd_rawmidi_file *rfile,
struct snd_rawmidi_status_x32 __user *src)
{
int err;
struct snd_rawmidi_status status;
if (get_user(status.stream, &src->stream))
return -EFAULT;
switch (status.stream) {
case SNDRV_RAWMIDI_STREAM_OUTPUT:
if (!rfile->output)
return -EINVAL;
err = snd_rawmidi_output_status(rfile->output, &status);
break;
case SNDRV_RAWMIDI_STREAM_INPUT:
if (!rfile->input)
return -EINVAL;
err = snd_rawmidi_input_status(rfile->input, &status);
break;
default:
return -EINVAL;
}
if (err < 0)
return err;
if (put_timespec(&status.tstamp, &src->tstamp) || if (copy_to_user(src, &compat_status, sizeof(*src)))
put_user(status.avail, &src->avail) ||
put_user(status.xruns, &src->xruns))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
#endif /* CONFIG_X86_X32 */
enum { enum {
SNDRV_RAWMIDI_IOCTL_PARAMS32 = _IOWR('W', 0x10, struct snd_rawmidi_params32), SNDRV_RAWMIDI_IOCTL_PARAMS32 = _IOWR('W', 0x10, struct snd_rawmidi_params32),
SNDRV_RAWMIDI_IOCTL_STATUS32 = _IOWR('W', 0x20, struct snd_rawmidi_status32), SNDRV_RAWMIDI_IOCTL_STATUS_COMPAT32 = _IOWR('W', 0x20, struct snd_rawmidi_status32),
#ifdef CONFIG_X86_X32 SNDRV_RAWMIDI_IOCTL_STATUS_COMPAT64 = _IOWR('W', 0x20, struct compat_snd_rawmidi_status64),
SNDRV_RAWMIDI_IOCTL_STATUS_X32 = _IOWR('W', 0x20, struct snd_rawmidi_status_x32),
#endif /* CONFIG_X86_X32 */
}; };
static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
...@@ -153,12 +112,10 @@ static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsign ...@@ -153,12 +112,10 @@ static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsign
return snd_rawmidi_ioctl(file, cmd, (unsigned long)argp); return snd_rawmidi_ioctl(file, cmd, (unsigned long)argp);
case SNDRV_RAWMIDI_IOCTL_PARAMS32: case SNDRV_RAWMIDI_IOCTL_PARAMS32:
return snd_rawmidi_ioctl_params_compat(rfile, argp); return snd_rawmidi_ioctl_params_compat(rfile, argp);
case SNDRV_RAWMIDI_IOCTL_STATUS32: case SNDRV_RAWMIDI_IOCTL_STATUS_COMPAT32:
return snd_rawmidi_ioctl_status_compat(rfile, argp); return snd_rawmidi_ioctl_status32(rfile, argp);
#ifdef CONFIG_X86_X32 case SNDRV_RAWMIDI_IOCTL_STATUS_COMPAT64:
case SNDRV_RAWMIDI_IOCTL_STATUS_X32: return snd_rawmidi_ioctl_status_compat64(rfile, argp);
return snd_rawmidi_ioctl_status_x32(rfile, argp);
#endif /* CONFIG_X86_X32 */
} }
return -ENOIOCTLCMD; return -ENOIOCTLCMD;
} }
This diff is collapsed.
...@@ -69,54 +69,11 @@ static int snd_timer_user_info_compat(struct file *file, ...@@ -69,54 +69,11 @@ static int snd_timer_user_info_compat(struct file *file,
return 0; return 0;
} }
struct snd_timer_status32 {
struct compat_timespec tstamp;
u32 resolution;
u32 lost;
u32 overrun;
u32 queue;
unsigned char reserved[64];
};
static int snd_timer_user_status_compat(struct file *file,
struct snd_timer_status32 __user *_status)
{
struct snd_timer_user *tu;
struct snd_timer_status32 status;
tu = file->private_data;
if (!tu->timeri)
return -EBADFD;
memset(&status, 0, sizeof(status));
status.tstamp.tv_sec = tu->tstamp.tv_sec;
status.tstamp.tv_nsec = tu->tstamp.tv_nsec;
status.resolution = snd_timer_resolution(tu->timeri);
status.lost = tu->timeri->lost;
status.overrun = tu->overrun;
spin_lock_irq(&tu->qlock);
status.queue = tu->qused;
spin_unlock_irq(&tu->qlock);
if (copy_to_user(_status, &status, sizeof(status)))
return -EFAULT;
return 0;
}
#ifdef CONFIG_X86_X32
/* X32 ABI has the same struct as x86-64 */
#define snd_timer_user_status_x32(file, s) \
snd_timer_user_status(file, s)
#endif /* CONFIG_X86_X32 */
/*
*/
enum { enum {
SNDRV_TIMER_IOCTL_GPARAMS32 = _IOW('T', 0x04, struct snd_timer_gparams32), SNDRV_TIMER_IOCTL_GPARAMS32 = _IOW('T', 0x04, struct snd_timer_gparams32),
SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct snd_timer_info32), SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct snd_timer_info32),
SNDRV_TIMER_IOCTL_STATUS32 = _IOW('T', 0x14, struct snd_timer_status32), SNDRV_TIMER_IOCTL_STATUS_COMPAT32 = _IOW('T', 0x14, struct snd_timer_status32),
#ifdef CONFIG_X86_X32 SNDRV_TIMER_IOCTL_STATUS_COMPAT64 = _IOW('T', 0x14, struct snd_timer_status64),
SNDRV_TIMER_IOCTL_STATUS_X32 = _IOW('T', 0x14, struct snd_timer_status),
#endif /* CONFIG_X86_X32 */
}; };
static long __snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, static long __snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd,
...@@ -126,7 +83,8 @@ static long __snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, ...@@ -126,7 +83,8 @@ static long __snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd,
switch (cmd) { switch (cmd) {
case SNDRV_TIMER_IOCTL_PVERSION: case SNDRV_TIMER_IOCTL_PVERSION:
case SNDRV_TIMER_IOCTL_TREAD: case SNDRV_TIMER_IOCTL_TREAD_OLD:
case SNDRV_TIMER_IOCTL_TREAD64:
case SNDRV_TIMER_IOCTL_GINFO: case SNDRV_TIMER_IOCTL_GINFO:
case SNDRV_TIMER_IOCTL_GSTATUS: case SNDRV_TIMER_IOCTL_GSTATUS:
case SNDRV_TIMER_IOCTL_SELECT: case SNDRV_TIMER_IOCTL_SELECT:
...@@ -140,17 +98,15 @@ static long __snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, ...@@ -140,17 +98,15 @@ static long __snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd,
case SNDRV_TIMER_IOCTL_PAUSE: case SNDRV_TIMER_IOCTL_PAUSE:
case SNDRV_TIMER_IOCTL_PAUSE_OLD: case SNDRV_TIMER_IOCTL_PAUSE_OLD:
case SNDRV_TIMER_IOCTL_NEXT_DEVICE: case SNDRV_TIMER_IOCTL_NEXT_DEVICE:
return __snd_timer_user_ioctl(file, cmd, (unsigned long)argp); return __snd_timer_user_ioctl(file, cmd, (unsigned long)argp, true);
case SNDRV_TIMER_IOCTL_GPARAMS32: case SNDRV_TIMER_IOCTL_GPARAMS32:
return snd_timer_user_gparams_compat(file, argp); return snd_timer_user_gparams_compat(file, argp);
case SNDRV_TIMER_IOCTL_INFO32: case SNDRV_TIMER_IOCTL_INFO32:
return snd_timer_user_info_compat(file, argp); return snd_timer_user_info_compat(file, argp);
case SNDRV_TIMER_IOCTL_STATUS32: case SNDRV_TIMER_IOCTL_STATUS_COMPAT32:
return snd_timer_user_status_compat(file, argp); return snd_timer_user_status32(file, argp);
#ifdef CONFIG_X86_X32 case SNDRV_TIMER_IOCTL_STATUS_COMPAT64:
case SNDRV_TIMER_IOCTL_STATUS_X32: return snd_timer_user_status64(file, argp);
return snd_timer_user_status_x32(file, argp);
#endif /* CONFIG_X86_X32 */
} }
return -ENOIOCTLCMD; return -ENOIOCTLCMD;
} }
......
...@@ -804,7 +804,7 @@ static void loopback_snd_timer_tasklet(unsigned long arg) ...@@ -804,7 +804,7 @@ static void loopback_snd_timer_tasklet(unsigned long arg)
static void loopback_snd_timer_event(struct snd_timer_instance *timeri, static void loopback_snd_timer_event(struct snd_timer_instance *timeri,
int event, int event,
struct timespec *tstamp, struct timespec64 *tstamp,
unsigned long resolution) unsigned long resolution)
{ {
/* Do not lock cable->lock here because timer->lock is already hold. /* Do not lock cable->lock here because timer->lock is already hold.
......
...@@ -487,7 +487,7 @@ static inline bool is_link_time_supported(struct snd_pcm_runtime *runtime, ...@@ -487,7 +487,7 @@ static inline bool is_link_time_supported(struct snd_pcm_runtime *runtime,
} }
static int azx_get_time_info(struct snd_pcm_substream *substream, static int azx_get_time_info(struct snd_pcm_substream *substream,
struct timespec *system_ts, struct timespec *audio_ts, struct timespec64 *system_ts, struct timespec64 *audio_ts,
struct snd_pcm_audio_tstamp_config *audio_tstamp_config, struct snd_pcm_audio_tstamp_config *audio_tstamp_config,
struct snd_pcm_audio_tstamp_report *audio_tstamp_report) struct snd_pcm_audio_tstamp_report *audio_tstamp_report)
{ {
...@@ -507,7 +507,7 @@ static int azx_get_time_info(struct snd_pcm_substream *substream, ...@@ -507,7 +507,7 @@ static int azx_get_time_info(struct snd_pcm_substream *substream,
if (audio_tstamp_config->report_delay) if (audio_tstamp_config->report_delay)
nsec = azx_adjust_codec_delay(substream, nsec); nsec = azx_adjust_codec_delay(substream, nsec);
*audio_ts = ns_to_timespec(nsec); *audio_ts = ns_to_timespec64(nsec);
audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK; audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK;
audio_tstamp_report->accuracy_report = 1; /* rest of structure is valid */ audio_tstamp_report->accuracy_report = 1; /* rest of structure is valid */
...@@ -524,16 +524,16 @@ static int azx_get_time_info(struct snd_pcm_substream *substream, ...@@ -524,16 +524,16 @@ static int azx_get_time_info(struct snd_pcm_substream *substream,
return -EINVAL; return -EINVAL;
case SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW: case SNDRV_PCM_TSTAMP_TYPE_MONOTONIC_RAW:
*system_ts = ktime_to_timespec(xtstamp.sys_monoraw); *system_ts = ktime_to_timespec64(xtstamp.sys_monoraw);
break; break;
default: default:
*system_ts = ktime_to_timespec(xtstamp.sys_realtime); *system_ts = ktime_to_timespec64(xtstamp.sys_realtime);
break; break;
} }
*audio_ts = ktime_to_timespec(xtstamp.device); *audio_ts = ktime_to_timespec64(xtstamp.device);
audio_tstamp_report->actual_type = audio_tstamp_report->actual_type =
SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED; SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED;
......
...@@ -1258,7 +1258,7 @@ static u64 skl_adjust_codec_delay(struct snd_pcm_substream *substream, ...@@ -1258,7 +1258,7 @@ static u64 skl_adjust_codec_delay(struct snd_pcm_substream *substream,
static int skl_platform_soc_get_time_info( static int skl_platform_soc_get_time_info(
struct snd_soc_component *component, struct snd_soc_component *component,
struct snd_pcm_substream *substream, struct snd_pcm_substream *substream,
struct timespec *system_ts, struct timespec *audio_ts, struct timespec64 *system_ts, struct timespec64 *audio_ts,
struct snd_pcm_audio_tstamp_config *audio_tstamp_config, struct snd_pcm_audio_tstamp_config *audio_tstamp_config,
struct snd_pcm_audio_tstamp_report *audio_tstamp_report) struct snd_pcm_audio_tstamp_report *audio_tstamp_report)
{ {
...@@ -1276,7 +1276,7 @@ static int skl_platform_soc_get_time_info( ...@@ -1276,7 +1276,7 @@ static int skl_platform_soc_get_time_info(
if (audio_tstamp_config->report_delay) if (audio_tstamp_config->report_delay)
nsec = skl_adjust_codec_delay(substream, nsec); nsec = skl_adjust_codec_delay(substream, nsec);
*audio_ts = ns_to_timespec(nsec); *audio_ts = ns_to_timespec64(nsec);
audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK; audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK;
audio_tstamp_report->accuracy_report = 1; /* rest of struct is valid */ audio_tstamp_report->accuracy_report = 1; /* rest of struct is valid */
......
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