File Index
Files and directories
Sign in
FILE

dice-extension.c

File preview with syntax highlighting.

linux-6.19.14/sound/firewire/dice/dice-extension.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * dice-extension.c - a part of driver for DICE based devices
  4 *
  5 * Copyright (c) 2018 Takashi Sakamoto
  6 */
  7
  8#include "dice.h"
  9
 10/* For TCD2210/2220, TCAT defines extension of application protocol. */
 11
 12#define DICE_EXT_APP_SPACE		0xffffe0200000uLL
 13
 14#define DICE_EXT_APP_CAPS_OFFSET	0x00
 15#define DICE_EXT_APP_CAPS_SIZE		0x04
 16#define DICE_EXT_APP_CMD_OFFSET		0x08
 17#define DICE_EXT_APP_CMD_SIZE		0x0c
 18#define DICE_EXT_APP_MIXER_OFFSET	0x10
 19#define DICE_EXT_APP_MIXER_SIZE		0x14
 20#define DICE_EXT_APP_PEAK_OFFSET	0x18
 21#define DICE_EXT_APP_PEAK_SIZE		0x1c
 22#define DICE_EXT_APP_ROUTER_OFFSET	0x20
 23#define DICE_EXT_APP_ROUTER_SIZE	0x24
 24#define DICE_EXT_APP_STREAM_OFFSET	0x28
 25#define DICE_EXT_APP_STREAM_SIZE	0x2c
 26#define DICE_EXT_APP_CURRENT_OFFSET	0x30
 27#define DICE_EXT_APP_CURRENT_SIZE	0x34
 28#define DICE_EXT_APP_STANDALONE_OFFSET	0x38
 29#define DICE_EXT_APP_STANDALONE_SIZE	0x3c
 30#define DICE_EXT_APP_APPLICATION_OFFSET	0x40
 31#define DICE_EXT_APP_APPLICATION_SIZE	0x44
 32
 33#define EXT_APP_STREAM_TX_NUMBER	0x0000
 34#define EXT_APP_STREAM_RX_NUMBER	0x0004
 35#define EXT_APP_STREAM_ENTRIES		0x0008
 36#define EXT_APP_STREAM_ENTRY_SIZE	0x010c
 37#define  EXT_APP_NUMBER_AUDIO		0x0000
 38#define  EXT_APP_NUMBER_MIDI		0x0004
 39#define  EXT_APP_NAMES			0x0008
 40#define   EXT_APP_NAMES_SIZE		256
 41#define  EXT_APP_AC3			0x0108
 42
 43#define EXT_APP_CONFIG_LOW_ROUTER	0x0000
 44#define EXT_APP_CONFIG_LOW_STREAM	0x1000
 45#define EXT_APP_CONFIG_MIDDLE_ROUTER	0x2000
 46#define EXT_APP_CONFIG_MIDDLE_STREAM	0x3000
 47#define EXT_APP_CONFIG_HIGH_ROUTER	0x4000
 48#define EXT_APP_CONFIG_HIGH_STREAM	0x5000
 49
 50static inline int read_transaction(struct snd_dice *dice, u64 section_addr,
 51				   u32 offset, void *buf, size_t len)
 52{
 53	return snd_fw_transaction(dice->unit,
 54				  len == 4 ? TCODE_READ_QUADLET_REQUEST :
 55					     TCODE_READ_BLOCK_REQUEST,
 56				  section_addr + offset, buf, len, 0);
 57}
 58
 59static int read_stream_entries(struct snd_dice *dice, u64 section_addr,
 60			       u32 base_offset, unsigned int stream_count,
 61			       unsigned int mode,
 62			       unsigned int pcm_channels[MAX_STREAMS][3],
 63			       unsigned int midi_ports[MAX_STREAMS])
 64{
 65	u32 entry_offset;
 66	__be32 reg[2];
 67	int err;
 68	int i;
 69
 70	for (i = 0; i < stream_count; ++i) {
 71		entry_offset = base_offset + i * EXT_APP_STREAM_ENTRY_SIZE;
 72		err = read_transaction(dice, section_addr,
 73				    entry_offset + EXT_APP_NUMBER_AUDIO,
 74				    reg, sizeof(reg));
 75		if (err < 0)
 76			return err;
 77		pcm_channels[i][mode] = be32_to_cpu(reg[0]);
 78		midi_ports[i] = max(midi_ports[i], be32_to_cpu(reg[1]));
 79	}
 80
 81	return 0;
 82}
 83
 84static int detect_stream_formats(struct snd_dice *dice, u64 section_addr)
 85{
 86	u32 base_offset;
 87	__be32 reg[2];
 88	unsigned int stream_count;
 89	int mode;
 90	int err = 0;
 91
 92	for (mode = 0; mode < SND_DICE_RATE_MODE_COUNT; ++mode) {
 93		unsigned int cap;
 94
 95		/*
 96		 * Some models report stream formats at highest mode, however
 97		 * they don't support the mode. Check clock capabilities.
 98		 */
 99		if (mode == 2) {
100			cap = CLOCK_CAP_RATE_176400 | CLOCK_CAP_RATE_192000;
101		} else if (mode == 1) {
102			cap = CLOCK_CAP_RATE_88200 | CLOCK_CAP_RATE_96000;
103		} else {
104			cap = CLOCK_CAP_RATE_32000 | CLOCK_CAP_RATE_44100 |
105			      CLOCK_CAP_RATE_48000;
106		}
107		if (!(cap & dice->clock_caps))
108			continue;
109
110		base_offset = 0x2000 * mode + 0x1000;
111
112		err = read_transaction(dice, section_addr,
113				       base_offset + EXT_APP_STREAM_TX_NUMBER,
114				       &reg, sizeof(reg));
115		if (err < 0)
116			break;
117
118		base_offset += EXT_APP_STREAM_ENTRIES;
119		stream_count = min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS);
120		err = read_stream_entries(dice, section_addr, base_offset,
121					  stream_count, mode,
122					  dice->tx_pcm_chs,
123					  dice->tx_midi_ports);
124		if (err < 0)
125			break;
126
127		base_offset += stream_count * EXT_APP_STREAM_ENTRY_SIZE;
128		stream_count = min_t(unsigned int, be32_to_cpu(reg[1]), MAX_STREAMS);
129		err = read_stream_entries(dice, section_addr, base_offset,
130					  stream_count,
131					  mode, dice->rx_pcm_chs,
132					  dice->rx_midi_ports);
133		if (err < 0)
134			break;
135	}
136
137	return err;
138}
139
140int snd_dice_detect_extension_formats(struct snd_dice *dice)
141{
142	__be32 *pointers;
143	unsigned int i;
144	u64 section_addr;
145	int err;
146
147	pointers = kmalloc_array(9, sizeof(__be32) * 2, GFP_KERNEL);
148	if (pointers == NULL)
149		return -ENOMEM;
150
151	err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
152				 DICE_EXT_APP_SPACE, pointers,
153				 9 * sizeof(__be32) * 2, 0);
154	if (err < 0)
155		goto end;
156
157	/* Check two of them for offset have the same value or not. */
158	for (i = 0; i < 9; ++i) {
159		int j;
160
161		for (j = i + 1; j < 9; ++j) {
162			if (pointers[i * 2] == pointers[j * 2]) {
163				// Fallback to limited functionality.
164				err = -ENXIO;
165				goto end;
166			}
167		}
168	}
169
170	section_addr = DICE_EXT_APP_SPACE + be32_to_cpu(pointers[12]) * 4;
171	err = detect_stream_formats(dice, section_addr);
172end:
173	kfree(pointers);
174	return err;
175}
~/ Read-only file preview.