162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * bebob_proc.c - a part of driver for BeBoB based devices 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2013-2014 Takashi Sakamoto 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "./bebob.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/* contents of information register */ 1162306a36Sopenharmony_cistruct hw_info { 1262306a36Sopenharmony_ci u64 manufacturer; 1362306a36Sopenharmony_ci u32 protocol_ver; 1462306a36Sopenharmony_ci u32 bld_ver; 1562306a36Sopenharmony_ci u32 guid[2]; 1662306a36Sopenharmony_ci u32 model_id; 1762306a36Sopenharmony_ci u32 model_rev; 1862306a36Sopenharmony_ci u64 fw_date; 1962306a36Sopenharmony_ci u64 fw_time; 2062306a36Sopenharmony_ci u32 fw_id; 2162306a36Sopenharmony_ci u32 fw_ver; 2262306a36Sopenharmony_ci u32 base_addr; 2362306a36Sopenharmony_ci u32 max_size; 2462306a36Sopenharmony_ci u64 bld_date; 2562306a36Sopenharmony_ci u64 bld_time; 2662306a36Sopenharmony_ci/* may not used in product 2762306a36Sopenharmony_ci u64 dbg_date; 2862306a36Sopenharmony_ci u64 dbg_time; 2962306a36Sopenharmony_ci u32 dbg_id; 3062306a36Sopenharmony_ci u32 dbg_version; 3162306a36Sopenharmony_ci*/ 3262306a36Sopenharmony_ci} __packed; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic void 3562306a36Sopenharmony_ciproc_read_hw_info(struct snd_info_entry *entry, 3662306a36Sopenharmony_ci struct snd_info_buffer *buffer) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci struct snd_bebob *bebob = entry->private_data; 3962306a36Sopenharmony_ci struct hw_info *info; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci info = kzalloc(sizeof(struct hw_info), GFP_KERNEL); 4262306a36Sopenharmony_ci if (info == NULL) 4362306a36Sopenharmony_ci return; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci if (snd_bebob_read_block(bebob->unit, 0, 4662306a36Sopenharmony_ci info, sizeof(struct hw_info)) < 0) 4762306a36Sopenharmony_ci goto end; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci snd_iprintf(buffer, "Manufacturer:\t%.8s\n", 5062306a36Sopenharmony_ci (char *)&info->manufacturer); 5162306a36Sopenharmony_ci snd_iprintf(buffer, "Protocol Ver:\t%d\n", info->protocol_ver); 5262306a36Sopenharmony_ci snd_iprintf(buffer, "Build Ver:\t%d\n", info->bld_ver); 5362306a36Sopenharmony_ci snd_iprintf(buffer, "GUID:\t\t0x%.8X%.8X\n", 5462306a36Sopenharmony_ci info->guid[0], info->guid[1]); 5562306a36Sopenharmony_ci snd_iprintf(buffer, "Model ID:\t0x%02X\n", info->model_id); 5662306a36Sopenharmony_ci snd_iprintf(buffer, "Model Rev:\t%d\n", info->model_rev); 5762306a36Sopenharmony_ci snd_iprintf(buffer, "Firmware Date:\t%.8s\n", (char *)&info->fw_date); 5862306a36Sopenharmony_ci snd_iprintf(buffer, "Firmware Time:\t%.8s\n", (char *)&info->fw_time); 5962306a36Sopenharmony_ci snd_iprintf(buffer, "Firmware ID:\t0x%X\n", info->fw_id); 6062306a36Sopenharmony_ci snd_iprintf(buffer, "Firmware Ver:\t%d\n", info->fw_ver); 6162306a36Sopenharmony_ci snd_iprintf(buffer, "Base Addr:\t0x%X\n", info->base_addr); 6262306a36Sopenharmony_ci snd_iprintf(buffer, "Max Size:\t%d\n", info->max_size); 6362306a36Sopenharmony_ci snd_iprintf(buffer, "Loader Date:\t%.8s\n", (char *)&info->bld_date); 6462306a36Sopenharmony_ci snd_iprintf(buffer, "Loader Time:\t%.8s\n", (char *)&info->bld_time); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ciend: 6762306a36Sopenharmony_ci kfree(info); 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic void 7162306a36Sopenharmony_ciproc_read_meters(struct snd_info_entry *entry, 7262306a36Sopenharmony_ci struct snd_info_buffer *buffer) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci struct snd_bebob *bebob = entry->private_data; 7562306a36Sopenharmony_ci const struct snd_bebob_meter_spec *spec = bebob->spec->meter; 7662306a36Sopenharmony_ci u32 *buf; 7762306a36Sopenharmony_ci unsigned int i, c, channels, size; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci if (spec == NULL) 8062306a36Sopenharmony_ci return; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci channels = spec->num * 2; 8362306a36Sopenharmony_ci size = channels * sizeof(u32); 8462306a36Sopenharmony_ci buf = kmalloc(size, GFP_KERNEL); 8562306a36Sopenharmony_ci if (buf == NULL) 8662306a36Sopenharmony_ci return; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci if (spec->get(bebob, buf, size) < 0) 8962306a36Sopenharmony_ci goto end; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci for (i = 0, c = 1; i < channels; i++) { 9262306a36Sopenharmony_ci snd_iprintf(buffer, "%s %d:\t%d\n", 9362306a36Sopenharmony_ci spec->labels[i / 2], c++, buf[i]); 9462306a36Sopenharmony_ci if ((i + 1 < channels - 1) && 9562306a36Sopenharmony_ci (strcmp(spec->labels[i / 2], 9662306a36Sopenharmony_ci spec->labels[(i + 1) / 2]) != 0)) 9762306a36Sopenharmony_ci c = 1; 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ciend: 10062306a36Sopenharmony_ci kfree(buf); 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic void 10462306a36Sopenharmony_ciproc_read_formation(struct snd_info_entry *entry, 10562306a36Sopenharmony_ci struct snd_info_buffer *buffer) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci struct snd_bebob *bebob = entry->private_data; 10862306a36Sopenharmony_ci struct snd_bebob_stream_formation *formation; 10962306a36Sopenharmony_ci unsigned int i; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci snd_iprintf(buffer, "Output Stream from device:\n"); 11262306a36Sopenharmony_ci snd_iprintf(buffer, "\tRate\tPCM\tMIDI\n"); 11362306a36Sopenharmony_ci formation = bebob->tx_stream_formations; 11462306a36Sopenharmony_ci for (i = 0; i < SND_BEBOB_STRM_FMT_ENTRIES; i++) { 11562306a36Sopenharmony_ci snd_iprintf(buffer, 11662306a36Sopenharmony_ci "\t%d\t%d\t%d\n", snd_bebob_rate_table[i], 11762306a36Sopenharmony_ci formation[i].pcm, formation[i].midi); 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci snd_iprintf(buffer, "Input Stream to device:\n"); 12162306a36Sopenharmony_ci snd_iprintf(buffer, "\tRate\tPCM\tMIDI\n"); 12262306a36Sopenharmony_ci formation = bebob->rx_stream_formations; 12362306a36Sopenharmony_ci for (i = 0; i < SND_BEBOB_STRM_FMT_ENTRIES; i++) { 12462306a36Sopenharmony_ci snd_iprintf(buffer, 12562306a36Sopenharmony_ci "\t%d\t%d\t%d\n", snd_bebob_rate_table[i], 12662306a36Sopenharmony_ci formation[i].pcm, formation[i].midi); 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic void 13162306a36Sopenharmony_ciproc_read_clock(struct snd_info_entry *entry, 13262306a36Sopenharmony_ci struct snd_info_buffer *buffer) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci static const char *const clk_labels[] = { 13562306a36Sopenharmony_ci "Internal", 13662306a36Sopenharmony_ci "External", 13762306a36Sopenharmony_ci "SYT-Match", 13862306a36Sopenharmony_ci }; 13962306a36Sopenharmony_ci struct snd_bebob *bebob = entry->private_data; 14062306a36Sopenharmony_ci const struct snd_bebob_rate_spec *rate_spec = bebob->spec->rate; 14162306a36Sopenharmony_ci const struct snd_bebob_clock_spec *clk_spec = bebob->spec->clock; 14262306a36Sopenharmony_ci enum snd_bebob_clock_type src; 14362306a36Sopenharmony_ci unsigned int rate; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if (rate_spec->get(bebob, &rate) >= 0) 14662306a36Sopenharmony_ci snd_iprintf(buffer, "Sampling rate: %d\n", rate); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (snd_bebob_stream_get_clock_src(bebob, &src) >= 0) { 14962306a36Sopenharmony_ci if (clk_spec) 15062306a36Sopenharmony_ci snd_iprintf(buffer, "Clock Source: %s\n", 15162306a36Sopenharmony_ci clk_labels[src]); 15262306a36Sopenharmony_ci else 15362306a36Sopenharmony_ci snd_iprintf(buffer, "Clock Source: %s (MSU-dest: %d)\n", 15462306a36Sopenharmony_ci clk_labels[src], bebob->sync_input_plug); 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic void 15962306a36Sopenharmony_ciadd_node(struct snd_bebob *bebob, struct snd_info_entry *root, const char *name, 16062306a36Sopenharmony_ci void (*op)(struct snd_info_entry *e, struct snd_info_buffer *b)) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci struct snd_info_entry *entry; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci entry = snd_info_create_card_entry(bebob->card, name, root); 16562306a36Sopenharmony_ci if (entry) 16662306a36Sopenharmony_ci snd_info_set_text_ops(entry, bebob, op); 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_civoid snd_bebob_proc_init(struct snd_bebob *bebob) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci struct snd_info_entry *root; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci /* 17462306a36Sopenharmony_ci * All nodes are automatically removed at snd_card_disconnect(), 17562306a36Sopenharmony_ci * by following to link list. 17662306a36Sopenharmony_ci */ 17762306a36Sopenharmony_ci root = snd_info_create_card_entry(bebob->card, "firewire", 17862306a36Sopenharmony_ci bebob->card->proc_root); 17962306a36Sopenharmony_ci if (root == NULL) 18062306a36Sopenharmony_ci return; 18162306a36Sopenharmony_ci root->mode = S_IFDIR | 0555; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci add_node(bebob, root, "clock", proc_read_clock); 18462306a36Sopenharmony_ci add_node(bebob, root, "firmware", proc_read_hw_info); 18562306a36Sopenharmony_ci add_node(bebob, root, "formation", proc_read_formation); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (bebob->spec->meter != NULL) 18862306a36Sopenharmony_ci add_node(bebob, root, "meter", proc_read_meters); 18962306a36Sopenharmony_ci} 190