[alsa-devel] ICE 1724 MIDI support still broken?
Takashi Iwai
tiwai at suse.de
Tue Apr 24 15:00:43 CEST 2007
At Mon, 23 Apr 2007 12:16:11 +0200,
私 wrote:
>
> At Thu, 19 Apr 2007 16:15:26 +0100,
> Daniel James wrote:
> >
> > Hello ALSA team,
> >
> > We have a user with an ESI Juli@ whose Linux box hangs when any MIDI
> > application starts up. I read that MIDI support is broken generally on
> > ICE 1724 cards; is this still the case in recent driver releases?
> >
> > If so, is there any interest in fixing this long-standing issue? The
> > user has indicated that his box would be available by ssh for any tests
> > required.
>
> Well, Juli is hard to fix right now from my side because of lack of
> hardware information. Maybe Jaroslav can do better because he
> apparently had contact with ESI.
I took a bit look at specs and tried to hack.
The below is a revised patch just for fixing possible problems
blindly. It extends mpu401_uart API, too. Give it a spin if you'd
like.
The irq handler has a check of possible endless loops, so it shouldn't
hang up so immediately. Check the kernel log.
If you get a message like "cmd: 0x3f failed at ...", try to uncomment
MPU401_INFO_NO_ACK in the argument of snd_mpu401_uart_new() in
ice1724.c.
You can try also set watermarks by commenting out the block around
line ice1724.c:2465 (/* for testing */) in the case of endless irq
loops.
The patch is against HG version, and I won't debug any older version.
Takashi
diff -r f73f5a4fa439 drivers/mpu401/mpu401_uart.c
--- a/drivers/mpu401/mpu401_uart.c Tue Apr 24 12:27:36 2007 +0200
+++ b/drivers/mpu401/mpu401_uart.c Tue Apr 24 14:45:24 2007 +0200
@@ -50,12 +50,10 @@ static void snd_mpu401_uart_output_write
*/
-#define snd_mpu401_input_avail(mpu) (!(mpu->read(mpu, MPU401C(mpu)) & 0x80))
-#define snd_mpu401_output_ready(mpu) (!(mpu->read(mpu, MPU401C(mpu)) & 0x40))
-
-#define MPU401_RESET 0xff
-#define MPU401_ENTER_UART 0x3f
-#define MPU401_ACK 0xfe
+#define snd_mpu401_input_avail(mpu) \
+ (!(mpu->read(mpu, MPU401C(mpu)) & MPU401_RX_EMPTY))
+#define snd_mpu401_output_ready(mpu) \
+ (!(mpu->read(mpu, MPU401C(mpu)) & MPU401_TX_FULL))
/* Build in lowlevel io */
static void mpu401_write_port(struct snd_mpu401 *mpu, unsigned char data,
@@ -242,7 +240,7 @@ static int snd_mpu401_uart_cmd(struct sn
#endif
}
mpu->write(mpu, cmd, MPU401C(mpu));
- if (ack) {
+ if (ack && !(mpu->info_flags & MPU401_INFO_NO_ACK)) {
ok = 0;
timeout = 10000;
while (!ok && timeout-- > 0) {
diff -r f73f5a4fa439 include/mpu401.h
--- a/include/mpu401.h Tue Apr 24 12:27:36 2007 +0200
+++ b/include/mpu401.h Tue Apr 24 14:44:55 2007 +0200
@@ -51,6 +51,7 @@
#define MPU401_INFO_MMIO (1 << 3) /* MMIO access */
#define MPU401_INFO_TX_IRQ (1 << 4) /* independent TX irq */
#define MPU401_INFO_UART_ONLY (1 << 5) /* No ENTER_UART cmd needed */
+#define MPU401_INFO_NO_ACK (1 << 6) /* No ACK cmd needed */
#define MPU401_MODE_BIT_INPUT 0
#define MPU401_MODE_BIT_OUTPUT 1
@@ -104,6 +105,21 @@ struct snd_mpu401 {
#define MPU401D(mpu) (mpu)->port
/*
+ * control register bits
+ */
+/* read MPU401C() */
+#define MPU401_RX_EMPTY 0x80
+#define MPU401_TX_FULL 0x40
+
+/* write MPU401C() */
+#define MPU401_RESET 0xff
+#define MPU401_ENTER_UART 0x3f
+
+/* read MPU401D() */
+#define MPU401_ACK 0xfe
+
+
+/*
*/
diff -r f73f5a4fa439 pci/ice1712/ice1724.c
--- a/pci/ice1712/ice1724.c Tue Apr 24 12:27:36 2007 +0200
+++ b/pci/ice1712/ice1724.c Tue Apr 24 14:52:07 2007 +0200
@@ -216,6 +216,32 @@ static unsigned int snd_vt1724_get_gpio_
}
/*
+ * MPU401 accessor
+ */
+static unsigned char snd_vt1724_mpu401_read(struct snd_mpu401 *mpu,
+ unsigned long addr)
+{
+ /* fix status bits to the standard position */
+ /* only RX_EMPTY and TX_FULL are checked */
+ if (addr == MPU401C(mpu))
+ return (inb(addr) & 0x0c) << 4;
+ else
+ return inb(addr);
+}
+
+static void snd_vt1724_mpu401_write(struct snd_mpu401 *mpu,
+ unsigned char data, unsigned long addr)
+{
+ if (addr == MPU401C(mpu)) {
+ if (data == MPU401_ENTER_UART)
+ outb(0x01, addr);
+ /* what else? */
+ } else
+ outb(data, addr);
+}
+
+
+/*
* Interrupt handler
*/
@@ -224,23 +250,44 @@ static irqreturn_t snd_vt1724_interrupt(
struct snd_ice1712 *ice = dev_id;
unsigned char status;
int handled = 0;
+#ifdef CONFIG_SND_DEBUG
+ int timeout = 0;
+#endif
while (1) {
status = inb(ICEREG1724(ice, IRQSTAT));
+ status &= VT1724_IRQ_MPU_RX|VT1724_IRQ_MPU_TX|VT1724_IRQ_MTPCM;
if (status == 0)
break;
-
+#ifdef CONFIG_SND_DEBUG
+ if (++timeout > 10) {
+ printk(KERN_ERR
+ "ice1724: Too long irq loop, status = 0x%x\n",
+ status);
+ break;
+ }
+#endif
handled = 1;
- /* these should probably be separated at some point,
- * but as we don't currently have MPU support on the board
- * I will leave it
- */
- if ((status & VT1724_IRQ_MPU_RX)||(status & VT1724_IRQ_MPU_TX)) {
+ if (status & VT1724_IRQ_MPU_TX) {
if (ice->rmidi[0])
- snd_mpu401_uart_interrupt(irq, ice->rmidi[0]->private_data);
- outb(status & (VT1724_IRQ_MPU_RX|VT1724_IRQ_MPU_TX), ICEREG1724(ice, IRQSTAT));
- status &= ~(VT1724_IRQ_MPU_RX|VT1724_IRQ_MPU_TX);
+ snd_mpu401_uart_interrupt_tx(irq,
+ ice->rmidi[0]->private_data);
+ else /* disable TX to be sure */
+ outb(inb(ICEREG1724(ice, IRQMASK)) |
+ VT1724_IRQ_MPU_RX,
+ ICEREG1724(ice, IRQMASK));
}
+ if (status & VT1724_IRQ_MPU_RX) {
+ if (ice->rmidi[0])
+ snd_mpu401_uart_interrupt(irq,
+ ice->rmidi[0]->private_data);
+ else /* disable RX to be sure */
+ outb(inb(ICEREG1724(ice, IRQMASK)) |
+ VT1724_IRQ_MPU_RX,
+ ICEREG1724(ice, IRQMASK));
+ }
+ /* ack MPU irq */
+ outb(status, ICEREG1724(ice, IRQSTAT));
if (status & VT1724_IRQ_MTPCM) {
/*
* Multi-track PCM
@@ -2276,10 +2323,7 @@ static int __devinit snd_vt1724_create(s
}
/* unmask used interrupts */
- if (! (ice->eeprom.data[ICE_EEP2_SYSCONF] & VT1724_CFG_MPU401))
- mask = VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX;
- else
- mask = 0;
+ mask = VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX;
outb(mask, ICEREG1724(ice, IRQMASK));
/* don't handle FIFO overrun/underruns (just yet),
* since they cause machine lockups
@@ -2400,14 +2444,30 @@ static int __devinit snd_vt1724_probe(st
if (! c->no_mpu401) {
if (ice->eeprom.data[ICE_EEP2_SYSCONF] & VT1724_CFG_MPU401) {
+ struct snd_mpu401 *mpu;
if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712,
ICEREG1724(ice, MPU_CTRL),
- MPU401_INFO_INTEGRATED,
+ (MPU401_INFO_INTEGRATED |
+ /*MPU401_INFO_NO_ACK |*/
+ MPU401_INFO_TX_IRQ),
ice->irq, 0,
&ice->rmidi[0])) < 0) {
snd_card_free(card);
return err;
}
+ mpu = ice->rmidi[0]->private_data;
+ mpu->read = snd_vt1724_mpu401_read;
+ mpu->write = snd_vt1724_mpu401_write;
+ /* unmask MPU RX/TX irqs */
+ outb(inb(ICEREG1724(ice, IRQMASK)) &
+ ~(VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX),
+ ICEREG1724(ice, IRQMASK));
+#if 0 /* for testing */
+ /* set watermarks */
+ outb(VT1724_MPU_RX_FIFO | 0x1,
+ ICEREG1724(ice, MPU_FIFO_WM));
+ outb(0x1, ICEREG1724(ice, MPU_FIFO_WM));
+#endif
}
}
More information about the Alsa-devel
mailing list