162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci// ff-protocol-former.c - a part of driver for RME Fireface series
362306a36Sopenharmony_ci//
462306a36Sopenharmony_ci// Copyright (c) 2019 Takashi Sakamoto
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/delay.h>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "ff.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#define FORMER_REG_SYNC_STATUS		0x0000801c0000ull
1162306a36Sopenharmony_ci/* For block write request. */
1262306a36Sopenharmony_ci#define FORMER_REG_FETCH_PCM_FRAMES	0x0000801c0000ull
1362306a36Sopenharmony_ci#define FORMER_REG_CLOCK_CONFIG		0x0000801c0004ull
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistatic int parse_clock_bits(u32 data, unsigned int *rate,
1662306a36Sopenharmony_ci			    enum snd_ff_clock_src *src)
1762306a36Sopenharmony_ci{
1862306a36Sopenharmony_ci	static const struct {
1962306a36Sopenharmony_ci		unsigned int rate;
2062306a36Sopenharmony_ci		u32 mask;
2162306a36Sopenharmony_ci	} *rate_entry, rate_entries[] = {
2262306a36Sopenharmony_ci		{  32000, 0x00000002, },
2362306a36Sopenharmony_ci		{  44100, 0x00000000, },
2462306a36Sopenharmony_ci		{  48000, 0x00000006, },
2562306a36Sopenharmony_ci		{  64000, 0x0000000a, },
2662306a36Sopenharmony_ci		{  88200, 0x00000008, },
2762306a36Sopenharmony_ci		{  96000, 0x0000000e, },
2862306a36Sopenharmony_ci		{ 128000, 0x00000012, },
2962306a36Sopenharmony_ci		{ 176400, 0x00000010, },
3062306a36Sopenharmony_ci		{ 192000, 0x00000016, },
3162306a36Sopenharmony_ci	};
3262306a36Sopenharmony_ci	static const struct {
3362306a36Sopenharmony_ci		enum snd_ff_clock_src src;
3462306a36Sopenharmony_ci		u32 mask;
3562306a36Sopenharmony_ci	} *clk_entry, clk_entries[] = {
3662306a36Sopenharmony_ci		{ SND_FF_CLOCK_SRC_ADAT1,	0x00000000, },
3762306a36Sopenharmony_ci		{ SND_FF_CLOCK_SRC_ADAT2,	0x00000400, },
3862306a36Sopenharmony_ci		{ SND_FF_CLOCK_SRC_SPDIF,	0x00000c00, },
3962306a36Sopenharmony_ci		{ SND_FF_CLOCK_SRC_WORD,	0x00001000, },
4062306a36Sopenharmony_ci		{ SND_FF_CLOCK_SRC_LTC,		0x00001800, },
4162306a36Sopenharmony_ci	};
4262306a36Sopenharmony_ci	int i;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(rate_entries); ++i) {
4562306a36Sopenharmony_ci		rate_entry = rate_entries + i;
4662306a36Sopenharmony_ci		if ((data & 0x0000001e) == rate_entry->mask) {
4762306a36Sopenharmony_ci			*rate = rate_entry->rate;
4862306a36Sopenharmony_ci			break;
4962306a36Sopenharmony_ci		}
5062306a36Sopenharmony_ci	}
5162306a36Sopenharmony_ci	if (i == ARRAY_SIZE(rate_entries))
5262306a36Sopenharmony_ci		return -EIO;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	if (data & 0x00000001) {
5562306a36Sopenharmony_ci		*src = SND_FF_CLOCK_SRC_INTERNAL;
5662306a36Sopenharmony_ci	} else {
5762306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(clk_entries); ++i) {
5862306a36Sopenharmony_ci			clk_entry = clk_entries + i;
5962306a36Sopenharmony_ci			if ((data & 0x00001c00) == clk_entry->mask) {
6062306a36Sopenharmony_ci				*src = clk_entry->src;
6162306a36Sopenharmony_ci				break;
6262306a36Sopenharmony_ci			}
6362306a36Sopenharmony_ci		}
6462306a36Sopenharmony_ci		if (i == ARRAY_SIZE(clk_entries))
6562306a36Sopenharmony_ci			return -EIO;
6662306a36Sopenharmony_ci	}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	return 0;
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic int former_get_clock(struct snd_ff *ff, unsigned int *rate,
7262306a36Sopenharmony_ci			    enum snd_ff_clock_src *src)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	__le32 reg;
7562306a36Sopenharmony_ci	u32 data;
7662306a36Sopenharmony_ci	int err;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
7962306a36Sopenharmony_ci				 FORMER_REG_CLOCK_CONFIG, &reg, sizeof(reg), 0);
8062306a36Sopenharmony_ci	if (err < 0)
8162306a36Sopenharmony_ci		return err;
8262306a36Sopenharmony_ci	data = le32_to_cpu(reg);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	return parse_clock_bits(data, rate, src);
8562306a36Sopenharmony_ci}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic int former_switch_fetching_mode(struct snd_ff *ff, bool enable)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	unsigned int count;
9062306a36Sopenharmony_ci	__le32 *reg;
9162306a36Sopenharmony_ci	int i;
9262306a36Sopenharmony_ci	int err;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	count = 0;
9562306a36Sopenharmony_ci	for (i = 0; i < SND_FF_STREAM_MODE_COUNT; ++i)
9662306a36Sopenharmony_ci		count = max(count, ff->spec->pcm_playback_channels[i]);
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	reg = kcalloc(count, sizeof(__le32), GFP_KERNEL);
9962306a36Sopenharmony_ci	if (!reg)
10062306a36Sopenharmony_ci		return -ENOMEM;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	if (!enable) {
10362306a36Sopenharmony_ci		/*
10462306a36Sopenharmony_ci		 * Each quadlet is corresponding to data channels in a data
10562306a36Sopenharmony_ci		 * blocks in reverse order. Precisely, quadlets for available
10662306a36Sopenharmony_ci		 * data channels should be enabled. Here, I take second best
10762306a36Sopenharmony_ci		 * to fetch PCM frames from all of data channels regardless of
10862306a36Sopenharmony_ci		 * stf.
10962306a36Sopenharmony_ci		 */
11062306a36Sopenharmony_ci		for (i = 0; i < count; ++i)
11162306a36Sopenharmony_ci			reg[i] = cpu_to_le32(0x00000001);
11262306a36Sopenharmony_ci	}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	err = snd_fw_transaction(ff->unit, TCODE_WRITE_BLOCK_REQUEST,
11562306a36Sopenharmony_ci				 FORMER_REG_FETCH_PCM_FRAMES, reg,
11662306a36Sopenharmony_ci				 sizeof(__le32) * count, 0);
11762306a36Sopenharmony_ci	kfree(reg);
11862306a36Sopenharmony_ci	return err;
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic void dump_clock_config(struct snd_ff *ff, struct snd_info_buffer *buffer)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	__le32 reg;
12462306a36Sopenharmony_ci	u32 data;
12562306a36Sopenharmony_ci	unsigned int rate;
12662306a36Sopenharmony_ci	enum snd_ff_clock_src src;
12762306a36Sopenharmony_ci	const char *label;
12862306a36Sopenharmony_ci	int err;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	err = snd_fw_transaction(ff->unit, TCODE_READ_BLOCK_REQUEST,
13162306a36Sopenharmony_ci				 FORMER_REG_CLOCK_CONFIG, &reg, sizeof(reg), 0);
13262306a36Sopenharmony_ci	if (err < 0)
13362306a36Sopenharmony_ci		return;
13462306a36Sopenharmony_ci	data = le32_to_cpu(reg);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	snd_iprintf(buffer, "Output S/PDIF format: %s (Emphasis: %s)\n",
13762306a36Sopenharmony_ci		    (data & 0x00000020) ? "Professional" : "Consumer",
13862306a36Sopenharmony_ci		    (data & 0x00000040) ? "on" : "off");
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	snd_iprintf(buffer, "Optical output interface format: %s\n",
14162306a36Sopenharmony_ci		    (data & 0x00000100) ? "S/PDIF" : "ADAT");
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	snd_iprintf(buffer, "Word output single speed: %s\n",
14462306a36Sopenharmony_ci		    (data & 0x00002000) ? "on" : "off");
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	snd_iprintf(buffer, "S/PDIF input interface: %s\n",
14762306a36Sopenharmony_ci		    (data & 0x00000200) ? "Optical" : "Coaxial");
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	err = parse_clock_bits(data, &rate, &src);
15062306a36Sopenharmony_ci	if (err < 0)
15162306a36Sopenharmony_ci		return;
15262306a36Sopenharmony_ci	label = snd_ff_proc_get_clk_label(src);
15362306a36Sopenharmony_ci	if (!label)
15462306a36Sopenharmony_ci		return;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	snd_iprintf(buffer, "Clock configuration: %d %s\n", rate, label);
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_cistatic void dump_sync_status(struct snd_ff *ff, struct snd_info_buffer *buffer)
16062306a36Sopenharmony_ci{
16162306a36Sopenharmony_ci	static const struct {
16262306a36Sopenharmony_ci		char *const label;
16362306a36Sopenharmony_ci		u32 locked_mask;
16462306a36Sopenharmony_ci		u32 synced_mask;
16562306a36Sopenharmony_ci	} *clk_entry, clk_entries[] = {
16662306a36Sopenharmony_ci		{ "WDClk",	0x40000000, 0x20000000, },
16762306a36Sopenharmony_ci		{ "S/PDIF",	0x00080000, 0x00040000, },
16862306a36Sopenharmony_ci		{ "ADAT1",	0x00000400, 0x00001000, },
16962306a36Sopenharmony_ci		{ "ADAT2",	0x00000800, 0x00002000, },
17062306a36Sopenharmony_ci	};
17162306a36Sopenharmony_ci	static const struct {
17262306a36Sopenharmony_ci		char *const label;
17362306a36Sopenharmony_ci		u32 mask;
17462306a36Sopenharmony_ci	} *referred_entry, referred_entries[] = {
17562306a36Sopenharmony_ci		{ "ADAT1",	0x00000000, },
17662306a36Sopenharmony_ci		{ "ADAT2",	0x00400000, },
17762306a36Sopenharmony_ci		{ "S/PDIF",	0x00c00000, },
17862306a36Sopenharmony_ci		{ "WDclk",	0x01000000, },
17962306a36Sopenharmony_ci		{ "TCO",	0x01400000, },
18062306a36Sopenharmony_ci	};
18162306a36Sopenharmony_ci	static const struct {
18262306a36Sopenharmony_ci		unsigned int rate;
18362306a36Sopenharmony_ci		u32 mask;
18462306a36Sopenharmony_ci	} *rate_entry, rate_entries[] = {
18562306a36Sopenharmony_ci		{ 32000,	0x02000000, },
18662306a36Sopenharmony_ci		{ 44100,	0x04000000, },
18762306a36Sopenharmony_ci		{ 48000,	0x06000000, },
18862306a36Sopenharmony_ci		{ 64000,	0x08000000, },
18962306a36Sopenharmony_ci		{ 88200,	0x0a000000, },
19062306a36Sopenharmony_ci		{ 96000,	0x0c000000, },
19162306a36Sopenharmony_ci		{ 128000,	0x0e000000, },
19262306a36Sopenharmony_ci		{ 176400,	0x10000000, },
19362306a36Sopenharmony_ci		{ 192000,	0x12000000, },
19462306a36Sopenharmony_ci	};
19562306a36Sopenharmony_ci	__le32 reg[2];
19662306a36Sopenharmony_ci	u32 data[2];
19762306a36Sopenharmony_ci	int i;
19862306a36Sopenharmony_ci	int err;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	err = snd_fw_transaction(ff->unit, TCODE_READ_BLOCK_REQUEST,
20162306a36Sopenharmony_ci				 FORMER_REG_SYNC_STATUS, reg, sizeof(reg), 0);
20262306a36Sopenharmony_ci	if (err < 0)
20362306a36Sopenharmony_ci		return;
20462306a36Sopenharmony_ci	data[0] = le32_to_cpu(reg[0]);
20562306a36Sopenharmony_ci	data[1] = le32_to_cpu(reg[1]);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	snd_iprintf(buffer, "External source detection:\n");
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(clk_entries); ++i) {
21062306a36Sopenharmony_ci		const char *state;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci		clk_entry = clk_entries + i;
21362306a36Sopenharmony_ci		if (data[0] & clk_entry->locked_mask) {
21462306a36Sopenharmony_ci			if (data[0] & clk_entry->synced_mask)
21562306a36Sopenharmony_ci				state = "sync";
21662306a36Sopenharmony_ci			else
21762306a36Sopenharmony_ci				state = "lock";
21862306a36Sopenharmony_ci		} else {
21962306a36Sopenharmony_ci			state = "none";
22062306a36Sopenharmony_ci		}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci		snd_iprintf(buffer, "%s: %s\n", clk_entry->label, state);
22362306a36Sopenharmony_ci	}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	snd_iprintf(buffer, "Referred clock:\n");
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	if (data[1] & 0x00000001) {
22862306a36Sopenharmony_ci		snd_iprintf(buffer, "Internal\n");
22962306a36Sopenharmony_ci	} else {
23062306a36Sopenharmony_ci		unsigned int rate;
23162306a36Sopenharmony_ci		const char *label;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(referred_entries); ++i) {
23462306a36Sopenharmony_ci			referred_entry = referred_entries + i;
23562306a36Sopenharmony_ci			if ((data[0] & 0x1e0000) == referred_entry->mask) {
23662306a36Sopenharmony_ci				label = referred_entry->label;
23762306a36Sopenharmony_ci				break;
23862306a36Sopenharmony_ci			}
23962306a36Sopenharmony_ci		}
24062306a36Sopenharmony_ci		if (i == ARRAY_SIZE(referred_entries))
24162306a36Sopenharmony_ci			label = "none";
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(rate_entries); ++i) {
24462306a36Sopenharmony_ci			rate_entry = rate_entries + i;
24562306a36Sopenharmony_ci			if ((data[0] & 0x1e000000) == rate_entry->mask) {
24662306a36Sopenharmony_ci				rate = rate_entry->rate;
24762306a36Sopenharmony_ci				break;
24862306a36Sopenharmony_ci			}
24962306a36Sopenharmony_ci		}
25062306a36Sopenharmony_ci		if (i == ARRAY_SIZE(rate_entries))
25162306a36Sopenharmony_ci			rate = 0;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci		snd_iprintf(buffer, "%s %d\n", label, rate);
25462306a36Sopenharmony_ci	}
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_cistatic void former_dump_status(struct snd_ff *ff,
25862306a36Sopenharmony_ci			       struct snd_info_buffer *buffer)
25962306a36Sopenharmony_ci{
26062306a36Sopenharmony_ci	dump_clock_config(ff, buffer);
26162306a36Sopenharmony_ci	dump_sync_status(ff, buffer);
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_cistatic int former_fill_midi_msg(struct snd_ff *ff,
26562306a36Sopenharmony_ci				struct snd_rawmidi_substream *substream,
26662306a36Sopenharmony_ci				unsigned int port)
26762306a36Sopenharmony_ci{
26862306a36Sopenharmony_ci	u8 *buf = (u8 *)ff->msg_buf[port];
26962306a36Sopenharmony_ci	int len;
27062306a36Sopenharmony_ci	int i;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	len = snd_rawmidi_transmit_peek(substream, buf,
27362306a36Sopenharmony_ci					SND_FF_MAXIMIM_MIDI_QUADS);
27462306a36Sopenharmony_ci	if (len <= 0)
27562306a36Sopenharmony_ci		return len;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	// One quadlet includes one byte.
27862306a36Sopenharmony_ci	for (i = len - 1; i >= 0; --i)
27962306a36Sopenharmony_ci		ff->msg_buf[port][i] = cpu_to_le32(buf[i]);
28062306a36Sopenharmony_ci	ff->rx_bytes[port] = len;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	return len;
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci#define FF800_STF		0x0000fc88f000
28662306a36Sopenharmony_ci#define FF800_RX_PACKET_FORMAT	0x0000fc88f004
28762306a36Sopenharmony_ci#define FF800_ALLOC_TX_STREAM	0x0000fc88f008
28862306a36Sopenharmony_ci#define FF800_ISOC_COMM_START	0x0000fc88f00c
28962306a36Sopenharmony_ci#define   FF800_TX_S800_FLAG	0x00000800
29062306a36Sopenharmony_ci#define FF800_ISOC_COMM_STOP	0x0000fc88f010
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci#define FF800_TX_PACKET_ISOC_CH	0x0000801c0008
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistatic int allocate_tx_resources(struct snd_ff *ff)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	__le32 reg;
29762306a36Sopenharmony_ci	unsigned int count;
29862306a36Sopenharmony_ci	unsigned int tx_isoc_channel;
29962306a36Sopenharmony_ci	int err;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	reg = cpu_to_le32(ff->tx_stream.data_block_quadlets);
30262306a36Sopenharmony_ci	err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
30362306a36Sopenharmony_ci				 FF800_ALLOC_TX_STREAM, &reg, sizeof(reg), 0);
30462306a36Sopenharmony_ci	if (err < 0)
30562306a36Sopenharmony_ci		return err;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	// Wait till the format of tx packet is available.
30862306a36Sopenharmony_ci	count = 0;
30962306a36Sopenharmony_ci	while (count++ < 10) {
31062306a36Sopenharmony_ci		u32 data;
31162306a36Sopenharmony_ci		err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
31262306a36Sopenharmony_ci				FF800_TX_PACKET_ISOC_CH, &reg, sizeof(reg), 0);
31362306a36Sopenharmony_ci		if (err < 0)
31462306a36Sopenharmony_ci			return err;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci		data = le32_to_cpu(reg);
31762306a36Sopenharmony_ci		if (data != 0xffffffff) {
31862306a36Sopenharmony_ci			tx_isoc_channel = data;
31962306a36Sopenharmony_ci			break;
32062306a36Sopenharmony_ci		}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci		msleep(50);
32362306a36Sopenharmony_ci	}
32462306a36Sopenharmony_ci	if (count >= 10)
32562306a36Sopenharmony_ci		return -ETIMEDOUT;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	// NOTE: this is a makeshift to start OHCI 1394 IR context in the
32862306a36Sopenharmony_ci	// channel. On the other hand, 'struct fw_iso_resources.allocated' is
32962306a36Sopenharmony_ci	// not true and it's not deallocated at stop.
33062306a36Sopenharmony_ci	ff->tx_resources.channel = tx_isoc_channel;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	return 0;
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cistatic int ff800_allocate_resources(struct snd_ff *ff, unsigned int rate)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	u32 data;
33862306a36Sopenharmony_ci	__le32 reg;
33962306a36Sopenharmony_ci	int err;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	reg = cpu_to_le32(rate);
34262306a36Sopenharmony_ci	err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
34362306a36Sopenharmony_ci				 FF800_STF, &reg, sizeof(reg), 0);
34462306a36Sopenharmony_ci	if (err < 0)
34562306a36Sopenharmony_ci		return err;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	// If starting isochronous communication immediately, change of STF has
34862306a36Sopenharmony_ci	// no effect. In this case, the communication runs based on former STF.
34962306a36Sopenharmony_ci	// Let's sleep for a bit.
35062306a36Sopenharmony_ci	msleep(100);
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	// Controllers should allocate isochronous resources for rx stream.
35362306a36Sopenharmony_ci	err = fw_iso_resources_allocate(&ff->rx_resources,
35462306a36Sopenharmony_ci				amdtp_stream_get_max_payload(&ff->rx_stream),
35562306a36Sopenharmony_ci				fw_parent_device(ff->unit)->max_speed);
35662306a36Sopenharmony_ci	if (err < 0)
35762306a36Sopenharmony_ci		return err;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	// Set isochronous channel and the number of quadlets of rx packets.
36062306a36Sopenharmony_ci	// This should be done before the allocation of tx resources to avoid
36162306a36Sopenharmony_ci	// periodical noise.
36262306a36Sopenharmony_ci	data = ff->rx_stream.data_block_quadlets << 3;
36362306a36Sopenharmony_ci	data = (data << 8) | ff->rx_resources.channel;
36462306a36Sopenharmony_ci	reg = cpu_to_le32(data);
36562306a36Sopenharmony_ci	err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
36662306a36Sopenharmony_ci				 FF800_RX_PACKET_FORMAT, &reg, sizeof(reg), 0);
36762306a36Sopenharmony_ci	if (err < 0)
36862306a36Sopenharmony_ci		return err;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	return allocate_tx_resources(ff);
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_cistatic int ff800_begin_session(struct snd_ff *ff, unsigned int rate)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	unsigned int generation = ff->rx_resources.generation;
37662306a36Sopenharmony_ci	__le32 reg;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	if (generation != fw_parent_device(ff->unit)->card->generation) {
37962306a36Sopenharmony_ci		int err = fw_iso_resources_update(&ff->rx_resources);
38062306a36Sopenharmony_ci		if (err < 0)
38162306a36Sopenharmony_ci			return err;
38262306a36Sopenharmony_ci	}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	reg = cpu_to_le32(0x80000000);
38562306a36Sopenharmony_ci	reg |= cpu_to_le32(ff->tx_stream.data_block_quadlets);
38662306a36Sopenharmony_ci	if (fw_parent_device(ff->unit)->max_speed == SCODE_800)
38762306a36Sopenharmony_ci		reg |= cpu_to_le32(FF800_TX_S800_FLAG);
38862306a36Sopenharmony_ci	return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
38962306a36Sopenharmony_ci				 FF800_ISOC_COMM_START, &reg, sizeof(reg), 0);
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_cistatic void ff800_finish_session(struct snd_ff *ff)
39362306a36Sopenharmony_ci{
39462306a36Sopenharmony_ci	__le32 reg;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	reg = cpu_to_le32(0x80000000);
39762306a36Sopenharmony_ci	snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
39862306a36Sopenharmony_ci			   FF800_ISOC_COMM_STOP, &reg, sizeof(reg), 0);
39962306a36Sopenharmony_ci}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci// Fireface 800 doesn't allow drivers to register lower 4 bytes of destination
40262306a36Sopenharmony_ci// address.
40362306a36Sopenharmony_ci// A write transaction to clear registered higher 4 bytes of destination address
40462306a36Sopenharmony_ci// has an effect to suppress asynchronous transaction from device.
40562306a36Sopenharmony_cistatic void ff800_handle_midi_msg(struct snd_ff *ff, unsigned int offset, const __le32 *buf,
40662306a36Sopenharmony_ci				  size_t length, u32 tstamp)
40762306a36Sopenharmony_ci{
40862306a36Sopenharmony_ci	int i;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	for (i = 0; i < length / 4; i++) {
41162306a36Sopenharmony_ci		u8 byte = le32_to_cpu(buf[i]) & 0xff;
41262306a36Sopenharmony_ci		struct snd_rawmidi_substream *substream;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci		substream = READ_ONCE(ff->tx_midi_substreams[0]);
41562306a36Sopenharmony_ci		if (substream)
41662306a36Sopenharmony_ci			snd_rawmidi_receive(substream, &byte, 1);
41762306a36Sopenharmony_ci	}
41862306a36Sopenharmony_ci}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ciconst struct snd_ff_protocol snd_ff_protocol_ff800 = {
42162306a36Sopenharmony_ci	.handle_msg		= ff800_handle_midi_msg,
42262306a36Sopenharmony_ci	.fill_midi_msg		= former_fill_midi_msg,
42362306a36Sopenharmony_ci	.get_clock		= former_get_clock,
42462306a36Sopenharmony_ci	.switch_fetching_mode	= former_switch_fetching_mode,
42562306a36Sopenharmony_ci	.allocate_resources	= ff800_allocate_resources,
42662306a36Sopenharmony_ci	.begin_session		= ff800_begin_session,
42762306a36Sopenharmony_ci	.finish_session		= ff800_finish_session,
42862306a36Sopenharmony_ci	.dump_status		= former_dump_status,
42962306a36Sopenharmony_ci};
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci#define FF400_STF		0x000080100500ull
43262306a36Sopenharmony_ci#define FF400_RX_PACKET_FORMAT	0x000080100504ull
43362306a36Sopenharmony_ci#define FF400_ISOC_COMM_START	0x000080100508ull
43462306a36Sopenharmony_ci#define FF400_TX_PACKET_FORMAT	0x00008010050cull
43562306a36Sopenharmony_ci#define FF400_ISOC_COMM_STOP	0x000080100510ull
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci// Fireface 400 manages isochronous channel number in 3 bit field. Therefore,
43862306a36Sopenharmony_ci// we can allocate between 0 and 7 channel.
43962306a36Sopenharmony_cistatic int ff400_allocate_resources(struct snd_ff *ff, unsigned int rate)
44062306a36Sopenharmony_ci{
44162306a36Sopenharmony_ci	__le32 reg;
44262306a36Sopenharmony_ci	enum snd_ff_stream_mode mode;
44362306a36Sopenharmony_ci	int i;
44462306a36Sopenharmony_ci	int err;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	// Check whether the given value is supported or not.
44762306a36Sopenharmony_ci	for (i = 0; i < CIP_SFC_COUNT; i++) {
44862306a36Sopenharmony_ci		if (amdtp_rate_table[i] == rate)
44962306a36Sopenharmony_ci			break;
45062306a36Sopenharmony_ci	}
45162306a36Sopenharmony_ci	if (i >= CIP_SFC_COUNT)
45262306a36Sopenharmony_ci		return -EINVAL;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	// Set the number of data blocks transferred in a second.
45562306a36Sopenharmony_ci	reg = cpu_to_le32(rate);
45662306a36Sopenharmony_ci	err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
45762306a36Sopenharmony_ci				 FF400_STF, &reg, sizeof(reg), 0);
45862306a36Sopenharmony_ci	if (err < 0)
45962306a36Sopenharmony_ci		return err;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	msleep(100);
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	err = snd_ff_stream_get_multiplier_mode(i, &mode);
46462306a36Sopenharmony_ci	if (err < 0)
46562306a36Sopenharmony_ci		return err;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	// Keep resources for in-stream.
46862306a36Sopenharmony_ci	ff->tx_resources.channels_mask = 0x00000000000000ffuLL;
46962306a36Sopenharmony_ci	err = fw_iso_resources_allocate(&ff->tx_resources,
47062306a36Sopenharmony_ci			amdtp_stream_get_max_payload(&ff->tx_stream),
47162306a36Sopenharmony_ci			fw_parent_device(ff->unit)->max_speed);
47262306a36Sopenharmony_ci	if (err < 0)
47362306a36Sopenharmony_ci		return err;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	// Keep resources for out-stream.
47662306a36Sopenharmony_ci	ff->rx_resources.channels_mask = 0x00000000000000ffuLL;
47762306a36Sopenharmony_ci	err = fw_iso_resources_allocate(&ff->rx_resources,
47862306a36Sopenharmony_ci			amdtp_stream_get_max_payload(&ff->rx_stream),
47962306a36Sopenharmony_ci			fw_parent_device(ff->unit)->max_speed);
48062306a36Sopenharmony_ci	if (err < 0)
48162306a36Sopenharmony_ci		fw_iso_resources_free(&ff->tx_resources);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	return err;
48462306a36Sopenharmony_ci}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_cistatic int ff400_begin_session(struct snd_ff *ff, unsigned int rate)
48762306a36Sopenharmony_ci{
48862306a36Sopenharmony_ci	unsigned int generation = ff->rx_resources.generation;
48962306a36Sopenharmony_ci	__le32 reg;
49062306a36Sopenharmony_ci	int err;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	if (generation != fw_parent_device(ff->unit)->card->generation) {
49362306a36Sopenharmony_ci		err = fw_iso_resources_update(&ff->tx_resources);
49462306a36Sopenharmony_ci		if (err < 0)
49562306a36Sopenharmony_ci			return err;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci		err = fw_iso_resources_update(&ff->rx_resources);
49862306a36Sopenharmony_ci		if (err < 0)
49962306a36Sopenharmony_ci			return err;
50062306a36Sopenharmony_ci	}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	// Set isochronous channel and the number of quadlets of received
50362306a36Sopenharmony_ci	// packets.
50462306a36Sopenharmony_ci	reg = cpu_to_le32(((ff->rx_stream.data_block_quadlets << 3) << 8) |
50562306a36Sopenharmony_ci			  ff->rx_resources.channel);
50662306a36Sopenharmony_ci	err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
50762306a36Sopenharmony_ci				 FF400_RX_PACKET_FORMAT, &reg, sizeof(reg), 0);
50862306a36Sopenharmony_ci	if (err < 0)
50962306a36Sopenharmony_ci		return err;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	// Set isochronous channel and the number of quadlets of transmitted
51262306a36Sopenharmony_ci	// packet.
51362306a36Sopenharmony_ci	// TODO: investigate the purpose of this 0x80.
51462306a36Sopenharmony_ci	reg = cpu_to_le32((0x80 << 24) |
51562306a36Sopenharmony_ci			  (ff->tx_resources.channel << 5) |
51662306a36Sopenharmony_ci			  (ff->tx_stream.data_block_quadlets));
51762306a36Sopenharmony_ci	err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
51862306a36Sopenharmony_ci				 FF400_TX_PACKET_FORMAT, &reg, sizeof(reg), 0);
51962306a36Sopenharmony_ci	if (err < 0)
52062306a36Sopenharmony_ci		return err;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	// Allow to transmit packets.
52362306a36Sopenharmony_ci	reg = cpu_to_le32(0x00000001);
52462306a36Sopenharmony_ci	return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
52562306a36Sopenharmony_ci				 FF400_ISOC_COMM_START, &reg, sizeof(reg), 0);
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_cistatic void ff400_finish_session(struct snd_ff *ff)
52962306a36Sopenharmony_ci{
53062306a36Sopenharmony_ci	__le32 reg;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	reg = cpu_to_le32(0x80000000);
53362306a36Sopenharmony_ci	snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
53462306a36Sopenharmony_ci			   FF400_ISOC_COMM_STOP, &reg, sizeof(reg), 0);
53562306a36Sopenharmony_ci}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_cistatic void parse_midi_msg(struct snd_ff *ff, u32 quad, unsigned int port)
53862306a36Sopenharmony_ci{
53962306a36Sopenharmony_ci	struct snd_rawmidi_substream *substream = READ_ONCE(ff->tx_midi_substreams[port]);
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	if (substream != NULL) {
54262306a36Sopenharmony_ci		u8 byte = (quad >> (16 * port)) & 0x000000ff;
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci		snd_rawmidi_receive(substream, &byte, 1);
54562306a36Sopenharmony_ci	}
54662306a36Sopenharmony_ci}
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci#define FF400_QUEUE_SIZE	32
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_cistruct ff400_msg_parser {
55162306a36Sopenharmony_ci	struct {
55262306a36Sopenharmony_ci		u32 msg;
55362306a36Sopenharmony_ci		u32 tstamp;
55462306a36Sopenharmony_ci	} msgs[FF400_QUEUE_SIZE];
55562306a36Sopenharmony_ci	size_t push_pos;
55662306a36Sopenharmony_ci	size_t pull_pos;
55762306a36Sopenharmony_ci};
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_cistatic bool ff400_has_msg(struct snd_ff *ff)
56062306a36Sopenharmony_ci{
56162306a36Sopenharmony_ci	struct ff400_msg_parser *parser = ff->msg_parser;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	return (parser->push_pos != parser->pull_pos);
56462306a36Sopenharmony_ci}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci// For Fireface 400, lower 4 bytes of destination address is configured by bit
56762306a36Sopenharmony_ci// flag in quadlet register (little endian) at 0x'0000'801'0051c. Drivers can
56862306a36Sopenharmony_ci// select one of 4 options:
56962306a36Sopenharmony_ci//
57062306a36Sopenharmony_ci// bit flags: offset of destination address
57162306a36Sopenharmony_ci//  - 0x04000000: 0x'....'....'0000'0000
57262306a36Sopenharmony_ci//  - 0x08000000: 0x'....'....'0000'0080
57362306a36Sopenharmony_ci//  - 0x10000000: 0x'....'....'0000'0100
57462306a36Sopenharmony_ci//  - 0x20000000: 0x'....'....'0000'0180
57562306a36Sopenharmony_ci//
57662306a36Sopenharmony_ci// Drivers can suppress the device to transfer asynchronous transactions by
57762306a36Sopenharmony_ci// using below 2 bits.
57862306a36Sopenharmony_ci//  - 0x01000000: suppress transmission
57962306a36Sopenharmony_ci//  - 0x02000000: suppress transmission
58062306a36Sopenharmony_ci//
58162306a36Sopenharmony_ci// Actually, the register is write-only and includes the other options such as
58262306a36Sopenharmony_ci// input attenuation. This driver allocates destination address with '0000'0000
58362306a36Sopenharmony_ci// in its lower offset and expects userspace application to configure the
58462306a36Sopenharmony_ci// register for it.
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci// When the message is for signal level operation, the upper 4 bits in MSB expresses the pair of
58762306a36Sopenharmony_ci// stereo physical port.
58862306a36Sopenharmony_ci// - 0: Microphone input 0/1
58962306a36Sopenharmony_ci// - 1: Line input 0/1
59062306a36Sopenharmony_ci// - [2-4]: Line output 0-5
59162306a36Sopenharmony_ci// - 5: Headphone output 0/1
59262306a36Sopenharmony_ci// - 6: S/PDIF output 0/1
59362306a36Sopenharmony_ci// - [7-10]: ADAT output 0-7
59462306a36Sopenharmony_ci//
59562306a36Sopenharmony_ci// The value of signal level can be detected by mask of 0x00fffc00. For signal level of microphone
59662306a36Sopenharmony_ci// input:
59762306a36Sopenharmony_ci//
59862306a36Sopenharmony_ci// - 0:    0.0 dB
59962306a36Sopenharmony_ci// - 10: +10.0 dB
60062306a36Sopenharmony_ci// - 11: +11.0 dB
60162306a36Sopenharmony_ci// - 12: +12.0 dB
60262306a36Sopenharmony_ci// - ...
60362306a36Sopenharmony_ci// - 63: +63.0 dB:
60462306a36Sopenharmony_ci// - 64: +64.0 dB:
60562306a36Sopenharmony_ci// - 65: +65.0 dB:
60662306a36Sopenharmony_ci//
60762306a36Sopenharmony_ci// For signal level of line input:
60862306a36Sopenharmony_ci//
60962306a36Sopenharmony_ci// - 0:  0.0 dB
61062306a36Sopenharmony_ci// - 1: +0.5 dB
61162306a36Sopenharmony_ci// - 2: +1.0 dB
61262306a36Sopenharmony_ci// - 3: +1.5 dB
61362306a36Sopenharmony_ci// - ...
61462306a36Sopenharmony_ci// - 34: +17.0 dB:
61562306a36Sopenharmony_ci// - 35: +17.5 dB:
61662306a36Sopenharmony_ci// - 36: +18.0 dB:
61762306a36Sopenharmony_ci//
61862306a36Sopenharmony_ci// For signal level of any type of output:
61962306a36Sopenharmony_ci//
62062306a36Sopenharmony_ci// - 63: -infinite
62162306a36Sopenharmony_ci// - 62: -58.0 dB
62262306a36Sopenharmony_ci// - 61: -56.0 dB
62362306a36Sopenharmony_ci// - 60: -54.0 dB
62462306a36Sopenharmony_ci// - 59: -53.0 dB
62562306a36Sopenharmony_ci// - 58: -52.0 dB
62662306a36Sopenharmony_ci// - ...
62762306a36Sopenharmony_ci// - 7: -1.0 dB
62862306a36Sopenharmony_ci// - 6:  0.0 dB
62962306a36Sopenharmony_ci// - 5: +1.0 dB
63062306a36Sopenharmony_ci// - ...
63162306a36Sopenharmony_ci// - 2: +4.0 dB
63262306a36Sopenharmony_ci// - 1: +5.0 dB
63362306a36Sopenharmony_ci// - 0: +6.0 dB
63462306a36Sopenharmony_ci//
63562306a36Sopenharmony_ci// When the message is not for signal level operation, it's for MIDI bytes. When matching to
63662306a36Sopenharmony_ci// FF400_MSG_FLAG_IS_MIDI_PORT_0, one MIDI byte can be detected by mask of 0x000000ff. When
63762306a36Sopenharmony_ci// matching to FF400_MSG_FLAG_IS_MIDI_PORT_1, one MIDI byte can be detected by mask of 0x00ff0000.
63862306a36Sopenharmony_ci#define FF400_MSG_FLAG_IS_SIGNAL_LEVEL		0x04000000
63962306a36Sopenharmony_ci#define  FF400_MSG_FLAG_IS_RIGHT_CHANNEL	0x08000000
64062306a36Sopenharmony_ci#define  FF400_MSG_FLAG_IS_STEREO_PAIRED	0x02000000
64162306a36Sopenharmony_ci#define  FF400_MSG_MASK_STEREO_PAIR		0xf0000000
64262306a36Sopenharmony_ci#define  FF400_MSG_MASK_SIGNAL_LEVEL		0x00fffc00
64362306a36Sopenharmony_ci#define FF400_MSG_FLAG_IS_MIDI_PORT_0		0x00000100
64462306a36Sopenharmony_ci#define  FF400_MSG_MASK_MIDI_PORT_0		0x000000ff
64562306a36Sopenharmony_ci#define FF400_MSG_FLAG_IS_MIDI_PORT_1		0x01000000
64662306a36Sopenharmony_ci#define  FF400_MSG_MASK_MIDI_PORT_1		0x00ff0000
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_cistatic void ff400_handle_msg(struct snd_ff *ff, unsigned int offset, const __le32 *buf,
64962306a36Sopenharmony_ci			     size_t length, u32 tstamp)
65062306a36Sopenharmony_ci{
65162306a36Sopenharmony_ci	bool need_hwdep_wake_up = false;
65262306a36Sopenharmony_ci	int i;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	for (i = 0; i < length / 4; i++) {
65562306a36Sopenharmony_ci		u32 quad = le32_to_cpu(buf[i]);
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci		if (quad & FF400_MSG_FLAG_IS_SIGNAL_LEVEL) {
65862306a36Sopenharmony_ci			struct ff400_msg_parser *parser = ff->msg_parser;
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci			parser->msgs[parser->push_pos].msg = quad;
66162306a36Sopenharmony_ci			parser->msgs[parser->push_pos].tstamp = tstamp;
66262306a36Sopenharmony_ci			++parser->push_pos;
66362306a36Sopenharmony_ci			if (parser->push_pos >= FF400_QUEUE_SIZE)
66462306a36Sopenharmony_ci				parser->push_pos = 0;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci			need_hwdep_wake_up = true;
66762306a36Sopenharmony_ci		} else if (quad & FF400_MSG_FLAG_IS_MIDI_PORT_0) {
66862306a36Sopenharmony_ci			parse_midi_msg(ff, quad, 0);
66962306a36Sopenharmony_ci		} else if (quad & FF400_MSG_FLAG_IS_MIDI_PORT_1) {
67062306a36Sopenharmony_ci			parse_midi_msg(ff, quad, 1);
67162306a36Sopenharmony_ci		}
67262306a36Sopenharmony_ci	}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	if (need_hwdep_wake_up)
67562306a36Sopenharmony_ci		wake_up(&ff->hwdep_wait);
67662306a36Sopenharmony_ci}
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_cistatic long ff400_copy_msg_to_user(struct snd_ff *ff, char __user *buf, long count)
67962306a36Sopenharmony_ci{
68062306a36Sopenharmony_ci	struct snd_firewire_event_ff400_message ev = {
68162306a36Sopenharmony_ci		.type = SNDRV_FIREWIRE_EVENT_FF400_MESSAGE,
68262306a36Sopenharmony_ci		.message_count = 0,
68362306a36Sopenharmony_ci	};
68462306a36Sopenharmony_ci	struct ff400_msg_parser *parser = ff->msg_parser;
68562306a36Sopenharmony_ci	long consumed = 0;
68662306a36Sopenharmony_ci	long ret = 0;
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	if (count < sizeof(ev) || parser->pull_pos == parser->push_pos)
68962306a36Sopenharmony_ci		return 0;
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	count -= sizeof(ev);
69262306a36Sopenharmony_ci	consumed += sizeof(ev);
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	while (count >= sizeof(*parser->msgs) && parser->pull_pos != parser->push_pos) {
69562306a36Sopenharmony_ci		spin_unlock_irq(&ff->lock);
69662306a36Sopenharmony_ci		if (copy_to_user(buf + consumed, parser->msgs + parser->pull_pos,
69762306a36Sopenharmony_ci				 sizeof(*parser->msgs)))
69862306a36Sopenharmony_ci			ret = -EFAULT;
69962306a36Sopenharmony_ci		spin_lock_irq(&ff->lock);
70062306a36Sopenharmony_ci		if (ret)
70162306a36Sopenharmony_ci			return ret;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci		++parser->pull_pos;
70462306a36Sopenharmony_ci		if (parser->pull_pos >= FF400_QUEUE_SIZE)
70562306a36Sopenharmony_ci			parser->pull_pos = 0;
70662306a36Sopenharmony_ci		++ev.message_count;
70762306a36Sopenharmony_ci		count -= sizeof(*parser->msgs);
70862306a36Sopenharmony_ci		consumed += sizeof(*parser->msgs);
70962306a36Sopenharmony_ci	}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	spin_unlock_irq(&ff->lock);
71262306a36Sopenharmony_ci	if (copy_to_user(buf, &ev, sizeof(ev)))
71362306a36Sopenharmony_ci		ret = -EFAULT;
71462306a36Sopenharmony_ci	spin_lock_irq(&ff->lock);
71562306a36Sopenharmony_ci	if (ret)
71662306a36Sopenharmony_ci		return ret;
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	return consumed;
71962306a36Sopenharmony_ci}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ciconst struct snd_ff_protocol snd_ff_protocol_ff400 = {
72262306a36Sopenharmony_ci	.msg_parser_size	= sizeof(struct ff400_msg_parser),
72362306a36Sopenharmony_ci	.has_msg		= ff400_has_msg,
72462306a36Sopenharmony_ci	.copy_msg_to_user	= ff400_copy_msg_to_user,
72562306a36Sopenharmony_ci	.handle_msg		= ff400_handle_msg,
72662306a36Sopenharmony_ci	.fill_midi_msg		= former_fill_midi_msg,
72762306a36Sopenharmony_ci	.get_clock		= former_get_clock,
72862306a36Sopenharmony_ci	.switch_fetching_mode	= former_switch_fetching_mode,
72962306a36Sopenharmony_ci	.allocate_resources	= ff400_allocate_resources,
73062306a36Sopenharmony_ci	.begin_session		= ff400_begin_session,
73162306a36Sopenharmony_ci	.finish_session		= ff400_finish_session,
73262306a36Sopenharmony_ci	.dump_status		= former_dump_status,
73362306a36Sopenharmony_ci};
734