ALSA: Avoid using timespec for struct snd_pcm_status
[muen/linux.git] / sound / core / pcm_compat.c
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 compat_snd_pcm_status64 {
172         s32 state;
173         u8 rsvd[4]; /* alignment */
174         s64 trigger_tstamp_sec;
175         s64 trigger_tstamp_nsec;
176         s64 tstamp_sec;
177         s64 tstamp_nsec;
178         u32 appl_ptr;
179         u32 hw_ptr;
180         s32 delay;
181         u32 avail;
182         u32 avail_max;
183         u32 overrange;
184         s32 suspended_state;
185         u32 audio_tstamp_data;
186         s64 audio_tstamp_sec;
187         s64 audio_tstamp_nsec;
188         s64 driver_tstamp_sec;
189         s64 driver_tstamp_nsec;
190         u32 audio_tstamp_accuracy;
191         unsigned char reserved[52-4*sizeof(s64)];
192 } __packed;
193
194 #define put_timespec(src, dst) copy_to_user(dst, src, sizeof(*dst))
195
196 static int snd_pcm_status_user_compat64(struct snd_pcm_substream *substream,
197                                         struct compat_snd_pcm_status64 __user *src,
198                                         bool ext)
199 {
200         struct snd_pcm_status64 status;
201         struct compat_snd_pcm_status64 compat_status64;
202         int err;
203
204         memset(&status, 0, sizeof(status));
205         memset(&compat_status64, 0, sizeof(compat_status64));
206         /*
207          * with extension, parameters are read/write,
208          * get audio_tstamp_data from user,
209          * ignore rest of status structure
210          */
211         if (ext && get_user(status.audio_tstamp_data,
212                                 (u32 __user *)(&src->audio_tstamp_data)))
213                 return -EFAULT;
214         err = snd_pcm_status64(substream, &status);
215         if (err < 0)
216                 return err;
217
218         if (clear_user(src, sizeof(*src)))
219                 return -EFAULT;
220
221         compat_status64 = (struct compat_snd_pcm_status64) {
222                 .state = status.state,
223                 .trigger_tstamp_sec = status.trigger_tstamp_sec,
224                 .trigger_tstamp_nsec = status.trigger_tstamp_nsec,
225                 .tstamp_sec = status.tstamp_sec,
226                 .tstamp_nsec = status.tstamp_nsec,
227                 .appl_ptr = status.appl_ptr,
228                 .hw_ptr = status.hw_ptr,
229                 .delay = status.delay,
230                 .avail = status.avail,
231                 .avail_max = status.avail_max,
232                 .overrange = status.overrange,
233                 .suspended_state = status.suspended_state,
234                 .audio_tstamp_data = status.audio_tstamp_data,
235                 .audio_tstamp_sec = status.audio_tstamp_sec,
236                 .audio_tstamp_nsec = status.audio_tstamp_nsec,
237                 .driver_tstamp_sec = status.audio_tstamp_sec,
238                 .driver_tstamp_nsec = status.audio_tstamp_nsec,
239                 .audio_tstamp_accuracy = status.audio_tstamp_accuracy,
240         };
241
242         if (copy_to_user(src, &compat_status64, sizeof(compat_status64)))
243                 return -EFAULT;
244
245         return err;
246 }
247
248 /* both for HW_PARAMS and HW_REFINE */
249 static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream,
250                                           int refine, 
251                                           struct snd_pcm_hw_params32 __user *data32)
252 {
253         struct snd_pcm_hw_params *data;
254         struct snd_pcm_runtime *runtime;
255         int err;
256
257         if (! (runtime = substream->runtime))
258                 return -ENOTTY;
259
260         data = kmalloc(sizeof(*data), GFP_KERNEL);
261         if (!data)
262                 return -ENOMEM;
263
264         /* only fifo_size (RO from userspace) is different, so just copy all */
265         if (copy_from_user(data, data32, sizeof(*data32))) {
266                 err = -EFAULT;
267                 goto error;
268         }
269
270         if (refine)
271                 err = snd_pcm_hw_refine(substream, data);
272         else
273                 err = snd_pcm_hw_params(substream, data);
274         if (err < 0)
275                 goto error;
276         if (copy_to_user(data32, data, sizeof(*data32)) ||
277             put_user(data->fifo_size, &data32->fifo_size)) {
278                 err = -EFAULT;
279                 goto error;
280         }
281
282         if (! refine) {
283                 unsigned int new_boundary = recalculate_boundary(runtime);
284                 if (new_boundary)
285                         runtime->boundary = new_boundary;
286         }
287  error:
288         kfree(data);
289         return err;
290 }
291
292
293 /*
294  */
295 struct snd_xferi32 {
296         s32 result;
297         u32 buf;
298         u32 frames;
299 };
300
301 static int snd_pcm_ioctl_xferi_compat(struct snd_pcm_substream *substream,
302                                       int dir, struct snd_xferi32 __user *data32)
303 {
304         compat_caddr_t buf;
305         u32 frames;
306         int err;
307
308         if (! substream->runtime)
309                 return -ENOTTY;
310         if (substream->stream != dir)
311                 return -EINVAL;
312         if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
313                 return -EBADFD;
314
315         if (get_user(buf, &data32->buf) ||
316             get_user(frames, &data32->frames))
317                 return -EFAULT;
318
319         if (dir == SNDRV_PCM_STREAM_PLAYBACK)
320                 err = snd_pcm_lib_write(substream, compat_ptr(buf), frames);
321         else
322                 err = snd_pcm_lib_read(substream, compat_ptr(buf), frames);
323         if (err < 0)
324                 return err;
325         /* copy the result */
326         if (put_user(err, &data32->result))
327                 return -EFAULT;
328         return 0;
329 }
330
331
332 /* snd_xfern needs remapping of bufs */
333 struct snd_xfern32 {
334         s32 result;
335         u32 bufs;  /* this is void **; */
336         u32 frames;
337 };
338
339 /*
340  * xfern ioctl nees to copy (up to) 128 pointers on stack.
341  * although we may pass the copied pointers through f_op->ioctl, but the ioctl
342  * handler there expands again the same 128 pointers on stack, so it is better
343  * to handle the function (calling pcm_readv/writev) directly in this handler.
344  */
345 static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream,
346                                       int dir, struct snd_xfern32 __user *data32)
347 {
348         compat_caddr_t buf;
349         compat_caddr_t __user *bufptr;
350         u32 frames;
351         void __user **bufs;
352         int err, ch, i;
353
354         if (! substream->runtime)
355                 return -ENOTTY;
356         if (substream->stream != dir)
357                 return -EINVAL;
358         if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
359                 return -EBADFD;
360
361         if ((ch = substream->runtime->channels) > 128)
362                 return -EINVAL;
363         if (get_user(buf, &data32->bufs) ||
364             get_user(frames, &data32->frames))
365                 return -EFAULT;
366         bufptr = compat_ptr(buf);
367         bufs = kmalloc_array(ch, sizeof(void __user *), GFP_KERNEL);
368         if (bufs == NULL)
369                 return -ENOMEM;
370         for (i = 0; i < ch; i++) {
371                 u32 ptr;
372                 if (get_user(ptr, bufptr)) {
373                         kfree(bufs);
374                         return -EFAULT;
375                 }
376                 bufs[i] = compat_ptr(ptr);
377                 bufptr++;
378         }
379         if (dir == SNDRV_PCM_STREAM_PLAYBACK)
380                 err = snd_pcm_lib_writev(substream, bufs, frames);
381         else
382                 err = snd_pcm_lib_readv(substream, bufs, frames);
383         if (err >= 0) {
384                 if (put_user(err, &data32->result))
385                         err = -EFAULT;
386         }
387         kfree(bufs);
388         return err;
389 }
390
391
392 struct snd_pcm_mmap_status32 {
393         s32 state;
394         s32 pad1;
395         u32 hw_ptr;
396         struct compat_timespec tstamp;
397         s32 suspended_state;
398         struct compat_timespec audio_tstamp;
399 } __attribute__((packed));
400
401 struct snd_pcm_mmap_control32 {
402         u32 appl_ptr;
403         u32 avail_min;
404 };
405
406 struct snd_pcm_sync_ptr32 {
407         u32 flags;
408         union {
409                 struct snd_pcm_mmap_status32 status;
410                 unsigned char reserved[64];
411         } s;
412         union {
413                 struct snd_pcm_mmap_control32 control;
414                 unsigned char reserved[64];
415         } c;
416 } __attribute__((packed));
417
418 static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream,
419                                          struct snd_pcm_sync_ptr32 __user *src)
420 {
421         struct snd_pcm_runtime *runtime = substream->runtime;
422         volatile struct snd_pcm_mmap_status *status;
423         volatile struct snd_pcm_mmap_control *control;
424         u32 sflags;
425         struct snd_pcm_mmap_control scontrol;
426         struct snd_pcm_mmap_status sstatus;
427         snd_pcm_uframes_t boundary;
428         int err;
429
430         if (snd_BUG_ON(!runtime))
431                 return -EINVAL;
432
433         if (get_user(sflags, &src->flags) ||
434             get_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
435             get_user(scontrol.avail_min, &src->c.control.avail_min))
436                 return -EFAULT;
437         if (sflags & SNDRV_PCM_SYNC_PTR_HWSYNC) {
438                 err = snd_pcm_hwsync(substream);
439                 if (err < 0)
440                         return err;
441         }
442         status = runtime->status;
443         control = runtime->control;
444         boundary = recalculate_boundary(runtime);
445         if (! boundary)
446                 boundary = 0x7fffffff;
447         snd_pcm_stream_lock_irq(substream);
448         /* FIXME: we should consider the boundary for the sync from app */
449         if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
450                 control->appl_ptr = scontrol.appl_ptr;
451         else
452                 scontrol.appl_ptr = control->appl_ptr % boundary;
453         if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
454                 control->avail_min = scontrol.avail_min;
455         else
456                 scontrol.avail_min = control->avail_min;
457         sstatus.state = status->state;
458         sstatus.hw_ptr = status->hw_ptr % boundary;
459         sstatus.tstamp = status->tstamp;
460         sstatus.suspended_state = status->suspended_state;
461         sstatus.audio_tstamp = status->audio_tstamp;
462         snd_pcm_stream_unlock_irq(substream);
463         if (put_user(sstatus.state, &src->s.status.state) ||
464             put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) ||
465             compat_put_timespec(&sstatus.tstamp, &src->s.status.tstamp) ||
466             put_user(sstatus.suspended_state, &src->s.status.suspended_state) ||
467             compat_put_timespec(&sstatus.audio_tstamp,
468                     &src->s.status.audio_tstamp) ||
469             put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
470             put_user(scontrol.avail_min, &src->c.control.avail_min))
471                 return -EFAULT;
472
473         return 0;
474 }
475
476 #ifdef CONFIG_X86_X32
477 /* X32 ABI has 64bit timespec and 64bit alignment */
478 struct snd_pcm_mmap_status_x32 {
479         s32 state;
480         s32 pad1;
481         u32 hw_ptr;
482         u32 pad2; /* alignment */
483         struct timespec tstamp;
484         s32 suspended_state;
485         s32 pad3;
486         struct timespec audio_tstamp;
487 } __packed;
488
489 struct snd_pcm_mmap_control_x32 {
490         u32 appl_ptr;
491         u32 avail_min;
492 };
493
494 struct snd_pcm_sync_ptr_x32 {
495         u32 flags;
496         u32 rsvd; /* alignment */
497         union {
498                 struct snd_pcm_mmap_status_x32 status;
499                 unsigned char reserved[64];
500         } s;
501         union {
502                 struct snd_pcm_mmap_control_x32 control;
503                 unsigned char reserved[64];
504         } c;
505 } __packed;
506
507 static int snd_pcm_ioctl_sync_ptr_x32(struct snd_pcm_substream *substream,
508                                       struct snd_pcm_sync_ptr_x32 __user *src)
509 {
510         struct snd_pcm_runtime *runtime = substream->runtime;
511         volatile struct snd_pcm_mmap_status *status;
512         volatile struct snd_pcm_mmap_control *control;
513         u32 sflags;
514         struct snd_pcm_mmap_control scontrol;
515         struct snd_pcm_mmap_status sstatus;
516         snd_pcm_uframes_t boundary;
517         int err;
518
519         if (snd_BUG_ON(!runtime))
520                 return -EINVAL;
521
522         if (get_user(sflags, &src->flags) ||
523             get_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
524             get_user(scontrol.avail_min, &src->c.control.avail_min))
525                 return -EFAULT;
526         if (sflags & SNDRV_PCM_SYNC_PTR_HWSYNC) {
527                 err = snd_pcm_hwsync(substream);
528                 if (err < 0)
529                         return err;
530         }
531         status = runtime->status;
532         control = runtime->control;
533         boundary = recalculate_boundary(runtime);
534         if (!boundary)
535                 boundary = 0x7fffffff;
536         snd_pcm_stream_lock_irq(substream);
537         /* FIXME: we should consider the boundary for the sync from app */
538         if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
539                 control->appl_ptr = scontrol.appl_ptr;
540         else
541                 scontrol.appl_ptr = control->appl_ptr % boundary;
542         if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
543                 control->avail_min = scontrol.avail_min;
544         else
545                 scontrol.avail_min = control->avail_min;
546         sstatus.state = status->state;
547         sstatus.hw_ptr = status->hw_ptr % boundary;
548         sstatus.tstamp = status->tstamp;
549         sstatus.suspended_state = status->suspended_state;
550         sstatus.audio_tstamp = status->audio_tstamp;
551         snd_pcm_stream_unlock_irq(substream);
552         if (put_user(sstatus.state, &src->s.status.state) ||
553             put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) ||
554             put_timespec(&sstatus.tstamp, &src->s.status.tstamp) ||
555             put_user(sstatus.suspended_state, &src->s.status.suspended_state) ||
556             put_timespec(&sstatus.audio_tstamp, &src->s.status.audio_tstamp) ||
557             put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
558             put_user(scontrol.avail_min, &src->c.control.avail_min))
559                 return -EFAULT;
560
561         return 0;
562 }
563 #endif /* CONFIG_X86_X32 */
564
565 /*
566  */
567 enum {
568         SNDRV_PCM_IOCTL_HW_REFINE32 = _IOWR('A', 0x10, struct snd_pcm_hw_params32),
569         SNDRV_PCM_IOCTL_HW_PARAMS32 = _IOWR('A', 0x11, struct snd_pcm_hw_params32),
570         SNDRV_PCM_IOCTL_SW_PARAMS32 = _IOWR('A', 0x13, struct snd_pcm_sw_params32),
571         SNDRV_PCM_IOCTL_STATUS_COMPAT32 = _IOR('A', 0x20, struct snd_pcm_status32),
572         SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT32 = _IOWR('A', 0x24, struct snd_pcm_status32),
573         SNDRV_PCM_IOCTL_DELAY32 = _IOR('A', 0x21, s32),
574         SNDRV_PCM_IOCTL_CHANNEL_INFO32 = _IOR('A', 0x32, struct snd_pcm_channel_info32),
575         SNDRV_PCM_IOCTL_REWIND32 = _IOW('A', 0x46, u32),
576         SNDRV_PCM_IOCTL_FORWARD32 = _IOW('A', 0x49, u32),
577         SNDRV_PCM_IOCTL_WRITEI_FRAMES32 = _IOW('A', 0x50, struct snd_xferi32),
578         SNDRV_PCM_IOCTL_READI_FRAMES32 = _IOR('A', 0x51, struct snd_xferi32),
579         SNDRV_PCM_IOCTL_WRITEN_FRAMES32 = _IOW('A', 0x52, struct snd_xfern32),
580         SNDRV_PCM_IOCTL_READN_FRAMES32 = _IOR('A', 0x53, struct snd_xfern32),
581         SNDRV_PCM_IOCTL_SYNC_PTR32 = _IOWR('A', 0x23, struct snd_pcm_sync_ptr32),
582         SNDRV_PCM_IOCTL_STATUS_COMPAT64 = _IOR('A', 0x20, struct compat_snd_pcm_status64),
583         SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT64 = _IOWR('A', 0x24, struct compat_snd_pcm_status64),
584 #ifdef CONFIG_X86_X32
585         SNDRV_PCM_IOCTL_CHANNEL_INFO_X32 = _IOR('A', 0x32, struct snd_pcm_channel_info),
586         SNDRV_PCM_IOCTL_SYNC_PTR_X32 = _IOWR('A', 0x23, struct snd_pcm_sync_ptr_x32),
587 #endif /* CONFIG_X86_X32 */
588 };
589
590 static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
591 {
592         struct snd_pcm_file *pcm_file;
593         struct snd_pcm_substream *substream;
594         void __user *argp = compat_ptr(arg);
595
596         pcm_file = file->private_data;
597         if (! pcm_file)
598                 return -ENOTTY;
599         substream = pcm_file->substream;
600         if (! substream)
601                 return -ENOTTY;
602
603         /*
604          * When PCM is used on 32bit mode, we need to disable
605          * mmap of PCM status/control records because of the size
606          * incompatibility.
607          */
608         pcm_file->no_compat_mmap = 1;
609
610         switch (cmd) {
611         case SNDRV_PCM_IOCTL_PVERSION:
612         case SNDRV_PCM_IOCTL_INFO:
613         case SNDRV_PCM_IOCTL_TSTAMP:
614         case SNDRV_PCM_IOCTL_TTSTAMP:
615         case SNDRV_PCM_IOCTL_USER_PVERSION:
616         case SNDRV_PCM_IOCTL_HWSYNC:
617         case SNDRV_PCM_IOCTL_PREPARE:
618         case SNDRV_PCM_IOCTL_RESET:
619         case SNDRV_PCM_IOCTL_START:
620         case SNDRV_PCM_IOCTL_DROP:
621         case SNDRV_PCM_IOCTL_DRAIN:
622         case SNDRV_PCM_IOCTL_PAUSE:
623         case SNDRV_PCM_IOCTL_HW_FREE:
624         case SNDRV_PCM_IOCTL_RESUME:
625         case SNDRV_PCM_IOCTL_XRUN:
626         case SNDRV_PCM_IOCTL_LINK:
627         case SNDRV_PCM_IOCTL_UNLINK:
628                 return snd_pcm_common_ioctl(file, substream, cmd, argp);
629         case SNDRV_PCM_IOCTL_HW_REFINE32:
630                 return snd_pcm_ioctl_hw_params_compat(substream, 1, argp);
631         case SNDRV_PCM_IOCTL_HW_PARAMS32:
632                 return snd_pcm_ioctl_hw_params_compat(substream, 0, argp);
633         case SNDRV_PCM_IOCTL_SW_PARAMS32:
634                 return snd_pcm_ioctl_sw_params_compat(substream, argp);
635         case SNDRV_PCM_IOCTL_STATUS_COMPAT32:
636                 return snd_pcm_status_user32(substream, argp, false);
637         case SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT32:
638                 return snd_pcm_status_user32(substream, argp, true);
639         case SNDRV_PCM_IOCTL_SYNC_PTR32:
640                 return snd_pcm_ioctl_sync_ptr_compat(substream, argp);
641         case SNDRV_PCM_IOCTL_CHANNEL_INFO32:
642                 return snd_pcm_ioctl_channel_info_compat(substream, argp);
643         case SNDRV_PCM_IOCTL_WRITEI_FRAMES32:
644                 return snd_pcm_ioctl_xferi_compat(substream, SNDRV_PCM_STREAM_PLAYBACK, argp);
645         case SNDRV_PCM_IOCTL_READI_FRAMES32:
646                 return snd_pcm_ioctl_xferi_compat(substream, SNDRV_PCM_STREAM_CAPTURE, argp);
647         case SNDRV_PCM_IOCTL_WRITEN_FRAMES32:
648                 return snd_pcm_ioctl_xfern_compat(substream, SNDRV_PCM_STREAM_PLAYBACK, argp);
649         case SNDRV_PCM_IOCTL_READN_FRAMES32:
650                 return snd_pcm_ioctl_xfern_compat(substream, SNDRV_PCM_STREAM_CAPTURE, argp);
651         case SNDRV_PCM_IOCTL_DELAY32:
652                 return snd_pcm_ioctl_delay_compat(substream, argp);
653         case SNDRV_PCM_IOCTL_REWIND32:
654                 return snd_pcm_ioctl_rewind_compat(substream, argp);
655         case SNDRV_PCM_IOCTL_FORWARD32:
656                 return snd_pcm_ioctl_forward_compat(substream, argp);
657         case SNDRV_PCM_IOCTL_STATUS_COMPAT64:
658                 return snd_pcm_status_user_compat64(substream, argp, false);
659         case SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT64:
660                 return snd_pcm_status_user_compat64(substream, argp, true);
661 #ifdef CONFIG_X86_X32
662         case SNDRV_PCM_IOCTL_SYNC_PTR_X32:
663                 return snd_pcm_ioctl_sync_ptr_x32(substream, argp);
664         case SNDRV_PCM_IOCTL_CHANNEL_INFO_X32:
665                 return snd_pcm_ioctl_channel_info_x32(substream, argp);
666 #endif /* CONFIG_X86_X32 */
667         }
668
669         return -ENOIOCTLCMD;
670 }