summaryrefslogtreecommitdiffstats
path: root/sound/firewire/lib.c
diff options
context:
space:
mode:
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>2015-10-09 01:10:28 +0200
committerTakashi Iwai <tiwai@suse.de>2015-10-09 09:57:06 +0200
commitea848b7b62ab6d3078955b87833c3b336b71bc9f (patch)
tree1295ae58de9a3db05cc46082b595ac7250dd4922 /sound/firewire/lib.c
parentALSA: firewire-lib: schedule work again when MIDI substream has rest of MIDI ... (diff)
downloadlinux-ea848b7b62ab6d3078955b87833c3b336b71bc9f.tar.xz
linux-ea848b7b62ab6d3078955b87833c3b336b71bc9f.zip
ALSA: firewire-lib: add throttle for MIDI data rate
Typically, the target devices have internal buffer to adjust output of received MIDI messages for MIDI serial bus, while the capacity of the buffer is limited. IEEE 1394 transactions can transfer more MIDI messages than MIDI serial bus can. This can cause buffer over flow in device side. This commit adds throttle to limit MIDI data rate by counting intervals between two MIDI messages. Usual MIDI messages consists of two or three bytes. This requires 1.302 to 1.953 mili-seconds interval between these messages. This commit uses kernel monotonic time service to calculate the time of next transaction. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/firewire/lib.c')
-rw-r--r--sound/firewire/lib.c18
1 files changed, 17 insertions, 1 deletions
diff --git a/sound/firewire/lib.c b/sound/firewire/lib.c
index 3e9afd7d402c..9a98c7cd8744 100644
--- a/sound/firewire/lib.c
+++ b/sound/firewire/lib.c
@@ -76,6 +76,9 @@ static void async_midi_port_callback(struct fw_card *card, int rcode,
if (rcode == RCODE_COMPLETE && substream != NULL)
snd_rawmidi_transmit_ack(substream, port->consume_bytes);
+ else if (!rcode_is_permanent_error(rcode))
+ /* To start next transaction immediately for recovery. */
+ port->next_ktime = ktime_set(0, 0);
port->idling = true;
@@ -99,6 +102,12 @@ static void midi_port_work(struct work_struct *work)
if (substream == NULL || snd_rawmidi_transmit_empty(substream))
return;
+ /* Do it in next chance. */
+ if (ktime_after(port->next_ktime, ktime_get())) {
+ schedule_work(&port->work);
+ return;
+ }
+
/*
* Fill the buffer. The callee must use snd_rawmidi_transmit_peek().
* Later, snd_rawmidi_transmit_ack() is called.
@@ -107,8 +116,10 @@ static void midi_port_work(struct work_struct *work)
port->consume_bytes = port->fill(substream, port->buf);
if (port->consume_bytes <= 0) {
/* Do it in next chance, immediately. */
- if (port->consume_bytes == 0)
+ if (port->consume_bytes == 0) {
+ port->next_ktime = ktime_set(0, 0);
schedule_work(&port->work);
+ }
return;
}
@@ -118,6 +129,10 @@ static void midi_port_work(struct work_struct *work)
else
type = TCODE_WRITE_BLOCK_REQUEST;
+ /* Set interval to next transaction. */
+ port->next_ktime = ktime_add_ns(ktime_get(),
+ port->consume_bytes * 8 * NSEC_PER_SEC / 31250);
+
/* Start this transaction. */
port->idling = false;
@@ -162,6 +177,7 @@ int snd_fw_async_midi_port_init(struct snd_fw_async_midi_port *port,
port->addr = addr;
port->fill = fill;
port->idling = true;
+ port->next_ktime = ktime_set(0, 0);
INIT_WORK(&port->work, midi_port_work);