linux/sound/core/pcm_compat.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *   32bit -> 64bit ioctl wrapper for PCM API
   4 *   Copyright (c) by Takashi Iwai <tiwai@suse.de>
   5 */
   6
   7/* This file included from pcm_native.c */
   8
   9#include <linux/compat.h>
  10#include <linux/slab.h>
  11
  12static int snd_pcm_ioctl_delay_compat(struct snd_pcm_substream *substream,
  13                                      s32 __user *src)
  14{
  15        snd_pcm_sframes_t delay;
  16        int err;
  17
  18        err = snd_pcm_delay(substream, &delay);
  19        if (err)
  20                return err;
  21        if (put_user(delay, src))
  22                return -EFAULT;
  23        return 0;
  24}
  25
  26static int snd_pcm_ioctl_rewind_compat(struct snd_pcm_substream *substream,
  27                                       u32 __user *src)
  28{
  29        snd_pcm_uframes_t frames;
  30        int err;
  31
  32        if (get_user(frames, src))
  33                return -EFAULT;
  34        err = snd_pcm_rewind(substream, frames);
  35        if (put_user(err, src))
  36                return -EFAULT;
  37        return err < 0 ? err : 0;
  38}
  39
  40static int snd_pcm_ioctl_forward_compat(struct snd_pcm_substream *substream,
  41                                       u32 __user *src)
  42{
  43        snd_pcm_uframes_t frames;
  44        int err;
  45
  46        if (get_user(frames, src))
  47                return -EFAULT;
  48        err = snd_pcm_forward(substream, frames);
  49        if (put_user(err, src))
  50                return -EFAULT;
  51        return err < 0 ? err : 0;
  52}
  53
  54struct snd_pcm_hw_params32 {
  55        u32 flags;
  56        struct snd_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK - SNDRV_PCM_HW_PARAM_FIRST_MASK + 1]; /* this must be identical */
  57        struct snd_mask mres[5];        /* reserved masks */
  58        struct snd_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1];
  59        struct snd_interval ires[9];    /* reserved intervals */
  60        u32 rmask;
  61        u32 cmask;
  62        u32 info;
  63        u32 msbits;
  64        u32 rate_num;
  65        u32 rate_den;
  66        u32 fifo_size;
  67        unsigned char reserved[64];
  68};
  69
  70struct snd_pcm_sw_params32 {
  71        s32 tstamp_mode;
  72        u32 period_step;
  73        u32 sleep_min;
  74        u32 avail_min;
  75        u32 xfer_align;
  76        u32 start_threshold;
  77        u32 stop_threshold;
  78        u32 silence_threshold;
  79        u32 silence_size;
  80        u32 boundary;
  81        u32 proto;
  82        u32 tstamp_type;
  83        unsigned char reserved[56];
  84};
  85
  86static int snd_pcm_ioctl_sw_params_compat(struct snd_pcm_substream *substream,
  87                                          struct snd_pcm_sw_params32 __user *src)
  88{
  89        struct snd_pcm_sw_params params;
  90        snd_pcm_uframes_t boundary;
  91        int err;
  92
  93        memset(&params, 0, sizeof(params));
  94        if (get_user(params.tstamp_mode, &src->tstamp_mode) ||
  95            get_user(params.period_step, &src->period_step) ||
  96            get_user(params.sleep_min, &src->sleep_min) ||
  97            get_user(params.avail_min, &src->avail_min) ||
  98            get_user(params.xfer_align, &src->xfer_align) ||
  99            get_user(params.start_threshold, &src->start_threshold) ||
 100            get_user(params.stop_threshold, &src->stop_threshold) ||
 101            get_user(params.silence_threshold, &src->silence_threshold) ||
 102            get_user(params.silence_size, &src->silence_size) ||
 103            get_user(params.tstamp_type, &src->tstamp_type) ||
 104            get_user(params.proto, &src->proto))
 105                return -EFAULT;
 106        /*
 107         * Check silent_size parameter.  Since we have 64bit boundary,
 108         * silence_size must be compared with the 32bit boundary.
 109         */
 110        boundary = recalculate_boundary(substream->runtime);
 111        if (boundary && params.silence_size >= boundary)
 112                params.silence_size = substream->runtime->boundary;
 113        err = snd_pcm_sw_params(substream, &params);
 114        if (err < 0)
 115                return err;
 116        if (boundary && put_user(boundary, &src->boundary))
 117                return -EFAULT;
 118        return err;
 119}
 120
 121struct snd_pcm_channel_info32 {
 122        u32 channel;
 123        u32 offset;
 124        u32 first;
 125        u32 step;
 126};
 127
 128static int snd_pcm_ioctl_channel_info_compat(struct snd_pcm_substream *substream,
 129                                             struct snd_pcm_channel_info32 __user *src)
 130{
 131        struct snd_pcm_channel_info info;
 132        int err;
 133
 134        if (get_user(info.channel, &src->channel) ||
 135            get_user(info.offset, &src->offset) ||
 136            get_user(info.first, &src->first) ||
 137            get_user(info.step, &src->step))
 138                return -EFAULT;
 139        err = snd_pcm_channel_info(substream, &info);
 140        if (err < 0)
 141                return err;
 142        if (put_user(info.channel, &src->channel) ||
 143            put_user(info.offset, &src->offset) ||
 144            put_user(info.first, &src->first) ||
 145            put_user(info.step, &src->step))
 146                return -EFAULT;
 147        return err;
 148}
 149
 150#ifdef CONFIG_X86_X32
 151/* X32 ABI has the same struct as x86-64 for snd_pcm_channel_info */
 152static int snd_pcm_channel_info_user(struct snd_pcm_substream *substream,
 153                                     struct snd_pcm_channel_info __user *src);
 154#define snd_pcm_ioctl_channel_info_x32(s, p)    \
 155        snd_pcm_channel_info_user(s, p)
 156#endif /* CONFIG_X86_X32 */
 157
 158struct compat_snd_pcm_status64 {
 159        snd_pcm_state_t state;
 160        u8 rsvd[4]; /* alignment */
 161        s64 trigger_tstamp_sec;
 162        s64 trigger_tstamp_nsec;
 163        s64 tstamp_sec;
 164        s64 tstamp_nsec;
 165        u32 appl_ptr;
 166        u32 hw_ptr;
 167        s32 delay;
 168        u32 avail;
 169        u32 avail_max;
 170        u32 overrange;
 171        snd_pcm_state_t suspended_state;
 172        u32 audio_tstamp_data;
 173        s64 audio_tstamp_sec;
 174        s64 audio_tstamp_nsec;
 175        s64 driver_tstamp_sec;
 176        s64 driver_tstamp_nsec;
 177        u32 audio_tstamp_accuracy;
 178        unsigned char reserved[52-4*sizeof(s64)];
 179} __packed;
 180
 181static int snd_pcm_status_user_compat64(struct snd_pcm_substream *substream,
 182                                        struct compat_snd_pcm_status64 __user *src,
 183                                        bool ext)
 184{
 185        struct snd_pcm_status64 status;
 186        struct compat_snd_pcm_status64 compat_status64;
 187        int err;
 188
 189        memset(&status, 0, sizeof(status));
 190        memset(&compat_status64, 0, sizeof(compat_status64));
 191        /*
 192         * with extension, parameters are read/write,
 193         * get audio_tstamp_data from user,
 194         * ignore rest of status structure
 195         */
 196        if (ext && get_user(status.audio_tstamp_data,
 197                                (u32 __user *)(&src->audio_tstamp_data)))
 198                return -EFAULT;
 199        err = snd_pcm_status64(substream, &status);
 200        if (err < 0)
 201                return err;
 202
 203        if (clear_user(src, sizeof(*src)))
 204                return -EFAULT;
 205
 206        compat_status64 = (struct compat_snd_pcm_status64) {
 207                .state = status.state,
 208                .trigger_tstamp_sec = status.trigger_tstamp_sec,
 209                .trigger_tstamp_nsec = status.trigger_tstamp_nsec,
 210                .tstamp_sec = status.tstamp_sec,
 211                .tstamp_nsec = status.tstamp_nsec,
 212                .appl_ptr = status.appl_ptr,
 213                .hw_ptr = status.hw_ptr,
 214                .delay = status.delay,
 215                .avail = status.avail,
 216                .avail_max = status.avail_max,
 217                .overrange = status.overrange,
 218                .suspended_state = status.suspended_state,
 219                .audio_tstamp_data = status.audio_tstamp_data,
 220                .audio_tstamp_sec = status.audio_tstamp_sec,
 221                .audio_tstamp_nsec = status.audio_tstamp_nsec,
 222                .driver_tstamp_sec = status.audio_tstamp_sec,
 223                .driver_tstamp_nsec = status.audio_tstamp_nsec,
 224                .audio_tstamp_accuracy = status.audio_tstamp_accuracy,
 225        };
 226
 227        if (copy_to_user(src, &compat_status64, sizeof(compat_status64)))
 228                return -EFAULT;
 229
 230        return err;
 231}
 232
 233/* both for HW_PARAMS and HW_REFINE */
 234static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream,
 235                                          int refine, 
 236                                          struct snd_pcm_hw_params32 __user *data32)
 237{
 238        struct snd_pcm_hw_params *data;
 239        struct snd_pcm_runtime *runtime;
 240        int err;
 241
 242        runtime = substream->runtime;
 243        if (!runtime)
 244                return -ENOTTY;
 245
 246        data = kmalloc(sizeof(*data), GFP_KERNEL);
 247        if (!data)
 248                return -ENOMEM;
 249
 250        /* only fifo_size (RO from userspace) is different, so just copy all */
 251        if (copy_from_user(data, data32, sizeof(*data32))) {
 252                err = -EFAULT;
 253                goto error;
 254        }
 255
 256        if (refine)
 257                err = snd_pcm_hw_refine(substream, data);
 258        else
 259                err = snd_pcm_hw_params(substream, data);
 260        if (err < 0)
 261                goto error;
 262        if (copy_to_user(data32, data, sizeof(*data32)) ||
 263            put_user(data->fifo_size, &data32->fifo_size)) {
 264                err = -EFAULT;
 265                goto error;
 266        }
 267
 268        if (! refine) {
 269                unsigned int new_boundary = recalculate_boundary(runtime);
 270                if (new_boundary)
 271                        runtime->boundary = new_boundary;
 272        }
 273 error:
 274        kfree(data);
 275        return err;
 276}
 277
 278
 279/*
 280 */
 281struct snd_xferi32 {
 282        s32 result;
 283        u32 buf;
 284        u32 frames;
 285};
 286
 287static int snd_pcm_ioctl_xferi_compat(struct snd_pcm_substream *substream,
 288                                      int dir, struct snd_xferi32 __user *data32)
 289{
 290        compat_caddr_t buf;
 291        u32 frames;
 292        int err;
 293
 294        if (! substream->runtime)
 295                return -ENOTTY;
 296        if (substream->stream != dir)
 297                return -EINVAL;
 298        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
 299                return -EBADFD;
 300
 301        if (get_user(buf, &data32->buf) ||
 302            get_user(frames, &data32->frames))
 303                return -EFAULT;
 304
 305        if (dir == SNDRV_PCM_STREAM_PLAYBACK)
 306                err = snd_pcm_lib_write(substream, compat_ptr(buf), frames);
 307        else
 308                err = snd_pcm_lib_read(substream, compat_ptr(buf), frames);
 309        if (err < 0)
 310                return err;
 311        /* copy the result */
 312        if (put_user(err, &data32->result))
 313                return -EFAULT;
 314        return 0;
 315}
 316
 317
 318/* snd_xfern needs remapping of bufs */
 319struct snd_xfern32 {
 320        s32 result;
 321        u32 bufs;  /* this is void **; */
 322        u32 frames;
 323};
 324
 325/*
 326 * xfern ioctl nees to copy (up to) 128 pointers on stack.
 327 * although we may pass the copied pointers through f_op->ioctl, but the ioctl
 328 * handler there expands again the same 128 pointers on stack, so it is better
 329 * to handle the function (calling pcm_readv/writev) directly in this handler.
 330 */
 331static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream,
 332                                      int dir, struct snd_xfern32 __user *data32)
 333{
 334        compat_caddr_t buf;
 335        compat_caddr_t __user *bufptr;
 336        u32 frames;
 337        void __user **bufs;
 338        int err, ch, i;
 339
 340        if (! substream->runtime)
 341                return -ENOTTY;
 342        if (substream->stream != dir)
 343                return -EINVAL;
 344        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
 345                return -EBADFD;
 346
 347        ch = substream->runtime->channels;
 348        if (ch > 128)
 349                return -EINVAL;
 350        if (get_user(buf, &data32->bufs) ||
 351            get_user(frames, &data32->frames))
 352                return -EFAULT;
 353        bufptr = compat_ptr(buf);
 354        bufs = kmalloc_array(ch, sizeof(void __user *), GFP_KERNEL);
 355        if (bufs == NULL)
 356                return -ENOMEM;
 357        for (i = 0; i < ch; i++) {
 358                u32 ptr;
 359                if (get_user(ptr, bufptr)) {
 360                        kfree(bufs);
 361                        return -EFAULT;
 362                }
 363                bufs[i] = compat_ptr(ptr);
 364                bufptr++;
 365        }
 366        if (dir == SNDRV_PCM_STREAM_PLAYBACK)
 367                err = snd_pcm_lib_writev(substream, bufs, frames);
 368        else
 369                err = snd_pcm_lib_readv(substream, bufs, frames);
 370        if (err >= 0) {
 371                if (put_user(err, &data32->result))
 372                        err = -EFAULT;
 373        }
 374        kfree(bufs);
 375        return err;
 376}
 377
 378#ifdef CONFIG_X86_X32
 379/* X32 ABI has 64bit timespec and 64bit alignment */
 380struct snd_pcm_mmap_status_x32 {
 381        snd_pcm_state_t state;
 382        s32 pad1;
 383        u32 hw_ptr;
 384        u32 pad2; /* alignment */
 385        s64 tstamp_sec;
 386        s64 tstamp_nsec;
 387        snd_pcm_state_t suspended_state;
 388        s32 pad3;
 389        s64 audio_tstamp_sec;
 390        s64 audio_tstamp_nsec;
 391} __packed;
 392
 393struct snd_pcm_mmap_control_x32 {
 394        u32 appl_ptr;
 395        u32 avail_min;
 396};
 397
 398struct snd_pcm_sync_ptr_x32 {
 399        u32 flags;
 400        u32 rsvd; /* alignment */
 401        union {
 402                struct snd_pcm_mmap_status_x32 status;
 403                unsigned char reserved[64];
 404        } s;
 405        union {
 406                struct snd_pcm_mmap_control_x32 control;
 407                unsigned char reserved[64];
 408        } c;
 409} __packed;
 410
 411static int snd_pcm_ioctl_sync_ptr_x32(struct snd_pcm_substream *substream,
 412                                      struct snd_pcm_sync_ptr_x32 __user *src)
 413{
 414        struct snd_pcm_runtime *runtime = substream->runtime;
 415        volatile struct snd_pcm_mmap_status *status;
 416        volatile struct snd_pcm_mmap_control *control;
 417        u32 sflags;
 418        struct snd_pcm_mmap_control scontrol;
 419        struct snd_pcm_mmap_status sstatus;
 420        snd_pcm_uframes_t boundary;
 421        int err;
 422
 423        if (snd_BUG_ON(!runtime))
 424                return -EINVAL;
 425
 426        if (get_user(sflags, &src->flags) ||
 427            get_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
 428            get_user(scontrol.avail_min, &src->c.control.avail_min))
 429                return -EFAULT;
 430        if (sflags & SNDRV_PCM_SYNC_PTR_HWSYNC) {
 431                err = snd_pcm_hwsync(substream);
 432                if (err < 0)
 433                        return err;
 434        }
 435        status = runtime->status;
 436        control = runtime->control;
 437        boundary = recalculate_boundary(runtime);
 438        if (!boundary)
 439                boundary = 0x7fffffff;
 440        snd_pcm_stream_lock_irq(substream);
 441        /* FIXME: we should consider the boundary for the sync from app */
 442        if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
 443                control->appl_ptr = scontrol.appl_ptr;
 444        else
 445                scontrol.appl_ptr = control->appl_ptr % boundary;
 446        if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
 447                control->avail_min = scontrol.avail_min;
 448        else
 449                scontrol.avail_min = control->avail_min;
 450        sstatus.state = status->state;
 451        sstatus.hw_ptr = status->hw_ptr % boundary;
 452        sstatus.tstamp = status->tstamp;
 453        sstatus.suspended_state = status->suspended_state;
 454        sstatus.audio_tstamp = status->audio_tstamp;
 455        snd_pcm_stream_unlock_irq(substream);
 456        if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
 457                snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
 458        if (put_user(sstatus.state, &src->s.status.state) ||
 459            put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) ||
 460            put_user(sstatus.tstamp.tv_sec, &src->s.status.tstamp_sec) ||
 461            put_user(sstatus.tstamp.tv_nsec, &src->s.status.tstamp_nsec) ||
 462            put_user(sstatus.suspended_state, &src->s.status.suspended_state) ||
 463            put_user(sstatus.audio_tstamp.tv_sec, &src->s.status.audio_tstamp_sec) ||
 464            put_user(sstatus.audio_tstamp.tv_nsec, &src->s.status.audio_tstamp_nsec) ||
 465            put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
 466            put_user(scontrol.avail_min, &src->c.control.avail_min))
 467                return -EFAULT;
 468
 469        return 0;
 470}
 471#endif /* CONFIG_X86_X32 */
 472
 473#ifdef __BIG_ENDIAN
 474typedef char __pad_before_u32[4];
 475typedef char __pad_after_u32[0];
 476#else
 477typedef char __pad_before_u32[0];
 478typedef char __pad_after_u32[4];
 479#endif
 480
 481/* PCM 2.0.15 API definition had a bug in mmap control; it puts the avail_min
 482 * at the wrong offset due to a typo in padding type.
 483 * The bug hits only 32bit.
 484 * A workaround for incorrect read/write is needed only in 32bit compat mode.
 485 */
 486struct __snd_pcm_mmap_control64_buggy {
 487        __pad_before_u32 __pad1;
 488        __u32 appl_ptr;
 489        __pad_before_u32 __pad2;        /* SiC! here is the bug */
 490        __pad_before_u32 __pad3;
 491        __u32 avail_min;
 492        __pad_after_uframe __pad4;
 493};
 494
 495static int snd_pcm_ioctl_sync_ptr_buggy(struct snd_pcm_substream *substream,
 496                                        struct snd_pcm_sync_ptr __user *_sync_ptr)
 497{
 498        struct snd_pcm_runtime *runtime = substream->runtime;
 499        struct snd_pcm_sync_ptr sync_ptr;
 500        struct __snd_pcm_mmap_control64_buggy *sync_cp;
 501        volatile struct snd_pcm_mmap_status *status;
 502        volatile struct snd_pcm_mmap_control *control;
 503        int err;
 504
 505        memset(&sync_ptr, 0, sizeof(sync_ptr));
 506        sync_cp = (struct __snd_pcm_mmap_control64_buggy *)&sync_ptr.c.control;
 507        if (get_user(sync_ptr.flags, (unsigned __user *)&(_sync_ptr->flags)))
 508                return -EFAULT;
 509        if (copy_from_user(sync_cp, &(_sync_ptr->c.control), sizeof(*sync_cp)))
 510                return -EFAULT;
 511        status = runtime->status;
 512        control = runtime->control;
 513        if (sync_ptr.flags & SNDRV_PCM_SYNC_PTR_HWSYNC) {
 514                err = snd_pcm_hwsync(substream);
 515                if (err < 0)
 516                        return err;
 517        }
 518        snd_pcm_stream_lock_irq(substream);
 519        if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) {
 520                err = pcm_lib_apply_appl_ptr(substream, sync_cp->appl_ptr);
 521                if (err < 0) {
 522                        snd_pcm_stream_unlock_irq(substream);
 523                        return err;
 524                }
 525        } else {
 526                sync_cp->appl_ptr = control->appl_ptr;
 527        }
 528        if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
 529                control->avail_min = sync_cp->avail_min;
 530        else
 531                sync_cp->avail_min = control->avail_min;
 532        sync_ptr.s.status.state = status->state;
 533        sync_ptr.s.status.hw_ptr = status->hw_ptr;
 534        sync_ptr.s.status.tstamp = status->tstamp;
 535        sync_ptr.s.status.suspended_state = status->suspended_state;
 536        sync_ptr.s.status.audio_tstamp = status->audio_tstamp;
 537        snd_pcm_stream_unlock_irq(substream);
 538        if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL))
 539                snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
 540        if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr)))
 541                return -EFAULT;
 542        return 0;
 543}
 544
 545/*
 546 */
 547enum {
 548        SNDRV_PCM_IOCTL_HW_REFINE32 = _IOWR('A', 0x10, struct snd_pcm_hw_params32),
 549        SNDRV_PCM_IOCTL_HW_PARAMS32 = _IOWR('A', 0x11, struct snd_pcm_hw_params32),
 550        SNDRV_PCM_IOCTL_SW_PARAMS32 = _IOWR('A', 0x13, struct snd_pcm_sw_params32),
 551        SNDRV_PCM_IOCTL_STATUS_COMPAT32 = _IOR('A', 0x20, struct snd_pcm_status32),
 552        SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT32 = _IOWR('A', 0x24, struct snd_pcm_status32),
 553        SNDRV_PCM_IOCTL_DELAY32 = _IOR('A', 0x21, s32),
 554        SNDRV_PCM_IOCTL_CHANNEL_INFO32 = _IOR('A', 0x32, struct snd_pcm_channel_info32),
 555        SNDRV_PCM_IOCTL_REWIND32 = _IOW('A', 0x46, u32),
 556        SNDRV_PCM_IOCTL_FORWARD32 = _IOW('A', 0x49, u32),
 557        SNDRV_PCM_IOCTL_WRITEI_FRAMES32 = _IOW('A', 0x50, struct snd_xferi32),
 558        SNDRV_PCM_IOCTL_READI_FRAMES32 = _IOR('A', 0x51, struct snd_xferi32),
 559        SNDRV_PCM_IOCTL_WRITEN_FRAMES32 = _IOW('A', 0x52, struct snd_xfern32),
 560        SNDRV_PCM_IOCTL_READN_FRAMES32 = _IOR('A', 0x53, struct snd_xfern32),
 561        SNDRV_PCM_IOCTL_STATUS_COMPAT64 = _IOR('A', 0x20, struct compat_snd_pcm_status64),
 562        SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT64 = _IOWR('A', 0x24, struct compat_snd_pcm_status64),
 563#ifdef CONFIG_X86_X32
 564        SNDRV_PCM_IOCTL_CHANNEL_INFO_X32 = _IOR('A', 0x32, struct snd_pcm_channel_info),
 565        SNDRV_PCM_IOCTL_SYNC_PTR_X32 = _IOWR('A', 0x23, struct snd_pcm_sync_ptr_x32),
 566#endif /* CONFIG_X86_X32 */
 567};
 568
 569static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
 570{
 571        struct snd_pcm_file *pcm_file;
 572        struct snd_pcm_substream *substream;
 573        void __user *argp = compat_ptr(arg);
 574
 575        pcm_file = file->private_data;
 576        if (! pcm_file)
 577                return -ENOTTY;
 578        substream = pcm_file->substream;
 579        if (! substream)
 580                return -ENOTTY;
 581
 582        /*
 583         * When PCM is used on 32bit mode, we need to disable
 584         * mmap of the old PCM status/control records because
 585         * of the size incompatibility.
 586         */
 587        pcm_file->no_compat_mmap = 1;
 588
 589        switch (cmd) {
 590        case SNDRV_PCM_IOCTL_PVERSION:
 591        case SNDRV_PCM_IOCTL_INFO:
 592        case SNDRV_PCM_IOCTL_TSTAMP:
 593        case SNDRV_PCM_IOCTL_TTSTAMP:
 594        case SNDRV_PCM_IOCTL_USER_PVERSION:
 595        case SNDRV_PCM_IOCTL_HWSYNC:
 596        case SNDRV_PCM_IOCTL_PREPARE:
 597        case SNDRV_PCM_IOCTL_RESET:
 598        case SNDRV_PCM_IOCTL_START:
 599        case SNDRV_PCM_IOCTL_DROP:
 600        case SNDRV_PCM_IOCTL_DRAIN:
 601        case SNDRV_PCM_IOCTL_PAUSE:
 602        case SNDRV_PCM_IOCTL_HW_FREE:
 603        case SNDRV_PCM_IOCTL_RESUME:
 604        case SNDRV_PCM_IOCTL_XRUN:
 605        case SNDRV_PCM_IOCTL_LINK:
 606        case SNDRV_PCM_IOCTL_UNLINK:
 607        case __SNDRV_PCM_IOCTL_SYNC_PTR32:
 608                return snd_pcm_common_ioctl(file, substream, cmd, argp);
 609        case __SNDRV_PCM_IOCTL_SYNC_PTR64:
 610#ifdef CONFIG_X86_X32
 611                if (in_x32_syscall())
 612                        return snd_pcm_ioctl_sync_ptr_x32(substream, argp);
 613#endif /* CONFIG_X86_X32 */
 614                return snd_pcm_ioctl_sync_ptr_buggy(substream, argp);
 615        case SNDRV_PCM_IOCTL_HW_REFINE32:
 616                return snd_pcm_ioctl_hw_params_compat(substream, 1, argp);
 617        case SNDRV_PCM_IOCTL_HW_PARAMS32:
 618                return snd_pcm_ioctl_hw_params_compat(substream, 0, argp);
 619        case SNDRV_PCM_IOCTL_SW_PARAMS32:
 620                return snd_pcm_ioctl_sw_params_compat(substream, argp);
 621        case SNDRV_PCM_IOCTL_STATUS_COMPAT32:
 622                return snd_pcm_status_user32(substream, argp, false);
 623        case SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT32:
 624                return snd_pcm_status_user32(substream, argp, true);
 625        case SNDRV_PCM_IOCTL_CHANNEL_INFO32:
 626                return snd_pcm_ioctl_channel_info_compat(substream, argp);
 627        case SNDRV_PCM_IOCTL_WRITEI_FRAMES32:
 628                return snd_pcm_ioctl_xferi_compat(substream, SNDRV_PCM_STREAM_PLAYBACK, argp);
 629        case SNDRV_PCM_IOCTL_READI_FRAMES32:
 630                return snd_pcm_ioctl_xferi_compat(substream, SNDRV_PCM_STREAM_CAPTURE, argp);
 631        case SNDRV_PCM_IOCTL_WRITEN_FRAMES32:
 632                return snd_pcm_ioctl_xfern_compat(substream, SNDRV_PCM_STREAM_PLAYBACK, argp);
 633        case SNDRV_PCM_IOCTL_READN_FRAMES32:
 634                return snd_pcm_ioctl_xfern_compat(substream, SNDRV_PCM_STREAM_CAPTURE, argp);
 635        case SNDRV_PCM_IOCTL_DELAY32:
 636                return snd_pcm_ioctl_delay_compat(substream, argp);
 637        case SNDRV_PCM_IOCTL_REWIND32:
 638                return snd_pcm_ioctl_rewind_compat(substream, argp);
 639        case SNDRV_PCM_IOCTL_FORWARD32:
 640                return snd_pcm_ioctl_forward_compat(substream, argp);
 641        case SNDRV_PCM_IOCTL_STATUS_COMPAT64:
 642                return snd_pcm_status_user_compat64(substream, argp, false);
 643        case SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT64:
 644                return snd_pcm_status_user_compat64(substream, argp, true);
 645#ifdef CONFIG_X86_X32
 646        case SNDRV_PCM_IOCTL_CHANNEL_INFO_X32:
 647                return snd_pcm_ioctl_channel_info_x32(substream, argp);
 648#endif /* CONFIG_X86_X32 */
 649        }
 650
 651        return -ENOIOCTLCMD;
 652}
 653