[alsa-devel] MIDI on ice1724 - preliminary findings and questions
Hi,
I am trying to fix the ancient MIDI problem with ice1724 cards. I applied Takashi's patch from http://mailman.alsa-project.org/pipermail/alsa-devel/2007-April/000641.html and made some minor changes (MPU401_INFO_INPUT | MPU401_INFO_OUTPUT to mpu401_uart info_flags, added a few debugs for testing).
I can test only MIDI input using my MIDI keyboard, I have no MIDI output device available. The input works fine now, the output most probably too since the method snd_vt1724_mpu401_write gets called when transmitting some data with amidi.
But here is the problem I do not understand:
When no MIDI input/output is used, the interrupt handler snd_vt1724_interrupt gets called with interrupt status 0x10 which correctly refers to the audio data interrupt (VT1724_IRQ_MTPCM).
However, when MIDI input or output is used (opened) even for a short time after the module is loaded, any subsequent audio playback generates interrupt status of 0x30 which refers to VT1724_IRQ_MTPCM AND VT1724_IRQ_MPU_TX. I have no idea why VT1724_IRQ_MPU_TX gets generated.
The first run of the snd_vt1724_interrupt loop tries to handle the MPU TX status, calling uart_interrupt_tx in mpu401_uart.c:
if (test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode) && test_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode)) { spin_lock_irqsave(&mpu->output_lock, flags); snd_mpu401_uart_output_write(mpu); spin_unlock_irqrestore(&mpu->output_lock, flags); }
However, since the MPU output is not open at this time (no MIDI is being transmitted), the call to snd_mpu401_uart_output_write is skipped. Even though I think the interrupt status should get cleared by
outb(status, ICEREG1724(ice, IRQSTAT))
the loop repeats with the MPU TX interrupt status enabled until the timeout check breaks the while loop, returning to the interrupt handler the next moment again.
Apr 19 22:20:47 nahore kernel: [ 2402.938245] uart interrupt: status 0x30 Apr 19 22:20:47 nahore kernel: [ 2402.938260] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.938267] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.938274] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.938281] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.938288] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.938295] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.938302] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.938309] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.938316] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.938323] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.938326] ice1724: Too long irq loop, status = 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.961247] uart interrupt: status 0x30 Apr 19 22:20:47 nahore kernel: [ 2402.961278] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.961285] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.961292] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.961299] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.961306] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.961313] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.961320] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.961327] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.961334] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.961341] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.961344] ice1724: Too long irq loop, status = 0x20
After the playback stops, the interrupts are gone too. It seems as if the playback interrupt initiates the MPU TX interrupt.
If we could avoid generating the MPU TX interrupt during regular playback, I believe the major problem would be resolved.
Even if I mask the interrupts (CCS01) and do not explicitly unmask them (according to proc ice1724 the CCS01 register stays at 0xa0), the interrupt gets generated.
I am enclosing the testing patch producing the above given results.
Thanks a lot for any suggestion or help.
Regards,
Pavel.
At Tue, 22 Apr 2008 22:23:55 +0200, Pavel Hofman wrote:
Hi,
I am trying to fix the ancient MIDI problem with ice1724 cards. I applied Takashi's patch from http://mailman.alsa-project.org/pipermail/alsa-devel/2007-April/000641.html and made some minor changes (MPU401_INFO_INPUT | MPU401_INFO_OUTPUT to mpu401_uart info_flags, added a few debugs for testing).
Thanks for tracking this bug!
I can test only MIDI input using my MIDI keyboard, I have no MIDI output device available. The input works fine now, the output most probably too since the method snd_vt1724_mpu401_write gets called when transmitting some data with amidi.
But here is the problem I do not understand:
When no MIDI input/output is used, the interrupt handler snd_vt1724_interrupt gets called with interrupt status 0x10 which correctly refers to the audio data interrupt (VT1724_IRQ_MTPCM).
However, when MIDI input or output is used (opened) even for a short time after the module is loaded, any subsequent audio playback generates interrupt status of 0x30 which refers to VT1724_IRQ_MTPCM AND VT1724_IRQ_MPU_TX. I have no idea why VT1724_IRQ_MPU_TX gets generated.
The first run of the snd_vt1724_interrupt loop tries to handle the MPU TX status, calling uart_interrupt_tx in mpu401_uart.c:
if (test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode) && test_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode)) { spin_lock_irqsave(&mpu->output_lock, flags); snd_mpu401_uart_output_write(mpu); spin_unlock_irqrestore(&mpu->output_lock, flags); }
However, since the MPU output is not open at this time (no MIDI is being transmitted), the call to snd_mpu401_uart_output_write is skipped. Even though I think the interrupt status should get cleared by
outb(status, ICEREG1724(ice, IRQSTAT))
the loop repeats with the MPU TX interrupt status enabled until the timeout check breaks the while loop, returning to the interrupt handler the next moment again.
Apr 19 22:20:47 nahore kernel: [ 2402.938245] uart interrupt: status 0x30 Apr 19 22:20:47 nahore kernel: [ 2402.938260] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.938267] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.938274] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.938281] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.938288] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.938295] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.938302] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.938309] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.938316] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.938323] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.938326] ice1724: Too long irq loop, status = 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.961247] uart interrupt: status 0x30 Apr 19 22:20:47 nahore kernel: [ 2402.961278] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.961285] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.961292] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.961299] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.961306] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.961313] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.961320] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.961327] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.961334] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.961341] uart interrupt: status 0x20 Apr 19 22:20:47 nahore kernel: [ 2402.961344] ice1724: Too long irq loop, status = 0x20
After the playback stops, the interrupts are gone too. It seems as if the playback interrupt initiates the MPU TX interrupt.
If we could avoid generating the MPU TX interrupt during regular playback, I believe the major problem would be resolved.
Even if I mask the interrupts (CCS01) and do not explicitly unmask them (according to proc ice1724 the CCS01 register stays at 0xa0), the interrupt gets generated.
OK, then the simplest way would be to just ignore the TX bit at the second or later check.
How about the patch below?
thanks,
Takashi
---
diff -r f8fbce7ba459 drivers/mpu401/mpu401_uart.c --- a/drivers/mpu401/mpu401_uart.c Tue Apr 22 18:39:49 2008 +0200 +++ b/drivers/mpu401/mpu401_uart.c Wed Apr 23 12:04:54 2008 +0200 @@ -49,12 +49,10 @@
*/
-#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, diff -r f8fbce7ba459 include/mpu401.h --- a/include/mpu401.h Tue Apr 22 18:39:49 2008 +0200 +++ b/include/mpu401.h Wed Apr 23 12:04:54 2008 +0200 @@ -103,6 +103,21 @@ #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 f8fbce7ba459 pci/ice1712/ice1724.c --- a/pci/ice1712/ice1724.c Tue Apr 22 18:39:49 2008 +0200 +++ b/pci/ice1712/ice1724.c Wed Apr 23 12:04:54 2008 +0200 @@ -223,6 +223,32 @@ }
/* + * 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 */
@@ -230,24 +256,53 @@ { struct snd_ice1712 *ice = dev_id; unsigned char status; + unsigned char status_mask = + VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX | VT1724_IRQ_MTPCM; int handled = 0; +#ifdef CONFIG_SND_DEBUG + int timeout = 0; +#endif
while (1) { status = inb(ICEREG1724(ice, IRQSTAT)); + status &= status_mask; 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_TX, + ICEREG1724(ice, IRQMASK)); + /* 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 + * next loop. + */ + status_mask &= ~VT1724_IRQ_MPU_TX; } + 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 @@ -2236,10 +2291,7 @@ }
/* 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 @@ -2373,14 +2425,29 @@
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_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 } }
diff -r f8fbce7ba459 pci/ice1712/prodigy192.c --- a/pci/ice1712/prodigy192.c Tue Apr 22 18:39:49 2008 +0200 +++ b/pci/ice1712/prodigy192.c Wed Apr 23 12:04:54 2008 +0200 @@ -812,10 +812,6 @@ .build_controls = prodigy192_add_controls, .eeprom_size = sizeof(prodigy71_eeprom), .eeprom_data = prodigy71_eeprom, - /* the current MPU401 code loops infinitely - * when opening midi device - */ - .no_mpu401 = 1, }, { } /* terminator */ };
Takashi Iwai wrote:
At Tue, 22 Apr 2008 22:23:55 +0200, Pavel Hofman wrote:
Hi,
...........
After the playback stops, the interrupts are gone too. It seems as if the playback interrupt initiates the MPU TX interrupt.
If we could avoid generating the MPU TX interrupt during regular playback, I believe the major problem would be resolved.
Even if I mask the interrupts (CCS01) and do not explicitly unmask them (according to proc ice1724 the CCS01 register stays at 0xa0), the interrupt gets generated.
OK, then the simplest way would be to just ignore the TX bit at the second or later check.
How about the patch below?
Takashi, thanks for the hack idea. The overhead is just one more loop which is nothing. I will test it and post details of further problems (there is a bunch of them :) )
Pavel.
Pavel Hofman wrote:
Takashi Iwai wrote:
At Tue, 22 Apr 2008 22:23:55 +0200, Pavel Hofman wrote:
Hi,
...........
After the playback stops, the interrupts are gone too. It seems as if the playback interrupt initiates the MPU TX interrupt.
If we could avoid generating the MPU TX interrupt during regular playback, I believe the major problem would be resolved.
Even if I mask the interrupts (CCS01) and do not explicitly unmask them (according to proc ice1724 the CCS01 register stays at 0xa0), the interrupt gets generated.
OK, then the simplest way would be to just ignore the TX bit at the second or later check.
How about the patch below?
Takashi, thanks for the hack idea. The overhead is just one more loop which is nothing. I will test it and post details of further problems (there is a bunch of them :) )
Hi,
The hack works fine, I am finally getting no CPU burning during playback and MIDI input/output.
Now the next problem are delays. amidi through ice1724 prints the rawmidi data a fraction of a second later compared to USB midi input. I guess there is not much we could do about it. The format is a bit different which probably does not matter:
pavel@nahore:~$ amidi -l Dir Device Name IO hw:0,0 Audiotrak Prodigy 192 MIDI IO hw:1,0,0 Keystation Pro 88 MIDI 1 I hw:1,0,1 Keystation Pro 88 MIDI 2
ice1724 midi: pavel@nahore:~$ amidi -p hw:0 -d
90 2D 5E 2D 00 90 30 79 30 00
USB midi: pavel@nahore:~$ amidi -p hw:1 -d
90 2D 4C 90 2D 00 90 30 5E 90 30 00
However, what makes a huge delay difference is the next step - aseqdump. Here USB still outputs data immediately:
pavel@nahore:~$ aseqdump -p 20:0 Waiting for data. Press Ctrl+C to end. Source_ Event_________________ Ch _Data__ 20:0 Note on 0 41 94 20:0 Note on 0 41 0 20:0 Note on 0 45 80 20:0 Note on 0 45 0
Whereas through ice1724 midi it takes several seconds for the same notes to appear in aseqdump:
pavel@nahore:~$ aseqdump -p 16:0 Waiting for data. Press Ctrl+C to end. Source_ Event_________________ Ch _Data__ 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing 16:0 Note on 0 43 86 16:0 Note on 0 43 0 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing 16:0 Note on 0 47 100 16:0 Note on 0 47 0 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing
Google told me the "Active Sensing" messages are OK. Still, the whole pack of lines appears at once, but with a huge delay.
When hooking Qsynth to the inputs, notes through USB sound immediately, Notes through ice1724 get delayed by several seconds, but mostly they produce no sound at all. Surprisingly, the few notes which actually make it through sound long (just like the piano sustain pedal). USB notes do not have this effect.
Please make respective fixes to the enclosed patch as it involves some changes that make the MPU401 actually work.
Thanks a lot for advice and suggestions.
Pavel.
At Wed, 23 Apr 2008 22:19:04 +0200, Pavel Hofman wrote:
Pavel Hofman wrote:
Takashi Iwai wrote:
At Tue, 22 Apr 2008 22:23:55 +0200, Pavel Hofman wrote:
Hi,
...........
After the playback stops, the interrupts are gone too. It seems as if the playback interrupt initiates the MPU TX interrupt.
If we could avoid generating the MPU TX interrupt during regular playback, I believe the major problem would be resolved.
Even if I mask the interrupts (CCS01) and do not explicitly unmask them (according to proc ice1724 the CCS01 register stays at 0xa0), the interrupt gets generated.
OK, then the simplest way would be to just ignore the TX bit at the second or later check.
How about the patch below?
Takashi, thanks for the hack idea. The overhead is just one more loop which is nothing. I will test it and post details of further problems (there is a bunch of them :) )
Hi,
The hack works fine, I am finally getting no CPU burning during playback and MIDI input/output.
Thanks for checking. The fixed patches are on HG tree now. Please sync your tree.
Now the next problem are delays. amidi through ice1724 prints the rawmidi data a fraction of a second later compared to USB midi input. I guess there is not much we could do about it. The format is a bit different which probably does not matter:
pavel@nahore:~$ amidi -l Dir Device Name IO hw:0,0 Audiotrak Prodigy 192 MIDI IO hw:1,0,0 Keystation Pro 88 MIDI 1 I hw:1,0,1 Keystation Pro 88 MIDI 2
ice1724 midi: pavel@nahore:~$ amidi -p hw:0 -d
90 2D 5E 2D 00 90 30 79 30 00
USB midi: pavel@nahore:~$ amidi -p hw:1 -d
90 2D 4C 90 2D 00 90 30 5E 90 30 00
However, what makes a huge delay difference is the next step - aseqdump. Here USB still outputs data immediately:
pavel@nahore:~$ aseqdump -p 20:0 Waiting for data. Press Ctrl+C to end. Source_ Event_________________ Ch _Data__ 20:0 Note on 0 41 94 20:0 Note on 0 41 0 20:0 Note on 0 45 80 20:0 Note on 0 45 0
Whereas through ice1724 midi it takes several seconds for the same notes to appear in aseqdump:
pavel@nahore:~$ aseqdump -p 16:0 Waiting for data. Press Ctrl+C to end. Source_ Event_________________ Ch _Data__ 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing 16:0 Note on 0 43 86 16:0 Note on 0 43 0 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing 16:0 Note on 0 47 100 16:0 Note on 0 47 0 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing 16:0 Active Sensing
Google told me the "Active Sensing" messages are OK. Still, the whole pack of lines appears at once, but with a huge delay.
When hooking Qsynth to the inputs, notes through USB sound immediately, Notes through ice1724 get delayed by several seconds, but mostly they produce no sound at all. Surprisingly, the few notes which actually make it through sound long (just like the piano sustain pedal). USB notes do not have this effect.
So, now it's a problem of MIDI "input", if I understand correctly? What we need to check at first is whether the MPU_RX irq is issued at the correct timing. If not, check whether MPU watermarks (MPU_FIFO_WM, CCS0E). According to the datasheet, the values are 0 for both RX and TX.
Takashi
Takashi Iwai wrote:
At Wed, 23 Apr 2008 22:19:04 +0200, Pavel Hofman wrote:
Pavel Hofman wrote:
Takashi Iwai wrote:
At Tue, 22 Apr 2008 22:23:55 +0200, Pavel Hofman wrote:
Hi,
...........
After the playback stops, the interrupts are gone too. It seems as if the playback interrupt initiates the MPU TX interrupt.
If we could avoid generating the MPU TX interrupt during regular playback, I believe the major problem would be resolved.
Even if I mask the interrupts (CCS01) and do not explicitly unmask them (according to proc ice1724 the CCS01 register stays at 0xa0), the interrupt gets generated.
OK, then the simplest way would be to just ignore the TX bit at the second or later check.
How about the patch below?
Takashi, thanks for the hack idea. The overhead is just one more loop which is nothing. I will test it and post details of further problems (there is a bunch of them :) )
Hi,
The hack works fine, I am finally getting no CPU burning during playback and MIDI input/output.
Thanks for checking. The fixed patches are on HG tree now. Please sync your tree.
Takashi, the patch you put into HG was not the one I sent you, but sort of the original one that I said did not work.
pavel@nahore:~$ amidi -p hw:0 -d ALSA lib rawmidi_hw.c:233:(snd_rawmidi_hw_open) open /dev/snd/midiC0D0 failed: Input/output error cannot open port "hw:0": Input/output error
amidi -p hw:0 -S F0411042110C000000000074FF0411042110C000000000074F7F0411042110C000000000\ 074F7F0411042110C0F0411042110C000000000074FF0411042110C000000000074F7F041\ 1042110C000000000074F7F0411042110C0 ALSA lib rawmidi_hw.c:233:(snd_rawmidi_hw_open) open /dev/snd/midiC0D0 failed: Input/output error cannot open port "hw:0": Input/output error
I do not know the reason for MPU401_INFO_NO_ACK. You removed it from the original patch, but without it I always get the input/output error.
................
So, now it's a problem of MIDI "input", if I understand correctly? What we need to check at first is whether the MPU_RX irq is issued at the correct timing. If not, check whether MPU watermarks (MPU_FIFO_WM, CCS0E). According to the datasheet, the values are 0 for both RX and TX.
MPU_RX irq did not get fired at all, even though the IRQ mask register CCS01 was 0x00, i.e. all interrupts enabled. I enabled the watermarks and that did the trick :) MPU_RX gets fired now, the delays are gone and Qsynth plays find with MIDI from USB or ice1724 input. It still feels as if midi from ice1724 has a little bit higher latency but I do not think we can do anything about it (plus it may just be my subjective feeling).
I am enclosing a patch to current HG which does not produce errors and puts HG to the functionality I have now. MIDI input works correctly. MIDI output is not physically tested, I only checked that snd_vt1724_mpu401_write gets called with reasonable data.
Thanks,
Pavel.
At Thu, 24 Apr 2008 22:47:54 +0200, Pavel Hofman wrote:
Takashi Iwai wrote:
At Wed, 23 Apr 2008 22:19:04 +0200, Pavel Hofman wrote:
Pavel Hofman wrote:
Takashi Iwai wrote:
At Tue, 22 Apr 2008 22:23:55 +0200, Pavel Hofman wrote:
Hi,
...........
After the playback stops, the interrupts are gone too. It seems as if the playback interrupt initiates the MPU TX interrupt.
If we could avoid generating the MPU TX interrupt during regular playback, I believe the major problem would be resolved.
Even if I mask the interrupts (CCS01) and do not explicitly unmask them (according to proc ice1724 the CCS01 register stays at 0xa0), the interrupt gets generated.
OK, then the simplest way would be to just ignore the TX bit at the second or later check.
How about the patch below?
Takashi, thanks for the hack idea. The overhead is just one more loop which is nothing. I will test it and post details of further problems (there is a bunch of them :) )
Hi,
The hack works fine, I am finally getting no CPU burning during playback and MIDI input/output.
Thanks for checking. The fixed patches are on HG tree now. Please sync your tree.
Takashi, the patch you put into HG was not the one I sent you, but sort of the original one that I said did not work.
pavel@nahore:~$ amidi -p hw:0 -d ALSA lib rawmidi_hw.c:233:(snd_rawmidi_hw_open) open /dev/snd/midiC0D0 failed: Input/output error cannot open port "hw:0": Input/output error
amidi -p hw:0 -S F0411042110C000000000074FF0411042110C000000000074F7F0411042110C000000000\ 074F7F0411042110C0F0411042110C000000000074FF0411042110C000000000074F7F041\ 1042110C000000000074F7F0411042110C0 ALSA lib rawmidi_hw.c:233:(snd_rawmidi_hw_open) open /dev/snd/midiC0D0 failed: Input/output error cannot open port "hw:0": Input/output error
I do not know the reason for MPU401_INFO_NO_ACK. You removed it from the original patch, but without it I always get the input/output error.
Ah, thanks, I overlooked it. Fixed now.
................
So, now it's a problem of MIDI "input", if I understand correctly? What we need to check at first is whether the MPU_RX irq is issued at the correct timing. If not, check whether MPU watermarks (MPU_FIFO_WM, CCS0E). According to the datasheet, the values are 0 for both RX and TX.
MPU_RX irq did not get fired at all, even though the IRQ mask register CCS01 was 0x00, i.e. all interrupts enabled. I enabled the watermarks and that did the trick :) MPU_RX gets fired now, the delays are gone and Qsynth plays find with MIDI from USB or ice1724 input.
Great, fixed on HG as well.
It still feels as if midi from ice1724 has a little bit higher latency but I do not think we can do anything about it (plus it may just be my subjective feeling).
This might be the difference between the transport ways. USB can be faster.
I am enclosing a patch to current HG which does not produce errors and puts HG to the functionality I have now. MIDI input works correctly. MIDI output is not physically tested, I only checked that snd_vt1724_mpu401_write gets called with reasonable data.
That should be enough. Thanks for your testing!
Takashi
Takashi Iwai wrote:
I do not know the reason for MPU401_INFO_NO_ACK. You removed it from the original patch, but without it I always get the input/output error.
Ah, thanks, I overlooked it. Fixed now.
Takashi, thanks, but the patch I sent you sets MPU401_INFO_INPUT and MPU401_INFO_OUTPUT flags too. They enable the actual input/output methods in mpu401_uart.c.
Thanks a lot for fixing.
Pavel.
At Fri, 25 Apr 2008 09:06:19 +0200, Pavel Hofman wrote:
Takashi Iwai wrote:
I do not know the reason for MPU401_INFO_NO_ACK. You removed it from the original patch, but without it I always get the input/output error.
Ah, thanks, I overlooked it. Fixed now.
Takashi, thanks, but the patch I sent you sets MPU401_INFO_INPUT and MPU401_INFO_OUTPUT flags too. They enable the actual input/output methods in mpu401_uart.c.
They aren't needed if you create full-duplex streams. Could you check whether the latest code still causes any errors?
thanks,
Takashi
Takashi Iwai wrote:
At Fri, 25 Apr 2008 09:06:19 +0200, Pavel Hofman wrote:
Takashi Iwai wrote:
I do not know the reason for MPU401_INFO_NO_ACK. You removed it from the original patch, but without it I always get the input/output error.
Ah, thanks, I overlooked it. Fixed now.
Takashi, thanks, but the patch I sent you sets MPU401_INFO_INPUT and MPU401_INFO_OUTPUT flags too. They enable the actual input/output methods in mpu401_uart.c.
They aren't needed if you create full-duplex streams. Could you check whether the latest code still causes any errors?
Oh, I overlooked the code
if (! (info_flags & (MPU401_INFO_INPUT | MPU401_INFO_OUTPUT))) info_flags |= MPU401_INFO_INPUT | MPU401_INFO_OUTPUT;
in snd_mpu401_uart_new.
So it should be OK. I will test and report errors, but I don't expect any :)
Thanks,
Pavel.
Takashi Iwai wrote:
At Fri, 25 Apr 2008 09:06:19 +0200, Pavel Hofman wrote:
Takashi Iwai wrote:
I do not know the reason for MPU401_INFO_NO_ACK. You removed it from the original patch, but without it I always get the input/output error.
Ah, thanks, I overlooked it. Fixed now.
Takashi, thanks, but the patch I sent you sets MPU401_INFO_INPUT and MPU401_INFO_OUTPUT flags too. They enable the actual input/output methods in mpu401_uart.c.
They aren't needed if you create full-duplex streams. Could you check whether the latest code still causes any errors?
The code works fine on standard kernel.
But in the RT kernel of Ubuntu 7.10 (2.6.22-14-rt, 1000HZ compared to 250HZ of the -generic kernel), MIDI interrupts get thrown continuously, hogging CPU with the IRQXX "process".
When playing 44.1kHz audio with buffer size of 32768, snd_vt1724_interrupt is called every 185ms. With the buffer size of 4096, it is every 23ms. So far so good.
But when I try to output some midi, the routine gets called every 24us (i.e. 1000 times faster). Comparing the time difference between my several debug printk's in snd_vt1724_interrupt (approx. 5us between each printk record a few lines of code apart) and between each call of the method (24us), I thought there would be a loop somewhere in the interrupt handler calling code. But /proc/interrupts really shows over 40k interrupts a second for ICE1724.
Changing the watermarks up to 0x1f makes no difference.
Masking the MIDI interrupts works, snd_vt1724_interrupt is called only during VT1724_IRQ_MTPCM interrupts, with the MIDI status bits MPU_TX/MPU_RX set when reading/writing with amidi.
My HW: ancient AMD Duron 900MHz.
The interrupt flood occurs no matter whether the MIDI input is connected to my MIDI keyboard or not.
Thanks a lot to anyone for suggestions.
Pavel.
At Wed, 30 Apr 2008 22:07:42 +0200, Pavel Hofman wrote:
Takashi Iwai wrote:
At Fri, 25 Apr 2008 09:06:19 +0200, Pavel Hofman wrote:
Takashi Iwai wrote:
I do not know the reason for MPU401_INFO_NO_ACK. You removed it from the original patch, but without it I always get the input/output error.
Ah, thanks, I overlooked it. Fixed now.
Takashi, thanks, but the patch I sent you sets MPU401_INFO_INPUT and MPU401_INFO_OUTPUT flags too. They enable the actual input/output methods in mpu401_uart.c.
They aren't needed if you create full-duplex streams. Could you check whether the latest code still causes any errors?
The code works fine on standard kernel.
But in the RT kernel of Ubuntu 7.10 (2.6.22-14-rt, 1000HZ compared to 250HZ of the -generic kernel), MIDI interrupts get thrown continuously, hogging CPU with the IRQXX "process".
When playing 44.1kHz audio with buffer size of 32768, snd_vt1724_interrupt is called every 185ms. With the buffer size of 4096, it is every 23ms. So far so good.
But when I try to output some midi, the routine gets called every 24us (i.e. 1000 times faster). Comparing the time difference between my several debug printk's in snd_vt1724_interrupt (approx. 5us between each printk record a few lines of code apart) and between each call of the method (24us), I thought there would be a loop somewhere in the interrupt handler calling code. But /proc/interrupts really shows over 40k interrupts a second for ICE1724.
Changing the watermarks up to 0x1f makes no difference.
That looks bad.
Masking the MIDI interrupts works, snd_vt1724_interrupt is called only during VT1724_IRQ_MTPCM interrupts, with the MIDI status bits MPU_TX/MPU_RX set when reading/writing with amidi.
Hm, is it TX or RX, or in both cases? Could you check which one (TX or RX) causes this?
Takashi
My HW: ancient AMD Duron 900MHz.
The interrupt flood occurs no matter whether the MIDI input is connected to my MIDI keyboard or not.
Thanks a lot to anyone for suggestions.
Pavel.
Takashi Iwai wrote:
At Wed, 30 Apr 2008 22:07:42 +0200, Pavel Hofman wrote:
Takashi Iwai wrote:
At Fri, 25 Apr 2008 09:06:19 +0200, Pavel Hofman wrote:
The code works fine on standard kernel.
But in the RT kernel of Ubuntu 7.10 (2.6.22-14-rt, 1000HZ compared to 250HZ of the -generic kernel), MIDI interrupts get thrown continuously, hogging CPU with the IRQXX "process".
When playing 44.1kHz audio with buffer size of 32768, snd_vt1724_interrupt is called every 185ms. With the buffer size of 4096, it is every 23ms. So far so good.
But when I try to output some midi, the routine gets called every 24us (i.e. 1000 times faster). Comparing the time difference between my several debug printk's in snd_vt1724_interrupt (approx. 5us between each printk record a few lines of code apart) and between each call of the method (24us), I thought there would be a loop somewhere in the interrupt handler calling code. But /proc/interrupts really shows over 40k interrupts a second for ICE1724.
Changing the watermarks up to 0x1f makes no difference.
That looks bad.
Masking the MIDI interrupts works, snd_vt1724_interrupt is called only during VT1724_IRQ_MTPCM interrupts, with the MIDI status bits MPU_TX/MPU_RX set when reading/writing with amidi.
Hm, is it TX or RX, or in both cases? Could you check which one (TX or RX) causes this?
Both reading (amidi -p hw:0 -d) and writing (amidi -p hw:0 -S F0411042110C000000000074FF0411042110C000000) starts the TX interrupt flood (irq status: 0x20) immediately. Upon opening input as well as output the method snd_mpu401_do_reset is called - is perhaps the culprit somewhere there?
Thanks,
Pavel.
At Sat, 03 May 2008 21:12:02 +0200, Pavel Hofman wrote:
Takashi Iwai wrote:
At Wed, 30 Apr 2008 22:07:42 +0200, Pavel Hofman wrote:
Takashi Iwai wrote:
At Fri, 25 Apr 2008 09:06:19 +0200, Pavel Hofman wrote:
The code works fine on standard kernel.
But in the RT kernel of Ubuntu 7.10 (2.6.22-14-rt, 1000HZ compared to 250HZ of the -generic kernel), MIDI interrupts get thrown continuously, hogging CPU with the IRQXX "process".
When playing 44.1kHz audio with buffer size of 32768, snd_vt1724_interrupt is called every 185ms. With the buffer size of 4096, it is every 23ms. So far so good.
But when I try to output some midi, the routine gets called every 24us (i.e. 1000 times faster). Comparing the time difference between my several debug printk's in snd_vt1724_interrupt (approx. 5us between each printk record a few lines of code apart) and between each call of the method (24us), I thought there would be a loop somewhere in the interrupt handler calling code. But /proc/interrupts really shows over 40k interrupts a second for ICE1724.
Changing the watermarks up to 0x1f makes no difference.
That looks bad.
Masking the MIDI interrupts works, snd_vt1724_interrupt is called only during VT1724_IRQ_MTPCM interrupts, with the MIDI status bits MPU_TX/MPU_RX set when reading/writing with amidi.
Hm, is it TX or RX, or in both cases? Could you check which one (TX or RX) causes this?
Both reading (amidi -p hw:0 -d) and writing (amidi -p hw:0 -S F0411042110C000000000074FF0411042110C000000) starts the TX interrupt flood (irq status: 0x20) immediately. Upon opening input as well as output the method snd_mpu401_do_reset is called - is perhaps the culprit somewhere there?
Possibly. It write 0x00 to data at the beginning in snd_mpu401_uart_cmd(). What happens if you remove it?
Takashi
Takashi Iwai wrote:
At Sat, 03 May 2008 21:12:02 +0200, Pavel Hofman wrote:
Takashi Iwai wrote:
At Wed, 30 Apr 2008 22:07:42 +0200, Pavel Hofman wrote:
Takashi Iwai wrote:
At Fri, 25 Apr 2008 09:06:19 +0200, Pavel Hofman wrote:
The code works fine on standard kernel.
But in the RT kernel of Ubuntu 7.10 (2.6.22-14-rt, 1000HZ compared to 250HZ of the -generic kernel), MIDI interrupts get thrown continuously, hogging CPU with the IRQXX "process".
When playing 44.1kHz audio with buffer size of 32768, snd_vt1724_interrupt is called every 185ms. With the buffer size of 4096, it is every 23ms. So far so good.
But when I try to output some midi, the routine gets called every 24us (i.e. 1000 times faster). Comparing the time difference between my several debug printk's in snd_vt1724_interrupt (approx. 5us between each printk record a few lines of code apart) and between each call of the method (24us), I thought there would be a loop somewhere in the interrupt handler calling code. But /proc/interrupts really shows over 40k interrupts a second for ICE1724.
Changing the watermarks up to 0x1f makes no difference.
That looks bad.
Masking the MIDI interrupts works, snd_vt1724_interrupt is called only during VT1724_IRQ_MTPCM interrupts, with the MIDI status bits MPU_TX/MPU_RX set when reading/writing with amidi.
Hm, is it TX or RX, or in both cases? Could you check which one (TX or RX) causes this?
Both reading (amidi -p hw:0 -d) and writing (amidi -p hw:0 -S F0411042110C000000000074FF0411042110C000000) starts the TX interrupt flood (irq status: 0x20) immediately. Upon opening input as well as output the method snd_mpu401_do_reset is called - is perhaps the culprit somewhere there?
Possibly. It write 0x00 to data at the beginning in snd_mpu401_uart_cmd(). What happens if you remove it?
Unfortunately nothing, no change.
Actually, when does the MPU_TX interrupt get thrown? Upon exhausting some output buffer? I understand interrupts for DMA, but mpu uart does not use DMA, right?
Thanks a lot for help, I am not giving up :)
Pavel.
Pavel Hofman wrote:
Actually, when does the MPU_TX interrupt get thrown? Upon exhausting some output buffer?
According to the datasheet, when the number of bytes in the TX FIFO goes below the watermark value (for some unspecified value of "below").
Is there a reason why the watermarks are set to 1 and not to 0?
Anyway, this hardware is not compatible with the MPU-401, so we should not try to twist the MPU-401 code into working with it. Please try the patch below (not tested, I don't have the hardware).
Index: alsa/alsa-kernel/pci/Kconfig =================================================================== --- alsa.orig/alsa-kernel/pci/Kconfig 2008-05-13 22:18:20.000000000 +0200 +++ alsa/alsa-kernel/pci/Kconfig 2008-05-14 21:47:28.000000000 +0200 @@ -695,7 +695,7 @@ config SND_ICE1712 config SND_ICE1724 tristate "ICE/VT1724/1720 (Envy24HT/PT)" depends on SND - select SND_MPU401_UART + select SND_RAWMIDI select SND_AC97_CODEC select SND_VMASTER help Index: alsa/alsa-kernel/pci/ice1712/ice1712.h =================================================================== --- alsa.orig/alsa-kernel/pci/ice1712/ice1712.h 2008-05-13 22:18:20.000000000 +0200 +++ alsa/alsa-kernel/pci/ice1712/ice1712.h 2008-05-14 21:47:28.000000000 +0200 @@ -333,6 +333,8 @@ struct snd_ice1712 { unsigned int has_spdif: 1; /* VT1720/4 - has SPDIF I/O */ unsigned int force_pdma4: 1; /* VT1720/4 - PDMA4 as non-spdif */ unsigned int force_rdma1: 1; /* VT1720/4 - RDMA1 as non-spdif */ + unsigned int midi_output: 1; /* VT1720/4: MIDI output triggered */ + unsigned int midi_input: 1; /* VT1720/4: MIDI input triggered */ unsigned int num_total_dacs; /* total DACs */ unsigned int num_total_adcs; /* total ADCs */ unsigned int cur_rate; /* current rate */ Index: alsa/alsa-kernel/pci/ice1712/envy24ht.h =================================================================== --- alsa.orig/alsa-kernel/pci/ice1712/envy24ht.h 2007-10-24 20:22:01.000000000 +0200 +++ alsa/alsa-kernel/pci/ice1712/envy24ht.h 2008-05-14 21:55:36.000000000 +0200 @@ -93,9 +93,13 @@ enum { #define VT1724_REG_MPU_TXFIFO 0x0a /*byte ro. number of bytes in TX fifo*/ #define VT1724_REG_MPU_RXFIFO 0x0b /*byte ro. number of bytes in RX fifo*/
-//are these 2 the wrong way around? they don't seem to be used yet anyway -#define VT1724_REG_MPU_CTRL 0x0c /* byte */ -#define VT1724_REG_MPU_DATA 0x0d /* byte */ +#define VT1724_REG_MPU_DATA 0x0c /* byte */ +#define VT1724_REG_MPU_CTRL 0x0d /* byte */ +#define VT1724_MPU_UART 0x01 +#define VT1724_MPU_TX_EMPTY 0x02 +#define VT1724_MPU_TX_FULL 0x04 +#define VT1724_MPU_RX_EMPTY 0x08 +#define VT1724_MPU_RX_FULL 0x10
#define VT1724_REG_MPU_FIFO_WM 0x0e /*byte set the high/low watermarks for RX/TX fifos*/ #define VT1724_MPU_RX_FIFO 0x20 //1=rx fifo watermark 0=tx fifo watermark Index: alsa/alsa-kernel/pci/ice1712/ice1724.c =================================================================== --- alsa.orig/alsa-kernel/pci/ice1712/ice1724.c 2008-05-13 22:18:20.000000000 +0200 +++ alsa/alsa-kernel/pci/ice1712/ice1724.c 2008-05-14 22:31:48.000000000 +0200 @@ -32,7 +32,7 @@ #include <linux/mutex.h> #include <sound/core.h> #include <sound/info.h> -#include <sound/mpu401.h> +#include <sound/rawmidi.h> #include <sound/initval.h>
#include <sound/asoundef.h> @@ -223,30 +223,154 @@ static unsigned int snd_vt1724_get_gpio_ }
/* - * MPU401 accessor + * MIDI */ -static unsigned char snd_vt1724_mpu401_read(struct snd_mpu401 *mpu, - unsigned long addr) + +static void vt1724_midi_clear_rx(struct snd_ice1712 *ice) +{ + unsigned int count; + + for (count = inb(ICEREG1724(ice, MPU_RXFIFO)); count > 0; --count) + inb(ICEREG1724(ice, MPU_DATA)); +} + +static inline struct snd_rawmidi_substream * +get_rawmidi_substream(struct snd_ice1712 *ice, unsigned int stream) +{ + return list_first_entry(ice->rmidi[0]->streams[stream].substreams, + struct snd_rawmidi_substream, list) +} + +static void vt1724_midi_write(struct snd_ice1712 *ice) +{ + struct snd_rawmidi_substream *s; + int count, i; + u8 buffer[32]; + + s = get_rawmidi_substream(ice, SNDRV_RAWMIDI_STREAM_OUTPUT); + count = 31 - inb(ICEREG1724(ice, MPU_TXFIFO)); + if (count > 0) { + count = snd_rawmidi_transmit(s, buffer, count); + for (i = 0; i < count; ++i) + outb(buffer[i], ICEREG1724(ice, MPU_DATA)); + } +} + +static void vt1724_midi_read(struct snd_ice1712 *ice) +{ + struct snd_rawmidi_substream *s; + int count, i; + u8 buffer[32]; + + s = get_rawmidi_substream(ice, SNDRV_RAWMIDI_STREAM_INPUT); + count = inb(ICEREG1724(ice, MPU_RXFIFO)); + if (count > 0) { + for (i = 0; i < count; ++i) + buffer[i] = inb(ICEREG1724(ice, MPU_DATA)); + snd_rawmidi_receive(s, buffer, count); + } +} + +static void vt1724_enable_midi_irq(struct snd_rawmidi_substream *substream, + u8 flag, int enable) { - /* fix status bits to the standard position */ - /* only RX_EMPTY and TX_FULL are checked */ - if (addr == MPU401C(mpu)) - return (inb(addr) & 0x0c) << 4; + struct snd_ice1712 *ice = substream->rmidi->private_data; + u8 mask; + + spin_lock_irq(&ice->reg_lock); + mask = inb(ICEREG1724(ice, IRQMASK)); + if (enable) + mask &= ~flag; else - return inb(addr); + mask |= flag; + outb(mask, ICEREG1724(ice, IRQMASK)); + spin_unlock_irq(&ice->reg_lock); }
-static void snd_vt1724_mpu401_write(struct snd_mpu401 *mpu, - unsigned char data, unsigned long addr) +static int vt1724_midi_output_open(struct snd_rawmidi_substream *s) { - if (addr == MPU401C(mpu)) { - if (data == MPU401_ENTER_UART) - outb(0x01, addr); - /* what else? */ - } else - outb(data, addr); + 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; +} + +static void vt1724_midi_output_trigger(struct snd_rawmidi_substream *s, int up) +{ + struct snd_ice1712 *ice = s->rmidi->private_data; + unsigned long flags; + + spin_lock_irqsave(&ice->reg_lock, flags); + if (up) { + ice->midi_output = 1; + vt1724_midi_write(ice); + } else { + ice->midi_output = 0; + } + spin_unlock_irqrestore(&ice->reg_lock, flags); + return 0; +} + +static void vt1724_midi_output_drain(struct snd_rawmidi_substream *s) +{ + struct snd_ice1712 *ice = s->rmidi->private_data; + unsigned long timeout; + + /* 32 bytes should be transmitted in less than about 12 ms */ + timeout = jiffies + msecs_to_jiffies(15); + do { + if (inb(ICEREG1724(ice, MPU_CTRL)) & VT1724_MPU_TX_EMPTY) + break; + schedule_timeout_uninterruptible(1); + } while (time_after(timeout, jiffies)); +} + +static struct snd_rawmidi_ops vt1724_midi_output_ops = { + .open = vt1724_midi_output_open, + .close = vt1724_midi_output_close, + .trigger = vt1724_midi_output_trigger, + .drain = vt1724_midi_output_drain, +}; + +static int vt1724_midi_input_open(struct snd_rawmidi_substream *s) +{ + vt1724_midi_clear_rx(s->rmidi->private_data); + vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_RX, 1); + return 0; +} + +static int vt1724_midi_input_close(struct snd_rawmidi_substream *s) +{ + vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_RX, 0); + return 0; +} + +static void vt1724_midi_input_trigger(struct snd_rawmidi_substream *s, int up) +{ + struct snd_ice1712 *ice = s->rmidi->private_data; + unsigned long flags; + + spin_lock_irqsave(&ice->reg_lock, flags); + if (up) { + ice->midi_input = 1; + vt1724_midi_read(ice); + } else { + ice->midi_input = 0; + } + spin_unlock_irqrestore(&ice->reg_lock, flags); + return 0; +} + +static struct snd_rawmidi_ops vt1724_midi_input_ops = { + .open = vt1724_midi_input_open, + .close = vt1724_midi_input_close, + .trigger = vt1724_midi_input_trigger, +}; +
/* * Interrupt handler @@ -278,13 +402,10 @@ static irqreturn_t snd_vt1724_interrupt( #endif handled = 1; if (status & VT1724_IRQ_MPU_TX) { - if (ice->rmidi[0]) - 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_TX, - ICEREG1724(ice, IRQMASK)); + spin_lock(&ice->reg_lock); + if (ice->midi_output) + vt1724_midi_write(ice); + spin_unlock(&ice->reg_lock); /* 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 @@ -293,13 +414,12 @@ static irqreturn_t snd_vt1724_interrupt( status_mask &= ~VT1724_IRQ_MPU_TX; } 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)); + 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)); @@ -2425,28 +2545,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_NO_ACK | - MPU401_INFO_TX_IRQ), - ice->irq, 0, - &ice->rmidi[0])) < 0) { + struct snd_rawmidi *rmidi; + + err = snd_rawmidi_new(card, "MIDI", 0, 1, 1, &rmidi); + if (err < 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)); + ice->rmidi[0] = rmidi; + rmidi->private_data = ice; + strcpy(rmidi->name, "ICE1724 MIDI"); + rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | + SNDRV_RAWMIDI_INFO_INPUT | + SNDRV_RAWMIDI_INFO_DUPLEX; + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, + vt1724_midi_output_ops); + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, + vt1724_midi_input_ops); + /* set watermarks */ outb(VT1724_MPU_RX_FIFO | 0x1, ICEREG1724(ice, MPU_FIFO_WM)); outb(0x1, ICEREG1724(ice, MPU_FIFO_WM)); + /* set UART mode */ + outb(0x01, ICEREG1724(ice, MPU_CTRL)); } }
At Thu, 15 May 2008 09:21:02 +0200, Clemens Ladisch wrote:
Pavel Hofman wrote:
Actually, when does the MPU_TX interrupt get thrown? Upon exhausting some output buffer?
According to the datasheet, when the number of bytes in the TX FIFO goes below the watermark value (for some unspecified value of "below").
Is there a reason why the watermarks are set to 1 and not to 0?
We got TX IRQ storm when it was 0, according to Pavel.
Anyway, this hardware is not compatible with the MPU-401, so we should not try to twist the MPU-401 code into working with it.
Agreed. I thought it's enough similar to the real MPU401, but it's getting nastier.
thanks,
Takashi
Clemens Ladisch wrote:
Pavel Hofman wrote:
Actually, when does the MPU_TX interrupt get thrown? Upon exhausting some output buffer?
According to the datasheet, when the number of bytes in the TX FIFO goes below the watermark value (for some unspecified value of "below").
Is there a reason why the watermarks are set to 1 and not to 0?
Anyway, this hardware is not compatible with the MPU-401, so we should not try to twist the MPU-401 code into working with it. Please try the patch below (not tested, I don't have the hardware).
Clemens,
Thanks a lot. After a few pointer fixes to make it compile your code works flawlessly for both the generic as well as realtime ubuntu kernel.
I am enclosing the functioning patch.
Now I cannot feel any delay difference between usb and ice1724 midi inputs. Well done, gentlemen, thank you all.
Regards,
Pavel Hofman.
Pavel Hofman wrote:
Thanks a lot. After a few pointer fixes to make it compile your code works flawlessly for both the generic as well as realtime ubuntu kernel.
Does it also work if you set the watermarks to 0?
Regards, Clemens
Clemens Ladisch wrote:
Pavel Hofman wrote:
Thanks a lot. After a few pointer fixes to make it compile your code works flawlessly for both the generic as well as realtime ubuntu kernel.
Does it also work if you set the watermarks to 0?
Test results for rt kernel - watermarks set to 0 bring the IRQ flood when the MIDI device is opened ( amidi -p hw:0 -d).
I am fine with the current setting - no floods, latency comparable to USB.
Regards,
Pavel.
participants (3)
-
Clemens Ladisch
-
Pavel Hofman
-
Takashi Iwai