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        if (! (runtime = substream->runtime))
 243                return -ENOTTY;
 244
 245        data = kmalloc(sizeof(*data), GFP_KERNEL);
 246        if (!data)
 247                return -ENOMEM;
 248
 249        /* only fifo_size (RO from userspace) is different, so just copy all */
 250        if (copy_from_user(data, data32, sizeof(*data32))) {
 251                err = -EFAULT;
 252                goto error;
 253        }
 254
 255        if (refine)
 256                err = snd_pcm_hw_refine(substream, data);
 257        else
 258                err = snd_pcm_hw_params(substream, data);
 259        if (err < 0)
 260                goto error;
 261        if (copy_to_user(data32, data, sizeof(*data32)) ||
 262            put_user(data->fifo_size, &data32->fifo_size)) {
 263                err = -EFAULT;
 264                goto error;
 265        }
 266
 267        if (! refine) {
 268                unsigned int new_boundary = recalculate_boundary(runtime);
 269                if (new_boundary)
 270                        runtime->boundary = new_boundary;
 271        }
 272 error:
 273        kfree(data);
 274        return err;
 275}
 276
 277
 278/*
 279 */
 280struct snd_xferi32 {
 281        s32 result;
 282        u32 buf;
 283        u32 frames;
 284};
 285
 286static int snd_pcm_ioctl_xferi_compat(struct snd_pcm_substream *substream,
 287                                      int dir, struct snd_xferi32 __user *data32)
 288{
 289        compat_caddr_t buf;
 290        u32 frames;
 291        int err;
 292
 293        if (! substream->runtime)
 294                return -ENOTTY;
 295        if (substream->stream != dir)
 296                return -EINVAL;
 297        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
 298                return -EBADFD;
 299
 300        if (get_user(buf, &data32->buf) ||
 301            get_user(frames, &data32->frames))
 302                return -EFAULT;
 303
 304        if (dir == SNDRV_PCM_STREAM_PLAYBACK)
 305                err = snd_pcm_lib_write(substream, compat_ptr(buf), frames);
 306        else
 307                err = snd_pcm_lib_read(substream, compat_ptr(buf), frames);
 308        if (err < 0)
 309                return err;
 310        /* copy the result */
 311        if (put_user(err, &data32->result))
 312                return -EFAULT;
 313        return 0;
 314}
 315
 316
 317/* snd_xfern needs remapping of bufs */
 318struct snd_xfern32 {
 319        s32 result;
 320        u32 bufs;  /* this is void **; */
 321        u32 frames;
 322};
 323
 324/*
 325 * xfern ioctl nees to copy (up to) 128 pointers on stack.
 326 * although we may pass the copied pointers through f_op->ioctl, but the ioctl
 327 * handler there expands again the same 128 pointers on stack, so it is better
 328 * to handle the function (calling pcm_readv/writev) directly in this handler.
 329 */
 330static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream,
 331                                      int dir, struct snd_xfern32 __user *data32)
 332{
 333        compat_caddr_t buf;
 334        compat_caddr_t __user *bufptr;
 335        u32 frames;
 336        void __user **bufs;
 337        int err, ch, i;
 338
 339        if (! substream->runtime)
 340                return -ENOTTY;
 341        if (substream->stream != dir)
 342                return -EINVAL;
 343        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
 344                return -EBADFD;
 345
 346        if ((ch = substream->runtime->channels) > 128)
 347                return -EINVAL;
 348        if (get_user(buf, &data32->bufs) ||
 349            get_user(frames, &data32->frames))
 350                return -EFAULT;
 351        bufptr = compat_ptr(buf);
 352        bufs = kmalloc_array(ch, sizeof(void __user *), GFP_KERNEL);
 353        if (bufs == NULL)
 354                return -ENOMEM;
 355        for (i = 0; i < ch; i++) {
 356                u32 ptr;
 357                if (get_user(ptr, bufptr)) {
 358                        kfree(bufs);
 359                        return -EFAULT;
 360                }
 361                bufs[i] = compat_ptr(ptr);
 362                bufptr++;
 363        }
 364        if (dir == SNDRV_PCM_STREAM_PLAYBACK)
 365                err = snd_pcm_lib_writev(substream, bufs, frames);
 366        else
 367                err = snd_pcm_lib_readv(substream, bufs, frames);
 368        if (err >= 0) {
 369                if (put_user(err, &data32->result))
 370                        err = -EFAULT;
 371        }
 372        kfree(bufs);
 373        return err;
 374}
 375
 376#ifdef CONFIG_X86_X32
 377/* X32 ABI has 64bit timespec and 64bit alignment */
 378struct snd_pcm_mmap_status_x32 {
 379        snd_pcm_state_t state;
 380        s32 pad1;
 381        u32 hw_ptr;
 382        u32 pad2; /* alignment */
 383        s64 tstamp_sec;
 384        s64 tstamp_nsec;
 385        snd_pcm_state_t suspended_state;
 386        s32 pad3;
 387        s64 audio_tstamp_sec;
 388        s64 audio_tstamp_nsec;
 389} __packed;
 390
 391struct snd_pcm_mmap_control_x32 {
 392        u32 appl_ptr;
 393        u32 avail_min;
 394};
 395
 396struct snd_pcm_sync_ptr_x32 {
 397        u32 flags;
 398        u32 rsvd; /* alignment */
 399        union {
 400                struct snd_pcm_mmap_status_x32 status;
 401                unsigned char reserved[64];
 402        } s;
 403        union {
 404                struct snd_pcm_mmap_control_x32 control;
 405                unsigned char reserved[64];
 406        } c;
 407} __packed;
 408
 409static int snd_pcm_ioctl_sync_ptr_x32(struct snd_pcm_substream *substream,
 410                                      struct snd_pcm_sync_ptr_x32 __user *src)
 411{
 412        struct snd_pcm_runtime *runtime = substream->runtime;
 413        volatile struct snd_pcm_mmap_status *status;
 414        volatile struct snd_pcm_mmap_control *control;
 415        u32 sflags;
 416        struct snd_pcm_mmap_control scontrol;
 417        struct snd_pcm_mmap_status sstatus;
 418        snd_pcm_uframes_t boundary;
 419        int err;
 420
 421        if (snd_BUG_ON(!runtime))
 422                return -EINVAL;
 423
 424        if (get_user(sflags, &src->flags) ||
 425            get_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
 426            get_user(scontrol.avail_min, &src->c.control.avail_min))
 427                return -EFAULT;
 428        if (sflags & SNDRV_PCM_SYNC_PTR_HWSYNC) {
 429                err = snd_pcm_hwsync(substream);
 430                if (err < 0)
 431                        return err;
 432        }
 433        status = runtime->status;
 434        control = runtime->control;
 435        boundary = recalculate_boundary(runtime);
 436        if (!boundary)
 437                boundary = 0x7fffffff;
 438        snd_pcm_stream_lock_irq(substream);
 439        /* FIXME: we should consider the boundary for the sync from app */
 440        if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
 441                control->appl_ptr = scontrol.appl_ptr;
 442        else
 443                scontrol.appl_ptr = control->appl_ptr % boundary;
 444        if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
 445                control->avail_min = scontrol.avail_min;
 446        else
 447                scontrol.avail_min = control->avail_min;
 448        sstatus.state = status->state;
 449        sstatus.hw_ptr = status->hw_ptr % boundary;
 450        sstatus.tstamp = status->tstamp;
 451        sstatus.suspended_state = status->suspended_state;
 452        sstatus.audio_tstamp = status->audio_tstamp;
 453        snd_pcm_stream_unlock_irq(substream);
 454        if (put_user(sstatus.state, &src->s.status.state) ||
 455            put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) ||
 456            put_user(sstatus.tstamp.tv_sec, &src->s.status.tstamp_sec) ||
 457            put_user(sstatus.tstamp.tv_nsec, &src->s.status.tstamp_nsec) ||
 458            put_user(sstatus.suspended_state, &src->s.status.suspended_state) ||
 459            put_user(sstatus.audio_tstamp.tv_sec, &src->s.status.audio_tstamp_sec) ||
 460            put_user(sstatus.audio_tstamp.tv_nsec, &src->s.status.audio_tstamp_nsec) ||
 461            put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
 462            put_user(scontrol.avail_min, &src->c.control.avail_min))
 463                return -EFAULT;
 464
 465        return 0;
 466}
 467#endif /* CONFIG_X86_X32 */
 468
 469/*
 470 */
 471enum {
 472        SNDRV_PCM_IOCTL_HW_REFINE32 = _IOWR('A', 0x10, struct snd_pcm_hw_params32),
 473        SNDRV_PCM_IOCTL_HW_PARAMS32 = _IOWR('A', 0x11, struct snd_pcm_hw_params32),
 474        SNDRV_PCM_IOCTL_SW_PARAMS32 = _IOWR('A', 0x13, struct snd_pcm_sw_params32),
 475        SNDRV_PCM_IOCTL_STATUS_COMPAT32 = _IOR('A', 0x20, struct snd_pcm_status32),
 476        SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT32 = _IOWR('A', 0x24, struct snd_pcm_status32),
 477        SNDRV_PCM_IOCTL_DELAY32 = _IOR('A', 0x21, s32),
 478        SNDRV_PCM_IOCTL_CHANNEL_INFO32 = _IOR('A', 0x32, struct snd_pcm_channel_info32),
 479        SNDRV_PCM_IOCTL_REWIND32 = _IOW('A', 0x46, u32),
 480        SNDRV_PCM_IOCTL_FORWARD32 = _IOW('A', 0x49, u32),
 481        SNDRV_PCM_IOCTL_WRITEI_FRAMES32 = _IOW('A', 0x50, struct snd_xferi32),
 482        SNDRV_PCM_IOCTL_READI_FRAMES32 = _IOR('A', 0x51, struct snd_xferi32),
 483        SNDRV_PCM_IOCTL_WRITEN_FRAMES32 = _IOW('A', 0x52, struct snd_xfern32),
 484        SNDRV_PCM_IOCTL_READN_FRAMES32 = _IOR('A', 0x53, struct snd_xfern32),
 485        SNDRV_PCM_IOCTL_STATUS_COMPAT64 = _IOR('A', 0x20, struct compat_snd_pcm_status64),
 486        SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT64 = _IOWR('A', 0x24, struct compat_snd_pcm_status64),
 487#ifdef CONFIG_X86_X32
 488        SNDRV_PCM_IOCTL_CHANNEL_INFO_X32 = _IOR('A', 0x32, struct snd_pcm_channel_info),
 489        SNDRV_PCM_IOCTL_SYNC_PTR_X32 = _IOWR('A', 0x23, struct snd_pcm_sync_ptr_x32),
 490#endif /* CONFIG_X86_X32 */
 491};
 492
 493static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
 494{
 495        struct snd_pcm_file *pcm_file;
 496        struct snd_pcm_substream *substream;
 497        void __user *argp = compat_ptr(arg);
 498
 499        pcm_file = file->private_data;
 500        if (! pcm_file)
 501                return -ENOTTY;
 502        substream = pcm_file->substream;
 503        if (! substream)
 504                return -ENOTTY;
 505
 506        /*
 507         * When PCM is used on 32bit mode, we need to disable
 508         * mmap of the old PCM status/control records because
 509         * of the size incompatibility.
 510         */
 511        pcm_file->no_compat_mmap = 1;
 512
 513        switch (cmd) {
 514        case SNDRV_PCM_IOCTL_PVERSION:
 515        case SNDRV_PCM_IOCTL_INFO:
 516        case SNDRV_PCM_IOCTL_TSTAMP:
 517        case SNDRV_PCM_IOCTL_TTSTAMP:
 518        case SNDRV_PCM_IOCTL_USER_PVERSION:
 519        case SNDRV_PCM_IOCTL_HWSYNC:
 520        case SNDRV_PCM_IOCTL_PREPARE:
 521        case SNDRV_PCM_IOCTL_RESET:
 522        case SNDRV_PCM_IOCTL_START:
 523        case SNDRV_PCM_IOCTL_DROP:
 524        case SNDRV_PCM_IOCTL_DRAIN:
 525        case SNDRV_PCM_IOCTL_PAUSE:
 526        case SNDRV_PCM_IOCTL_HW_FREE:
 527        case SNDRV_PCM_IOCTL_RESUME:
 528        case SNDRV_PCM_IOCTL_XRUN:
 529        case SNDRV_PCM_IOCTL_LINK:
 530        case SNDRV_PCM_IOCTL_UNLINK:
 531        case __SNDRV_PCM_IOCTL_SYNC_PTR32:
 532                return snd_pcm_common_ioctl(file, substream, cmd, argp);
 533        case __SNDRV_PCM_IOCTL_SYNC_PTR64:
 534#ifdef CONFIG_X86_X32
 535                if (in_x32_syscall())
 536                        return snd_pcm_ioctl_sync_ptr_x32(substream, argp);
 537#endif /* CONFIG_X86_X32 */
 538                return snd_pcm_common_ioctl(file, substream, cmd, argp);
 539        case SNDRV_PCM_IOCTL_HW_REFINE32:
 540                return snd_pcm_ioctl_hw_params_compat(substream, 1, argp);
 541        case SNDRV_PCM_IOCTL_HW_PARAMS32:
 542                return snd_pcm_ioctl_hw_params_compat(substream, 0, argp);
 543        case SNDRV_PCM_IOCTL_SW_PARAMS32:
 544                return snd_pcm_ioctl_sw_params_compat(substream, argp);
 545        case SNDRV_PCM_IOCTL_STATUS_COMPAT32:
 546                return snd_pcm_status_user32(substream, argp, false);
 547        case SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT32:
 548                return snd_pcm_status_user32(substream, argp, true);
 549        case SNDRV_PCM_IOCTL_CHANNEL_INFO32:
 550                return snd_pcm_ioctl_channel_info_compat(substream, argp);
 551        case SNDRV_PCM_IOCTL_WRITEI_FRAMES32:
 552                return snd_pcm_ioctl_xferi_compat(substream, SNDRV_PCM_STREAM_PLAYBACK, argp);
 553        case SNDRV_PCM_IOCTL_READI_FRAMES32:
 554                return snd_pcm_ioctl_xferi_compat(substream, SNDRV_PCM_STREAM_CAPTURE, argp);
 555        case SNDRV_PCM_IOCTL_WRITEN_FRAMES32:
 556                return snd_pcm_ioctl_xfern_compat(substream, SNDRV_PCM_STREAM_PLAYBACK, argp);
 557        case SNDRV_PCM_IOCTL_READN_FRAMES32:
 558                return snd_pcm_ioctl_xfern_compat(substream, SNDRV_PCM_STREAM_CAPTURE, argp);
 559        case SNDRV_PCM_IOCTL_DELAY32:
 560                return snd_pcm_ioctl_delay_compat(substream, argp);
 561        case SNDRV_PCM_IOCTL_REWIND32:
 562                return snd_pcm_ioctl_rewind_compat(substream, argp);
 563        case SNDRV_PCM_IOCTL_FORWARD32:
 564                return snd_pcm_ioctl_forward_compat(substream, argp);
 565        case SNDRV_PCM_IOCTL_STATUS_COMPAT64:
 566                return snd_pcm_status_user_compat64(substream, argp, false);
 567        case SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT64:
 568                return snd_pcm_status_user_compat64(substream, argp, true);
 569#ifdef CONFIG_X86_X32
 570        case SNDRV_PCM_IOCTL_CHANNEL_INFO_X32:
 571                return snd_pcm_ioctl_channel_info_x32(substream, argp);
 572#endif /* CONFIG_X86_X32 */
 573        }
 574
 575        return -ENOIOCTLCMD;
 576}
 577