18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * bebob_proc.c - a part of driver for BeBoB based devices 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2013-2014 Takashi Sakamoto 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "./bebob.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/* contents of information register */ 118c2ecf20Sopenharmony_cistruct hw_info { 128c2ecf20Sopenharmony_ci u64 manufacturer; 138c2ecf20Sopenharmony_ci u32 protocol_ver; 148c2ecf20Sopenharmony_ci u32 bld_ver; 158c2ecf20Sopenharmony_ci u32 guid[2]; 168c2ecf20Sopenharmony_ci u32 model_id; 178c2ecf20Sopenharmony_ci u32 model_rev; 188c2ecf20Sopenharmony_ci u64 fw_date; 198c2ecf20Sopenharmony_ci u64 fw_time; 208c2ecf20Sopenharmony_ci u32 fw_id; 218c2ecf20Sopenharmony_ci u32 fw_ver; 228c2ecf20Sopenharmony_ci u32 base_addr; 238c2ecf20Sopenharmony_ci u32 max_size; 248c2ecf20Sopenharmony_ci u64 bld_date; 258c2ecf20Sopenharmony_ci u64 bld_time; 268c2ecf20Sopenharmony_ci/* may not used in product 278c2ecf20Sopenharmony_ci u64 dbg_date; 288c2ecf20Sopenharmony_ci u64 dbg_time; 298c2ecf20Sopenharmony_ci u32 dbg_id; 308c2ecf20Sopenharmony_ci u32 dbg_version; 318c2ecf20Sopenharmony_ci*/ 328c2ecf20Sopenharmony_ci} __packed; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic void 358c2ecf20Sopenharmony_ciproc_read_hw_info(struct snd_info_entry *entry, 368c2ecf20Sopenharmony_ci struct snd_info_buffer *buffer) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci struct snd_bebob *bebob = entry->private_data; 398c2ecf20Sopenharmony_ci struct hw_info *info; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci info = kzalloc(sizeof(struct hw_info), GFP_KERNEL); 428c2ecf20Sopenharmony_ci if (info == NULL) 438c2ecf20Sopenharmony_ci return; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci if (snd_bebob_read_block(bebob->unit, 0, 468c2ecf20Sopenharmony_ci info, sizeof(struct hw_info)) < 0) 478c2ecf20Sopenharmony_ci goto end; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Manufacturer:\t%.8s\n", 508c2ecf20Sopenharmony_ci (char *)&info->manufacturer); 518c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Protocol Ver:\t%d\n", info->protocol_ver); 528c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Build Ver:\t%d\n", info->bld_ver); 538c2ecf20Sopenharmony_ci snd_iprintf(buffer, "GUID:\t\t0x%.8X%.8X\n", 548c2ecf20Sopenharmony_ci info->guid[0], info->guid[1]); 558c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Model ID:\t0x%02X\n", info->model_id); 568c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Model Rev:\t%d\n", info->model_rev); 578c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Firmware Date:\t%.8s\n", (char *)&info->fw_date); 588c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Firmware Time:\t%.8s\n", (char *)&info->fw_time); 598c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Firmware ID:\t0x%X\n", info->fw_id); 608c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Firmware Ver:\t%d\n", info->fw_ver); 618c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Base Addr:\t0x%X\n", info->base_addr); 628c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Max Size:\t%d\n", info->max_size); 638c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Loader Date:\t%.8s\n", (char *)&info->bld_date); 648c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Loader Time:\t%.8s\n", (char *)&info->bld_time); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ciend: 678c2ecf20Sopenharmony_ci kfree(info); 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic void 718c2ecf20Sopenharmony_ciproc_read_meters(struct snd_info_entry *entry, 728c2ecf20Sopenharmony_ci struct snd_info_buffer *buffer) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci struct snd_bebob *bebob = entry->private_data; 758c2ecf20Sopenharmony_ci const struct snd_bebob_meter_spec *spec = bebob->spec->meter; 768c2ecf20Sopenharmony_ci u32 *buf; 778c2ecf20Sopenharmony_ci unsigned int i, c, channels, size; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci if (spec == NULL) 808c2ecf20Sopenharmony_ci return; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci channels = spec->num * 2; 838c2ecf20Sopenharmony_ci size = channels * sizeof(u32); 848c2ecf20Sopenharmony_ci buf = kmalloc(size, GFP_KERNEL); 858c2ecf20Sopenharmony_ci if (buf == NULL) 868c2ecf20Sopenharmony_ci return; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (spec->get(bebob, buf, size) < 0) 898c2ecf20Sopenharmony_ci goto end; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci for (i = 0, c = 1; i < channels; i++) { 928c2ecf20Sopenharmony_ci snd_iprintf(buffer, "%s %d:\t%d\n", 938c2ecf20Sopenharmony_ci spec->labels[i / 2], c++, buf[i]); 948c2ecf20Sopenharmony_ci if ((i + 1 < channels - 1) && 958c2ecf20Sopenharmony_ci (strcmp(spec->labels[i / 2], 968c2ecf20Sopenharmony_ci spec->labels[(i + 1) / 2]) != 0)) 978c2ecf20Sopenharmony_ci c = 1; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ciend: 1008c2ecf20Sopenharmony_ci kfree(buf); 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic void 1048c2ecf20Sopenharmony_ciproc_read_formation(struct snd_info_entry *entry, 1058c2ecf20Sopenharmony_ci struct snd_info_buffer *buffer) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci struct snd_bebob *bebob = entry->private_data; 1088c2ecf20Sopenharmony_ci struct snd_bebob_stream_formation *formation; 1098c2ecf20Sopenharmony_ci unsigned int i; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Output Stream from device:\n"); 1128c2ecf20Sopenharmony_ci snd_iprintf(buffer, "\tRate\tPCM\tMIDI\n"); 1138c2ecf20Sopenharmony_ci formation = bebob->tx_stream_formations; 1148c2ecf20Sopenharmony_ci for (i = 0; i < SND_BEBOB_STRM_FMT_ENTRIES; i++) { 1158c2ecf20Sopenharmony_ci snd_iprintf(buffer, 1168c2ecf20Sopenharmony_ci "\t%d\t%d\t%d\n", snd_bebob_rate_table[i], 1178c2ecf20Sopenharmony_ci formation[i].pcm, formation[i].midi); 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Input Stream to device:\n"); 1218c2ecf20Sopenharmony_ci snd_iprintf(buffer, "\tRate\tPCM\tMIDI\n"); 1228c2ecf20Sopenharmony_ci formation = bebob->rx_stream_formations; 1238c2ecf20Sopenharmony_ci for (i = 0; i < SND_BEBOB_STRM_FMT_ENTRIES; i++) { 1248c2ecf20Sopenharmony_ci snd_iprintf(buffer, 1258c2ecf20Sopenharmony_ci "\t%d\t%d\t%d\n", snd_bebob_rate_table[i], 1268c2ecf20Sopenharmony_ci formation[i].pcm, formation[i].midi); 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic void 1318c2ecf20Sopenharmony_ciproc_read_clock(struct snd_info_entry *entry, 1328c2ecf20Sopenharmony_ci struct snd_info_buffer *buffer) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci static const char *const clk_labels[] = { 1358c2ecf20Sopenharmony_ci "Internal", 1368c2ecf20Sopenharmony_ci "External", 1378c2ecf20Sopenharmony_ci "SYT-Match", 1388c2ecf20Sopenharmony_ci }; 1398c2ecf20Sopenharmony_ci struct snd_bebob *bebob = entry->private_data; 1408c2ecf20Sopenharmony_ci const struct snd_bebob_rate_spec *rate_spec = bebob->spec->rate; 1418c2ecf20Sopenharmony_ci const struct snd_bebob_clock_spec *clk_spec = bebob->spec->clock; 1428c2ecf20Sopenharmony_ci enum snd_bebob_clock_type src; 1438c2ecf20Sopenharmony_ci unsigned int rate; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (rate_spec->get(bebob, &rate) >= 0) 1468c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Sampling rate: %d\n", rate); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (snd_bebob_stream_get_clock_src(bebob, &src) >= 0) { 1498c2ecf20Sopenharmony_ci if (clk_spec) 1508c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Clock Source: %s\n", 1518c2ecf20Sopenharmony_ci clk_labels[src]); 1528c2ecf20Sopenharmony_ci else 1538c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Clock Source: %s (MSU-dest: %d)\n", 1548c2ecf20Sopenharmony_ci clk_labels[src], bebob->sync_input_plug); 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic void 1598c2ecf20Sopenharmony_ciadd_node(struct snd_bebob *bebob, struct snd_info_entry *root, const char *name, 1608c2ecf20Sopenharmony_ci void (*op)(struct snd_info_entry *e, struct snd_info_buffer *b)) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci struct snd_info_entry *entry; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci entry = snd_info_create_card_entry(bebob->card, name, root); 1658c2ecf20Sopenharmony_ci if (entry) 1668c2ecf20Sopenharmony_ci snd_info_set_text_ops(entry, bebob, op); 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_civoid snd_bebob_proc_init(struct snd_bebob *bebob) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci struct snd_info_entry *root; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci /* 1748c2ecf20Sopenharmony_ci * All nodes are automatically removed at snd_card_disconnect(), 1758c2ecf20Sopenharmony_ci * by following to link list. 1768c2ecf20Sopenharmony_ci */ 1778c2ecf20Sopenharmony_ci root = snd_info_create_card_entry(bebob->card, "firewire", 1788c2ecf20Sopenharmony_ci bebob->card->proc_root); 1798c2ecf20Sopenharmony_ci if (root == NULL) 1808c2ecf20Sopenharmony_ci return; 1818c2ecf20Sopenharmony_ci root->mode = S_IFDIR | 0555; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci add_node(bebob, root, "clock", proc_read_clock); 1848c2ecf20Sopenharmony_ci add_node(bebob, root, "firmware", proc_read_hw_info); 1858c2ecf20Sopenharmony_ci add_node(bebob, root, "formation", proc_read_formation); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (bebob->spec->meter != NULL) 1888c2ecf20Sopenharmony_ci add_node(bebob, root, "meter", proc_read_meters); 1898c2ecf20Sopenharmony_ci} 190