1 /* 2 * ff-proc.c - a part of driver for RME Fireface series 3 * 4 * Copyright (c) 2015-2017 Takashi Sakamoto 5 * 6 * Licensed under the terms of the GNU General Public License, version 2. 7 */ 8 9 #include "./ff.h" 10 11 static void proc_dump_clock_config(struct snd_info_entry *entry, 12 struct snd_info_buffer *buffer) 13 { 14 struct snd_ff *ff = entry->private_data; 15 __le32 reg; 16 u32 data; 17 unsigned int rate; 18 const char *src; 19 int err; 20 21 err = snd_fw_transaction(ff->unit, TCODE_READ_BLOCK_REQUEST, 22 SND_FF_REG_CLOCK_CONFIG, ®, sizeof(reg), 0); 23 if (err < 0) 24 return; 25 26 data = le32_to_cpu(reg); 27 28 snd_iprintf(buffer, "Output S/PDIF format: %s (Emphasis: %s)\n", 29 (data & 0x20) ? "Professional" : "Consumer", 30 (data & 0x40) ? "on" : "off"); 31 32 snd_iprintf(buffer, "Optical output interface format: %s\n", 33 ((data >> 8) & 0x01) ? "S/PDIF" : "ADAT"); 34 35 snd_iprintf(buffer, "Word output single speed: %s\n", 36 ((data >> 8) & 0x20) ? "on" : "off"); 37 38 snd_iprintf(buffer, "S/PDIF input interface: %s\n", 39 ((data >> 8) & 0x02) ? "Optical" : "Coaxial"); 40 41 switch ((data >> 1) & 0x03) { 42 case 0x01: 43 rate = 32000; 44 break; 45 case 0x00: 46 rate = 44100; 47 break; 48 case 0x03: 49 rate = 48000; 50 break; 51 case 0x02: 52 default: 53 return; 54 } 55 56 if (data & 0x08) 57 rate *= 2; 58 else if (data & 0x10) 59 rate *= 4; 60 61 snd_iprintf(buffer, "Sampling rate: %d\n", rate); 62 63 if (data & 0x01) { 64 src = "Internal"; 65 } else { 66 switch ((data >> 10) & 0x07) { 67 case 0x00: 68 src = "ADAT1"; 69 break; 70 case 0x01: 71 src = "ADAT2"; 72 break; 73 case 0x03: 74 src = "S/PDIF"; 75 break; 76 case 0x04: 77 src = "Word"; 78 break; 79 case 0x05: 80 src = "LTC"; 81 break; 82 default: 83 return; 84 } 85 } 86 87 snd_iprintf(buffer, "Sync to clock source: %s\n", src); 88 } 89 90 static void proc_dump_sync_status(struct snd_info_entry *entry, 91 struct snd_info_buffer *buffer) 92 { 93 struct snd_ff *ff = entry->private_data; 94 __le32 reg; 95 u32 data; 96 int err; 97 98 err = snd_fw_transaction(ff->unit, TCODE_READ_QUADLET_REQUEST, 99 SND_FF_REG_SYNC_STATUS, ®, sizeof(reg), 0); 100 if (err < 0) 101 return; 102 103 data = le32_to_cpu(reg); 104 105 snd_iprintf(buffer, "External source detection:\n"); 106 107 snd_iprintf(buffer, "Word Clock:"); 108 if ((data >> 24) & 0x20) { 109 if ((data >> 24) & 0x40) 110 snd_iprintf(buffer, "sync\n"); 111 else 112 snd_iprintf(buffer, "lock\n"); 113 } else { 114 snd_iprintf(buffer, "none\n"); 115 } 116 117 snd_iprintf(buffer, "S/PDIF:"); 118 if ((data >> 16) & 0x10) { 119 if ((data >> 16) & 0x04) 120 snd_iprintf(buffer, "sync\n"); 121 else 122 snd_iprintf(buffer, "lock\n"); 123 } else { 124 snd_iprintf(buffer, "none\n"); 125 } 126 127 snd_iprintf(buffer, "ADAT1:"); 128 if ((data >> 8) & 0x04) { 129 if ((data >> 8) & 0x10) 130 snd_iprintf(buffer, "sync\n"); 131 else 132 snd_iprintf(buffer, "lock\n"); 133 } else { 134 snd_iprintf(buffer, "none\n"); 135 } 136 137 snd_iprintf(buffer, "ADAT2:"); 138 if ((data >> 8) & 0x08) { 139 if ((data >> 8) & 0x20) 140 snd_iprintf(buffer, "sync\n"); 141 else 142 snd_iprintf(buffer, "lock\n"); 143 } else { 144 snd_iprintf(buffer, "none\n"); 145 } 146 147 snd_iprintf(buffer, "\nUsed external source:\n"); 148 149 if (((data >> 22) & 0x07) == 0x07) { 150 snd_iprintf(buffer, "None\n"); 151 } else { 152 switch ((data >> 22) & 0x07) { 153 case 0x00: 154 snd_iprintf(buffer, "ADAT1:"); 155 break; 156 case 0x01: 157 snd_iprintf(buffer, "ADAT2:"); 158 break; 159 case 0x03: 160 snd_iprintf(buffer, "S/PDIF:"); 161 break; 162 case 0x04: 163 snd_iprintf(buffer, "Word:"); 164 break; 165 case 0x07: 166 snd_iprintf(buffer, "Nothing:"); 167 break; 168 case 0x02: 169 case 0x05: 170 case 0x06: 171 default: 172 snd_iprintf(buffer, "unknown:"); 173 break; 174 } 175 176 if ((data >> 25) & 0x07) { 177 switch ((data >> 25) & 0x07) { 178 case 0x01: 179 snd_iprintf(buffer, "32000\n"); 180 break; 181 case 0x02: 182 snd_iprintf(buffer, "44100\n"); 183 break; 184 case 0x03: 185 snd_iprintf(buffer, "48000\n"); 186 break; 187 case 0x04: 188 snd_iprintf(buffer, "64000\n"); 189 break; 190 case 0x05: 191 snd_iprintf(buffer, "88200\n"); 192 break; 193 case 0x06: 194 snd_iprintf(buffer, "96000\n"); 195 break; 196 case 0x07: 197 snd_iprintf(buffer, "128000\n"); 198 break; 199 case 0x08: 200 snd_iprintf(buffer, "176400\n"); 201 break; 202 case 0x09: 203 snd_iprintf(buffer, "192000\n"); 204 break; 205 case 0x00: 206 snd_iprintf(buffer, "unknown\n"); 207 break; 208 } 209 } 210 } 211 212 snd_iprintf(buffer, "Multiplied:"); 213 snd_iprintf(buffer, "%d\n", (data & 0x3ff) * 250); 214 } 215 216 static void add_node(struct snd_ff *ff, struct snd_info_entry *root, 217 const char *name, 218 void (*op)(struct snd_info_entry *e, 219 struct snd_info_buffer *b)) 220 { 221 struct snd_info_entry *entry; 222 223 entry = snd_info_create_card_entry(ff->card, name, root); 224 if (entry == NULL) 225 return; 226 227 snd_info_set_text_ops(entry, ff, op); 228 if (snd_info_register(entry) < 0) 229 snd_info_free_entry(entry); 230 } 231 232 void snd_ff_proc_init(struct snd_ff *ff) 233 { 234 struct snd_info_entry *root; 235 236 /* 237 * All nodes are automatically removed at snd_card_disconnect(), 238 * by following to link list. 239 */ 240 root = snd_info_create_card_entry(ff->card, "firewire", 241 ff->card->proc_root); 242 if (root == NULL) 243 return; 244 root->mode = S_IFDIR | 0555; 245 if (snd_info_register(root) < 0) { 246 snd_info_free_entry(root); 247 return; 248 } 249 250 add_node(ff, root, "clock-config", proc_dump_clock_config); 251 add_node(ff, root, "sync-status", proc_dump_sync_status); 252 } 253