diff options
-rw-r--r-- | sound/core/control.c | 7 | ||||
-rw-r--r-- | sound/core/pcm_native.c | 39 |
2 files changed, 40 insertions, 6 deletions
diff --git a/sound/core/control.c b/sound/core/control.c index 268ab7471224..439ce64f9d82 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -237,8 +237,9 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol, access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE| SNDRV_CTL_ELEM_ACCESS_INACTIVE| - SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE| - SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)); + SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE| + SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND| + SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)); kctl.info = ncontrol->info; kctl.get = ncontrol->get; kctl.put = ncontrol->put; @@ -1099,7 +1100,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, if (copy_from_user(&tlv, _tlv, sizeof(tlv))) return -EFAULT; - if (tlv.length < sizeof(unsigned int) * 3) + if (tlv.length < sizeof(unsigned int) * 2) return -EINVAL; down_read(&card->controls_rwsem); kctl = snd_ctl_find_numid(card, tlv.numid); diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index b79c777d2118..17935746eb18 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -27,6 +27,7 @@ #include <linux/pm_qos_params.h> #include <linux/uio.h> #include <linux/dma-mapping.h> +#include <linux/math64.h> #include <sound/core.h> #include <sound/control.h> #include <sound/info.h> @@ -366,6 +367,38 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime) return usecs; } +static int calc_boundary(struct snd_pcm_runtime *runtime) +{ + u_int64_t boundary; + + boundary = (u_int64_t)runtime->buffer_size * + (u_int64_t)runtime->period_size; +#if BITS_PER_LONG < 64 + /* try to find lowest common multiple for buffer and period */ + if (boundary > LONG_MAX - runtime->buffer_size) { + u_int32_t remainder = -1; + u_int32_t divident = runtime->buffer_size; + u_int32_t divisor = runtime->period_size; + while (remainder) { + remainder = divident % divisor; + if (remainder) { + divident = divisor; + divisor = remainder; + } + } + boundary = div_u64(boundary, divisor); + if (boundary > LONG_MAX - runtime->buffer_size) + return -ERANGE; + } +#endif + if (boundary == 0) + return -ERANGE; + runtime->boundary = boundary; + while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size) + runtime->boundary *= 2; + return 0; +} + static int snd_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -441,9 +474,9 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, runtime->stop_threshold = runtime->buffer_size; runtime->silence_threshold = 0; runtime->silence_size = 0; - runtime->boundary = runtime->buffer_size; - while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size) - runtime->boundary *= 2; + err = calc_boundary(runtime); + if (err < 0) + goto _error; snd_pcm_timer_resolution_change(substream); runtime->status->state = SNDRV_PCM_STATE_SETUP; |