430 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk>4 * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit5 * Version: 0.0.186 *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.615 * Use separate card based DMA buffer for periods table list.16 * 0.0.717 * Change remove and rename ctrls into lists.18 * 0.0.819 * Try to fix capture sources.20 * 0.0.921 * Fix AC3 output.22 * Enable S32_LE format support.23 * 0.0.1024 * Enable playback 48000 and 96000 rates. (Rates other that these do not work, even with "plug:front".)25 * 0.0.1126 * Add Model name recognition.27 * 0.0.1228 * 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.1331 * Single trigger call for multi channels.32 * 0.0.1433 * Set limits based on what the sound card hardware can do.34 * playback periods_min=2, periods_max=835 * capture hw constraints require period_size = n * 64 bytes.36 * playback hw constraints require period_size = n * 64 bytes.37 * 0.0.1538 * Separate ca0106.c into separate functional .c files.39 * 0.0.1640 * Modified Copyright message.41 * 0.0.1742 * Add iec958 file in proc file system to show status of SPDIF in.43 * 0.0.1844 * 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 else187 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}430