From patchwork Tue Nov 25 21:54:10 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Clemens Ladisch X-Patchwork-Id: 5382751 Return-Path: X-Original-To: patchwork-alsa-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 368469F39D for ; Tue, 25 Nov 2014 21:54:58 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 4F8CC201EC for ; Tue, 25 Nov 2014 21:54:57 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.kernel.org (Postfix) with ESMTP id 0C09B201D3 for ; Tue, 25 Nov 2014 21:54:56 +0000 (UTC) Received: by alsa0.perex.cz (Postfix, from userid 1000) id 317912659C4; Tue, 25 Nov 2014 22:54:50 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from alsa0.perex.cz (localhost [IPv6:::1]) by alsa0.perex.cz (Postfix) with ESMTP id EF17E260654; Tue, 25 Nov 2014 22:54:39 +0100 (CET) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 336BE26582D; Tue, 25 Nov 2014 22:54:38 +0100 (CET) Received: from dehamd003.servertools24.de (dehamd003.servertools24.de [31.47.254.18]) by alsa0.perex.cz (Postfix) with ESMTP id 2E70C260654 for ; Tue, 25 Nov 2014 22:54:30 +0100 (CET) Received: from [192.168.42.209] (tmo-102-113.customers.d1-online.com [80.187.102.113]) by dehamd003.servertools24.de (Postfix) with ESMTPSA id 2815FF805D; Tue, 25 Nov 2014 22:50:33 +0100 (CET) Message-ID: <5474FA82.4030408@ladisch.de> Date: Tue, 25 Nov 2014 22:54:10 +0100 From: Clemens Ladisch User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.2.0 MIME-Version: 1.0 To: Takashi Iwai References: <5474FA18.7000501@ladisch.de> In-Reply-To: <5474FA18.7000501@ladisch.de> X-PPP-Message-ID: <20141125215033.90619.96903@dehamd003.servertools24.de> X-PPP-Vhost: ladisch.de Cc: alsa-devel@alsa-project.org, Takashi Sakamoto Subject: [alsa-devel] [PATCH 2/2] ALSA: firewire-lib: limit the MIDI data rate X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP Do no send MIDI bytes at the full rate at which FireWire packets happen to be sent, but restrict them to the actual rate of a real MIDI port. This is required by the specification, and prevents data loss when the device's buffer overruns. Signed-off-by: Clemens Ladisch --- sound/firewire/amdtp.c | 61 +++++++++++++++++++++++++++++++++++++++++++----- sound/firewire/amdtp.h | 2 ++ 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c index 17548d8..c0c0c5e 100644 --- a/sound/firewire/amdtp.c +++ b/sound/firewire/amdtp.c @@ -22,6 +22,12 @@ #define TICKS_PER_SECOND (TICKS_PER_CYCLE * CYCLES_PER_SECOND) /* + * Nominally 3125 bytes/second, but the MIDI port's clock might be + * 1% too slow, and the bus clock 100 ppm too fast. + */ +#define MIDI_BYTES_PER_SECOND 3093 + +/* * Several devices look only at the first eight data blocks. * In any case, this is more than enough for the MIDI data rate. */ @@ -226,6 +232,14 @@ sfc_found: for (i = 0; i < pcm_channels; i++) s->pcm_positions[i] = i; s->midi_position = s->pcm_channels; + + /* + * We do not know the actual MIDI FIFO size of most devices. Just + * assume two bytes, i.e., one byte can be received over the bus while + * the previous one is transmitted over MIDI. + * (The value here is adjusted for midi_ratelimit_per_packet().) + */ + s->midi_fifo_limit = rate - MIDI_BYTES_PER_SECOND * s->syt_interval + 1; } EXPORT_SYMBOL(amdtp_stream_set_parameters); @@ -467,6 +481,36 @@ static void amdtp_fill_pcm_silence(struct amdtp_stream *s, } } +/* + * To avoid sending MIDI bytes at too high a rate, assume that the receiving + * device has a FIFO, and track how much it is filled. This values increases + * by one whenever we send one byte in a packet, but the FIFO empties at + * a constant rate independent of our packet rate. One packet has syt_interval + * samples, so the number of bytes that empty out of the FIFO, per packet(!), + * is MIDI_BYTES_PER_SECOND * syt_interval / sample_rate. To avoid storing + * fractional values, the values in midi_fifo_used[] are measured in bytes + * multiplied by the sample rate. + */ +static bool midi_ratelimit_per_packet(struct amdtp_stream *s, unsigned int port) +{ + int used; + + used = s->midi_fifo_used[port]; + if (used == 0) /* common shortcut */ + return true; + + used -= MIDI_BYTES_PER_SECOND * s->syt_interval; + used = max(used, 0); + s->midi_fifo_used[port] = used; + + return used < s->midi_fifo_limit; +} + +static void midi_rate_use_one_byte(struct amdtp_stream *s, unsigned int port) +{ + s->midi_fifo_used[port] += amdtp_rate_table[s->sfc]; +} + static void amdtp_fill_midi(struct amdtp_stream *s, __be32 *buffer, unsigned int frames) { @@ -474,16 +518,21 @@ static void amdtp_fill_midi(struct amdtp_stream *s, u8 *b; for (f = 0; f < frames; f++) { - buffer[s->midi_position] = 0; b = (u8 *)&buffer[s->midi_position]; port = (s->data_block_counter + f) % 8; - if ((f >= MAX_MIDI_RX_BLOCKS) || - (s->midi[port] == NULL) || - (snd_rawmidi_transmit(s->midi[port], b + 1, 1) <= 0)) - b[0] = 0x80; - else + if (f < MAX_MIDI_RX_BLOCKS && + midi_ratelimit_per_packet(s, port) && + s->midi[port] != NULL && + snd_rawmidi_transmit(s->midi[port], &b[1], 1) == 1) { + midi_rate_use_one_byte(s, port); b[0] = 0x81; + } else { + b[0] = 0x80; + b[1] = 0; + } + b[2] = 0; + b[3] = 0; buffer += s->data_block_quadlets; } diff --git a/sound/firewire/amdtp.h b/sound/firewire/amdtp.h index cd4c4df..8a03a91 100644 --- a/sound/firewire/amdtp.h +++ b/sound/firewire/amdtp.h @@ -148,6 +148,8 @@ struct amdtp_stream { bool double_pcm_frames; struct snd_rawmidi_substream *midi[AMDTP_MAX_CHANNELS_FOR_MIDI * 8]; + int midi_fifo_limit; + int midi_fifo_used[AMDTP_MAX_CHANNELS_FOR_MIDI * 8]; /* quirk: fixed interval of dbc between previos/current packets. */ unsigned int tx_dbc_interval;