UnduingВо-первых проверь правильно ли определился базовый порт (
sb_base_port).
Во-вторых у тебя вроде бы
Vibra16? Если так то
ALSA тебе в помощь (путь alsa-driver-x.x.x\alsa-kernel\isa\sb).
Там в модуле
sb16_main.c обработчик выглядит так:
Code:
irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id)
{
struct snd_sb *chip = dev_id;
unsigned char status;
int ok;
spin_lock(&chip->mixer_lock);
status = snd_sbmixer_read(chip, SB_DSP4_IRQSTATUS);
spin_unlock(&chip->mixer_lock);
if ((status & SB_IRQTYPE_MPUIN) && chip->rmidi_callback)
chip->rmidi_callback(irq, chip->rmidi->private_data);
if (status & SB_IRQTYPE_8BIT) {
ok = 0;
if (chip->mode & SB_MODE_PLAYBACK_8) {
snd_pcm_period_elapsed(chip->playback_substream);
snd_sb16_csp_update(chip);
ok++;
}
if (chip->mode & SB_MODE_CAPTURE_8) {
snd_pcm_period_elapsed(chip->capture_substream);
ok++;
}
spin_lock(&chip->reg_lock);
if (!ok)
snd_sbdsp_command(chip, SB_DSP_DMA8_OFF);
snd_sb_ack_8bit(chip);
spin_unlock(&chip->reg_lock);
}
if (status & SB_IRQTYPE_16BIT) {
ok = 0;
if (chip->mode & SB_MODE_PLAYBACK_16) {
snd_pcm_period_elapsed(chip->playback_substream);
snd_sb16_csp_update(chip);
ok++;
}
if (chip->mode & SB_MODE_CAPTURE_16) {
snd_pcm_period_elapsed(chip->capture_substream);
ok++;
}
spin_lock(&chip->reg_lock);
if (!ok)
snd_sbdsp_command(chip, SB_DSP_DMA16_OFF);
snd_sb_ack_16bit(chip);
spin_unlock(&chip->reg_lock);
}
return IRQ_HANDLED;
}
В зависимости от переменной
status прерывание может быть 8-ми или 16-ти битным.
Статус читается вот этой процедурой из модуля
sb_mixer.c:
Code:
unsigned char snd_sbmixer_read(struct snd_sb *chip, unsigned char reg)
{
unsigned char result;
outb(reg, SBP(chip, MIXER_ADDR));
udelay(10);
result = inb(SBP(chip, MIXER_DATA));
udelay(10);
#ifdef IO_DEBUG
snd_printk(KERN_DEBUG "mixer_read 0x%x 0x%x\n", reg, result);
#endif
return result;
}
В
sb.h можно найти процедуры
snd_sb_ack_8bit и
snd_sb_ack_16bit.
Code:
static inline void snd_sb_ack_8bit(struct snd_sb *chip)
{
inb(SBP(chip, DATA_AVAIL));
}
static inline void snd_sb_ack_16bit(struct snd_sb *chip)
{
inb(SBP(chip, DATA_AVAIL_16));
}
В текущем обработчике прерываний драйвера для
sb16 есть реализация только
snd_sb_ack_16bit, вот она
Code:
225 mov edx,[sb_base_port] ;tell the DSP that we have processed IRQ
226 add dl,0xF ;0xF for 16 bit sound, 0xE for 8 bit sound
227 in al,dx ;for non-stop sound
Статус не проверяется, может быть и в этом проблема, может и не в этом нужно проверить.
Если базовый порт всё-таки определяется верно, попробуй добавить к обработчику чтение статуса:
Code:
mov edx,[sb_base_port]
add dl,0xF
mov al, 0x4
out dx,al
inc dl
mov eax, 10000 ; wait 10 ms
call StallExec
in al,dx
push eax
mov eax, 10000 ; wait 10 ms
call StallExec
pop eax
и обработку 8 битного прерывания:
Code:
mov edx,[sb_base_port] ;tell the DSP that we have processed IRQ
add dl,0xE ;0xF for 16 bit sound, 0xE for 8 bit sound
in al,dx ;for non-stop sound
StallExec можно взять
здесь.
Да и ещё наверное лучше будет сообщать о завершении обработки прерывания в конце, а не в начале обработчика.