aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci
diff options
context:
space:
mode:
authorJaroslav Kysela <perex@perex.cz>2009-04-13 15:31:25 -0400
committerJaroslav Kysela <perex@perex.cz>2009-04-13 15:31:25 -0400
commitda2436a23c038055b1da6fe30b6ea2886b1e07b0 (patch)
tree465310474de14dffcbe847b9c1d4312ae700eb30 /sound/pci
parent920e4ae31cb113328e617f4a0663fb17d7b09124 (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')
-rw-r--r--sound/pci/intel8x0.c43
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;