cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ff-protocol-latter.c (14655B)


      1// SPDX-License-Identifier: GPL-2.0
      2// ff-protocol-latter - a part of driver for RME Fireface series
      3//
      4// Copyright (c) 2019 Takashi Sakamoto
      5//
      6// Licensed under the terms of the GNU General Public License, version 2.
      7
      8#include <linux/delay.h>
      9
     10#include "ff.h"
     11
     12#define LATTER_STF		0xffff00000004ULL
     13#define LATTER_ISOC_CHANNELS	0xffff00000008ULL
     14#define LATTER_ISOC_START	0xffff0000000cULL
     15#define LATTER_FETCH_MODE	0xffff00000010ULL
     16#define LATTER_SYNC_STATUS	0x0000801c0000ULL
     17
     18// The content of sync status register differs between models.
     19//
     20// Fireface UCX:
     21//  0xf0000000: (unidentified)
     22//  0x0f000000: effective rate of sampling clock
     23//  0x00f00000: detected rate of word clock on BNC interface
     24//  0x000f0000: detected rate of ADAT or S/PDIF on optical interface
     25//  0x0000f000: detected rate of S/PDIF on coaxial interface
     26//  0x00000e00: effective source of sampling clock
     27//    0x00000e00: Internal
     28//    0x00000800: (unidentified)
     29//    0x00000600: Word clock on BNC interface
     30//    0x00000400: ADAT on optical interface
     31//    0x00000200: S/PDIF on coaxial or optical interface
     32//  0x00000100: Optical interface is used for ADAT signal
     33//  0x00000080: (unidentified)
     34//  0x00000040: Synchronized to word clock on BNC interface
     35//  0x00000020: Synchronized to ADAT or S/PDIF on optical interface
     36//  0x00000010: Synchronized to S/PDIF on coaxial interface
     37//  0x00000008: (unidentified)
     38//  0x00000004: Lock word clock on BNC interface
     39//  0x00000002: Lock ADAT or S/PDIF on optical interface
     40//  0x00000001: Lock S/PDIF on coaxial interface
     41//
     42// Fireface 802 (and perhaps UFX):
     43//   0xf0000000: effective rate of sampling clock
     44//   0x0f000000: detected rate of ADAT-B on 2nd optical interface
     45//   0x00f00000: detected rate of ADAT-A on 1st optical interface
     46//   0x000f0000: detected rate of AES/EBU on XLR or coaxial interface
     47//   0x0000f000: detected rate of word clock on BNC interface
     48//   0x00000e00: effective source of sampling clock
     49//     0x00000e00: internal
     50//     0x00000800: ADAT-B
     51//     0x00000600: ADAT-A
     52//     0x00000400: AES/EBU
     53//     0x00000200: Word clock
     54//   0x00000080: Synchronized to ADAT-B on 2nd optical interface
     55//   0x00000040: Synchronized to ADAT-A on 1st optical interface
     56//   0x00000020: Synchronized to AES/EBU on XLR or 2nd optical interface
     57//   0x00000010: Synchronized to word clock on BNC interface
     58//   0x00000008: Lock ADAT-B on 2nd optical interface
     59//   0x00000004: Lock ADAT-A on 1st optical interface
     60//   0x00000002: Lock AES/EBU on XLR or 2nd optical interface
     61//   0x00000001: Lock word clock on BNC interface
     62//
     63// The pattern for rate bits:
     64//   0x00: 32.0 kHz
     65//   0x01: 44.1 kHz
     66//   0x02: 48.0 kHz
     67//   0x04: 64.0 kHz
     68//   0x05: 88.2 kHz
     69//   0x06: 96.0 kHz
     70//   0x08: 128.0 kHz
     71//   0x09: 176.4 kHz
     72//   0x0a: 192.0 kHz
     73static int parse_clock_bits(u32 data, unsigned int *rate,
     74			    enum snd_ff_clock_src *src,
     75			    enum snd_ff_unit_version unit_version)
     76{
     77	static const struct {
     78		unsigned int rate;
     79		u32 flag;
     80	} *rate_entry, rate_entries[] = {
     81		{ 32000,	0x00, },
     82		{ 44100,	0x01, },
     83		{ 48000,	0x02, },
     84		{ 64000,	0x04, },
     85		{ 88200,	0x05, },
     86		{ 96000,	0x06, },
     87		{ 128000,	0x08, },
     88		{ 176400,	0x09, },
     89		{ 192000,	0x0a, },
     90	};
     91	static const struct {
     92		enum snd_ff_clock_src src;
     93		u32 flag;
     94	} *clk_entry, *clk_entries, ucx_clk_entries[] = {
     95		{ SND_FF_CLOCK_SRC_SPDIF,	0x00000200, },
     96		{ SND_FF_CLOCK_SRC_ADAT1,	0x00000400, },
     97		{ SND_FF_CLOCK_SRC_WORD,	0x00000600, },
     98		{ SND_FF_CLOCK_SRC_INTERNAL,	0x00000e00, },
     99	}, ufx_ff802_clk_entries[] = {
    100		{ SND_FF_CLOCK_SRC_WORD,	0x00000200, },
    101		{ SND_FF_CLOCK_SRC_SPDIF,	0x00000400, },
    102		{ SND_FF_CLOCK_SRC_ADAT1,	0x00000600, },
    103		{ SND_FF_CLOCK_SRC_ADAT2,	0x00000800, },
    104		{ SND_FF_CLOCK_SRC_INTERNAL,	0x00000e00, },
    105	};
    106	u32 rate_bits;
    107	unsigned int clk_entry_count;
    108	int i;
    109
    110	if (unit_version == SND_FF_UNIT_VERSION_UCX) {
    111		rate_bits = (data & 0x0f000000) >> 24;
    112		clk_entries = ucx_clk_entries;
    113		clk_entry_count = ARRAY_SIZE(ucx_clk_entries);
    114	} else {
    115		rate_bits = (data & 0xf0000000) >> 28;
    116		clk_entries = ufx_ff802_clk_entries;
    117		clk_entry_count = ARRAY_SIZE(ufx_ff802_clk_entries);
    118	}
    119
    120	for (i = 0; i < ARRAY_SIZE(rate_entries); ++i) {
    121		rate_entry = rate_entries + i;
    122		if (rate_bits == rate_entry->flag) {
    123			*rate = rate_entry->rate;
    124			break;
    125		}
    126	}
    127	if (i == ARRAY_SIZE(rate_entries))
    128		return -EIO;
    129
    130	for (i = 0; i < clk_entry_count; ++i) {
    131		clk_entry = clk_entries + i;
    132		if ((data & 0x000e00) == clk_entry->flag) {
    133			*src = clk_entry->src;
    134			break;
    135		}
    136	}
    137	if (i == clk_entry_count)
    138		return -EIO;
    139
    140	return 0;
    141}
    142
    143static int latter_get_clock(struct snd_ff *ff, unsigned int *rate,
    144			   enum snd_ff_clock_src *src)
    145{
    146	__le32 reg;
    147	u32 data;
    148	int err;
    149
    150	err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
    151				 LATTER_SYNC_STATUS, &reg, sizeof(reg), 0);
    152	if (err < 0)
    153		return err;
    154	data = le32_to_cpu(reg);
    155
    156	return parse_clock_bits(data, rate, src, ff->unit_version);
    157}
    158
    159static int latter_switch_fetching_mode(struct snd_ff *ff, bool enable)
    160{
    161	u32 data;
    162	__le32 reg;
    163
    164	if (enable)
    165		data = 0x00000000;
    166	else
    167		data = 0xffffffff;
    168	reg = cpu_to_le32(data);
    169
    170	return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
    171				  LATTER_FETCH_MODE, &reg, sizeof(reg), 0);
    172}
    173
    174static int latter_allocate_resources(struct snd_ff *ff, unsigned int rate)
    175{
    176	enum snd_ff_stream_mode mode;
    177	unsigned int code;
    178	__le32 reg;
    179	unsigned int count;
    180	int i;
    181	int err;
    182
    183	// Set the number of data blocks transferred in a second.
    184	if (rate % 48000 == 0)
    185		code = 0x04;
    186	else if (rate % 44100 == 0)
    187		code = 0x02;
    188	else if (rate % 32000 == 0)
    189		code = 0x00;
    190	else
    191		return -EINVAL;
    192
    193	if (rate >= 64000 && rate < 128000)
    194		code |= 0x08;
    195	else if (rate >= 128000)
    196		code |= 0x10;
    197
    198	reg = cpu_to_le32(code);
    199	err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
    200				 LATTER_STF, &reg, sizeof(reg), 0);
    201	if (err < 0)
    202		return err;
    203
    204	// Confirm to shift transmission clock.
    205	count = 0;
    206	while (count++ < 10) {
    207		unsigned int curr_rate;
    208		enum snd_ff_clock_src src;
    209
    210		err = latter_get_clock(ff, &curr_rate, &src);
    211		if (err < 0)
    212			return err;
    213
    214		if (curr_rate == rate)
    215			break;
    216	}
    217	if (count > 10)
    218		return -ETIMEDOUT;
    219
    220	for (i = 0; i < ARRAY_SIZE(amdtp_rate_table); ++i) {
    221		if (rate == amdtp_rate_table[i])
    222			break;
    223	}
    224	if (i == ARRAY_SIZE(amdtp_rate_table))
    225		return -EINVAL;
    226
    227	err = snd_ff_stream_get_multiplier_mode(i, &mode);
    228	if (err < 0)
    229		return err;
    230
    231	// Keep resources for in-stream.
    232	ff->tx_resources.channels_mask = 0x00000000000000ffuLL;
    233	err = fw_iso_resources_allocate(&ff->tx_resources,
    234			amdtp_stream_get_max_payload(&ff->tx_stream),
    235			fw_parent_device(ff->unit)->max_speed);
    236	if (err < 0)
    237		return err;
    238
    239	// Keep resources for out-stream.
    240	ff->rx_resources.channels_mask = 0x00000000000000ffuLL;
    241	err = fw_iso_resources_allocate(&ff->rx_resources,
    242			amdtp_stream_get_max_payload(&ff->rx_stream),
    243			fw_parent_device(ff->unit)->max_speed);
    244	if (err < 0)
    245		fw_iso_resources_free(&ff->tx_resources);
    246
    247	return err;
    248}
    249
    250static int latter_begin_session(struct snd_ff *ff, unsigned int rate)
    251{
    252	unsigned int generation = ff->rx_resources.generation;
    253	unsigned int flag;
    254	u32 data;
    255	__le32 reg;
    256	int err;
    257
    258	if (ff->unit_version == SND_FF_UNIT_VERSION_UCX) {
    259		// For Fireface UCX. Always use the maximum number of data
    260		// channels in data block of packet.
    261		if (rate >= 32000 && rate <= 48000)
    262			flag = 0x92;
    263		else if (rate >= 64000 && rate <= 96000)
    264			flag = 0x8e;
    265		else if (rate >= 128000 && rate <= 192000)
    266			flag = 0x8c;
    267		else
    268			return -EINVAL;
    269	} else {
    270		// For Fireface UFX and 802. Due to bandwidth limitation on
    271		// IEEE 1394a (400 Mbps), Analog 1-12 and AES are available
    272		// without any ADAT at quadruple speed.
    273		if (rate >= 32000 && rate <= 48000)
    274			flag = 0x9e;
    275		else if (rate >= 64000 && rate <= 96000)
    276			flag = 0x96;
    277		else if (rate >= 128000 && rate <= 192000)
    278			flag = 0x8e;
    279		else
    280			return -EINVAL;
    281	}
    282
    283	if (generation != fw_parent_device(ff->unit)->card->generation) {
    284		err = fw_iso_resources_update(&ff->tx_resources);
    285		if (err < 0)
    286			return err;
    287
    288		err = fw_iso_resources_update(&ff->rx_resources);
    289		if (err < 0)
    290			return err;
    291	}
    292
    293	data = (ff->tx_resources.channel << 8) | ff->rx_resources.channel;
    294	reg = cpu_to_le32(data);
    295	err = snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
    296				 LATTER_ISOC_CHANNELS, &reg, sizeof(reg), 0);
    297	if (err < 0)
    298		return err;
    299
    300	reg = cpu_to_le32(flag);
    301	return snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
    302				  LATTER_ISOC_START, &reg, sizeof(reg), 0);
    303}
    304
    305static void latter_finish_session(struct snd_ff *ff)
    306{
    307	__le32 reg;
    308
    309	reg = cpu_to_le32(0x00000000);
    310	snd_fw_transaction(ff->unit, TCODE_WRITE_QUADLET_REQUEST,
    311			   LATTER_ISOC_START, &reg, sizeof(reg), 0);
    312}
    313
    314static void latter_dump_status(struct snd_ff *ff, struct snd_info_buffer *buffer)
    315{
    316	static const struct {
    317		char *const label;
    318		u32 locked_mask;
    319		u32 synced_mask;
    320	} *clk_entry, *clk_entries, ucx_clk_entries[] = {
    321		{ "S/PDIF",	0x00000001, 0x00000010, },
    322		{ "ADAT",	0x00000002, 0x00000020, },
    323		{ "WDClk",	0x00000004, 0x00000040, },
    324	}, ufx_ff802_clk_entries[] = {
    325		{ "WDClk",	0x00000001, 0x00000010, },
    326		{ "AES/EBU",	0x00000002, 0x00000020, },
    327		{ "ADAT-A",	0x00000004, 0x00000040, },
    328		{ "ADAT-B",	0x00000008, 0x00000080, },
    329	};
    330	__le32 reg;
    331	u32 data;
    332	unsigned int rate;
    333	enum snd_ff_clock_src src;
    334	const char *label;
    335	unsigned int clk_entry_count;
    336	int i;
    337	int err;
    338
    339	err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST,
    340				 LATTER_SYNC_STATUS, &reg, sizeof(reg), 0);
    341	if (err < 0)
    342		return;
    343	data = le32_to_cpu(reg);
    344
    345	snd_iprintf(buffer, "External source detection:\n");
    346
    347	if (ff->unit_version == SND_FF_UNIT_VERSION_UCX) {
    348		clk_entries = ucx_clk_entries;
    349		clk_entry_count = ARRAY_SIZE(ucx_clk_entries);
    350	} else {
    351		clk_entries = ufx_ff802_clk_entries;
    352		clk_entry_count = ARRAY_SIZE(ufx_ff802_clk_entries);
    353	}
    354
    355	for (i = 0; i < clk_entry_count; ++i) {
    356		clk_entry = clk_entries + i;
    357		snd_iprintf(buffer, "%s: ", clk_entry->label);
    358		if (data & clk_entry->locked_mask) {
    359			if (data & clk_entry->synced_mask)
    360				snd_iprintf(buffer, "sync\n");
    361			else
    362				snd_iprintf(buffer, "lock\n");
    363		} else {
    364			snd_iprintf(buffer, "none\n");
    365		}
    366	}
    367
    368	err = parse_clock_bits(data, &rate, &src, ff->unit_version);
    369	if (err < 0)
    370		return;
    371	label = snd_ff_proc_get_clk_label(src);
    372	if (!label)
    373		return;
    374
    375	snd_iprintf(buffer, "Referred clock: %s %d\n", label, rate);
    376}
    377
    378// NOTE: transactions are transferred within 0x00-0x7f in allocated range of
    379// address. This seems to be for check of discontinuity in receiver side.
    380//
    381// Like Fireface 400, drivers can select one of 4 options for lower 4 bytes of
    382// destination address by bit flags in quadlet register (little endian) at
    383// 0x'ffff'0000'0014:
    384//
    385// bit flags: offset of destination address
    386// - 0x00002000: 0x'....'....'0000'0000
    387// - 0x00004000: 0x'....'....'0000'0080
    388// - 0x00008000: 0x'....'....'0000'0100
    389// - 0x00010000: 0x'....'....'0000'0180
    390//
    391// Drivers can suppress the device to transfer asynchronous transactions by
    392// clear these bit flags.
    393//
    394// Actually, the register is write-only and includes the other settings such as
    395// input attenuation. This driver allocates for the first option
    396// (0x'....'....'0000'0000) and expects userspace application to configure the
    397// register for it.
    398static void latter_handle_midi_msg(struct snd_ff *ff, unsigned int offset,
    399				   __le32 *buf, size_t length)
    400{
    401	u32 data = le32_to_cpu(*buf);
    402	unsigned int index = (data & 0x000000f0) >> 4;
    403	u8 byte[3];
    404	struct snd_rawmidi_substream *substream;
    405	unsigned int len;
    406
    407	if (index >= ff->spec->midi_in_ports)
    408		return;
    409
    410	switch (data & 0x0000000f) {
    411	case 0x00000008:
    412	case 0x00000009:
    413	case 0x0000000a:
    414	case 0x0000000b:
    415	case 0x0000000e:
    416		len = 3;
    417		break;
    418	case 0x0000000c:
    419	case 0x0000000d:
    420		len = 2;
    421		break;
    422	default:
    423		len = data & 0x00000003;
    424		if (len == 0)
    425			len = 3;
    426		break;
    427	}
    428
    429	byte[0] = (data & 0x0000ff00) >> 8;
    430	byte[1] = (data & 0x00ff0000) >> 16;
    431	byte[2] = (data & 0xff000000) >> 24;
    432
    433	substream = READ_ONCE(ff->tx_midi_substreams[index]);
    434	if (substream)
    435		snd_rawmidi_receive(substream, byte, len);
    436}
    437
    438/*
    439 * When return minus value, given argument is not MIDI status.
    440 * When return 0, given argument is a beginning of system exclusive.
    441 * When return the others, given argument is MIDI data.
    442 */
    443static inline int calculate_message_bytes(u8 status)
    444{
    445	switch (status) {
    446	case 0xf6:	/* Tune request. */
    447	case 0xf8:	/* Timing clock. */
    448	case 0xfa:	/* Start. */
    449	case 0xfb:	/* Continue. */
    450	case 0xfc:	/* Stop. */
    451	case 0xfe:	/* Active sensing. */
    452	case 0xff:	/* System reset. */
    453		return 1;
    454	case 0xf1:	/* MIDI time code quarter frame. */
    455	case 0xf3:	/* Song select. */
    456		return 2;
    457	case 0xf2:	/* Song position pointer. */
    458		return 3;
    459	case 0xf0:	/* Exclusive. */
    460		return 0;
    461	case 0xf7:	/* End of exclusive. */
    462		break;
    463	case 0xf4:	/* Undefined. */
    464	case 0xf5:	/* Undefined. */
    465	case 0xf9:	/* Undefined. */
    466	case 0xfd:	/* Undefined. */
    467		break;
    468	default:
    469		switch (status & 0xf0) {
    470		case 0x80:	/* Note on. */
    471		case 0x90:	/* Note off. */
    472		case 0xa0:	/* Polyphonic key pressure. */
    473		case 0xb0:	/* Control change and Mode change. */
    474		case 0xe0:	/* Pitch bend change. */
    475			return 3;
    476		case 0xc0:	/* Program change. */
    477		case 0xd0:	/* Channel pressure. */
    478			return 2;
    479		default:
    480		break;
    481		}
    482	break;
    483	}
    484
    485	return -EINVAL;
    486}
    487
    488static int latter_fill_midi_msg(struct snd_ff *ff,
    489				struct snd_rawmidi_substream *substream,
    490				unsigned int port)
    491{
    492	u32 data = {0};
    493	u8 *buf = (u8 *)&data;
    494	int consumed;
    495
    496	buf[0] = port << 4;
    497	consumed = snd_rawmidi_transmit_peek(substream, buf + 1, 3);
    498	if (consumed <= 0)
    499		return consumed;
    500
    501	if (!ff->on_sysex[port]) {
    502		if (buf[1] != 0xf0) {
    503			if (consumed < calculate_message_bytes(buf[1]))
    504				return 0;
    505		} else {
    506			// The beginning of exclusives.
    507			ff->on_sysex[port] = true;
    508		}
    509
    510		buf[0] |= consumed;
    511	} else {
    512		if (buf[1] != 0xf7) {
    513			if (buf[2] == 0xf7 || buf[3] == 0xf7) {
    514				// Transfer end code at next time.
    515				consumed -= 1;
    516			}
    517
    518			buf[0] |= consumed;
    519		} else {
    520			// The end of exclusives.
    521			ff->on_sysex[port] = false;
    522			consumed = 1;
    523			buf[0] |= 0x0f;
    524		}
    525	}
    526
    527	ff->msg_buf[port][0] = cpu_to_le32(data);
    528	ff->rx_bytes[port] = consumed;
    529
    530	return 1;
    531}
    532
    533const struct snd_ff_protocol snd_ff_protocol_latter = {
    534	.handle_midi_msg	= latter_handle_midi_msg,
    535	.fill_midi_msg		= latter_fill_midi_msg,
    536	.get_clock		= latter_get_clock,
    537	.switch_fetching_mode	= latter_switch_fetching_mode,
    538	.allocate_resources	= latter_allocate_resources,
    539	.begin_session		= latter_begin_session,
    540	.finish_session		= latter_finish_session,
    541	.dump_status		= latter_dump_status,
    542};