diff options
author | Jaroslav Kysela <perex@perex.cz> | 2009-04-13 15:31:25 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2009-04-13 15:31:25 -0400 |
commit | da2436a23c038055b1da6fe30b6ea2886b1e07b0 (patch) | |
tree | 465310474de14dffcbe847b9c1d4312ae700eb30 /sound/pci/intel8x0.c | |
parent | 920e4ae31cb113328e617f4a0663fb17d7b09124 (diff) |
[ALSA] intel8x0: do not use zero value from PICB register
It seems that the zero value from the PICB (position in current buffer)
register is not reliable. Use jiffies to correct returned value
from the ring buffer pointer callback.
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound/pci/intel8x0.c')
-rw-r--r-- | sound/pci/intel8x0.c | 43 |
1 files changed, 33 insertions, 10 deletions
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index c86ff499460b..6962f94d1bea 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c | |||
@@ -355,6 +355,9 @@ struct ichdev { | |||
355 | unsigned int fragsize1; | 355 | unsigned int fragsize1; |
356 | unsigned int position; | 356 | unsigned int position; |
357 | unsigned int pos_shift; | 357 | unsigned int pos_shift; |
358 | unsigned int last_pos; | ||
359 | unsigned long last_pos_jiffies; | ||
360 | unsigned int jiffy_to_bytes; | ||
358 | int frags; | 361 | int frags; |
359 | int lvi; | 362 | int lvi; |
360 | int lvi_frag; | 363 | int lvi_frag; |
@@ -838,7 +841,10 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd | |||
838 | ichdev->suspended = 0; | 841 | ichdev->suspended = 0; |
839 | /* fallthru */ | 842 | /* fallthru */ |
840 | case SNDRV_PCM_TRIGGER_START: | 843 | case SNDRV_PCM_TRIGGER_START: |
844 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
841 | val = ICH_IOCE | ICH_STARTBM; | 845 | val = ICH_IOCE | ICH_STARTBM; |
846 | ichdev->last_pos = ichdev->position; | ||
847 | ichdev->last_pos_jiffies = jiffies; | ||
842 | break; | 848 | break; |
843 | case SNDRV_PCM_TRIGGER_SUSPEND: | 849 | case SNDRV_PCM_TRIGGER_SUSPEND: |
844 | ichdev->suspended = 1; | 850 | ichdev->suspended = 1; |
@@ -849,9 +855,6 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd | |||
849 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 855 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
850 | val = ICH_IOCE; | 856 | val = ICH_IOCE; |
851 | break; | 857 | break; |
852 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
853 | val = ICH_IOCE | ICH_STARTBM; | ||
854 | break; | ||
855 | default: | 858 | default: |
856 | return -EINVAL; | 859 | return -EINVAL; |
857 | } | 860 | } |
@@ -1045,6 +1048,7 @@ static int snd_intel8x0_pcm_prepare(struct snd_pcm_substream *substream) | |||
1045 | ichdev->pos_shift = (runtime->sample_bits > 16) ? 2 : 1; | 1048 | ichdev->pos_shift = (runtime->sample_bits > 16) ? 2 : 1; |
1046 | } | 1049 | } |
1047 | snd_intel8x0_setup_periods(chip, ichdev); | 1050 | snd_intel8x0_setup_periods(chip, ichdev); |
1051 | ichdev->jiffy_to_bytes = (runtime->rate * 4 * ichdev->pos_shift) / HZ; | ||
1048 | return 0; | 1052 | return 0; |
1049 | } | 1053 | } |
1050 | 1054 | ||
@@ -1053,7 +1057,7 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *subs | |||
1053 | struct intel8x0 *chip = snd_pcm_substream_chip(substream); | 1057 | struct intel8x0 *chip = snd_pcm_substream_chip(substream); |
1054 | struct ichdev *ichdev = get_ichdev(substream); | 1058 | struct ichdev *ichdev = get_ichdev(substream); |
1055 | size_t ptr1, ptr; | 1059 | size_t ptr1, ptr; |
1056 | int civ, timeout = 100; | 1060 | int civ, timeout = 10; |
1057 | unsigned int position; | 1061 | unsigned int position; |
1058 | 1062 | ||
1059 | spin_lock(&chip->reg_lock); | 1063 | spin_lock(&chip->reg_lock); |
@@ -1069,9 +1073,19 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *subs | |||
1069 | ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb)) | 1073 | ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb)) |
1070 | break; | 1074 | break; |
1071 | } while (timeout--); | 1075 | } while (timeout--); |
1072 | ptr1 <<= ichdev->pos_shift; | 1076 | if (ptr1 != 0) { |
1073 | ptr = ichdev->fragsize1 - ptr1; | 1077 | ptr1 <<= ichdev->pos_shift; |
1074 | ptr += position; | 1078 | ptr = ichdev->fragsize1 - ptr1; |
1079 | ptr += position; | ||
1080 | ichdev->last_pos = ptr; | ||
1081 | ichdev->last_pos_jiffies = jiffies; | ||
1082 | } else { | ||
1083 | ptr1 = jiffies - ichdev->last_pos_jiffies; | ||
1084 | if (ptr1) | ||
1085 | ptr1 -= 1; | ||
1086 | ptr = ichdev->last_pos + ptr1 * ichdev->jiffy_to_bytes; | ||
1087 | ptr %= ichdev->size; | ||
1088 | } | ||
1075 | spin_unlock(&chip->reg_lock); | 1089 | spin_unlock(&chip->reg_lock); |
1076 | if (ptr >= ichdev->size) | 1090 | if (ptr >= ichdev->size) |
1077 | return 0; | 1091 | return 0; |
@@ -2710,9 +2724,13 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip) | |||
2710 | pos1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb)) | 2724 | pos1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb)) |
2711 | break; | 2725 | break; |
2712 | } while (timeout--); | 2726 | } while (timeout--); |
2713 | pos = ichdev->fragsize1; | 2727 | if (pos1 == 0) { /* oops, this value is not reliable */ |
2714 | pos -= pos1 << ichdev->pos_shift; | 2728 | pos = 0; |
2715 | pos += ichdev->position; | 2729 | } else { |
2730 | pos = ichdev->fragsize1; | ||
2731 | pos -= pos1 << ichdev->pos_shift; | ||
2732 | pos += ichdev->position; | ||
2733 | } | ||
2716 | chip->in_measurement = 0; | 2734 | chip->in_measurement = 0; |
2717 | do_posix_clock_monotonic_gettime(&stop_time); | 2735 | do_posix_clock_monotonic_gettime(&stop_time); |
2718 | /* stop */ | 2736 | /* stop */ |
@@ -2729,6 +2747,11 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip) | |||
2729 | iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS); | 2747 | iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS); |
2730 | spin_unlock_irq(&chip->reg_lock); | 2748 | spin_unlock_irq(&chip->reg_lock); |
2731 | 2749 | ||
2750 | if (pos == 0) { | ||
2751 | snd_printk(KERN_ERR "intel8x0: measure - unreliable DMA position..\n"); | ||
2752 | return; | ||
2753 | } | ||
2754 | |||
2732 | pos /= 4; | 2755 | pos /= 4; |
2733 | t = stop_time.tv_sec - start_time.tv_sec; | 2756 | t = stop_time.tv_sec - start_time.tv_sec; |
2734 | t *= 1000000; | 2757 | t *= 1000000; |