root/sound/core/pcm_compat.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. snd_pcm_ioctl_delay_compat
  2. snd_pcm_ioctl_rewind_compat
  3. snd_pcm_ioctl_forward_compat
  4. recalculate_boundary
  5. snd_pcm_ioctl_sw_params_compat
  6. snd_pcm_ioctl_channel_info_compat
  7. snd_pcm_status_user_compat
  8. snd_pcm_status_user_x32
  9. snd_pcm_ioctl_hw_params_compat
  10. snd_pcm_ioctl_xferi_compat
  11. snd_pcm_ioctl_xfern_compat
  12. snd_pcm_ioctl_sync_ptr_compat
  13. snd_pcm_ioctl_sync_ptr_x32
  14. snd_pcm_ioctl_compat

   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 
  12 static 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 
  26 static 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 
  40 static 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 
  54 struct 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 
  70 struct 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 
  86 /* recalcuate the boundary within 32bit */
  87 static snd_pcm_uframes_t recalculate_boundary(struct snd_pcm_runtime *runtime)
  88 {
  89         snd_pcm_uframes_t boundary;
  90 
  91         if (! runtime->buffer_size)
  92                 return 0;
  93         boundary = runtime->buffer_size;
  94         while (boundary * 2 <= 0x7fffffffUL - runtime->buffer_size)
  95                 boundary *= 2;
  96         return boundary;
  97 }
  98 
  99 static int snd_pcm_ioctl_sw_params_compat(struct snd_pcm_substream *substream,
 100                                           struct snd_pcm_sw_params32 __user *src)
 101 {
 102         struct snd_pcm_sw_params params;
 103         snd_pcm_uframes_t boundary;
 104         int err;
 105 
 106         memset(&params, 0, sizeof(params));
 107         if (get_user(params.tstamp_mode, &src->tstamp_mode) ||
 108             get_user(params.period_step, &src->period_step) ||
 109             get_user(params.sleep_min, &src->sleep_min) ||
 110             get_user(params.avail_min, &src->avail_min) ||
 111             get_user(params.xfer_align, &src->xfer_align) ||
 112             get_user(params.start_threshold, &src->start_threshold) ||
 113             get_user(params.stop_threshold, &src->stop_threshold) ||
 114             get_user(params.silence_threshold, &src->silence_threshold) ||
 115             get_user(params.silence_size, &src->silence_size) ||
 116             get_user(params.tstamp_type, &src->tstamp_type) ||
 117             get_user(params.proto, &src->proto))
 118                 return -EFAULT;
 119         /*
 120          * Check silent_size parameter.  Since we have 64bit boundary,
 121          * silence_size must be compared with the 32bit boundary.
 122          */
 123         boundary = recalculate_boundary(substream->runtime);
 124         if (boundary && params.silence_size >= boundary)
 125                 params.silence_size = substream->runtime->boundary;
 126         err = snd_pcm_sw_params(substream, &params);
 127         if (err < 0)
 128                 return err;
 129         if (boundary && put_user(boundary, &src->boundary))
 130                 return -EFAULT;
 131         return err;
 132 }
 133 
 134 struct snd_pcm_channel_info32 {
 135         u32 channel;
 136         u32 offset;
 137         u32 first;
 138         u32 step;
 139 };
 140 
 141 static int snd_pcm_ioctl_channel_info_compat(struct snd_pcm_substream *substream,
 142                                              struct snd_pcm_channel_info32 __user *src)
 143 {
 144         struct snd_pcm_channel_info info;
 145         int err;
 146 
 147         if (get_user(info.channel, &src->channel) ||
 148             get_user(info.offset, &src->offset) ||
 149             get_user(info.first, &src->first) ||
 150             get_user(info.step, &src->step))
 151                 return -EFAULT;
 152         err = snd_pcm_channel_info(substream, &info);
 153         if (err < 0)
 154                 return err;
 155         if (put_user(info.channel, &src->channel) ||
 156             put_user(info.offset, &src->offset) ||
 157             put_user(info.first, &src->first) ||
 158             put_user(info.step, &src->step))
 159                 return -EFAULT;
 160         return err;
 161 }
 162 
 163 #ifdef CONFIG_X86_X32
 164 /* X32 ABI has the same struct as x86-64 for snd_pcm_channel_info */
 165 static int snd_pcm_channel_info_user(struct snd_pcm_substream *substream,
 166                                      struct snd_pcm_channel_info __user *src);
 167 #define snd_pcm_ioctl_channel_info_x32(s, p)    \
 168         snd_pcm_channel_info_user(s, p)
 169 #endif /* CONFIG_X86_X32 */
 170 
 171 struct snd_pcm_status32 {
 172         s32 state;
 173         struct compat_timespec trigger_tstamp;
 174         struct compat_timespec tstamp;
 175         u32 appl_ptr;
 176         u32 hw_ptr;
 177         s32 delay;
 178         u32 avail;
 179         u32 avail_max;
 180         u32 overrange;
 181         s32 suspended_state;
 182         u32 audio_tstamp_data;
 183         struct compat_timespec audio_tstamp;
 184         struct compat_timespec driver_tstamp;
 185         u32 audio_tstamp_accuracy;
 186         unsigned char reserved[52-2*sizeof(struct compat_timespec)];
 187 } __attribute__((packed));
 188 
 189 
 190 static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream,
 191                                       struct snd_pcm_status32 __user *src,
 192                                       bool ext)
 193 {
 194         struct snd_pcm_status status;
 195         int err;
 196 
 197         memset(&status, 0, sizeof(status));
 198         /*
 199          * with extension, parameters are read/write,
 200          * get audio_tstamp_data from user,
 201          * ignore rest of status structure
 202          */
 203         if (ext && get_user(status.audio_tstamp_data,
 204                                 (u32 __user *)(&src->audio_tstamp_data)))
 205                 return -EFAULT;
 206         err = snd_pcm_status(substream, &status);
 207         if (err < 0)
 208                 return err;
 209 
 210         if (clear_user(src, sizeof(*src)))
 211                 return -EFAULT;
 212         if (put_user(status.state, &src->state) ||
 213             compat_put_timespec(&status.trigger_tstamp, &src->trigger_tstamp) ||
 214             compat_put_timespec(&status.tstamp, &src->tstamp) ||
 215             put_user(status.appl_ptr, &src->appl_ptr) ||
 216             put_user(status.hw_ptr, &src->hw_ptr) ||
 217             put_user(status.delay, &src->delay) ||
 218             put_user(status.avail, &src->avail) ||
 219             put_user(status.avail_max, &src->avail_max) ||
 220             put_user(status.overrange, &src->overrange) ||
 221             put_user(status.suspended_state, &src->suspended_state) ||
 222             put_user(status.audio_tstamp_data, &src->audio_tstamp_data) ||
 223             compat_put_timespec(&status.audio_tstamp, &src->audio_tstamp) ||
 224             compat_put_timespec(&status.driver_tstamp, &src->driver_tstamp) ||
 225             put_user(status.audio_tstamp_accuracy, &src->audio_tstamp_accuracy))
 226                 return -EFAULT;
 227 
 228         return err;
 229 }
 230 
 231 #ifdef CONFIG_X86_X32
 232 /* X32 ABI has 64bit timespec and 64bit alignment */
 233 struct snd_pcm_status_x32 {
 234         s32 state;
 235         u32 rsvd; /* alignment */
 236         struct timespec trigger_tstamp;
 237         struct timespec tstamp;
 238         u32 appl_ptr;
 239         u32 hw_ptr;
 240         s32 delay;
 241         u32 avail;
 242         u32 avail_max;
 243         u32 overrange;
 244         s32 suspended_state;
 245         u32 audio_tstamp_data;
 246         struct timespec audio_tstamp;
 247         struct timespec driver_tstamp;
 248         u32 audio_tstamp_accuracy;
 249         unsigned char reserved[52-2*sizeof(struct timespec)];
 250 } __packed;
 251 
 252 #define put_timespec(src, dst) copy_to_user(dst, src, sizeof(*dst))
 253 
 254 static int snd_pcm_status_user_x32(struct snd_pcm_substream *substream,
 255                                    struct snd_pcm_status_x32 __user *src,
 256                                    bool ext)
 257 {
 258         struct snd_pcm_status status;
 259         int err;
 260 
 261         memset(&status, 0, sizeof(status));
 262         /*
 263          * with extension, parameters are read/write,
 264          * get audio_tstamp_data from user,
 265          * ignore rest of status structure
 266          */
 267         if (ext && get_user(status.audio_tstamp_data,
 268                                 (u32 __user *)(&src->audio_tstamp_data)))
 269                 return -EFAULT;
 270         err = snd_pcm_status(substream, &status);
 271         if (err < 0)
 272                 return err;
 273 
 274         if (clear_user(src, sizeof(*src)))
 275                 return -EFAULT;
 276         if (put_user(status.state, &src->state) ||
 277             put_timespec(&status.trigger_tstamp, &src->trigger_tstamp) ||
 278             put_timespec(&status.tstamp, &src->tstamp) ||
 279             put_user(status.appl_ptr, &src->appl_ptr) ||
 280             put_user(status.hw_ptr, &src->hw_ptr) ||
 281             put_user(status.delay, &src->delay) ||
 282             put_user(status.avail, &src->avail) ||
 283             put_user(status.avail_max, &src->avail_max) ||
 284             put_user(status.overrange, &src->overrange) ||
 285             put_user(status.suspended_state, &src->suspended_state) ||
 286             put_user(status.audio_tstamp_data, &src->audio_tstamp_data) ||
 287             put_timespec(&status.audio_tstamp, &src->audio_tstamp) ||
 288             put_timespec(&status.driver_tstamp, &src->driver_tstamp) ||
 289             put_user(status.audio_tstamp_accuracy, &src->audio_tstamp_accuracy))
 290                 return -EFAULT;
 291 
 292         return err;
 293 }
 294 #endif /* CONFIG_X86_X32 */
 295 
 296 /* both for HW_PARAMS and HW_REFINE */
 297 static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream,
 298                                           int refine, 
 299                                           struct snd_pcm_hw_params32 __user *data32)
 300 {
 301         struct snd_pcm_hw_params *data;
 302         struct snd_pcm_runtime *runtime;
 303         int err;
 304 
 305         if (! (runtime = substream->runtime))
 306                 return -ENOTTY;
 307 
 308         data = kmalloc(sizeof(*data), GFP_KERNEL);
 309         if (!data)
 310                 return -ENOMEM;
 311 
 312         /* only fifo_size (RO from userspace) is different, so just copy all */
 313         if (copy_from_user(data, data32, sizeof(*data32))) {
 314                 err = -EFAULT;
 315                 goto error;
 316         }
 317 
 318         if (refine)
 319                 err = snd_pcm_hw_refine(substream, data);
 320         else
 321                 err = snd_pcm_hw_params(substream, data);
 322         if (err < 0)
 323                 goto error;
 324         if (copy_to_user(data32, data, sizeof(*data32)) ||
 325             put_user(data->fifo_size, &data32->fifo_size)) {
 326                 err = -EFAULT;
 327                 goto error;
 328         }
 329 
 330         if (! refine) {
 331                 unsigned int new_boundary = recalculate_boundary(runtime);
 332                 if (new_boundary)
 333                         runtime->boundary = new_boundary;
 334         }
 335  error:
 336         kfree(data);
 337         return err;
 338 }
 339 
 340 
 341 /*
 342  */
 343 struct snd_xferi32 {
 344         s32 result;
 345         u32 buf;
 346         u32 frames;
 347 };
 348 
 349 static int snd_pcm_ioctl_xferi_compat(struct snd_pcm_substream *substream,
 350                                       int dir, struct snd_xferi32 __user *data32)
 351 {
 352         compat_caddr_t buf;
 353         u32 frames;
 354         int err;
 355 
 356         if (! substream->runtime)
 357                 return -ENOTTY;
 358         if (substream->stream != dir)
 359                 return -EINVAL;
 360         if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
 361                 return -EBADFD;
 362 
 363         if (get_user(buf, &data32->buf) ||
 364             get_user(frames, &data32->frames))
 365                 return -EFAULT;
 366 
 367         if (dir == SNDRV_PCM_STREAM_PLAYBACK)
 368                 err = snd_pcm_lib_write(substream, compat_ptr(buf), frames);
 369         else
 370                 err = snd_pcm_lib_read(substream, compat_ptr(buf), frames);
 371         if (err < 0)
 372                 return err;
 373         /* copy the result */
 374         if (put_user(err, &data32->result))
 375                 return -EFAULT;
 376         return 0;
 377 }
 378 
 379 
 380 /* snd_xfern needs remapping of bufs */
 381 struct snd_xfern32 {
 382         s32 result;
 383         u32 bufs;  /* this is void **; */
 384         u32 frames;
 385 };
 386 
 387 /*
 388  * xfern ioctl nees to copy (up to) 128 pointers on stack.
 389  * although we may pass the copied pointers through f_op->ioctl, but the ioctl
 390  * handler there expands again the same 128 pointers on stack, so it is better
 391  * to handle the function (calling pcm_readv/writev) directly in this handler.
 392  */
 393 static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream,
 394                                       int dir, struct snd_xfern32 __user *data32)
 395 {
 396         compat_caddr_t buf;
 397         compat_caddr_t __user *bufptr;
 398         u32 frames;
 399         void __user **bufs;
 400         int err, ch, i;
 401 
 402         if (! substream->runtime)
 403                 return -ENOTTY;
 404         if (substream->stream != dir)
 405                 return -EINVAL;
 406         if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
 407                 return -EBADFD;
 408 
 409         if ((ch = substream->runtime->channels) > 128)
 410                 return -EINVAL;
 411         if (get_user(buf, &data32->bufs) ||
 412             get_user(frames, &data32->frames))
 413                 return -EFAULT;
 414         bufptr = compat_ptr(buf);
 415         bufs = kmalloc_array(ch, sizeof(void __user *), GFP_KERNEL);
 416         if (bufs == NULL)
 417                 return -ENOMEM;
 418         for (i = 0; i < ch; i++) {
 419                 u32 ptr;
 420                 if (get_user(ptr, bufptr)) {
 421                         kfree(bufs);
 422                         return -EFAULT;
 423                 }
 424                 bufs[i] = compat_ptr(ptr);
 425                 bufptr++;
 426         }
 427         if (dir == SNDRV_PCM_STREAM_PLAYBACK)
 428                 err = snd_pcm_lib_writev(substream, bufs, frames);
 429         else
 430                 err = snd_pcm_lib_readv(substream, bufs, frames);
 431         if (err >= 0) {
 432                 if (put_user(err, &data32->result))
 433                         err = -EFAULT;
 434         }
 435         kfree(bufs);
 436         return err;
 437 }
 438 
 439 
 440 struct snd_pcm_mmap_status32 {
 441         s32 state;
 442         s32 pad1;
 443         u32 hw_ptr;
 444         struct compat_timespec tstamp;
 445         s32 suspended_state;
 446         struct compat_timespec audio_tstamp;
 447 } __attribute__((packed));
 448 
 449 struct snd_pcm_mmap_control32 {
 450         u32 appl_ptr;
 451         u32 avail_min;
 452 };
 453 
 454 struct snd_pcm_sync_ptr32 {
 455         u32 flags;
 456         union {
 457                 struct snd_pcm_mmap_status32 status;
 458                 unsigned char reserved[64];
 459         } s;
 460         union {
 461                 struct snd_pcm_mmap_control32 control;
 462                 unsigned char reserved[64];
 463         } c;
 464 } __attribute__((packed));
 465 
 466 static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream,
 467                                          struct snd_pcm_sync_ptr32 __user *src)
 468 {
 469         struct snd_pcm_runtime *runtime = substream->runtime;
 470         volatile struct snd_pcm_mmap_status *status;
 471         volatile struct snd_pcm_mmap_control *control;
 472         u32 sflags;
 473         struct snd_pcm_mmap_control scontrol;
 474         struct snd_pcm_mmap_status sstatus;
 475         snd_pcm_uframes_t boundary;
 476         int err;
 477 
 478         if (snd_BUG_ON(!runtime))
 479                 return -EINVAL;
 480 
 481         if (get_user(sflags, &src->flags) ||
 482             get_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
 483             get_user(scontrol.avail_min, &src->c.control.avail_min))
 484                 return -EFAULT;
 485         if (sflags & SNDRV_PCM_SYNC_PTR_HWSYNC) {
 486                 err = snd_pcm_hwsync(substream);
 487                 if (err < 0)
 488                         return err;
 489         }
 490         status = runtime->status;
 491         control = runtime->control;
 492         boundary = recalculate_boundary(runtime);
 493         if (! boundary)
 494                 boundary = 0x7fffffff;
 495         snd_pcm_stream_lock_irq(substream);
 496         /* FIXME: we should consider the boundary for the sync from app */
 497         if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
 498                 control->appl_ptr = scontrol.appl_ptr;
 499         else
 500                 scontrol.appl_ptr = control->appl_ptr % boundary;
 501         if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
 502                 control->avail_min = scontrol.avail_min;
 503         else
 504                 scontrol.avail_min = control->avail_min;
 505         sstatus.state = status->state;
 506         sstatus.hw_ptr = status->hw_ptr % boundary;
 507         sstatus.tstamp = status->tstamp;
 508         sstatus.suspended_state = status->suspended_state;
 509         sstatus.audio_tstamp = status->audio_tstamp;
 510         snd_pcm_stream_unlock_irq(substream);
 511         if (put_user(sstatus.state, &src->s.status.state) ||
 512             put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) ||
 513             compat_put_timespec(&sstatus.tstamp, &src->s.status.tstamp) ||
 514             put_user(sstatus.suspended_state, &src->s.status.suspended_state) ||
 515             compat_put_timespec(&sstatus.audio_tstamp,
 516                     &src->s.status.audio_tstamp) ||
 517             put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
 518             put_user(scontrol.avail_min, &src->c.control.avail_min))
 519                 return -EFAULT;
 520 
 521         return 0;
 522 }
 523 
 524 #ifdef CONFIG_X86_X32
 525 /* X32 ABI has 64bit timespec and 64bit alignment */
 526 struct snd_pcm_mmap_status_x32 {
 527         s32 state;
 528         s32 pad1;
 529         u32 hw_ptr;
 530         u32 pad2; /* alignment */
 531         struct timespec tstamp;
 532         s32 suspended_state;
 533         s32 pad3;
 534         struct timespec audio_tstamp;
 535 } __packed;
 536 
 537 struct snd_pcm_mmap_control_x32 {
 538         u32 appl_ptr;
 539         u32 avail_min;
 540 };
 541 
 542 struct snd_pcm_sync_ptr_x32 {
 543         u32 flags;
 544         u32 rsvd; /* alignment */
 545         union {
 546                 struct snd_pcm_mmap_status_x32 status;
 547                 unsigned char reserved[64];
 548         } s;
 549         union {
 550                 struct snd_pcm_mmap_control_x32 control;
 551                 unsigned char reserved[64];
 552         } c;
 553 } __packed;
 554 
 555 static int snd_pcm_ioctl_sync_ptr_x32(struct snd_pcm_substream *substream,
 556                                       struct snd_pcm_sync_ptr_x32 __user *src)
 557 {
 558         struct snd_pcm_runtime *runtime = substream->runtime;
 559         volatile struct snd_pcm_mmap_status *status;
 560         volatile struct snd_pcm_mmap_control *control;
 561         u32 sflags;
 562         struct snd_pcm_mmap_control scontrol;
 563         struct snd_pcm_mmap_status sstatus;
 564         snd_pcm_uframes_t boundary;
 565         int err;
 566 
 567         if (snd_BUG_ON(!runtime))
 568                 return -EINVAL;
 569 
 570         if (get_user(sflags, &src->flags) ||
 571             get_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
 572             get_user(scontrol.avail_min, &src->c.control.avail_min))
 573                 return -EFAULT;
 574         if (sflags & SNDRV_PCM_SYNC_PTR_HWSYNC) {
 575                 err = snd_pcm_hwsync(substream);
 576                 if (err < 0)
 577                         return err;
 578         }
 579         status = runtime->status;
 580         control = runtime->control;
 581         boundary = recalculate_boundary(runtime);
 582         if (!boundary)
 583                 boundary = 0x7fffffff;
 584         snd_pcm_stream_lock_irq(substream);
 585         /* FIXME: we should consider the boundary for the sync from app */
 586         if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
 587                 control->appl_ptr = scontrol.appl_ptr;
 588         else
 589                 scontrol.appl_ptr = control->appl_ptr % boundary;
 590         if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
 591                 control->avail_min = scontrol.avail_min;
 592         else
 593                 scontrol.avail_min = control->avail_min;
 594         sstatus.state = status->state;
 595         sstatus.hw_ptr = status->hw_ptr % boundary;
 596         sstatus.tstamp = status->tstamp;
 597         sstatus.suspended_state = status->suspended_state;
 598         sstatus.audio_tstamp = status->audio_tstamp;
 599         snd_pcm_stream_unlock_irq(substream);
 600         if (put_user(sstatus.state, &src->s.status.state) ||
 601             put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) ||
 602             put_timespec(&sstatus.tstamp, &src->s.status.tstamp) ||
 603             put_user(sstatus.suspended_state, &src->s.status.suspended_state) ||
 604             put_timespec(&sstatus.audio_tstamp, &src->s.status.audio_tstamp) ||
 605             put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
 606             put_user(scontrol.avail_min, &src->c.control.avail_min))
 607                 return -EFAULT;
 608 
 609         return 0;
 610 }
 611 #endif /* CONFIG_X86_X32 */
 612 
 613 /*
 614  */
 615 enum {
 616         SNDRV_PCM_IOCTL_HW_REFINE32 = _IOWR('A', 0x10, struct snd_pcm_hw_params32),
 617         SNDRV_PCM_IOCTL_HW_PARAMS32 = _IOWR('A', 0x11, struct snd_pcm_hw_params32),
 618         SNDRV_PCM_IOCTL_SW_PARAMS32 = _IOWR('A', 0x13, struct snd_pcm_sw_params32),
 619         SNDRV_PCM_IOCTL_STATUS32 = _IOR('A', 0x20, struct snd_pcm_status32),
 620         SNDRV_PCM_IOCTL_STATUS_EXT32 = _IOWR('A', 0x24, struct snd_pcm_status32),
 621         SNDRV_PCM_IOCTL_DELAY32 = _IOR('A', 0x21, s32),
 622         SNDRV_PCM_IOCTL_CHANNEL_INFO32 = _IOR('A', 0x32, struct snd_pcm_channel_info32),
 623         SNDRV_PCM_IOCTL_REWIND32 = _IOW('A', 0x46, u32),
 624         SNDRV_PCM_IOCTL_FORWARD32 = _IOW('A', 0x49, u32),
 625         SNDRV_PCM_IOCTL_WRITEI_FRAMES32 = _IOW('A', 0x50, struct snd_xferi32),
 626         SNDRV_PCM_IOCTL_READI_FRAMES32 = _IOR('A', 0x51, struct snd_xferi32),
 627         SNDRV_PCM_IOCTL_WRITEN_FRAMES32 = _IOW('A', 0x52, struct snd_xfern32),
 628         SNDRV_PCM_IOCTL_READN_FRAMES32 = _IOR('A', 0x53, struct snd_xfern32),
 629         SNDRV_PCM_IOCTL_SYNC_PTR32 = _IOWR('A', 0x23, struct snd_pcm_sync_ptr32),
 630 #ifdef CONFIG_X86_X32
 631         SNDRV_PCM_IOCTL_CHANNEL_INFO_X32 = _IOR('A', 0x32, struct snd_pcm_channel_info),
 632         SNDRV_PCM_IOCTL_STATUS_X32 = _IOR('A', 0x20, struct snd_pcm_status_x32),
 633         SNDRV_PCM_IOCTL_STATUS_EXT_X32 = _IOWR('A', 0x24, struct snd_pcm_status_x32),
 634         SNDRV_PCM_IOCTL_SYNC_PTR_X32 = _IOWR('A', 0x23, struct snd_pcm_sync_ptr_x32),
 635 #endif /* CONFIG_X86_X32 */
 636 };
 637 
 638 static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
 639 {
 640         struct snd_pcm_file *pcm_file;
 641         struct snd_pcm_substream *substream;
 642         void __user *argp = compat_ptr(arg);
 643 
 644         pcm_file = file->private_data;
 645         if (! pcm_file)
 646                 return -ENOTTY;
 647         substream = pcm_file->substream;
 648         if (! substream)
 649                 return -ENOTTY;
 650 
 651         /*
 652          * When PCM is used on 32bit mode, we need to disable
 653          * mmap of PCM status/control records because of the size
 654          * incompatibility.
 655          */
 656         pcm_file->no_compat_mmap = 1;
 657 
 658         switch (cmd) {
 659         case SNDRV_PCM_IOCTL_PVERSION:
 660         case SNDRV_PCM_IOCTL_INFO:
 661         case SNDRV_PCM_IOCTL_TSTAMP:
 662         case SNDRV_PCM_IOCTL_TTSTAMP:
 663         case SNDRV_PCM_IOCTL_USER_PVERSION:
 664         case SNDRV_PCM_IOCTL_HWSYNC:
 665         case SNDRV_PCM_IOCTL_PREPARE:
 666         case SNDRV_PCM_IOCTL_RESET:
 667         case SNDRV_PCM_IOCTL_START:
 668         case SNDRV_PCM_IOCTL_DROP:
 669         case SNDRV_PCM_IOCTL_DRAIN:
 670         case SNDRV_PCM_IOCTL_PAUSE:
 671         case SNDRV_PCM_IOCTL_HW_FREE:
 672         case SNDRV_PCM_IOCTL_RESUME:
 673         case SNDRV_PCM_IOCTL_XRUN:
 674         case SNDRV_PCM_IOCTL_LINK:
 675         case SNDRV_PCM_IOCTL_UNLINK:
 676                 return snd_pcm_common_ioctl(file, substream, cmd, argp);
 677         case SNDRV_PCM_IOCTL_HW_REFINE32:
 678                 return snd_pcm_ioctl_hw_params_compat(substream, 1, argp);
 679         case SNDRV_PCM_IOCTL_HW_PARAMS32:
 680                 return snd_pcm_ioctl_hw_params_compat(substream, 0, argp);
 681         case SNDRV_PCM_IOCTL_SW_PARAMS32:
 682                 return snd_pcm_ioctl_sw_params_compat(substream, argp);
 683         case SNDRV_PCM_IOCTL_STATUS32:
 684                 return snd_pcm_status_user_compat(substream, argp, false);
 685         case SNDRV_PCM_IOCTL_STATUS_EXT32:
 686                 return snd_pcm_status_user_compat(substream, argp, true);
 687         case SNDRV_PCM_IOCTL_SYNC_PTR32:
 688                 return snd_pcm_ioctl_sync_ptr_compat(substream, argp);
 689         case SNDRV_PCM_IOCTL_CHANNEL_INFO32:
 690                 return snd_pcm_ioctl_channel_info_compat(substream, argp);
 691         case SNDRV_PCM_IOCTL_WRITEI_FRAMES32:
 692                 return snd_pcm_ioctl_xferi_compat(substream, SNDRV_PCM_STREAM_PLAYBACK, argp);
 693         case SNDRV_PCM_IOCTL_READI_FRAMES32:
 694                 return snd_pcm_ioctl_xferi_compat(substream, SNDRV_PCM_STREAM_CAPTURE, argp);
 695         case SNDRV_PCM_IOCTL_WRITEN_FRAMES32:
 696                 return snd_pcm_ioctl_xfern_compat(substream, SNDRV_PCM_STREAM_PLAYBACK, argp);
 697         case SNDRV_PCM_IOCTL_READN_FRAMES32:
 698                 return snd_pcm_ioctl_xfern_compat(substream, SNDRV_PCM_STREAM_CAPTURE, argp);
 699         case SNDRV_PCM_IOCTL_DELAY32:
 700                 return snd_pcm_ioctl_delay_compat(substream, argp);
 701         case SNDRV_PCM_IOCTL_REWIND32:
 702                 return snd_pcm_ioctl_rewind_compat(substream, argp);
 703         case SNDRV_PCM_IOCTL_FORWARD32:
 704                 return snd_pcm_ioctl_forward_compat(substream, argp);
 705 #ifdef CONFIG_X86_X32
 706         case SNDRV_PCM_IOCTL_STATUS_X32:
 707                 return snd_pcm_status_user_x32(substream, argp, false);
 708         case SNDRV_PCM_IOCTL_STATUS_EXT_X32:
 709                 return snd_pcm_status_user_x32(substream, argp, true);
 710         case SNDRV_PCM_IOCTL_SYNC_PTR_X32:
 711                 return snd_pcm_ioctl_sync_ptr_x32(substream, argp);
 712         case SNDRV_PCM_IOCTL_CHANNEL_INFO_X32:
 713                 return snd_pcm_ioctl_channel_info_x32(substream, argp);
 714 #endif /* CONFIG_X86_X32 */
 715         }
 716 
 717         return -ENOIOCTLCMD;
 718 }

/* [<][>][^][v][top][bottom][index][help] */