xref: /OK3568_Linux_fs/kernel/sound/firewire/dice/dice-proc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * dice_proc.c - a part of driver for Dice based devices
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (c) Clemens Ladisch
6*4882a593Smuzhiyun  * Copyright (c) 2014 Takashi Sakamoto
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include "dice.h"
10*4882a593Smuzhiyun 
dice_proc_read_mem(struct snd_dice * dice,void * buffer,unsigned int offset_q,unsigned int quadlets)11*4882a593Smuzhiyun static int dice_proc_read_mem(struct snd_dice *dice, void *buffer,
12*4882a593Smuzhiyun 			      unsigned int offset_q, unsigned int quadlets)
13*4882a593Smuzhiyun {
14*4882a593Smuzhiyun 	unsigned int i;
15*4882a593Smuzhiyun 	int err;
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun 	err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
18*4882a593Smuzhiyun 				 DICE_PRIVATE_SPACE + 4 * offset_q,
19*4882a593Smuzhiyun 				 buffer, 4 * quadlets, 0);
20*4882a593Smuzhiyun 	if (err < 0)
21*4882a593Smuzhiyun 		return err;
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun 	for (i = 0; i < quadlets; ++i)
24*4882a593Smuzhiyun 		be32_to_cpus(&((u32 *)buffer)[i]);
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun 	return 0;
27*4882a593Smuzhiyun }
28*4882a593Smuzhiyun 
str_from_array(const char * const strs[],unsigned int count,unsigned int i)29*4882a593Smuzhiyun static const char *str_from_array(const char *const strs[], unsigned int count,
30*4882a593Smuzhiyun 				  unsigned int i)
31*4882a593Smuzhiyun {
32*4882a593Smuzhiyun 	if (i < count)
33*4882a593Smuzhiyun 		return strs[i];
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun 	return "(unknown)";
36*4882a593Smuzhiyun }
37*4882a593Smuzhiyun 
dice_proc_fixup_string(char * s,unsigned int size)38*4882a593Smuzhiyun static void dice_proc_fixup_string(char *s, unsigned int size)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun 	unsigned int i;
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun 	for (i = 0; i < size; i += 4)
43*4882a593Smuzhiyun 		cpu_to_le32s((u32 *)(s + i));
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	for (i = 0; i < size - 2; ++i) {
46*4882a593Smuzhiyun 		if (s[i] == '\0')
47*4882a593Smuzhiyun 			return;
48*4882a593Smuzhiyun 		if (s[i] == '\\' && s[i + 1] == '\\') {
49*4882a593Smuzhiyun 			s[i + 2] = '\0';
50*4882a593Smuzhiyun 			return;
51*4882a593Smuzhiyun 		}
52*4882a593Smuzhiyun 	}
53*4882a593Smuzhiyun 	s[size - 1] = '\0';
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun 
dice_proc_read(struct snd_info_entry * entry,struct snd_info_buffer * buffer)56*4882a593Smuzhiyun static void dice_proc_read(struct snd_info_entry *entry,
57*4882a593Smuzhiyun 			   struct snd_info_buffer *buffer)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun 	static const char *const section_names[5] = {
60*4882a593Smuzhiyun 		"global", "tx", "rx", "ext_sync", "unused2"
61*4882a593Smuzhiyun 	};
62*4882a593Smuzhiyun 	static const char *const clock_sources[] = {
63*4882a593Smuzhiyun 		"aes1", "aes2", "aes3", "aes4", "aes", "adat", "tdif",
64*4882a593Smuzhiyun 		"wc", "arx1", "arx2", "arx3", "arx4", "internal"
65*4882a593Smuzhiyun 	};
66*4882a593Smuzhiyun 	static const char *const rates[] = {
67*4882a593Smuzhiyun 		"32000", "44100", "48000", "88200", "96000", "176400", "192000",
68*4882a593Smuzhiyun 		"any low", "any mid", "any high", "none"
69*4882a593Smuzhiyun 	};
70*4882a593Smuzhiyun 	struct snd_dice *dice = entry->private_data;
71*4882a593Smuzhiyun 	u32 sections[ARRAY_SIZE(section_names) * 2];
72*4882a593Smuzhiyun 	struct {
73*4882a593Smuzhiyun 		u32 number;
74*4882a593Smuzhiyun 		u32 size;
75*4882a593Smuzhiyun 	} tx_rx_header;
76*4882a593Smuzhiyun 	union {
77*4882a593Smuzhiyun 		struct {
78*4882a593Smuzhiyun 			u32 owner_hi, owner_lo;
79*4882a593Smuzhiyun 			u32 notification;
80*4882a593Smuzhiyun 			char nick_name[NICK_NAME_SIZE];
81*4882a593Smuzhiyun 			u32 clock_select;
82*4882a593Smuzhiyun 			u32 enable;
83*4882a593Smuzhiyun 			u32 status;
84*4882a593Smuzhiyun 			u32 extended_status;
85*4882a593Smuzhiyun 			u32 sample_rate;
86*4882a593Smuzhiyun 			u32 version;
87*4882a593Smuzhiyun 			u32 clock_caps;
88*4882a593Smuzhiyun 			char clock_source_names[CLOCK_SOURCE_NAMES_SIZE];
89*4882a593Smuzhiyun 		} global;
90*4882a593Smuzhiyun 		struct {
91*4882a593Smuzhiyun 			u32 iso;
92*4882a593Smuzhiyun 			u32 number_audio;
93*4882a593Smuzhiyun 			u32 number_midi;
94*4882a593Smuzhiyun 			u32 speed;
95*4882a593Smuzhiyun 			char names[TX_NAMES_SIZE];
96*4882a593Smuzhiyun 			u32 ac3_caps;
97*4882a593Smuzhiyun 			u32 ac3_enable;
98*4882a593Smuzhiyun 		} tx;
99*4882a593Smuzhiyun 		struct {
100*4882a593Smuzhiyun 			u32 iso;
101*4882a593Smuzhiyun 			u32 seq_start;
102*4882a593Smuzhiyun 			u32 number_audio;
103*4882a593Smuzhiyun 			u32 number_midi;
104*4882a593Smuzhiyun 			char names[RX_NAMES_SIZE];
105*4882a593Smuzhiyun 			u32 ac3_caps;
106*4882a593Smuzhiyun 			u32 ac3_enable;
107*4882a593Smuzhiyun 		} rx;
108*4882a593Smuzhiyun 		struct {
109*4882a593Smuzhiyun 			u32 clock_source;
110*4882a593Smuzhiyun 			u32 locked;
111*4882a593Smuzhiyun 			u32 rate;
112*4882a593Smuzhiyun 			u32 adat_user_data;
113*4882a593Smuzhiyun 		} ext_sync;
114*4882a593Smuzhiyun 	} buf;
115*4882a593Smuzhiyun 	unsigned int quadlets, stream, i;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	if (dice_proc_read_mem(dice, sections, 0, ARRAY_SIZE(sections)) < 0)
118*4882a593Smuzhiyun 		return;
119*4882a593Smuzhiyun 	snd_iprintf(buffer, "sections:\n");
120*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(section_names); ++i)
121*4882a593Smuzhiyun 		snd_iprintf(buffer, "  %s: offset %u, size %u\n",
122*4882a593Smuzhiyun 			    section_names[i],
123*4882a593Smuzhiyun 			    sections[i * 2], sections[i * 2 + 1]);
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	quadlets = min_t(u32, sections[1], sizeof(buf.global) / 4);
126*4882a593Smuzhiyun 	if (dice_proc_read_mem(dice, &buf.global, sections[0], quadlets) < 0)
127*4882a593Smuzhiyun 		return;
128*4882a593Smuzhiyun 	snd_iprintf(buffer, "global:\n");
129*4882a593Smuzhiyun 	snd_iprintf(buffer, "  owner: %04x:%04x%08x\n",
130*4882a593Smuzhiyun 		    buf.global.owner_hi >> 16,
131*4882a593Smuzhiyun 		    buf.global.owner_hi & 0xffff, buf.global.owner_lo);
132*4882a593Smuzhiyun 	snd_iprintf(buffer, "  notification: %08x\n", buf.global.notification);
133*4882a593Smuzhiyun 	dice_proc_fixup_string(buf.global.nick_name, NICK_NAME_SIZE);
134*4882a593Smuzhiyun 	snd_iprintf(buffer, "  nick name: %s\n", buf.global.nick_name);
135*4882a593Smuzhiyun 	snd_iprintf(buffer, "  clock select: %s %s\n",
136*4882a593Smuzhiyun 		    str_from_array(clock_sources, ARRAY_SIZE(clock_sources),
137*4882a593Smuzhiyun 				   buf.global.clock_select & CLOCK_SOURCE_MASK),
138*4882a593Smuzhiyun 		    str_from_array(rates, ARRAY_SIZE(rates),
139*4882a593Smuzhiyun 				   (buf.global.clock_select & CLOCK_RATE_MASK)
140*4882a593Smuzhiyun 				   >> CLOCK_RATE_SHIFT));
141*4882a593Smuzhiyun 	snd_iprintf(buffer, "  enable: %u\n", buf.global.enable);
142*4882a593Smuzhiyun 	snd_iprintf(buffer, "  status: %slocked %s\n",
143*4882a593Smuzhiyun 		    buf.global.status & STATUS_SOURCE_LOCKED ? "" : "un",
144*4882a593Smuzhiyun 		    str_from_array(rates, ARRAY_SIZE(rates),
145*4882a593Smuzhiyun 				   (buf.global.status &
146*4882a593Smuzhiyun 				    STATUS_NOMINAL_RATE_MASK)
147*4882a593Smuzhiyun 				   >> CLOCK_RATE_SHIFT));
148*4882a593Smuzhiyun 	snd_iprintf(buffer, "  ext status: %08x\n", buf.global.extended_status);
149*4882a593Smuzhiyun 	snd_iprintf(buffer, "  sample rate: %u\n", buf.global.sample_rate);
150*4882a593Smuzhiyun 	if (quadlets >= 90) {
151*4882a593Smuzhiyun 		snd_iprintf(buffer, "  version: %u.%u.%u.%u\n",
152*4882a593Smuzhiyun 			    (buf.global.version >> 24) & 0xff,
153*4882a593Smuzhiyun 			    (buf.global.version >> 16) & 0xff,
154*4882a593Smuzhiyun 			    (buf.global.version >>  8) & 0xff,
155*4882a593Smuzhiyun 			    (buf.global.version >>  0) & 0xff);
156*4882a593Smuzhiyun 		snd_iprintf(buffer, "  clock caps:");
157*4882a593Smuzhiyun 		for (i = 0; i <= 6; ++i)
158*4882a593Smuzhiyun 			if (buf.global.clock_caps & (1 << i))
159*4882a593Smuzhiyun 				snd_iprintf(buffer, " %s", rates[i]);
160*4882a593Smuzhiyun 		for (i = 0; i <= 12; ++i)
161*4882a593Smuzhiyun 			if (buf.global.clock_caps & (1 << (16 + i)))
162*4882a593Smuzhiyun 				snd_iprintf(buffer, " %s", clock_sources[i]);
163*4882a593Smuzhiyun 		snd_iprintf(buffer, "\n");
164*4882a593Smuzhiyun 		dice_proc_fixup_string(buf.global.clock_source_names,
165*4882a593Smuzhiyun 				       CLOCK_SOURCE_NAMES_SIZE);
166*4882a593Smuzhiyun 		snd_iprintf(buffer, "  clock source names: %s\n",
167*4882a593Smuzhiyun 			    buf.global.clock_source_names);
168*4882a593Smuzhiyun 	}
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	if (dice_proc_read_mem(dice, &tx_rx_header, sections[2], 2) < 0)
171*4882a593Smuzhiyun 		return;
172*4882a593Smuzhiyun 	quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.tx) / 4);
173*4882a593Smuzhiyun 	for (stream = 0; stream < tx_rx_header.number; ++stream) {
174*4882a593Smuzhiyun 		if (dice_proc_read_mem(dice, &buf.tx, sections[2] + 2 +
175*4882a593Smuzhiyun 				       stream * tx_rx_header.size,
176*4882a593Smuzhiyun 				       quadlets) < 0)
177*4882a593Smuzhiyun 			break;
178*4882a593Smuzhiyun 		snd_iprintf(buffer, "tx %u:\n", stream);
179*4882a593Smuzhiyun 		snd_iprintf(buffer, "  iso channel: %d\n", (int)buf.tx.iso);
180*4882a593Smuzhiyun 		snd_iprintf(buffer, "  audio channels: %u\n",
181*4882a593Smuzhiyun 			    buf.tx.number_audio);
182*4882a593Smuzhiyun 		snd_iprintf(buffer, "  midi ports: %u\n", buf.tx.number_midi);
183*4882a593Smuzhiyun 		snd_iprintf(buffer, "  speed: S%u\n", 100u << buf.tx.speed);
184*4882a593Smuzhiyun 		if (quadlets >= 68) {
185*4882a593Smuzhiyun 			dice_proc_fixup_string(buf.tx.names, TX_NAMES_SIZE);
186*4882a593Smuzhiyun 			snd_iprintf(buffer, "  names: %s\n", buf.tx.names);
187*4882a593Smuzhiyun 		}
188*4882a593Smuzhiyun 		if (quadlets >= 70) {
189*4882a593Smuzhiyun 			snd_iprintf(buffer, "  ac3 caps: %08x\n",
190*4882a593Smuzhiyun 				    buf.tx.ac3_caps);
191*4882a593Smuzhiyun 			snd_iprintf(buffer, "  ac3 enable: %08x\n",
192*4882a593Smuzhiyun 				    buf.tx.ac3_enable);
193*4882a593Smuzhiyun 		}
194*4882a593Smuzhiyun 	}
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	if (dice_proc_read_mem(dice, &tx_rx_header, sections[4], 2) < 0)
197*4882a593Smuzhiyun 		return;
198*4882a593Smuzhiyun 	quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.rx) / 4);
199*4882a593Smuzhiyun 	for (stream = 0; stream < tx_rx_header.number; ++stream) {
200*4882a593Smuzhiyun 		if (dice_proc_read_mem(dice, &buf.rx, sections[4] + 2 +
201*4882a593Smuzhiyun 				       stream * tx_rx_header.size,
202*4882a593Smuzhiyun 				       quadlets) < 0)
203*4882a593Smuzhiyun 			break;
204*4882a593Smuzhiyun 		snd_iprintf(buffer, "rx %u:\n", stream);
205*4882a593Smuzhiyun 		snd_iprintf(buffer, "  iso channel: %d\n", (int)buf.rx.iso);
206*4882a593Smuzhiyun 		snd_iprintf(buffer, "  sequence start: %u\n", buf.rx.seq_start);
207*4882a593Smuzhiyun 		snd_iprintf(buffer, "  audio channels: %u\n",
208*4882a593Smuzhiyun 			    buf.rx.number_audio);
209*4882a593Smuzhiyun 		snd_iprintf(buffer, "  midi ports: %u\n", buf.rx.number_midi);
210*4882a593Smuzhiyun 		if (quadlets >= 68) {
211*4882a593Smuzhiyun 			dice_proc_fixup_string(buf.rx.names, RX_NAMES_SIZE);
212*4882a593Smuzhiyun 			snd_iprintf(buffer, "  names: %s\n", buf.rx.names);
213*4882a593Smuzhiyun 		}
214*4882a593Smuzhiyun 		if (quadlets >= 70) {
215*4882a593Smuzhiyun 			snd_iprintf(buffer, "  ac3 caps: %08x\n",
216*4882a593Smuzhiyun 				    buf.rx.ac3_caps);
217*4882a593Smuzhiyun 			snd_iprintf(buffer, "  ac3 enable: %08x\n",
218*4882a593Smuzhiyun 				    buf.rx.ac3_enable);
219*4882a593Smuzhiyun 		}
220*4882a593Smuzhiyun 	}
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	quadlets = min_t(u32, sections[7], sizeof(buf.ext_sync) / 4);
223*4882a593Smuzhiyun 	if (quadlets >= 4) {
224*4882a593Smuzhiyun 		if (dice_proc_read_mem(dice, &buf.ext_sync,
225*4882a593Smuzhiyun 				       sections[6], 4) < 0)
226*4882a593Smuzhiyun 			return;
227*4882a593Smuzhiyun 		snd_iprintf(buffer, "ext status:\n");
228*4882a593Smuzhiyun 		snd_iprintf(buffer, "  clock source: %s\n",
229*4882a593Smuzhiyun 			    str_from_array(clock_sources,
230*4882a593Smuzhiyun 					   ARRAY_SIZE(clock_sources),
231*4882a593Smuzhiyun 					   buf.ext_sync.clock_source));
232*4882a593Smuzhiyun 		snd_iprintf(buffer, "  locked: %u\n", buf.ext_sync.locked);
233*4882a593Smuzhiyun 		snd_iprintf(buffer, "  rate: %s\n",
234*4882a593Smuzhiyun 			    str_from_array(rates, ARRAY_SIZE(rates),
235*4882a593Smuzhiyun 					   buf.ext_sync.rate));
236*4882a593Smuzhiyun 		snd_iprintf(buffer, "  adat user data: ");
237*4882a593Smuzhiyun 		if (buf.ext_sync.adat_user_data & ADAT_USER_DATA_NO_DATA)
238*4882a593Smuzhiyun 			snd_iprintf(buffer, "-\n");
239*4882a593Smuzhiyun 		else
240*4882a593Smuzhiyun 			snd_iprintf(buffer, "%x\n",
241*4882a593Smuzhiyun 				    buf.ext_sync.adat_user_data);
242*4882a593Smuzhiyun 	}
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun 
dice_proc_read_formation(struct snd_info_entry * entry,struct snd_info_buffer * buffer)245*4882a593Smuzhiyun static void dice_proc_read_formation(struct snd_info_entry *entry,
246*4882a593Smuzhiyun 				     struct snd_info_buffer *buffer)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun 	static const char *const rate_labels[] = {
249*4882a593Smuzhiyun 		[SND_DICE_RATE_MODE_LOW]	= "low",
250*4882a593Smuzhiyun 		[SND_DICE_RATE_MODE_MIDDLE]	= "middle",
251*4882a593Smuzhiyun 		[SND_DICE_RATE_MODE_HIGH]	= "high",
252*4882a593Smuzhiyun 	};
253*4882a593Smuzhiyun 	struct snd_dice *dice = entry->private_data;
254*4882a593Smuzhiyun 	int i, j;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	snd_iprintf(buffer, "Output stream from unit:\n");
257*4882a593Smuzhiyun 	for (i = 0; i < SND_DICE_RATE_MODE_COUNT; ++i)
258*4882a593Smuzhiyun 		snd_iprintf(buffer, "\t%s", rate_labels[i]);
259*4882a593Smuzhiyun 	snd_iprintf(buffer, "\tMIDI\n");
260*4882a593Smuzhiyun 	for (i = 0; i < MAX_STREAMS; ++i) {
261*4882a593Smuzhiyun 		snd_iprintf(buffer, "Tx %u:", i);
262*4882a593Smuzhiyun 		for (j = 0; j < SND_DICE_RATE_MODE_COUNT; ++j)
263*4882a593Smuzhiyun 			snd_iprintf(buffer, "\t%u", dice->tx_pcm_chs[i][j]);
264*4882a593Smuzhiyun 		snd_iprintf(buffer, "\t%u\n", dice->tx_midi_ports[i]);
265*4882a593Smuzhiyun 	}
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	snd_iprintf(buffer, "Input stream to unit:\n");
268*4882a593Smuzhiyun 	for (i = 0; i < SND_DICE_RATE_MODE_COUNT; ++i)
269*4882a593Smuzhiyun 		snd_iprintf(buffer, "\t%s", rate_labels[i]);
270*4882a593Smuzhiyun 	snd_iprintf(buffer, "\n");
271*4882a593Smuzhiyun 	for (i = 0; i < MAX_STREAMS; ++i) {
272*4882a593Smuzhiyun 		snd_iprintf(buffer, "Rx %u:", i);
273*4882a593Smuzhiyun 		for (j = 0; j < SND_DICE_RATE_MODE_COUNT; ++j)
274*4882a593Smuzhiyun 			snd_iprintf(buffer, "\t%u", dice->rx_pcm_chs[i][j]);
275*4882a593Smuzhiyun 		snd_iprintf(buffer, "\t%u\n", dice->rx_midi_ports[i]);
276*4882a593Smuzhiyun 	}
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun 
add_node(struct snd_dice * dice,struct snd_info_entry * root,const char * name,void (* op)(struct snd_info_entry * entry,struct snd_info_buffer * buffer))279*4882a593Smuzhiyun static void add_node(struct snd_dice *dice, struct snd_info_entry *root,
280*4882a593Smuzhiyun 		     const char *name,
281*4882a593Smuzhiyun 		     void (*op)(struct snd_info_entry *entry,
282*4882a593Smuzhiyun 				struct snd_info_buffer *buffer))
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun 	struct snd_info_entry *entry;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	entry = snd_info_create_card_entry(dice->card, name, root);
287*4882a593Smuzhiyun 	if (entry)
288*4882a593Smuzhiyun 		snd_info_set_text_ops(entry, dice, op);
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun 
snd_dice_create_proc(struct snd_dice * dice)291*4882a593Smuzhiyun void snd_dice_create_proc(struct snd_dice *dice)
292*4882a593Smuzhiyun {
293*4882a593Smuzhiyun 	struct snd_info_entry *root;
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	/*
296*4882a593Smuzhiyun 	 * All nodes are automatically removed at snd_card_disconnect(),
297*4882a593Smuzhiyun 	 * by following to link list.
298*4882a593Smuzhiyun 	 */
299*4882a593Smuzhiyun 	root = snd_info_create_card_entry(dice->card, "firewire",
300*4882a593Smuzhiyun 					  dice->card->proc_root);
301*4882a593Smuzhiyun 	if (!root)
302*4882a593Smuzhiyun 		return;
303*4882a593Smuzhiyun 	root->mode = S_IFDIR | 0555;
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 	add_node(dice, root, "dice", dice_proc_read);
306*4882a593Smuzhiyun 	add_node(dice, root, "formation", dice_proc_read_formation);
307*4882a593Smuzhiyun }
308