mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-31 12:10:52 -04:00
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 <[email protected]> Cc: <[email protected]> Signed-off-by: Takashi Iwai <[email protected]>
This commit is contained in:
parent
a5ba6beb83
commit
56385a12d9
5 changed files with 38 additions and 5 deletions
|
|
@ -52,6 +52,7 @@ static int max_synth_voices[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 64};
|
|||
static int max_buffer_size[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 128};
|
||||
static int enable_ir[SNDRV_CARDS];
|
||||
static uint subsystem[SNDRV_CARDS]; /* Force card subsystem model */
|
||||
static uint delay_pcm_irq[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
|
||||
|
||||
module_param_array(index, int, NULL, 0444);
|
||||
MODULE_PARM_DESC(index, "Index value for the EMU10K1 soundcard.");
|
||||
|
|
@ -73,6 +74,8 @@ module_param_array(enable_ir, bool, NULL, 0444);
|
|||
MODULE_PARM_DESC(enable_ir, "Enable IR.");
|
||||
module_param_array(subsystem, uint, NULL, 0444);
|
||||
MODULE_PARM_DESC(subsystem, "Force card subsystem model.");
|
||||
module_param_array(delay_pcm_irq, uint, NULL, 0444);
|
||||
MODULE_PARM_DESC(delay_pcm_irq, "Delay PCM interrupt by specified number of samples (default 0).");
|
||||
/*
|
||||
* Class 0401: 1102:0008 (rev 00) Subsystem: 1102:1001 -> Audigy2 Value Model:SB0400
|
||||
*/
|
||||
|
|
@ -127,6 +130,7 @@ static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci,
|
|||
&emu)) < 0)
|
||||
goto error;
|
||||
card->private_data = emu;
|
||||
emu->delay_pcm_irq = delay_pcm_irq[dev] & 0x1f;
|
||||
if ((err = snd_emu10k1_pcm(emu, 0, NULL)) < 0)
|
||||
goto error;
|
||||
if ((err = snd_emu10k1_pcm_mic(emu, 1, NULL)) < 0)
|
||||
|
|
|
|||
|
|
@ -332,7 +332,7 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu,
|
|||
evoice->epcm->ccca_start_addr = start_addr + ccis;
|
||||
if (extra) {
|
||||
start_addr += ccis;
|
||||
end_addr += ccis;
|
||||
end_addr += ccis + emu->delay_pcm_irq;
|
||||
}
|
||||
if (stereo && !extra) {
|
||||
snd_emu10k1_ptr_write(emu, CPF, voice, CPF_STEREO_MASK);
|
||||
|
|
@ -360,7 +360,9 @@ static void snd_emu10k1_pcm_init_voice(struct snd_emu10k1 *emu,
|
|||
/* Assumption that PT is already 0 so no harm overwriting */
|
||||
snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]);
|
||||
snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24));
|
||||
snd_emu10k1_ptr_write(emu, PSST, voice, start_addr | (send_amount[2] << 24));
|
||||
snd_emu10k1_ptr_write(emu, PSST, voice,
|
||||
(start_addr + (extra ? emu->delay_pcm_irq : 0)) |
|
||||
(send_amount[2] << 24));
|
||||
if (emu->card_capabilities->emu_model)
|
||||
pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */
|
||||
else
|
||||
|
|
@ -732,6 +734,23 @@ static void snd_emu10k1_playback_stop_voice(struct snd_emu10k1 *emu, struct snd_
|
|||
snd_emu10k1_ptr_write(emu, IP, voice, 0);
|
||||
}
|
||||
|
||||
static inline void snd_emu10k1_playback_mangle_extra(struct snd_emu10k1 *emu,
|
||||
struct snd_emu10k1_pcm *epcm,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_runtime *runtime)
|
||||
{
|
||||
unsigned int ptr, period_pos;
|
||||
|
||||
/* try to sychronize the current position for the interrupt
|
||||
source voice */
|
||||
period_pos = runtime->status->hw_ptr - runtime->hw_ptr_interrupt;
|
||||
period_pos %= runtime->period_size;
|
||||
ptr = snd_emu10k1_ptr_read(emu, CCCA, epcm->extra->number);
|
||||
ptr &= ~0x00ffffff;
|
||||
ptr |= epcm->ccca_start_addr + period_pos;
|
||||
snd_emu10k1_ptr_write(emu, CCCA, epcm->extra->number, ptr);
|
||||
}
|
||||
|
||||
static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream,
|
||||
int cmd)
|
||||
{
|
||||
|
|
@ -753,6 +772,8 @@ static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream,
|
|||
/* follow thru */
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
if (cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE)
|
||||
snd_emu10k1_playback_mangle_extra(emu, epcm, substream, runtime);
|
||||
mix = &emu->pcm_mixer[substream->number];
|
||||
snd_emu10k1_playback_prepare_voice(emu, epcm->voices[0], 1, 0, mix);
|
||||
snd_emu10k1_playback_prepare_voice(emu, epcm->voices[1], 0, 0, mix);
|
||||
|
|
@ -869,8 +890,9 @@ static snd_pcm_uframes_t snd_emu10k1_playback_pointer(struct snd_pcm_substream *
|
|||
#endif
|
||||
/*
|
||||
printk(KERN_DEBUG
|
||||
"ptr = 0x%x, buffer_size = 0x%x, period_size = 0x%x\n",
|
||||
ptr, runtime->buffer_size, runtime->period_size);
|
||||
"ptr = 0x%lx, buffer_size = 0x%lx, period_size = 0x%lx\n",
|
||||
(long)ptr, (long)runtime->buffer_size,
|
||||
(long)runtime->period_size);
|
||||
*/
|
||||
return ptr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -310,8 +310,10 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst
|
|||
if (snd_BUG_ON(!hdr))
|
||||
return NULL;
|
||||
|
||||
idx = runtime->period_size >= runtime->buffer_size ?
|
||||
(emu->delay_pcm_irq * 2) : 0;
|
||||
mutex_lock(&hdr->block_mutex);
|
||||
blk = search_empty(emu, runtime->dma_bytes);
|
||||
blk = search_empty(emu, runtime->dma_bytes + idx);
|
||||
if (blk == NULL) {
|
||||
mutex_unlock(&hdr->block_mutex);
|
||||
return NULL;
|
||||
|
|
|
|||
Loading…
Reference in a new issue