diff options
-rw-r--r-- | sound/core/pcm_compat.c | 42 |
1 files changed, 28 insertions, 14 deletions
diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index 3920bf0eebbf..eef94a15f50a 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c | |||
@@ -103,10 +103,24 @@ struct sndrv_pcm_sw_params32 { | |||
103 | unsigned char reserved[64]; | 103 | unsigned char reserved[64]; |
104 | }; | 104 | }; |
105 | 105 | ||
106 | /* recalcuate the boundary within 32bit */ | ||
107 | static snd_pcm_uframes_t recalculate_boundary(snd_pcm_runtime_t *runtime) | ||
108 | { | ||
109 | snd_pcm_uframes_t boundary; | ||
110 | |||
111 | if (! runtime->buffer_size) | ||
112 | return 0; | ||
113 | boundary = runtime->buffer_size; | ||
114 | while (boundary * 2 <= 0x7fffffffUL - runtime->buffer_size) | ||
115 | boundary *= 2; | ||
116 | return boundary; | ||
117 | } | ||
118 | |||
106 | static int snd_pcm_ioctl_sw_params_compat(snd_pcm_substream_t *substream, | 119 | static int snd_pcm_ioctl_sw_params_compat(snd_pcm_substream_t *substream, |
107 | struct sndrv_pcm_sw_params32 __user *src) | 120 | struct sndrv_pcm_sw_params32 __user *src) |
108 | { | 121 | { |
109 | snd_pcm_sw_params_t params; | 122 | snd_pcm_sw_params_t params; |
123 | snd_pcm_uframes_t boundary; | ||
110 | int err; | 124 | int err; |
111 | 125 | ||
112 | memset(¶ms, 0, sizeof(params)); | 126 | memset(¶ms, 0, sizeof(params)); |
@@ -120,10 +134,17 @@ static int snd_pcm_ioctl_sw_params_compat(snd_pcm_substream_t *substream, | |||
120 | get_user(params.silence_threshold, &src->silence_threshold) || | 134 | get_user(params.silence_threshold, &src->silence_threshold) || |
121 | get_user(params.silence_size, &src->silence_size)) | 135 | get_user(params.silence_size, &src->silence_size)) |
122 | return -EFAULT; | 136 | return -EFAULT; |
137 | /* | ||
138 | * Check silent_size parameter. Since we have 64bit boundary, | ||
139 | * silence_size must be compared with the 32bit boundary. | ||
140 | */ | ||
141 | boundary = recalculate_boundary(substream->runtime); | ||
142 | if (boundary && params.silence_size >= boundary) | ||
143 | params.silence_size = substream->runtime->boundary; | ||
123 | err = snd_pcm_sw_params(substream, ¶ms); | 144 | err = snd_pcm_sw_params(substream, ¶ms); |
124 | if (err < 0) | 145 | if (err < 0) |
125 | return err; | 146 | return err; |
126 | if (put_user(params.boundary, &src->boundary)) | 147 | if (put_user(boundary, &src->boundary)) |
127 | return -EFAULT; | 148 | return -EFAULT; |
128 | return err; | 149 | return err; |
129 | } | 150 | } |
@@ -199,16 +220,6 @@ static int snd_pcm_status_user_compat(snd_pcm_substream_t *substream, | |||
199 | return err; | 220 | return err; |
200 | } | 221 | } |
201 | 222 | ||
202 | /* recalcuate the boundary within 32bit */ | ||
203 | static void recalculate_boundary(snd_pcm_runtime_t *runtime) | ||
204 | { | ||
205 | if (! runtime->buffer_size) | ||
206 | return; | ||
207 | runtime->boundary = runtime->buffer_size; | ||
208 | while (runtime->boundary * 2 <= 0x7fffffffUL - runtime->buffer_size) | ||
209 | runtime->boundary *= 2; | ||
210 | } | ||
211 | |||
212 | /* both for HW_PARAMS and HW_REFINE */ | 223 | /* both for HW_PARAMS and HW_REFINE */ |
213 | static int snd_pcm_ioctl_hw_params_compat(snd_pcm_substream_t *substream, | 224 | static int snd_pcm_ioctl_hw_params_compat(snd_pcm_substream_t *substream, |
214 | int refine, | 225 | int refine, |
@@ -242,7 +253,7 @@ static int snd_pcm_ioctl_hw_params_compat(snd_pcm_substream_t *substream, | |||
242 | } | 253 | } |
243 | 254 | ||
244 | if (! refine) | 255 | if (! refine) |
245 | recalculate_boundary(runtime); | 256 | runtime->boundary = recalculate_boundary(runtime); |
246 | error: | 257 | error: |
247 | kfree(data); | 258 | kfree(data); |
248 | return err; | 259 | return err; |
@@ -380,6 +391,7 @@ static int snd_pcm_ioctl_sync_ptr_compat(snd_pcm_substream_t *substream, | |||
380 | u32 sflags; | 391 | u32 sflags; |
381 | struct sndrv_pcm_mmap_control scontrol; | 392 | struct sndrv_pcm_mmap_control scontrol; |
382 | struct sndrv_pcm_mmap_status sstatus; | 393 | struct sndrv_pcm_mmap_status sstatus; |
394 | snd_pcm_uframes_t boundary; | ||
383 | int err; | 395 | int err; |
384 | 396 | ||
385 | snd_assert(runtime, return -EINVAL); | 397 | snd_assert(runtime, return -EINVAL); |
@@ -395,17 +407,19 @@ static int snd_pcm_ioctl_sync_ptr_compat(snd_pcm_substream_t *substream, | |||
395 | } | 407 | } |
396 | status = runtime->status; | 408 | status = runtime->status; |
397 | control = runtime->control; | 409 | control = runtime->control; |
410 | boundary = recalculate_boundary(runtime); | ||
398 | snd_pcm_stream_lock_irq(substream); | 411 | snd_pcm_stream_lock_irq(substream); |
412 | /* FIXME: we should consider the boundary for the sync from app */ | ||
399 | if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) | 413 | if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) |
400 | control->appl_ptr = scontrol.appl_ptr; | 414 | control->appl_ptr = scontrol.appl_ptr; |
401 | else | 415 | else |
402 | scontrol.appl_ptr = control->appl_ptr; | 416 | scontrol.appl_ptr = control->appl_ptr % boundary; |
403 | if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) | 417 | if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) |
404 | control->avail_min = scontrol.avail_min; | 418 | control->avail_min = scontrol.avail_min; |
405 | else | 419 | else |
406 | scontrol.avail_min = control->avail_min; | 420 | scontrol.avail_min = control->avail_min; |
407 | sstatus.state = status->state; | 421 | sstatus.state = status->state; |
408 | sstatus.hw_ptr = status->hw_ptr; | 422 | sstatus.hw_ptr = status->hw_ptr % boundary; |
409 | sstatus.tstamp = status->tstamp; | 423 | sstatus.tstamp = status->tstamp; |
410 | sstatus.suspended_state = status->suspended_state; | 424 | sstatus.suspended_state = status->suspended_state; |
411 | snd_pcm_stream_unlock_irq(substream); | 425 | snd_pcm_stream_unlock_irq(substream); |