aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/es1938.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/es1938.c')
-rw-r--r--sound/pci/es1938.c27
1 files changed, 25 insertions, 2 deletions
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c
index fbe3da73eaff..1a314fa99c45 100644
--- a/sound/pci/es1938.c
+++ b/sound/pci/es1938.c
@@ -226,6 +226,7 @@ struct es1938 {
226 unsigned int dma2_start; 226 unsigned int dma2_start;
227 unsigned int dma1_shift; 227 unsigned int dma1_shift;
228 unsigned int dma2_shift; 228 unsigned int dma2_shift;
229 unsigned int last_capture_dmaaddr;
229 unsigned int active; 230 unsigned int active;
230 231
231 spinlock_t reg_lock; 232 spinlock_t reg_lock;
@@ -528,6 +529,7 @@ static void snd_es1938_capture_setdma(struct es1938 *chip)
528 outb(1, SLDM_REG(chip, DMAMASK)); 529 outb(1, SLDM_REG(chip, DMAMASK));
529 outb(0x14, SLDM_REG(chip, DMAMODE)); 530 outb(0x14, SLDM_REG(chip, DMAMODE));
530 outl(chip->dma1_start, SLDM_REG(chip, DMAADDR)); 531 outl(chip->dma1_start, SLDM_REG(chip, DMAADDR));
532 chip->last_capture_dmaaddr = chip->dma1_start;
531 outw(chip->dma1_size - 1, SLDM_REG(chip, DMACOUNT)); 533 outw(chip->dma1_size - 1, SLDM_REG(chip, DMACOUNT));
532 /* 3. Unmask DMA */ 534 /* 3. Unmask DMA */
533 outb(0, SLDM_REG(chip, DMAMASK)); 535 outb(0, SLDM_REG(chip, DMAMASK));
@@ -769,19 +771,40 @@ static int snd_es1938_playback_prepare(struct snd_pcm_substream *substream)
769 return -EINVAL; 771 return -EINVAL;
770} 772}
771 773
774/* during the incrementing of dma counters the DMA register reads sometimes
775 returns garbage. To ensure a valid hw pointer, the following checks which
776 should be very unlikely to fail are used:
777 - is the current DMA address in the valid DMA range ?
778 - is the sum of DMA address and DMA counter pointing to the last DMA byte ?
779 One can argue this could differ by one byte depending on which register is
780 updated first, so the implementation below allows for that.
781*/
772static snd_pcm_uframes_t snd_es1938_capture_pointer(struct snd_pcm_substream *substream) 782static snd_pcm_uframes_t snd_es1938_capture_pointer(struct snd_pcm_substream *substream)
773{ 783{
774 struct es1938 *chip = snd_pcm_substream_chip(substream); 784 struct es1938 *chip = snd_pcm_substream_chip(substream);
775 size_t ptr; 785 size_t ptr;
786#if 0
776 size_t old, new; 787 size_t old, new;
777#if 1
778 /* This stuff is *needed*, don't ask why - AB */ 788 /* This stuff is *needed*, don't ask why - AB */
779 old = inw(SLDM_REG(chip, DMACOUNT)); 789 old = inw(SLDM_REG(chip, DMACOUNT));
780 while ((new = inw(SLDM_REG(chip, DMACOUNT))) != old) 790 while ((new = inw(SLDM_REG(chip, DMACOUNT))) != old)
781 old = new; 791 old = new;
782 ptr = chip->dma1_size - 1 - new; 792 ptr = chip->dma1_size - 1 - new;
783#else 793#else
784 ptr = inl(SLDM_REG(chip, DMAADDR)) - chip->dma1_start; 794 size_t count;
795 unsigned int diff;
796
797 ptr = inl(SLDM_REG(chip, DMAADDR));
798 count = inw(SLDM_REG(chip, DMACOUNT));
799 diff = chip->dma1_start + chip->dma1_size - ptr - count;
800
801 if (diff > 3 || ptr < chip->dma1_start
802 || ptr >= chip->dma1_start+chip->dma1_size)
803 ptr = chip->last_capture_dmaaddr; /* bad, use last saved */
804 else
805 chip->last_capture_dmaaddr = ptr; /* good, remember it */
806
807 ptr -= chip->dma1_start;
785#endif 808#endif
786 return ptr >> chip->dma1_shift; 809 return ptr >> chip->dma1_shift;
787} 810}