Hello! This is a solution to an old problem with full duplex on SB16 cards, described in detail in
http://www.mail-archive.com/alsa-user@;lists.sourceforge.net/msg02194.html The core of this problem is, that ALSA is sending SB_DSP_DMA[8|16]_OFF 0xd0/0xd5 command instead of SB_DSP_DMA[8/16]_EXIT commands 0xda/0xd9. SB_DSP_DMA*_OFF command in fact only "pause" DMA transfer and does not clear pending interrupt in sb16 chip. But the problem with SB_DSP_DMA*_EXIT command is, that it causes unwanted repeat of last period as SNDRV_PCM_TRIGGER_STOP command is sent after last period. Thus, at the end of playback/capture, sb16 IRQ will not be acknowledged, and no further interrupts will occur. In a problem description, I can find: start capture -> ack 16bit IRQ in snd_sb16_setup_rate() function start playback -> ack 8bit IRQ stop playback -> 8bit IRQ is pending stop capture -> 8bit IRQ is pending start playback -> clear 16bit IRQ In this state, 8bit IRQ is still pending! It looks that with some SB DSP chip versions, this will block generation of 8 _and_ 16bit IRQs. Attached patch (untested!) acknowledges [16|8] bit interrupt, but adds [8|16] bit acknowledge, if secondary channel is not in use at the moment. Please, could someone with described problems test this patch. Another problem, described in http://www.mail-archive.com/alsa-user@;lists.sourceforge.net/msg04960.html is perhaps connected with the way sb16 driver reports mutual sample rate, when one channel is already in use. Locked rate will be reported only when second channel is opened, so it is possible that selected rate won't be programmed to sb16 chip if capture and playback channels are opened simultaneously and no playback/capture has started yet. Uros.
Index: sb16_main.c =================================================================== RCS file: /cvsroot/alsa/alsa-kernel/isa/sb/sb16_main.c,v retrieving revision 1.12 diff -u -r1.12 sb16_main.c --- sb16_main.c 23 Oct 2002 19:07:44 -0000 1.12 +++ sb16_main.c 7 Nov 2002 12:23:09 -0000 @@ -224,10 +224,30 @@ unsigned long flags; spin_lock_irqsave(&chip->reg_lock, flags); - if (chip->mode & (channel == SNDRV_PCM_STREAM_PLAYBACK ? SB_MODE_PLAYBACK_16 : SB_MODE_CAPTURE_16)) - snd_sb_ack_16bit(chip); - else - snd_sb_ack_8bit(chip); + + /* acknowledge stalled interrupts */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (chip->mode & SB_MODE_PLAYBACK_16) { + snd_sb_ack_16bit(chip); + if (! (chip->mode & SB_RATE_LOCK_CAPTURE)) + snd_sb_ack_8bit(chip); + } else { + snd_sb_ack_8bit(chip); + if (! (chip->mode & SB_RATE_LOCK_CAPTURE)) + snd_sb_ack_16bit(chip); + } + } else { + if (chip->mode & SB_MODE_CAPTURE_16) { + snd_sb_ack_16bit(chip); + if (! (chip->mode & SB_RATE_LOCK_PLAYBACK)) + snd_sb_ack_8bit(chip); + } else { + snd_sb_ack_8bit(chip); + if (! (chip->mode & SB_RATE_LOCK_PLAYBACK)) + snd_sb_ack_16bit(chip); + } + } + if (!(chip->mode & SB_RATE_LOCK)) { chip->locked_rate = rate; snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE_IN);