18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * fireworks_proc.c - a part of driver for Fireworks based devices 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2009-2010 Clemens Ladisch 68c2ecf20Sopenharmony_ci * Copyright (c) 2013-2014 Takashi Sakamoto 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "./fireworks.h" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_cistatic inline const char* 128c2ecf20Sopenharmony_ciget_phys_name(struct snd_efw_phys_grp *grp, bool input) 138c2ecf20Sopenharmony_ci{ 148c2ecf20Sopenharmony_ci static const char *const ch_type[] = { 158c2ecf20Sopenharmony_ci "Analog", "S/PDIF", "ADAT", "S/PDIF or ADAT", "Mirroring", 168c2ecf20Sopenharmony_ci "Headphones", "I2S", "Guitar", "Pirzo Guitar", "Guitar String", 178c2ecf20Sopenharmony_ci }; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci if (grp->type < ARRAY_SIZE(ch_type)) 208c2ecf20Sopenharmony_ci return ch_type[grp->type]; 218c2ecf20Sopenharmony_ci else if (input) 228c2ecf20Sopenharmony_ci return "Input"; 238c2ecf20Sopenharmony_ci else 248c2ecf20Sopenharmony_ci return "Output"; 258c2ecf20Sopenharmony_ci} 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic void 288c2ecf20Sopenharmony_ciproc_read_hwinfo(struct snd_info_entry *entry, struct snd_info_buffer *buffer) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci struct snd_efw *efw = entry->private_data; 318c2ecf20Sopenharmony_ci unsigned short i; 328c2ecf20Sopenharmony_ci struct snd_efw_hwinfo *hwinfo; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci hwinfo = kmalloc(sizeof(struct snd_efw_hwinfo), GFP_KERNEL); 358c2ecf20Sopenharmony_ci if (hwinfo == NULL) 368c2ecf20Sopenharmony_ci return; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci if (snd_efw_command_get_hwinfo(efw, hwinfo) < 0) 398c2ecf20Sopenharmony_ci goto end; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci snd_iprintf(buffer, "guid_hi: 0x%X\n", hwinfo->guid_hi); 428c2ecf20Sopenharmony_ci snd_iprintf(buffer, "guid_lo: 0x%X\n", hwinfo->guid_lo); 438c2ecf20Sopenharmony_ci snd_iprintf(buffer, "type: 0x%X\n", hwinfo->type); 448c2ecf20Sopenharmony_ci snd_iprintf(buffer, "version: 0x%X\n", hwinfo->version); 458c2ecf20Sopenharmony_ci snd_iprintf(buffer, "vendor_name: %s\n", hwinfo->vendor_name); 468c2ecf20Sopenharmony_ci snd_iprintf(buffer, "model_name: %s\n", hwinfo->model_name); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci snd_iprintf(buffer, "dsp_version: 0x%X\n", hwinfo->dsp_version); 498c2ecf20Sopenharmony_ci snd_iprintf(buffer, "arm_version: 0x%X\n", hwinfo->arm_version); 508c2ecf20Sopenharmony_ci snd_iprintf(buffer, "fpga_version: 0x%X\n", hwinfo->fpga_version); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci snd_iprintf(buffer, "flags: 0x%X\n", hwinfo->flags); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci snd_iprintf(buffer, "max_sample_rate: 0x%X\n", hwinfo->max_sample_rate); 558c2ecf20Sopenharmony_ci snd_iprintf(buffer, "min_sample_rate: 0x%X\n", hwinfo->min_sample_rate); 568c2ecf20Sopenharmony_ci snd_iprintf(buffer, "supported_clock: 0x%X\n", 578c2ecf20Sopenharmony_ci hwinfo->supported_clocks); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci snd_iprintf(buffer, "phys out: 0x%X\n", hwinfo->phys_out); 608c2ecf20Sopenharmony_ci snd_iprintf(buffer, "phys in: 0x%X\n", hwinfo->phys_in); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci snd_iprintf(buffer, "phys in grps: 0x%X\n", 638c2ecf20Sopenharmony_ci hwinfo->phys_in_grp_count); 648c2ecf20Sopenharmony_ci for (i = 0; i < hwinfo->phys_in_grp_count; i++) { 658c2ecf20Sopenharmony_ci snd_iprintf(buffer, 668c2ecf20Sopenharmony_ci "phys in grp[%d]: type 0x%X, count 0x%X\n", 678c2ecf20Sopenharmony_ci i, hwinfo->phys_out_grps[i].type, 688c2ecf20Sopenharmony_ci hwinfo->phys_out_grps[i].count); 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci snd_iprintf(buffer, "phys out grps: 0x%X\n", 728c2ecf20Sopenharmony_ci hwinfo->phys_out_grp_count); 738c2ecf20Sopenharmony_ci for (i = 0; i < hwinfo->phys_out_grp_count; i++) { 748c2ecf20Sopenharmony_ci snd_iprintf(buffer, 758c2ecf20Sopenharmony_ci "phys out grps[%d]: type 0x%X, count 0x%X\n", 768c2ecf20Sopenharmony_ci i, hwinfo->phys_out_grps[i].type, 778c2ecf20Sopenharmony_ci hwinfo->phys_out_grps[i].count); 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci snd_iprintf(buffer, "amdtp rx pcm channels 1x: 0x%X\n", 818c2ecf20Sopenharmony_ci hwinfo->amdtp_rx_pcm_channels); 828c2ecf20Sopenharmony_ci snd_iprintf(buffer, "amdtp tx pcm channels 1x: 0x%X\n", 838c2ecf20Sopenharmony_ci hwinfo->amdtp_tx_pcm_channels); 848c2ecf20Sopenharmony_ci snd_iprintf(buffer, "amdtp rx pcm channels 2x: 0x%X\n", 858c2ecf20Sopenharmony_ci hwinfo->amdtp_rx_pcm_channels_2x); 868c2ecf20Sopenharmony_ci snd_iprintf(buffer, "amdtp tx pcm channels 2x: 0x%X\n", 878c2ecf20Sopenharmony_ci hwinfo->amdtp_tx_pcm_channels_2x); 888c2ecf20Sopenharmony_ci snd_iprintf(buffer, "amdtp rx pcm channels 4x: 0x%X\n", 898c2ecf20Sopenharmony_ci hwinfo->amdtp_rx_pcm_channels_4x); 908c2ecf20Sopenharmony_ci snd_iprintf(buffer, "amdtp tx pcm channels 4x: 0x%X\n", 918c2ecf20Sopenharmony_ci hwinfo->amdtp_tx_pcm_channels_4x); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci snd_iprintf(buffer, "midi out ports: 0x%X\n", hwinfo->midi_out_ports); 948c2ecf20Sopenharmony_ci snd_iprintf(buffer, "midi in ports: 0x%X\n", hwinfo->midi_in_ports); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci snd_iprintf(buffer, "mixer playback channels: 0x%X\n", 978c2ecf20Sopenharmony_ci hwinfo->mixer_playback_channels); 988c2ecf20Sopenharmony_ci snd_iprintf(buffer, "mixer capture channels: 0x%X\n", 998c2ecf20Sopenharmony_ci hwinfo->mixer_capture_channels); 1008c2ecf20Sopenharmony_ciend: 1018c2ecf20Sopenharmony_ci kfree(hwinfo); 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic void 1058c2ecf20Sopenharmony_ciproc_read_clock(struct snd_info_entry *entry, struct snd_info_buffer *buffer) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci struct snd_efw *efw = entry->private_data; 1088c2ecf20Sopenharmony_ci enum snd_efw_clock_source clock_source; 1098c2ecf20Sopenharmony_ci unsigned int sampling_rate; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (snd_efw_command_get_clock_source(efw, &clock_source) < 0) 1128c2ecf20Sopenharmony_ci return; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if (snd_efw_command_get_sampling_rate(efw, &sampling_rate) < 0) 1158c2ecf20Sopenharmony_ci return; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Clock Source: %d\n", clock_source); 1188c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Sampling Rate: %d\n", sampling_rate); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci/* 1228c2ecf20Sopenharmony_ci * NOTE: 1238c2ecf20Sopenharmony_ci * dB = 20 * log10(linear / 0x01000000) 1248c2ecf20Sopenharmony_ci * -144.0 dB when linear is 0 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_cistatic void 1278c2ecf20Sopenharmony_ciproc_read_phys_meters(struct snd_info_entry *entry, 1288c2ecf20Sopenharmony_ci struct snd_info_buffer *buffer) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci struct snd_efw *efw = entry->private_data; 1318c2ecf20Sopenharmony_ci struct snd_efw_phys_meters *meters; 1328c2ecf20Sopenharmony_ci unsigned int g, c, m, max, size; 1338c2ecf20Sopenharmony_ci const char *name; 1348c2ecf20Sopenharmony_ci u32 *linear; 1358c2ecf20Sopenharmony_ci int err; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci size = sizeof(struct snd_efw_phys_meters) + 1388c2ecf20Sopenharmony_ci (efw->phys_in + efw->phys_out) * sizeof(u32); 1398c2ecf20Sopenharmony_ci meters = kzalloc(size, GFP_KERNEL); 1408c2ecf20Sopenharmony_ci if (meters == NULL) 1418c2ecf20Sopenharmony_ci return; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci err = snd_efw_command_get_phys_meters(efw, meters, size); 1448c2ecf20Sopenharmony_ci if (err < 0) 1458c2ecf20Sopenharmony_ci goto end; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Physical Meters:\n"); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci m = 0; 1508c2ecf20Sopenharmony_ci max = min(efw->phys_out, meters->out_meters); 1518c2ecf20Sopenharmony_ci linear = meters->values; 1528c2ecf20Sopenharmony_ci snd_iprintf(buffer, " %d Outputs:\n", max); 1538c2ecf20Sopenharmony_ci for (g = 0; g < efw->phys_out_grp_count; g++) { 1548c2ecf20Sopenharmony_ci name = get_phys_name(&efw->phys_out_grps[g], false); 1558c2ecf20Sopenharmony_ci for (c = 0; c < efw->phys_out_grps[g].count; c++) { 1568c2ecf20Sopenharmony_ci if (m < max) 1578c2ecf20Sopenharmony_ci snd_iprintf(buffer, "\t%s [%d]: %d\n", 1588c2ecf20Sopenharmony_ci name, c, linear[m++]); 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci m = 0; 1638c2ecf20Sopenharmony_ci max = min(efw->phys_in, meters->in_meters); 1648c2ecf20Sopenharmony_ci linear = meters->values + meters->out_meters; 1658c2ecf20Sopenharmony_ci snd_iprintf(buffer, " %d Inputs:\n", max); 1668c2ecf20Sopenharmony_ci for (g = 0; g < efw->phys_in_grp_count; g++) { 1678c2ecf20Sopenharmony_ci name = get_phys_name(&efw->phys_in_grps[g], true); 1688c2ecf20Sopenharmony_ci for (c = 0; c < efw->phys_in_grps[g].count; c++) 1698c2ecf20Sopenharmony_ci if (m < max) 1708c2ecf20Sopenharmony_ci snd_iprintf(buffer, "\t%s [%d]: %d\n", 1718c2ecf20Sopenharmony_ci name, c, linear[m++]); 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ciend: 1748c2ecf20Sopenharmony_ci kfree(meters); 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic void 1788c2ecf20Sopenharmony_ciproc_read_queues_state(struct snd_info_entry *entry, 1798c2ecf20Sopenharmony_ci struct snd_info_buffer *buffer) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci struct snd_efw *efw = entry->private_data; 1828c2ecf20Sopenharmony_ci unsigned int consumed; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (efw->pull_ptr > efw->push_ptr) 1858c2ecf20Sopenharmony_ci consumed = snd_efw_resp_buf_size - 1868c2ecf20Sopenharmony_ci (unsigned int)(efw->pull_ptr - efw->push_ptr); 1878c2ecf20Sopenharmony_ci else 1888c2ecf20Sopenharmony_ci consumed = (unsigned int)(efw->push_ptr - efw->pull_ptr); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci snd_iprintf(buffer, "%d/%d\n", 1918c2ecf20Sopenharmony_ci consumed, snd_efw_resp_buf_size); 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic void 1958c2ecf20Sopenharmony_ciadd_node(struct snd_efw *efw, struct snd_info_entry *root, const char *name, 1968c2ecf20Sopenharmony_ci void (*op)(struct snd_info_entry *e, struct snd_info_buffer *b)) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci struct snd_info_entry *entry; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci entry = snd_info_create_card_entry(efw->card, name, root); 2018c2ecf20Sopenharmony_ci if (entry) 2028c2ecf20Sopenharmony_ci snd_info_set_text_ops(entry, efw, op); 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_civoid snd_efw_proc_init(struct snd_efw *efw) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci struct snd_info_entry *root; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci /* 2108c2ecf20Sopenharmony_ci * All nodes are automatically removed at snd_card_disconnect(), 2118c2ecf20Sopenharmony_ci * by following to link list. 2128c2ecf20Sopenharmony_ci */ 2138c2ecf20Sopenharmony_ci root = snd_info_create_card_entry(efw->card, "firewire", 2148c2ecf20Sopenharmony_ci efw->card->proc_root); 2158c2ecf20Sopenharmony_ci if (root == NULL) 2168c2ecf20Sopenharmony_ci return; 2178c2ecf20Sopenharmony_ci root->mode = S_IFDIR | 0555; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci add_node(efw, root, "clock", proc_read_clock); 2208c2ecf20Sopenharmony_ci add_node(efw, root, "firmware", proc_read_hwinfo); 2218c2ecf20Sopenharmony_ci add_node(efw, root, "meters", proc_read_phys_meters); 2228c2ecf20Sopenharmony_ci add_node(efw, root, "queues", proc_read_queues_state); 2238c2ecf20Sopenharmony_ci} 224