1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * motu-proc.c - a part of driver for MOTU FireWire series |
4 | * |
5 | * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp> |
6 | */ |
7 | |
8 | #include "./motu.h" |
9 | |
10 | static const char *const clock_names[] = { |
11 | [SND_MOTU_CLOCK_SOURCE_INTERNAL] = "Internal" , |
12 | [SND_MOTU_CLOCK_SOURCE_ADAT_ON_DSUB] = "ADAT on Dsub-9pin interface" , |
13 | [SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT] = "ADAT on optical interface" , |
14 | [SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_A] = "ADAT on optical interface A" , |
15 | [SND_MOTU_CLOCK_SOURCE_ADAT_ON_OPT_B] = "ADAT on optical interface B" , |
16 | [SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT] = "S/PDIF on optical interface" , |
17 | [SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_A] = "S/PDIF on optical interface A" , |
18 | [SND_MOTU_CLOCK_SOURCE_SPDIF_ON_OPT_B] = "S/PDIF on optical interface B" , |
19 | [SND_MOTU_CLOCK_SOURCE_SPDIF_ON_COAX] = "S/PDIF on coaxial interface" , |
20 | [SND_MOTU_CLOCK_SOURCE_AESEBU_ON_XLR] = "AESEBU on XLR interface" , |
21 | [SND_MOTU_CLOCK_SOURCE_WORD_ON_BNC] = "Word clock on BNC interface" , |
22 | [SND_MOTU_CLOCK_SOURCE_SPH] = "Source packet header" , |
23 | [SND_MOTU_CLOCK_SOURCE_UNKNOWN] = "Unknown" , |
24 | }; |
25 | |
26 | static void proc_read_clock(struct snd_info_entry *entry, |
27 | struct snd_info_buffer *buffer) |
28 | { |
29 | |
30 | struct snd_motu *motu = entry->private_data; |
31 | unsigned int rate; |
32 | enum snd_motu_clock_source source; |
33 | |
34 | if (snd_motu_protocol_get_clock_rate(motu, rate: &rate) < 0) |
35 | return; |
36 | if (snd_motu_protocol_get_clock_source(motu, source: &source) < 0) |
37 | return; |
38 | |
39 | snd_iprintf(buffer, "Rate:\t%d\n" , rate); |
40 | snd_iprintf(buffer, "Source:\t%s\n" , clock_names[source]); |
41 | } |
42 | |
43 | static void proc_read_format(struct snd_info_entry *entry, |
44 | struct snd_info_buffer *buffer) |
45 | { |
46 | struct snd_motu *motu = entry->private_data; |
47 | unsigned int mode; |
48 | struct snd_motu_packet_format *formats; |
49 | int i; |
50 | |
51 | if (snd_motu_protocol_cache_packet_formats(motu) < 0) |
52 | return; |
53 | |
54 | snd_iprintf(buffer, "tx:\tmsg\tfixed\ttotal\n" ); |
55 | for (i = 0; i < SND_MOTU_CLOCK_RATE_COUNT; ++i) { |
56 | mode = i >> 1; |
57 | |
58 | formats = &motu->tx_packet_formats; |
59 | snd_iprintf(buffer, |
60 | "%u:\t%u\t%u\t%u\n" , |
61 | snd_motu_clock_rates[i], |
62 | formats->msg_chunks, |
63 | motu->spec->tx_fixed_pcm_chunks[mode], |
64 | formats->pcm_chunks[mode]); |
65 | } |
66 | |
67 | snd_iprintf(buffer, "rx:\tmsg\tfixed\ttotal\n" ); |
68 | for (i = 0; i < SND_MOTU_CLOCK_RATE_COUNT; ++i) { |
69 | mode = i >> 1; |
70 | |
71 | formats = &motu->rx_packet_formats; |
72 | snd_iprintf(buffer, |
73 | "%u:\t%u\t%u\t%u\n" , |
74 | snd_motu_clock_rates[i], |
75 | formats->msg_chunks, |
76 | motu->spec->rx_fixed_pcm_chunks[mode], |
77 | formats->pcm_chunks[mode]); |
78 | } |
79 | } |
80 | |
81 | static void add_node(struct snd_motu *motu, struct snd_info_entry *root, |
82 | const char *name, |
83 | void (*op)(struct snd_info_entry *e, |
84 | struct snd_info_buffer *b)) |
85 | { |
86 | struct snd_info_entry *entry; |
87 | |
88 | entry = snd_info_create_card_entry(card: motu->card, name, parent: root); |
89 | if (entry) |
90 | snd_info_set_text_ops(entry, private_data: motu, read: op); |
91 | } |
92 | |
93 | void snd_motu_proc_init(struct snd_motu *motu) |
94 | { |
95 | struct snd_info_entry *root; |
96 | |
97 | /* |
98 | * All nodes are automatically removed at snd_card_disconnect(), |
99 | * by following to link list. |
100 | */ |
101 | root = snd_info_create_card_entry(card: motu->card, name: "firewire" , |
102 | parent: motu->card->proc_root); |
103 | if (root == NULL) |
104 | return; |
105 | root->mode = S_IFDIR | 0555; |
106 | |
107 | add_node(motu, root, name: "clock" , op: proc_read_clock); |
108 | add_node(motu, root, name: "format" , op: proc_read_format); |
109 | } |
110 | |