From d0b2f91bede3bd5e3d24dd6803e56eee959c1797 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Fabian=20Silva=20Delgado?= Date: Thu, 20 Oct 2016 00:10:27 -0300 Subject: Linux-libre 4.8.2-gnu --- sound/core/compress_offload.c | 67 ++++++++++++++++++++++++++++++++++++-- sound/core/control.c | 32 ++++++++++++++++++ sound/core/seq/oss/seq_oss_synth.c | 10 +++--- sound/core/seq/seq_timer.c | 23 +++++-------- sound/core/seq/seq_timer.h | 2 +- 5 files changed, 112 insertions(+), 22 deletions(-) (limited to 'sound/core') diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index 9b3334be9..2c498488a 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -67,6 +67,8 @@ struct snd_compr_file { struct snd_compr_stream stream; }; +static void error_delayed_work(struct work_struct *work); + /* * a note on stream states used: * we use following states in the compressed core @@ -123,6 +125,9 @@ static int snd_compr_open(struct inode *inode, struct file *f) snd_card_unref(compr->card); return -ENOMEM; } + + INIT_DELAYED_WORK(&data->stream.error_work, error_delayed_work); + data->stream.ops = compr->ops; data->stream.direction = dirn; data->stream.private_data = compr->private_data; @@ -153,6 +158,8 @@ static int snd_compr_free(struct inode *inode, struct file *f) struct snd_compr_file *data = f->private_data; struct snd_compr_runtime *runtime = data->stream.runtime; + cancel_delayed_work_sync(&data->stream.error_work); + switch (runtime->state) { case SNDRV_PCM_STATE_RUNNING: case SNDRV_PCM_STATE_DRAINING: @@ -237,6 +244,15 @@ snd_compr_ioctl_avail(struct snd_compr_stream *stream, unsigned long arg) avail = snd_compr_calc_avail(stream, &ioctl_avail); ioctl_avail.avail = avail; + switch (stream->runtime->state) { + case SNDRV_PCM_STATE_OPEN: + return -EBADFD; + case SNDRV_PCM_STATE_XRUN: + return -EPIPE; + default: + break; + } + if (copy_to_user((__u64 __user *)arg, &ioctl_avail, sizeof(ioctl_avail))) return -EFAULT; @@ -346,11 +362,13 @@ static ssize_t snd_compr_read(struct file *f, char __user *buf, switch (stream->runtime->state) { case SNDRV_PCM_STATE_OPEN: case SNDRV_PCM_STATE_PREPARED: - case SNDRV_PCM_STATE_XRUN: case SNDRV_PCM_STATE_SUSPENDED: case SNDRV_PCM_STATE_DISCONNECTED: retval = -EBADFD; goto out; + case SNDRV_PCM_STATE_XRUN: + retval = -EPIPE; + goto out; } avail = snd_compr_get_avail(stream); @@ -399,10 +417,16 @@ static unsigned int snd_compr_poll(struct file *f, poll_table *wait) stream = &data->stream; mutex_lock(&stream->device->lock); - if (stream->runtime->state == SNDRV_PCM_STATE_OPEN) { + + switch (stream->runtime->state) { + case SNDRV_PCM_STATE_OPEN: + case SNDRV_PCM_STATE_XRUN: retval = snd_compr_get_poll(stream) | POLLERR; goto out; + default: + break; } + poll_wait(f, &stream->runtime->sleep, wait); avail = snd_compr_get_avail(stream); @@ -697,6 +721,45 @@ static int snd_compr_stop(struct snd_compr_stream *stream) return retval; } +static void error_delayed_work(struct work_struct *work) +{ + struct snd_compr_stream *stream; + + stream = container_of(work, struct snd_compr_stream, error_work.work); + + mutex_lock(&stream->device->lock); + + stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP); + wake_up(&stream->runtime->sleep); + + mutex_unlock(&stream->device->lock); +} + +/* + * snd_compr_stop_error: Report a fatal error on a stream + * @stream: pointer to stream + * @state: state to transition the stream to + * + * Stop the stream and set its state. + * + * Should be called with compressed device lock held. + */ +int snd_compr_stop_error(struct snd_compr_stream *stream, + snd_pcm_state_t state) +{ + if (stream->runtime->state == state) + return 0; + + stream->runtime->state = state; + + pr_debug("Changing state to: %d\n", state); + + queue_delayed_work(system_power_efficient_wq, &stream->error_work, 0); + + return 0; +} +EXPORT_SYMBOL_GPL(snd_compr_stop_error); + static int snd_compress_wait_for_drain(struct snd_compr_stream *stream) { int ret; diff --git a/sound/core/control.c b/sound/core/control.c index b4fe9b002..fb096cb20 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -807,6 +807,36 @@ static int snd_ctl_elem_list(struct snd_card *card, return 0; } +static bool validate_element_member_dimension(struct snd_ctl_elem_info *info) +{ + unsigned int members; + unsigned int i; + + if (info->dimen.d[0] == 0) + return true; + + members = 1; + for (i = 0; i < ARRAY_SIZE(info->dimen.d); ++i) { + if (info->dimen.d[i] == 0) + break; + members *= info->dimen.d[i]; + + /* + * info->count should be validated in advance, to guarantee + * calculation soundness. + */ + if (members > info->count) + return false; + } + + for (++i; i < ARRAY_SIZE(info->dimen.d); ++i) { + if (info->dimen.d[i] > 0) + return false; + } + + return members == info->count; +} + static int snd_ctl_elem_info(struct snd_ctl_file *ctl, struct snd_ctl_elem_info *info) { @@ -1274,6 +1304,8 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, if (info->count < 1 || info->count > max_value_counts[info->type]) return -EINVAL; + if (!validate_element_member_dimension(info)) + return -EINVAL; private_size = value_sizes[info->type] * info->count; /* diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c index b16dbef04..cd0e0ebbf 100644 --- a/sound/core/seq/oss/seq_oss_synth.c +++ b/sound/core/seq/oss/seq_oss_synth.c @@ -70,11 +70,11 @@ struct seq_oss_synth { static int max_synth_devs; static struct seq_oss_synth *synth_devs[SNDRV_SEQ_OSS_MAX_SYNTH_DEVS]; static struct seq_oss_synth midi_synth_dev = { - -1, /* seq_device */ - SYNTH_TYPE_MIDI, /* synth_type */ - 0, /* synth_subtype */ - 16, /* nr_voices */ - "MIDI", /* name */ + .seq_device = -1, + .synth_type = SYNTH_TYPE_MIDI, + .synth_subtype = 0, + .nr_voices = 16, + .name = "MIDI", }; static DEFINE_SPINLOCK(register_lock); diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index 293104926..dcc102813 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c @@ -165,7 +165,7 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri, snd_seq_timer_update_tick(&tmr->tick, resolution); /* register actual time of this timer update */ - do_gettimeofday(&tmr->last_update); + ktime_get_ts64(&tmr->last_update); spin_unlock_irqrestore(&tmr->lock, flags); @@ -392,7 +392,7 @@ static int seq_timer_start(struct snd_seq_timer *tmr) return -EINVAL; snd_timer_start(tmr->timeri, tmr->ticks); tmr->running = 1; - do_gettimeofday(&tmr->last_update); + ktime_get_ts64(&tmr->last_update); return 0; } @@ -420,7 +420,7 @@ static int seq_timer_continue(struct snd_seq_timer *tmr) } snd_timer_start(tmr->timeri, tmr->ticks); tmr->running = 1; - do_gettimeofday(&tmr->last_update); + ktime_get_ts64(&tmr->last_update); return 0; } @@ -444,17 +444,12 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr) spin_lock_irqsave(&tmr->lock, flags); cur_time = tmr->cur_time; if (tmr->running) { - struct timeval tm; - int usec; - do_gettimeofday(&tm); - usec = (int)(tm.tv_usec - tmr->last_update.tv_usec); - if (usec < 0) { - cur_time.tv_nsec += (1000000 + usec) * 1000; - cur_time.tv_sec += tm.tv_sec - tmr->last_update.tv_sec - 1; - } else { - cur_time.tv_nsec += usec * 1000; - cur_time.tv_sec += tm.tv_sec - tmr->last_update.tv_sec; - } + struct timespec64 tm; + + ktime_get_ts64(&tm); + tm = timespec64_sub(tm, tmr->last_update); + cur_time.tv_nsec = tm.tv_nsec; + cur_time.tv_sec = tm.tv_sec; snd_seq_sanity_real_time(&cur_time); } spin_unlock_irqrestore(&tmr->lock, flags); diff --git a/sound/core/seq/seq_timer.h b/sound/core/seq/seq_timer.h index 88dfb7180..9506b661f 100644 --- a/sound/core/seq/seq_timer.h +++ b/sound/core/seq/seq_timer.h @@ -52,7 +52,7 @@ struct snd_seq_timer { unsigned int skew; unsigned int skew_base; - struct timeval last_update; /* time of last clock update, used for interpolation */ + struct timespec64 last_update; /* time of last clock update, used for interpolation */ spinlock_t lock; }; -- cgit v1.2.3