diff options
author | Takashi Sakamoto <o-takashi@sakamocchi.jp> | 2014-04-25 09:45:08 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2014-05-26 08:27:47 -0400 |
commit | 6a22683e89e2c851f754ebbec0f2a53f2967bc07 (patch) | |
tree | ab1ee3b97ee3d5402371e2c1bc205283a100a79e /sound | |
parent | b84b1a27b48eb3aea13127f83ec291c614df2992 (diff) |
ALSA: fireworks: Add proc interface for debugging purpose
This commit adds proc interface to output infomation for debugging.
- firmware information
- sampling rate and clock source
- physical metering (linear value)
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/firewire/fireworks/Makefile | 2 | ||||
-rw-r--r-- | sound/firewire/fireworks/fireworks.c | 17 | ||||
-rw-r--r-- | sound/firewire/fireworks/fireworks.h | 11 | ||||
-rw-r--r-- | sound/firewire/fireworks/fireworks_proc.c | 214 |
4 files changed, 243 insertions, 1 deletions
diff --git a/sound/firewire/fireworks/Makefile b/sound/firewire/fireworks/Makefile index 1bccb653e326..52bd15e285b0 100644 --- a/sound/firewire/fireworks/Makefile +++ b/sound/firewire/fireworks/Makefile | |||
@@ -1,3 +1,3 @@ | |||
1 | snd-fireworks-objs := fireworks_transaction.o fireworks_command.o \ | 1 | snd-fireworks-objs := fireworks_transaction.o fireworks_command.o \ |
2 | fireworks_stream.o fireworks.o | 2 | fireworks_stream.o fireworks_proc.o fireworks.o |
3 | obj-m += snd-fireworks.o | 3 | obj-m += snd-fireworks.o |
diff --git a/sound/firewire/fireworks/fireworks.c b/sound/firewire/fireworks/fireworks.c index 25997f1ee300..311e4a6ef0a6 100644 --- a/sound/firewire/fireworks/fireworks.c +++ b/sound/firewire/fireworks/fireworks.c | |||
@@ -150,6 +150,21 @@ get_hardware_info(struct snd_efw *efw) | |||
150 | efw->pcm_playback_channels[0] = hwinfo->amdtp_rx_pcm_channels; | 150 | efw->pcm_playback_channels[0] = hwinfo->amdtp_rx_pcm_channels; |
151 | efw->pcm_playback_channels[1] = hwinfo->amdtp_rx_pcm_channels_2x; | 151 | efw->pcm_playback_channels[1] = hwinfo->amdtp_rx_pcm_channels_2x; |
152 | efw->pcm_playback_channels[2] = hwinfo->amdtp_rx_pcm_channels_4x; | 152 | efw->pcm_playback_channels[2] = hwinfo->amdtp_rx_pcm_channels_4x; |
153 | |||
154 | /* Hardware metering. */ | ||
155 | if (hwinfo->phys_in_grp_count > HWINFO_MAX_CAPS_GROUPS || | ||
156 | hwinfo->phys_out_grp_count > HWINFO_MAX_CAPS_GROUPS) { | ||
157 | return -EIO; | ||
158 | goto end; | ||
159 | } | ||
160 | efw->phys_in = hwinfo->phys_in; | ||
161 | efw->phys_out = hwinfo->phys_out; | ||
162 | efw->phys_in_grp_count = hwinfo->phys_in_grp_count; | ||
163 | efw->phys_out_grp_count = hwinfo->phys_out_grp_count; | ||
164 | memcpy(&efw->phys_in_grps, hwinfo->phys_in_grps, | ||
165 | sizeof(struct snd_efw_phys_grp) * hwinfo->phys_in_grp_count); | ||
166 | memcpy(&efw->phys_out_grps, hwinfo->phys_out_grps, | ||
167 | sizeof(struct snd_efw_phys_grp) * hwinfo->phys_out_grp_count); | ||
153 | end: | 168 | end: |
154 | kfree(hwinfo); | 169 | kfree(hwinfo); |
155 | return err; | 170 | return err; |
@@ -209,6 +224,8 @@ efw_probe(struct fw_unit *unit, | |||
209 | if (entry->model_id == MODEL_ECHO_AUDIOFIRE_9) | 224 | if (entry->model_id == MODEL_ECHO_AUDIOFIRE_9) |
210 | efw->is_af9 = true; | 225 | efw->is_af9 = true; |
211 | 226 | ||
227 | snd_efw_proc_init(efw); | ||
228 | |||
212 | err = snd_efw_stream_init_duplex(efw); | 229 | err = snd_efw_stream_init_duplex(efw); |
213 | if (err < 0) | 230 | if (err < 0) |
214 | goto error; | 231 | goto error; |
diff --git a/sound/firewire/fireworks/fireworks.h b/sound/firewire/fireworks/fireworks.h index 3f998510ddf3..eef7ad89fd4e 100644 --- a/sound/firewire/fireworks/fireworks.h +++ b/sound/firewire/fireworks/fireworks.h | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <sound/core.h> | 21 | #include <sound/core.h> |
22 | #include <sound/initval.h> | 22 | #include <sound/initval.h> |
23 | #include <sound/pcm.h> | 23 | #include <sound/pcm.h> |
24 | #include <sound/info.h> | ||
24 | 25 | ||
25 | #include "../packets-buffer.h" | 26 | #include "../packets-buffer.h" |
26 | #include "../iso-resources.h" | 27 | #include "../iso-resources.h" |
@@ -79,6 +80,14 @@ struct snd_efw { | |||
79 | struct cmp_connection in_conn; | 80 | struct cmp_connection in_conn; |
80 | atomic_t capture_substreams; | 81 | atomic_t capture_substreams; |
81 | atomic_t playback_substreams; | 82 | atomic_t playback_substreams; |
83 | |||
84 | /* hardware metering parameters */ | ||
85 | unsigned int phys_out; | ||
86 | unsigned int phys_in; | ||
87 | unsigned int phys_out_grp_count; | ||
88 | unsigned int phys_in_grp_count; | ||
89 | struct snd_efw_phys_grp phys_out_grps[HWINFO_MAX_CAPS_GROUPS]; | ||
90 | struct snd_efw_phys_grp phys_in_grps[HWINFO_MAX_CAPS_GROUPS]; | ||
82 | }; | 91 | }; |
83 | 92 | ||
84 | struct snd_efw_transaction { | 93 | struct snd_efw_transaction { |
@@ -187,6 +196,8 @@ void snd_efw_stream_stop_duplex(struct snd_efw *efw); | |||
187 | void snd_efw_stream_update_duplex(struct snd_efw *efw); | 196 | void snd_efw_stream_update_duplex(struct snd_efw *efw); |
188 | void snd_efw_stream_destroy_duplex(struct snd_efw *efw); | 197 | void snd_efw_stream_destroy_duplex(struct snd_efw *efw); |
189 | 198 | ||
199 | void snd_efw_proc_init(struct snd_efw *efw); | ||
200 | |||
190 | #define SND_EFW_DEV_ENTRY(vendor, model) \ | 201 | #define SND_EFW_DEV_ENTRY(vendor, model) \ |
191 | { \ | 202 | { \ |
192 | .match_flags = IEEE1394_MATCH_VENDOR_ID | \ | 203 | .match_flags = IEEE1394_MATCH_VENDOR_ID | \ |
diff --git a/sound/firewire/fireworks/fireworks_proc.c b/sound/firewire/fireworks/fireworks_proc.c new file mode 100644 index 000000000000..631c91f64db4 --- /dev/null +++ b/sound/firewire/fireworks/fireworks_proc.c | |||
@@ -0,0 +1,214 @@ | |||
1 | /* | ||
2 | * fireworks_proc.c - a part of driver for Fireworks based devices | ||
3 | * | ||
4 | * Copyright (c) 2009-2010 Clemens Ladisch | ||
5 | * Copyright (c) 2013-2014 Takashi Sakamoto | ||
6 | * | ||
7 | * Licensed under the terms of the GNU General Public License, version 2. | ||
8 | */ | ||
9 | |||
10 | #include "./fireworks.h" | ||
11 | |||
12 | static inline const char* | ||
13 | get_phys_name(struct snd_efw_phys_grp *grp, bool input) | ||
14 | { | ||
15 | const char *const ch_type[] = { | ||
16 | "Analog", "S/PDIF", "ADAT", "S/PDIF or ADAT", "Mirroring", | ||
17 | "Headphones", "I2S", "Guitar", "Pirzo Guitar", "Guitar String", | ||
18 | }; | ||
19 | |||
20 | if (grp->type < ARRAY_SIZE(ch_type)) | ||
21 | return ch_type[grp->type]; | ||
22 | else if (input) | ||
23 | return "Input"; | ||
24 | else | ||
25 | return "Output"; | ||
26 | } | ||
27 | |||
28 | static void | ||
29 | proc_read_hwinfo(struct snd_info_entry *entry, struct snd_info_buffer *buffer) | ||
30 | { | ||
31 | struct snd_efw *efw = entry->private_data; | ||
32 | unsigned short i; | ||
33 | struct snd_efw_hwinfo *hwinfo; | ||
34 | |||
35 | hwinfo = kmalloc(sizeof(struct snd_efw_hwinfo), GFP_KERNEL); | ||
36 | if (hwinfo == NULL) | ||
37 | return; | ||
38 | |||
39 | if (snd_efw_command_get_hwinfo(efw, hwinfo) < 0) | ||
40 | goto end; | ||
41 | |||
42 | snd_iprintf(buffer, "guid_hi: 0x%X\n", hwinfo->guid_hi); | ||
43 | snd_iprintf(buffer, "guid_lo: 0x%X\n", hwinfo->guid_lo); | ||
44 | snd_iprintf(buffer, "type: 0x%X\n", hwinfo->type); | ||
45 | snd_iprintf(buffer, "version: 0x%X\n", hwinfo->version); | ||
46 | snd_iprintf(buffer, "vendor_name: %s\n", hwinfo->vendor_name); | ||
47 | snd_iprintf(buffer, "model_name: %s\n", hwinfo->model_name); | ||
48 | |||
49 | snd_iprintf(buffer, "dsp_version: 0x%X\n", hwinfo->dsp_version); | ||
50 | snd_iprintf(buffer, "arm_version: 0x%X\n", hwinfo->arm_version); | ||
51 | snd_iprintf(buffer, "fpga_version: 0x%X\n", hwinfo->fpga_version); | ||
52 | |||
53 | snd_iprintf(buffer, "flags: 0x%X\n", hwinfo->flags); | ||
54 | |||
55 | snd_iprintf(buffer, "max_sample_rate: 0x%X\n", hwinfo->max_sample_rate); | ||
56 | snd_iprintf(buffer, "min_sample_rate: 0x%X\n", hwinfo->min_sample_rate); | ||
57 | snd_iprintf(buffer, "supported_clock: 0x%X\n", | ||
58 | hwinfo->supported_clocks); | ||
59 | |||
60 | snd_iprintf(buffer, "phys out: 0x%X\n", hwinfo->phys_out); | ||
61 | snd_iprintf(buffer, "phys in: 0x%X\n", hwinfo->phys_in); | ||
62 | |||
63 | snd_iprintf(buffer, "phys in grps: 0x%X\n", | ||
64 | hwinfo->phys_in_grp_count); | ||
65 | for (i = 0; i < hwinfo->phys_in_grp_count; i++) { | ||
66 | snd_iprintf(buffer, | ||
67 | "phys in grp[0x%d]: type 0x%d, count 0x%d\n", | ||
68 | i, hwinfo->phys_out_grps[i].type, | ||
69 | hwinfo->phys_out_grps[i].count); | ||
70 | } | ||
71 | |||
72 | snd_iprintf(buffer, "phys out grps: 0x%X\n", | ||
73 | hwinfo->phys_out_grp_count); | ||
74 | for (i = 0; i < hwinfo->phys_out_grp_count; i++) { | ||
75 | snd_iprintf(buffer, | ||
76 | "phys out grps[0x%d]: type 0x%d, count 0x%d\n", | ||
77 | i, hwinfo->phys_out_grps[i].type, | ||
78 | hwinfo->phys_out_grps[i].count); | ||
79 | } | ||
80 | |||
81 | snd_iprintf(buffer, "amdtp rx pcm channels 1x: 0x%X\n", | ||
82 | hwinfo->amdtp_rx_pcm_channels); | ||
83 | snd_iprintf(buffer, "amdtp tx pcm channels 1x: 0x%X\n", | ||
84 | hwinfo->amdtp_tx_pcm_channels); | ||
85 | snd_iprintf(buffer, "amdtp rx pcm channels 2x: 0x%X\n", | ||
86 | hwinfo->amdtp_rx_pcm_channels_2x); | ||
87 | snd_iprintf(buffer, "amdtp tx pcm channels 2x: 0x%X\n", | ||
88 | hwinfo->amdtp_tx_pcm_channels_2x); | ||
89 | snd_iprintf(buffer, "amdtp rx pcm channels 4x: 0x%X\n", | ||
90 | hwinfo->amdtp_rx_pcm_channels_4x); | ||
91 | snd_iprintf(buffer, "amdtp tx pcm channels 4x: 0x%X\n", | ||
92 | hwinfo->amdtp_tx_pcm_channels_4x); | ||
93 | |||
94 | snd_iprintf(buffer, "midi out ports: 0x%X\n", hwinfo->midi_out_ports); | ||
95 | snd_iprintf(buffer, "midi in ports: 0x%X\n", hwinfo->midi_in_ports); | ||
96 | |||
97 | snd_iprintf(buffer, "mixer playback channels: 0x%X\n", | ||
98 | hwinfo->mixer_playback_channels); | ||
99 | snd_iprintf(buffer, "mixer capture channels: 0x%X\n", | ||
100 | hwinfo->mixer_capture_channels); | ||
101 | end: | ||
102 | kfree(hwinfo); | ||
103 | } | ||
104 | |||
105 | static void | ||
106 | proc_read_clock(struct snd_info_entry *entry, struct snd_info_buffer *buffer) | ||
107 | { | ||
108 | struct snd_efw *efw = entry->private_data; | ||
109 | enum snd_efw_clock_source clock_source; | ||
110 | unsigned int sampling_rate; | ||
111 | |||
112 | if (snd_efw_command_get_clock_source(efw, &clock_source) < 0) | ||
113 | return; | ||
114 | |||
115 | if (snd_efw_command_get_sampling_rate(efw, &sampling_rate) < 0) | ||
116 | return; | ||
117 | |||
118 | snd_iprintf(buffer, "Clock Source: %d\n", clock_source); | ||
119 | snd_iprintf(buffer, "Sampling Rate: %d\n", sampling_rate); | ||
120 | } | ||
121 | |||
122 | /* | ||
123 | * NOTE: | ||
124 | * dB = 20 * log10(linear / 0x01000000) | ||
125 | * -144.0 dB when linear is 0 | ||
126 | */ | ||
127 | static void | ||
128 | proc_read_phys_meters(struct snd_info_entry *entry, | ||
129 | struct snd_info_buffer *buffer) | ||
130 | { | ||
131 | struct snd_efw *efw = entry->private_data; | ||
132 | struct snd_efw_phys_meters *meters; | ||
133 | unsigned int g, c, m, max, size; | ||
134 | const char *name; | ||
135 | u32 *linear; | ||
136 | int err; | ||
137 | |||
138 | size = sizeof(struct snd_efw_phys_meters) + | ||
139 | (efw->phys_in + efw->phys_out) * sizeof(u32); | ||
140 | meters = kzalloc(size, GFP_KERNEL); | ||
141 | if (meters == NULL) | ||
142 | return; | ||
143 | |||
144 | err = snd_efw_command_get_phys_meters(efw, meters, size); | ||
145 | if (err < 0) | ||
146 | goto end; | ||
147 | |||
148 | snd_iprintf(buffer, "Physical Meters:\n"); | ||
149 | |||
150 | m = 0; | ||
151 | max = min(efw->phys_out, meters->out_meters); | ||
152 | linear = meters->values; | ||
153 | snd_iprintf(buffer, " %d Outputs:\n", max); | ||
154 | for (g = 0; g < efw->phys_out_grp_count; g++) { | ||
155 | name = get_phys_name(&efw->phys_out_grps[g], false); | ||
156 | for (c = 0; c < efw->phys_out_grps[g].count; c++) { | ||
157 | if (m < max) | ||
158 | snd_iprintf(buffer, "\t%s [%d]: %d\n", | ||
159 | name, c, linear[m++]); | ||
160 | } | ||
161 | } | ||
162 | |||
163 | m = 0; | ||
164 | max = min(efw->phys_in, meters->in_meters); | ||
165 | linear = meters->values + meters->out_meters; | ||
166 | snd_iprintf(buffer, " %d Inputs:\n", max); | ||
167 | for (g = 0; g < efw->phys_in_grp_count; g++) { | ||
168 | name = get_phys_name(&efw->phys_in_grps[g], true); | ||
169 | for (c = 0; c < efw->phys_in_grps[g].count; c++) | ||
170 | if (m < max) | ||
171 | snd_iprintf(buffer, "\t%s [%d]: %d\n", | ||
172 | name, c, linear[m++]); | ||
173 | } | ||
174 | end: | ||
175 | kfree(meters); | ||
176 | } | ||
177 | |||
178 | static void | ||
179 | add_node(struct snd_efw *efw, struct snd_info_entry *root, const char *name, | ||
180 | void (*op)(struct snd_info_entry *e, struct snd_info_buffer *b)) | ||
181 | { | ||
182 | struct snd_info_entry *entry; | ||
183 | |||
184 | entry = snd_info_create_card_entry(efw->card, name, root); | ||
185 | if (entry == NULL) | ||
186 | return; | ||
187 | |||
188 | snd_info_set_text_ops(entry, efw, op); | ||
189 | if (snd_info_register(entry) < 0) | ||
190 | snd_info_free_entry(entry); | ||
191 | } | ||
192 | |||
193 | void snd_efw_proc_init(struct snd_efw *efw) | ||
194 | { | ||
195 | struct snd_info_entry *root; | ||
196 | |||
197 | /* | ||
198 | * All nodes are automatically removed at snd_card_disconnect(), | ||
199 | * by following to link list. | ||
200 | */ | ||
201 | root = snd_info_create_card_entry(efw->card, "firewire", | ||
202 | efw->card->proc_root); | ||
203 | if (root == NULL) | ||
204 | return; | ||
205 | root->mode = S_IFDIR | S_IRUGO | S_IXUGO; | ||
206 | if (snd_info_register(root) < 0) { | ||
207 | snd_info_free_entry(root); | ||
208 | return; | ||
209 | } | ||
210 | |||
211 | add_node(efw, root, "clock", proc_read_clock); | ||
212 | add_node(efw, root, "firmware", proc_read_hwinfo); | ||
213 | add_node(efw, root, "meters", proc_read_phys_meters); | ||
214 | } | ||