1*da607e19SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
26a22683eSTakashi Sakamoto /*
36a22683eSTakashi Sakamoto * fireworks_proc.c - a part of driver for Fireworks based devices
46a22683eSTakashi Sakamoto *
56a22683eSTakashi Sakamoto * Copyright (c) 2009-2010 Clemens Ladisch
66a22683eSTakashi Sakamoto * Copyright (c) 2013-2014 Takashi Sakamoto
76a22683eSTakashi Sakamoto */
86a22683eSTakashi Sakamoto
96a22683eSTakashi Sakamoto #include "./fireworks.h"
106a22683eSTakashi Sakamoto
116a22683eSTakashi Sakamoto static inline const char*
get_phys_name(struct snd_efw_phys_grp * grp,bool input)126a22683eSTakashi Sakamoto get_phys_name(struct snd_efw_phys_grp *grp, bool input)
136a22683eSTakashi Sakamoto {
14782fbec7STakashi Sakamoto static const char *const ch_type[] = {
156a22683eSTakashi Sakamoto "Analog", "S/PDIF", "ADAT", "S/PDIF or ADAT", "Mirroring",
166a22683eSTakashi Sakamoto "Headphones", "I2S", "Guitar", "Pirzo Guitar", "Guitar String",
176a22683eSTakashi Sakamoto };
186a22683eSTakashi Sakamoto
196a22683eSTakashi Sakamoto if (grp->type < ARRAY_SIZE(ch_type))
206a22683eSTakashi Sakamoto return ch_type[grp->type];
216a22683eSTakashi Sakamoto else if (input)
226a22683eSTakashi Sakamoto return "Input";
236a22683eSTakashi Sakamoto else
246a22683eSTakashi Sakamoto return "Output";
256a22683eSTakashi Sakamoto }
266a22683eSTakashi Sakamoto
276a22683eSTakashi Sakamoto static void
proc_read_hwinfo(struct snd_info_entry * entry,struct snd_info_buffer * buffer)286a22683eSTakashi Sakamoto proc_read_hwinfo(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
296a22683eSTakashi Sakamoto {
306a22683eSTakashi Sakamoto struct snd_efw *efw = entry->private_data;
316a22683eSTakashi Sakamoto unsigned short i;
326a22683eSTakashi Sakamoto struct snd_efw_hwinfo *hwinfo;
336a22683eSTakashi Sakamoto
346a22683eSTakashi Sakamoto hwinfo = kmalloc(sizeof(struct snd_efw_hwinfo), GFP_KERNEL);
356a22683eSTakashi Sakamoto if (hwinfo == NULL)
366a22683eSTakashi Sakamoto return;
376a22683eSTakashi Sakamoto
386a22683eSTakashi Sakamoto if (snd_efw_command_get_hwinfo(efw, hwinfo) < 0)
396a22683eSTakashi Sakamoto goto end;
406a22683eSTakashi Sakamoto
416a22683eSTakashi Sakamoto snd_iprintf(buffer, "guid_hi: 0x%X\n", hwinfo->guid_hi);
426a22683eSTakashi Sakamoto snd_iprintf(buffer, "guid_lo: 0x%X\n", hwinfo->guid_lo);
436a22683eSTakashi Sakamoto snd_iprintf(buffer, "type: 0x%X\n", hwinfo->type);
446a22683eSTakashi Sakamoto snd_iprintf(buffer, "version: 0x%X\n", hwinfo->version);
456a22683eSTakashi Sakamoto snd_iprintf(buffer, "vendor_name: %s\n", hwinfo->vendor_name);
466a22683eSTakashi Sakamoto snd_iprintf(buffer, "model_name: %s\n", hwinfo->model_name);
476a22683eSTakashi Sakamoto
486a22683eSTakashi Sakamoto snd_iprintf(buffer, "dsp_version: 0x%X\n", hwinfo->dsp_version);
496a22683eSTakashi Sakamoto snd_iprintf(buffer, "arm_version: 0x%X\n", hwinfo->arm_version);
506a22683eSTakashi Sakamoto snd_iprintf(buffer, "fpga_version: 0x%X\n", hwinfo->fpga_version);
516a22683eSTakashi Sakamoto
526a22683eSTakashi Sakamoto snd_iprintf(buffer, "flags: 0x%X\n", hwinfo->flags);
536a22683eSTakashi Sakamoto
546a22683eSTakashi Sakamoto snd_iprintf(buffer, "max_sample_rate: 0x%X\n", hwinfo->max_sample_rate);
556a22683eSTakashi Sakamoto snd_iprintf(buffer, "min_sample_rate: 0x%X\n", hwinfo->min_sample_rate);
566a22683eSTakashi Sakamoto snd_iprintf(buffer, "supported_clock: 0x%X\n",
576a22683eSTakashi Sakamoto hwinfo->supported_clocks);
586a22683eSTakashi Sakamoto
596a22683eSTakashi Sakamoto snd_iprintf(buffer, "phys out: 0x%X\n", hwinfo->phys_out);
606a22683eSTakashi Sakamoto snd_iprintf(buffer, "phys in: 0x%X\n", hwinfo->phys_in);
616a22683eSTakashi Sakamoto
626a22683eSTakashi Sakamoto snd_iprintf(buffer, "phys in grps: 0x%X\n",
636a22683eSTakashi Sakamoto hwinfo->phys_in_grp_count);
646a22683eSTakashi Sakamoto for (i = 0; i < hwinfo->phys_in_grp_count; i++) {
656a22683eSTakashi Sakamoto snd_iprintf(buffer,
6630225ed5STakashi Sakamoto "phys in grp[%d]: type 0x%X, count 0x%X\n",
676a22683eSTakashi Sakamoto i, hwinfo->phys_out_grps[i].type,
686a22683eSTakashi Sakamoto hwinfo->phys_out_grps[i].count);
696a22683eSTakashi Sakamoto }
706a22683eSTakashi Sakamoto
716a22683eSTakashi Sakamoto snd_iprintf(buffer, "phys out grps: 0x%X\n",
726a22683eSTakashi Sakamoto hwinfo->phys_out_grp_count);
736a22683eSTakashi Sakamoto for (i = 0; i < hwinfo->phys_out_grp_count; i++) {
746a22683eSTakashi Sakamoto snd_iprintf(buffer,
7530225ed5STakashi Sakamoto "phys out grps[%d]: type 0x%X, count 0x%X\n",
766a22683eSTakashi Sakamoto i, hwinfo->phys_out_grps[i].type,
776a22683eSTakashi Sakamoto hwinfo->phys_out_grps[i].count);
786a22683eSTakashi Sakamoto }
796a22683eSTakashi Sakamoto
806a22683eSTakashi Sakamoto snd_iprintf(buffer, "amdtp rx pcm channels 1x: 0x%X\n",
816a22683eSTakashi Sakamoto hwinfo->amdtp_rx_pcm_channels);
826a22683eSTakashi Sakamoto snd_iprintf(buffer, "amdtp tx pcm channels 1x: 0x%X\n",
836a22683eSTakashi Sakamoto hwinfo->amdtp_tx_pcm_channels);
846a22683eSTakashi Sakamoto snd_iprintf(buffer, "amdtp rx pcm channels 2x: 0x%X\n",
856a22683eSTakashi Sakamoto hwinfo->amdtp_rx_pcm_channels_2x);
866a22683eSTakashi Sakamoto snd_iprintf(buffer, "amdtp tx pcm channels 2x: 0x%X\n",
876a22683eSTakashi Sakamoto hwinfo->amdtp_tx_pcm_channels_2x);
886a22683eSTakashi Sakamoto snd_iprintf(buffer, "amdtp rx pcm channels 4x: 0x%X\n",
896a22683eSTakashi Sakamoto hwinfo->amdtp_rx_pcm_channels_4x);
906a22683eSTakashi Sakamoto snd_iprintf(buffer, "amdtp tx pcm channels 4x: 0x%X\n",
916a22683eSTakashi Sakamoto hwinfo->amdtp_tx_pcm_channels_4x);
926a22683eSTakashi Sakamoto
936a22683eSTakashi Sakamoto snd_iprintf(buffer, "midi out ports: 0x%X\n", hwinfo->midi_out_ports);
946a22683eSTakashi Sakamoto snd_iprintf(buffer, "midi in ports: 0x%X\n", hwinfo->midi_in_ports);
956a22683eSTakashi Sakamoto
966a22683eSTakashi Sakamoto snd_iprintf(buffer, "mixer playback channels: 0x%X\n",
976a22683eSTakashi Sakamoto hwinfo->mixer_playback_channels);
986a22683eSTakashi Sakamoto snd_iprintf(buffer, "mixer capture channels: 0x%X\n",
996a22683eSTakashi Sakamoto hwinfo->mixer_capture_channels);
1006a22683eSTakashi Sakamoto end:
1016a22683eSTakashi Sakamoto kfree(hwinfo);
1026a22683eSTakashi Sakamoto }
1036a22683eSTakashi Sakamoto
1046a22683eSTakashi Sakamoto static void
proc_read_clock(struct snd_info_entry * entry,struct snd_info_buffer * buffer)1056a22683eSTakashi Sakamoto proc_read_clock(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
1066a22683eSTakashi Sakamoto {
1076a22683eSTakashi Sakamoto struct snd_efw *efw = entry->private_data;
1086a22683eSTakashi Sakamoto enum snd_efw_clock_source clock_source;
1096a22683eSTakashi Sakamoto unsigned int sampling_rate;
1106a22683eSTakashi Sakamoto
1116a22683eSTakashi Sakamoto if (snd_efw_command_get_clock_source(efw, &clock_source) < 0)
1126a22683eSTakashi Sakamoto return;
1136a22683eSTakashi Sakamoto
1146a22683eSTakashi Sakamoto if (snd_efw_command_get_sampling_rate(efw, &sampling_rate) < 0)
1156a22683eSTakashi Sakamoto return;
1166a22683eSTakashi Sakamoto
1176a22683eSTakashi Sakamoto snd_iprintf(buffer, "Clock Source: %d\n", clock_source);
1186a22683eSTakashi Sakamoto snd_iprintf(buffer, "Sampling Rate: %d\n", sampling_rate);
1196a22683eSTakashi Sakamoto }
1206a22683eSTakashi Sakamoto
1216a22683eSTakashi Sakamoto /*
1226a22683eSTakashi Sakamoto * NOTE:
1236a22683eSTakashi Sakamoto * dB = 20 * log10(linear / 0x01000000)
1246a22683eSTakashi Sakamoto * -144.0 dB when linear is 0
1256a22683eSTakashi Sakamoto */
1266a22683eSTakashi Sakamoto static void
proc_read_phys_meters(struct snd_info_entry * entry,struct snd_info_buffer * buffer)1276a22683eSTakashi Sakamoto proc_read_phys_meters(struct snd_info_entry *entry,
1286a22683eSTakashi Sakamoto struct snd_info_buffer *buffer)
1296a22683eSTakashi Sakamoto {
1306a22683eSTakashi Sakamoto struct snd_efw *efw = entry->private_data;
1316a22683eSTakashi Sakamoto struct snd_efw_phys_meters *meters;
1326a22683eSTakashi Sakamoto unsigned int g, c, m, max, size;
1336a22683eSTakashi Sakamoto const char *name;
1346a22683eSTakashi Sakamoto u32 *linear;
1356a22683eSTakashi Sakamoto int err;
1366a22683eSTakashi Sakamoto
1376a22683eSTakashi Sakamoto size = sizeof(struct snd_efw_phys_meters) +
1386a22683eSTakashi Sakamoto (efw->phys_in + efw->phys_out) * sizeof(u32);
1396a22683eSTakashi Sakamoto meters = kzalloc(size, GFP_KERNEL);
1406a22683eSTakashi Sakamoto if (meters == NULL)
1416a22683eSTakashi Sakamoto return;
1426a22683eSTakashi Sakamoto
1436a22683eSTakashi Sakamoto err = snd_efw_command_get_phys_meters(efw, meters, size);
1446a22683eSTakashi Sakamoto if (err < 0)
1456a22683eSTakashi Sakamoto goto end;
1466a22683eSTakashi Sakamoto
1476a22683eSTakashi Sakamoto snd_iprintf(buffer, "Physical Meters:\n");
1486a22683eSTakashi Sakamoto
1496a22683eSTakashi Sakamoto m = 0;
1506a22683eSTakashi Sakamoto max = min(efw->phys_out, meters->out_meters);
1516a22683eSTakashi Sakamoto linear = meters->values;
1526a22683eSTakashi Sakamoto snd_iprintf(buffer, " %d Outputs:\n", max);
1536a22683eSTakashi Sakamoto for (g = 0; g < efw->phys_out_grp_count; g++) {
1546a22683eSTakashi Sakamoto name = get_phys_name(&efw->phys_out_grps[g], false);
1556a22683eSTakashi Sakamoto for (c = 0; c < efw->phys_out_grps[g].count; c++) {
1566a22683eSTakashi Sakamoto if (m < max)
1576a22683eSTakashi Sakamoto snd_iprintf(buffer, "\t%s [%d]: %d\n",
1586a22683eSTakashi Sakamoto name, c, linear[m++]);
1596a22683eSTakashi Sakamoto }
1606a22683eSTakashi Sakamoto }
1616a22683eSTakashi Sakamoto
1626a22683eSTakashi Sakamoto m = 0;
1636a22683eSTakashi Sakamoto max = min(efw->phys_in, meters->in_meters);
1646a22683eSTakashi Sakamoto linear = meters->values + meters->out_meters;
1656a22683eSTakashi Sakamoto snd_iprintf(buffer, " %d Inputs:\n", max);
1666a22683eSTakashi Sakamoto for (g = 0; g < efw->phys_in_grp_count; g++) {
1676a22683eSTakashi Sakamoto name = get_phys_name(&efw->phys_in_grps[g], true);
1686a22683eSTakashi Sakamoto for (c = 0; c < efw->phys_in_grps[g].count; c++)
1696a22683eSTakashi Sakamoto if (m < max)
1706a22683eSTakashi Sakamoto snd_iprintf(buffer, "\t%s [%d]: %d\n",
1716a22683eSTakashi Sakamoto name, c, linear[m++]);
1726a22683eSTakashi Sakamoto }
1736a22683eSTakashi Sakamoto end:
1746a22683eSTakashi Sakamoto kfree(meters);
1756a22683eSTakashi Sakamoto }
1766a22683eSTakashi Sakamoto
1776a22683eSTakashi Sakamoto static void
proc_read_queues_state(struct snd_info_entry * entry,struct snd_info_buffer * buffer)178555e8a8fSTakashi Sakamoto proc_read_queues_state(struct snd_info_entry *entry,
179555e8a8fSTakashi Sakamoto struct snd_info_buffer *buffer)
180555e8a8fSTakashi Sakamoto {
181555e8a8fSTakashi Sakamoto struct snd_efw *efw = entry->private_data;
182555e8a8fSTakashi Sakamoto unsigned int consumed;
183555e8a8fSTakashi Sakamoto
184555e8a8fSTakashi Sakamoto if (efw->pull_ptr > efw->push_ptr)
185555e8a8fSTakashi Sakamoto consumed = snd_efw_resp_buf_size -
186555e8a8fSTakashi Sakamoto (unsigned int)(efw->pull_ptr - efw->push_ptr);
187555e8a8fSTakashi Sakamoto else
188555e8a8fSTakashi Sakamoto consumed = (unsigned int)(efw->push_ptr - efw->pull_ptr);
189555e8a8fSTakashi Sakamoto
1906b1ca4bcSTakashi Sakamoto snd_iprintf(buffer, "%d/%d\n",
1916b1ca4bcSTakashi Sakamoto consumed, snd_efw_resp_buf_size);
192555e8a8fSTakashi Sakamoto }
193555e8a8fSTakashi Sakamoto
194555e8a8fSTakashi Sakamoto static void
add_node(struct snd_efw * efw,struct snd_info_entry * root,const char * name,void (* op)(struct snd_info_entry * e,struct snd_info_buffer * b))1956a22683eSTakashi Sakamoto add_node(struct snd_efw *efw, struct snd_info_entry *root, const char *name,
1966a22683eSTakashi Sakamoto void (*op)(struct snd_info_entry *e, struct snd_info_buffer *b))
1976a22683eSTakashi Sakamoto {
1986a22683eSTakashi Sakamoto struct snd_info_entry *entry;
1996a22683eSTakashi Sakamoto
2006a22683eSTakashi Sakamoto entry = snd_info_create_card_entry(efw->card, name, root);
2010c298bdcSTakashi Iwai if (entry)
2026a22683eSTakashi Sakamoto snd_info_set_text_ops(entry, efw, op);
2036a22683eSTakashi Sakamoto }
2046a22683eSTakashi Sakamoto
snd_efw_proc_init(struct snd_efw * efw)2056a22683eSTakashi Sakamoto void snd_efw_proc_init(struct snd_efw *efw)
2066a22683eSTakashi Sakamoto {
2076a22683eSTakashi Sakamoto struct snd_info_entry *root;
2086a22683eSTakashi Sakamoto
2096a22683eSTakashi Sakamoto /*
2106a22683eSTakashi Sakamoto * All nodes are automatically removed at snd_card_disconnect(),
2116a22683eSTakashi Sakamoto * by following to link list.
2126a22683eSTakashi Sakamoto */
2136a22683eSTakashi Sakamoto root = snd_info_create_card_entry(efw->card, "firewire",
2146a22683eSTakashi Sakamoto efw->card->proc_root);
2156a22683eSTakashi Sakamoto if (root == NULL)
2166a22683eSTakashi Sakamoto return;
2176a73cf46SJoe Perches root->mode = S_IFDIR | 0555;
2186a22683eSTakashi Sakamoto
2196a22683eSTakashi Sakamoto add_node(efw, root, "clock", proc_read_clock);
2206a22683eSTakashi Sakamoto add_node(efw, root, "firmware", proc_read_hwinfo);
2216a22683eSTakashi Sakamoto add_node(efw, root, "meters", proc_read_phys_meters);
222555e8a8fSTakashi Sakamoto add_node(efw, root, "queues", proc_read_queues_state);
2236a22683eSTakashi Sakamoto }
224