From e199d1eb7f5dbc8e5127af08726a8b6452e2641f Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 20 Jan 2019 17:25:45 +0900 Subject: ALSA: fireface: rename protocol layer for former models In a series of Fireface, later model supports different protocol from former models. This commit is a preparation to support both of protocols. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/Makefile | 2 +- sound/firewire/fireface/ff-protocol-ff800.c | 143 --------------------------- sound/firewire/fireface/ff-protocol-former.c | 142 ++++++++++++++++++++++++++ 3 files changed, 143 insertions(+), 144 deletions(-) delete mode 100644 sound/firewire/fireface/ff-protocol-ff800.c create mode 100644 sound/firewire/fireface/ff-protocol-former.c (limited to 'sound/firewire') diff --git a/sound/firewire/fireface/Makefile b/sound/firewire/fireface/Makefile index 79a7d6d99d72..3fb586d32584 100644 --- a/sound/firewire/fireface/Makefile +++ b/sound/firewire/fireface/Makefile @@ -1,4 +1,4 @@ snd-fireface-objs := ff.o ff-transaction.o ff-midi.o ff-proc.o amdtp-ff.o \ ff-stream.o ff-pcm.o ff-hwdep.o ff-protocol-ff400.o \ - ff-protocol-ff800.o + ff-protocol-former.o obj-$(CONFIG_SND_FIREFACE) += snd-fireface.o diff --git a/sound/firewire/fireface/ff-protocol-ff800.c b/sound/firewire/fireface/ff-protocol-ff800.c deleted file mode 100644 index 2acbf6039770..000000000000 --- a/sound/firewire/fireface/ff-protocol-ff800.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * ff-protocol-ff800.c - a part of driver for RME Fireface series - * - * Copyright (c) 2018 Takashi Sakamoto - * - * 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; - - for (i = 0; i < length / 4; i++) { - u8 byte = le32_to_cpu(buf[i]) & 0xff; - struct snd_rawmidi_substream *substream; - - substream = READ_ONCE(ff->tx_midi_substreams[0]); - if (substream) - snd_rawmidi_receive(substream, &byte, 1); - } -} - -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-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c new file mode 100644 index 000000000000..a383fd5fc879 --- /dev/null +++ b/sound/firewire/fireface/ff-protocol-former.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0 +// ff-protocol-former.c - a part of driver for RME Fireface series +// +// Copyright (c) 2019 Takashi Sakamoto +// +// 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; + + for (i = 0; i < length / 4; i++) { + u8 byte = le32_to_cpu(buf[i]) & 0xff; + struct snd_rawmidi_substream *substream; + + substream = READ_ONCE(ff->tx_midi_substreams[0]); + if (substream) + snd_rawmidi_receive(substream, &byte, 1); + } +} + +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, +}; -- cgit v1.2.3 From 9dd466aca377182b7ea77bc0058c64abba667f90 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 20 Jan 2019 17:25:46 +0900 Subject: ALSA: fireface: unify protocol layer for FF400/FF800 This commit moves codes for Fireface 400 to a file of former protocol. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/Makefile | 3 +- sound/firewire/fireface/ff-protocol-ff400.c | 161 --------------------------- sound/firewire/fireface/ff-protocol-former.c | 147 ++++++++++++++++++++++++ 3 files changed, 148 insertions(+), 163 deletions(-) delete mode 100644 sound/firewire/fireface/ff-protocol-ff400.c (limited to 'sound/firewire') diff --git a/sound/firewire/fireface/Makefile b/sound/firewire/fireface/Makefile index 3fb586d32584..62eb78962b93 100644 --- a/sound/firewire/fireface/Makefile +++ b/sound/firewire/fireface/Makefile @@ -1,4 +1,3 @@ snd-fireface-objs := ff.o ff-transaction.o ff-midi.o ff-proc.o amdtp-ff.o \ - ff-stream.o ff-pcm.o ff-hwdep.o ff-protocol-ff400.o \ - ff-protocol-former.o + ff-stream.o ff-pcm.o ff-hwdep.o ff-protocol-former.o obj-$(CONFIG_SND_FIREFACE) += snd-fireface.o diff --git a/sound/firewire/fireface/ff-protocol-ff400.c b/sound/firewire/fireface/ff-protocol-ff400.c deleted file mode 100644 index 2280fab9b3c7..000000000000 --- a/sound/firewire/fireface/ff-protocol-ff400.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * ff-protocol-ff400.c - a part of driver for RME Fireface series - * - * Copyright (c) 2015-2017 Takashi Sakamoto - * - * Licensed under the terms of the GNU General Public License, version 2. - */ - -#include -#include "ff.h" - -#define FF400_STF 0x000080100500ull -#define FF400_RX_PACKET_FORMAT 0x000080100504ull -#define FF400_ISOC_COMM_START 0x000080100508ull -#define FF400_TX_PACKET_FORMAT 0x00008010050cull -#define FF400_ISOC_COMM_STOP 0x000080100510ull - -/* - * Fireface 400 manages isochronous channel number in 3 bit field. Therefore, - * we can allocate between 0 and 7 channel. - */ -static int keep_resources(struct snd_ff *ff, unsigned int rate) -{ - enum snd_ff_stream_mode mode; - int i; - int err; - - // Check whether the given value is supported or not. - for (i = 0; i < CIP_SFC_COUNT; i++) { - if (amdtp_rate_table[i] == rate) - break; - } - if (i >= CIP_SFC_COUNT) - return -EINVAL; - - err = snd_ff_stream_get_multiplier_mode(i, &mode); - if (err < 0) - return err; - - /* Keep resources for in-stream. */ - ff->tx_resources.channels_mask = 0x00000000000000ffuLL; - err = fw_iso_resources_allocate(&ff->tx_resources, - amdtp_stream_get_max_payload(&ff->tx_stream), - fw_parent_device(ff->unit)->max_speed); - if (err < 0) - return err; - - /* Keep resources for out-stream. */ - err = amdtp_ff_set_parameters(&ff->rx_stream, rate, - ff->spec->pcm_playback_channels[mode]); - if (err < 0) - return err; - ff->rx_resources.channels_mask = 0x00000000000000ffuLL; - 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) - fw_iso_resources_free(&ff->tx_resources); - - return err; -} - -static int ff400_begin_session(struct snd_ff *ff, unsigned int rate) -{ - __le32 reg; - int err; - - err = keep_resources(ff, rate); - if (err < 0) - return err; - - /* Set the number of data blocks transferred in a second. */ - reg = cpu_to_le32(rate); - err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, - FF400_STF, ®, sizeof(reg), 0); - if (err < 0) - return err; - - msleep(100); - - /* - * Set isochronous channel and the number of quadlets of received - * packets. - */ - reg = cpu_to_le32(((ff->rx_stream.data_block_quadlets << 3) << 8) | - ff->rx_resources.channel); - err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, - FF400_RX_PACKET_FORMAT, ®, sizeof(reg), 0); - if (err < 0) - return err; - - /* - * Set isochronous channel and the number of quadlets of transmitted - * packet. - */ - /* TODO: investigate the purpose of this 0x80. */ - reg = cpu_to_le32((0x80 << 24) | - (ff->tx_resources.channel << 5) | - (ff->tx_stream.data_block_quadlets)); - err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, - FF400_TX_PACKET_FORMAT, ®, sizeof(reg), 0); - if (err < 0) - return err; - - /* Allow to transmit packets. */ - reg = cpu_to_le32(0x00000001); - return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, - FF400_ISOC_COMM_START, ®, sizeof(reg), 0); -} - -static void ff400_finish_session(struct snd_ff *ff) -{ - __le32 reg; - - reg = cpu_to_le32(0x80000000); - snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, - FF400_ISOC_COMM_STOP, ®, sizeof(reg), 0); -} - -static void ff400_handle_midi_msg(struct snd_ff *ff, __le32 *buf, size_t length) -{ - int i; - - for (i = 0; i < length / 4; i++) { - u32 quad = le32_to_cpu(buf[i]); - u8 byte; - unsigned int index; - struct snd_rawmidi_substream *substream; - - /* Message in first port. */ - /* - * This value may represent the index of this unit when the same - * units are on the same IEEE 1394 bus. This driver doesn't use - * it. - */ - index = (quad >> 8) & 0xff; - if (index > 0) { - substream = READ_ONCE(ff->tx_midi_substreams[0]); - if (substream != NULL) { - byte = quad & 0xff; - snd_rawmidi_receive(substream, &byte, 1); - } - } - - /* Message in second port. */ - index = (quad >> 24) & 0xff; - if (index > 0) { - substream = READ_ONCE(ff->tx_midi_substreams[1]); - if (substream != NULL) { - byte = (quad >> 16) & 0xff; - snd_rawmidi_receive(substream, &byte, 1); - } - } - } -} - -const struct snd_ff_protocol snd_ff_protocol_ff400 = { - .handle_midi_msg = ff400_handle_midi_msg, - .begin_session = ff400_begin_session, - .finish_session = ff400_finish_session, -}; diff --git a/sound/firewire/fireface/ff-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c index a383fd5fc879..ed1271a89484 100644 --- a/sound/firewire/fireface/ff-protocol-former.c +++ b/sound/firewire/fireface/ff-protocol-former.c @@ -140,3 +140,150 @@ const struct snd_ff_protocol snd_ff_protocol_ff800 = { .begin_session = ff800_begin_session, .finish_session = ff800_finish_session, }; + +#define FF400_STF 0x000080100500ull +#define FF400_RX_PACKET_FORMAT 0x000080100504ull +#define FF400_ISOC_COMM_START 0x000080100508ull +#define FF400_TX_PACKET_FORMAT 0x00008010050cull +#define FF400_ISOC_COMM_STOP 0x000080100510ull + +/* + * Fireface 400 manages isochronous channel number in 3 bit field. Therefore, + * we can allocate between 0 and 7 channel. + */ +static int keep_resources(struct snd_ff *ff, unsigned int rate) +{ + enum snd_ff_stream_mode mode; + int i; + int err; + + // Check whether the given value is supported or not. + for (i = 0; i < CIP_SFC_COUNT; i++) { + if (amdtp_rate_table[i] == rate) + break; + } + if (i >= CIP_SFC_COUNT) + return -EINVAL; + + err = snd_ff_stream_get_multiplier_mode(i, &mode); + if (err < 0) + return err; + + /* Keep resources for in-stream. */ + ff->tx_resources.channels_mask = 0x00000000000000ffuLL; + err = fw_iso_resources_allocate(&ff->tx_resources, + amdtp_stream_get_max_payload(&ff->tx_stream), + fw_parent_device(ff->unit)->max_speed); + if (err < 0) + return err; + + /* Keep resources for out-stream. */ + ff->rx_resources.channels_mask = 0x00000000000000ffuLL; + 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) + fw_iso_resources_free(&ff->tx_resources); + + return err; +} + +static int ff400_begin_session(struct snd_ff *ff, unsigned int rate) +{ + __le32 reg; + int err; + + err = keep_resources(ff, rate); + if (err < 0) + return err; + + /* Set the number of data blocks transferred in a second. */ + reg = cpu_to_le32(rate); + err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, + FF400_STF, ®, sizeof(reg), 0); + if (err < 0) + return err; + + msleep(100); + + /* + * Set isochronous channel and the number of quadlets of received + * packets. + */ + reg = cpu_to_le32(((ff->rx_stream.data_block_quadlets << 3) << 8) | + ff->rx_resources.channel); + err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, + FF400_RX_PACKET_FORMAT, ®, sizeof(reg), 0); + if (err < 0) + return err; + + /* + * Set isochronous channel and the number of quadlets of transmitted + * packet. + */ + /* TODO: investigate the purpose of this 0x80. */ + reg = cpu_to_le32((0x80 << 24) | + (ff->tx_resources.channel << 5) | + (ff->tx_stream.data_block_quadlets)); + err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, + FF400_TX_PACKET_FORMAT, ®, sizeof(reg), 0); + if (err < 0) + return err; + + /* Allow to transmit packets. */ + reg = cpu_to_le32(0x00000001); + return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, + FF400_ISOC_COMM_START, ®, sizeof(reg), 0); +} + +static void ff400_finish_session(struct snd_ff *ff) +{ + __le32 reg; + + reg = cpu_to_le32(0x80000000); + snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, + FF400_ISOC_COMM_STOP, ®, sizeof(reg), 0); +} + +static void ff400_handle_midi_msg(struct snd_ff *ff, __le32 *buf, size_t length) +{ + int i; + + for (i = 0; i < length / 4; i++) { + u32 quad = le32_to_cpu(buf[i]); + u8 byte; + unsigned int index; + struct snd_rawmidi_substream *substream; + + /* Message in first port. */ + /* + * This value may represent the index of this unit when the same + * units are on the same IEEE 1394 bus. This driver doesn't use + * it. + */ + index = (quad >> 8) & 0xff; + if (index > 0) { + substream = READ_ONCE(ff->tx_midi_substreams[0]); + if (substream != NULL) { + byte = quad & 0xff; + snd_rawmidi_receive(substream, &byte, 1); + } + } + + /* Message in second port. */ + index = (quad >> 24) & 0xff; + if (index > 0) { + substream = READ_ONCE(ff->tx_midi_substreams[1]); + if (substream != NULL) { + byte = (quad >> 16) & 0xff; + snd_rawmidi_receive(substream, &byte, 1); + } + } + } +} + +const struct snd_ff_protocol snd_ff_protocol_ff400 = { + .handle_midi_msg = ff400_handle_midi_msg, + .begin_session = ff400_begin_session, + .finish_session = ff400_finish_session, +}; -- cgit v1.2.3 From 2f8af5b3f09cd3d2b483b35a400bf2b827ada179 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 20 Jan 2019 17:25:47 +0900 Subject: ALSA: fireface: obsolete proc node to leave one node In a series of Fireface, latter protocol has no way for drivers to retrieve current clock configuration. On the other hand, this driver has proc node for it. This commit removes a proc node to dump both clock configuration and synchronization status in one proc node. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-proc.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'sound/firewire') diff --git a/sound/firewire/fireface/ff-proc.c b/sound/firewire/fireface/ff-proc.c index a0c550dabe9a..37f84b7fc432 100644 --- a/sound/firewire/fireface/ff-proc.c +++ b/sound/firewire/fireface/ff-proc.c @@ -8,10 +8,8 @@ #include "./ff.h" -static void proc_dump_clock_config(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) +static void dump_clock_config(struct snd_ff *ff, struct snd_info_buffer *buffer) { - struct snd_ff *ff = entry->private_data; __le32 reg; u32 data; unsigned int rate; @@ -87,10 +85,8 @@ static void proc_dump_clock_config(struct snd_info_entry *entry, snd_iprintf(buffer, "Sync to clock source: %s\n", src); } -static void proc_dump_sync_status(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) +static void dump_sync_status(struct snd_ff *ff, struct snd_info_buffer *buffer) { - struct snd_ff *ff = entry->private_data; __le32 reg; u32 data; int err; @@ -213,6 +209,15 @@ static void proc_dump_sync_status(struct snd_info_entry *entry, snd_iprintf(buffer, "%d\n", (data & 0x3ff) * 250); } +static void proc_dump_status(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct snd_ff *ff = entry->private_data; + + dump_clock_config(ff, buffer); + dump_sync_status(ff, buffer); +} + static void add_node(struct snd_ff *ff, struct snd_info_entry *root, const char *name, void (*op)(struct snd_info_entry *e, @@ -247,6 +252,5 @@ void snd_ff_proc_init(struct snd_ff *ff) return; } - add_node(ff, root, "clock-config", proc_dump_clock_config); - add_node(ff, root, "sync-status", proc_dump_sync_status); + add_node(ff, root, "status", proc_dump_status); } -- cgit v1.2.3 From e9e29cf8522093f146ab2c23194eee78dd84fa4e Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 20 Jan 2019 17:25:48 +0900 Subject: ALSA: fireface: add protocol-dependent operation to dump status This commit adds a member for a callback function to dump status and move existing code to former protocol. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-proc.c | 204 +------------------------- sound/firewire/fireface/ff-protocol-former.c | 212 +++++++++++++++++++++++++++ sound/firewire/fireface/ff.h | 2 +- 3 files changed, 214 insertions(+), 204 deletions(-) (limited to 'sound/firewire') diff --git a/sound/firewire/fireface/ff-proc.c b/sound/firewire/fireface/ff-proc.c index 37f84b7fc432..8a7cfb6ccce6 100644 --- a/sound/firewire/fireface/ff-proc.c +++ b/sound/firewire/fireface/ff-proc.c @@ -8,214 +8,12 @@ #include "./ff.h" -static void dump_clock_config(struct snd_ff *ff, struct snd_info_buffer *buffer) -{ - __le32 reg; - u32 data; - unsigned int rate; - const char *src; - int err; - - err = snd_fw_transaction(ff->unit, TCODE_READ_BLOCK_REQUEST, - SND_FF_REG_CLOCK_CONFIG, ®, sizeof(reg), 0); - if (err < 0) - return; - - data = le32_to_cpu(reg); - - snd_iprintf(buffer, "Output S/PDIF format: %s (Emphasis: %s)\n", - (data & 0x20) ? "Professional" : "Consumer", - (data & 0x40) ? "on" : "off"); - - snd_iprintf(buffer, "Optical output interface format: %s\n", - ((data >> 8) & 0x01) ? "S/PDIF" : "ADAT"); - - snd_iprintf(buffer, "Word output single speed: %s\n", - ((data >> 8) & 0x20) ? "on" : "off"); - - snd_iprintf(buffer, "S/PDIF input interface: %s\n", - ((data >> 8) & 0x02) ? "Optical" : "Coaxial"); - - switch ((data >> 1) & 0x03) { - case 0x01: - rate = 32000; - break; - case 0x00: - rate = 44100; - break; - case 0x03: - rate = 48000; - break; - case 0x02: - default: - return; - } - - if (data & 0x08) - rate *= 2; - else if (data & 0x10) - rate *= 4; - - snd_iprintf(buffer, "Sampling rate: %d\n", rate); - - if (data & 0x01) { - src = "Internal"; - } else { - switch ((data >> 10) & 0x07) { - case 0x00: - src = "ADAT1"; - break; - case 0x01: - src = "ADAT2"; - break; - case 0x03: - src = "S/PDIF"; - break; - case 0x04: - src = "Word"; - break; - case 0x05: - src = "LTC"; - break; - default: - return; - } - } - - snd_iprintf(buffer, "Sync to clock source: %s\n", src); -} - -static void dump_sync_status(struct snd_ff *ff, struct snd_info_buffer *buffer) -{ - __le32 reg; - u32 data; - int err; - - err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST, - SND_FF_REG_SYNC_STATUS, ®, sizeof(reg), 0); - if (err < 0) - return; - - data = le32_to_cpu(reg); - - snd_iprintf(buffer, "External source detection:\n"); - - snd_iprintf(buffer, "Word Clock:"); - if ((data >> 24) & 0x20) { - if ((data >> 24) & 0x40) - snd_iprintf(buffer, "sync\n"); - else - snd_iprintf(buffer, "lock\n"); - } else { - snd_iprintf(buffer, "none\n"); - } - - snd_iprintf(buffer, "S/PDIF:"); - if ((data >> 16) & 0x10) { - if ((data >> 16) & 0x04) - snd_iprintf(buffer, "sync\n"); - else - snd_iprintf(buffer, "lock\n"); - } else { - snd_iprintf(buffer, "none\n"); - } - - snd_iprintf(buffer, "ADAT1:"); - if ((data >> 8) & 0x04) { - if ((data >> 8) & 0x10) - snd_iprintf(buffer, "sync\n"); - else - snd_iprintf(buffer, "lock\n"); - } else { - snd_iprintf(buffer, "none\n"); - } - - snd_iprintf(buffer, "ADAT2:"); - if ((data >> 8) & 0x08) { - if ((data >> 8) & 0x20) - snd_iprintf(buffer, "sync\n"); - else - snd_iprintf(buffer, "lock\n"); - } else { - snd_iprintf(buffer, "none\n"); - } - - snd_iprintf(buffer, "\nUsed external source:\n"); - - if (((data >> 22) & 0x07) == 0x07) { - snd_iprintf(buffer, "None\n"); - } else { - switch ((data >> 22) & 0x07) { - case 0x00: - snd_iprintf(buffer, "ADAT1:"); - break; - case 0x01: - snd_iprintf(buffer, "ADAT2:"); - break; - case 0x03: - snd_iprintf(buffer, "S/PDIF:"); - break; - case 0x04: - snd_iprintf(buffer, "Word:"); - break; - case 0x07: - snd_iprintf(buffer, "Nothing:"); - break; - case 0x02: - case 0x05: - case 0x06: - default: - snd_iprintf(buffer, "unknown:"); - break; - } - - if ((data >> 25) & 0x07) { - switch ((data >> 25) & 0x07) { - case 0x01: - snd_iprintf(buffer, "32000\n"); - break; - case 0x02: - snd_iprintf(buffer, "44100\n"); - break; - case 0x03: - snd_iprintf(buffer, "48000\n"); - break; - case 0x04: - snd_iprintf(buffer, "64000\n"); - break; - case 0x05: - snd_iprintf(buffer, "88200\n"); - break; - case 0x06: - snd_iprintf(buffer, "96000\n"); - break; - case 0x07: - snd_iprintf(buffer, "128000\n"); - break; - case 0x08: - snd_iprintf(buffer, "176400\n"); - break; - case 0x09: - snd_iprintf(buffer, "192000\n"); - break; - case 0x00: - snd_iprintf(buffer, "unknown\n"); - break; - } - } - } - - snd_iprintf(buffer, "Multiplied:"); - snd_iprintf(buffer, "%d\n", (data & 0x3ff) * 250); -} - static void proc_dump_status(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_ff *ff = entry->private_data; - dump_clock_config(ff, buffer); - dump_sync_status(ff, buffer); + ff->spec->protocol->dump_status(ff, buffer); } static void add_node(struct snd_ff *ff, struct snd_info_entry *root, diff --git a/sound/firewire/fireface/ff-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c index ed1271a89484..5f97e7fc7281 100644 --- a/sound/firewire/fireface/ff-protocol-former.c +++ b/sound/firewire/fireface/ff-protocol-former.c @@ -9,6 +9,216 @@ #include "ff.h" +#define FORMER_REG_SYNC_STATUS 0x0000801c0000ull + +static void dump_clock_config(struct snd_ff *ff, struct snd_info_buffer *buffer) +{ + __le32 reg; + u32 data; + unsigned int rate; + const char *src; + int err; + + err = snd_fw_transaction(ff->unit, TCODE_READ_BLOCK_REQUEST, + SND_FF_REG_CLOCK_CONFIG, ®, sizeof(reg), 0); + if (err < 0) + return; + + data = le32_to_cpu(reg); + + snd_iprintf(buffer, "Output S/PDIF format: %s (Emphasis: %s)\n", + (data & 0x20) ? "Professional" : "Consumer", + (data & 0x40) ? "on" : "off"); + + snd_iprintf(buffer, "Optical output interface format: %s\n", + ((data >> 8) & 0x01) ? "S/PDIF" : "ADAT"); + + snd_iprintf(buffer, "Word output single speed: %s\n", + ((data >> 8) & 0x20) ? "on" : "off"); + + snd_iprintf(buffer, "S/PDIF input interface: %s\n", + ((data >> 8) & 0x02) ? "Optical" : "Coaxial"); + + switch ((data >> 1) & 0x03) { + case 0x01: + rate = 32000; + break; + case 0x00: + rate = 44100; + break; + case 0x03: + rate = 48000; + break; + case 0x02: + default: + return; + } + + if (data & 0x08) + rate *= 2; + else if (data & 0x10) + rate *= 4; + + snd_iprintf(buffer, "Sampling rate: %d\n", rate); + + if (data & 0x01) { + src = "Internal"; + } else { + switch ((data >> 10) & 0x07) { + case 0x00: + src = "ADAT1"; + break; + case 0x01: + src = "ADAT2"; + break; + case 0x03: + src = "S/PDIF"; + break; + case 0x04: + src = "Word"; + break; + case 0x05: + src = "LTC"; + break; + default: + return; + } + } + + snd_iprintf(buffer, "Sync to clock source: %s\n", src); +} + +static void dump_sync_status(struct snd_ff *ff, struct snd_info_buffer *buffer) +{ + __le32 reg; + u32 data; + int err; + + err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST, + FORMER_REG_SYNC_STATUS, ®, sizeof(reg), 0); + if (err < 0) + return; + + data = le32_to_cpu(reg); + + snd_iprintf(buffer, "External source detection:\n"); + + snd_iprintf(buffer, "Word Clock:"); + if ((data >> 24) & 0x20) { + if ((data >> 24) & 0x40) + snd_iprintf(buffer, "sync\n"); + else + snd_iprintf(buffer, "lock\n"); + } else { + snd_iprintf(buffer, "none\n"); + } + + snd_iprintf(buffer, "S/PDIF:"); + if ((data >> 16) & 0x10) { + if ((data >> 16) & 0x04) + snd_iprintf(buffer, "sync\n"); + else + snd_iprintf(buffer, "lock\n"); + } else { + snd_iprintf(buffer, "none\n"); + } + + snd_iprintf(buffer, "ADAT1:"); + if ((data >> 8) & 0x04) { + if ((data >> 8) & 0x10) + snd_iprintf(buffer, "sync\n"); + else + snd_iprintf(buffer, "lock\n"); + } else { + snd_iprintf(buffer, "none\n"); + } + + snd_iprintf(buffer, "ADAT2:"); + if ((data >> 8) & 0x08) { + if ((data >> 8) & 0x20) + snd_iprintf(buffer, "sync\n"); + else + snd_iprintf(buffer, "lock\n"); + } else { + snd_iprintf(buffer, "none\n"); + } + + snd_iprintf(buffer, "\nUsed external source:\n"); + + if (((data >> 22) & 0x07) == 0x07) { + snd_iprintf(buffer, "None\n"); + } else { + switch ((data >> 22) & 0x07) { + case 0x00: + snd_iprintf(buffer, "ADAT1:"); + break; + case 0x01: + snd_iprintf(buffer, "ADAT2:"); + break; + case 0x03: + snd_iprintf(buffer, "S/PDIF:"); + break; + case 0x04: + snd_iprintf(buffer, "Word:"); + break; + case 0x07: + snd_iprintf(buffer, "Nothing:"); + break; + case 0x02: + case 0x05: + case 0x06: + default: + snd_iprintf(buffer, "unknown:"); + break; + } + + if ((data >> 25) & 0x07) { + switch ((data >> 25) & 0x07) { + case 0x01: + snd_iprintf(buffer, "32000\n"); + break; + case 0x02: + snd_iprintf(buffer, "44100\n"); + break; + case 0x03: + snd_iprintf(buffer, "48000\n"); + break; + case 0x04: + snd_iprintf(buffer, "64000\n"); + break; + case 0x05: + snd_iprintf(buffer, "88200\n"); + break; + case 0x06: + snd_iprintf(buffer, "96000\n"); + break; + case 0x07: + snd_iprintf(buffer, "128000\n"); + break; + case 0x08: + snd_iprintf(buffer, "176400\n"); + break; + case 0x09: + snd_iprintf(buffer, "192000\n"); + break; + case 0x00: + snd_iprintf(buffer, "unknown\n"); + break; + } + } + } + + snd_iprintf(buffer, "Multiplied:"); + snd_iprintf(buffer, "%d\n", (data & 0x3ff) * 250); +} + +static void former_dump_status(struct snd_ff *ff, + struct snd_info_buffer *buffer) +{ + dump_clock_config(ff, buffer); + dump_sync_status(ff, buffer); +} + #define FF800_STF 0x0000fc88f000 #define FF800_RX_PACKET_FORMAT 0x0000fc88f004 #define FF800_ALLOC_TX_STREAM 0x0000fc88f008 @@ -139,6 +349,7 @@ 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, + .dump_status = former_dump_status, }; #define FF400_STF 0x000080100500ull @@ -286,4 +497,5 @@ const struct snd_ff_protocol snd_ff_protocol_ff400 = { .handle_midi_msg = ff400_handle_midi_msg, .begin_session = ff400_begin_session, .finish_session = ff400_finish_session, + .dump_status = former_dump_status, }; diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h index 7dfc7745a914..3f22b8d84e36 100644 --- a/sound/firewire/fireface/ff.h +++ b/sound/firewire/fireface/ff.h @@ -35,7 +35,6 @@ #define SND_FF_IN_MIDI_PORTS 2 #define SND_FF_OUT_MIDI_PORTS 2 -#define SND_FF_REG_SYNC_STATUS 0x0000801c0000ull /* For block write request. */ #define SND_FF_REG_FETCH_PCM_FRAMES 0x0000801c0000ull #define SND_FF_REG_CLOCK_CONFIG 0x0000801c0004ull @@ -111,6 +110,7 @@ struct snd_ff_protocol { void (*handle_midi_msg)(struct snd_ff *ff, __le32 *buf, size_t length); int (*begin_session)(struct snd_ff *ff, unsigned int rate); void (*finish_session)(struct snd_ff *ff); + void (*dump_status)(struct snd_ff *ff, struct snd_info_buffer *buffer); }; extern const struct snd_ff_protocol snd_ff_protocol_ff800; -- cgit v1.2.3 From ae3053c28b86f4f9d4480f6d3ac27f43d8e657ef Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 20 Jan 2019 17:25:49 +0900 Subject: ALSA: fireface: add protocol-dependent operation to switch mode to fetch PCM frame This commit adds a member for a callback function to switch frame fetching mode to former protocol. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-protocol-former.c | 38 ++++++++++++++++++++++++++++ sound/firewire/fireface/ff-stream.c | 38 ++-------------------------- sound/firewire/fireface/ff.h | 3 +-- 3 files changed, 41 insertions(+), 38 deletions(-) (limited to 'sound/firewire') diff --git a/sound/firewire/fireface/ff-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c index 5f97e7fc7281..279bd032acf0 100644 --- a/sound/firewire/fireface/ff-protocol-former.c +++ b/sound/firewire/fireface/ff-protocol-former.c @@ -10,6 +10,42 @@ #include "ff.h" #define FORMER_REG_SYNC_STATUS 0x0000801c0000ull +/* For block write request. */ +#define FORMER_REG_FETCH_PCM_FRAMES 0x0000801c0000ull + +static int former_switch_fetching_mode(struct snd_ff *ff, bool enable) +{ + unsigned int count; + __le32 *reg; + int i; + int err; + + count = 0; + for (i = 0; i < SND_FF_STREAM_MODE_COUNT; ++i) + count = max(count, ff->spec->pcm_playback_channels[i]); + + reg = kcalloc(count, sizeof(__le32), GFP_KERNEL); + if (!reg) + return -ENOMEM; + + if (!enable) { + /* + * Each quadlet is corresponding to data channels in a data + * blocks in reverse order. Precisely, quadlets for available + * data channels should be enabled. Here, I take second best + * to fetch PCM frames from all of data channels regardless of + * stf. + */ + for (i = 0; i < count; ++i) + reg[i] = cpu_to_le32(0x00000001); + } + + err = snd_fw_transaction(ff->unit, TCODE_WRITE_BLOCK_REQUEST, + FORMER_REG_FETCH_PCM_FRAMES, reg, + sizeof(__le32) * count, 0); + kfree(reg); + return err; +} static void dump_clock_config(struct snd_ff *ff, struct snd_info_buffer *buffer) { @@ -347,6 +383,7 @@ 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, + .switch_fetching_mode = former_switch_fetching_mode, .begin_session = ff800_begin_session, .finish_session = ff800_finish_session, .dump_status = former_dump_status, @@ -495,6 +532,7 @@ static void ff400_handle_midi_msg(struct snd_ff *ff, __le32 *buf, size_t length) const struct snd_ff_protocol snd_ff_protocol_ff400 = { .handle_midi_msg = ff400_handle_midi_msg, + .switch_fetching_mode = former_switch_fetching_mode, .begin_session = ff400_begin_session, .finish_session = ff400_finish_session, .dump_status = former_dump_status, diff --git a/sound/firewire/fireface/ff-stream.c b/sound/firewire/fireface/ff-stream.c index a490e4553721..43e1e2679798 100644 --- a/sound/firewire/fireface/ff-stream.c +++ b/sound/firewire/fireface/ff-stream.c @@ -37,44 +37,10 @@ static void release_resources(struct snd_ff *ff) fw_iso_resources_free(&ff->rx_resources); } -static int switch_fetching_mode(struct snd_ff *ff, bool enable) -{ - unsigned int count; - __le32 *reg; - int i; - int err; - - count = 0; - for (i = 0; i < SND_FF_STREAM_MODE_COUNT; ++i) - count = max(count, ff->spec->pcm_playback_channels[i]); - - reg = kcalloc(count, sizeof(__le32), GFP_KERNEL); - if (!reg) - return -ENOMEM; - - if (!enable) { - /* - * Each quadlet is corresponding to data channels in a data - * blocks in reverse order. Precisely, quadlets for available - * data channels should be enabled. Here, I take second best - * to fetch PCM frames from all of data channels regardless of - * stf. - */ - for (i = 0; i < count; ++i) - reg[i] = cpu_to_le32(0x00000001); - } - - err = snd_fw_transaction(ff->unit, TCODE_WRITE_BLOCK_REQUEST, - SND_FF_REG_FETCH_PCM_FRAMES, reg, - sizeof(__le32) * count, 0); - kfree(reg); - return err; -} - static inline void finish_session(struct snd_ff *ff) { ff->spec->protocol->finish_session(ff); - switch_fetching_mode(ff, false); + ff->spec->protocol->switch_fetching_mode(ff, false); } static int init_stream(struct snd_ff *ff, enum amdtp_stream_direction dir) @@ -206,7 +172,7 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate) goto error; } - err = switch_fetching_mode(ff, true); + err = ff->spec->protocol->switch_fetching_mode(ff, true); if (err < 0) goto error; } diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h index 3f22b8d84e36..29f55518bf85 100644 --- a/sound/firewire/fireface/ff.h +++ b/sound/firewire/fireface/ff.h @@ -35,8 +35,6 @@ #define SND_FF_IN_MIDI_PORTS 2 #define SND_FF_OUT_MIDI_PORTS 2 -/* For block write request. */ -#define SND_FF_REG_FETCH_PCM_FRAMES 0x0000801c0000ull #define SND_FF_REG_CLOCK_CONFIG 0x0000801c0004ull enum snd_ff_stream_mode { @@ -108,6 +106,7 @@ enum snd_ff_clock_src { struct snd_ff_protocol { void (*handle_midi_msg)(struct snd_ff *ff, __le32 *buf, size_t length); + int (*switch_fetching_mode)(struct snd_ff *ff, bool enable); int (*begin_session)(struct snd_ff *ff, unsigned int rate); void (*finish_session)(struct snd_ff *ff); void (*dump_status)(struct snd_ff *ff, struct snd_info_buffer *buffer); -- cgit v1.2.3 From b1d0cb0ae511c0558155c4d4cbb852c9e53bfb67 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 20 Jan 2019 17:25:50 +0900 Subject: ALSA: fireface: add protocol-dependent operation to get clock status This commit adds a member for a callback function to get clock status to former protocol. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-pcm.c | 2 +- sound/firewire/fireface/ff-protocol-former.c | 68 +++++++++++++++++++++++++++- sound/firewire/fireface/ff-stream.c | 2 +- sound/firewire/fireface/ff-transaction.c | 63 -------------------------- sound/firewire/fireface/ff.h | 6 +-- 5 files changed, 71 insertions(+), 70 deletions(-) (limited to 'sound/firewire') diff --git a/sound/firewire/fireface/ff-pcm.c b/sound/firewire/fireface/ff-pcm.c index d0bc96b20a65..5adf04b95c04 100644 --- a/sound/firewire/fireface/ff-pcm.c +++ b/sound/firewire/fireface/ff-pcm.c @@ -152,7 +152,7 @@ static int pcm_open(struct snd_pcm_substream *substream) if (err < 0) goto release_lock; - err = snd_ff_transaction_get_clock(ff, &rate, &src); + err = ff->spec->protocol->get_clock(ff, &rate, &src); if (err < 0) goto release_lock; diff --git a/sound/firewire/fireface/ff-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c index 279bd032acf0..d32104ed0c08 100644 --- a/sound/firewire/fireface/ff-protocol-former.c +++ b/sound/firewire/fireface/ff-protocol-former.c @@ -12,6 +12,70 @@ #define FORMER_REG_SYNC_STATUS 0x0000801c0000ull /* For block write request. */ #define FORMER_REG_FETCH_PCM_FRAMES 0x0000801c0000ull +#define FORMER_REG_CLOCK_CONFIG 0x0000801c0004ull + +static int former_get_clock(struct snd_ff *ff, unsigned int *rate, + enum snd_ff_clock_src *src) +{ + __le32 reg; + u32 data; + int err; + + err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST, + FORMER_REG_CLOCK_CONFIG, ®, sizeof(reg), 0); + if (err < 0) + return err; + data = le32_to_cpu(reg); + + /* Calculate sampling rate. */ + switch ((data >> 1) & 0x03) { + case 0x01: + *rate = 32000; + break; + case 0x00: + *rate = 44100; + break; + case 0x03: + *rate = 48000; + break; + case 0x02: + default: + return -EIO; + } + + if (data & 0x08) + *rate *= 2; + else if (data & 0x10) + *rate *= 4; + + /* Calculate source of clock. */ + if (data & 0x01) { + *src = SND_FF_CLOCK_SRC_INTERNAL; + } else { + /* TODO: 0x02, 0x06, 0x07? */ + switch ((data >> 10) & 0x07) { + case 0x00: + *src = SND_FF_CLOCK_SRC_ADAT1; + break; + case 0x01: + *src = SND_FF_CLOCK_SRC_ADAT2; + break; + case 0x03: + *src = SND_FF_CLOCK_SRC_SPDIF; + break; + case 0x04: + *src = SND_FF_CLOCK_SRC_WORD; + break; + case 0x05: + *src = SND_FF_CLOCK_SRC_LTC; + break; + default: + return -EIO; + } + } + + return 0; +} static int former_switch_fetching_mode(struct snd_ff *ff, bool enable) { @@ -56,7 +120,7 @@ static void dump_clock_config(struct snd_ff *ff, struct snd_info_buffer *buffer) int err; err = snd_fw_transaction(ff->unit, TCODE_READ_BLOCK_REQUEST, - SND_FF_REG_CLOCK_CONFIG, ®, sizeof(reg), 0); + FORMER_REG_CLOCK_CONFIG, ®, sizeof(reg), 0); if (err < 0) return; @@ -383,6 +447,7 @@ 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, + .get_clock = former_get_clock, .switch_fetching_mode = former_switch_fetching_mode, .begin_session = ff800_begin_session, .finish_session = ff800_finish_session, @@ -532,6 +597,7 @@ static void ff400_handle_midi_msg(struct snd_ff *ff, __le32 *buf, size_t length) const struct snd_ff_protocol snd_ff_protocol_ff400 = { .handle_midi_msg = ff400_handle_midi_msg, + .get_clock = former_get_clock, .switch_fetching_mode = former_switch_fetching_mode, .begin_session = ff400_begin_session, .finish_session = ff400_finish_session, diff --git a/sound/firewire/fireface/ff-stream.c b/sound/firewire/fireface/ff-stream.c index 43e1e2679798..a8a90f1ae09e 100644 --- a/sound/firewire/fireface/ff-stream.c +++ b/sound/firewire/fireface/ff-stream.c @@ -113,7 +113,7 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate) if (ff->substreams_counter == 0) return 0; - err = snd_ff_transaction_get_clock(ff, &curr_rate, &src); + err = ff->spec->protocol->get_clock(ff, &curr_rate, &src); if (err < 0) return err; if (curr_rate != rate || diff --git a/sound/firewire/fireface/ff-transaction.c b/sound/firewire/fireface/ff-transaction.c index 5f4ddfd55403..065e045d3fb5 100644 --- a/sound/firewire/fireface/ff-transaction.c +++ b/sound/firewire/fireface/ff-transaction.c @@ -11,69 +11,6 @@ #define SND_FF_REG_MIDI_RX_PORT_0 0x000080180000ull #define SND_FF_REG_MIDI_RX_PORT_1 0x000080190000ull -int snd_ff_transaction_get_clock(struct snd_ff *ff, unsigned int *rate, - enum snd_ff_clock_src *src) -{ - __le32 reg; - u32 data; - int err; - - err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST, - SND_FF_REG_CLOCK_CONFIG, ®, sizeof(reg), 0); - if (err < 0) - return err; - data = le32_to_cpu(reg); - - /* Calculate sampling rate. */ - switch ((data >> 1) & 0x03) { - case 0x01: - *rate = 32000; - break; - case 0x00: - *rate = 44100; - break; - case 0x03: - *rate = 48000; - break; - case 0x02: - default: - return -EIO; - } - - if (data & 0x08) - *rate *= 2; - else if (data & 0x10) - *rate *= 4; - - /* Calculate source of clock. */ - if (data & 0x01) { - *src = SND_FF_CLOCK_SRC_INTERNAL; - } else { - /* TODO: 0x02, 0x06, 0x07? */ - switch ((data >> 10) & 0x07) { - case 0x00: - *src = SND_FF_CLOCK_SRC_ADAT1; - break; - case 0x01: - *src = SND_FF_CLOCK_SRC_ADAT2; - break; - case 0x03: - *src = SND_FF_CLOCK_SRC_SPDIF; - break; - case 0x04: - *src = SND_FF_CLOCK_SRC_WORD; - break; - case 0x05: - *src = SND_FF_CLOCK_SRC_LTC; - break; - default: - return -EIO; - } - } - - return 0; -} - static void finish_transmit_midi_msg(struct snd_ff *ff, unsigned int port, int rcode) { diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h index 29f55518bf85..1de2f5ec26fd 100644 --- a/sound/firewire/fireface/ff.h +++ b/sound/firewire/fireface/ff.h @@ -35,8 +35,6 @@ #define SND_FF_IN_MIDI_PORTS 2 #define SND_FF_OUT_MIDI_PORTS 2 -#define SND_FF_REG_CLOCK_CONFIG 0x0000801c0004ull - enum snd_ff_stream_mode { SND_FF_STREAM_MODE_LOW = 0, SND_FF_STREAM_MODE_MID, @@ -106,6 +104,8 @@ enum snd_ff_clock_src { struct snd_ff_protocol { void (*handle_midi_msg)(struct snd_ff *ff, __le32 *buf, size_t length); + int (*get_clock)(struct snd_ff *ff, unsigned int *rate, + enum snd_ff_clock_src *src); int (*switch_fetching_mode)(struct snd_ff *ff, bool enable); int (*begin_session)(struct snd_ff *ff, unsigned int rate); void (*finish_session)(struct snd_ff *ff); @@ -115,8 +115,6 @@ struct snd_ff_protocol { extern const struct snd_ff_protocol snd_ff_protocol_ff800; extern const struct snd_ff_protocol snd_ff_protocol_ff400; -int snd_ff_transaction_get_clock(struct snd_ff *ff, unsigned int *rate, - enum snd_ff_clock_src *src); int snd_ff_transaction_register(struct snd_ff *ff); int snd_ff_transaction_reregister(struct snd_ff *ff); void snd_ff_transaction_unregister(struct snd_ff *ff); -- cgit v1.2.3 From 22f745871408a58223e2f87e3d4e43d10229e61a Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 20 Jan 2019 17:25:51 +0900 Subject: ALSA: fireface: code refactoring for dump of sync status This commit adds refactoring for dump of sync status by adding tables for check bits. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-protocol-former.c | 176 ++++++++++++--------------- 1 file changed, 75 insertions(+), 101 deletions(-) (limited to 'sound/firewire') diff --git a/sound/firewire/fireface/ff-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c index d32104ed0c08..fb2af10d2690 100644 --- a/sound/firewire/fireface/ff-protocol-former.c +++ b/sound/firewire/fireface/ff-protocol-former.c @@ -190,126 +190,100 @@ static void dump_clock_config(struct snd_ff *ff, struct snd_info_buffer *buffer) static void dump_sync_status(struct snd_ff *ff, struct snd_info_buffer *buffer) { - __le32 reg; - u32 data; + static const struct { + char *const label; + u32 locked_mask; + u32 synced_mask; + } *clk_entry, clk_entries[] = { + { "WDClk", 0x40000000, 0x20000000, }, + { "S/PDIF", 0x00080000, 0x00040000, }, + { "ADAT1", 0x00000400, 0x00001000, }, + { "ADAT2", 0x00000800, 0x00002000, }, + }; + static const struct { + char *const label; + u32 mask; + } *referred_entry, referred_entries[] = { + { "ADAT1", 0x00000000, }, + { "ADAT2", 0x00400000, }, + { "S/PDIF", 0x00c00000, }, + { "WDclk", 0x01000000, }, + { "TCO", 0x01400000, }, + }; + static const struct { + unsigned int rate; + u32 mask; + } *rate_entry, rate_entries[] = { + { 32000, 0x02000000, }, + { 44100, 0x04000000, }, + { 48000, 0x06000000, }, + { 64000, 0x08000000, }, + { 88200, 0x0a000000, }, + { 96000, 0x0c000000, }, + { 128000, 0x0e000000, }, + { 176400, 0x10000000, }, + { 192000, 0x12000000, }, + }; + __le32 reg[2]; + u32 data[2]; + int i; int err; - err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST, - FORMER_REG_SYNC_STATUS, ®, sizeof(reg), 0); + err = snd_fw_transaction(ff->unit, TCODE_READ_BLOCK_REQUEST, + FORMER_REG_SYNC_STATUS, reg, sizeof(reg), 0); if (err < 0) return; - - data = le32_to_cpu(reg); + data[0] = le32_to_cpu(reg[0]); + data[1] = le32_to_cpu(reg[1]); snd_iprintf(buffer, "External source detection:\n"); - snd_iprintf(buffer, "Word Clock:"); - if ((data >> 24) & 0x20) { - if ((data >> 24) & 0x40) - snd_iprintf(buffer, "sync\n"); - else - snd_iprintf(buffer, "lock\n"); - } else { - snd_iprintf(buffer, "none\n"); - } + for (i = 0; i < ARRAY_SIZE(clk_entries); ++i) { + const char *state; + + clk_entry = clk_entries + i; + if (data[0] & clk_entry->locked_mask) { + if (data[0] & clk_entry->synced_mask) + state = "sync"; + else + state = "lock"; + } else { + state = "none"; + } - snd_iprintf(buffer, "S/PDIF:"); - if ((data >> 16) & 0x10) { - if ((data >> 16) & 0x04) - snd_iprintf(buffer, "sync\n"); - else - snd_iprintf(buffer, "lock\n"); - } else { - snd_iprintf(buffer, "none\n"); + snd_iprintf(buffer, "%s: %s\n", clk_entry->label, state); } - snd_iprintf(buffer, "ADAT1:"); - if ((data >> 8) & 0x04) { - if ((data >> 8) & 0x10) - snd_iprintf(buffer, "sync\n"); - else - snd_iprintf(buffer, "lock\n"); - } else { - snd_iprintf(buffer, "none\n"); - } + snd_iprintf(buffer, "Referred clock:\n"); - snd_iprintf(buffer, "ADAT2:"); - if ((data >> 8) & 0x08) { - if ((data >> 8) & 0x20) - snd_iprintf(buffer, "sync\n"); - else - snd_iprintf(buffer, "lock\n"); + if (data[1] & 0x00000001) { + snd_iprintf(buffer, "Internal\n"); } else { - snd_iprintf(buffer, "none\n"); - } + unsigned int rate; + const char *label; - snd_iprintf(buffer, "\nUsed external source:\n"); - - if (((data >> 22) & 0x07) == 0x07) { - snd_iprintf(buffer, "None\n"); - } else { - switch ((data >> 22) & 0x07) { - case 0x00: - snd_iprintf(buffer, "ADAT1:"); - break; - case 0x01: - snd_iprintf(buffer, "ADAT2:"); - break; - case 0x03: - snd_iprintf(buffer, "S/PDIF:"); - break; - case 0x04: - snd_iprintf(buffer, "Word:"); - break; - case 0x07: - snd_iprintf(buffer, "Nothing:"); - break; - case 0x02: - case 0x05: - case 0x06: - default: - snd_iprintf(buffer, "unknown:"); - break; + for (i = 0; i < ARRAY_SIZE(referred_entries); ++i) { + referred_entry = referred_entries + i; + if ((data[0] & 0x1e0000) == referred_entry->mask) { + label = referred_entry->label; + break; + } } + if (i == ARRAY_SIZE(referred_entries)) + label = "none"; - if ((data >> 25) & 0x07) { - switch ((data >> 25) & 0x07) { - case 0x01: - snd_iprintf(buffer, "32000\n"); - break; - case 0x02: - snd_iprintf(buffer, "44100\n"); - break; - case 0x03: - snd_iprintf(buffer, "48000\n"); - break; - case 0x04: - snd_iprintf(buffer, "64000\n"); - break; - case 0x05: - snd_iprintf(buffer, "88200\n"); - break; - case 0x06: - snd_iprintf(buffer, "96000\n"); - break; - case 0x07: - snd_iprintf(buffer, "128000\n"); - break; - case 0x08: - snd_iprintf(buffer, "176400\n"); - break; - case 0x09: - snd_iprintf(buffer, "192000\n"); - break; - case 0x00: - snd_iprintf(buffer, "unknown\n"); + for (i = 0; i < ARRAY_SIZE(rate_entries); ++i) { + rate_entry = rate_entries + i; + if ((data[0] & 0x1e000000) == rate_entry->mask) { + rate = rate_entry->rate; break; } } - } + if (i == ARRAY_SIZE(rate_entries)) + rate = 0; - snd_iprintf(buffer, "Multiplied:"); - snd_iprintf(buffer, "%d\n", (data & 0x3ff) * 250); + snd_iprintf(buffer, "%s %d\n", label, rate); + } } static void former_dump_status(struct snd_ff *ff, -- cgit v1.2.3 From 4c4871a8055a1ff95fbd415d426d7e1d4b763edb Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 20 Jan 2019 17:25:52 +0900 Subject: ALSA: fireface: code refactoring to parse of clock configuration A procedure to retrieve clock configuration is used by two callers. Each of caller has duplicated code to parse bits. This commit adds refactoring to remove the duplicated code. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-proc.c | 17 +++ sound/firewire/fireface/ff-protocol-former.c | 172 +++++++++++---------------- sound/firewire/fireface/ff.h | 1 + 3 files changed, 89 insertions(+), 101 deletions(-) (limited to 'sound/firewire') diff --git a/sound/firewire/fireface/ff-proc.c b/sound/firewire/fireface/ff-proc.c index 8a7cfb6ccce6..a55e68ec1832 100644 --- a/sound/firewire/fireface/ff-proc.c +++ b/sound/firewire/fireface/ff-proc.c @@ -8,6 +8,23 @@ #include "./ff.h" +const char *snd_ff_proc_get_clk_label(enum snd_ff_clock_src src) +{ + static const char *const labels[] = { + "Internal", + "S/PDIF", + "ADAT1", + "ADAT2", + "Word", + "LTC", + }; + + if (src >= ARRAY_SIZE(labels)) + return NULL; + + return labels[src]; +} + static void proc_dump_status(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { diff --git a/sound/firewire/fireface/ff-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c index fb2af10d2690..9c0ae50e88d1 100644 --- a/sound/firewire/fireface/ff-protocol-former.c +++ b/sound/firewire/fireface/ff-protocol-former.c @@ -14,6 +14,62 @@ #define FORMER_REG_FETCH_PCM_FRAMES 0x0000801c0000ull #define FORMER_REG_CLOCK_CONFIG 0x0000801c0004ull +static int parse_clock_bits(u32 data, unsigned int *rate, + enum snd_ff_clock_src *src) +{ + static const struct { + unsigned int rate; + u32 mask; + } *rate_entry, rate_entries[] = { + { 32000, 0x00000002, }, + { 44100, 0x00000000, }, + { 48000, 0x00000006, }, + { 64000, 0x0000000a, }, + { 88200, 0x00000008, }, + { 96000, 0x0000000e, }, + { 128000, 0x00000012, }, + { 176400, 0x00000010, }, + { 192000, 0x00000016, }, + }; + static const struct { + enum snd_ff_clock_src src; + u32 mask; + } *clk_entry, clk_entries[] = { + { SND_FF_CLOCK_SRC_ADAT1, 0x00000000, }, + { SND_FF_CLOCK_SRC_ADAT2, 0x00000400, }, + { SND_FF_CLOCK_SRC_SPDIF, 0x00000c00, }, + { SND_FF_CLOCK_SRC_WORD, 0x00001000, }, + { SND_FF_CLOCK_SRC_LTC, 0x00001800, }, + }; + int i; + + for (i = 0; i < ARRAY_SIZE(rate_entries); ++i) { + rate_entry = rate_entries + i; + if ((data & 0x0000001e) == rate_entry->mask) { + *rate = rate_entry->rate; + break; + } + } + if (i == ARRAY_SIZE(rate_entries)) + return -EIO; + + if (data & 0x00000001) { + *src = SND_FF_CLOCK_SRC_INTERNAL; + } else { + for (i = 0; i < ARRAY_SIZE(clk_entries); ++i) { + clk_entry = clk_entries + i; + if ((data & 0x00001c00) == clk_entry->mask) { + *src = clk_entry->src; + break; + } + } + if (i == ARRAY_SIZE(clk_entries)) + return -EIO; + } + + return 0; +} + static int former_get_clock(struct snd_ff *ff, unsigned int *rate, enum snd_ff_clock_src *src) { @@ -27,54 +83,7 @@ static int former_get_clock(struct snd_ff *ff, unsigned int *rate, return err; data = le32_to_cpu(reg); - /* Calculate sampling rate. */ - switch ((data >> 1) & 0x03) { - case 0x01: - *rate = 32000; - break; - case 0x00: - *rate = 44100; - break; - case 0x03: - *rate = 48000; - break; - case 0x02: - default: - return -EIO; - } - - if (data & 0x08) - *rate *= 2; - else if (data & 0x10) - *rate *= 4; - - /* Calculate source of clock. */ - if (data & 0x01) { - *src = SND_FF_CLOCK_SRC_INTERNAL; - } else { - /* TODO: 0x02, 0x06, 0x07? */ - switch ((data >> 10) & 0x07) { - case 0x00: - *src = SND_FF_CLOCK_SRC_ADAT1; - break; - case 0x01: - *src = SND_FF_CLOCK_SRC_ADAT2; - break; - case 0x03: - *src = SND_FF_CLOCK_SRC_SPDIF; - break; - case 0x04: - *src = SND_FF_CLOCK_SRC_WORD; - break; - case 0x05: - *src = SND_FF_CLOCK_SRC_LTC; - break; - default: - return -EIO; - } - } - - return 0; + return parse_clock_bits(data, rate, src); } static int former_switch_fetching_mode(struct snd_ff *ff, bool enable) @@ -116,76 +125,37 @@ static void dump_clock_config(struct snd_ff *ff, struct snd_info_buffer *buffer) __le32 reg; u32 data; unsigned int rate; - const char *src; + enum snd_ff_clock_src src; + const char *label; int err; err = snd_fw_transaction(ff->unit, TCODE_READ_BLOCK_REQUEST, FORMER_REG_CLOCK_CONFIG, ®, sizeof(reg), 0); if (err < 0) return; - data = le32_to_cpu(reg); snd_iprintf(buffer, "Output S/PDIF format: %s (Emphasis: %s)\n", - (data & 0x20) ? "Professional" : "Consumer", - (data & 0x40) ? "on" : "off"); + (data & 0x00000020) ? "Professional" : "Consumer", + (data & 0x00000040) ? "on" : "off"); snd_iprintf(buffer, "Optical output interface format: %s\n", - ((data >> 8) & 0x01) ? "S/PDIF" : "ADAT"); + (data & 0x00000100) ? "S/PDIF" : "ADAT"); snd_iprintf(buffer, "Word output single speed: %s\n", - ((data >> 8) & 0x20) ? "on" : "off"); + (data & 0x00002000) ? "on" : "off"); snd_iprintf(buffer, "S/PDIF input interface: %s\n", - ((data >> 8) & 0x02) ? "Optical" : "Coaxial"); - - switch ((data >> 1) & 0x03) { - case 0x01: - rate = 32000; - break; - case 0x00: - rate = 44100; - break; - case 0x03: - rate = 48000; - break; - case 0x02: - default: - return; - } - - if (data & 0x08) - rate *= 2; - else if (data & 0x10) - rate *= 4; - - snd_iprintf(buffer, "Sampling rate: %d\n", rate); + (data & 0x00000200) ? "Optical" : "Coaxial"); - if (data & 0x01) { - src = "Internal"; - } else { - switch ((data >> 10) & 0x07) { - case 0x00: - src = "ADAT1"; - break; - case 0x01: - src = "ADAT2"; - break; - case 0x03: - src = "S/PDIF"; - break; - case 0x04: - src = "Word"; - break; - case 0x05: - src = "LTC"; - break; - default: - return; - } - } + err = parse_clock_bits(data, &rate, &src); + if (err < 0) + return; + label = snd_ff_proc_get_clk_label(src); + if (!label) + return; - snd_iprintf(buffer, "Sync to clock source: %s\n", src); + snd_iprintf(buffer, "Clock configuration: %d %s\n", rate, label); } static void dump_sync_status(struct snd_ff *ff, struct snd_info_buffer *buffer) diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h index 1de2f5ec26fd..cdb16e931c31 100644 --- a/sound/firewire/fireface/ff.h +++ b/sound/firewire/fireface/ff.h @@ -139,6 +139,7 @@ int snd_ff_stream_lock_try(struct snd_ff *ff); void snd_ff_stream_lock_release(struct snd_ff *ff); void snd_ff_proc_init(struct snd_ff *ff); +const char *snd_ff_proc_get_clk_label(enum snd_ff_clock_src src); int snd_ff_create_midi_devices(struct snd_ff *ff); -- cgit v1.2.3 From fd1cc9de64c2ca6c2b5b9061421580a22bfac023 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 20 Jan 2019 17:25:53 +0900 Subject: ALSA: fireface: add support for Fireface UCX Fireface UFX was shipped by RME GmbH in 2012. This model supports later protocol for management of isochronous communication and synchronization of sampling transmission frequency. This commit adds support for the model. At present, it's not clear how to encode MIDI messages and decide destination address for asynchronous transaction, thus this commit adds support for isochronous communication for PCM frames only. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/Kconfig | 1 + sound/firewire/fireface/Makefile | 3 +- sound/firewire/fireface/ff-protocol-latter.c | 273 +++++++++++++++++++++++++++ sound/firewire/fireface/ff.c | 41 +++- sound/firewire/fireface/ff.h | 1 + 5 files changed, 310 insertions(+), 9 deletions(-) create mode 100644 sound/firewire/fireface/ff-protocol-latter.c (limited to 'sound/firewire') diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig index 052e00590259..b9e96d0b3a0a 100644 --- a/sound/firewire/Kconfig +++ b/sound/firewire/Kconfig @@ -163,5 +163,6 @@ config SND_FIREFACE Say Y here to include support for RME fireface series. * Fireface 400 * Fireface 800 + * Fireface UCX endif # SND_FIREWIRE diff --git a/sound/firewire/fireface/Makefile b/sound/firewire/fireface/Makefile index 62eb78962b93..d64f4e2a1096 100644 --- a/sound/firewire/fireface/Makefile +++ b/sound/firewire/fireface/Makefile @@ -1,3 +1,4 @@ snd-fireface-objs := ff.o ff-transaction.o ff-midi.o ff-proc.o amdtp-ff.o \ - ff-stream.o ff-pcm.o ff-hwdep.o ff-protocol-former.o + ff-stream.o ff-pcm.o ff-hwdep.o ff-protocol-former.o \ + ff-protocol-latter.o obj-$(CONFIG_SND_FIREFACE) += snd-fireface.o diff --git a/sound/firewire/fireface/ff-protocol-latter.c b/sound/firewire/fireface/ff-protocol-latter.c new file mode 100644 index 000000000000..64767ba439db --- /dev/null +++ b/sound/firewire/fireface/ff-protocol-latter.c @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: GPL-2.0 +// ff-protocol-latter - a part of driver for RME Fireface series +// +// Copyright (c) 2019 Takashi Sakamoto +// +// Licensed under the terms of the GNU General Public License, version 2. + +#include + +#include "ff.h" + +#define LATTER_STF 0xffff00000004 +#define LATTER_ISOC_CHANNELS 0xffff00000008 +#define LATTER_ISOC_START 0xffff0000000c +#define LATTER_FETCH_MODE 0xffff00000010 +#define LATTER_SYNC_STATUS 0x0000801c0000 + +static int parse_clock_bits(u32 data, unsigned int *rate, + enum snd_ff_clock_src *src) +{ + static const struct { + unsigned int rate; + u32 flag; + } *rate_entry, rate_entries[] = { + { 32000, 0x00000000, }, + { 44100, 0x01000000, }, + { 48000, 0x02000000, }, + { 64000, 0x04000000, }, + { 88200, 0x05000000, }, + { 96000, 0x06000000, }, + { 128000, 0x08000000, }, + { 176400, 0x09000000, }, + { 192000, 0x0a000000, }, + }; + static const struct { + enum snd_ff_clock_src src; + u32 flag; + } *clk_entry, clk_entries[] = { + { SND_FF_CLOCK_SRC_SPDIF, 0x00000200, }, + { SND_FF_CLOCK_SRC_ADAT1, 0x00000400, }, + { SND_FF_CLOCK_SRC_WORD, 0x00000600, }, + { SND_FF_CLOCK_SRC_INTERNAL, 0x00000e00, }, + }; + int i; + + for (i = 0; i < ARRAY_SIZE(rate_entries); ++i) { + rate_entry = rate_entries + i; + if ((data & 0x0f000000) == rate_entry->flag) { + *rate = rate_entry->rate; + break; + } + } + if (i == ARRAY_SIZE(rate_entries)) + return -EIO; + + for (i = 0; i < ARRAY_SIZE(clk_entries); ++i) { + clk_entry = clk_entries + i; + if ((data & 0x000e00) == clk_entry->flag) { + *src = clk_entry->src; + break; + } + } + if (i == ARRAY_SIZE(clk_entries)) + return -EIO; + + return 0; +} + +static int latter_get_clock(struct snd_ff *ff, unsigned int *rate, + enum snd_ff_clock_src *src) +{ + __le32 reg; + u32 data; + int err; + + err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST, + LATTER_SYNC_STATUS, ®, sizeof(reg), 0); + if (err < 0) + return err; + data = le32_to_cpu(reg); + + return parse_clock_bits(data, rate, src); +} + +static int latter_switch_fetching_mode(struct snd_ff *ff, bool enable) +{ + u32 data; + __le32 reg; + + if (enable) + data = 0x00000000; + else + data = 0xffffffff; + reg = cpu_to_le32(data); + + return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, + LATTER_FETCH_MODE, ®, sizeof(reg), 0); +} + +static int keep_resources(struct snd_ff *ff, unsigned int rate) +{ + enum snd_ff_stream_mode mode; + int i; + int err; + + // Check whether the given value is supported or not. + for (i = 0; i < CIP_SFC_COUNT; i++) { + if (amdtp_rate_table[i] == rate) + break; + } + if (i >= CIP_SFC_COUNT) + return -EINVAL; + + err = snd_ff_stream_get_multiplier_mode(i, &mode); + if (err < 0) + return err; + + /* Keep resources for in-stream. */ + ff->tx_resources.channels_mask = 0x00000000000000ffuLL; + err = fw_iso_resources_allocate(&ff->tx_resources, + amdtp_stream_get_max_payload(&ff->tx_stream), + fw_parent_device(ff->unit)->max_speed); + if (err < 0) + return err; + + /* Keep resources for out-stream. */ + ff->rx_resources.channels_mask = 0x00000000000000ffuLL; + 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) + fw_iso_resources_free(&ff->tx_resources); + + return err; +} + +static int latter_begin_session(struct snd_ff *ff, unsigned int rate) +{ + static const struct { + unsigned int stf; + unsigned int code; + unsigned int flag; + } *entry, rate_table[] = { + { 32000, 0x00, 0x92, }, + { 44100, 0x02, 0x92, }, + { 48000, 0x04, 0x92, }, + { 64000, 0x08, 0x8e, }, + { 88200, 0x0a, 0x8e, }, + { 96000, 0x0c, 0x8e, }, + { 128000, 0x10, 0x8c, }, + { 176400, 0x12, 0x8c, }, + { 192000, 0x14, 0x8c, }, + }; + u32 data; + __le32 reg; + unsigned int count; + int i; + int err; + + for (i = 0; i < ARRAY_SIZE(rate_table); ++i) { + entry = rate_table + i; + if (entry->stf == rate) + break; + } + if (i == ARRAY_SIZE(rate_table)) + return -EINVAL; + + reg = cpu_to_le32(entry->code); + err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, + LATTER_STF, ®, sizeof(reg), 0); + if (err < 0) + return err; + + // Confirm to shift transmission clock. + count = 0; + while (count++ < 10) { + unsigned int curr_rate; + enum snd_ff_clock_src src; + + err = latter_get_clock(ff, &curr_rate, &src); + if (err < 0) + return err; + + if (curr_rate == rate) + break; + } + if (count == 10) + return -ETIMEDOUT; + + err = keep_resources(ff, rate); + if (err < 0) + return err; + + data = (ff->tx_resources.channel << 8) | ff->rx_resources.channel; + reg = cpu_to_le32(data); + err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, + LATTER_ISOC_CHANNELS, ®, sizeof(reg), 0); + if (err < 0) + return err; + + // Always use the maximum number of data channels in data block of + // packet. + reg = cpu_to_le32(entry->flag); + return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, + LATTER_ISOC_START, ®, sizeof(reg), 0); +} + +static void latter_finish_session(struct snd_ff *ff) +{ + __le32 reg; + + reg = cpu_to_le32(0x00000000); + snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST, + LATTER_ISOC_START, ®, sizeof(reg), 0); +} + +static void latter_dump_status(struct snd_ff *ff, struct snd_info_buffer *buffer) +{ + static const struct { + char *const label; + u32 locked_mask; + u32 synced_mask; + } *clk_entry, clk_entries[] = { + { "S/PDIF", 0x00000001, 0x00000010, }, + { "ADAT", 0x00000002, 0x00000020, }, + { "WDClk", 0x00000004, 0x00000040, }, + }; + __le32 reg; + u32 data; + unsigned int rate; + enum snd_ff_clock_src src; + const char *label; + int i; + int err; + + err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST, + LATTER_SYNC_STATUS, ®, sizeof(reg), 0); + if (err < 0) + return; + data = le32_to_cpu(reg); + + snd_iprintf(buffer, "External source detection:\n"); + + for (i = 0; i < ARRAY_SIZE(clk_entries); ++i) { + clk_entry = clk_entries + i; + snd_iprintf(buffer, "%s: ", clk_entry->label); + if (data & clk_entry->locked_mask) { + if (data & clk_entry->synced_mask) + snd_iprintf(buffer, "sync\n"); + else + snd_iprintf(buffer, "lock\n"); + } else { + snd_iprintf(buffer, "none\n"); + } + } + + err = parse_clock_bits(data, &rate, &src); + if (err < 0) + return; + label = snd_ff_proc_get_clk_label(src); + if (!label) + return; + + snd_iprintf(buffer, "Referred clock: %s %d\n", label, rate); +} + +const struct snd_ff_protocol snd_ff_protocol_latter = { + .get_clock = latter_get_clock, + .switch_fetching_mode = latter_switch_fetching_mode, + .begin_session = latter_begin_session, + .finish_session = latter_finish_session, + .dump_status = latter_dump_status, +}; diff --git a/sound/firewire/fireface/ff.c b/sound/firewire/fireface/ff.c index 36575f4159d1..fd9c980e3cf4 100644 --- a/sound/firewire/fireface/ff.c +++ b/sound/firewire/fireface/ff.c @@ -32,7 +32,8 @@ static void ff_card_free(struct snd_card *card) struct snd_ff *ff = card->private_data; snd_ff_stream_destroy_duplex(ff); - snd_ff_transaction_unregister(ff); + if (ff->spec->midi_high_addr > 0) + snd_ff_transaction_unregister(ff); } static void do_registration(struct work_struct *work) @@ -50,9 +51,11 @@ static void do_registration(struct work_struct *work) ff->card->private_free = ff_card_free; ff->card->private_data = ff; - err = snd_ff_transaction_register(ff); - if (err < 0) - goto error; + if (ff->spec->midi_high_addr > 0) { + err = snd_ff_transaction_register(ff); + if (err < 0) + goto error; + } name_card(ff); @@ -62,9 +65,11 @@ static void do_registration(struct work_struct *work) snd_ff_proc_init(ff); - err = snd_ff_create_midi_devices(ff); - if (err < 0) - goto error; + if (ff->spec->midi_in_ports > 0 || ff->spec->midi_out_ports > 0) { + err = snd_ff_create_midi_devices(ff); + if (err < 0) + goto error; + } err = snd_ff_create_pcm_devices(ff); if (err < 0) @@ -119,7 +124,8 @@ static void snd_ff_update(struct fw_unit *unit) if (!ff->registered) snd_fw_schedule_registration(unit, &ff->dwork); - snd_ff_transaction_reregister(ff); + if (ff->spec->midi_high_addr > 0) + snd_ff_transaction_reregister(ff); if (ff->registered) snd_ff_stream_update_duplex(ff); @@ -165,6 +171,13 @@ static const struct snd_ff_spec spec_ff400 = { .midi_high_addr = 0x0000801003f4ull, }; +static const struct snd_ff_spec spec_ucx = { + .name = "FirefaceUCX", + .pcm_capture_channels = {18, 14, 12}, + .pcm_playback_channels = {18, 14, 12}, + .protocol = &snd_ff_protocol_latter, +}; + static const struct ieee1394_device_id snd_ff_id_table[] = { /* Fireface 800 */ { @@ -190,6 +203,18 @@ static const struct ieee1394_device_id snd_ff_id_table[] = { .model_id = 0x101800, .driver_data = (kernel_ulong_t)&spec_ff400, }, + // Fireface UCX. + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | + IEEE1394_MATCH_SPECIFIER_ID | + IEEE1394_MATCH_VERSION | + IEEE1394_MATCH_MODEL_ID, + .vendor_id = OUI_RME, + .specifier_id = OUI_RME, + .version = 0x000004, + .model_id = 0x101800, + .driver_data = (kernel_ulong_t)&spec_ucx, + }, {} }; MODULE_DEVICE_TABLE(ieee1394, snd_ff_id_table); diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h index cdb16e931c31..8aea7920b57f 100644 --- a/sound/firewire/fireface/ff.h +++ b/sound/firewire/fireface/ff.h @@ -114,6 +114,7 @@ struct snd_ff_protocol { extern const struct snd_ff_protocol snd_ff_protocol_ff800; extern const struct snd_ff_protocol snd_ff_protocol_ff400; +extern const struct snd_ff_protocol snd_ff_protocol_latter; int snd_ff_transaction_register(struct snd_ff *ff); int snd_ff_transaction_reregister(struct snd_ff *ff); -- cgit v1.2.3 From 6c644e4e954ddae26880d82e7aa4f551662cdae3 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 22 Jan 2019 22:17:00 +0900 Subject: ALSA: fireface: change prototype of handler for async transaction with MIDI messages In a series of Fireface, devices transfer asynchronous transaction with MIDI messages. In the transaction, content is different depending on models. ALSA fireface driver has protocol-dependent handler to pick up MIDI messages from the content. In latter models of the series, the transaction is transferred to range of address sequentially. This seems to check continuity of transferred messages. This commit changes prototype of the handler to receive offset of address for received transactions. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-protocol-former.c | 6 ++++-- sound/firewire/fireface/ff-transaction.c | 4 +++- sound/firewire/fireface/ff.h | 3 ++- 3 files changed, 9 insertions(+), 4 deletions(-) (limited to 'sound/firewire') diff --git a/sound/firewire/fireface/ff-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c index 9c0ae50e88d1..266e4892a818 100644 --- a/sound/firewire/fireface/ff-protocol-former.c +++ b/sound/firewire/fireface/ff-protocol-former.c @@ -375,7 +375,8 @@ static void ff800_finish_session(struct snd_ff *ff) FF800_ISOC_COMM_STOP, ®, sizeof(reg), 0); } -static void ff800_handle_midi_msg(struct snd_ff *ff, __le32 *buf, size_t length) +static void ff800_handle_midi_msg(struct snd_ff *ff, unsigned int offset, + __le32 *buf, size_t length) { int i; @@ -502,7 +503,8 @@ static void ff400_finish_session(struct snd_ff *ff) FF400_ISOC_COMM_STOP, ®, sizeof(reg), 0); } -static void ff400_handle_midi_msg(struct snd_ff *ff, __le32 *buf, size_t length) +static void ff400_handle_midi_msg(struct snd_ff *ff, unsigned int offset, + __le32 *buf, size_t length) { int i; diff --git a/sound/firewire/fireface/ff-transaction.c b/sound/firewire/fireface/ff-transaction.c index 065e045d3fb5..d3fde813ce17 100644 --- a/sound/firewire/fireface/ff-transaction.c +++ b/sound/firewire/fireface/ff-transaction.c @@ -146,7 +146,9 @@ static void handle_midi_msg(struct fw_card *card, struct fw_request *request, fw_send_response(card, request, RCODE_COMPLETE); - ff->spec->protocol->handle_midi_msg(ff, buf, length); + offset -= ff->async_handler.offset; + ff->spec->protocol->handle_midi_msg(ff, (unsigned int)offset, buf, + length); } static int allocate_own_address(struct snd_ff *ff, int i) diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h index 8aea7920b57f..ddcffb8d85c6 100644 --- a/sound/firewire/fireface/ff.h +++ b/sound/firewire/fireface/ff.h @@ -103,7 +103,8 @@ enum snd_ff_clock_src { }; struct snd_ff_protocol { - void (*handle_midi_msg)(struct snd_ff *ff, __le32 *buf, size_t length); + void (*handle_midi_msg)(struct snd_ff *ff, unsigned int offset, + __le32 *buf, size_t length); int (*get_clock)(struct snd_ff *ff, unsigned int *rate, enum snd_ff_clock_src *src); int (*switch_fetching_mode)(struct snd_ff *ff, bool enable); -- cgit v1.2.3 From 900896771a2f7ba126194911c58dc095fc0dd3d7 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 22 Jan 2019 22:17:01 +0900 Subject: ALSA: fireface: add model-dependent parameter for address range to receive async transaction In Fireface series, drivers can register destination address for asynchronous transaction which transfers MIDI messages from device. In former models, all of the transactions arrive at the registered address without any offset. In latter models, each of the transaction arrives at the registered address with sequential offset within 0x00 to 0x7f. This seems to be for discontinuity detection. This commit adds model-dependent member for the address range. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-transaction.c | 2 +- sound/firewire/fireface/ff.c | 2 ++ sound/firewire/fireface/ff.h | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) (limited to 'sound/firewire') diff --git a/sound/firewire/fireface/ff-transaction.c b/sound/firewire/fireface/ff-transaction.c index d3fde813ce17..0506755891ce 100644 --- a/sound/firewire/fireface/ff-transaction.c +++ b/sound/firewire/fireface/ff-transaction.c @@ -156,7 +156,7 @@ static int allocate_own_address(struct snd_ff *ff, int i) struct fw_address_region midi_msg_region; int err; - ff->async_handler.length = SND_FF_MAXIMIM_MIDI_QUADS * 4; + ff->async_handler.length = ff->spec->midi_addr_range; ff->async_handler.address_callback = handle_midi_msg; ff->async_handler.callback_data = ff; diff --git a/sound/firewire/fireface/ff.c b/sound/firewire/fireface/ff.c index fd9c980e3cf4..c09a4875aa86 100644 --- a/sound/firewire/fireface/ff.c +++ b/sound/firewire/fireface/ff.c @@ -159,6 +159,7 @@ static const struct snd_ff_spec spec_ff800 = { .midi_out_ports = 1, .protocol = &snd_ff_protocol_ff800, .midi_high_addr = 0x000200000320ull, + .midi_addr_range = 12, }; static const struct snd_ff_spec spec_ff400 = { @@ -169,6 +170,7 @@ static const struct snd_ff_spec spec_ff400 = { .midi_out_ports = 2, .protocol = &snd_ff_protocol_ff400, .midi_high_addr = 0x0000801003f4ull, + .midi_addr_range = SND_FF_MAXIMIM_MIDI_QUADS * 4, }; static const struct snd_ff_spec spec_ucx = { diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h index ddcffb8d85c6..b86ca4fb7d9b 100644 --- a/sound/firewire/fireface/ff.h +++ b/sound/firewire/fireface/ff.h @@ -54,6 +54,7 @@ struct snd_ff_spec { const struct snd_ff_protocol *protocol; u64 midi_high_addr; + u8 midi_addr_range; }; struct snd_ff { -- cgit v1.2.3 From 73f5537fb209e8dcd503c9ce140baa7e892fb65e Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 22 Jan 2019 22:17:02 +0900 Subject: ALSA: fireface: support tx MIDI functionality of Fireface UCX Fireface UCX transfers asynchronous transactions for MIDI messages. One transaction includes quadlet data therefore it can transfer 3 message bytes as maximum. Base address of the destination is configured by two settings; a register for higher 8 byte of the address, and a bitflag to option register indicates lower 8byte. The register for higher address is 0x'ffff'0000'0034. Unfortunately, firmware v24 includes a bug to ignore registered value for the destination address and transfers to 0x0001xxxxxxxx always. This driver doesn't work well if the bug exists, therefore users should install the latest firmware (v27). The bitflag is a part of value to be written to option register (0x'ffff'0000'0014). lower addr: bitflag (little endian) '0000'0000: 0x00002000 '0000'0080: 0x00004000 '0000'0100: 0x00008000 '0000'0180: 0x00010000 This register includes more options but they are not relevant to packet streaming or MIDI functionality. This driver don't touch it. Furthermore, the transaction is sent to address offset incremented by 4 byte to the offset in previous time. When it reaches base address plus 0x7c, next offset is the base address. Content of the transaction includes a prefix byte. Upper 4 bits of the byte indicates port number, and the rest 4 bits indicate the way to decode rest of bytes for MIDI message. Except for system exclusive messages, the rest bits are the same as status bits of the message without channel bits. For system exclusive messages, the rest bits are encoded according to included message bytes. For example: message: f0 7e 7f 09 01 f7 offset: content (little endian, port 0) '0000: 0x04f07e7f '0004: 0x070901f7 message: f0 00 00 66 14 20 00 00 00 f7 offset: content (little endian, port 1) '0014: 0x14f00000 '0018: 0x14661420 '001c: 0x14000000 '0020: 0x15f70000 message: f0 00 00 66 14 20 00 00 f7 offset: content (little endian, port 0) '0078: 0x04f00000 '007c: 0x04661420 '0000: 0x070000f7 This commit supports decoding scheme for the above and allows applications to receive MIDI messages via ALSA rawmidi interface. The lower 8 bytes of destination address is fixed to 0x'0000'0000, thus this driver expects userspace applications to configure option register with bitflag 0x00002000 in advance. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-protocol-latter.c | 43 ++++++++++++++++++++++++++++ sound/firewire/fireface/ff.c | 25 +++++++--------- 2 files changed, 54 insertions(+), 14 deletions(-) (limited to 'sound/firewire') diff --git a/sound/firewire/fireface/ff-protocol-latter.c b/sound/firewire/fireface/ff-protocol-latter.c index 64767ba439db..a812ab6feb58 100644 --- a/sound/firewire/fireface/ff-protocol-latter.c +++ b/sound/firewire/fireface/ff-protocol-latter.c @@ -264,7 +264,50 @@ static void latter_dump_status(struct snd_ff *ff, struct snd_info_buffer *buffer snd_iprintf(buffer, "Referred clock: %s %d\n", label, rate); } +// NOTE: transactions are transferred within 0x00-0x7f in allocated range of +// address. This seems to be for check of discontinuity in receiver side. +static void latter_handle_midi_msg(struct snd_ff *ff, unsigned int offset, + __le32 *buf, size_t length) +{ + u32 data = le32_to_cpu(*buf); + unsigned int index = (data & 0x000000f0) >> 4; + u8 byte[3]; + struct snd_rawmidi_substream *substream; + unsigned int len; + + if (index > ff->spec->midi_in_ports) + return; + + switch (data & 0x0000000f) { + case 0x00000008: + case 0x00000009: + case 0x0000000a: + case 0x0000000b: + case 0x0000000e: + len = 3; + break; + case 0x0000000c: + case 0x0000000d: + len = 2; + break; + default: + len = data & 0x00000003; + if (len == 0) + len = 3; + break; + } + + byte[0] = (data & 0x0000ff00) >> 8; + byte[1] = (data & 0x00ff0000) >> 16; + byte[2] = (data & 0xff000000) >> 24; + + substream = READ_ONCE(ff->tx_midi_substreams[index]); + if (substream) + snd_rawmidi_receive(substream, byte, len); +} + const struct snd_ff_protocol snd_ff_protocol_latter = { + .handle_midi_msg = latter_handle_midi_msg, .get_clock = latter_get_clock, .switch_fetching_mode = latter_switch_fetching_mode, .begin_session = latter_begin_session, diff --git a/sound/firewire/fireface/ff.c b/sound/firewire/fireface/ff.c index c09a4875aa86..a2a9fd82f27d 100644 --- a/sound/firewire/fireface/ff.c +++ b/sound/firewire/fireface/ff.c @@ -32,8 +32,7 @@ static void ff_card_free(struct snd_card *card) struct snd_ff *ff = card->private_data; snd_ff_stream_destroy_duplex(ff); - if (ff->spec->midi_high_addr > 0) - snd_ff_transaction_unregister(ff); + snd_ff_transaction_unregister(ff); } static void do_registration(struct work_struct *work) @@ -51,11 +50,9 @@ static void do_registration(struct work_struct *work) ff->card->private_free = ff_card_free; ff->card->private_data = ff; - if (ff->spec->midi_high_addr > 0) { - err = snd_ff_transaction_register(ff); - if (err < 0) - goto error; - } + err = snd_ff_transaction_register(ff); + if (err < 0) + goto error; name_card(ff); @@ -65,11 +62,9 @@ static void do_registration(struct work_struct *work) snd_ff_proc_init(ff); - if (ff->spec->midi_in_ports > 0 || ff->spec->midi_out_ports > 0) { - err = snd_ff_create_midi_devices(ff); - if (err < 0) - goto error; - } + err = snd_ff_create_midi_devices(ff); + if (err < 0) + goto error; err = snd_ff_create_pcm_devices(ff); if (err < 0) @@ -124,8 +119,7 @@ static void snd_ff_update(struct fw_unit *unit) if (!ff->registered) snd_fw_schedule_registration(unit, &ff->dwork); - if (ff->spec->midi_high_addr > 0) - snd_ff_transaction_reregister(ff); + snd_ff_transaction_reregister(ff); if (ff->registered) snd_ff_stream_update_duplex(ff); @@ -177,7 +171,10 @@ static const struct snd_ff_spec spec_ucx = { .name = "FirefaceUCX", .pcm_capture_channels = {18, 14, 12}, .pcm_playback_channels = {18, 14, 12}, + .midi_in_ports = 2, .protocol = &snd_ff_protocol_latter, + .midi_high_addr = 0xffff00000034ull, + .midi_addr_range = 0x80, }; static const struct ieee1394_device_id snd_ff_id_table[] = { -- cgit v1.2.3 From 481e09ac9a82644af697884cc522b76b4dd07e4d Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 22 Jan 2019 22:17:03 +0900 Subject: ALSA: fireface: add model-dependent parameter for address to receive async transaction for MIDI messages Between former and latter models, destination address to receive asynchronous transactions for MIDI messages is different. This commit adds model-dependent parameter for the addresses. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-transaction.c | 7 ++----- sound/firewire/fireface/ff.c | 3 +++ sound/firewire/fireface/ff.h | 1 + 3 files changed, 6 insertions(+), 5 deletions(-) (limited to 'sound/firewire') diff --git a/sound/firewire/fireface/ff-transaction.c b/sound/firewire/fireface/ff-transaction.c index 0506755891ce..92ca76ab7537 100644 --- a/sound/firewire/fireface/ff-transaction.c +++ b/sound/firewire/fireface/ff-transaction.c @@ -8,9 +8,6 @@ #include "ff.h" -#define SND_FF_REG_MIDI_RX_PORT_0 0x000080180000ull -#define SND_FF_REG_MIDI_RX_PORT_1 0x000080190000ull - static void finish_transmit_midi_msg(struct snd_ff *ff, unsigned int port, int rcode) { @@ -93,10 +90,10 @@ static void transmit_midi_msg(struct snd_ff *ff, unsigned int port) fill_midi_buf(ff, port, i, buf[i]); if (port == 0) { - addr = SND_FF_REG_MIDI_RX_PORT_0; + addr = ff->spec->midi_rx_addrs[0]; callback = finish_transmit_midi0_msg; } else { - addr = SND_FF_REG_MIDI_RX_PORT_1; + addr = ff->spec->midi_rx_addrs[1]; callback = finish_transmit_midi1_msg; } diff --git a/sound/firewire/fireface/ff.c b/sound/firewire/fireface/ff.c index a2a9fd82f27d..675c6ab556eb 100644 --- a/sound/firewire/fireface/ff.c +++ b/sound/firewire/fireface/ff.c @@ -154,6 +154,7 @@ static const struct snd_ff_spec spec_ff800 = { .protocol = &snd_ff_protocol_ff800, .midi_high_addr = 0x000200000320ull, .midi_addr_range = 12, + .midi_rx_addrs = {0x000080180000ull, 0}, }; static const struct snd_ff_spec spec_ff400 = { @@ -165,6 +166,7 @@ static const struct snd_ff_spec spec_ff400 = { .protocol = &snd_ff_protocol_ff400, .midi_high_addr = 0x0000801003f4ull, .midi_addr_range = SND_FF_MAXIMIM_MIDI_QUADS * 4, + .midi_rx_addrs = {0x000080180000ull, 0x000080190000ull}, }; static const struct snd_ff_spec spec_ucx = { @@ -175,6 +177,7 @@ static const struct snd_ff_spec spec_ucx = { .protocol = &snd_ff_protocol_latter, .midi_high_addr = 0xffff00000034ull, .midi_addr_range = 0x80, + .midi_rx_addrs = {0xffff00000030ull, 0xffff00000030ull}, }; static const struct ieee1394_device_id snd_ff_id_table[] = { diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h index b86ca4fb7d9b..edad75a4b260 100644 --- a/sound/firewire/fireface/ff.h +++ b/sound/firewire/fireface/ff.h @@ -55,6 +55,7 @@ struct snd_ff_spec { const struct snd_ff_protocol *protocol; u64 midi_high_addr; u8 midi_addr_range; + u64 midi_rx_addrs[SND_FF_OUT_MIDI_PORTS]; }; struct snd_ff { -- cgit v1.2.3 From 82b6297b4434d1bc523f3470be4875ab185c6663 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 22 Jan 2019 22:17:04 +0900 Subject: ALSA: fireface: add protocol-specific operation to fill transaction buffer with MIDI messages Between former and latter models, content of asynchronous transaction for MIDI messages from driver to device is different. This commit is a preparation to support latter models. A protocol-specific operation is added to encode MIDI messages to the transaction. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-protocol-former.c | 23 +++++++++++++++++++++ sound/firewire/fireface/ff-transaction.c | 31 +++++++++++----------------- sound/firewire/fireface/ff.h | 3 +++ 3 files changed, 38 insertions(+), 19 deletions(-) (limited to 'sound/firewire') diff --git a/sound/firewire/fireface/ff-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c index 266e4892a818..e0acf40a02ee 100644 --- a/sound/firewire/fireface/ff-protocol-former.c +++ b/sound/firewire/fireface/ff-protocol-former.c @@ -263,6 +263,27 @@ static void former_dump_status(struct snd_ff *ff, dump_sync_status(ff, buffer); } +static int former_fill_midi_msg(struct snd_ff *ff, + struct snd_rawmidi_substream *substream, + unsigned int port) +{ + u8 *buf = (u8 *)ff->msg_buf[port]; + int len; + int i; + + len = snd_rawmidi_transmit_peek(substream, buf, + SND_FF_MAXIMIM_MIDI_QUADS); + if (len <= 0) + return len; + + // One quadlet includes one byte. + for (i = len - 1; i >= 0; --i) + ff->msg_buf[port][i] = cpu_to_le32(buf[i]); + ff->rx_bytes[port] = len; + + return len; +} + #define FF800_STF 0x0000fc88f000 #define FF800_RX_PACKET_FORMAT 0x0000fc88f004 #define FF800_ALLOC_TX_STREAM 0x0000fc88f008 @@ -392,6 +413,7 @@ static void ff800_handle_midi_msg(struct snd_ff *ff, unsigned int offset, const struct snd_ff_protocol snd_ff_protocol_ff800 = { .handle_midi_msg = ff800_handle_midi_msg, + .fill_midi_msg = former_fill_midi_msg, .get_clock = former_get_clock, .switch_fetching_mode = former_switch_fetching_mode, .begin_session = ff800_begin_session, @@ -543,6 +565,7 @@ static void ff400_handle_midi_msg(struct snd_ff *ff, unsigned int offset, const struct snd_ff_protocol snd_ff_protocol_ff400 = { .handle_midi_msg = ff400_handle_midi_msg, + .fill_midi_msg = former_fill_midi_msg, .get_clock = former_get_clock, .switch_fetching_mode = former_switch_fetching_mode, .begin_session = ff400_begin_session, diff --git a/sound/firewire/fireface/ff-transaction.c b/sound/firewire/fireface/ff-transaction.c index 92ca76ab7537..d8a8b01b39a1 100644 --- a/sound/firewire/fireface/ff-transaction.c +++ b/sound/firewire/fireface/ff-transaction.c @@ -51,23 +51,17 @@ static void finish_transmit_midi1_msg(struct fw_card *card, int rcode, finish_transmit_midi_msg(ff, 1, rcode); } -static inline void fill_midi_buf(struct snd_ff *ff, unsigned int port, - unsigned int index, u8 byte) -{ - ff->msg_buf[port][index] = cpu_to_le32(byte); -} - static void transmit_midi_msg(struct snd_ff *ff, unsigned int port) { struct snd_rawmidi_substream *substream = READ_ONCE(ff->rx_midi_substreams[port]); - u8 *buf = (u8 *)ff->msg_buf[port]; - int i, len; + int quad_count; struct fw_device *fw_dev = fw_parent_device(ff->unit); unsigned long long addr; int generation; fw_transaction_callback_t callback; + int tcode; if (substream == NULL || snd_rawmidi_transmit_empty(substream)) return; @@ -81,14 +75,10 @@ static void transmit_midi_msg(struct snd_ff *ff, unsigned int port) return; } - len = snd_rawmidi_transmit_peek(substream, buf, - SND_FF_MAXIMIM_MIDI_QUADS); - if (len <= 0) + quad_count = ff->spec->protocol->fill_midi_msg(ff, substream, port); + if (quad_count <= 0) return; - for (i = len - 1; i >= 0; i--) - fill_midi_buf(ff, port, i, buf[i]); - if (port == 0) { addr = ff->spec->midi_rx_addrs[0]; callback = finish_transmit_midi0_msg; @@ -99,8 +89,12 @@ static void transmit_midi_msg(struct snd_ff *ff, unsigned int port) /* Set interval to next transaction. */ ff->next_ktime[port] = ktime_add_ns(ktime_get(), - len * 8 * NSEC_PER_SEC / 31250); - ff->rx_bytes[port] = len; + ff->rx_bytes[port] * 8 * NSEC_PER_SEC / 31250); + + if (quad_count == 1) + tcode = TCODE_WRITE_QUADLET_REQUEST; + else + tcode = TCODE_WRITE_BLOCK_REQUEST; /* * In Linux FireWire core, when generation is updated with memory @@ -112,10 +106,9 @@ static void transmit_midi_msg(struct snd_ff *ff, unsigned int port) */ generation = fw_dev->generation; smp_rmb(); - fw_send_request(fw_dev->card, &ff->transactions[port], - TCODE_WRITE_BLOCK_REQUEST, + fw_send_request(fw_dev->card, &ff->transactions[port], tcode, fw_dev->node_id, generation, fw_dev->max_speed, - addr, &ff->msg_buf[port], len * 4, + addr, &ff->msg_buf[port], quad_count * 4, callback, &ff->transactions[port]); } diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h index edad75a4b260..e52ad11803e0 100644 --- a/sound/firewire/fireface/ff.h +++ b/sound/firewire/fireface/ff.h @@ -107,6 +107,9 @@ enum snd_ff_clock_src { struct snd_ff_protocol { void (*handle_midi_msg)(struct snd_ff *ff, unsigned int offset, __le32 *buf, size_t length); + int (*fill_midi_msg)(struct snd_ff *ff, + struct snd_rawmidi_substream *substream, + unsigned int port); int (*get_clock)(struct snd_ff *ff, unsigned int *rate, enum snd_ff_clock_src *src); int (*switch_fetching_mode)(struct snd_ff *ff, bool enable); -- cgit v1.2.3 From f0f9f497d44e2f696b4e16c41f3eaa13a009f22d Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 22 Jan 2019 22:17:05 +0900 Subject: ALSA: fireface: support rx MIDI functionality for Fireface UCX In latter model of Fireface series, asynchronous transaction includes a prefix byte to indicate the way to decode included MIDI bytes. Upper 4 bits of the prefix byte indicates port number, and the rest 4 bits indicate the way to decode rest of bytes for MIDI messages. Basically the rest bits indicates the number of bytes for MIDI message. However, if the last byte of each MIDi message is included, the rest bits are 0xf. For example: message: f0 00 00 66 14 20 00 00 f7 offset: content (big endian, port 0) '0030: 0x02f00000 '0030: 0x03006614 '0030: 0x03200000 '0030: 0x0ff70000 This commit supports encoding scheme for the above and allows applications to transfer MIDI messages via ALSA rawmidi interface. An unused member (running_status) is reused to keep state of transmission of system exclusive messages. For your information, this is a dump of config rom. $ sudo ./hinawa-config-rom-printer /dev/fw1 { 'bus-info': { 'bmc': False, 'chip_ID': 13225063715, 'cmc': False, 'cyc_clk_acc': 0, 'imc': False, 'isc': True, 'max_rec': 512, 'name': '1394', 'node_vendor_ID': 2613}, 'root-directory': [ [ 'NODE_CAPABILITIES', { 'addressing': {'64': True, 'fix': True, 'prv': False}, 'misc': {'int': False, 'ms': False, 'spt': True}, 'state': { 'atn': False, 'ded': False, 'drq': True, 'elo': False, 'init': False, 'lst': True, 'off': False}, 'testing': {'bas': False, 'ext': False}}], ['VENDOR', 2613], ['DESCRIPTOR', 'RME!'], ['EUI_64', 2873037108442403], [ 'UNIT', [ ['SPECIFIER_ID', 2613], ['VERSION', 4], ['MODEL', 1054720], ['DESCRIPTOR', 'Fireface UCX']]]]} Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-midi.c | 2 +- sound/firewire/fireface/ff-protocol-latter.c | 96 ++++++++++++++++++++++++++++ sound/firewire/fireface/ff.c | 1 + sound/firewire/fireface/ff.h | 2 +- 4 files changed, 99 insertions(+), 2 deletions(-) (limited to 'sound/firewire') diff --git a/sound/firewire/fireface/ff-midi.c b/sound/firewire/fireface/ff-midi.c index 6a49611ee462..5b44e1c4569a 100644 --- a/sound/firewire/fireface/ff-midi.c +++ b/sound/firewire/fireface/ff-midi.c @@ -19,7 +19,7 @@ static int midi_playback_open(struct snd_rawmidi_substream *substream) struct snd_ff *ff = substream->rmidi->private_data; /* Initialize internal status. */ - ff->running_status[substream->number] = 0; + ff->on_sysex[substream->number] = 0; ff->rx_midi_error[substream->number] = false; WRITE_ONCE(ff->rx_midi_substreams[substream->number], substream); diff --git a/sound/firewire/fireface/ff-protocol-latter.c b/sound/firewire/fireface/ff-protocol-latter.c index a812ab6feb58..817af4447349 100644 --- a/sound/firewire/fireface/ff-protocol-latter.c +++ b/sound/firewire/fireface/ff-protocol-latter.c @@ -306,8 +306,104 @@ static void latter_handle_midi_msg(struct snd_ff *ff, unsigned int offset, snd_rawmidi_receive(substream, byte, len); } +/* + * When return minus value, given argument is not MIDI status. + * When return 0, given argument is a beginning of system exclusive. + * When return the others, given argument is MIDI data. + */ +static inline int calculate_message_bytes(u8 status) +{ + switch (status) { + case 0xf6: /* Tune request. */ + case 0xf8: /* Timing clock. */ + case 0xfa: /* Start. */ + case 0xfb: /* Continue. */ + case 0xfc: /* Stop. */ + case 0xfe: /* Active sensing. */ + case 0xff: /* System reset. */ + return 1; + case 0xf1: /* MIDI time code quarter frame. */ + case 0xf3: /* Song select. */ + return 2; + case 0xf2: /* Song position pointer. */ + return 3; + case 0xf0: /* Exclusive. */ + return 0; + case 0xf7: /* End of exclusive. */ + break; + case 0xf4: /* Undefined. */ + case 0xf5: /* Undefined. */ + case 0xf9: /* Undefined. */ + case 0xfd: /* Undefined. */ + break; + default: + switch (status & 0xf0) { + case 0x80: /* Note on. */ + case 0x90: /* Note off. */ + case 0xa0: /* Polyphonic key pressure. */ + case 0xb0: /* Control change and Mode change. */ + case 0xe0: /* Pitch bend change. */ + return 3; + case 0xc0: /* Program change. */ + case 0xd0: /* Channel pressure. */ + return 2; + default: + break; + } + break; + } + + return -EINVAL; +} + +static int latter_fill_midi_msg(struct snd_ff *ff, + struct snd_rawmidi_substream *substream, + unsigned int port) +{ + u32 data = {0}; + u8 *buf = (u8 *)&data; + int consumed; + + buf[0] = port << 4; + consumed = snd_rawmidi_transmit_peek(substream, buf + 1, 3); + if (consumed <= 0) + return consumed; + + if (!ff->on_sysex[port]) { + if (buf[1] != 0xf0) { + if (consumed < calculate_message_bytes(buf[1])) + return 0; + } else { + // The beginning of exclusives. + ff->on_sysex[port] = true; + } + + buf[0] |= consumed; + } else { + if (buf[1] != 0xf7) { + if (buf[2] == 0xf7 || buf[3] == 0xf7) { + // Transfer end code at next time. + consumed -= 1; + } + + buf[0] |= consumed; + } else { + // The end of exclusives. + ff->on_sysex[port] = false; + consumed = 1; + buf[0] |= 0x0f; + } + } + + ff->msg_buf[port][0] = cpu_to_le32(data); + ff->rx_bytes[port] = consumed; + + return 1; +} + const struct snd_ff_protocol snd_ff_protocol_latter = { .handle_midi_msg = latter_handle_midi_msg, + .fill_midi_msg = latter_fill_midi_msg, .get_clock = latter_get_clock, .switch_fetching_mode = latter_switch_fetching_mode, .begin_session = latter_begin_session, diff --git a/sound/firewire/fireface/ff.c b/sound/firewire/fireface/ff.c index 675c6ab556eb..a9611157f4c8 100644 --- a/sound/firewire/fireface/ff.c +++ b/sound/firewire/fireface/ff.c @@ -174,6 +174,7 @@ static const struct snd_ff_spec spec_ucx = { .pcm_capture_channels = {18, 14, 12}, .pcm_playback_channels = {18, 14, 12}, .midi_in_ports = 2, + .midi_out_ports = 2, .protocol = &snd_ff_protocol_latter, .midi_high_addr = 0xffff00000034ull, .midi_addr_range = 0x80, diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h index e52ad11803e0..ed8fea0ff5e1 100644 --- a/sound/firewire/fireface/ff.h +++ b/sound/firewire/fireface/ff.h @@ -75,7 +75,7 @@ struct snd_ff { /* TO handle MIDI rx. */ struct snd_rawmidi_substream *rx_midi_substreams[SND_FF_OUT_MIDI_PORTS]; - u8 running_status[SND_FF_OUT_MIDI_PORTS]; + bool on_sysex[SND_FF_OUT_MIDI_PORTS]; __le32 msg_buf[SND_FF_OUT_MIDI_PORTS][SND_FF_MAXIMIM_MIDI_QUADS]; struct work_struct rx_midi_work[SND_FF_OUT_MIDI_PORTS]; struct fw_transaction transactions[SND_FF_OUT_MIDI_PORTS]; -- cgit v1.2.3 From d8002539ec7b8bc793a212b79db4a796ce9bce9c Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Thu, 24 Jan 2019 18:32:03 +0900 Subject: ALSA: fireface: comment cleanup about destination address of async transactions for MIDI messages In Fireface series, registration of higher 4 bytes of destination address for asynchronous transaction of MIDI messages is done by a write transaction to model-specific register. On the other hand, registration of lower 4 bytes of the address is selectable from 4 options. A register for this registration includes the other purpose options such as input attenuation. Thus this driver expects userspace applications to configure the register. Actual behaviour for the asynchronous transaction is different depending on protocols. In former protocol, destination offset of each transaction is the same as the registered address even if it is block request. In latter models, destination offset of each transaction is the offset of previous transaction plus 4 byte and the transaction is quadlet request. This commit cleanups comments about the above mechanism. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-protocol-former.c | 23 ++++++++++++++++++ sound/firewire/fireface/ff-protocol-latter.c | 18 ++++++++++++++ sound/firewire/fireface/ff-transaction.c | 36 ++++++---------------------- 3 files changed, 48 insertions(+), 29 deletions(-) (limited to 'sound/firewire') diff --git a/sound/firewire/fireface/ff-protocol-former.c b/sound/firewire/fireface/ff-protocol-former.c index e0acf40a02ee..8d1c2c6e907b 100644 --- a/sound/firewire/fireface/ff-protocol-former.c +++ b/sound/firewire/fireface/ff-protocol-former.c @@ -396,6 +396,10 @@ static void ff800_finish_session(struct snd_ff *ff) FF800_ISOC_COMM_STOP, ®, sizeof(reg), 0); } +// Fireface 800 doesn't allow drivers to register lower 4 bytes of destination +// address. +// A write transaction to clear registered higher 4 bytes of destination address +// has an effect to suppress asynchronous transaction from device. static void ff800_handle_midi_msg(struct snd_ff *ff, unsigned int offset, __le32 *buf, size_t length) { @@ -525,6 +529,25 @@ static void ff400_finish_session(struct snd_ff *ff) FF400_ISOC_COMM_STOP, ®, sizeof(reg), 0); } +// For Fireface 400, lower 4 bytes of destination address is configured by bit +// flag in quadlet register (little endian) at 0x'0000'801'0051c. Drivers can +// select one of 4 options: +// +// bit flags: offset of destination address +// - 0x04000000: 0x'....'....'0000'0000 +// - 0x08000000: 0x'....'....'0000'0080 +// - 0x10000000: 0x'....'....'0000'0100 +// - 0x20000000: 0x'....'....'0000'0180 +// +// Drivers can suppress the device to transfer asynchronous transactions by +// using below 2 bits. +// - 0x01000000: suppress transmission +// - 0x02000000: suppress transmission +// +// Actually, the register is write-only and includes the other options such as +// input attenuation. This driver allocates destination address with '0000'0000 +// in its lower offset and expects userspace application to configure the +// register for it. static void ff400_handle_midi_msg(struct snd_ff *ff, unsigned int offset, __le32 *buf, size_t length) { diff --git a/sound/firewire/fireface/ff-protocol-latter.c b/sound/firewire/fireface/ff-protocol-latter.c index 817af4447349..0fbc1950327f 100644 --- a/sound/firewire/fireface/ff-protocol-latter.c +++ b/sound/firewire/fireface/ff-protocol-latter.c @@ -266,6 +266,24 @@ static void latter_dump_status(struct snd_ff *ff, struct snd_info_buffer *buffer // NOTE: transactions are transferred within 0x00-0x7f in allocated range of // address. This seems to be for check of discontinuity in receiver side. +// +// Like Fireface 400, drivers can select one of 4 options for lower 4 bytes of +// destination address by bit flags in quadlet register (little endian) at +// 0x'ffff'0000'0014: +// +// bit flags: offset of destination address +// - 0x00002000: 0x'....'....'0000'0000 +// - 0x00004000: 0x'....'....'0000'0080 +// - 0x00008000: 0x'....'....'0000'0100 +// - 0x00010000: 0x'....'....'0000'0180 +// +// Drivers can suppress the device to transfer asynchronous transactions by +// clear these bit flags. +// +// Actually, the register is write-only and includes the other settings such as +// input attenuation. This driver allocates for the first option +// (0x'....'....'0000'0000) and expects userspace application to configure the +// register for it. static void latter_handle_midi_msg(struct snd_ff *ff, unsigned int offset, __le32 *buf, size_t length) { diff --git a/sound/firewire/fireface/ff-transaction.c b/sound/firewire/fireface/ff-transaction.c index d8a8b01b39a1..0d6ad19363b8 100644 --- a/sound/firewire/fireface/ff-transaction.c +++ b/sound/firewire/fireface/ff-transaction.c @@ -165,35 +165,13 @@ static int allocate_own_address(struct snd_ff *ff, int i) return err; } -/* - * Controllers are allowed to register higher 4 bytes of address to receive - * the transactions. Different models have different registers for this purpose; - * e.g. 0x'0000'8010'03f4 for Fireface 400. - * The controllers are not allowed to register lower 4 bytes of the address. - * They are forced to select one of 4 options for the part of address by writing - * corresponding bits to 0x'0000'8010'051f. - * - * The 3rd-6th bits of this register are flags to indicate lower 4 bytes of - * address to which the device transferrs the transactions. In short: - * - 0x20: 0x'....'....'0000'0180 - * - 0x10: 0x'....'....'0000'0100 - * - 0x08: 0x'....'....'0000'0080 - * - 0x04: 0x'....'....'0000'0000 - * - * This driver configure 0x'....'....'0000'0000 to receive MIDI messages from - * units. The 3rd bit of the register should be configured, however this driver - * deligates this task to userspace applications due to a restriction that this - * register is write-only and the other bits have own effects. - * - * Unlike Fireface 800, Fireface 400 cancels transferring asynchronous - * transactions when the 1st and 2nd of the register stand. These two bits have - * the same effect. - * - 0x02, 0x01: cancel transferring - * - * On the other hand, the bits have no effect on Fireface 800. This model - * cancels asynchronous transactions when the higher 4 bytes of address is - * overwritten with zero. - */ +// Controllers are allowed to register higher 4 bytes of destination address to +// receive asynchronous transactions for MIDI messages, while the way to +// register lower 4 bytes of address is different depending on protocols. For +// details, please refer to comments in protocol implementations. +// +// This driver expects userspace applications to configure registers for the +// lower address because in most cases such registers has the other settings. int snd_ff_transaction_reregister(struct snd_ff *ff) { struct fw_card *fw_card = fw_parent_device(ff->unit)->card; -- cgit v1.2.3 From 2dee43ec3f31de39dc74e76e6ed65d976f486df0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 25 Jan 2019 15:44:18 +0300 Subject: ALSA: fireface: Off by one in latter_handle_midi_msg() The > should be >= or otherwise we potentially read one element beyond the end of the ff->tx_midi_substreams[] array. Fixes: 73f5537fb209 ("ALSA: fireface: support tx MIDI functionality of Fireface UCX") Signed-off-by: Dan Carpenter Reviewed-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/fireface/ff-protocol-latter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/firewire') diff --git a/sound/firewire/fireface/ff-protocol-latter.c b/sound/firewire/fireface/ff-protocol-latter.c index 0fbc1950327f..c8236ff89b7f 100644 --- a/sound/firewire/fireface/ff-protocol-latter.c +++ b/sound/firewire/fireface/ff-protocol-latter.c @@ -293,7 +293,7 @@ static void latter_handle_midi_msg(struct snd_ff *ff, unsigned int offset, struct snd_rawmidi_substream *substream; unsigned int len; - if (index > ff->spec->midi_in_ports) + if (index >= ff->spec->midi_in_ports) return; switch (data & 0x0000000f) { -- cgit v1.2.3 From b2e9e1c8810ee05c95f4d55800b8afae70ab01b4 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 28 Jan 2019 20:40:58 +0900 Subject: ALSA: dice: add support for Solid State Logic Duende Classic/Mini Duende Classic was produced by Solid State Logic in 2006, as a first model of Duende DSP series. The following model, Duende Mini was produced in 2008. They are designed to receive isochronous packets for PCM frames via IEEE 1394 bus, perform signal processing by downloaded program, then transfer isochronous packets for converted PCM frames. These two models includes the same embedded board, consists of several ICs below: - Texus Instruments Inc, TSB41AB3 for physical layer of IEEE 1394 bus - WaveFront semiconductor, DICE II STD ASIC for link/protocol layer - Altera MAX 3000A CPLD for programs - Analog devices, SHARC ADSP-21363 for signal processing (4 chips) This commit adds support for the two models to ALSA dice driver. Like support for the other devices, packet streaming is just available. Userspace applications should be developed if full features became available; e.g. program uploader and parameter controller. $ ./hinawa-config-rom-printer /dev/fw1 { 'bus-info': { 'adj': False, 'bmc': False, 'chip_ID': 349771402425, 'cmc': True, 'cyc_clk_acc': 255, 'generation': 1, 'imc': True, 'isc': True, 'link_spd': 2, 'max_ROM': 1, 'max_rec': 512, 'name': '1394', 'node_vendor_ID': 20674, 'pmc': False}, 'root-directory': [ ['VENDOR', 20674], ['DESCRIPTOR', 'Solid State Logic'], ['MODEL', 112], ['DESCRIPTOR', 'Duende board'], [ 'NODE_CAPABILITIES', { 'addressing': {'64': True, 'fix': True, 'prv': True}, 'misc': {'int': False, 'ms': False, 'spt': True}, 'state': { 'atn': False, 'ded': False, 'drq': True, 'elo': False, 'init': False, 'lst': True, 'off': False}, 'testing': {'bas': False, 'ext': False}}], [ 'UNIT', [ ['SPECIFIER_ID', 20674], ['VERSION', 1], ['MODEL', 112], ['DESCRIPTOR', 'Duende board']]]]} Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/dice/dice.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'sound/firewire') diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index ed50b222d36e..eee184b05d93 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c @@ -18,6 +18,7 @@ MODULE_LICENSE("GPL v2"); #define OUI_ALESIS 0x000595 #define OUI_MAUDIO 0x000d6c #define OUI_MYTEK 0x001ee8 +#define OUI_SSL 0x0050c2 // Actually ID reserved by IEEE. #define DICE_CATEGORY_ID 0x04 #define WEISS_CATEGORY_ID 0x00 @@ -196,7 +197,7 @@ static int dice_probe(struct fw_unit *unit, struct snd_dice *dice; int err; - if (!entry->driver_data) { + if (!entry->driver_data && entry->vendor_id != OUI_SSL) { err = check_dice_category(unit); if (err < 0) return -ENODEV; @@ -361,6 +362,15 @@ static const struct ieee1394_device_id dice_id_table[] = { .model_id = 0x000002, .driver_data = (kernel_ulong_t)snd_dice_detect_mytek_formats, }, + // Solid State Logic, Duende Classic and Mini. + // NOTE: each field of GUID in config ROM is not compliant to standard + // DICE scheme. + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | + IEEE1394_MATCH_MODEL_ID, + .vendor_id = OUI_SSL, + .model_id = 0x000070, + }, { .match_flags = IEEE1394_MATCH_VERSION, .version = DICE_INTERFACE, -- cgit v1.2.3 From 0c298bdc38a00b8bbbd4df21c85c57d8a9dab625 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 5 Feb 2019 12:34:12 +0100 Subject: ALSA: firewire: Remove superfluous snd_info_register() calls The calls of snd_info_register() are superfluous and should be avoided at the procfs creation time. They are called at the end of the whole initialization via snd_card_register(). This patch drops such superfluous calls. Reviewed-by: Takashi Sakamoto Tested-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob_proc.c | 12 ++---------- sound/firewire/dice/dice-proc.c | 12 ++---------- sound/firewire/digi00x/digi00x-proc.c | 16 ++-------------- sound/firewire/fireface/ff-proc.c | 12 ++---------- sound/firewire/fireworks/fireworks_proc.c | 12 ++---------- sound/firewire/motu/motu-proc.c | 12 ++---------- sound/firewire/oxfw/oxfw-proc.c | 12 ++---------- sound/firewire/tascam/tascam-proc.c | 12 ++---------- 8 files changed, 16 insertions(+), 84 deletions(-) (limited to 'sound/firewire') diff --git a/sound/firewire/bebob/bebob_proc.c b/sound/firewire/bebob/bebob_proc.c index 8096891af913..05e2a1c6326c 100644 --- a/sound/firewire/bebob/bebob_proc.c +++ b/sound/firewire/bebob/bebob_proc.c @@ -163,12 +163,8 @@ add_node(struct snd_bebob *bebob, struct snd_info_entry *root, const char *name, struct snd_info_entry *entry; entry = snd_info_create_card_entry(bebob->card, name, root); - if (entry == NULL) - return; - - snd_info_set_text_ops(entry, bebob, op); - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); + if (entry) + snd_info_set_text_ops(entry, bebob, op); } void snd_bebob_proc_init(struct snd_bebob *bebob) @@ -184,10 +180,6 @@ void snd_bebob_proc_init(struct snd_bebob *bebob) if (root == NULL) return; root->mode = S_IFDIR | 0555; - if (snd_info_register(root) < 0) { - snd_info_free_entry(root); - return; - } add_node(bebob, root, "clock", proc_read_clock); add_node(bebob, root, "firmware", proc_read_hw_info); diff --git a/sound/firewire/dice/dice-proc.c b/sound/firewire/dice/dice-proc.c index bb870fc73f99..9b1d509c6320 100644 --- a/sound/firewire/dice/dice-proc.c +++ b/sound/firewire/dice/dice-proc.c @@ -285,12 +285,8 @@ static void add_node(struct snd_dice *dice, struct snd_info_entry *root, struct snd_info_entry *entry; entry = snd_info_create_card_entry(dice->card, name, root); - if (!entry) - return; - - snd_info_set_text_ops(entry, dice, op); - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); + if (entry) + snd_info_set_text_ops(entry, dice, op); } void snd_dice_create_proc(struct snd_dice *dice) @@ -306,10 +302,6 @@ void snd_dice_create_proc(struct snd_dice *dice) if (!root) return; root->mode = S_IFDIR | 0555; - if (snd_info_register(root) < 0) { - snd_info_free_entry(root); - return; - } add_node(dice, root, "dice", dice_proc_read); add_node(dice, root, "formation", dice_proc_read_formation); diff --git a/sound/firewire/digi00x/digi00x-proc.c b/sound/firewire/digi00x/digi00x-proc.c index 6996d5a6ff5f..d22e8675b10f 100644 --- a/sound/firewire/digi00x/digi00x-proc.c +++ b/sound/firewire/digi00x/digi00x-proc.c @@ -80,20 +80,8 @@ void snd_dg00x_proc_init(struct snd_dg00x *dg00x) return; root->mode = S_IFDIR | 0555; - if (snd_info_register(root) < 0) { - snd_info_free_entry(root); - return; - } entry = snd_info_create_card_entry(dg00x->card, "clock", root); - if (entry == NULL) { - snd_info_free_entry(root); - return; - } - - snd_info_set_text_ops(entry, dg00x, proc_read_clock); - if (snd_info_register(entry) < 0) { - snd_info_free_entry(entry); - snd_info_free_entry(root); - } + if (entry) + snd_info_set_text_ops(entry, dg00x, proc_read_clock); } diff --git a/sound/firewire/fireface/ff-proc.c b/sound/firewire/fireface/ff-proc.c index a55e68ec1832..b886b541c94b 100644 --- a/sound/firewire/fireface/ff-proc.c +++ b/sound/firewire/fireface/ff-proc.c @@ -41,12 +41,8 @@ static void add_node(struct snd_ff *ff, struct snd_info_entry *root, struct snd_info_entry *entry; entry = snd_info_create_card_entry(ff->card, name, root); - if (entry == NULL) - return; - - snd_info_set_text_ops(entry, ff, op); - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); + if (entry) + snd_info_set_text_ops(entry, ff, op); } void snd_ff_proc_init(struct snd_ff *ff) @@ -62,10 +58,6 @@ void snd_ff_proc_init(struct snd_ff *ff) if (root == NULL) return; root->mode = S_IFDIR | 0555; - if (snd_info_register(root) < 0) { - snd_info_free_entry(root); - return; - } add_node(ff, root, "status", proc_dump_status); } diff --git a/sound/firewire/fireworks/fireworks_proc.c b/sound/firewire/fireworks/fireworks_proc.c index 779ecec5af62..9fa5c34a9572 100644 --- a/sound/firewire/fireworks/fireworks_proc.c +++ b/sound/firewire/fireworks/fireworks_proc.c @@ -199,12 +199,8 @@ add_node(struct snd_efw *efw, struct snd_info_entry *root, const char *name, struct snd_info_entry *entry; entry = snd_info_create_card_entry(efw->card, name, root); - if (entry == NULL) - return; - - snd_info_set_text_ops(entry, efw, op); - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); + if (entry) + snd_info_set_text_ops(entry, efw, op); } void snd_efw_proc_init(struct snd_efw *efw) @@ -220,10 +216,6 @@ void snd_efw_proc_init(struct snd_efw *efw) if (root == NULL) return; root->mode = S_IFDIR | 0555; - if (snd_info_register(root) < 0) { - snd_info_free_entry(root); - return; - } add_node(efw, root, "clock", proc_read_clock); add_node(efw, root, "firmware", proc_read_hwinfo); diff --git a/sound/firewire/motu/motu-proc.c b/sound/firewire/motu/motu-proc.c index ab6830a6d242..94327853620a 100644 --- a/sound/firewire/motu/motu-proc.c +++ b/sound/firewire/motu/motu-proc.c @@ -87,12 +87,8 @@ static void add_node(struct snd_motu *motu, struct snd_info_entry *root, struct snd_info_entry *entry; entry = snd_info_create_card_entry(motu->card, name, root); - if (entry == NULL) - return; - - snd_info_set_text_ops(entry, motu, op); - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); + if (entry) + snd_info_set_text_ops(entry, motu, op); } void snd_motu_proc_init(struct snd_motu *motu) @@ -108,10 +104,6 @@ void snd_motu_proc_init(struct snd_motu *motu) if (root == NULL) return; root->mode = S_IFDIR | 0555; - if (snd_info_register(root) < 0) { - snd_info_free_entry(root); - return; - } add_node(motu, root, "clock", proc_read_clock); add_node(motu, root, "format", proc_read_format); diff --git a/sound/firewire/oxfw/oxfw-proc.c b/sound/firewire/oxfw/oxfw-proc.c index 27dac071bc73..644107e3782e 100644 --- a/sound/firewire/oxfw/oxfw-proc.c +++ b/sound/firewire/oxfw/oxfw-proc.c @@ -83,12 +83,8 @@ static void add_node(struct snd_oxfw *oxfw, struct snd_info_entry *root, struct snd_info_entry *entry; entry = snd_info_create_card_entry(oxfw->card, name, root); - if (entry == NULL) - return; - - snd_info_set_text_ops(entry, oxfw, op); - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); + if (entry) + snd_info_set_text_ops(entry, oxfw, op); } void snd_oxfw_proc_init(struct snd_oxfw *oxfw) @@ -104,10 +100,6 @@ void snd_oxfw_proc_init(struct snd_oxfw *oxfw) if (root == NULL) return; root->mode = S_IFDIR | 0555; - if (snd_info_register(root) < 0) { - snd_info_free_entry(root); - return; - } add_node(oxfw, root, "formation", proc_read_formation); } diff --git a/sound/firewire/tascam/tascam-proc.c b/sound/firewire/tascam/tascam-proc.c index fee3bf32a0da..8bc8d277394a 100644 --- a/sound/firewire/tascam/tascam-proc.c +++ b/sound/firewire/tascam/tascam-proc.c @@ -58,12 +58,8 @@ static void add_node(struct snd_tscm *tscm, struct snd_info_entry *root, struct snd_info_entry *entry; entry = snd_info_create_card_entry(tscm->card, name, root); - if (entry == NULL) - return; - - snd_info_set_text_ops(entry, tscm, op); - if (snd_info_register(entry) < 0) - snd_info_free_entry(entry); + if (entry) + snd_info_set_text_ops(entry, tscm, op); } void snd_tscm_proc_init(struct snd_tscm *tscm) @@ -79,10 +75,6 @@ void snd_tscm_proc_init(struct snd_tscm *tscm) if (root == NULL) return; root->mode = S_IFDIR | 0555; - if (snd_info_register(root) < 0) { - snd_info_free_entry(root); - return; - } add_node(tscm, root, "firmware", proc_read_firmware); } -- cgit v1.2.3 From 7dc661bd8d3261053b69e4e2d0050cd1ee540fc1 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 26 Feb 2019 13:38:16 +0900 Subject: ALSA: bebob: use more identical mod_alias for Saffire Pro 10 I/O against Liquid Saffire 56 ALSA bebob driver has an entry for Focusrite Saffire Pro 10 I/O. The entry matches vendor_id in root directory and model_id in unit directory of configuration ROM for IEEE 1394 bus. On the other hand, configuration ROM of Focusrite Liquid Saffire 56 has the same vendor_id and model_id. This device is an application of TCAT Dice (TCD2220 a.k.a Dice Jr.) however ALSA bebob driver can be bound to it randomly instead of ALSA dice driver. At present, drivers in ALSA firewire stack can not handle this situation appropriately. This commit uses more identical mod_alias for Focusrite Saffire Pro 10 I/O in ALSA bebob driver. $ python2 crpp < /sys/bus/firewire/devices/fw1/config_rom ROM header and bus information block ----------------------------------------------------------------- 400 042a829d bus_info_length 4, crc_length 42, crc 33437 404 31333934 bus_name "1394" 408 f0649222 irmc 1, cmc 1, isc 1, bmc 1, pmc 0, cyc_clk_acc 100, max_rec 9 (1024), max_rom 2, gen 2, spd 2 (S400) 40c 00130e01 company_id 00130e | 410 000606e0 device_id 01000606e0 | EUI-64 00130e01000606e0 root directory ----------------------------------------------------------------- 414 0009d31c directory_length 9, crc 54044 418 04000014 hardware version 41c 0c0083c0 node capabilities per IEEE 1394 420 0300130e vendor 424 81000012 --> descriptor leaf at 46c 428 17000006 model 42c 81000016 --> descriptor leaf at 484 430 130120c2 version 434 d1000002 --> unit directory at 43c 438 d4000006 --> dependent info directory at 450 unit directory at 43c ----------------------------------------------------------------- 43c 0004707c directory_length 4, crc 28796 440 1200a02d specifier id: 1394 TA 444 13010001 version: AV/C 448 17000006 model 44c 81000013 --> descriptor leaf at 498 dependent info directory at 450 ----------------------------------------------------------------- 450 000637c7 directory_length 6, crc 14279 454 120007f5 specifier id 458 13000001 version 45c 3affffc7 (immediate value) 460 3b100000 (immediate value) 464 3cffffc7 (immediate value) 468 3d600000 (immediate value) descriptor leaf at 46c ----------------------------------------------------------------- 46c 00056f3b leaf_length 5, crc 28475 470 00000000 textual descriptor 474 00000000 minimal ASCII 478 466f6375 "Focu" 47c 73726974 "srit" 480 65000000 "e" descriptor leaf at 484 ----------------------------------------------------------------- 484 0004a165 leaf_length 4, crc 41317 488 00000000 textual descriptor 48c 00000000 minimal ASCII 490 50726f31 "Pro1" 494 30494f00 "0IO" descriptor leaf at 498 ----------------------------------------------------------------- 498 0004a165 leaf_length 4, crc 41317 49c 00000000 textual descriptor 4a0 00000000 minimal ASCII 4a4 50726f31 "Pro1" 4a8 30494f00 "0IO" $ python2 crpp < /sys/bus/firewire/devices/fw1/config_rom ROM header and bus information block ----------------------------------------------------------------- 400 040442e4 bus_info_length 4, crc_length 4, crc 17124 404 31333934 bus_name "1394" 408 e0ff8112 irmc 1, cmc 1, isc 1, bmc 0, pmc 0, cyc_clk_acc 255, max_rec 8 (512), max_rom 1, gen 1, spd 2 (S400) 40c 00130e04 company_id 00130e | 410 018001e9 device_id 04018001e9 | EUI-64 00130e04018001e9 root directory ----------------------------------------------------------------- 414 00065612 directory_length 6, crc 22034 418 0300130e vendor 41c 8100000a --> descriptor leaf at 444 420 17000006 model 424 8100000e --> descriptor leaf at 45c 428 0c0087c0 node capabilities per IEEE 1394 42c d1000001 --> unit directory at 430 unit directory at 430 ----------------------------------------------------------------- 430 000418a0 directory_length 4, crc 6304 434 1200130e specifier id 438 13000001 version 43c 17000006 model 440 8100000f --> descriptor leaf at 47c descriptor leaf at 444 ----------------------------------------------------------------- 444 00056f3b leaf_length 5, crc 28475 448 00000000 textual descriptor 44c 00000000 minimal ASCII 450 466f6375 "Focu" 454 73726974 "srit" 458 65000000 "e" descriptor leaf at 45c ----------------------------------------------------------------- 45c 000762c6 leaf_length 7, crc 25286 460 00000000 textual descriptor 464 00000000 minimal ASCII 468 4c495155 "LIQU" 46c 49445f53 "ID_S" 470 41464649 "AFFI" 474 52455f35 "RE_5" 478 36000000 "6" descriptor leaf at 47c ----------------------------------------------------------------- 47c 000762c6 leaf_length 7, crc 25286 480 00000000 textual descriptor 484 00000000 minimal ASCII 488 4c495155 "LIQU" 48c 49445f53 "ID_S" 490 41464649 "AFFI" 494 52455f35 "RE_5" 498 36000000 "6" Cc: # v3.16+ Fixes: 25784ec2d034 ("ALSA: bebob: Add support for Focusrite Saffire/SaffirePro series") Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'sound/firewire') diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c index d91874275d2c..5b46e8dcc2dd 100644 --- a/sound/firewire/bebob/bebob.c +++ b/sound/firewire/bebob/bebob.c @@ -448,7 +448,19 @@ static const struct ieee1394_device_id bebob_id_table[] = { /* Focusrite, SaffirePro 26 I/O */ SND_BEBOB_DEV_ENTRY(VEN_FOCUSRITE, 0x00000003, &saffirepro_26_spec), /* Focusrite, SaffirePro 10 I/O */ - SND_BEBOB_DEV_ENTRY(VEN_FOCUSRITE, 0x00000006, &saffirepro_10_spec), + { + // The combination of vendor_id and model_id is the same as the + // same as the one of Liquid Saffire 56. + .match_flags = IEEE1394_MATCH_VENDOR_ID | + IEEE1394_MATCH_MODEL_ID | + IEEE1394_MATCH_SPECIFIER_ID | + IEEE1394_MATCH_VERSION, + .vendor_id = VEN_FOCUSRITE, + .model_id = 0x000006, + .specifier_id = 0x00a02d, + .version = 0x010001, + .driver_data = (kernel_ulong_t)&saffirepro_10_spec, + }, /* Focusrite, Saffire(no label and LE) */ SND_BEBOB_DEV_ENTRY(VEN_FOCUSRITE, MODEL_FOCUSRITE_SAFFIRE_BOTH, &saffire_spec), -- cgit v1.2.3 From f97a0944a72b26a2bece72516294e112a890f98a Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 26 Feb 2019 13:38:37 +0900 Subject: ALSA: firewire-motu: fix construction of PCM frame for capture direction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In data blocks of common isochronous packet for MOTU devices, PCM frames are multiplexed in a shape of '24 bit * 4 Audio Pack', described in IEC 61883-6. The frames are not aligned to quadlet. For capture PCM substream, ALSA firewire-motu driver constructs PCM frames by reading data blocks byte-by-byte. However this operation includes bug for lower byte of the PCM sample. This brings invalid content of the PCM samples. This commit fixes the bug. Reported-by: Peter Sjöberg Cc: # v4.12+ Fixes: 4641c9394010 ("ALSA: firewire-motu: add MOTU specific protocol layer") Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/motu/amdtp-motu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sound/firewire') diff --git a/sound/firewire/motu/amdtp-motu.c b/sound/firewire/motu/amdtp-motu.c index f0555a24d90e..6c9b743ea74b 100644 --- a/sound/firewire/motu/amdtp-motu.c +++ b/sound/firewire/motu/amdtp-motu.c @@ -136,7 +136,9 @@ static void read_pcm_s32(struct amdtp_stream *s, byte = (u8 *)buffer + p->pcm_byte_offset; for (c = 0; c < channels; ++c) { - *dst = (byte[0] << 24) | (byte[1] << 16) | byte[2]; + *dst = (byte[0] << 24) | + (byte[1] << 16) | + (byte[2] << 8); byte += 3; dst++; } -- cgit v1.2.3