Skip to content

Commit

Permalink
ALSA: firewire-lib: add throttle for MIDI data rate
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Takashi Iwai <[email protected]>
  • Loading branch information
takaswie authored and tiwai committed Oct 9, 2015
1 parent e8a40d9 commit ea848b7
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 1 deletion.
18 changes: 17 additions & 1 deletion sound/firewire/lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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.
Expand All @@ -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;
}

Expand All @@ -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;

Expand Down Expand Up @@ -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);

Expand Down
1 change: 1 addition & 0 deletions sound/firewire/lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit ea848b7

Please sign in to comment.