X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=sound%2Fcore%2Fpcm_native.c;h=aef18682c03569b792ad9d44b13432288406dbe2;hb=480cf663e6988b3e79b570b42d2dbdb6c2ba9b94;hp=905234817c891d8c2cb0f2446416386aafac1fcc;hpb=e63340ae6b6205fef26b40a75673d1c9c0c8bb90;p=safe%2Fjmp%2Flinux-2.6 diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 9052348..aef1868 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1,6 +1,6 @@ /* * Digital Audio (PCM) abstract layer - * Copyright (c) by Jaroslav Kysela + * Copyright (c) by Jaroslav Kysela * * * This program is free software; you can redistribute it and/or modify @@ -19,12 +19,12 @@ * */ -#include #include #include #include +#include #include -#include +#include #include #include #include @@ -95,7 +95,6 @@ int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info) struct snd_pcm *pcm = substream->pcm; struct snd_pcm_str *pstr = substream->pstr; - snd_assert(substream != NULL, return -ENXIO); memset(info, 0, sizeof(*info)); info->card = pcm->card->number; info->device = pcm->device; @@ -370,9 +369,9 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, unsigned int bits; snd_pcm_uframes_t frames; - snd_assert(substream != NULL, return -ENXIO); + if (PCM_RUNTIME_CHECK(substream)) + return -ENXIO; runtime = substream->runtime; - snd_assert(runtime != NULL, return -ENXIO); snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_OPEN: @@ -413,7 +412,6 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, runtime->period_size = params_period_size(params); runtime->periods = params_periods(params); runtime->buffer_size = params_buffer_size(params); - runtime->tick_time = params_tick_time(params); runtime->info = params->info; runtime->rate_num = params->rate_num; runtime->rate_den = params->rate_den; @@ -433,9 +431,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, /* Default sw params */ runtime->tstamp_mode = SNDRV_PCM_TSTAMP_NONE; runtime->period_step = 1; - runtime->sleep_min = 0; runtime->control->avail_min = runtime->period_size; - runtime->xfer_align = runtime->period_size; runtime->start_threshold = 1; runtime->stop_threshold = runtime->buffer_size; runtime->silence_threshold = 0; @@ -447,9 +443,11 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, snd_pcm_timer_resolution_change(substream); runtime->status->state = SNDRV_PCM_STATE_SETUP; - remove_acceptable_latency(substream->latency_id); + pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY, + substream->latency_id); if ((usecs = period_to_usecs(runtime)) >= 0) - set_acceptable_latency(substream->latency_id, usecs); + pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY, + substream->latency_id, usecs); return 0; _error: /* hardware might be unuseable from this time, @@ -491,9 +489,9 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime; int result = 0; - snd_assert(substream != NULL, return -ENXIO); + if (PCM_RUNTIME_CHECK(substream)) + return -ENXIO; runtime = substream->runtime; - snd_assert(runtime != NULL, return -ENXIO); snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_SETUP: @@ -509,7 +507,8 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream) if (substream->ops->hw_free) result = substream->ops->hw_free(substream); runtime->status->state = SNDRV_PCM_STATE_OPEN; - remove_acceptable_latency(substream->latency_id); + pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY, + substream->latency_id); return result; } @@ -518,9 +517,9 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, { struct snd_pcm_runtime *runtime; - snd_assert(substream != NULL, return -ENXIO); + if (PCM_RUNTIME_CHECK(substream)) + return -ENXIO; runtime = substream->runtime; - snd_assert(runtime != NULL, return -ENXIO); snd_pcm_stream_lock_irq(substream); if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { snd_pcm_stream_unlock_irq(substream); @@ -532,9 +531,6 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, return -EINVAL; if (params->avail_min == 0) return -EINVAL; - if (params->xfer_align == 0 || - params->xfer_align % runtime->min_align != 0) - return -EINVAL; if (params->silence_size >= runtime->boundary) { if (params->silence_threshold != 0) return -EINVAL; @@ -546,20 +542,14 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, } snd_pcm_stream_lock_irq(substream); runtime->tstamp_mode = params->tstamp_mode; - runtime->sleep_min = params->sleep_min; runtime->period_step = params->period_step; runtime->control->avail_min = params->avail_min; runtime->start_threshold = params->start_threshold; runtime->stop_threshold = params->stop_threshold; runtime->silence_threshold = params->silence_threshold; runtime->silence_size = params->silence_size; - runtime->xfer_align = params->xfer_align; params->boundary = runtime->boundary; if (snd_pcm_running(substream)) { - if (runtime->sleep_min) - snd_pcm_tick_prepare(substream); - else - snd_pcm_tick_set(substream, 0); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0) snd_pcm_playback_silence(substream, ULONG_MAX); @@ -595,12 +585,13 @@ int snd_pcm_status(struct snd_pcm_substream *substream, status->trigger_tstamp = runtime->trigger_tstamp; if (snd_pcm_running(substream)) { snd_pcm_update_hw_ptr(substream); - if (runtime->tstamp_mode & SNDRV_PCM_TSTAMP_MMAP) + if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) { status->tstamp = runtime->status->tstamp; - else - getnstimeofday(&status->tstamp); - } else - getnstimeofday(&status->tstamp); + goto _tstamp_end; + } + } + snd_pcm_gettime(runtime, &status->tstamp); + _tstamp_end: status->appl_ptr = runtime->control->appl_ptr; status->hw_ptr = runtime->status->hw_ptr; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { @@ -630,11 +621,8 @@ static int snd_pcm_status_user(struct snd_pcm_substream *substream, struct snd_pcm_status __user * _status) { struct snd_pcm_status status; - struct snd_pcm_runtime *runtime; int res; - snd_assert(substream != NULL, return -ENXIO); - runtime = substream->runtime; memset(&status, 0, sizeof(status)); res = snd_pcm_status(substream, &status); if (res < 0) @@ -650,7 +638,6 @@ static int snd_pcm_channel_info(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime; unsigned int channel; - snd_assert(substream != NULL, return -ENXIO); channel = info->channel; runtime = substream->runtime; snd_pcm_stream_lock_irq(substream); @@ -688,7 +675,7 @@ static void snd_pcm_trigger_tstamp(struct snd_pcm_substream *substream) if (runtime->trigger_master == NULL) return; if (runtime->trigger_master == substream) { - getnstimeofday(&runtime->trigger_tstamp); + snd_pcm_gettime(runtime, &runtime->trigger_tstamp); } else { snd_pcm_trigger_tstamp(runtime->trigger_master); runtime->trigger_tstamp = runtime->trigger_master->runtime->trigger_tstamp; @@ -712,26 +699,23 @@ static int snd_pcm_action_group(struct action_ops *ops, struct snd_pcm_substream *substream, int state, int do_lock) { - struct list_head *pos; struct snd_pcm_substream *s = NULL; struct snd_pcm_substream *s1; int res = 0; - snd_pcm_group_for_each(pos, substream) { - s = snd_pcm_group_substream_entry(pos); + snd_pcm_group_for_each_entry(s, substream) { if (do_lock && s != substream) - spin_lock(&s->self_group.lock); + spin_lock_nested(&s->self_group.lock, + SINGLE_DEPTH_NESTING); res = ops->pre_action(s, state); if (res < 0) goto _unlock; } - snd_pcm_group_for_each(pos, substream) { - s = snd_pcm_group_substream_entry(pos); + snd_pcm_group_for_each_entry(s, substream) { res = ops->do_action(s, state); if (res < 0) { if (ops->undo_action) { - snd_pcm_group_for_each(pos, substream) { - s1 = snd_pcm_group_substream_entry(pos); + snd_pcm_group_for_each_entry(s1, substream) { if (s1 == s) /* failed stream */ break; ops->undo_action(s1, state); @@ -741,15 +725,13 @@ static int snd_pcm_action_group(struct action_ops *ops, goto _unlock; } } - snd_pcm_group_for_each(pos, substream) { - s = snd_pcm_group_substream_entry(pos); + snd_pcm_group_for_each_entry(s, substream) { ops->post_action(s, state); } _unlock: if (do_lock) { /* unlock streams */ - snd_pcm_group_for_each(pos, substream) { - s1 = snd_pcm_group_substream_entry(pos); + snd_pcm_group_for_each_entry(s1, substream) { if (s1 != substream) spin_unlock(&s1->self_group.lock); if (s1 == s) /* end */ @@ -880,8 +862,6 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0) snd_pcm_playback_silence(substream, ULONG_MAX); - if (runtime->sleep_min) - snd_pcm_tick_prepare(substream); if (substream->timer) snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTART, &runtime->trigger_tstamp); @@ -895,10 +875,8 @@ static struct action_ops snd_pcm_action_start = { }; /** - * snd_pcm_start + * snd_pcm_start - start all linked streams * @substream: the PCM substream instance - * - * Start all linked streams. */ int snd_pcm_start(struct snd_pcm_substream *substream) { @@ -935,7 +913,6 @@ static void snd_pcm_post_stop(struct snd_pcm_substream *substream, int state) snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTOP, &runtime->trigger_tstamp); runtime->status->state = state; - snd_pcm_tick_set(substream, 0); } wake_up(&runtime->sleep); } @@ -947,12 +924,11 @@ static struct action_ops snd_pcm_action_stop = { }; /** - * snd_pcm_stop + * snd_pcm_stop - try to stop all running streams in the substream group * @substream: the PCM substream instance * @state: PCM state after stopping the stream * - * Try to stop all running streams in the substream group. - * The state of each stream is changed to the given value after that unconditionally. + * The state of each stream is then changed to the given state unconditionally. */ int snd_pcm_stop(struct snd_pcm_substream *substream, int state) { @@ -962,11 +938,10 @@ int snd_pcm_stop(struct snd_pcm_substream *substream, int state) EXPORT_SYMBOL(snd_pcm_stop); /** - * snd_pcm_drain_done + * snd_pcm_drain_done - stop the DMA only when the given stream is playback * @substream: the PCM substream * - * Stop the DMA only when the given stream is playback. - * The state is changed to SETUP. + * After stopping, the state is changed to SETUP. * Unlike snd_pcm_stop(), this affects only the given stream. */ int snd_pcm_drain_done(struct snd_pcm_substream *substream) @@ -1019,12 +994,9 @@ static void snd_pcm_post_pause(struct snd_pcm_substream *substream, int push) snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MPAUSE, &runtime->trigger_tstamp); - snd_pcm_tick_set(substream, 0); wake_up(&runtime->sleep); } else { runtime->status->state = SNDRV_PCM_STATE_RUNNING; - if (runtime->sleep_min) - snd_pcm_tick_prepare(substream); if (substream->timer) snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MCONTINUE, @@ -1079,7 +1051,6 @@ static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state) &runtime->trigger_tstamp); runtime->status->suspended_state = runtime->status->state; runtime->status->state = SNDRV_PCM_STATE_SUSPENDED; - snd_pcm_tick_set(substream, 0); wake_up(&runtime->sleep); } @@ -1090,10 +1061,9 @@ static struct action_ops snd_pcm_action_suspend = { }; /** - * snd_pcm_suspend + * snd_pcm_suspend - trigger SUSPEND to all linked streams * @substream: the PCM substream * - * Trigger SUSPEND to all linked streams. * After this call, all streams are changed to SUSPENDED state. */ int snd_pcm_suspend(struct snd_pcm_substream *substream) @@ -1113,10 +1083,9 @@ int snd_pcm_suspend(struct snd_pcm_substream *substream) EXPORT_SYMBOL(snd_pcm_suspend); /** - * snd_pcm_suspend_all + * snd_pcm_suspend_all - trigger SUSPEND to all substreams in the given pcm * @pcm: the PCM instance * - * Trigger SUSPEND to all substreams in the given pcm. * After this call, all streams are changed to SUSPENDED state. */ int snd_pcm_suspend_all(struct snd_pcm *pcm) @@ -1182,8 +1151,6 @@ static void snd_pcm_post_resume(struct snd_pcm_substream *substream, int state) snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MRESUME, &runtime->trigger_tstamp); runtime->status->state = runtime->status->suspended_state; - if (runtime->sleep_min) - snd_pcm_tick_prepare(substream); } static struct action_ops snd_pcm_action_resume = { @@ -1272,7 +1239,6 @@ static int snd_pcm_do_reset(struct snd_pcm_substream *substream, int state) int err = substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_RESET, NULL); if (err < 0) return err; - // snd_assert(runtime->status->hw_ptr < runtime->buffer_size, ); runtime->hw_ptr_base = 0; runtime->hw_ptr_interrupt = runtime->status->hw_ptr - runtime->status->hw_ptr % runtime->period_size; @@ -1341,11 +1307,9 @@ static struct action_ops snd_pcm_action_prepare = { }; /** - * snd_pcm_prepare + * snd_pcm_prepare - prepare the PCM substream to be triggerable * @substream: the PCM substream instance * @file: file to refer f_flags - * - * Prepare the PCM substream to be triggerable. */ static int snd_pcm_prepare(struct snd_pcm_substream *substream, struct file *file) @@ -1400,10 +1364,10 @@ static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, int state) } else { /* stop running stream */ if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) { - int state = snd_pcm_capture_avail(runtime) > 0 ? + int new_state = snd_pcm_capture_avail(runtime) > 0 ? SNDRV_PCM_STATE_DRAINING : SNDRV_PCM_STATE_SETUP; - snd_pcm_do_stop(substream, state); - snd_pcm_post_stop(substream, state); + snd_pcm_do_stop(substream, new_state); + snd_pcm_post_stop(substream, new_state); } } return 0; @@ -1438,12 +1402,11 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream) { struct snd_card *card; struct snd_pcm_runtime *runtime; - struct list_head *pos; + struct snd_pcm_substream *s; int result = 0; int i, num_drecs; struct drain_rec *drec, drec_tmp, *d; - snd_assert(substream != NULL, return -ENXIO); card = substream->pcm->card; runtime = substream->runtime; @@ -1473,8 +1436,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream) /* count only playback streams */ num_drecs = 0; - snd_pcm_group_for_each(pos, substream) { - struct snd_pcm_substream *s = snd_pcm_group_substream_entry(pos); + snd_pcm_group_for_each_entry(s, substream) { runtime = s->runtime; if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) { d = &drec[num_drecs++]; @@ -1493,7 +1455,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream) snd_pcm_stream_lock_irq(substream); /* resume pause */ - if (runtime->status->state == SNDRV_PCM_STATE_PAUSED) + if (substream->runtime->status->state == SNDRV_PCM_STATE_PAUSED) snd_pcm_pause(substream, 0); /* pre-start/stop - all running streams are changed to DRAINING state */ @@ -1564,21 +1526,16 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream) struct snd_card *card; int result = 0; - snd_assert(substream != NULL, return -ENXIO); + if (PCM_RUNTIME_CHECK(substream)) + return -ENXIO; runtime = substream->runtime; card = substream->pcm->card; if (runtime->status->state == SNDRV_PCM_STATE_OPEN || - runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED) + runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED || + runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) return -EBADFD; - snd_power_lock(card); - if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { - result = snd_power_wait(card, SNDRV_CTL_POWER_D0); - if (result < 0) - goto _unlock; - } - snd_pcm_stream_lock_irq(substream); /* resume pause */ if (runtime->status->state == SNDRV_PCM_STATE_PAUSED) @@ -1587,8 +1544,7 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream) snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); /* runtime->control->appl_ptr = runtime->status->hw_ptr; */ snd_pcm_stream_unlock_irq(substream); - _unlock: - snd_power_unlock(card); + return result; } @@ -1674,7 +1630,7 @@ static void relink_to_local(struct snd_pcm_substream *substream) static int snd_pcm_unlink(struct snd_pcm_substream *substream) { - struct list_head *pos; + struct snd_pcm_substream *s; int res = 0; down_write(&snd_pcm_link_rwsem); @@ -1686,8 +1642,8 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream) list_del(&substream->link_list); substream->group->count--; if (substream->group->count == 1) { /* detach the last stream, too */ - snd_pcm_group_for_each(pos, substream) { - relink_to_local(snd_pcm_group_substream_entry(pos)); + snd_pcm_group_for_each_entry(s, substream) { + relink_to_local(s); break; } kfree(substream->group); @@ -1793,12 +1749,18 @@ static int snd_pcm_hw_rule_sample_bits(struct snd_pcm_hw_params *params, static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000 }; +const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = { + .count = ARRAY_SIZE(rates), + .list = rates, +}; + static int snd_pcm_hw_rule_rate(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { struct snd_pcm_hardware *hw = rule->private; return snd_interval_list(hw_param_interval(params, rule->var), - ARRAY_SIZE(rates), rates, hw->rates); + snd_pcm_known_rates.count, + snd_pcm_known_rates.list, hw->rates); } static int snd_pcm_hw_rule_buffer_bytes_max(struct snd_pcm_hw_params *params, @@ -1958,33 +1920,41 @@ int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream) mask |= 1 << SNDRV_PCM_ACCESS_MMAP_COMPLEX; } err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_ACCESS, mask); - snd_assert(err >= 0, return -EINVAL); + if (err < 0) + return err; err = snd_pcm_hw_constraint_mask64(runtime, SNDRV_PCM_HW_PARAM_FORMAT, hw->formats); - snd_assert(err >= 0, return -EINVAL); + if (err < 0) + return err; err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_SUBFORMAT, 1 << SNDRV_PCM_SUBFORMAT_STD); - snd_assert(err >= 0, return -EINVAL); + if (err < 0) + return err; err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, hw->channels_min, hw->channels_max); - snd_assert(err >= 0, return -EINVAL); + if (err < 0) + return err; err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE, hw->rate_min, hw->rate_max); - snd_assert(err >= 0, return -EINVAL); + if (err < 0) + return err; err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, hw->period_bytes_min, hw->period_bytes_max); - snd_assert(err >= 0, return -EINVAL); + if (err < 0) + return err; err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIODS, hw->periods_min, hw->periods_max); - snd_assert(err >= 0, return -EINVAL); + if (err < 0) + return err; err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, hw->period_bytes_min, hw->buffer_bytes_max); - snd_assert(err >= 0, return -EINVAL); + if (err < 0) + return err; err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, snd_pcm_hw_rule_buffer_bytes_max, substream, @@ -1995,7 +1965,8 @@ int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream) /* FIXME: remove */ if (runtime->dma_bytes) { err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 0, runtime->dma_bytes); - snd_assert(err >= 0, return -EINVAL); + if (err < 0) + return -EINVAL; } if (!(hw->rates & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))) { @@ -2007,8 +1978,6 @@ int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream) } /* FIXME: this belong to lowlevel */ - snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_TICK_TIME, - 1000000 / HZ, 1000000 / HZ); snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); return 0; @@ -2093,8 +2062,8 @@ static int snd_pcm_open_file(struct file *file, struct snd_pcm_str *str; int err; - snd_assert(rpcm_file != NULL, return -EINVAL); - *rpcm_file = NULL; + if (rpcm_file) + *rpcm_file = NULL; err = snd_pcm_open_substream(pcm, stream, file, &substream); if (err < 0) @@ -2112,7 +2081,8 @@ static int snd_pcm_open_file(struct file *file, substream->pcm_release = pcm_release_private; } file->private_data = pcm_file; - *rpcm_file = pcm_file; + if (rpcm_file) + *rpcm_file = pcm_file; return 0; } @@ -2196,7 +2166,8 @@ static int snd_pcm_release(struct inode *inode, struct file *file) pcm_file = file->private_data; substream = pcm_file->substream; - snd_assert(substream != NULL, return -ENXIO); + if (snd_BUG_ON(!substream)) + return -ENXIO; pcm = substream->pcm; fasync_helper(-1, file, 0, &substream->runtime->fasync); mutex_lock(&pcm->open_mutex); @@ -2244,15 +2215,10 @@ static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *subst } if (frames > (snd_pcm_uframes_t)hw_avail) frames = hw_avail; - else - frames -= frames % runtime->xfer_align; appl_ptr = runtime->control->appl_ptr - frames; if (appl_ptr < 0) appl_ptr += runtime->boundary; runtime->control->appl_ptr = appl_ptr; - if (runtime->status->state == SNDRV_PCM_STATE_RUNNING && - runtime->sleep_min) - snd_pcm_tick_prepare(substream); ret = frames; __end: snd_pcm_stream_unlock_irq(substream); @@ -2294,15 +2260,10 @@ static snd_pcm_sframes_t snd_pcm_capture_rewind(struct snd_pcm_substream *substr } if (frames > (snd_pcm_uframes_t)hw_avail) frames = hw_avail; - else - frames -= frames % runtime->xfer_align; appl_ptr = runtime->control->appl_ptr - frames; if (appl_ptr < 0) appl_ptr += runtime->boundary; runtime->control->appl_ptr = appl_ptr; - if (runtime->status->state == SNDRV_PCM_STATE_RUNNING && - runtime->sleep_min) - snd_pcm_tick_prepare(substream); ret = frames; __end: snd_pcm_stream_unlock_irq(substream); @@ -2345,15 +2306,10 @@ static snd_pcm_sframes_t snd_pcm_playback_forward(struct snd_pcm_substream *subs } if (frames > (snd_pcm_uframes_t)avail) frames = avail; - else - frames -= frames % runtime->xfer_align; appl_ptr = runtime->control->appl_ptr + frames; if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary) appl_ptr -= runtime->boundary; runtime->control->appl_ptr = appl_ptr; - if (runtime->status->state == SNDRV_PCM_STATE_RUNNING && - runtime->sleep_min) - snd_pcm_tick_prepare(substream); ret = frames; __end: snd_pcm_stream_unlock_irq(substream); @@ -2396,15 +2352,10 @@ static snd_pcm_sframes_t snd_pcm_capture_forward(struct snd_pcm_substream *subst } if (frames > (snd_pcm_uframes_t)avail) frames = avail; - else - frames -= frames % runtime->xfer_align; appl_ptr = runtime->control->appl_ptr + frames; if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary) appl_ptr -= runtime->boundary; runtime->control->appl_ptr = appl_ptr; - if (runtime->status->state == SNDRV_PCM_STATE_RUNNING && - runtime->sleep_min) - snd_pcm_tick_prepare(substream); ret = frames; __end: snd_pcm_stream_unlock_irq(substream); @@ -2519,20 +2470,35 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream, return -EFAULT; return 0; } + +static int snd_pcm_tstamp(struct snd_pcm_substream *substream, int __user *_arg) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + int arg; + + if (get_user(arg, _arg)) + return -EFAULT; + if (arg < 0 || arg > SNDRV_PCM_TSTAMP_TYPE_LAST) + return -EINVAL; + runtime->tstamp_type = SNDRV_PCM_TSTAMP_TYPE_GETTIMEOFDAY; + if (arg == SNDRV_PCM_TSTAMP_TYPE_MONOTONIC) + runtime->tstamp_type = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC; + return 0; +} static int snd_pcm_common_ioctl1(struct file *file, struct snd_pcm_substream *substream, unsigned int cmd, void __user *arg) { - snd_assert(substream != NULL, return -ENXIO); - switch (cmd) { case SNDRV_PCM_IOCTL_PVERSION: return put_user(SNDRV_PCM_VERSION, (int __user *)arg) ? -EFAULT : 0; case SNDRV_PCM_IOCTL_INFO: return snd_pcm_info_user(substream, arg); - case SNDRV_PCM_IOCTL_TSTAMP: /* just for compatibility */ + case SNDRV_PCM_IOCTL_TSTAMP: /* just for compatibility */ return 0; + case SNDRV_PCM_IOCTL_TTSTAMP: + return snd_pcm_tstamp(substream, arg); case SNDRV_PCM_IOCTL_HW_REFINE: return snd_pcm_hw_refine_user(substream, arg); case SNDRV_PCM_IOCTL_HW_PARAMS: @@ -2592,8 +2558,10 @@ static int snd_pcm_playback_ioctl1(struct file *file, struct snd_pcm_substream *substream, unsigned int cmd, void __user *arg) { - snd_assert(substream != NULL, return -ENXIO); - snd_assert(substream->stream == SNDRV_PCM_STREAM_PLAYBACK, return -EINVAL); + if (snd_BUG_ON(!substream)) + return -ENXIO; + if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_PLAYBACK)) + return -EINVAL; switch (cmd) { case SNDRV_PCM_IOCTL_WRITEI_FRAMES: { @@ -2672,8 +2640,10 @@ static int snd_pcm_capture_ioctl1(struct file *file, struct snd_pcm_substream *substream, unsigned int cmd, void __user *arg) { - snd_assert(substream != NULL, return -ENXIO); - snd_assert(substream->stream == SNDRV_PCM_STREAM_CAPTURE, return -EINVAL); + if (snd_BUG_ON(!substream)) + return -ENXIO; + if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_CAPTURE)) + return -EINVAL; switch (cmd) { case SNDRV_PCM_IOCTL_READI_FRAMES: { @@ -2812,7 +2782,8 @@ static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count, pcm_file = file->private_data; substream = pcm_file->substream; - snd_assert(substream != NULL, return -ENXIO); + if (PCM_RUNTIME_CHECK(substream)) + return -ENXIO; runtime = substream->runtime; if (runtime->status->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; @@ -2835,21 +2806,17 @@ static ssize_t snd_pcm_write(struct file *file, const char __user *buf, pcm_file = file->private_data; substream = pcm_file->substream; - snd_assert(substream != NULL, result = -ENXIO; goto end); + if (PCM_RUNTIME_CHECK(substream)) + return -ENXIO; runtime = substream->runtime; - if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { - result = -EBADFD; - goto end; - } - if (!frame_aligned(runtime, count)) { - result = -EINVAL; - goto end; - } + if (runtime->status->state == SNDRV_PCM_STATE_OPEN) + return -EBADFD; + if (!frame_aligned(runtime, count)) + return -EINVAL; count = bytes_to_frames(runtime, count); result = snd_pcm_lib_write(substream, buf, count); if (result > 0) result = frames_to_bytes(runtime, result); - end: return result; } @@ -2867,7 +2834,8 @@ static ssize_t snd_pcm_aio_read(struct kiocb *iocb, const struct iovec *iov, pcm_file = iocb->ki_filp->private_data; substream = pcm_file->substream; - snd_assert(substream != NULL, return -ENXIO); + if (PCM_RUNTIME_CHECK(substream)) + return -ENXIO; runtime = substream->runtime; if (runtime->status->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; @@ -2901,17 +2869,14 @@ static ssize_t snd_pcm_aio_write(struct kiocb *iocb, const struct iovec *iov, pcm_file = iocb->ki_filp->private_data; substream = pcm_file->substream; - snd_assert(substream != NULL, result = -ENXIO; goto end); + if (PCM_RUNTIME_CHECK(substream)) + return -ENXIO; runtime = substream->runtime; - if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { - result = -EBADFD; - goto end; - } + if (runtime->status->state == SNDRV_PCM_STATE_OPEN) + return -EBADFD; if (nr_segs > 128 || nr_segs != runtime->channels || - !frame_aligned(runtime, iov->iov_len)) { - result = -EINVAL; - goto end; - } + !frame_aligned(runtime, iov->iov_len)) + return -EINVAL; frames = bytes_to_samples(runtime, iov->iov_len); bufs = kmalloc(sizeof(void *) * nr_segs, GFP_KERNEL); if (bufs == NULL) @@ -2922,7 +2887,6 @@ static ssize_t snd_pcm_aio_write(struct kiocb *iocb, const struct iovec *iov, if (result > 0) result = frames_to_bytes(runtime, result); kfree(bufs); - end: return result; } @@ -2937,7 +2901,8 @@ static unsigned int snd_pcm_playback_poll(struct file *file, poll_table * wait) pcm_file = file->private_data; substream = pcm_file->substream; - snd_assert(substream != NULL, return -ENXIO); + if (PCM_RUNTIME_CHECK(substream)) + return -ENXIO; runtime = substream->runtime; poll_wait(file, &runtime->sleep, wait); @@ -2975,7 +2940,8 @@ static unsigned int snd_pcm_capture_poll(struct file *file, poll_table * wait) pcm_file = file->private_data; substream = pcm_file->substream; - snd_assert(substream != NULL, return -ENXIO); + if (PCM_RUNTIME_CHECK(substream)) + return -ENXIO; runtime = substream->runtime; poll_wait(file, &runtime->sleep, wait); @@ -3018,26 +2984,23 @@ static unsigned int snd_pcm_capture_poll(struct file *file, poll_table * wait) /* * mmap status record */ -static struct page * snd_pcm_mmap_status_nopage(struct vm_area_struct *area, - unsigned long address, int *type) +static int snd_pcm_mmap_status_fault(struct vm_area_struct *area, + struct vm_fault *vmf) { struct snd_pcm_substream *substream = area->vm_private_data; struct snd_pcm_runtime *runtime; - struct page * page; if (substream == NULL) - return NOPAGE_SIGBUS; + return VM_FAULT_SIGBUS; runtime = substream->runtime; - page = virt_to_page(runtime->status); - get_page(page); - if (type) - *type = VM_FAULT_MINOR; - return page; + vmf->page = virt_to_page(runtime->status); + get_page(vmf->page); + return 0; } static struct vm_operations_struct snd_pcm_vm_ops_status = { - .nopage = snd_pcm_mmap_status_nopage, + .fault = snd_pcm_mmap_status_fault, }; static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file, @@ -3048,7 +3011,6 @@ static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file if (!(area->vm_flags & VM_READ)) return -EINVAL; runtime = substream->runtime; - snd_assert(runtime != NULL, return -EAGAIN); size = area->vm_end - area->vm_start; if (size != PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status))) return -EINVAL; @@ -3061,26 +3023,23 @@ static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file /* * mmap control record */ -static struct page * snd_pcm_mmap_control_nopage(struct vm_area_struct *area, - unsigned long address, int *type) +static int snd_pcm_mmap_control_fault(struct vm_area_struct *area, + struct vm_fault *vmf) { struct snd_pcm_substream *substream = area->vm_private_data; struct snd_pcm_runtime *runtime; - struct page * page; if (substream == NULL) - return NOPAGE_SIGBUS; + return VM_FAULT_SIGBUS; runtime = substream->runtime; - page = virt_to_page(runtime->control); - get_page(page); - if (type) - *type = VM_FAULT_MINOR; - return page; + vmf->page = virt_to_page(runtime->control); + get_page(vmf->page); + return 0; } static struct vm_operations_struct snd_pcm_vm_ops_control = { - .nopage = snd_pcm_mmap_control_nopage, + .fault = snd_pcm_mmap_control_fault, }; static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file *file, @@ -3091,7 +3050,6 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file if (!(area->vm_flags & VM_READ)) return -EINVAL; runtime = substream->runtime; - snd_assert(runtime != NULL, return -EAGAIN); size = area->vm_end - area->vm_start; if (size != PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control))) return -EINVAL; @@ -3117,10 +3075,10 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file #endif /* coherent mmap */ /* - * nopage callback for mmapping a RAM page + * fault callback for mmapping a RAM page */ -static struct page *snd_pcm_mmap_data_nopage(struct vm_area_struct *area, - unsigned long address, int *type) +static int snd_pcm_mmap_data_fault(struct vm_area_struct *area, + struct vm_fault *vmf) { struct snd_pcm_substream *substream = area->vm_private_data; struct snd_pcm_runtime *runtime; @@ -3130,33 +3088,30 @@ static struct page *snd_pcm_mmap_data_nopage(struct vm_area_struct *area, size_t dma_bytes; if (substream == NULL) - return NOPAGE_SIGBUS; + return VM_FAULT_SIGBUS; runtime = substream->runtime; - offset = area->vm_pgoff << PAGE_SHIFT; - offset += address - area->vm_start; - snd_assert((offset % PAGE_SIZE) == 0, return NOPAGE_SIGBUS); + offset = vmf->pgoff << PAGE_SHIFT; dma_bytes = PAGE_ALIGN(runtime->dma_bytes); if (offset > dma_bytes - PAGE_SIZE) - return NOPAGE_SIGBUS; + return VM_FAULT_SIGBUS; if (substream->ops->page) { page = substream->ops->page(substream, offset); - if (! page) - return NOPAGE_OOM; /* XXX: is this really due to OOM? */ + if (!page) + return VM_FAULT_SIGBUS; } else { vaddr = runtime->dma_area + offset; page = virt_to_page(vaddr); } get_page(page); - if (type) - *type = VM_FAULT_MINOR; - return page; + vmf->page = page; + return 0; } static struct vm_operations_struct snd_pcm_vm_ops_data = { .open = snd_pcm_mmap_data_open, .close = snd_pcm_mmap_data_close, - .nopage = snd_pcm_mmap_data_nopage, + .fault = snd_pcm_mmap_data_fault, }; /* @@ -3226,7 +3181,6 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, return -EINVAL; } runtime = substream->runtime; - snd_assert(runtime != NULL, return -EAGAIN); if (runtime->status->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; if (!(runtime->info & SNDRV_PCM_INFO_MMAP)) @@ -3258,7 +3212,8 @@ static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area) pcm_file = file->private_data; substream = pcm_file->substream; - snd_assert(substream != NULL, return -ENXIO); + if (PCM_RUNTIME_CHECK(substream)) + return -ENXIO; offset = area->vm_pgoff << PAGE_SHIFT; switch (offset) { @@ -3281,14 +3236,17 @@ static int snd_pcm_fasync(int fd, struct file * file, int on) struct snd_pcm_file * pcm_file; struct snd_pcm_substream *substream; struct snd_pcm_runtime *runtime; - int err; + int err = -ENXIO; + lock_kernel(); pcm_file = file->private_data; substream = pcm_file->substream; - snd_assert(substream != NULL, return -ENXIO); + if (PCM_RUNTIME_CHECK(substream)) + goto out; runtime = substream->runtime; - err = fasync_helper(fd, file, on, &runtime->fasync); +out: + unlock_kernel(); if (err < 0) return err; return 0; @@ -3419,6 +3377,17 @@ out: } #endif /* CONFIG_SND_SUPPORT_OLD_API */ +#ifndef CONFIG_MMU +unsigned long dummy_get_unmapped_area(struct file *file, unsigned long addr, + unsigned long len, unsigned long pgoff, + unsigned long flags) +{ + return 0; +} +#else +# define dummy_get_unmapped_area NULL +#endif + /* * Register section */ @@ -3435,6 +3404,7 @@ const struct file_operations snd_pcm_f_ops[2] = { .compat_ioctl = snd_pcm_ioctl_compat, .mmap = snd_pcm_mmap, .fasync = snd_pcm_fasync, + .get_unmapped_area = dummy_get_unmapped_area, }, { .owner = THIS_MODULE, @@ -3447,5 +3417,6 @@ const struct file_operations snd_pcm_f_ops[2] = { .compat_ioctl = snd_pcm_ioctl_compat, .mmap = snd_pcm_mmap, .fasync = snd_pcm_fasync, + .get_unmapped_area = dummy_get_unmapped_area, } };