summary refs log tree commit diff
path: root/sound/firewire
diff options
context:
space:
mode:
Diffstat (limited to 'sound/firewire')
-rw-r--r--sound/firewire/lib.c18
-rw-r--r--sound/firewire/lib.h1
2 files changed, 18 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);
 
diff --git a/sound/firewire/lib.h b/sound/firewire/lib.h
index 0af06f44e8c2..59e086587212 100644
--- a/sound/firewire/lib.h
+++ b/sound/firewire/lib.h
@@ -31,6 +31,7 @@ struct snd_fw_async_midi_port {
 	struct fw_device *parent;
 	struct work_struct work;
 	bool idling;
+	ktime_t next_ktime;
 
 	u64 addr;
 	struct fw_transaction transaction;