ca0106_proc.c (13184B)
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 64struct snd_ca0106_category_str { 65 int val; 66 const char *name; 67}; 68 69static 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 84static 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 258static 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 280static 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 unsigned long flags; 285 char line[64]; 286 u32 reg, val; 287 while (!snd_info_get_line(buffer, line, sizeof(line))) { 288 if (sscanf(line, "%x %x", ®, &val) != 2) 289 continue; 290 if (reg < 0x40 && val <= 0xffffffff) { 291 spin_lock_irqsave(&emu->emu_lock, flags); 292 outl(val, emu->port + (reg & 0xfffffffc)); 293 spin_unlock_irqrestore(&emu->emu_lock, flags); 294 } 295 } 296} 297 298static void snd_ca0106_proc_reg_read32(struct snd_info_entry *entry, 299 struct snd_info_buffer *buffer) 300{ 301 struct snd_ca0106 *emu = entry->private_data; 302 unsigned long value; 303 unsigned long flags; 304 int i; 305 snd_iprintf(buffer, "Registers:\n\n"); 306 for(i = 0; i < 0x20; i+=4) { 307 spin_lock_irqsave(&emu->emu_lock, flags); 308 value = inl(emu->port + i); 309 spin_unlock_irqrestore(&emu->emu_lock, flags); 310 snd_iprintf(buffer, "Register %02X: %08lX\n", i, value); 311 } 312} 313 314static void snd_ca0106_proc_reg_read16(struct snd_info_entry *entry, 315 struct snd_info_buffer *buffer) 316{ 317 struct snd_ca0106 *emu = entry->private_data; 318 unsigned int value; 319 unsigned long flags; 320 int i; 321 snd_iprintf(buffer, "Registers:\n\n"); 322 for(i = 0; i < 0x20; i+=2) { 323 spin_lock_irqsave(&emu->emu_lock, flags); 324 value = inw(emu->port + i); 325 spin_unlock_irqrestore(&emu->emu_lock, flags); 326 snd_iprintf(buffer, "Register %02X: %04X\n", i, value); 327 } 328} 329 330static void snd_ca0106_proc_reg_read8(struct snd_info_entry *entry, 331 struct snd_info_buffer *buffer) 332{ 333 struct snd_ca0106 *emu = entry->private_data; 334 unsigned int value; 335 unsigned long flags; 336 int i; 337 snd_iprintf(buffer, "Registers:\n\n"); 338 for(i = 0; i < 0x20; i+=1) { 339 spin_lock_irqsave(&emu->emu_lock, flags); 340 value = inb(emu->port + i); 341 spin_unlock_irqrestore(&emu->emu_lock, flags); 342 snd_iprintf(buffer, "Register %02X: %02X\n", i, value); 343 } 344} 345 346static void snd_ca0106_proc_reg_read1(struct snd_info_entry *entry, 347 struct snd_info_buffer *buffer) 348{ 349 struct snd_ca0106 *emu = entry->private_data; 350 unsigned long value; 351 int i,j; 352 353 snd_iprintf(buffer, "Registers\n"); 354 for(i = 0; i < 0x40; i++) { 355 snd_iprintf(buffer, "%02X: ",i); 356 for (j = 0; j < 4; j++) { 357 value = snd_ca0106_ptr_read(emu, i, j); 358 snd_iprintf(buffer, "%08lX ", value); 359 } 360 snd_iprintf(buffer, "\n"); 361 } 362} 363 364static void snd_ca0106_proc_reg_read2(struct snd_info_entry *entry, 365 struct snd_info_buffer *buffer) 366{ 367 struct snd_ca0106 *emu = entry->private_data; 368 unsigned long value; 369 int i,j; 370 371 snd_iprintf(buffer, "Registers\n"); 372 for(i = 0x40; i < 0x80; i++) { 373 snd_iprintf(buffer, "%02X: ",i); 374 for (j = 0; j < 4; j++) { 375 value = snd_ca0106_ptr_read(emu, i, j); 376 snd_iprintf(buffer, "%08lX ", value); 377 } 378 snd_iprintf(buffer, "\n"); 379 } 380} 381 382static void snd_ca0106_proc_reg_write(struct snd_info_entry *entry, 383 struct snd_info_buffer *buffer) 384{ 385 struct snd_ca0106 *emu = entry->private_data; 386 char line[64]; 387 unsigned int reg, channel_id , val; 388 while (!snd_info_get_line(buffer, line, sizeof(line))) { 389 if (sscanf(line, "%x %x %x", ®, &channel_id, &val) != 3) 390 continue; 391 if (reg < 0x80 && val <= 0xffffffff && channel_id <= 3) 392 snd_ca0106_ptr_write(emu, reg, channel_id, val); 393 } 394} 395 396static void snd_ca0106_proc_i2c_write(struct snd_info_entry *entry, 397 struct snd_info_buffer *buffer) 398{ 399 struct snd_ca0106 *emu = entry->private_data; 400 char line[64]; 401 unsigned int reg, val; 402 while (!snd_info_get_line(buffer, line, sizeof(line))) { 403 if (sscanf(line, "%x %x", ®, &val) != 2) 404 continue; 405 if ((reg <= 0x7f) || (val <= 0x1ff)) { 406 snd_ca0106_i2c_write(emu, reg, val); 407 } 408 } 409} 410 411int snd_ca0106_proc_init(struct snd_ca0106 *emu) 412{ 413 snd_card_ro_proc_new(emu->card, "iec958", emu, snd_ca0106_proc_iec958); 414 snd_card_rw_proc_new(emu->card, "ca0106_reg32", emu, 415 snd_ca0106_proc_reg_read32, 416 snd_ca0106_proc_reg_write32); 417 snd_card_ro_proc_new(emu->card, "ca0106_reg16", emu, 418 snd_ca0106_proc_reg_read16); 419 snd_card_ro_proc_new(emu->card, "ca0106_reg8", emu, 420 snd_ca0106_proc_reg_read8); 421 snd_card_rw_proc_new(emu->card, "ca0106_regs1", emu, 422 snd_ca0106_proc_reg_read1, 423 snd_ca0106_proc_reg_write); 424 snd_card_rw_proc_new(emu->card, "ca0106_i2c", emu, NULL, 425 snd_ca0106_proc_i2c_write); 426 snd_card_ro_proc_new(emu->card, "ca0106_regs2", emu, 427 snd_ca0106_proc_reg_read2); 428 return 0; 429}