static void snd_mpu401_uart_input_trigger(struct snd_rawmidi_substream *substream, int up) { unsigned long flags; struct snd_mpu401 *mpu; int max = 64; mpu = substream->rmidi->private_data; if (up) { if (! test_and_set_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode)) { while (max-- > 0) mpu->read(mpu, MPU401D(mpu)); if (mpu->info_flags & MPU401_INFO_USE_TIMER) snd_mpu401_uart_add_timer(mpu, 1); } spin_lock_irqsave(&mpu->input_lock, flags); snd_mpu401_uart_input_read(mpu); spin_unlock_irqrestore(&mpu->input_lock, flags); } else { if (mpu->info_flags & MPU401_INFO_USE_TIMER) snd_mpu401_uart_remove_timer(mpu, 1); clear_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode); } }
/* * trigger input callback */ static void snd_mpu401_uart_input_trigger(snd_rawmidi_substream_t * substream, int up) { unsigned long flags; mpu401_t *mpu; int max = 64; mpu = substream->rmidi->private_data; if (up) { if (! test_and_set_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode)) { /* first time - flush FIFO */ while (max-- > 0) mpu->read(mpu, MPU401D(mpu)); if (mpu->irq < 0) snd_mpu401_uart_add_timer(mpu, 1); } /* read data in advance */ /* prevent double enter via rawmidi->event callback */ if (atomic_dec_and_test(&mpu->rx_loop)) { local_irq_save(flags); if (spin_trylock(&mpu->input_lock)) { snd_mpu401_uart_input_read(mpu); spin_unlock(&mpu->input_lock); } local_irq_restore(flags); } atomic_inc(&mpu->rx_loop); } else { if (mpu->irq < 0) snd_mpu401_uart_remove_timer(mpu, 1); clear_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode); } }
/* * trigger input callback */ static void snd_mpu401_uart_input_trigger(snd_rawmidi_substream_t * substream, int up) { unsigned long flags; mpu401_t *mpu; int max = 64; mpu = substream->rmidi->private_data; if (up) { if (! test_and_set_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode)) { /* first time - flush FIFO */ while (max-- > 0) mpu->read(mpu, MPU401D(mpu)); if (mpu->irq < 0) snd_mpu401_uart_add_timer(mpu, 1); } /* read data in advance */ spin_lock_irqsave(&mpu->input_lock, flags); snd_mpu401_uart_input_read(mpu); spin_unlock_irqrestore(&mpu->input_lock, flags); } else { if (mpu->irq < 0) snd_mpu401_uart_remove_timer(mpu, 1); clear_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode); } }
static int snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd, int ack) { unsigned long flags; int timeout, ok; spin_lock_irqsave(&mpu->input_lock, flags); if (mpu->hardware != MPU401_HW_TRID4DWAVE) { mpu->write(mpu, 0x00, MPU401D(mpu)); } if (mpu->hardware != MPU401_HW_SB) { for (timeout = 1000; timeout > 0 && !snd_mpu401_output_ready(mpu); timeout--) udelay(10); #ifdef CONFIG_SND_DEBUG if (!timeout) snd_printk(KERN_ERR "cmd: tx timeout (status = 0x%x)\n", mpu->read(mpu, MPU401C(mpu))); #endif } mpu->write(mpu, cmd, MPU401C(mpu)); if (ack && !(mpu->info_flags & MPU401_INFO_NO_ACK)) { ok = 0; timeout = 10000; while (!ok && timeout-- > 0) { if (snd_mpu401_input_avail(mpu)) { if (mpu->read(mpu, MPU401D(mpu)) == MPU401_ACK) ok = 1; } } if (!ok && mpu->read(mpu, MPU401D(mpu)) == MPU401_ACK) ok = 1; } else ok = 1; spin_unlock_irqrestore(&mpu->input_lock, flags); if (!ok) { snd_printk(KERN_ERR "cmd: 0x%x failed at 0x%lx " "(status = 0x%x, data = 0x%x)\n", cmd, mpu->port, mpu->read(mpu, MPU401C(mpu)), mpu->read(mpu, MPU401D(mpu))); return 1; } return 0; }
static void snd_mpu401_uart_clear_rx(mpu401_t *mpu) { int timeout = 100000; for (; timeout > 0 && snd_mpu401_input_avail(mpu); timeout--) mpu->read(mpu, MPU401D(mpu)); #ifdef CONFIG_SND_DEBUG if (timeout <= 0) snd_printk("cmd: clear rx timeout (status = 0x%x)\n", mpu->read(mpu, MPU401C(mpu))); #endif }
static void snd_mpu401_uart_input_read(struct snd_mpu401 * mpu) { int max = 128; unsigned char byte; while (max-- > 0) { if (! snd_mpu401_input_avail(mpu)) break; byte = mpu->read(mpu, MPU401D(mpu)); if (test_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode)) snd_rawmidi_receive(mpu->substream_input, &byte, 1); } }
static void snd_mpu401_uart_cmd(mpu401_t * mpu, unsigned char cmd, int ack) { unsigned long flags; int timeout, ok; spin_lock_irqsave(&mpu->input_lock, flags); if (mpu->hardware != MPU401_HW_TRID4DWAVE) { mpu->write(mpu, 0x00, MPU401D(mpu)); /*snd_mpu401_uart_clear_rx(mpu);*/ } /* ok. standard MPU-401 initialization */ if (mpu->hardware != MPU401_HW_SB) { for (timeout = 1000; timeout > 0 && !snd_mpu401_output_ready(mpu); timeout--) udelay(10); #ifdef CONFIG_SND_DEBUG if (!timeout) snd_printk("cmd: tx timeout (status = 0x%x)\n", mpu->read(mpu, MPU401C(mpu))); #endif } mpu->write(mpu, cmd, MPU401C(mpu)); if (ack) { ok = 0; timeout = 10000; while (!ok && timeout-- > 0) { if (snd_mpu401_input_avail(mpu)) { if (mpu->read(mpu, MPU401D(mpu)) == MPU401_ACK) ok = 1; } } if (!ok && mpu->read(mpu, MPU401D(mpu)) == MPU401_ACK) ok = 1; } else { ok = 1; } spin_unlock_irqrestore(&mpu->input_lock, flags); if (! ok) snd_printk("cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)\n", cmd, mpu->port, mpu->read(mpu, MPU401C(mpu)), mpu->read(mpu, MPU401D(mpu))); // snd_printk("cmd: 0x%x at 0x%lx (status = 0x%x, data = 0x%x)\n", cmd, mpu->port, mpu->read(mpu, MPU401C(mpu)), mpu->read(mpu, MPU401D(mpu))); }
/* * transfer input pending data * call with input_lock spinlock held */ static void snd_mpu401_uart_input_read(mpu401_t * mpu) { int max = 128; unsigned char byte; while (max-- > 0) { if (snd_mpu401_input_avail(mpu)) { byte = mpu->read(mpu, MPU401D(mpu)); if (test_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode)) snd_rawmidi_receive(mpu->substream_input, &byte, 1); } else { break; /* input not available */ } } }
static void snd_mpu401_uart_output_write(struct snd_mpu401 * mpu) { unsigned char byte; int max = 256; do { if (snd_rawmidi_transmit_peek(mpu->substream_output, &byte, 1) == 1) { if (!snd_mpu401_output_ready(mpu) && !snd_mpu401_output_ready(mpu)) break; mpu->write(mpu, byte, MPU401D(mpu)); snd_rawmidi_transmit_ack(mpu->substream_output, 1); } else { snd_mpu401_uart_remove_timer (mpu, 0); break; } } while (--max > 0); }
/* * write output pending bytes * call with output_lock spinlock held */ static void snd_mpu401_uart_output_write(mpu401_t * mpu) { unsigned char byte; int max = 256, timeout; do { if (snd_rawmidi_transmit_peek(mpu->substream_output, &byte, 1) == 1) { for (timeout = 100; timeout > 0; timeout--) { if (snd_mpu401_output_ready(mpu)) { mpu->write(mpu, byte, MPU401D(mpu)); snd_rawmidi_transmit_ack(mpu->substream_output, 1); break; } } if (timeout == 0) break; /* Tx FIFO full - try again later */ } else { snd_mpu401_uart_remove_timer (mpu, 0); break; /* no other data - leave the tx loop */ } } while (--max > 0); }
/* * write output pending bytes * call with output_lock spinlock held */ static void snd_mpu401_uart_output_write(struct snd_mpu401 * mpu) { unsigned char byte; int max = 256; do { if (snd_rawmidi_transmit_peek(mpu->substream_output, &byte, 1) == 1) { /* * Try twice because there is hardware that insists on * setting the output busy bit after each write. */ if (!snd_mpu401_output_ready(mpu) && !snd_mpu401_output_ready(mpu)) break; /* Tx FIFO full - try again later */ mpu->write(mpu, byte, MPU401D(mpu)); snd_rawmidi_transmit_ack(mpu->substream_output, 1); } else { snd_mpu401_uart_remove_timer (mpu, 0); break; /* no other data - leave the tx loop */ } } while (--max > 0); }
/* * This is apparently the standard way to initailise an MPU-401 */ static inline void initialise_mpu401(const struct snd_mpu401 * mpu) { outb(0, MPU401D(mpu)); }