From patchwork Sun Dec 16 08:32:32 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Sakamoto X-Patchwork-Id: 10732385 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 413A41575 for ; Sun, 16 Dec 2018 08:33:31 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3018329DC4 for ; Sun, 16 Dec 2018 08:33:31 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2303029DC8; Sun, 16 Dec 2018 08:33:31 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3A69429DC4 for ; Sun, 16 Dec 2018 08:33:30 +0000 (UTC) Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id 9C0DC267AD4; Sun, 16 Dec 2018 09:33:04 +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 6250A267AC1; Sun, 16 Dec 2018 09:32:59 +0100 (CET) Received: from mail-pf1-f193.google.com (mail-pf1-f193.google.com [209.85.210.193]) by alsa0.perex.cz (Postfix) with ESMTP id 76221267944 for ; Sun, 16 Dec 2018 09:32:56 +0100 (CET) Received: by mail-pf1-f193.google.com with SMTP id c72so4869610pfc.6 for ; Sun, 16 Dec 2018 00:32:56 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=DtYNmYU7hJR2lxTndOCWuDrWTpUhG6BAm7uu5z3d8Cw=; b=iXE7HykWjmtfc5l3H/2CmawRjLB15G5jwYkAF9Eq5mVMXuN/3tQiGFhofg36xSZU9E 63gg2cTYFOOsbP8veXbSKFSy/NKSxuQoDHRXuQ53Ay4/wxrtd+FApmTMAJiTrTxcEJiW vFNhjmyPvIyaPrfSvbyJVgu9IpSOeblJHrPBVcNL4LYUQZZnJ4CjV13q9DPOtL7uz70U /xlZdsnNfL3olTOOCaM1ivLRLRQnkM30l7n7L+qlCMvN/q+7siNRgQypfHK32R4CJyMw TweahiucsMf9bPdsGzFNDFhPk6ziuKTvWNM2um+axhRD8+GxWlnuQO0y78HndDRFcBXt XK+g== X-Gm-Message-State: AA+aEWYQgYm0GMFBG1L314TgQRWOzyp52YvGnxzocTadA7V9rcfon4F+ frUlbndH8rbUDVXtCb//34Q= X-Google-Smtp-Source: AFSGD/VA2++UbcjMxpBHw+jz7p5F7xlaYOBYo6hRaR8UnDX8wMK/veYL9dEljM2MQimBa/KjWyBhRQ== X-Received: by 2002:a62:2606:: with SMTP id m6mr8733574pfm.133.1544949175595; Sun, 16 Dec 2018 00:32:55 -0800 (PST) Received: from localhost.localdomain ([2405:6580:9660:3200:bcf1:29e1:e2b3:875b]) by smtp.gmail.com with ESMTPSA id d11sm13712984pgi.25.2018.12.16.00.32.53 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 16 Dec 2018 00:32:55 -0800 (PST) From: Takashi Sakamoto To: clemens@ladisch.de, tiwai@suse.de Date: Sun, 16 Dec 2018 17:32:32 +0900 Message-Id: <20181216083233.11358-5-o-takashi@sakamocchi.jp> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181216083233.11358-1-o-takashi@sakamocchi.jp> References: <20181216083233.11358-1-o-takashi@sakamocchi.jp> MIME-Version: 1.0 Cc: alsa-devel@alsa-project.org, ffado-devel@lists.sourceforge.net Subject: [alsa-devel] [PATCH 4/5] ALSA: fireface: add support for packet streaming on Fireface 800 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 This commit adds a functionality to multiplex PCM frames into isochronous packets and demultiplex PCM frames from isochronous packets for ALSA PCM applications. Fireface 800 voluntarily maintains resources for tx isochronous communication. It performs reservation of isochronous channel and allocation/update of bandwidth in some cases below: - at a first request to allocation after bus resets - at requests to allocation when further bandwidth is required When request is grant and the unit is prepared, read data from 0x0000801c0008 represents isochronous channel for tx stream, then the unit can handle requests to start communication. If driver send the request without checking the register, the unit takes panic to continue bus resets. The unit starts transmission of tx packets after receiving several rx packets from driver. I note that the unit can process tx/rx packets and generate/record sound regardless of HOST LED. Signed-off-by: Takashi Sakamoto --- sound/firewire/fireface/ff-protocol-ff800.c | 116 ++++++++++++++++++++ sound/firewire/fireface/ff.c | 29 +++-- 2 files changed, 129 insertions(+), 16 deletions(-) diff --git a/sound/firewire/fireface/ff-protocol-ff800.c b/sound/firewire/fireface/ff-protocol-ff800.c index d24439734304..2acbf6039770 100644 --- a/sound/firewire/fireface/ff-protocol-ff800.c +++ b/sound/firewire/fireface/ff-protocol-ff800.c @@ -6,8 +6,122 @@ * Licensed under the terms of the GNU General Public License, version 2. */ +#include + #include "ff.h" +#define FF800_STF 0x0000fc88f000 +#define FF800_RX_PACKET_FORMAT 0x0000fc88f004 +#define FF800_ALLOC_TX_STREAM 0x0000fc88f008 +#define FF800_ISOC_COMM_START 0x0000fc88f00c +#define FF800_TX_S800_FLAG 0x00000800 +#define FF800_ISOC_COMM_STOP 0x0000fc88f010 + +#define FF800_TX_PACKET_ISOC_CH 0x0000801c0008 + +static int allocate_rx_resources(struct snd_ff *ff) +{ + u32 data; + __le32 reg; + int err; + + // Controllers should allocate isochronous resources for rx stream. + err = fw_iso_resources_allocate(&ff->rx_resources, + amdtp_stream_get_max_payload(&ff->rx_stream), + fw_parent_device(ff->unit)->max_speed); + if (err < 0) + return err; + + // Set isochronous channel and the number of quadlets of rx packets. + data = ff->rx_stream.data_block_quadlets << 3; + data = (data << 8) | ff->rx_resources.channel; + reg = cpu_to_le32(data); + return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, + FF800_RX_PACKET_FORMAT, ®, sizeof(reg), 0); +} + +static int allocate_tx_resources(struct snd_ff *ff) +{ + __le32 reg; + unsigned int count; + unsigned int tx_isoc_channel; + int err; + + reg = cpu_to_le32(ff->tx_stream.data_block_quadlets); + err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, + FF800_ALLOC_TX_STREAM, ®, sizeof(reg), 0); + if (err < 0) + return err; + + // Wait till the format of tx packet is available. + count = 0; + while (count++ < 10) { + u32 data; + err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST, + FF800_TX_PACKET_ISOC_CH, ®, sizeof(reg), 0); + if (err < 0) + return err; + + data = le32_to_cpu(reg); + if (data != 0xffffffff) { + tx_isoc_channel = data; + break; + } + + msleep(50); + } + if (count >= 10) + return -ETIMEDOUT; + + // NOTE: this is a makeshift to start OHCI 1394 IR context in the + // channel. On the other hand, 'struct fw_iso_resources.allocated' is + // not true and it's not deallocated at stop. + ff->tx_resources.channel = tx_isoc_channel; + + return 0; +} + +static int ff800_begin_session(struct snd_ff *ff, unsigned int rate) +{ + __le32 reg; + int err; + + reg = cpu_to_le32(rate); + err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, + FF800_STF, ®, sizeof(reg), 0); + if (err < 0) + return err; + + // If starting isochronous communication immediately, change of STF has + // no effect. In this case, the communication runs based on former STF. + // Let's sleep for a bit. + msleep(100); + + err = allocate_rx_resources(ff); + if (err < 0) + return err; + + err = allocate_tx_resources(ff); + if (err < 0) + return err; + + reg = cpu_to_le32(0x80000000); + reg |= cpu_to_le32(ff->tx_stream.data_block_quadlets); + if (fw_parent_device(ff->unit)->max_speed == SCODE_800) + reg |= cpu_to_le32(FF800_TX_S800_FLAG); + return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, + FF800_ISOC_COMM_START, ®, sizeof(reg), 0); +} + +static void ff800_finish_session(struct snd_ff *ff) +{ + __le32 reg; + + reg = cpu_to_le32(0x80000000); + snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, + FF800_ISOC_COMM_STOP, ®, sizeof(reg), 0); +} + static void ff800_handle_midi_msg(struct snd_ff *ff, __le32 *buf, size_t length) { int i; @@ -24,4 +138,6 @@ static void ff800_handle_midi_msg(struct snd_ff *ff, __le32 *buf, size_t length) const struct snd_ff_protocol snd_ff_protocol_ff800 = { .handle_midi_msg = ff800_handle_midi_msg, + .begin_session = ff800_begin_session, + .finish_session = ff800_finish_session, }; diff --git a/sound/firewire/fireface/ff.c b/sound/firewire/fireface/ff.c index d486984c0e5b..f7a752930060 100644 --- a/sound/firewire/fireface/ff.c +++ b/sound/firewire/fireface/ff.c @@ -31,8 +31,7 @@ static void ff_card_free(struct snd_card *card) { struct snd_ff *ff = card->private_data; - if (ff->spec->protocol->begin_session) - snd_ff_stream_destroy_duplex(ff); + snd_ff_stream_destroy_duplex(ff); snd_ff_transaction_unregister(ff); } @@ -57,11 +56,9 @@ static void do_registration(struct work_struct *work) name_card(ff); - if (ff->spec->protocol->begin_session) { - err = snd_ff_stream_init_duplex(ff); - if (err < 0) - goto error; - } + err = snd_ff_stream_init_duplex(ff); + if (err < 0) + goto error; snd_ff_proc_init(ff); @@ -69,15 +66,13 @@ static void do_registration(struct work_struct *work) if (err < 0) goto error; - if (ff->spec->protocol->begin_session) { - err = snd_ff_create_pcm_devices(ff); - if (err < 0) - goto error; + err = snd_ff_create_pcm_devices(ff); + if (err < 0) + goto error; - err = snd_ff_create_hwdep_devices(ff); - if (err < 0) - goto error; - } + err = snd_ff_create_hwdep_devices(ff); + if (err < 0) + goto error; err = snd_card_register(ff->card); if (err < 0) @@ -126,7 +121,7 @@ static void snd_ff_update(struct fw_unit *unit) snd_ff_transaction_reregister(ff); - if (ff->registered && ff->spec->protocol->begin_session) + if (ff->registered) snd_ff_stream_update_duplex(ff); } @@ -152,6 +147,8 @@ static void snd_ff_remove(struct fw_unit *unit) static const struct snd_ff_spec spec_ff800 = { .name = "Fireface800", + .pcm_capture_channels = {28, 20, 12}, + .pcm_playback_channels = {28, 20, 12}, .midi_in_ports = 1, .midi_out_ports = 1, .protocol = &snd_ff_protocol_ff800,