ALSA: ice1724 - Dynamic MIDI TX irq control

MIDI_TX IRQ seems always pending when any bytes on FIFO is available.
Thus, it's better to enable MPU_TX only when any bytres are really
stored in the substream, and disables immediately when the queue
becomes empty.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Takashi Iwai 2008-11-12 16:42:44 +01:00
parent 18e352e4a7
commit e683ec4697
1 changed files with 27 additions and 16 deletions

View File

@ -241,6 +241,8 @@ get_rawmidi_substream(struct snd_ice1712 *ice, unsigned int stream)
struct snd_rawmidi_substream, list);
}
static void enable_midi_irq(struct snd_ice1712 *ice, u8 flag, int enable);
static void vt1724_midi_write(struct snd_ice1712 *ice)
{
struct snd_rawmidi_substream *s;
@ -254,6 +256,11 @@ static void vt1724_midi_write(struct snd_ice1712 *ice)
for (i = 0; i < count; ++i)
outb(buffer[i], ICEREG1724(ice, MPU_DATA));
}
/* mask irq when all bytes have been transmitted.
* enabled again in output_trigger when the new data comes in.
*/
enable_midi_irq(ice, VT1724_IRQ_MPU_TX,
!snd_rawmidi_transmit_empty(s));
}
static void vt1724_midi_read(struct snd_ice1712 *ice)
@ -272,31 +279,34 @@ static void vt1724_midi_read(struct snd_ice1712 *ice)
}
}
static void vt1724_enable_midi_irq(struct snd_rawmidi_substream *substream,
u8 flag, int enable)
/* call with ice->reg_lock */
static void enable_midi_irq(struct snd_ice1712 *ice, u8 flag, int enable)
{
struct snd_ice1712 *ice = substream->rmidi->private_data;
u8 mask;
spin_lock_irq(&ice->reg_lock);
mask = inb(ICEREG1724(ice, IRQMASK));
u8 mask = inb(ICEREG1724(ice, IRQMASK));
if (enable)
mask &= ~flag;
else
mask |= flag;
outb(mask, ICEREG1724(ice, IRQMASK));
}
static void vt1724_enable_midi_irq(struct snd_rawmidi_substream *substream,
u8 flag, int enable)
{
struct snd_ice1712 *ice = substream->rmidi->private_data;
spin_lock_irq(&ice->reg_lock);
enable_midi_irq(ice, flag, enable);
spin_unlock_irq(&ice->reg_lock);
}
static int vt1724_midi_output_open(struct snd_rawmidi_substream *s)
{
vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_TX, 1);
return 0;
}
static int vt1724_midi_output_close(struct snd_rawmidi_substream *s)
{
vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_TX, 0);
return 0;
}
@ -311,6 +321,7 @@ static void vt1724_midi_output_trigger(struct snd_rawmidi_substream *s, int up)
vt1724_midi_write(ice);
} else {
ice->midi_output = 0;
enable_midi_irq(ice, VT1724_IRQ_MPU_TX, 0);
}
spin_unlock_irqrestore(&ice->reg_lock, flags);
}
@ -320,6 +331,7 @@ static void vt1724_midi_output_drain(struct snd_rawmidi_substream *s)
struct snd_ice1712 *ice = s->rmidi->private_data;
unsigned long timeout;
vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_TX, 0);
/* 32 bytes should be transmitted in less than about 12 ms */
timeout = jiffies + msecs_to_jiffies(15);
do {
@ -389,24 +401,24 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id)
status &= status_mask;
if (status == 0)
break;
spin_lock(&ice->reg_lock);
if (++timeout > 10) {
status = inb(ICEREG1724(ice, IRQSTAT));
printk(KERN_ERR "ice1724: Too long irq loop, "
"status = 0x%x\n", status);
if (status & VT1724_IRQ_MPU_TX) {
printk(KERN_ERR "ice1724: Disabling MPU_TX\n");
outb(inb(ICEREG1724(ice, IRQMASK)) |
VT1724_IRQ_MPU_TX,
ICEREG1724(ice, IRQMASK));
enable_midi_irq(ice, VT1724_IRQ_MPU_TX, 0);
}
spin_unlock(&ice->reg_lock);
break;
}
handled = 1;
if (status & VT1724_IRQ_MPU_TX) {
spin_lock(&ice->reg_lock);
if (ice->midi_output)
vt1724_midi_write(ice);
spin_unlock(&ice->reg_lock);
else
enable_midi_irq(ice, VT1724_IRQ_MPU_TX, 0);
/* Due to mysterical reasons, MPU_TX is always
* generated (and can't be cleared) when a PCM
* playback is going. So let's ignore at the
@ -415,15 +427,14 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id)
status_mask &= ~VT1724_IRQ_MPU_TX;
}
if (status & VT1724_IRQ_MPU_RX) {
spin_lock(&ice->reg_lock);
if (ice->midi_input)
vt1724_midi_read(ice);
else
vt1724_midi_clear_rx(ice);
spin_unlock(&ice->reg_lock);
}
/* ack MPU irq */
outb(status, ICEREG1724(ice, IRQSTAT));
spin_unlock(&ice->reg_lock);
if (status & VT1724_IRQ_MTPCM) {
/*
* Multi-track PCM