*参照元 [#qcd14da2] #backlinks *説明 [#zfdda6dc] -パス: [[linux-2.6.33/sound/core/pcm_lib.c]] -FIXME: これは何? --説明 **引数 [#e34af82b] -struct snd_pcm_substream *substream -- --[[linux-2.6.33/snd_pcm_substream]] **返り値 [#y8db3630] -int -- **参考 [#ze5301c2] *実装 [#m6597aef] static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_uframes_t pos; snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_ptr_interrupt, hw_base; snd_pcm_sframes_t hdelta, delta; unsigned long jdelta; - --[[linux-2.6.33/snd_pcm_runtime]] - --[[linux-2.6.33/snd_pcm_uframes_t]] - --[[linux-2.6.33/snd_pcm_sframes_t]] old_hw_ptr = runtime->status->hw_ptr; pos = snd_pcm_update_hw_ptr_pos(substream, runtime); if (pos == SNDRV_PCM_POS_XRUN) { xrun(substream); return -EPIPE; } - --[[linux-2.6.33/snd_pcm_update_hw_ptr_pos()]] - --[[linux-2.6.33/SNDRV_PCM_POS_XRUN]] - --[[linux-2.6.33/xrun()]] if (xrun_debug(substream, 8)) { - --[[linux-2.6.33/xrun_debug()]] char name[16]; pcm_debug_name(substream, name, sizeof(name)); snd_printd("period_update: %s: pos=0x%x/0x%x/0x%x, " "hwptr=0x%lx, hw_base=0x%lx, hw_intr=0x%lx\n", name, (unsigned int)pos, (unsigned int)runtime->period_size, (unsigned int)runtime->buffer_size, (unsigned long)old_hw_ptr, (unsigned long)runtime->hw_ptr_base, (unsigned long)runtime->hw_ptr_interrupt); - --[[linux-2.6.33/pcm_debug_name()]] - --[[linux-2.6.33/snd_printd()]] } hw_base = runtime->hw_ptr_base; new_hw_ptr = hw_base + pos; hw_ptr_interrupt = runtime->hw_ptr_interrupt + runtime->period_size; delta = new_hw_ptr - hw_ptr_interrupt; if (hw_ptr_interrupt >= runtime->boundary) { hw_ptr_interrupt -= runtime->boundary; if (hw_base < runtime->boundary / 2) /* hw_base was already lapped; recalc delta */ delta = new_hw_ptr - hw_ptr_interrupt; } if (delta < 0) { if (runtime->periods == 1 || new_hw_ptr < old_hw_ptr) delta += runtime->buffer_size; if (delta < 0) { hw_ptr_error(substream, "Unexpected hw_pointer value " "(stream=%i, pos=%ld, intr_ptr=%ld)\n", substream->stream, (long)pos, (long)hw_ptr_interrupt); - --[[linux-2.6.33/hw_ptr_error()]] #if 1 /* simply skipping the hwptr update seems more * robust in some cases, e.g. on VMware with * inaccurate timer source */ return 0; /* skip this update */ #else /* rebase to interrupt position */ hw_base = new_hw_ptr = hw_ptr_interrupt; /* align hw_base to buffer_size */ hw_base -= hw_base % runtime->buffer_size; delta = 0; #endif } else { hw_base += runtime->buffer_size; if (hw_base >= runtime->boundary) hw_base = 0; new_hw_ptr = hw_base + pos; } } /* Do jiffies check only in xrun_debug mode */ if (!xrun_debug(substream, 4)) goto no_jiffies_check; /* Skip the jiffies check for hardwares with BATCH flag. * Such hardware usually just increases the position at each IRQ, * thus it can't give any strange position. */ if (runtime->hw.info & SNDRV_PCM_INFO_BATCH) goto no_jiffies_check; - --[[linux-2.6.33/SNDRV_PCM_INFO_BATCH]] hdelta = new_hw_ptr - old_hw_ptr; if (hdelta < runtime->delay) goto no_jiffies_check; hdelta -= runtime->delay; jdelta = jiffies - runtime->hw_ptr_jiffies; if (((hdelta * HZ) / runtime->rate) > jdelta + HZ/100) { - --[[linux-2.6.33/HZ]] delta = jdelta / (((runtime->period_size * HZ) / runtime->rate) + HZ/100); hw_ptr_error(substream, "hw_ptr skipping! [Q] " "(pos=%ld, delta=%ld, period=%ld, " "jdelta=%lu/%lu/%lu)\n", (long)pos, (long)hdelta, (long)runtime->period_size, jdelta, ((hdelta * HZ) / runtime->rate), delta); hw_ptr_interrupt = runtime->hw_ptr_interrupt + runtime->period_size * delta; if (hw_ptr_interrupt >= runtime->boundary) hw_ptr_interrupt -= runtime->boundary; /* rebase to interrupt position */ hw_base = new_hw_ptr = hw_ptr_interrupt; /* align hw_base to buffer_size */ hw_base -= hw_base % runtime->buffer_size; delta = 0; } no_jiffies_check: if (delta > runtime->period_size + runtime->period_size / 2) { hw_ptr_error(substream, "Lost interrupts? " "(stream=%i, delta=%ld, intr_ptr=%ld)\n", substream->stream, (long)delta, (long)hw_ptr_interrupt); /* rebase hw_ptr_interrupt */ hw_ptr_interrupt = new_hw_ptr - new_hw_ptr % runtime->period_size; } runtime->hw_ptr_interrupt = hw_ptr_interrupt; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0) snd_pcm_playback_silence(substream, new_hw_ptr); - --[[linux-2.6.33/snd_pcm_playback_silence()]] if (runtime->status->hw_ptr == new_hw_ptr) return 0; runtime->hw_ptr_base = hw_base; runtime->status->hw_ptr = new_hw_ptr; runtime->hw_ptr_jiffies = jiffies; if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); - --[[linux-2.6.33/SNDRV_PCM_TSTAMP_ENABLE]] - --[[linux-2.6.33/snd_pcm_gettime()]] - --[[linux-2.6.33/timespec]] return snd_pcm_update_hw_ptr_post(substream, runtime); - --[[linux-2.6.33/snd_pcm_update_hw_ptr_post()]] } *コメント [#w8ebf5b2]