| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * 32bit -> 64bit ioctl wrapper for PCM API |
|---|
| 3 | 4 | * Copyright (c) by Takashi Iwai <tiwai@suse.de> |
|---|
| 4 | | - * |
|---|
| 5 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 6 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 7 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 8 | | - * (at your option) any later version. |
|---|
| 9 | | - * |
|---|
| 10 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 11 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 13 | | - * GNU General Public License for more details. |
|---|
| 14 | | - * |
|---|
| 15 | | - * You should have received a copy of the GNU General Public License |
|---|
| 16 | | - * along with this program; if not, write to the Free Software |
|---|
| 17 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 18 | | - * |
|---|
| 19 | 5 | */ |
|---|
| 20 | 6 | |
|---|
| 21 | 7 | /* This file included from pcm_native.c */ |
|---|
| .. | .. |
|---|
| 97 | 83 | unsigned char reserved[56]; |
|---|
| 98 | 84 | }; |
|---|
| 99 | 85 | |
|---|
| 100 | | -/* recalcuate the boundary within 32bit */ |
|---|
| 101 | | -static snd_pcm_uframes_t recalculate_boundary(struct snd_pcm_runtime *runtime) |
|---|
| 102 | | -{ |
|---|
| 103 | | - snd_pcm_uframes_t boundary; |
|---|
| 104 | | - |
|---|
| 105 | | - if (! runtime->buffer_size) |
|---|
| 106 | | - return 0; |
|---|
| 107 | | - boundary = runtime->buffer_size; |
|---|
| 108 | | - while (boundary * 2 <= 0x7fffffffUL - runtime->buffer_size) |
|---|
| 109 | | - boundary *= 2; |
|---|
| 110 | | - return boundary; |
|---|
| 111 | | -} |
|---|
| 112 | | - |
|---|
| 113 | 86 | static int snd_pcm_ioctl_sw_params_compat(struct snd_pcm_substream *substream, |
|---|
| 114 | 87 | struct snd_pcm_sw_params32 __user *src) |
|---|
| 115 | 88 | { |
|---|
| .. | .. |
|---|
| 182 | 155 | snd_pcm_channel_info_user(s, p) |
|---|
| 183 | 156 | #endif /* CONFIG_X86_X32 */ |
|---|
| 184 | 157 | |
|---|
| 185 | | -struct snd_pcm_status32 { |
|---|
| 186 | | - s32 state; |
|---|
| 187 | | - struct compat_timespec trigger_tstamp; |
|---|
| 188 | | - struct compat_timespec tstamp; |
|---|
| 158 | +struct 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; |
|---|
| 189 | 165 | u32 appl_ptr; |
|---|
| 190 | 166 | u32 hw_ptr; |
|---|
| 191 | 167 | s32 delay; |
|---|
| 192 | 168 | u32 avail; |
|---|
| 193 | 169 | u32 avail_max; |
|---|
| 194 | 170 | u32 overrange; |
|---|
| 195 | | - s32 suspended_state; |
|---|
| 171 | + snd_pcm_state_t suspended_state; |
|---|
| 196 | 172 | u32 audio_tstamp_data; |
|---|
| 197 | | - struct compat_timespec audio_tstamp; |
|---|
| 198 | | - struct compat_timespec driver_tstamp; |
|---|
| 173 | + s64 audio_tstamp_sec; |
|---|
| 174 | + s64 audio_tstamp_nsec; |
|---|
| 175 | + s64 driver_tstamp_sec; |
|---|
| 176 | + s64 driver_tstamp_nsec; |
|---|
| 199 | 177 | u32 audio_tstamp_accuracy; |
|---|
| 200 | | - unsigned char reserved[52-2*sizeof(struct compat_timespec)]; |
|---|
| 201 | | -} __attribute__((packed)); |
|---|
| 202 | | - |
|---|
| 203 | | - |
|---|
| 204 | | -static int snd_pcm_status_user_compat(struct snd_pcm_substream *substream, |
|---|
| 205 | | - struct snd_pcm_status32 __user *src, |
|---|
| 206 | | - bool ext) |
|---|
| 207 | | -{ |
|---|
| 208 | | - struct snd_pcm_status status; |
|---|
| 209 | | - int err; |
|---|
| 210 | | - |
|---|
| 211 | | - memset(&status, 0, sizeof(status)); |
|---|
| 212 | | - /* |
|---|
| 213 | | - * with extension, parameters are read/write, |
|---|
| 214 | | - * get audio_tstamp_data from user, |
|---|
| 215 | | - * ignore rest of status structure |
|---|
| 216 | | - */ |
|---|
| 217 | | - if (ext && get_user(status.audio_tstamp_data, |
|---|
| 218 | | - (u32 __user *)(&src->audio_tstamp_data))) |
|---|
| 219 | | - return -EFAULT; |
|---|
| 220 | | - err = snd_pcm_status(substream, &status); |
|---|
| 221 | | - if (err < 0) |
|---|
| 222 | | - return err; |
|---|
| 223 | | - |
|---|
| 224 | | - if (clear_user(src, sizeof(*src))) |
|---|
| 225 | | - return -EFAULT; |
|---|
| 226 | | - if (put_user(status.state, &src->state) || |
|---|
| 227 | | - compat_put_timespec(&status.trigger_tstamp, &src->trigger_tstamp) || |
|---|
| 228 | | - compat_put_timespec(&status.tstamp, &src->tstamp) || |
|---|
| 229 | | - put_user(status.appl_ptr, &src->appl_ptr) || |
|---|
| 230 | | - put_user(status.hw_ptr, &src->hw_ptr) || |
|---|
| 231 | | - put_user(status.delay, &src->delay) || |
|---|
| 232 | | - put_user(status.avail, &src->avail) || |
|---|
| 233 | | - put_user(status.avail_max, &src->avail_max) || |
|---|
| 234 | | - put_user(status.overrange, &src->overrange) || |
|---|
| 235 | | - put_user(status.suspended_state, &src->suspended_state) || |
|---|
| 236 | | - put_user(status.audio_tstamp_data, &src->audio_tstamp_data) || |
|---|
| 237 | | - compat_put_timespec(&status.audio_tstamp, &src->audio_tstamp) || |
|---|
| 238 | | - compat_put_timespec(&status.driver_tstamp, &src->driver_tstamp) || |
|---|
| 239 | | - put_user(status.audio_tstamp_accuracy, &src->audio_tstamp_accuracy)) |
|---|
| 240 | | - return -EFAULT; |
|---|
| 241 | | - |
|---|
| 242 | | - return err; |
|---|
| 243 | | -} |
|---|
| 244 | | - |
|---|
| 245 | | -#ifdef CONFIG_X86_X32 |
|---|
| 246 | | -/* X32 ABI has 64bit timespec and 64bit alignment */ |
|---|
| 247 | | -struct snd_pcm_status_x32 { |
|---|
| 248 | | - s32 state; |
|---|
| 249 | | - u32 rsvd; /* alignment */ |
|---|
| 250 | | - struct timespec trigger_tstamp; |
|---|
| 251 | | - struct timespec tstamp; |
|---|
| 252 | | - u32 appl_ptr; |
|---|
| 253 | | - u32 hw_ptr; |
|---|
| 254 | | - s32 delay; |
|---|
| 255 | | - u32 avail; |
|---|
| 256 | | - u32 avail_max; |
|---|
| 257 | | - u32 overrange; |
|---|
| 258 | | - s32 suspended_state; |
|---|
| 259 | | - u32 audio_tstamp_data; |
|---|
| 260 | | - struct timespec audio_tstamp; |
|---|
| 261 | | - struct timespec driver_tstamp; |
|---|
| 262 | | - u32 audio_tstamp_accuracy; |
|---|
| 263 | | - unsigned char reserved[52-2*sizeof(struct timespec)]; |
|---|
| 178 | + unsigned char reserved[52-4*sizeof(s64)]; |
|---|
| 264 | 179 | } __packed; |
|---|
| 265 | 180 | |
|---|
| 266 | | -#define put_timespec(src, dst) copy_to_user(dst, src, sizeof(*dst)) |
|---|
| 267 | | - |
|---|
| 268 | | -static int snd_pcm_status_user_x32(struct snd_pcm_substream *substream, |
|---|
| 269 | | - struct snd_pcm_status_x32 __user *src, |
|---|
| 270 | | - bool ext) |
|---|
| 181 | +static int snd_pcm_status_user_compat64(struct snd_pcm_substream *substream, |
|---|
| 182 | + struct compat_snd_pcm_status64 __user *src, |
|---|
| 183 | + bool ext) |
|---|
| 271 | 184 | { |
|---|
| 272 | | - struct snd_pcm_status status; |
|---|
| 185 | + struct snd_pcm_status64 status; |
|---|
| 186 | + struct compat_snd_pcm_status64 compat_status64; |
|---|
| 273 | 187 | int err; |
|---|
| 274 | 188 | |
|---|
| 275 | 189 | memset(&status, 0, sizeof(status)); |
|---|
| 190 | + memset(&compat_status64, 0, sizeof(compat_status64)); |
|---|
| 276 | 191 | /* |
|---|
| 277 | 192 | * with extension, parameters are read/write, |
|---|
| 278 | 193 | * get audio_tstamp_data from user, |
|---|
| .. | .. |
|---|
| 281 | 196 | if (ext && get_user(status.audio_tstamp_data, |
|---|
| 282 | 197 | (u32 __user *)(&src->audio_tstamp_data))) |
|---|
| 283 | 198 | return -EFAULT; |
|---|
| 284 | | - err = snd_pcm_status(substream, &status); |
|---|
| 199 | + err = snd_pcm_status64(substream, &status); |
|---|
| 285 | 200 | if (err < 0) |
|---|
| 286 | 201 | return err; |
|---|
| 287 | 202 | |
|---|
| 288 | 203 | if (clear_user(src, sizeof(*src))) |
|---|
| 289 | 204 | return -EFAULT; |
|---|
| 290 | | - if (put_user(status.state, &src->state) || |
|---|
| 291 | | - put_timespec(&status.trigger_tstamp, &src->trigger_tstamp) || |
|---|
| 292 | | - put_timespec(&status.tstamp, &src->tstamp) || |
|---|
| 293 | | - put_user(status.appl_ptr, &src->appl_ptr) || |
|---|
| 294 | | - put_user(status.hw_ptr, &src->hw_ptr) || |
|---|
| 295 | | - put_user(status.delay, &src->delay) || |
|---|
| 296 | | - put_user(status.avail, &src->avail) || |
|---|
| 297 | | - put_user(status.avail_max, &src->avail_max) || |
|---|
| 298 | | - put_user(status.overrange, &src->overrange) || |
|---|
| 299 | | - put_user(status.suspended_state, &src->suspended_state) || |
|---|
| 300 | | - put_user(status.audio_tstamp_data, &src->audio_tstamp_data) || |
|---|
| 301 | | - put_timespec(&status.audio_tstamp, &src->audio_tstamp) || |
|---|
| 302 | | - put_timespec(&status.driver_tstamp, &src->driver_tstamp) || |
|---|
| 303 | | - put_user(status.audio_tstamp_accuracy, &src->audio_tstamp_accuracy)) |
|---|
| 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))) |
|---|
| 304 | 228 | return -EFAULT; |
|---|
| 305 | 229 | |
|---|
| 306 | 230 | return err; |
|---|
| 307 | 231 | } |
|---|
| 308 | | -#endif /* CONFIG_X86_X32 */ |
|---|
| 309 | 232 | |
|---|
| 310 | 233 | /* both for HW_PARAMS and HW_REFINE */ |
|---|
| 311 | 234 | static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream, |
|---|
| .. | .. |
|---|
| 450 | 373 | return err; |
|---|
| 451 | 374 | } |
|---|
| 452 | 375 | |
|---|
| 453 | | - |
|---|
| 454 | | -struct snd_pcm_mmap_status32 { |
|---|
| 455 | | - s32 state; |
|---|
| 456 | | - s32 pad1; |
|---|
| 457 | | - u32 hw_ptr; |
|---|
| 458 | | - struct compat_timespec tstamp; |
|---|
| 459 | | - s32 suspended_state; |
|---|
| 460 | | - struct compat_timespec audio_tstamp; |
|---|
| 461 | | -} __attribute__((packed)); |
|---|
| 462 | | - |
|---|
| 463 | | -struct snd_pcm_mmap_control32 { |
|---|
| 464 | | - u32 appl_ptr; |
|---|
| 465 | | - u32 avail_min; |
|---|
| 466 | | -}; |
|---|
| 467 | | - |
|---|
| 468 | | -struct snd_pcm_sync_ptr32 { |
|---|
| 469 | | - u32 flags; |
|---|
| 470 | | - union { |
|---|
| 471 | | - struct snd_pcm_mmap_status32 status; |
|---|
| 472 | | - unsigned char reserved[64]; |
|---|
| 473 | | - } s; |
|---|
| 474 | | - union { |
|---|
| 475 | | - struct snd_pcm_mmap_control32 control; |
|---|
| 476 | | - unsigned char reserved[64]; |
|---|
| 477 | | - } c; |
|---|
| 478 | | -} __attribute__((packed)); |
|---|
| 479 | | - |
|---|
| 480 | | -static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream, |
|---|
| 481 | | - struct snd_pcm_sync_ptr32 __user *src) |
|---|
| 482 | | -{ |
|---|
| 483 | | - struct snd_pcm_runtime *runtime = substream->runtime; |
|---|
| 484 | | - volatile struct snd_pcm_mmap_status *status; |
|---|
| 485 | | - volatile struct snd_pcm_mmap_control *control; |
|---|
| 486 | | - u32 sflags; |
|---|
| 487 | | - struct snd_pcm_mmap_control scontrol; |
|---|
| 488 | | - struct snd_pcm_mmap_status sstatus; |
|---|
| 489 | | - snd_pcm_uframes_t boundary; |
|---|
| 490 | | - int err; |
|---|
| 491 | | - |
|---|
| 492 | | - if (snd_BUG_ON(!runtime)) |
|---|
| 493 | | - return -EINVAL; |
|---|
| 494 | | - |
|---|
| 495 | | - if (get_user(sflags, &src->flags) || |
|---|
| 496 | | - get_user(scontrol.appl_ptr, &src->c.control.appl_ptr) || |
|---|
| 497 | | - get_user(scontrol.avail_min, &src->c.control.avail_min)) |
|---|
| 498 | | - return -EFAULT; |
|---|
| 499 | | - if (sflags & SNDRV_PCM_SYNC_PTR_HWSYNC) { |
|---|
| 500 | | - err = snd_pcm_hwsync(substream); |
|---|
| 501 | | - if (err < 0) |
|---|
| 502 | | - return err; |
|---|
| 503 | | - } |
|---|
| 504 | | - status = runtime->status; |
|---|
| 505 | | - control = runtime->control; |
|---|
| 506 | | - boundary = recalculate_boundary(runtime); |
|---|
| 507 | | - if (! boundary) |
|---|
| 508 | | - boundary = 0x7fffffff; |
|---|
| 509 | | - snd_pcm_stream_lock_irq(substream); |
|---|
| 510 | | - /* FIXME: we should consider the boundary for the sync from app */ |
|---|
| 511 | | - if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) |
|---|
| 512 | | - control->appl_ptr = scontrol.appl_ptr; |
|---|
| 513 | | - else |
|---|
| 514 | | - scontrol.appl_ptr = control->appl_ptr % boundary; |
|---|
| 515 | | - if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) |
|---|
| 516 | | - control->avail_min = scontrol.avail_min; |
|---|
| 517 | | - else |
|---|
| 518 | | - scontrol.avail_min = control->avail_min; |
|---|
| 519 | | - sstatus.state = status->state; |
|---|
| 520 | | - sstatus.hw_ptr = status->hw_ptr % boundary; |
|---|
| 521 | | - sstatus.tstamp = status->tstamp; |
|---|
| 522 | | - sstatus.suspended_state = status->suspended_state; |
|---|
| 523 | | - sstatus.audio_tstamp = status->audio_tstamp; |
|---|
| 524 | | - snd_pcm_stream_unlock_irq(substream); |
|---|
| 525 | | - if (put_user(sstatus.state, &src->s.status.state) || |
|---|
| 526 | | - put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) || |
|---|
| 527 | | - compat_put_timespec(&sstatus.tstamp, &src->s.status.tstamp) || |
|---|
| 528 | | - put_user(sstatus.suspended_state, &src->s.status.suspended_state) || |
|---|
| 529 | | - compat_put_timespec(&sstatus.audio_tstamp, |
|---|
| 530 | | - &src->s.status.audio_tstamp) || |
|---|
| 531 | | - put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) || |
|---|
| 532 | | - put_user(scontrol.avail_min, &src->c.control.avail_min)) |
|---|
| 533 | | - return -EFAULT; |
|---|
| 534 | | - |
|---|
| 535 | | - return 0; |
|---|
| 536 | | -} |
|---|
| 537 | | - |
|---|
| 538 | 376 | #ifdef CONFIG_X86_X32 |
|---|
| 539 | 377 | /* X32 ABI has 64bit timespec and 64bit alignment */ |
|---|
| 540 | 378 | struct snd_pcm_mmap_status_x32 { |
|---|
| 541 | | - s32 state; |
|---|
| 379 | + snd_pcm_state_t state; |
|---|
| 542 | 380 | s32 pad1; |
|---|
| 543 | 381 | u32 hw_ptr; |
|---|
| 544 | 382 | u32 pad2; /* alignment */ |
|---|
| 545 | | - struct timespec tstamp; |
|---|
| 546 | | - s32 suspended_state; |
|---|
| 383 | + s64 tstamp_sec; |
|---|
| 384 | + s64 tstamp_nsec; |
|---|
| 385 | + snd_pcm_state_t suspended_state; |
|---|
| 547 | 386 | s32 pad3; |
|---|
| 548 | | - struct timespec audio_tstamp; |
|---|
| 387 | + s64 audio_tstamp_sec; |
|---|
| 388 | + s64 audio_tstamp_nsec; |
|---|
| 549 | 389 | } __packed; |
|---|
| 550 | 390 | |
|---|
| 551 | 391 | struct snd_pcm_mmap_control_x32 { |
|---|
| .. | .. |
|---|
| 613 | 453 | snd_pcm_stream_unlock_irq(substream); |
|---|
| 614 | 454 | if (put_user(sstatus.state, &src->s.status.state) || |
|---|
| 615 | 455 | put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) || |
|---|
| 616 | | - put_timespec(&sstatus.tstamp, &src->s.status.tstamp) || |
|---|
| 456 | + put_user(sstatus.tstamp.tv_sec, &src->s.status.tstamp_sec) || |
|---|
| 457 | + put_user(sstatus.tstamp.tv_nsec, &src->s.status.tstamp_nsec) || |
|---|
| 617 | 458 | put_user(sstatus.suspended_state, &src->s.status.suspended_state) || |
|---|
| 618 | | - put_timespec(&sstatus.audio_tstamp, &src->s.status.audio_tstamp) || |
|---|
| 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) || |
|---|
| 619 | 461 | put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) || |
|---|
| 620 | 462 | put_user(scontrol.avail_min, &src->c.control.avail_min)) |
|---|
| 621 | 463 | return -EFAULT; |
|---|
| .. | .. |
|---|
| 624 | 466 | } |
|---|
| 625 | 467 | #endif /* CONFIG_X86_X32 */ |
|---|
| 626 | 468 | |
|---|
| 469 | +#ifdef __BIG_ENDIAN |
|---|
| 470 | +typedef char __pad_before_u32[4]; |
|---|
| 471 | +typedef char __pad_after_u32[0]; |
|---|
| 472 | +#else |
|---|
| 473 | +typedef char __pad_before_u32[0]; |
|---|
| 474 | +typedef char __pad_after_u32[4]; |
|---|
| 475 | +#endif |
|---|
| 476 | + |
|---|
| 477 | +/* PCM 2.0.15 API definition had a bug in mmap control; it puts the avail_min |
|---|
| 478 | + * at the wrong offset due to a typo in padding type. |
|---|
| 479 | + * The bug hits only 32bit. |
|---|
| 480 | + * A workaround for incorrect read/write is needed only in 32bit compat mode. |
|---|
| 481 | + */ |
|---|
| 482 | +struct __snd_pcm_mmap_control64_buggy { |
|---|
| 483 | + __pad_before_u32 __pad1; |
|---|
| 484 | + __u32 appl_ptr; |
|---|
| 485 | + __pad_before_u32 __pad2; /* SiC! here is the bug */ |
|---|
| 486 | + __pad_before_u32 __pad3; |
|---|
| 487 | + __u32 avail_min; |
|---|
| 488 | + __pad_after_uframe __pad4; |
|---|
| 489 | +}; |
|---|
| 490 | + |
|---|
| 491 | +static int snd_pcm_ioctl_sync_ptr_buggy(struct snd_pcm_substream *substream, |
|---|
| 492 | + struct snd_pcm_sync_ptr __user *_sync_ptr) |
|---|
| 493 | +{ |
|---|
| 494 | + struct snd_pcm_runtime *runtime = substream->runtime; |
|---|
| 495 | + struct snd_pcm_sync_ptr sync_ptr; |
|---|
| 496 | + struct __snd_pcm_mmap_control64_buggy *sync_cp; |
|---|
| 497 | + volatile struct snd_pcm_mmap_status *status; |
|---|
| 498 | + volatile struct snd_pcm_mmap_control *control; |
|---|
| 499 | + int err; |
|---|
| 500 | + |
|---|
| 501 | + memset(&sync_ptr, 0, sizeof(sync_ptr)); |
|---|
| 502 | + sync_cp = (struct __snd_pcm_mmap_control64_buggy *)&sync_ptr.c.control; |
|---|
| 503 | + if (get_user(sync_ptr.flags, (unsigned __user *)&(_sync_ptr->flags))) |
|---|
| 504 | + return -EFAULT; |
|---|
| 505 | + if (copy_from_user(sync_cp, &(_sync_ptr->c.control), sizeof(*sync_cp))) |
|---|
| 506 | + return -EFAULT; |
|---|
| 507 | + status = runtime->status; |
|---|
| 508 | + control = runtime->control; |
|---|
| 509 | + if (sync_ptr.flags & SNDRV_PCM_SYNC_PTR_HWSYNC) { |
|---|
| 510 | + err = snd_pcm_hwsync(substream); |
|---|
| 511 | + if (err < 0) |
|---|
| 512 | + return err; |
|---|
| 513 | + } |
|---|
| 514 | + snd_pcm_stream_lock_irq(substream); |
|---|
| 515 | + if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) { |
|---|
| 516 | + err = pcm_lib_apply_appl_ptr(substream, sync_cp->appl_ptr); |
|---|
| 517 | + if (err < 0) { |
|---|
| 518 | + snd_pcm_stream_unlock_irq(substream); |
|---|
| 519 | + return err; |
|---|
| 520 | + } |
|---|
| 521 | + } else { |
|---|
| 522 | + sync_cp->appl_ptr = control->appl_ptr; |
|---|
| 523 | + } |
|---|
| 524 | + if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) |
|---|
| 525 | + control->avail_min = sync_cp->avail_min; |
|---|
| 526 | + else |
|---|
| 527 | + sync_cp->avail_min = control->avail_min; |
|---|
| 528 | + sync_ptr.s.status.state = status->state; |
|---|
| 529 | + sync_ptr.s.status.hw_ptr = status->hw_ptr; |
|---|
| 530 | + sync_ptr.s.status.tstamp = status->tstamp; |
|---|
| 531 | + sync_ptr.s.status.suspended_state = status->suspended_state; |
|---|
| 532 | + sync_ptr.s.status.audio_tstamp = status->audio_tstamp; |
|---|
| 533 | + snd_pcm_stream_unlock_irq(substream); |
|---|
| 534 | + if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr))) |
|---|
| 535 | + return -EFAULT; |
|---|
| 536 | + return 0; |
|---|
| 537 | +} |
|---|
| 538 | + |
|---|
| 627 | 539 | /* |
|---|
| 628 | 540 | */ |
|---|
| 629 | 541 | enum { |
|---|
| 630 | 542 | SNDRV_PCM_IOCTL_HW_REFINE32 = _IOWR('A', 0x10, struct snd_pcm_hw_params32), |
|---|
| 631 | 543 | SNDRV_PCM_IOCTL_HW_PARAMS32 = _IOWR('A', 0x11, struct snd_pcm_hw_params32), |
|---|
| 632 | 544 | SNDRV_PCM_IOCTL_SW_PARAMS32 = _IOWR('A', 0x13, struct snd_pcm_sw_params32), |
|---|
| 633 | | - SNDRV_PCM_IOCTL_STATUS32 = _IOR('A', 0x20, struct snd_pcm_status32), |
|---|
| 634 | | - SNDRV_PCM_IOCTL_STATUS_EXT32 = _IOWR('A', 0x24, struct snd_pcm_status32), |
|---|
| 545 | + SNDRV_PCM_IOCTL_STATUS_COMPAT32 = _IOR('A', 0x20, struct snd_pcm_status32), |
|---|
| 546 | + SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT32 = _IOWR('A', 0x24, struct snd_pcm_status32), |
|---|
| 635 | 547 | SNDRV_PCM_IOCTL_DELAY32 = _IOR('A', 0x21, s32), |
|---|
| 636 | 548 | SNDRV_PCM_IOCTL_CHANNEL_INFO32 = _IOR('A', 0x32, struct snd_pcm_channel_info32), |
|---|
| 637 | 549 | SNDRV_PCM_IOCTL_REWIND32 = _IOW('A', 0x46, u32), |
|---|
| .. | .. |
|---|
| 640 | 552 | SNDRV_PCM_IOCTL_READI_FRAMES32 = _IOR('A', 0x51, struct snd_xferi32), |
|---|
| 641 | 553 | SNDRV_PCM_IOCTL_WRITEN_FRAMES32 = _IOW('A', 0x52, struct snd_xfern32), |
|---|
| 642 | 554 | SNDRV_PCM_IOCTL_READN_FRAMES32 = _IOR('A', 0x53, struct snd_xfern32), |
|---|
| 643 | | - SNDRV_PCM_IOCTL_SYNC_PTR32 = _IOWR('A', 0x23, struct snd_pcm_sync_ptr32), |
|---|
| 555 | + SNDRV_PCM_IOCTL_STATUS_COMPAT64 = _IOR('A', 0x20, struct compat_snd_pcm_status64), |
|---|
| 556 | + SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT64 = _IOWR('A', 0x24, struct compat_snd_pcm_status64), |
|---|
| 644 | 557 | #ifdef CONFIG_X86_X32 |
|---|
| 645 | 558 | SNDRV_PCM_IOCTL_CHANNEL_INFO_X32 = _IOR('A', 0x32, struct snd_pcm_channel_info), |
|---|
| 646 | | - SNDRV_PCM_IOCTL_STATUS_X32 = _IOR('A', 0x20, struct snd_pcm_status_x32), |
|---|
| 647 | | - SNDRV_PCM_IOCTL_STATUS_EXT_X32 = _IOWR('A', 0x24, struct snd_pcm_status_x32), |
|---|
| 648 | 559 | SNDRV_PCM_IOCTL_SYNC_PTR_X32 = _IOWR('A', 0x23, struct snd_pcm_sync_ptr_x32), |
|---|
| 649 | 560 | #endif /* CONFIG_X86_X32 */ |
|---|
| 650 | 561 | }; |
|---|
| .. | .. |
|---|
| 664 | 575 | |
|---|
| 665 | 576 | /* |
|---|
| 666 | 577 | * When PCM is used on 32bit mode, we need to disable |
|---|
| 667 | | - * mmap of PCM status/control records because of the size |
|---|
| 668 | | - * incompatibility. |
|---|
| 578 | + * mmap of the old PCM status/control records because |
|---|
| 579 | + * of the size incompatibility. |
|---|
| 669 | 580 | */ |
|---|
| 670 | 581 | pcm_file->no_compat_mmap = 1; |
|---|
| 671 | 582 | |
|---|
| .. | .. |
|---|
| 687 | 598 | case SNDRV_PCM_IOCTL_XRUN: |
|---|
| 688 | 599 | case SNDRV_PCM_IOCTL_LINK: |
|---|
| 689 | 600 | case SNDRV_PCM_IOCTL_UNLINK: |
|---|
| 601 | + case __SNDRV_PCM_IOCTL_SYNC_PTR32: |
|---|
| 690 | 602 | return snd_pcm_common_ioctl(file, substream, cmd, argp); |
|---|
| 603 | + case __SNDRV_PCM_IOCTL_SYNC_PTR64: |
|---|
| 604 | +#ifdef CONFIG_X86_X32 |
|---|
| 605 | + if (in_x32_syscall()) |
|---|
| 606 | + return snd_pcm_ioctl_sync_ptr_x32(substream, argp); |
|---|
| 607 | +#endif /* CONFIG_X86_X32 */ |
|---|
| 608 | + return snd_pcm_ioctl_sync_ptr_buggy(substream, argp); |
|---|
| 691 | 609 | case SNDRV_PCM_IOCTL_HW_REFINE32: |
|---|
| 692 | 610 | return snd_pcm_ioctl_hw_params_compat(substream, 1, argp); |
|---|
| 693 | 611 | case SNDRV_PCM_IOCTL_HW_PARAMS32: |
|---|
| 694 | 612 | return snd_pcm_ioctl_hw_params_compat(substream, 0, argp); |
|---|
| 695 | 613 | case SNDRV_PCM_IOCTL_SW_PARAMS32: |
|---|
| 696 | 614 | return snd_pcm_ioctl_sw_params_compat(substream, argp); |
|---|
| 697 | | - case SNDRV_PCM_IOCTL_STATUS32: |
|---|
| 698 | | - return snd_pcm_status_user_compat(substream, argp, false); |
|---|
| 699 | | - case SNDRV_PCM_IOCTL_STATUS_EXT32: |
|---|
| 700 | | - return snd_pcm_status_user_compat(substream, argp, true); |
|---|
| 701 | | - case SNDRV_PCM_IOCTL_SYNC_PTR32: |
|---|
| 702 | | - return snd_pcm_ioctl_sync_ptr_compat(substream, argp); |
|---|
| 615 | + case SNDRV_PCM_IOCTL_STATUS_COMPAT32: |
|---|
| 616 | + return snd_pcm_status_user32(substream, argp, false); |
|---|
| 617 | + case SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT32: |
|---|
| 618 | + return snd_pcm_status_user32(substream, argp, true); |
|---|
| 703 | 619 | case SNDRV_PCM_IOCTL_CHANNEL_INFO32: |
|---|
| 704 | 620 | return snd_pcm_ioctl_channel_info_compat(substream, argp); |
|---|
| 705 | 621 | case SNDRV_PCM_IOCTL_WRITEI_FRAMES32: |
|---|
| .. | .. |
|---|
| 716 | 632 | return snd_pcm_ioctl_rewind_compat(substream, argp); |
|---|
| 717 | 633 | case SNDRV_PCM_IOCTL_FORWARD32: |
|---|
| 718 | 634 | return snd_pcm_ioctl_forward_compat(substream, argp); |
|---|
| 635 | + case SNDRV_PCM_IOCTL_STATUS_COMPAT64: |
|---|
| 636 | + return snd_pcm_status_user_compat64(substream, argp, false); |
|---|
| 637 | + case SNDRV_PCM_IOCTL_STATUS_EXT_COMPAT64: |
|---|
| 638 | + return snd_pcm_status_user_compat64(substream, argp, true); |
|---|
| 719 | 639 | #ifdef CONFIG_X86_X32 |
|---|
| 720 | | - case SNDRV_PCM_IOCTL_STATUS_X32: |
|---|
| 721 | | - return snd_pcm_status_user_x32(substream, argp, false); |
|---|
| 722 | | - case SNDRV_PCM_IOCTL_STATUS_EXT_X32: |
|---|
| 723 | | - return snd_pcm_status_user_x32(substream, argp, true); |
|---|
| 724 | | - case SNDRV_PCM_IOCTL_SYNC_PTR_X32: |
|---|
| 725 | | - return snd_pcm_ioctl_sync_ptr_x32(substream, argp); |
|---|
| 726 | 640 | case SNDRV_PCM_IOCTL_CHANNEL_INFO_X32: |
|---|
| 727 | 641 | return snd_pcm_ioctl_channel_info_x32(substream, argp); |
|---|
| 728 | 642 | #endif /* CONFIG_X86_X32 */ |
|---|