Commit 56385a12d9bb9e173751f74b6c430742018cafc0

Authored by Jaroslav Kysela
Committed by Takashi Iwai
1 parent a5ba6beb83

ALSA: emu10k1 - delay the PCM interrupts (add pcm_irq_delay parameter)

With some hardware combinations, the PCM interrupts are acknowledged
before the period boundary from the emu10k1 chip. The midlevel PCM code
gets confused and the playback stream is interrupted.

It seems that the interrupt processing shift by 2 samples is enough
to fix this issue. This default value does not harm other,
non-affected hardware.

More information: Kernel bugzilla bug#16300

[A copmile warning fixed by tiwai]

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Cc: <stable@kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>

Showing 5 changed files with 38 additions and 5 deletions Side-by-side Diff

include/sound/emu10k1.h
... ... @@ -1707,6 +1707,7 @@
1707 1707 unsigned int card_type; /* EMU10K1_CARD_* */
1708 1708 unsigned int ecard_ctrl; /* ecard control bits */
1709 1709 unsigned long dma_mask; /* PCI DMA mask */
  1710 + unsigned int delay_pcm_irq; /* in samples */
1710 1711 int max_cache_pages; /* max memory size / PAGE_SIZE */
1711 1712 struct snd_dma_buffer silent_page; /* silent page */
1712 1713 struct snd_dma_buffer ptb_pages; /* page table pages */
sound/core/pcm_native.c
... ... @@ -978,6 +978,10 @@
978 978 {
979 979 if (substream->runtime->trigger_master != substream)
980 980 return 0;
  981 + /* some drivers might use hw_ptr to recover from the pause -
  982 + update the hw_ptr now */
  983 + if (push)
  984 + snd_pcm_update_hw_ptr(substream);
981 985 /* The jiffies check in snd_pcm_update_hw_ptr*() is done by
982 986 * a delta betwen the current jiffies, this gives a large enough
983 987 * delta, effectively to skip the check once.
sound/pci/emu10k1/emu10k1.c
... ... @@ -52,6 +52,7 @@
52 52 static int max_buffer_size[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 128};
53 53 static int enable_ir[SNDRV_CARDS];
54 54 static uint subsystem[SNDRV_CARDS]; /* Force card subsystem model */
  55 +static uint delay_pcm_irq[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
55 56  
56 57 module_param_array(index, int, NULL, 0444);
57 58 MODULE_PARM_DESC(index, "Index value for the EMU10K1 soundcard.");
... ... @@ -73,6 +74,8 @@
73 74 MODULE_PARM_DESC(enable_ir, "Enable IR.");
74 75 module_param_array(subsystem, uint, NULL, 0444);
75 76 MODULE_PARM_DESC(subsystem, "Force card subsystem model.");
  77 +module_param_array(delay_pcm_irq, uint, NULL, 0444);
  78 +MODULE_PARM_DESC(delay_pcm_irq, "Delay PCM interrupt by specified number of samples (default 0).");
76 79 /*
77 80 * Class 0401: 1102:0008 (rev 00) Subsystem: 1102:1001 -> Audigy2 Value Model:SB0400
78 81 */
... ... @@ -127,6 +130,7 @@
127 130 &emu)) < 0)
128 131 goto error;
129 132 card->private_data = emu;
  133 + emu->delay_pcm_irq = delay_pcm_irq[dev] & 0x1f;
130 134 if ((err = snd_emu10k1_pcm(emu, 0, NULL)) < 0)
131 135 goto error;
132 136 if ((err = snd_emu10k1_pcm_mic(emu, 1, NULL)) < 0)
sound/pci/emu10k1/emupcm.c
... ... @@ -332,7 +332,7 @@
332 332 evoice->epcm->ccca_start_addr = start_addr + ccis;
333 333 if (extra) {
334 334 start_addr += ccis;
335   - end_addr += ccis;
  335 + end_addr += ccis + emu->delay_pcm_irq;
336 336 }
337 337 if (stereo && !extra) {
338 338 snd_emu10k1_ptr_write(emu, CPF, voice, CPF_STEREO_MASK);
... ... @@ -360,7 +360,9 @@
360 360 /* Assumption that PT is already 0 so no harm overwriting */
361 361 snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]);
362 362 snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24));
363   - snd_emu10k1_ptr_write(emu, PSST, voice, start_addr | (send_amount[2] << 24));
  363 + snd_emu10k1_ptr_write(emu, PSST, voice,
  364 + (start_addr + (extra ? emu->delay_pcm_irq : 0)) |
  365 + (send_amount[2] << 24));
364 366 if (emu->card_capabilities->emu_model)
365 367 pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */
366 368 else
... ... @@ -732,6 +734,23 @@
732 734 snd_emu10k1_ptr_write(emu, IP, voice, 0);
733 735 }
734 736  
  737 +static inline void snd_emu10k1_playback_mangle_extra(struct snd_emu10k1 *emu,
  738 + struct snd_emu10k1_pcm *epcm,
  739 + struct snd_pcm_substream *substream,
  740 + struct snd_pcm_runtime *runtime)
  741 +{
  742 + unsigned int ptr, period_pos;
  743 +
  744 + /* try to sychronize the current position for the interrupt
  745 + source voice */
  746 + period_pos = runtime->status->hw_ptr - runtime->hw_ptr_interrupt;
  747 + period_pos %= runtime->period_size;
  748 + ptr = snd_emu10k1_ptr_read(emu, CCCA, epcm->extra->number);
  749 + ptr &= ~0x00ffffff;
  750 + ptr |= epcm->ccca_start_addr + period_pos;
  751 + snd_emu10k1_ptr_write(emu, CCCA, epcm->extra->number, ptr);
  752 +}
  753 +
735 754 static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream,
736 755 int cmd)
737 756 {
... ... @@ -753,6 +772,8 @@
753 772 /* follow thru */
754 773 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
755 774 case SNDRV_PCM_TRIGGER_RESUME:
  775 + if (cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE)
  776 + snd_emu10k1_playback_mangle_extra(emu, epcm, substream, runtime);
756 777 mix = &emu->pcm_mixer[substream->number];
757 778 snd_emu10k1_playback_prepare_voice(emu, epcm->voices[0], 1, 0, mix);
758 779 snd_emu10k1_playback_prepare_voice(emu, epcm->voices[1], 0, 0, mix);
... ... @@ -869,8 +890,9 @@
869 890 #endif
870 891 /*
871 892 printk(KERN_DEBUG
872   - "ptr = 0x%x, buffer_size = 0x%x, period_size = 0x%x\n",
873   - ptr, runtime->buffer_size, runtime->period_size);
  893 + "ptr = 0x%lx, buffer_size = 0x%lx, period_size = 0x%lx\n",
  894 + (long)ptr, (long)runtime->buffer_size,
  895 + (long)runtime->period_size);
874 896 */
875 897 return ptr;
876 898 }
sound/pci/emu10k1/memory.c
... ... @@ -310,8 +310,10 @@
310 310 if (snd_BUG_ON(!hdr))
311 311 return NULL;
312 312  
  313 + idx = runtime->period_size >= runtime->buffer_size ?
  314 + (emu->delay_pcm_irq * 2) : 0;
313 315 mutex_lock(&hdr->block_mutex);
314   - blk = search_empty(emu, runtime->dma_bytes);
  316 + blk = search_empty(emu, runtime->dma_bytes + idx);
315 317 if (blk == NULL) {
316 318 mutex_unlock(&hdr->block_mutex);
317 319 return NULL;