[alsa-devel] [PATCH 06/25] ALSA: firewire-lib: add throttle for MIDI data rate

Takashi Sakamoto o-takashi at sakamocchi.jp
Thu Aug 13 23:34:46 CEST 2015


On Aug 13 2015 09:20, Takashi Sakamoto wrote:
> 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
> by jiffies 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. Using jiffies for this purpose is not perfect idea.
> Further work is needed for better implementation.
> 
> Signed-off-by: Takashi Sakamoto <o-takashi at sakamocchi.jp>
> ---
>  sound/firewire/lib.c | 18 +++++++++++++++++-
>  sound/firewire/lib.h |  1 +
>  2 files changed, 18 insertions(+), 1 deletion(-)
> 
> diff --git a/sound/firewire/lib.c b/sound/firewire/lib.c
> index e309b9b..452728c 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_tick = 0;
>  
>  	port->idling = true;
>  
> @@ -99,6 +102,12 @@ static void midi_port_tasklet(unsigned long data)
>  	if (substream == NULL || snd_rawmidi_transmit_empty(substream))
>  		return;
>  
> +	/* Do it in next chance. */
> +	if (time_is_after_jiffies(port->next_tick)) {
> +		tasklet_schedule(&port->tasklet);
> +		return;
> +	}
> +
>  	/*
>  	 * Fill the buffer. The callee must use snd_rawmidi_transmit_peek().
>  	 * Later, snd_rawmidi_transmit_ack() may be called.
> @@ -107,8 +116,10 @@ static void midi_port_tasklet(unsigned long data)
>  	port->consume_bytes = port->packetize(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_tick = 0;
>  			tasklet_schedule(&port->tasklet);
> +		}
>  		return;
>  	}
>  
> @@ -118,6 +129,10 @@ static void midi_port_tasklet(unsigned long data)
>  	else
>  		type = TCODE_WRITE_BLOCK_REQUEST;
>  
> +	/* Set interval to next transaction. */
> +	port->next_tick =
> +		jiffies_64 + msecs_to_jiffies(port->consume_bytes * 8 / 31250);
> +

I realize that the given argument should be multiplexed by 1000 to
represent mili-seconds.

>  	/* Start this transaction. */
>  	port->idling = false;
>  	generation = port->parent->generation;
> @@ -153,6 +168,7 @@ int snd_fw_async_midi_port_init(struct snd_fw_async_midi_port *port,
>  	port->addr = addr;
>  	port->packetize = packetize;
>  	port->idling = true;
> +	port->next_tick = 0;
>  
>  	tasklet_init(&port->tasklet, midi_port_tasklet, (unsigned long)port);
>  
> diff --git a/sound/firewire/lib.h b/sound/firewire/lib.h
> index 9d76f5c..e4b00e2 100644
> --- a/sound/firewire/lib.h
> +++ b/sound/firewire/lib.h
> @@ -26,6 +26,7 @@ struct snd_fw_async_midi_port {
>  	struct fw_device *parent;
>  	struct tasklet_struct tasklet;
>  	bool idling;
> +	unsigned long next_tick;
>  
>  	__u64 addr;
>  	struct fw_transaction transaction;
> 



More information about the Alsa-devel mailing list