Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / sound / firewire / dice / dice-proc.c
1 /*
2  * dice_proc.c - a part of driver for Dice based devices
3  *
4  * Copyright (c) Clemens Ladisch
5  * Copyright (c) 2014 Takashi Sakamoto
6  *
7  * Licensed under the terms of the GNU General Public License, version 2.
8  */
9
10 #include "dice.h"
11
12 static int dice_proc_read_mem(struct snd_dice *dice, void *buffer,
13                               unsigned int offset_q, unsigned int quadlets)
14 {
15         unsigned int i;
16         int err;
17
18         err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
19                                  DICE_PRIVATE_SPACE + 4 * offset_q,
20                                  buffer, 4 * quadlets, 0);
21         if (err < 0)
22                 return err;
23
24         for (i = 0; i < quadlets; ++i)
25                 be32_to_cpus(&((u32 *)buffer)[i]);
26
27         return 0;
28 }
29
30 static const char *str_from_array(const char *const strs[], unsigned int count,
31                                   unsigned int i)
32 {
33         if (i < count)
34                 return strs[i];
35
36         return "(unknown)";
37 }
38
39 static void dice_proc_fixup_string(char *s, unsigned int size)
40 {
41         unsigned int i;
42
43         for (i = 0; i < size; i += 4)
44                 cpu_to_le32s((u32 *)(s + i));
45
46         for (i = 0; i < size - 2; ++i) {
47                 if (s[i] == '\0')
48                         return;
49                 if (s[i] == '\\' && s[i + 1] == '\\') {
50                         s[i + 2] = '\0';
51                         return;
52                 }
53         }
54         s[size - 1] = '\0';
55 }
56
57 static void dice_proc_read(struct snd_info_entry *entry,
58                            struct snd_info_buffer *buffer)
59 {
60         static const char *const section_names[5] = {
61                 "global", "tx", "rx", "ext_sync", "unused2"
62         };
63         static const char *const clock_sources[] = {
64                 "aes1", "aes2", "aes3", "aes4", "aes", "adat", "tdif",
65                 "wc", "arx1", "arx2", "arx3", "arx4", "internal"
66         };
67         static const char *const rates[] = {
68                 "32000", "44100", "48000", "88200", "96000", "176400", "192000",
69                 "any low", "any mid", "any high", "none"
70         };
71         struct snd_dice *dice = entry->private_data;
72         u32 sections[ARRAY_SIZE(section_names) * 2];
73         struct {
74                 u32 number;
75                 u32 size;
76         } tx_rx_header;
77         union {
78                 struct {
79                         u32 owner_hi, owner_lo;
80                         u32 notification;
81                         char nick_name[NICK_NAME_SIZE];
82                         u32 clock_select;
83                         u32 enable;
84                         u32 status;
85                         u32 extended_status;
86                         u32 sample_rate;
87                         u32 version;
88                         u32 clock_caps;
89                         char clock_source_names[CLOCK_SOURCE_NAMES_SIZE];
90                 } global;
91                 struct {
92                         u32 iso;
93                         u32 number_audio;
94                         u32 number_midi;
95                         u32 speed;
96                         char names[TX_NAMES_SIZE];
97                         u32 ac3_caps;
98                         u32 ac3_enable;
99                 } tx;
100                 struct {
101                         u32 iso;
102                         u32 seq_start;
103                         u32 number_audio;
104                         u32 number_midi;
105                         char names[RX_NAMES_SIZE];
106                         u32 ac3_caps;
107                         u32 ac3_enable;
108                 } rx;
109                 struct {
110                         u32 clock_source;
111                         u32 locked;
112                         u32 rate;
113                         u32 adat_user_data;
114                 } ext_sync;
115         } buf;
116         unsigned int quadlets, stream, i;
117
118         if (dice_proc_read_mem(dice, sections, 0, ARRAY_SIZE(sections)) < 0)
119                 return;
120         snd_iprintf(buffer, "sections:\n");
121         for (i = 0; i < ARRAY_SIZE(section_names); ++i)
122                 snd_iprintf(buffer, "  %s: offset %u, size %u\n",
123                             section_names[i],
124                             sections[i * 2], sections[i * 2 + 1]);
125
126         quadlets = min_t(u32, sections[1], sizeof(buf.global) / 4);
127         if (dice_proc_read_mem(dice, &buf.global, sections[0], quadlets) < 0)
128                 return;
129         snd_iprintf(buffer, "global:\n");
130         snd_iprintf(buffer, "  owner: %04x:%04x%08x\n",
131                     buf.global.owner_hi >> 16,
132                     buf.global.owner_hi & 0xffff, buf.global.owner_lo);
133         snd_iprintf(buffer, "  notification: %08x\n", buf.global.notification);
134         dice_proc_fixup_string(buf.global.nick_name, NICK_NAME_SIZE);
135         snd_iprintf(buffer, "  nick name: %s\n", buf.global.nick_name);
136         snd_iprintf(buffer, "  clock select: %s %s\n",
137                     str_from_array(clock_sources, ARRAY_SIZE(clock_sources),
138                                    buf.global.clock_select & CLOCK_SOURCE_MASK),
139                     str_from_array(rates, ARRAY_SIZE(rates),
140                                    (buf.global.clock_select & CLOCK_RATE_MASK)
141                                    >> CLOCK_RATE_SHIFT));
142         snd_iprintf(buffer, "  enable: %u\n", buf.global.enable);
143         snd_iprintf(buffer, "  status: %slocked %s\n",
144                     buf.global.status & STATUS_SOURCE_LOCKED ? "" : "un",
145                     str_from_array(rates, ARRAY_SIZE(rates),
146                                    (buf.global.status &
147                                     STATUS_NOMINAL_RATE_MASK)
148                                    >> CLOCK_RATE_SHIFT));
149         snd_iprintf(buffer, "  ext status: %08x\n", buf.global.extended_status);
150         snd_iprintf(buffer, "  sample rate: %u\n", buf.global.sample_rate);
151         snd_iprintf(buffer, "  version: %u.%u.%u.%u\n",
152                     (buf.global.version >> 24) & 0xff,
153                     (buf.global.version >> 16) & 0xff,
154                     (buf.global.version >>  8) & 0xff,
155                     (buf.global.version >>  0) & 0xff);
156         if (quadlets >= 90) {
157                 snd_iprintf(buffer, "  clock caps:");
158                 for (i = 0; i <= 6; ++i)
159                         if (buf.global.clock_caps & (1 << i))
160                                 snd_iprintf(buffer, " %s", rates[i]);
161                 for (i = 0; i <= 12; ++i)
162                         if (buf.global.clock_caps & (1 << (16 + i)))
163                                 snd_iprintf(buffer, " %s", clock_sources[i]);
164                 snd_iprintf(buffer, "\n");
165                 dice_proc_fixup_string(buf.global.clock_source_names,
166                                        CLOCK_SOURCE_NAMES_SIZE);
167                 snd_iprintf(buffer, "  clock source names: %s\n",
168                             buf.global.clock_source_names);
169         }
170
171         if (dice_proc_read_mem(dice, &tx_rx_header, sections[2], 2) < 0)
172                 return;
173         quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.tx) / 4);
174         for (stream = 0; stream < tx_rx_header.number; ++stream) {
175                 if (dice_proc_read_mem(dice, &buf.tx, sections[2] + 2 +
176                                        stream * tx_rx_header.size,
177                                        quadlets) < 0)
178                         break;
179                 snd_iprintf(buffer, "tx %u:\n", stream);
180                 snd_iprintf(buffer, "  iso channel: %d\n", (int)buf.tx.iso);
181                 snd_iprintf(buffer, "  audio channels: %u\n",
182                             buf.tx.number_audio);
183                 snd_iprintf(buffer, "  midi ports: %u\n", buf.tx.number_midi);
184                 snd_iprintf(buffer, "  speed: S%u\n", 100u << buf.tx.speed);
185                 if (quadlets >= 68) {
186                         dice_proc_fixup_string(buf.tx.names, TX_NAMES_SIZE);
187                         snd_iprintf(buffer, "  names: %s\n", buf.tx.names);
188                 }
189                 if (quadlets >= 70) {
190                         snd_iprintf(buffer, "  ac3 caps: %08x\n",
191                                     buf.tx.ac3_caps);
192                         snd_iprintf(buffer, "  ac3 enable: %08x\n",
193                                     buf.tx.ac3_enable);
194                 }
195         }
196
197         if (dice_proc_read_mem(dice, &tx_rx_header, sections[4], 2) < 0)
198                 return;
199         quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.rx) / 4);
200         for (stream = 0; stream < tx_rx_header.number; ++stream) {
201                 if (dice_proc_read_mem(dice, &buf.rx, sections[4] + 2 +
202                                        stream * tx_rx_header.size,
203                                        quadlets) < 0)
204                         break;
205                 snd_iprintf(buffer, "rx %u:\n", stream);
206                 snd_iprintf(buffer, "  iso channel: %d\n", (int)buf.rx.iso);
207                 snd_iprintf(buffer, "  sequence start: %u\n", buf.rx.seq_start);
208                 snd_iprintf(buffer, "  audio channels: %u\n",
209                             buf.rx.number_audio);
210                 snd_iprintf(buffer, "  midi ports: %u\n", buf.rx.number_midi);
211                 if (quadlets >= 68) {
212                         dice_proc_fixup_string(buf.rx.names, RX_NAMES_SIZE);
213                         snd_iprintf(buffer, "  names: %s\n", buf.rx.names);
214                 }
215                 if (quadlets >= 70) {
216                         snd_iprintf(buffer, "  ac3 caps: %08x\n",
217                                     buf.rx.ac3_caps);
218                         snd_iprintf(buffer, "  ac3 enable: %08x\n",
219                                     buf.rx.ac3_enable);
220                 }
221         }
222
223         quadlets = min_t(u32, sections[7], sizeof(buf.ext_sync) / 4);
224         if (quadlets >= 4) {
225                 if (dice_proc_read_mem(dice, &buf.ext_sync,
226                                        sections[6], 4) < 0)
227                         return;
228                 snd_iprintf(buffer, "ext status:\n");
229                 snd_iprintf(buffer, "  clock source: %s\n",
230                             str_from_array(clock_sources,
231                                            ARRAY_SIZE(clock_sources),
232                                            buf.ext_sync.clock_source));
233                 snd_iprintf(buffer, "  locked: %u\n", buf.ext_sync.locked);
234                 snd_iprintf(buffer, "  rate: %s\n",
235                             str_from_array(rates, ARRAY_SIZE(rates),
236                                            buf.ext_sync.rate));
237                 snd_iprintf(buffer, "  adat user data: ");
238                 if (buf.ext_sync.adat_user_data & ADAT_USER_DATA_NO_DATA)
239                         snd_iprintf(buffer, "-\n");
240                 else
241                         snd_iprintf(buffer, "%x\n",
242                                     buf.ext_sync.adat_user_data);
243         }
244 }
245
246 void snd_dice_create_proc(struct snd_dice *dice)
247 {
248         struct snd_info_entry *entry;
249
250         if (!snd_card_proc_new(dice->card, "dice", &entry))
251                 snd_info_set_text_ops(entry, dice, dice_proc_read);
252 }