summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>2015-10-08 19:10:28 -0400
committerTakashi Iwai <tiwai@suse.de>2015-10-09 03:57:06 -0400
commitea848b7b62ab6d3078955b87833c3b336b71bc9f (patch)
tree1295ae58de9a3db05cc46082b595ac7250dd4922
parente8a40d9bcb2392ea502dc629d5d6c0556fdd3b0c (diff)
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>
-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,
76 76
77 if (rcode == RCODE_COMPLETE && substream != NULL) 77 if (rcode == RCODE_COMPLETE && substream != NULL)
78 snd_rawmidi_transmit_ack(substream, port->consume_bytes); 78 snd_rawmidi_transmit_ack(substream, port->consume_bytes);
79 else if (!rcode_is_permanent_error(rcode))
80 /* To start next transaction immediately for recovery. */
81 port->next_ktime = ktime_set(0, 0);
79 82
80 port->idling = true; 83 port->idling = true;
81 84
@@ -99,6 +102,12 @@ static void midi_port_work(struct work_struct *work)
99 if (substream == NULL || snd_rawmidi_transmit_empty(substream)) 102 if (substream == NULL || snd_rawmidi_transmit_empty(substream))
100 return; 103 return;
101 104
105 /* Do it in next chance. */
106 if (ktime_after(port->next_ktime, ktime_get())) {
107 schedule_work(&port->work);
108 return;
109 }
110
102 /* 111 /*
103 * Fill the buffer. The callee must use snd_rawmidi_transmit_peek(). 112 * Fill the buffer. The callee must use snd_rawmidi_transmit_peek().
104 * Later, snd_rawmidi_transmit_ack() is called. 113 * Later, snd_rawmidi_transmit_ack() is called.
@@ -107,8 +116,10 @@ static void midi_port_work(struct work_struct *work)
107 port->consume_bytes = port->fill(substream, port->buf); 116 port->consume_bytes = port->fill(substream, port->buf);
108 if (port->consume_bytes <= 0) { 117 if (port->consume_bytes <= 0) {
109 /* Do it in next chance, immediately. */ 118 /* Do it in next chance, immediately. */
110 if (port->consume_bytes == 0) 119 if (port->consume_bytes == 0) {
120 port->next_ktime = ktime_set(0, 0);
111 schedule_work(&port->work); 121 schedule_work(&port->work);
122 }
112 return; 123 return;
113 } 124 }
114 125
@@ -118,6 +129,10 @@ static void midi_port_work(struct work_struct *work)
118 else 129 else
119 type = TCODE_WRITE_BLOCK_REQUEST; 130 type = TCODE_WRITE_BLOCK_REQUEST;
120 131
132 /* Set interval to next transaction. */
133 port->next_ktime = ktime_add_ns(ktime_get(),
134 port->consume_bytes * 8 * NSEC_PER_SEC / 31250);
135
121 /* Start this transaction. */ 136 /* Start this transaction. */
122 port->idling = false; 137 port->idling = false;
123 138
@@ -162,6 +177,7 @@ int snd_fw_async_midi_port_init(struct snd_fw_async_midi_port *port,
162 port->addr = addr; 177 port->addr = addr;
163 port->fill = fill; 178 port->fill = fill;
164 port->idling = true; 179 port->idling = true;
180 port->next_ktime = ktime_set(0, 0);
165 181
166 INIT_WORK(&port->work, midi_port_work); 182 INIT_WORK(&port->work, midi_port_work);
167 183
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 {
31 struct fw_device *parent; 31 struct fw_device *parent;
32 struct work_struct work; 32 struct work_struct work;
33 bool idling; 33 bool idling;
34 ktime_t next_ktime;
34 35
35 u64 addr; 36 u64 addr;
36 struct fw_transaction transaction; 37 struct fw_transaction transaction;