diff options
author | Takashi Iwai | 2009-06-16 17:38:46 +0200 |
---|---|---|
committer | Takashi Iwai | 2009-06-16 17:38:46 +0200 |
commit | b909005ce15886e9f3283b876e17901f8057d2f7 (patch) | |
tree | 344ff0dcca3daf270f382eaee038a6f68b0fc083 | |
parent | 7998d90a143d0f8fbbb45282d5900a844de9bc16 (diff) | |
parent | f708eb1d71dc8ffb184da9f0bc53461c6dc10653 (diff) |
Merge branch 'topic/intel8x0' into for-linus
* topic/intel8x0:
ALSA: intel8x0 - Fix PCM position craziness
-rw-r--r-- | sound/pci/intel8x0.c | 24 |
1 files changed, 12 insertions, 12 deletions
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 173bebf9f51d..8aa5687f392a 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -356,8 +356,6 @@ struct ichdev { unsigned int position; unsigned int pos_shift; unsigned int last_pos; - unsigned long last_pos_jiffies; - unsigned int jiffy_to_bytes; int frags; int lvi; int lvi_frag; @@ -844,7 +842,6 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: val = ICH_IOCE | ICH_STARTBM; ichdev->last_pos = ichdev->position; - ichdev->last_pos_jiffies = jiffies; break; case SNDRV_PCM_TRIGGER_SUSPEND: ichdev->suspended = 1; @@ -1048,7 +1045,6 @@ static int snd_intel8x0_pcm_prepare(struct snd_pcm_substream *substream) ichdev->pos_shift = (runtime->sample_bits > 16) ? 2 : 1; } snd_intel8x0_setup_periods(chip, ichdev); - ichdev->jiffy_to_bytes = (runtime->rate * 4 * ichdev->pos_shift) / HZ; return 0; } @@ -1073,19 +1069,23 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *subs ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb)) break; } while (timeout--); + ptr = ichdev->last_pos; if (ptr1 != 0) { ptr1 <<= ichdev->pos_shift; ptr = ichdev->fragsize1 - ptr1; ptr += position; - ichdev->last_pos = ptr; - ichdev->last_pos_jiffies = jiffies; - } else { - ptr1 = jiffies - ichdev->last_pos_jiffies; - if (ptr1) - ptr1 -= 1; - ptr = ichdev->last_pos + ptr1 * ichdev->jiffy_to_bytes; - ptr %= ichdev->size; + if (ptr < ichdev->last_pos) { + unsigned int pos_base, last_base; + pos_base = position / ichdev->fragsize1; + last_base = ichdev->last_pos / ichdev->fragsize1; + /* another sanity check; ptr1 can go back to full + * before the base position is updated + */ + if (pos_base == last_base) + ptr = ichdev->last_pos; + } } + ichdev->last_pos = ptr; spin_unlock(&chip->reg_lock); if (ptr >= ichdev->size) return 0; |