1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * oxfw_proc.c - a part of driver for OXFW970/971 based devices
4 *
5 * Copyright (c) 2014 Takashi Sakamoto
6 */
7
8#include "./oxfw.h"
9
10static void proc_read_formation(struct snd_info_entry *entry,
11				struct snd_info_buffer *buffer)
12{
13	struct snd_oxfw *oxfw = entry->private_data;
14	struct snd_oxfw_stream_formation formation, curr;
15	u8 *format;
16	char flag;
17	int i, err;
18
19	/* Show input. */
20	err = snd_oxfw_stream_get_current_formation(oxfw,
21						    AVC_GENERAL_PLUG_DIR_IN,
22						    &curr);
23	if (err < 0)
24		return;
25
26	snd_iprintf(buffer, "Input Stream to device:\n");
27	snd_iprintf(buffer, "\tRate\tPCM\tMIDI\n");
28	for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
29		format = oxfw->rx_stream_formats[i];
30		if (format == NULL)
31			continue;
32
33		err = snd_oxfw_stream_parse_format(format, &formation);
34		if (err < 0)
35			continue;
36
37		if (memcmp(&formation, &curr, sizeof(curr)) == 0)
38			flag = '*';
39		else
40			flag = ' ';
41
42		snd_iprintf(buffer, "%c\t%d\t%d\t%d\n", flag,
43			    formation.rate, formation.pcm, formation.midi);
44	}
45
46	if (!oxfw->has_output)
47		return;
48
49	/* Show output. */
50	err = snd_oxfw_stream_get_current_formation(oxfw,
51						    AVC_GENERAL_PLUG_DIR_OUT,
52						    &curr);
53	if (err < 0)
54		return;
55
56	snd_iprintf(buffer, "Output Stream from device:\n");
57	snd_iprintf(buffer, "\tRate\tPCM\tMIDI\n");
58	for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
59		format = oxfw->tx_stream_formats[i];
60		if (format == NULL)
61			continue;
62
63		err = snd_oxfw_stream_parse_format(format, &formation);
64		if (err < 0)
65			continue;
66
67		if (memcmp(&formation, &curr, sizeof(curr)) == 0)
68			flag = '*';
69		else
70			flag = ' ';
71
72		snd_iprintf(buffer, "%c\t%d\t%d\t%d\n", flag,
73			    formation.rate, formation.pcm, formation.midi);
74	}
75}
76
77static void add_node(struct snd_oxfw *oxfw, struct snd_info_entry *root,
78		     const char *name,
79		     void (*op)(struct snd_info_entry *e,
80				struct snd_info_buffer *b))
81{
82	struct snd_info_entry *entry;
83
84	entry = snd_info_create_card_entry(oxfw->card, name, root);
85	if (entry)
86		snd_info_set_text_ops(entry, oxfw, op);
87}
88
89void snd_oxfw_proc_init(struct snd_oxfw *oxfw)
90{
91	struct snd_info_entry *root;
92
93	/*
94	 * All nodes are automatically removed at snd_card_disconnect(),
95	 * by following to link list.
96	 */
97	root = snd_info_create_card_entry(oxfw->card, "firewire",
98					  oxfw->card->proc_root);
99	if (root == NULL)
100		return;
101	root->mode = S_IFDIR | 0555;
102
103	add_node(oxfw, root, "formation", proc_read_formation);
104}
105