linux/sound/firewire/fireworks/fireworks_proc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * fireworks_proc.c - a part of driver for Fireworks based devices
   4 *
   5 * Copyright (c) 2009-2010 Clemens Ladisch
   6 * Copyright (c) 2013-2014 Takashi Sakamoto
   7 */
   8
   9#include "./fireworks.h"
  10
  11static inline const char*
  12get_phys_name(struct snd_efw_phys_grp *grp, bool input)
  13{
  14        static const char *const ch_type[] = {
  15                "Analog", "S/PDIF", "ADAT", "S/PDIF or ADAT", "Mirroring",
  16                "Headphones", "I2S", "Guitar", "Pirzo Guitar", "Guitar String",
  17        };
  18
  19        if (grp->type < ARRAY_SIZE(ch_type))
  20                return ch_type[grp->type];
  21        else if (input)
  22                return "Input";
  23        else
  24                return "Output";
  25}
  26
  27static void
  28proc_read_hwinfo(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
  29{
  30        struct snd_efw *efw = entry->private_data;
  31        unsigned short i;
  32        struct snd_efw_hwinfo *hwinfo;
  33
  34        hwinfo = kmalloc(sizeof(struct snd_efw_hwinfo), GFP_KERNEL);
  35        if (hwinfo == NULL)
  36                return;
  37
  38        if (snd_efw_command_get_hwinfo(efw, hwinfo) < 0)
  39                goto end;
  40
  41        snd_iprintf(buffer, "guid_hi: 0x%X\n", hwinfo->guid_hi);
  42        snd_iprintf(buffer, "guid_lo: 0x%X\n", hwinfo->guid_lo);
  43        snd_iprintf(buffer, "type: 0x%X\n", hwinfo->type);
  44        snd_iprintf(buffer, "version: 0x%X\n", hwinfo->version);
  45        snd_iprintf(buffer, "vendor_name: %s\n", hwinfo->vendor_name);
  46        snd_iprintf(buffer, "model_name: %s\n", hwinfo->model_name);
  47
  48        snd_iprintf(buffer, "dsp_version: 0x%X\n", hwinfo->dsp_version);
  49        snd_iprintf(buffer, "arm_version: 0x%X\n", hwinfo->arm_version);
  50        snd_iprintf(buffer, "fpga_version: 0x%X\n", hwinfo->fpga_version);
  51
  52        snd_iprintf(buffer, "flags: 0x%X\n", hwinfo->flags);
  53
  54        snd_iprintf(buffer, "max_sample_rate: 0x%X\n", hwinfo->max_sample_rate);
  55        snd_iprintf(buffer, "min_sample_rate: 0x%X\n", hwinfo->min_sample_rate);
  56        snd_iprintf(buffer, "supported_clock: 0x%X\n",
  57                    hwinfo->supported_clocks);
  58
  59        snd_iprintf(buffer, "phys out: 0x%X\n", hwinfo->phys_out);
  60        snd_iprintf(buffer, "phys in: 0x%X\n", hwinfo->phys_in);
  61
  62        snd_iprintf(buffer, "phys in grps: 0x%X\n",
  63                    hwinfo->phys_in_grp_count);
  64        for (i = 0; i < hwinfo->phys_in_grp_count; i++) {
  65                snd_iprintf(buffer,
  66                            "phys in grp[%d]: type 0x%X, count 0x%X\n",
  67                            i, hwinfo->phys_out_grps[i].type,
  68                            hwinfo->phys_out_grps[i].count);
  69        }
  70
  71        snd_iprintf(buffer, "phys out grps: 0x%X\n",
  72                    hwinfo->phys_out_grp_count);
  73        for (i = 0; i < hwinfo->phys_out_grp_count; i++) {
  74                snd_iprintf(buffer,
  75                            "phys out grps[%d]: type 0x%X, count 0x%X\n",
  76                            i, hwinfo->phys_out_grps[i].type,
  77                            hwinfo->phys_out_grps[i].count);
  78        }
  79
  80        snd_iprintf(buffer, "amdtp rx pcm channels 1x: 0x%X\n",
  81                    hwinfo->amdtp_rx_pcm_channels);
  82        snd_iprintf(buffer, "amdtp tx pcm channels 1x: 0x%X\n",
  83                    hwinfo->amdtp_tx_pcm_channels);
  84        snd_iprintf(buffer, "amdtp rx pcm channels 2x: 0x%X\n",
  85                    hwinfo->amdtp_rx_pcm_channels_2x);
  86        snd_iprintf(buffer, "amdtp tx pcm channels 2x: 0x%X\n",
  87                    hwinfo->amdtp_tx_pcm_channels_2x);
  88        snd_iprintf(buffer, "amdtp rx pcm channels 4x: 0x%X\n",
  89                    hwinfo->amdtp_rx_pcm_channels_4x);
  90        snd_iprintf(buffer, "amdtp tx pcm channels 4x: 0x%X\n",
  91                    hwinfo->amdtp_tx_pcm_channels_4x);
  92
  93        snd_iprintf(buffer, "midi out ports: 0x%X\n", hwinfo->midi_out_ports);
  94        snd_iprintf(buffer, "midi in ports: 0x%X\n", hwinfo->midi_in_ports);
  95
  96        snd_iprintf(buffer, "mixer playback channels: 0x%X\n",
  97                    hwinfo->mixer_playback_channels);
  98        snd_iprintf(buffer, "mixer capture channels: 0x%X\n",
  99                    hwinfo->mixer_capture_channels);
 100end:
 101        kfree(hwinfo);
 102}
 103
 104static void
 105proc_read_clock(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 106{
 107        struct snd_efw *efw = entry->private_data;
 108        enum snd_efw_clock_source clock_source;
 109        unsigned int sampling_rate;
 110
 111        if (snd_efw_command_get_clock_source(efw, &clock_source) < 0)
 112                return;
 113
 114        if (snd_efw_command_get_sampling_rate(efw, &sampling_rate) < 0)
 115                return;
 116
 117        snd_iprintf(buffer, "Clock Source: %d\n", clock_source);
 118        snd_iprintf(buffer, "Sampling Rate: %d\n", sampling_rate);
 119}
 120
 121/*
 122 * NOTE:
 123 *  dB = 20 * log10(linear / 0x01000000)
 124 *  -144.0 dB when linear is 0
 125 */
 126static void
 127proc_read_phys_meters(struct snd_info_entry *entry,
 128                      struct snd_info_buffer *buffer)
 129{
 130        struct snd_efw *efw = entry->private_data;
 131        struct snd_efw_phys_meters *meters;
 132        unsigned int g, c, m, max, size;
 133        const char *name;
 134        u32 *linear;
 135        int err;
 136
 137        size = sizeof(struct snd_efw_phys_meters) +
 138               (efw->phys_in + efw->phys_out) * sizeof(u32);
 139        meters = kzalloc(size, GFP_KERNEL);
 140        if (meters == NULL)
 141                return;
 142
 143        err = snd_efw_command_get_phys_meters(efw, meters, size);
 144        if (err < 0)
 145                goto end;
 146
 147        snd_iprintf(buffer, "Physical Meters:\n");
 148
 149        m = 0;
 150        max = min(efw->phys_out, meters->out_meters);
 151        linear = meters->values;
 152        snd_iprintf(buffer, " %d Outputs:\n", max);
 153        for (g = 0; g < efw->phys_out_grp_count; g++) {
 154                name = get_phys_name(&efw->phys_out_grps[g], false);
 155                for (c = 0; c < efw->phys_out_grps[g].count; c++) {
 156                        if (m < max)
 157                                snd_iprintf(buffer, "\t%s [%d]: %d\n",
 158                                            name, c, linear[m++]);
 159                }
 160        }
 161
 162        m = 0;
 163        max = min(efw->phys_in, meters->in_meters);
 164        linear = meters->values + meters->out_meters;
 165        snd_iprintf(buffer, " %d Inputs:\n", max);
 166        for (g = 0; g < efw->phys_in_grp_count; g++) {
 167                name = get_phys_name(&efw->phys_in_grps[g], true);
 168                for (c = 0; c < efw->phys_in_grps[g].count; c++)
 169                        if (m < max)
 170                                snd_iprintf(buffer, "\t%s [%d]: %d\n",
 171                                            name, c, linear[m++]);
 172        }
 173end:
 174        kfree(meters);
 175}
 176
 177static void
 178proc_read_queues_state(struct snd_info_entry *entry,
 179                       struct snd_info_buffer *buffer)
 180{
 181        struct snd_efw *efw = entry->private_data;
 182        unsigned int consumed;
 183
 184        if (efw->pull_ptr > efw->push_ptr)
 185                consumed = snd_efw_resp_buf_size -
 186                           (unsigned int)(efw->pull_ptr - efw->push_ptr);
 187        else
 188                consumed = (unsigned int)(efw->push_ptr - efw->pull_ptr);
 189
 190        snd_iprintf(buffer, "%d/%d\n",
 191                    consumed, snd_efw_resp_buf_size);
 192}
 193
 194static void
 195add_node(struct snd_efw *efw, struct snd_info_entry *root, const char *name,
 196         void (*op)(struct snd_info_entry *e, struct snd_info_buffer *b))
 197{
 198        struct snd_info_entry *entry;
 199
 200        entry = snd_info_create_card_entry(efw->card, name, root);
 201        if (entry)
 202                snd_info_set_text_ops(entry, efw, op);
 203}
 204
 205void snd_efw_proc_init(struct snd_efw *efw)
 206{
 207        struct snd_info_entry *root;
 208
 209        /*
 210         * All nodes are automatically removed at snd_card_disconnect(),
 211         * by following to link list.
 212         */
 213        root = snd_info_create_card_entry(efw->card, "firewire",
 214                                          efw->card->proc_root);
 215        if (root == NULL)
 216                return;
 217        root->mode = S_IFDIR | 0555;
 218
 219        add_node(efw, root, "clock", proc_read_clock);
 220        add_node(efw, root, "firmware", proc_read_hwinfo);
 221        add_node(efw, root, "meters", proc_read_phys_meters);
 222        add_node(efw, root, "queues", proc_read_queues_state);
 223}
 224