diff options
Diffstat (limited to 'sound/pci/es1938.c')
-rw-r--r-- | sound/pci/es1938.c | 28 |
1 files changed, 25 insertions, 3 deletions
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index fb25abe68a02..1a314fa99c45 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c | |||
@@ -47,7 +47,6 @@ | |||
47 | */ | 47 | */ |
48 | 48 | ||
49 | 49 | ||
50 | #include <sound/driver.h> | ||
51 | #include <linux/init.h> | 50 | #include <linux/init.h> |
52 | #include <linux/interrupt.h> | 51 | #include <linux/interrupt.h> |
53 | #include <linux/pci.h> | 52 | #include <linux/pci.h> |
@@ -227,6 +226,7 @@ struct es1938 { | |||
227 | unsigned int dma2_start; | 226 | unsigned int dma2_start; |
228 | unsigned int dma1_shift; | 227 | unsigned int dma1_shift; |
229 | unsigned int dma2_shift; | 228 | unsigned int dma2_shift; |
229 | unsigned int last_capture_dmaaddr; | ||
230 | unsigned int active; | 230 | unsigned int active; |
231 | 231 | ||
232 | spinlock_t reg_lock; | 232 | spinlock_t reg_lock; |
@@ -529,6 +529,7 @@ static void snd_es1938_capture_setdma(struct es1938 *chip) | |||
529 | outb(1, SLDM_REG(chip, DMAMASK)); | 529 | outb(1, SLDM_REG(chip, DMAMASK)); |
530 | outb(0x14, SLDM_REG(chip, DMAMODE)); | 530 | outb(0x14, SLDM_REG(chip, DMAMODE)); |
531 | 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; | ||
532 | outw(chip->dma1_size - 1, SLDM_REG(chip, DMACOUNT)); | 533 | outw(chip->dma1_size - 1, SLDM_REG(chip, DMACOUNT)); |
533 | /* 3. Unmask DMA */ | 534 | /* 3. Unmask DMA */ |
534 | outb(0, SLDM_REG(chip, DMAMASK)); | 535 | outb(0, SLDM_REG(chip, DMAMASK)); |
@@ -770,19 +771,40 @@ static int snd_es1938_playback_prepare(struct snd_pcm_substream *substream) | |||
770 | return -EINVAL; | 771 | return -EINVAL; |
771 | } | 772 | } |
772 | 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 | */ | ||
773 | static snd_pcm_uframes_t snd_es1938_capture_pointer(struct snd_pcm_substream *substream) | 782 | static snd_pcm_uframes_t snd_es1938_capture_pointer(struct snd_pcm_substream *substream) |
774 | { | 783 | { |
775 | struct es1938 *chip = snd_pcm_substream_chip(substream); | 784 | struct es1938 *chip = snd_pcm_substream_chip(substream); |
776 | size_t ptr; | 785 | size_t ptr; |
786 | #if 0 | ||
777 | size_t old, new; | 787 | size_t old, new; |
778 | #if 1 | ||
779 | /* This stuff is *needed*, don't ask why - AB */ | 788 | /* This stuff is *needed*, don't ask why - AB */ |
780 | old = inw(SLDM_REG(chip, DMACOUNT)); | 789 | old = inw(SLDM_REG(chip, DMACOUNT)); |
781 | while ((new = inw(SLDM_REG(chip, DMACOUNT))) != old) | 790 | while ((new = inw(SLDM_REG(chip, DMACOUNT))) != old) |
782 | old = new; | 791 | old = new; |
783 | ptr = chip->dma1_size - 1 - new; | 792 | ptr = chip->dma1_size - 1 - new; |
784 | #else | 793 | #else |
785 | 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; | ||
786 | #endif | 808 | #endif |
787 | return ptr >> chip->dma1_shift; | 809 | return ptr >> chip->dma1_shift; |
788 | } | 810 | } |