xref: /linux/sound/pci/ca0106/ca0106_proc.c (revision 05a54fa773284d1a7923cdfdd8f0c8dabb98bd26)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *  Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk>
4  *  Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit
5  *  Version: 0.0.18
6  *
7  *  FEATURES currently supported:
8  *    See ca0106_main.c for features.
9  *
10  *  Changelog:
11  *    Support interrupts per period.
12  *    Removed noise from Center/LFE channel when in Analog mode.
13  *    Rename and remove mixer controls.
14  *  0.0.6
15  *    Use separate card based DMA buffer for periods table list.
16  *  0.0.7
17  *    Change remove and rename ctrls into lists.
18  *  0.0.8
19  *    Try to fix capture sources.
20  *  0.0.9
21  *    Fix AC3 output.
22  *    Enable S32_LE format support.
23  *  0.0.10
24  *    Enable playback 48000 and 96000 rates. (Rates other that these do not work, even with "plug:front".)
25  *  0.0.11
26  *    Add Model name recognition.
27  *  0.0.12
28  *    Correct interrupt timing. interrupt at end of period, instead of in the middle of a playback period.
29  *    Remove redundent "voice" handling.
30  *  0.0.13
31  *    Single trigger call for multi channels.
32  *  0.0.14
33  *    Set limits based on what the sound card hardware can do.
34  *    playback periods_min=2, periods_max=8
35  *    capture hw constraints require period_size = n * 64 bytes.
36  *    playback hw constraints require period_size = n * 64 bytes.
37  *  0.0.15
38  *    Separate ca0106.c into separate functional .c files.
39  *  0.0.16
40  *    Modified Copyright message.
41  *  0.0.17
42  *    Add iec958 file in proc file system to show status of SPDIF in.
43  *  0.0.18
44  *    Implement support for Line-in capture on SB Live 24bit.
45  *
46  *  This code was initially based on code from ALSA's emu10k1x.c which is:
47  *  Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com>
48  */
49 #include <linux/delay.h>
50 #include <linux/init.h>
51 #include <linux/interrupt.h>
52 #include <linux/moduleparam.h>
53 #include <linux/io.h>
54 #include <sound/core.h>
55 #include <sound/initval.h>
56 #include <sound/pcm.h>
57 #include <sound/ac97_codec.h>
58 #include <sound/info.h>
59 #include <sound/asoundef.h>
60 
61 #include "ca0106.h"
62 
63 
64 struct snd_ca0106_category_str {
65 	int val;
66 	const char *name;
67 };
68 
69 static const struct snd_ca0106_category_str snd_ca0106_con_category[] = {
70 	{ IEC958_AES1_CON_DAT, "DAT" },
71 	{ IEC958_AES1_CON_VCR, "VCR" },
72 	{ IEC958_AES1_CON_MICROPHONE, "microphone" },
73 	{ IEC958_AES1_CON_SYNTHESIZER, "synthesizer" },
74 	{ IEC958_AES1_CON_RATE_CONVERTER, "rate converter" },
75 	{ IEC958_AES1_CON_MIXER, "mixer" },
76 	{ IEC958_AES1_CON_SAMPLER, "sampler" },
77 	{ IEC958_AES1_CON_PCM_CODER, "PCM coder" },
78 	{ IEC958_AES1_CON_IEC908_CD, "CD" },
79 	{ IEC958_AES1_CON_NON_IEC908_CD, "non-IEC908 CD" },
80 	{ IEC958_AES1_CON_GENERAL, "general" },
81 };
82 
83 
84 static void snd_ca0106_proc_dump_iec958( struct snd_info_buffer *buffer, u32 value)
85 {
86 	int i;
87 	u32 status[4];
88 	status[0] = value & 0xff;
89 	status[1] = (value >> 8) & 0xff;
90 	status[2] = (value >> 16)  & 0xff;
91 	status[3] = (value >> 24)  & 0xff;
92 
93 	if (! (status[0] & IEC958_AES0_PROFESSIONAL)) {
94 		/* consumer */
95 		snd_iprintf(buffer, "Mode: consumer\n");
96 		snd_iprintf(buffer, "Data: ");
97 		if (!(status[0] & IEC958_AES0_NONAUDIO)) {
98 			snd_iprintf(buffer, "audio\n");
99 		} else {
100 			snd_iprintf(buffer, "non-audio\n");
101 		}
102 		snd_iprintf(buffer, "Rate: ");
103 		switch (status[3] & IEC958_AES3_CON_FS) {
104 		case IEC958_AES3_CON_FS_44100:
105 			snd_iprintf(buffer, "44100 Hz\n");
106 			break;
107 		case IEC958_AES3_CON_FS_48000:
108 			snd_iprintf(buffer, "48000 Hz\n");
109 			break;
110 		case IEC958_AES3_CON_FS_32000:
111 			snd_iprintf(buffer, "32000 Hz\n");
112 			break;
113 		default:
114 			snd_iprintf(buffer, "unknown\n");
115 			break;
116 		}
117 		snd_iprintf(buffer, "Copyright: ");
118 		if (status[0] & IEC958_AES0_CON_NOT_COPYRIGHT) {
119 			snd_iprintf(buffer, "permitted\n");
120 		} else {
121 			snd_iprintf(buffer, "protected\n");
122 		}
123 		snd_iprintf(buffer, "Emphasis: ");
124 		if ((status[0] & IEC958_AES0_CON_EMPHASIS) != IEC958_AES0_CON_EMPHASIS_5015) {
125 			snd_iprintf(buffer, "none\n");
126 		} else {
127 			snd_iprintf(buffer, "50/15us\n");
128 		}
129 		snd_iprintf(buffer, "Category: ");
130 		for (i = 0; i < ARRAY_SIZE(snd_ca0106_con_category); i++) {
131 			if ((status[1] & IEC958_AES1_CON_CATEGORY) == snd_ca0106_con_category[i].val) {
132 				snd_iprintf(buffer, "%s\n", snd_ca0106_con_category[i].name);
133 				break;
134 			}
135 		}
136 		if (i >= ARRAY_SIZE(snd_ca0106_con_category)) {
137 			snd_iprintf(buffer, "unknown 0x%x\n", status[1] & IEC958_AES1_CON_CATEGORY);
138 		}
139 		snd_iprintf(buffer, "Original: ");
140 		if (status[1] & IEC958_AES1_CON_ORIGINAL) {
141 			snd_iprintf(buffer, "original\n");
142 		} else {
143 			snd_iprintf(buffer, "1st generation\n");
144 		}
145 		snd_iprintf(buffer, "Clock: ");
146 		switch (status[3] & IEC958_AES3_CON_CLOCK) {
147 		case IEC958_AES3_CON_CLOCK_1000PPM:
148 			snd_iprintf(buffer, "1000 ppm\n");
149 			break;
150 		case IEC958_AES3_CON_CLOCK_50PPM:
151 			snd_iprintf(buffer, "50 ppm\n");
152 			break;
153 		case IEC958_AES3_CON_CLOCK_VARIABLE:
154 			snd_iprintf(buffer, "variable pitch\n");
155 			break;
156 		default:
157 			snd_iprintf(buffer, "unknown\n");
158 			break;
159 		}
160 	} else {
161 		snd_iprintf(buffer, "Mode: professional\n");
162 		snd_iprintf(buffer, "Data: ");
163 		if (!(status[0] & IEC958_AES0_NONAUDIO)) {
164 			snd_iprintf(buffer, "audio\n");
165 		} else {
166 			snd_iprintf(buffer, "non-audio\n");
167 		}
168 		snd_iprintf(buffer, "Rate: ");
169 		switch (status[0] & IEC958_AES0_PRO_FS) {
170 		case IEC958_AES0_PRO_FS_44100:
171 			snd_iprintf(buffer, "44100 Hz\n");
172 			break;
173 		case IEC958_AES0_PRO_FS_48000:
174 			snd_iprintf(buffer, "48000 Hz\n");
175 			break;
176 		case IEC958_AES0_PRO_FS_32000:
177 			snd_iprintf(buffer, "32000 Hz\n");
178 			break;
179 		default:
180 			snd_iprintf(buffer, "unknown\n");
181 			break;
182 		}
183 		snd_iprintf(buffer, "Rate Locked: ");
184 		if (status[0] & IEC958_AES0_PRO_FREQ_UNLOCKED)
185 			snd_iprintf(buffer, "no\n");
186 		else
187 			snd_iprintf(buffer, "yes\n");
188 		snd_iprintf(buffer, "Emphasis: ");
189 		switch (status[0] & IEC958_AES0_PRO_EMPHASIS) {
190 		case IEC958_AES0_PRO_EMPHASIS_CCITT:
191 			snd_iprintf(buffer, "CCITT J.17\n");
192 			break;
193 		case IEC958_AES0_PRO_EMPHASIS_NONE:
194 			snd_iprintf(buffer, "none\n");
195 			break;
196 		case IEC958_AES0_PRO_EMPHASIS_5015:
197 			snd_iprintf(buffer, "50/15us\n");
198 			break;
199 		case IEC958_AES0_PRO_EMPHASIS_NOTID:
200 		default:
201 			snd_iprintf(buffer, "unknown\n");
202 			break;
203 		}
204 		snd_iprintf(buffer, "Stereophonic: ");
205 		if ((status[1] & IEC958_AES1_PRO_MODE) == IEC958_AES1_PRO_MODE_STEREOPHONIC) {
206 			snd_iprintf(buffer, "stereo\n");
207 		} else {
208 			snd_iprintf(buffer, "not indicated\n");
209 		}
210 		snd_iprintf(buffer, "Userbits: ");
211 		switch (status[1] & IEC958_AES1_PRO_USERBITS) {
212 		case IEC958_AES1_PRO_USERBITS_192:
213 			snd_iprintf(buffer, "192bit\n");
214 			break;
215 		case IEC958_AES1_PRO_USERBITS_UDEF:
216 			snd_iprintf(buffer, "user-defined\n");
217 			break;
218 		default:
219 			snd_iprintf(buffer, "unknown\n");
220 			break;
221 		}
222 		snd_iprintf(buffer, "Sample Bits: ");
223 		switch (status[2] & IEC958_AES2_PRO_SBITS) {
224 		case IEC958_AES2_PRO_SBITS_20:
225 			snd_iprintf(buffer, "20 bit\n");
226 			break;
227 		case IEC958_AES2_PRO_SBITS_24:
228 			snd_iprintf(buffer, "24 bit\n");
229 			break;
230 		case IEC958_AES2_PRO_SBITS_UDEF:
231 			snd_iprintf(buffer, "user defined\n");
232 			break;
233 		default:
234 			snd_iprintf(buffer, "unknown\n");
235 			break;
236 		}
237 		snd_iprintf(buffer, "Word Length: ");
238 		switch (status[2] & IEC958_AES2_PRO_WORDLEN) {
239 		case IEC958_AES2_PRO_WORDLEN_22_18:
240 			snd_iprintf(buffer, "22 bit or 18 bit\n");
241 			break;
242 		case IEC958_AES2_PRO_WORDLEN_23_19:
243 			snd_iprintf(buffer, "23 bit or 19 bit\n");
244 			break;
245 		case IEC958_AES2_PRO_WORDLEN_24_20:
246 			snd_iprintf(buffer, "24 bit or 20 bit\n");
247 			break;
248 		case IEC958_AES2_PRO_WORDLEN_20_16:
249 			snd_iprintf(buffer, "20 bit or 16 bit\n");
250 			break;
251 		default:
252 			snd_iprintf(buffer, "unknown\n");
253 			break;
254 		}
255 	}
256 }
257 
258 static void snd_ca0106_proc_iec958(struct snd_info_entry *entry,
259 				       struct snd_info_buffer *buffer)
260 {
261 	struct snd_ca0106 *emu = entry->private_data;
262 	u32 value;
263 
264         value = snd_ca0106_ptr_read(emu, SAMPLE_RATE_TRACKER_STATUS, 0);
265 	snd_iprintf(buffer, "Status: %s, %s, %s\n",
266 		  (value & 0x100000) ? "Rate Locked" : "Not Rate Locked",
267 		  (value & 0x200000) ? "SPDIF Locked" : "No SPDIF Lock",
268 		  (value & 0x400000) ? "Audio Valid" : "No valid audio" );
269 	snd_iprintf(buffer, "Estimated sample rate: %u\n",
270 		  ((value & 0xfffff) * 48000) / 0x8000 );
271 	if (value & 0x200000) {
272 		snd_iprintf(buffer, "IEC958/SPDIF input status:\n");
273         	value = snd_ca0106_ptr_read(emu, SPDIF_INPUT_STATUS, 0);
274 		snd_ca0106_proc_dump_iec958(buffer, value);
275 	}
276 
277 	snd_iprintf(buffer, "\n");
278 }
279 
280 static void snd_ca0106_proc_reg_write32(struct snd_info_entry *entry,
281 				       struct snd_info_buffer *buffer)
282 {
283 	struct snd_ca0106 *emu = entry->private_data;
284         char line[64];
285         u32 reg, val;
286         while (!snd_info_get_line(buffer, line, sizeof(line))) {
287                 if (sscanf(line, "%x %x", &reg, &val) != 2)
288                         continue;
289 		if (reg < 0x40 && val <= 0xffffffff) {
290 			guard(spinlock_irqsave)(&emu->emu_lock);
291 			outl(val, emu->port + (reg & 0xfffffffc));
292 		}
293         }
294 }
295 
296 static void snd_ca0106_proc_reg_read32(struct snd_info_entry *entry,
297 				       struct snd_info_buffer *buffer)
298 {
299 	struct snd_ca0106 *emu = entry->private_data;
300 	unsigned long value;
301 	int i;
302 
303 	snd_iprintf(buffer, "Registers:\n\n");
304 	for(i = 0; i < 0x20; i+=4) {
305 		scoped_guard(spinlock_irqsave, &emu->emu_lock) {
306 			value = inl(emu->port + i);
307 		}
308 		snd_iprintf(buffer, "Register %02X: %08lX\n", i, value);
309 	}
310 }
311 
312 static void snd_ca0106_proc_reg_read16(struct snd_info_entry *entry,
313 				       struct snd_info_buffer *buffer)
314 {
315 	struct snd_ca0106 *emu = entry->private_data;
316         unsigned int value;
317 	int i;
318 
319 	snd_iprintf(buffer, "Registers:\n\n");
320 	for(i = 0; i < 0x20; i+=2) {
321 		scoped_guard(spinlock_irqsave, &emu->emu_lock) {
322 			value = inw(emu->port + i);
323 		}
324 		snd_iprintf(buffer, "Register %02X: %04X\n", i, value);
325 	}
326 }
327 
328 static void snd_ca0106_proc_reg_read8(struct snd_info_entry *entry,
329 				       struct snd_info_buffer *buffer)
330 {
331 	struct snd_ca0106 *emu = entry->private_data;
332 	unsigned int value;
333 	int i;
334 
335 	snd_iprintf(buffer, "Registers:\n\n");
336 	for(i = 0; i < 0x20; i+=1) {
337 		scoped_guard(spinlock_irqsave, &emu->emu_lock) {
338 			value = inb(emu->port + i);
339 		}
340 		snd_iprintf(buffer, "Register %02X: %02X\n", i, value);
341 	}
342 }
343 
344 static void snd_ca0106_proc_reg_read1(struct snd_info_entry *entry,
345 				       struct snd_info_buffer *buffer)
346 {
347 	struct snd_ca0106 *emu = entry->private_data;
348 	unsigned long value;
349 	int i,j;
350 
351 	snd_iprintf(buffer, "Registers\n");
352 	for(i = 0; i < 0x40; i++) {
353 		snd_iprintf(buffer, "%02X: ",i);
354 		for (j = 0; j < 4; j++) {
355                   value = snd_ca0106_ptr_read(emu, i, j);
356 		  snd_iprintf(buffer, "%08lX ", value);
357                 }
358 	        snd_iprintf(buffer, "\n");
359 	}
360 }
361 
362 static void snd_ca0106_proc_reg_read2(struct snd_info_entry *entry,
363 				       struct snd_info_buffer *buffer)
364 {
365 	struct snd_ca0106 *emu = entry->private_data;
366 	unsigned long value;
367 	int i,j;
368 
369 	snd_iprintf(buffer, "Registers\n");
370 	for(i = 0x40; i < 0x80; i++) {
371 		snd_iprintf(buffer, "%02X: ",i);
372 		for (j = 0; j < 4; j++) {
373                   value = snd_ca0106_ptr_read(emu, i, j);
374 		  snd_iprintf(buffer, "%08lX ", value);
375                 }
376 	        snd_iprintf(buffer, "\n");
377 	}
378 }
379 
380 static void snd_ca0106_proc_reg_write(struct snd_info_entry *entry,
381 				       struct snd_info_buffer *buffer)
382 {
383 	struct snd_ca0106 *emu = entry->private_data;
384         char line[64];
385         unsigned int reg, channel_id , val;
386         while (!snd_info_get_line(buffer, line, sizeof(line))) {
387                 if (sscanf(line, "%x %x %x", &reg, &channel_id, &val) != 3)
388                         continue;
389 		if (reg < 0x80 && val <= 0xffffffff && channel_id <= 3)
390                         snd_ca0106_ptr_write(emu, reg, channel_id, val);
391         }
392 }
393 
394 static void snd_ca0106_proc_i2c_write(struct snd_info_entry *entry,
395 				       struct snd_info_buffer *buffer)
396 {
397 	struct snd_ca0106 *emu = entry->private_data;
398         char line[64];
399         unsigned int reg, val;
400         while (!snd_info_get_line(buffer, line, sizeof(line))) {
401                 if (sscanf(line, "%x %x", &reg, &val) != 2)
402                         continue;
403                 if ((reg <= 0x7f) || (val <= 0x1ff)) {
404                         snd_ca0106_i2c_write(emu, reg, val);
405 		}
406         }
407 }
408 
409 int snd_ca0106_proc_init(struct snd_ca0106 *emu)
410 {
411 	snd_card_ro_proc_new(emu->card, "iec958", emu, snd_ca0106_proc_iec958);
412 	snd_card_rw_proc_new(emu->card, "ca0106_reg32", emu,
413 			     snd_ca0106_proc_reg_read32,
414 			     snd_ca0106_proc_reg_write32);
415 	snd_card_ro_proc_new(emu->card, "ca0106_reg16", emu,
416 			     snd_ca0106_proc_reg_read16);
417 	snd_card_ro_proc_new(emu->card, "ca0106_reg8", emu,
418 			     snd_ca0106_proc_reg_read8);
419 	snd_card_rw_proc_new(emu->card, "ca0106_regs1", emu,
420 			     snd_ca0106_proc_reg_read1,
421 			     snd_ca0106_proc_reg_write);
422 	snd_card_rw_proc_new(emu->card, "ca0106_i2c", emu, NULL,
423 			     snd_ca0106_proc_i2c_write);
424 	snd_card_ro_proc_new(emu->card, "ca0106_regs2", emu,
425 			     snd_ca0106_proc_reg_read2);
426 	return 0;
427 }
428