diff options
Diffstat (limited to 'sound/core/pcm_compat.c')
| -rw-r--r-- | sound/core/pcm_compat.c | 471 |
1 files changed, 186 insertions, 285 deletions
diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index 946ab080ac00..54eb9bd8eb21 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c @@ -1,21 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * 32bit -> 64bit ioctl wrapper for PCM API * Copyright (c) by Takashi Iwai <tiwai@suse.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ /* This file included from pcm_native.c */ @@ -97,19 +83,6 @@ struct snd_pcm_sw_params32 { unsigned char reserved[56]; }; -/* recalcuate the boundary within 32bit */ -static snd_pcm_uframes_t recalculate_boundary(struct snd_pcm_runtime *runtime) -{ - snd_pcm_uframes_t boundary; - - if (! runtime->buffer_size) - return 0; - boundary = runtime->buffer_size; - while (boundary * 2 <= 0x7fffffffUL - runtime->buffer_size) - boundary *= 2; - return boundary; -} - static int snd_pcm_ioctl_sw_params_compat(struct snd_pcm_substream *substream, struct snd_pcm_sw_params32 __user *src) { @@ -174,105 +147,47 @@ static int snd_pcm_ioctl_channel_info_compat(struct snd_pcm_substream *substream return err; } -#ifdef CONFIG_X86_X32 +#ifdef CONFIG_X86_X32_ABI /* X32 ABI has the same struct as x86-64 for snd_pcm_channel_info */ static int snd_pcm_channel_info_user(struct snd_pcm_substream *substream, struct snd_pcm_channel_info __user *src); #define snd_pcm_ioctl_channel_info_x32(s, p) \ snd_pcm_channel_info_user(s, p) -#endif /* CONFIG_X86_X32 */ - -struct snd_pcm_status32 { - s32 state; - struct compat_timespec trigger_tstamp; - struct compat_timespec tstamp; +#endif /* CONFIG_X86_X32_ABI */ + +struct compat_snd_pcm_status64 { + snd_pcm_state_t state; + u8 rsvd[4]; /* alignment */ + 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; + snd_pcm_state_t suspended_state; u32 audio_tstamp_data; - struct compat_timespec audio_tstamp; - struct compat_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 compat_timespec)]; -} __attribute__((packed)); - - -static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream, - struct snd_pcm_status32 __user *src, - bool ext) -{ - struct snd_pcm_status status; - int err; - - 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 *)(&src->audio_tstamp_data))) - return -EFAULT; - err = snd_pcm_status(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)) - return -EFAULT; - - return err; -} - -#ifdef CONFIG_X86_X32 -/* X32 ABI has 64bit timespec and 64bit alignment */ -struct snd_pcm_status_x32 { - s32 state; - u32 rsvd; /* alignment */ - struct timespec trigger_tstamp; - struct timespec tstamp; - u32 appl_ptr; - u32 hw_ptr; - s32 delay; - u32 avail; - u32 avail_max; - u32 overrange; - s32 suspended_state; - u32 audio_tstamp_data; - struct timespec audio_tstamp; - struct timespec driver_tstamp; - 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, @@ -281,42 +196,51 @@ 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 */ /* both for HW_PARAMS and HW_REFINE */ static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream, int refine, struct snd_pcm_hw_params32 __user *data32) { - struct snd_pcm_hw_params *data; + struct snd_pcm_hw_params *data __free(kfree) = NULL; struct snd_pcm_runtime *runtime; int err; - if (! (runtime = substream->runtime)) + runtime = substream->runtime; + if (!runtime) return -ENOTTY; data = kmalloc(sizeof(*data), GFP_KERNEL); @@ -324,30 +248,28 @@ static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream, return -ENOMEM; /* only fifo_size (RO from userspace) is different, so just copy all */ - if (copy_from_user(data, data32, sizeof(*data32))) { - err = -EFAULT; - goto error; - } + if (copy_from_user(data, data32, sizeof(*data32))) + return -EFAULT; - if (refine) + if (refine) { err = snd_pcm_hw_refine(substream, data); - else + if (err < 0) + return err; + err = fixup_unreferenced_params(substream, data); + } else { err = snd_pcm_hw_params(substream, data); + } if (err < 0) - goto error; + return err; if (copy_to_user(data32, data, sizeof(*data32)) || - put_user(data->fifo_size, &data32->fifo_size)) { - err = -EFAULT; - goto error; - } + put_user(data->fifo_size, &data32->fifo_size)) + return -EFAULT; if (! refine) { unsigned int new_boundary = recalculate_boundary(runtime); if (new_boundary) runtime->boundary = new_boundary; } - error: - kfree(data); return err; } @@ -371,7 +293,7 @@ static int snd_pcm_ioctl_xferi_compat(struct snd_pcm_substream *substream, return -ENOTTY; if (substream->stream != dir) return -EINVAL; - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) + if (substream->runtime->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; if (get_user(buf, &data32->buf) || @@ -410,17 +332,18 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream, compat_caddr_t buf; compat_caddr_t __user *bufptr; u32 frames; - void __user **bufs; + void __user **bufs __free(kfree) = NULL; int err, ch, i; if (! substream->runtime) return -ENOTTY; if (substream->stream != dir) return -EINVAL; - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) + if (substream->runtime->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; - if ((ch = substream->runtime->channels) > 128) + ch = substream->runtime->channels; + if (ch > 128) return -EINVAL; if (get_user(buf, &data32->bufs) || get_user(frames, &data32->frames)) @@ -431,10 +354,8 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream, return -ENOMEM; for (i = 0; i < ch; i++) { u32 ptr; - if (get_user(ptr, bufptr)) { - kfree(bufs); + if (get_user(ptr, bufptr)) return -EFAULT; - } bufs[i] = compat_ptr(ptr); bufptr++; } @@ -444,41 +365,44 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream, err = snd_pcm_lib_readv(substream, bufs, frames); if (err >= 0) { if (put_user(err, &data32->result)) - err = -EFAULT; + return -EFAULT; } - kfree(bufs); return err; } - -struct snd_pcm_mmap_status32 { - s32 state; +#ifdef CONFIG_X86_X32_ABI +/* X32 ABI has 64bit timespec and 64bit alignment */ +struct snd_pcm_mmap_status_x32 { + snd_pcm_state_t state; s32 pad1; u32 hw_ptr; - struct compat_timespec tstamp; - s32 suspended_state; - struct compat_timespec audio_tstamp; -} __attribute__((packed)); + u32 pad2; /* alignment */ + struct __snd_timespec64 tstamp; + snd_pcm_state_t suspended_state; + s32 pad3; + struct __snd_timespec64 audio_tstamp; +} __packed; -struct snd_pcm_mmap_control32 { +struct snd_pcm_mmap_control_x32 { u32 appl_ptr; u32 avail_min; }; -struct snd_pcm_sync_ptr32 { +struct snd_pcm_sync_ptr_x32 { u32 flags; + u32 rsvd; /* alignment */ union { - struct snd_pcm_mmap_status32 status; + struct snd_pcm_mmap_status_x32 status; unsigned char reserved[64]; } s; union { - struct snd_pcm_mmap_control32 control; + struct snd_pcm_mmap_control_x32 control; unsigned char reserved[64]; } c; -} __attribute__((packed)); +} __packed; -static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream, - struct snd_pcm_sync_ptr32 __user *src) +static int snd_pcm_ioctl_sync_ptr_x32(struct snd_pcm_substream *substream, + struct snd_pcm_sync_ptr_x32 __user *src) { struct snd_pcm_runtime *runtime = substream->runtime; volatile struct snd_pcm_mmap_status *status; @@ -492,9 +416,7 @@ static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream, if (snd_BUG_ON(!runtime)) return -EINVAL; - if (get_user(sflags, &src->flags) || - get_user(scontrol.appl_ptr, &src->c.control.appl_ptr) || - get_user(scontrol.avail_min, &src->c.control.avail_min)) + if (snd_pcm_sync_ptr_get_user(sflags, scontrol, src)) return -EFAULT; if (sflags & SNDRV_PCM_SYNC_PTR_HWSYNC) { err = snd_pcm_hwsync(substream); @@ -504,125 +426,102 @@ static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream, status = runtime->status; control = runtime->control; boundary = recalculate_boundary(runtime); - if (! boundary) + if (!boundary) boundary = 0x7fffffff; - snd_pcm_stream_lock_irq(substream); - /* FIXME: we should consider the boundary for the sync from app */ + scoped_guard(pcm_stream_lock_irq, substream) { + /* FIXME: we should consider the boundary for the sync from app */ + if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) + control->appl_ptr = scontrol.appl_ptr; + else + scontrol.appl_ptr = control->appl_ptr % boundary; + if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) + control->avail_min = scontrol.avail_min; + else + scontrol.avail_min = control->avail_min; + sstatus.state = status->state; + sstatus.hw_ptr = status->hw_ptr % boundary; + sstatus.tstamp = status->tstamp; + sstatus.suspended_state = status->suspended_state; + sstatus.audio_tstamp = status->audio_tstamp; + } if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) - control->appl_ptr = scontrol.appl_ptr; - else - scontrol.appl_ptr = control->appl_ptr % boundary; - if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) - control->avail_min = scontrol.avail_min; - else - scontrol.avail_min = control->avail_min; - sstatus.state = status->state; - sstatus.hw_ptr = status->hw_ptr % boundary; - sstatus.tstamp = status->tstamp; - sstatus.suspended_state = status->suspended_state; - sstatus.audio_tstamp = status->audio_tstamp; - snd_pcm_stream_unlock_irq(substream); - if (put_user(sstatus.state, &src->s.status.state) || - put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) || - compat_put_timespec(&sstatus.tstamp, &src->s.status.tstamp) || - put_user(sstatus.suspended_state, &src->s.status.suspended_state) || - compat_put_timespec(&sstatus.audio_tstamp, - &src->s.status.audio_tstamp) || - put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) || - put_user(scontrol.avail_min, &src->c.control.avail_min)) + snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE); + if (snd_pcm_sync_ptr_put_user(sstatus, scontrol, src)) return -EFAULT; return 0; } - -#ifdef CONFIG_X86_X32 -/* X32 ABI has 64bit timespec and 64bit alignment */ -struct snd_pcm_mmap_status_x32 { - s32 state; - s32 pad1; - u32 hw_ptr; - u32 pad2; /* alignment */ - struct timespec tstamp; - s32 suspended_state; - s32 pad3; - struct timespec audio_tstamp; -} __packed; - -struct snd_pcm_mmap_control_x32 { - u32 appl_ptr; - u32 avail_min; +#endif /* CONFIG_X86_X32_ABI */ + +#ifdef __BIG_ENDIAN +typedef char __pad_before_u32[4]; +typedef char __pad_after_u32[0]; +#else +typedef char __pad_before_u32[0]; +typedef char __pad_after_u32[4]; +#endif + +/* PCM 2.0.15 API definition had a bug in mmap control; it puts the avail_min + * at the wrong offset due to a typo in padding type. + * The bug hits only 32bit. + * A workaround for incorrect read/write is needed only in 32bit compat mode. + */ +struct __snd_pcm_mmap_control64_buggy { + __pad_before_u32 __pad1; + __u32 appl_ptr; + __pad_before_u32 __pad2; /* SiC! here is the bug */ + __pad_before_u32 __pad3; + __u32 avail_min; + __pad_after_uframe __pad4; }; -struct snd_pcm_sync_ptr_x32 { - u32 flags; - u32 rsvd; /* alignment */ - union { - struct snd_pcm_mmap_status_x32 status; - unsigned char reserved[64]; - } s; - union { - struct snd_pcm_mmap_control_x32 control; - unsigned char reserved[64]; - } c; -} __packed; - -static int snd_pcm_ioctl_sync_ptr_x32(struct snd_pcm_substream *substream, - struct snd_pcm_sync_ptr_x32 __user *src) +static int snd_pcm_ioctl_sync_ptr_buggy(struct snd_pcm_substream *substream, + struct snd_pcm_sync_ptr __user *_sync_ptr) { struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_pcm_sync_ptr sync_ptr; + struct __snd_pcm_mmap_control64_buggy *sync_cp; volatile struct snd_pcm_mmap_status *status; volatile struct snd_pcm_mmap_control *control; - u32 sflags; - struct snd_pcm_mmap_control scontrol; - struct snd_pcm_mmap_status sstatus; - snd_pcm_uframes_t boundary; int err; - if (snd_BUG_ON(!runtime)) - return -EINVAL; - - if (get_user(sflags, &src->flags) || - get_user(scontrol.appl_ptr, &src->c.control.appl_ptr) || - get_user(scontrol.avail_min, &src->c.control.avail_min)) + memset(&sync_ptr, 0, sizeof(sync_ptr)); + sync_cp = (struct __snd_pcm_mmap_control64_buggy *)&sync_ptr.c.control; + if (get_user(sync_ptr.flags, (unsigned __user *)&(_sync_ptr->flags))) return -EFAULT; - if (sflags & SNDRV_PCM_SYNC_PTR_HWSYNC) { + if (copy_from_user(sync_cp, &(_sync_ptr->c.control), sizeof(*sync_cp))) + return -EFAULT; + status = runtime->status; + control = runtime->control; + if (sync_ptr.flags & SNDRV_PCM_SYNC_PTR_HWSYNC) { err = snd_pcm_hwsync(substream); if (err < 0) return err; } - status = runtime->status; - control = runtime->control; - boundary = recalculate_boundary(runtime); - if (!boundary) - boundary = 0x7fffffff; - snd_pcm_stream_lock_irq(substream); - /* FIXME: we should consider the boundary for the sync from app */ - if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) - control->appl_ptr = scontrol.appl_ptr; - else - scontrol.appl_ptr = control->appl_ptr % boundary; - if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) - control->avail_min = scontrol.avail_min; - else - scontrol.avail_min = control->avail_min; - sstatus.state = status->state; - sstatus.hw_ptr = status->hw_ptr % boundary; - sstatus.tstamp = status->tstamp; - sstatus.suspended_state = status->suspended_state; - sstatus.audio_tstamp = status->audio_tstamp; - snd_pcm_stream_unlock_irq(substream); - if (put_user(sstatus.state, &src->s.status.state) || - put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) || - put_timespec(&sstatus.tstamp, &src->s.status.tstamp) || - put_user(sstatus.suspended_state, &src->s.status.suspended_state) || - put_timespec(&sstatus.audio_tstamp, &src->s.status.audio_tstamp) || - put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) || - put_user(scontrol.avail_min, &src->c.control.avail_min)) + scoped_guard(pcm_stream_lock_irq, substream) { + if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) { + err = pcm_lib_apply_appl_ptr(substream, sync_cp->appl_ptr); + if (err < 0) + return err; + } else { + sync_cp->appl_ptr = control->appl_ptr; + } + if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) + control->avail_min = sync_cp->avail_min; + else + sync_cp->avail_min = control->avail_min; + sync_ptr.s.status.state = status->state; + sync_ptr.s.status.hw_ptr = status->hw_ptr; + sync_ptr.s.status.tstamp = status->tstamp; + sync_ptr.s.status.suspended_state = status->suspended_state; + sync_ptr.s.status.audio_tstamp = status->audio_tstamp; + } + if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) + snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE); + if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr))) return -EFAULT; - return 0; } -#endif /* CONFIG_X86_X32 */ /* */ @@ -630,8 +529,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 snd_pcm_status32), + SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT32 = _IOWR('A', 0x24, struct 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), @@ -640,13 +539,12 @@ enum { SNDRV_PCM_IOCTL_READI_FRAMES32 = _IOR('A', 0x51, struct snd_xferi32), 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), -#ifdef CONFIG_X86_X32 + 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 CONFIG_X86_X32_ABI 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 */ +#endif /* CONFIG_X86_X32_ABI */ }; static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) @@ -664,8 +562,8 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l /* * When PCM is used on 32bit mode, we need to disable - * mmap of PCM status/control records because of the size - * incompatibility. + * mmap of the old PCM status/control records because + * of the size incompatibility. */ pcm_file->no_compat_mmap = 1; @@ -687,19 +585,24 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l case SNDRV_PCM_IOCTL_XRUN: case SNDRV_PCM_IOCTL_LINK: case SNDRV_PCM_IOCTL_UNLINK: + case __SNDRV_PCM_IOCTL_SYNC_PTR32: return snd_pcm_common_ioctl(file, substream, cmd, argp); + case __SNDRV_PCM_IOCTL_SYNC_PTR64: +#ifdef CONFIG_X86_X32_ABI + if (in_x32_syscall()) + return snd_pcm_ioctl_sync_ptr_x32(substream, argp); +#endif /* CONFIG_X86_X32_ABI */ + return snd_pcm_ioctl_sync_ptr_buggy(substream, argp); case SNDRV_PCM_IOCTL_HW_REFINE32: return snd_pcm_ioctl_hw_params_compat(substream, 1, argp); case SNDRV_PCM_IOCTL_HW_PARAMS32: 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: - return snd_pcm_status_user_compat(substream, argp, false); - case SNDRV_PCM_IOCTL_STATUS_EXT32: - return snd_pcm_status_user_compat(substream, argp, true); - case SNDRV_PCM_IOCTL_SYNC_PTR32: - return snd_pcm_ioctl_sync_ptr_compat(substream, argp); + case SNDRV_PCM_IOCTL_STATUS_COMPAT32: + return snd_pcm_status_user32(substream, argp, false); + case SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT32: + return snd_pcm_status_user32(substream, argp, true); case SNDRV_PCM_IOCTL_CHANNEL_INFO32: return snd_pcm_ioctl_channel_info_compat(substream, argp); case SNDRV_PCM_IOCTL_WRITEI_FRAMES32: @@ -716,16 +619,14 @@ 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); -#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_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 CONFIG_X86_X32_ABI case SNDRV_PCM_IOCTL_CHANNEL_INFO_X32: return snd_pcm_ioctl_channel_info_x32(substream, argp); -#endif /* CONFIG_X86_X32 */ +#endif /* CONFIG_X86_X32_ABI */ } return -ENOIOCTLCMD; |
