11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk> 41da177e4SLinus Torvalds * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit 57199acdcSJames Courtier-Dutton * Version: 0.0.18 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * FEATURES currently supported: 81da177e4SLinus Torvalds * See ca0106_main.c for features. 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds * Changelog: 111da177e4SLinus Torvalds * Support interrupts per period. 121da177e4SLinus Torvalds * Removed noise from Center/LFE channel when in Analog mode. 131da177e4SLinus Torvalds * Rename and remove mixer controls. 141da177e4SLinus Torvalds * 0.0.6 151da177e4SLinus Torvalds * Use separate card based DMA buffer for periods table list. 161da177e4SLinus Torvalds * 0.0.7 171da177e4SLinus Torvalds * Change remove and rename ctrls into lists. 181da177e4SLinus Torvalds * 0.0.8 191da177e4SLinus Torvalds * Try to fix capture sources. 201da177e4SLinus Torvalds * 0.0.9 211da177e4SLinus Torvalds * Fix AC3 output. 221da177e4SLinus Torvalds * Enable S32_LE format support. 231da177e4SLinus Torvalds * 0.0.10 241da177e4SLinus Torvalds * Enable playback 48000 and 96000 rates. (Rates other that these do not work, even with "plug:front".) 251da177e4SLinus Torvalds * 0.0.11 261da177e4SLinus Torvalds * Add Model name recognition. 271da177e4SLinus Torvalds * 0.0.12 281da177e4SLinus Torvalds * Correct interrupt timing. interrupt at end of period, instead of in the middle of a playback period. 291da177e4SLinus Torvalds * Remove redundent "voice" handling. 301da177e4SLinus Torvalds * 0.0.13 311da177e4SLinus Torvalds * Single trigger call for multi channels. 321da177e4SLinus Torvalds * 0.0.14 331da177e4SLinus Torvalds * Set limits based on what the sound card hardware can do. 341da177e4SLinus Torvalds * playback periods_min=2, periods_max=8 351da177e4SLinus Torvalds * capture hw constraints require period_size = n * 64 bytes. 361da177e4SLinus Torvalds * playback hw constraints require period_size = n * 64 bytes. 371da177e4SLinus Torvalds * 0.0.15 381da177e4SLinus Torvalds * Separate ca0106.c into separate functional .c files. 391da177e4SLinus Torvalds * 0.0.16 401da177e4SLinus Torvalds * Modified Copyright message. 411da177e4SLinus Torvalds * 0.0.17 421da177e4SLinus Torvalds * Add iec958 file in proc file system to show status of SPDIF in. 437199acdcSJames Courtier-Dutton * 0.0.18 447199acdcSJames Courtier-Dutton * Implement support for Line-in capture on SB Live 24bit. 451da177e4SLinus Torvalds * 4625985edcSLucas De Marchi * This code was initially based on code from ALSA's emu10k1x.c which is: 471da177e4SLinus Torvalds * Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com> 481da177e4SLinus Torvalds */ 491da177e4SLinus Torvalds #include <linux/delay.h> 501da177e4SLinus Torvalds #include <linux/init.h> 511da177e4SLinus Torvalds #include <linux/interrupt.h> 521da177e4SLinus Torvalds #include <linux/moduleparam.h> 536cbbfe1cSTakashi Iwai #include <linux/io.h> 541da177e4SLinus Torvalds #include <sound/core.h> 551da177e4SLinus Torvalds #include <sound/initval.h> 561da177e4SLinus Torvalds #include <sound/pcm.h> 571da177e4SLinus Torvalds #include <sound/ac97_codec.h> 581da177e4SLinus Torvalds #include <sound/info.h> 591da177e4SLinus Torvalds #include <sound/asoundef.h> 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds #include "ca0106.h" 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds struct snd_ca0106_category_str { 651da177e4SLinus Torvalds int val; 661da177e4SLinus Torvalds const char *name; 671da177e4SLinus Torvalds }; 681da177e4SLinus Torvalds 69*311840d9STakashi Iwai static const struct snd_ca0106_category_str snd_ca0106_con_category[] = { 701da177e4SLinus Torvalds { IEC958_AES1_CON_DAT, "DAT" }, 711da177e4SLinus Torvalds { IEC958_AES1_CON_VCR, "VCR" }, 721da177e4SLinus Torvalds { IEC958_AES1_CON_MICROPHONE, "microphone" }, 731da177e4SLinus Torvalds { IEC958_AES1_CON_SYNTHESIZER, "synthesizer" }, 741da177e4SLinus Torvalds { IEC958_AES1_CON_RATE_CONVERTER, "rate converter" }, 751da177e4SLinus Torvalds { IEC958_AES1_CON_MIXER, "mixer" }, 761da177e4SLinus Torvalds { IEC958_AES1_CON_SAMPLER, "sampler" }, 771da177e4SLinus Torvalds { IEC958_AES1_CON_PCM_CODER, "PCM coder" }, 781da177e4SLinus Torvalds { IEC958_AES1_CON_IEC908_CD, "CD" }, 791da177e4SLinus Torvalds { IEC958_AES1_CON_NON_IEC908_CD, "non-IEC908 CD" }, 801da177e4SLinus Torvalds { IEC958_AES1_CON_GENERAL, "general" }, 811da177e4SLinus Torvalds }; 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds 84e4a3d145STakashi Iwai static void snd_ca0106_proc_dump_iec958( struct snd_info_buffer *buffer, u32 value) 851da177e4SLinus Torvalds { 861da177e4SLinus Torvalds int i; 871da177e4SLinus Torvalds u32 status[4]; 881da177e4SLinus Torvalds status[0] = value & 0xff; 891da177e4SLinus Torvalds status[1] = (value >> 8) & 0xff; 901da177e4SLinus Torvalds status[2] = (value >> 16) & 0xff; 911da177e4SLinus Torvalds status[3] = (value >> 24) & 0xff; 921da177e4SLinus Torvalds 931da177e4SLinus Torvalds if (! (status[0] & IEC958_AES0_PROFESSIONAL)) { 941da177e4SLinus Torvalds /* consumer */ 951da177e4SLinus Torvalds snd_iprintf(buffer, "Mode: consumer\n"); 961da177e4SLinus Torvalds snd_iprintf(buffer, "Data: "); 971da177e4SLinus Torvalds if (!(status[0] & IEC958_AES0_NONAUDIO)) { 981da177e4SLinus Torvalds snd_iprintf(buffer, "audio\n"); 991da177e4SLinus Torvalds } else { 1001da177e4SLinus Torvalds snd_iprintf(buffer, "non-audio\n"); 1011da177e4SLinus Torvalds } 1021da177e4SLinus Torvalds snd_iprintf(buffer, "Rate: "); 1031da177e4SLinus Torvalds switch (status[3] & IEC958_AES3_CON_FS) { 1041da177e4SLinus Torvalds case IEC958_AES3_CON_FS_44100: 1051da177e4SLinus Torvalds snd_iprintf(buffer, "44100 Hz\n"); 1061da177e4SLinus Torvalds break; 1071da177e4SLinus Torvalds case IEC958_AES3_CON_FS_48000: 1081da177e4SLinus Torvalds snd_iprintf(buffer, "48000 Hz\n"); 1091da177e4SLinus Torvalds break; 1101da177e4SLinus Torvalds case IEC958_AES3_CON_FS_32000: 1111da177e4SLinus Torvalds snd_iprintf(buffer, "32000 Hz\n"); 1121da177e4SLinus Torvalds break; 1131da177e4SLinus Torvalds default: 1141da177e4SLinus Torvalds snd_iprintf(buffer, "unknown\n"); 1151da177e4SLinus Torvalds break; 1161da177e4SLinus Torvalds } 1171da177e4SLinus Torvalds snd_iprintf(buffer, "Copyright: "); 1181da177e4SLinus Torvalds if (status[0] & IEC958_AES0_CON_NOT_COPYRIGHT) { 1191da177e4SLinus Torvalds snd_iprintf(buffer, "permitted\n"); 1201da177e4SLinus Torvalds } else { 1211da177e4SLinus Torvalds snd_iprintf(buffer, "protected\n"); 1221da177e4SLinus Torvalds } 1231da177e4SLinus Torvalds snd_iprintf(buffer, "Emphasis: "); 1241da177e4SLinus Torvalds if ((status[0] & IEC958_AES0_CON_EMPHASIS) != IEC958_AES0_CON_EMPHASIS_5015) { 1251da177e4SLinus Torvalds snd_iprintf(buffer, "none\n"); 1261da177e4SLinus Torvalds } else { 1271da177e4SLinus Torvalds snd_iprintf(buffer, "50/15us\n"); 1281da177e4SLinus Torvalds } 1291da177e4SLinus Torvalds snd_iprintf(buffer, "Category: "); 1301da177e4SLinus Torvalds for (i = 0; i < ARRAY_SIZE(snd_ca0106_con_category); i++) { 1311da177e4SLinus Torvalds if ((status[1] & IEC958_AES1_CON_CATEGORY) == snd_ca0106_con_category[i].val) { 1321da177e4SLinus Torvalds snd_iprintf(buffer, "%s\n", snd_ca0106_con_category[i].name); 1331da177e4SLinus Torvalds break; 1341da177e4SLinus Torvalds } 1351da177e4SLinus Torvalds } 1361da177e4SLinus Torvalds if (i >= ARRAY_SIZE(snd_ca0106_con_category)) { 1371da177e4SLinus Torvalds snd_iprintf(buffer, "unknown 0x%x\n", status[1] & IEC958_AES1_CON_CATEGORY); 1381da177e4SLinus Torvalds } 1391da177e4SLinus Torvalds snd_iprintf(buffer, "Original: "); 1401da177e4SLinus Torvalds if (status[1] & IEC958_AES1_CON_ORIGINAL) { 1411da177e4SLinus Torvalds snd_iprintf(buffer, "original\n"); 1421da177e4SLinus Torvalds } else { 1431da177e4SLinus Torvalds snd_iprintf(buffer, "1st generation\n"); 1441da177e4SLinus Torvalds } 1451da177e4SLinus Torvalds snd_iprintf(buffer, "Clock: "); 1461da177e4SLinus Torvalds switch (status[3] & IEC958_AES3_CON_CLOCK) { 1471da177e4SLinus Torvalds case IEC958_AES3_CON_CLOCK_1000PPM: 1481da177e4SLinus Torvalds snd_iprintf(buffer, "1000 ppm\n"); 1491da177e4SLinus Torvalds break; 1501da177e4SLinus Torvalds case IEC958_AES3_CON_CLOCK_50PPM: 1511da177e4SLinus Torvalds snd_iprintf(buffer, "50 ppm\n"); 1521da177e4SLinus Torvalds break; 1531da177e4SLinus Torvalds case IEC958_AES3_CON_CLOCK_VARIABLE: 1541da177e4SLinus Torvalds snd_iprintf(buffer, "variable pitch\n"); 1551da177e4SLinus Torvalds break; 1561da177e4SLinus Torvalds default: 1571da177e4SLinus Torvalds snd_iprintf(buffer, "unknown\n"); 1581da177e4SLinus Torvalds break; 1591da177e4SLinus Torvalds } 1601da177e4SLinus Torvalds } else { 1611da177e4SLinus Torvalds snd_iprintf(buffer, "Mode: professional\n"); 1621da177e4SLinus Torvalds snd_iprintf(buffer, "Data: "); 1631da177e4SLinus Torvalds if (!(status[0] & IEC958_AES0_NONAUDIO)) { 1641da177e4SLinus Torvalds snd_iprintf(buffer, "audio\n"); 1651da177e4SLinus Torvalds } else { 1661da177e4SLinus Torvalds snd_iprintf(buffer, "non-audio\n"); 1671da177e4SLinus Torvalds } 1681da177e4SLinus Torvalds snd_iprintf(buffer, "Rate: "); 1691da177e4SLinus Torvalds switch (status[0] & IEC958_AES0_PRO_FS) { 1701da177e4SLinus Torvalds case IEC958_AES0_PRO_FS_44100: 1711da177e4SLinus Torvalds snd_iprintf(buffer, "44100 Hz\n"); 1721da177e4SLinus Torvalds break; 1731da177e4SLinus Torvalds case IEC958_AES0_PRO_FS_48000: 1741da177e4SLinus Torvalds snd_iprintf(buffer, "48000 Hz\n"); 1751da177e4SLinus Torvalds break; 1761da177e4SLinus Torvalds case IEC958_AES0_PRO_FS_32000: 1771da177e4SLinus Torvalds snd_iprintf(buffer, "32000 Hz\n"); 1781da177e4SLinus Torvalds break; 1791da177e4SLinus Torvalds default: 1801da177e4SLinus Torvalds snd_iprintf(buffer, "unknown\n"); 1811da177e4SLinus Torvalds break; 1821da177e4SLinus Torvalds } 1831da177e4SLinus Torvalds snd_iprintf(buffer, "Rate Locked: "); 1841da177e4SLinus Torvalds if (status[0] & IEC958_AES0_PRO_FREQ_UNLOCKED) 1851da177e4SLinus Torvalds snd_iprintf(buffer, "no\n"); 1861da177e4SLinus Torvalds else 1871da177e4SLinus Torvalds snd_iprintf(buffer, "yes\n"); 1881da177e4SLinus Torvalds snd_iprintf(buffer, "Emphasis: "); 1891da177e4SLinus Torvalds switch (status[0] & IEC958_AES0_PRO_EMPHASIS) { 1901da177e4SLinus Torvalds case IEC958_AES0_PRO_EMPHASIS_CCITT: 1911da177e4SLinus Torvalds snd_iprintf(buffer, "CCITT J.17\n"); 1921da177e4SLinus Torvalds break; 1931da177e4SLinus Torvalds case IEC958_AES0_PRO_EMPHASIS_NONE: 1941da177e4SLinus Torvalds snd_iprintf(buffer, "none\n"); 1951da177e4SLinus Torvalds break; 1961da177e4SLinus Torvalds case IEC958_AES0_PRO_EMPHASIS_5015: 1971da177e4SLinus Torvalds snd_iprintf(buffer, "50/15us\n"); 1981da177e4SLinus Torvalds break; 1991da177e4SLinus Torvalds case IEC958_AES0_PRO_EMPHASIS_NOTID: 2001da177e4SLinus Torvalds default: 2011da177e4SLinus Torvalds snd_iprintf(buffer, "unknown\n"); 2021da177e4SLinus Torvalds break; 2031da177e4SLinus Torvalds } 2041da177e4SLinus Torvalds snd_iprintf(buffer, "Stereophonic: "); 2051da177e4SLinus Torvalds if ((status[1] & IEC958_AES1_PRO_MODE) == IEC958_AES1_PRO_MODE_STEREOPHONIC) { 2061da177e4SLinus Torvalds snd_iprintf(buffer, "stereo\n"); 2071da177e4SLinus Torvalds } else { 2081da177e4SLinus Torvalds snd_iprintf(buffer, "not indicated\n"); 2091da177e4SLinus Torvalds } 2101da177e4SLinus Torvalds snd_iprintf(buffer, "Userbits: "); 2111da177e4SLinus Torvalds switch (status[1] & IEC958_AES1_PRO_USERBITS) { 2121da177e4SLinus Torvalds case IEC958_AES1_PRO_USERBITS_192: 2131da177e4SLinus Torvalds snd_iprintf(buffer, "192bit\n"); 2141da177e4SLinus Torvalds break; 2151da177e4SLinus Torvalds case IEC958_AES1_PRO_USERBITS_UDEF: 2161da177e4SLinus Torvalds snd_iprintf(buffer, "user-defined\n"); 2171da177e4SLinus Torvalds break; 2181da177e4SLinus Torvalds default: 219af901ca1SAndré Goddard Rosa snd_iprintf(buffer, "unknown\n"); 2201da177e4SLinus Torvalds break; 2211da177e4SLinus Torvalds } 2221da177e4SLinus Torvalds snd_iprintf(buffer, "Sample Bits: "); 2231da177e4SLinus Torvalds switch (status[2] & IEC958_AES2_PRO_SBITS) { 2241da177e4SLinus Torvalds case IEC958_AES2_PRO_SBITS_20: 2251da177e4SLinus Torvalds snd_iprintf(buffer, "20 bit\n"); 2261da177e4SLinus Torvalds break; 2271da177e4SLinus Torvalds case IEC958_AES2_PRO_SBITS_24: 2281da177e4SLinus Torvalds snd_iprintf(buffer, "24 bit\n"); 2291da177e4SLinus Torvalds break; 2301da177e4SLinus Torvalds case IEC958_AES2_PRO_SBITS_UDEF: 2311da177e4SLinus Torvalds snd_iprintf(buffer, "user defined\n"); 2321da177e4SLinus Torvalds break; 2331da177e4SLinus Torvalds default: 2341da177e4SLinus Torvalds snd_iprintf(buffer, "unknown\n"); 2351da177e4SLinus Torvalds break; 2361da177e4SLinus Torvalds } 2371da177e4SLinus Torvalds snd_iprintf(buffer, "Word Length: "); 2381da177e4SLinus Torvalds switch (status[2] & IEC958_AES2_PRO_WORDLEN) { 2391da177e4SLinus Torvalds case IEC958_AES2_PRO_WORDLEN_22_18: 2401da177e4SLinus Torvalds snd_iprintf(buffer, "22 bit or 18 bit\n"); 2411da177e4SLinus Torvalds break; 2421da177e4SLinus Torvalds case IEC958_AES2_PRO_WORDLEN_23_19: 2431da177e4SLinus Torvalds snd_iprintf(buffer, "23 bit or 19 bit\n"); 2441da177e4SLinus Torvalds break; 2451da177e4SLinus Torvalds case IEC958_AES2_PRO_WORDLEN_24_20: 2461da177e4SLinus Torvalds snd_iprintf(buffer, "24 bit or 20 bit\n"); 2471da177e4SLinus Torvalds break; 2481da177e4SLinus Torvalds case IEC958_AES2_PRO_WORDLEN_20_16: 2491da177e4SLinus Torvalds snd_iprintf(buffer, "20 bit or 16 bit\n"); 2501da177e4SLinus Torvalds break; 2511da177e4SLinus Torvalds default: 2521da177e4SLinus Torvalds snd_iprintf(buffer, "unknown\n"); 2531da177e4SLinus Torvalds break; 2541da177e4SLinus Torvalds } 2551da177e4SLinus Torvalds } 2561da177e4SLinus Torvalds } 2571da177e4SLinus Torvalds 258e4a3d145STakashi Iwai static void snd_ca0106_proc_iec958(struct snd_info_entry *entry, 259e4a3d145STakashi Iwai struct snd_info_buffer *buffer) 2601da177e4SLinus Torvalds { 261e4a3d145STakashi Iwai struct snd_ca0106 *emu = entry->private_data; 2621da177e4SLinus Torvalds u32 value; 2631da177e4SLinus Torvalds 2641da177e4SLinus Torvalds value = snd_ca0106_ptr_read(emu, SAMPLE_RATE_TRACKER_STATUS, 0); 2651da177e4SLinus Torvalds snd_iprintf(buffer, "Status: %s, %s, %s\n", 2661da177e4SLinus Torvalds (value & 0x100000) ? "Rate Locked" : "Not Rate Locked", 2671da177e4SLinus Torvalds (value & 0x200000) ? "SPDIF Locked" : "No SPDIF Lock", 2681da177e4SLinus Torvalds (value & 0x400000) ? "Audio Valid" : "No valid audio" ); 2691da177e4SLinus Torvalds snd_iprintf(buffer, "Estimated sample rate: %u\n", 2701da177e4SLinus Torvalds ((value & 0xfffff) * 48000) / 0x8000 ); 2711da177e4SLinus Torvalds if (value & 0x200000) { 2721da177e4SLinus Torvalds snd_iprintf(buffer, "IEC958/SPDIF input status:\n"); 2731da177e4SLinus Torvalds value = snd_ca0106_ptr_read(emu, SPDIF_INPUT_STATUS, 0); 2741da177e4SLinus Torvalds snd_ca0106_proc_dump_iec958(buffer, value); 2751da177e4SLinus Torvalds } 2761da177e4SLinus Torvalds 2771da177e4SLinus Torvalds snd_iprintf(buffer, "\n"); 2781da177e4SLinus Torvalds } 2791da177e4SLinus Torvalds 280e4a3d145STakashi Iwai static void snd_ca0106_proc_reg_write32(struct snd_info_entry *entry, 281e4a3d145STakashi Iwai struct snd_info_buffer *buffer) 2821da177e4SLinus Torvalds { 283e4a3d145STakashi Iwai struct snd_ca0106 *emu = entry->private_data; 2841da177e4SLinus Torvalds unsigned long flags; 2851da177e4SLinus Torvalds char line[64]; 2861da177e4SLinus Torvalds u32 reg, val; 2871da177e4SLinus Torvalds while (!snd_info_get_line(buffer, line, sizeof(line))) { 2881da177e4SLinus Torvalds if (sscanf(line, "%x %x", ®, &val) != 2) 2891da177e4SLinus Torvalds continue; 29084ed1a19SRoel Kluin if (reg < 0x40 && val <= 0xffffffff) { 2911da177e4SLinus Torvalds spin_lock_irqsave(&emu->emu_lock, flags); 2921da177e4SLinus Torvalds outl(val, emu->port + (reg & 0xfffffffc)); 2931da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->emu_lock, flags); 2941da177e4SLinus Torvalds } 2951da177e4SLinus Torvalds } 2961da177e4SLinus Torvalds } 2971da177e4SLinus Torvalds 298e4a3d145STakashi Iwai static void snd_ca0106_proc_reg_read32(struct snd_info_entry *entry, 299e4a3d145STakashi Iwai struct snd_info_buffer *buffer) 3001da177e4SLinus Torvalds { 301e4a3d145STakashi Iwai struct snd_ca0106 *emu = entry->private_data; 3021da177e4SLinus Torvalds unsigned long value; 3031da177e4SLinus Torvalds unsigned long flags; 3041da177e4SLinus Torvalds int i; 3051da177e4SLinus Torvalds snd_iprintf(buffer, "Registers:\n\n"); 3061da177e4SLinus Torvalds for(i = 0; i < 0x20; i+=4) { 3071da177e4SLinus Torvalds spin_lock_irqsave(&emu->emu_lock, flags); 3081da177e4SLinus Torvalds value = inl(emu->port + i); 3091da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->emu_lock, flags); 3101da177e4SLinus Torvalds snd_iprintf(buffer, "Register %02X: %08lX\n", i, value); 3111da177e4SLinus Torvalds } 3121da177e4SLinus Torvalds } 3131da177e4SLinus Torvalds 314e4a3d145STakashi Iwai static void snd_ca0106_proc_reg_read16(struct snd_info_entry *entry, 315e4a3d145STakashi Iwai struct snd_info_buffer *buffer) 3161da177e4SLinus Torvalds { 317e4a3d145STakashi Iwai struct snd_ca0106 *emu = entry->private_data; 3181da177e4SLinus Torvalds unsigned int value; 3191da177e4SLinus Torvalds unsigned long flags; 3201da177e4SLinus Torvalds int i; 3211da177e4SLinus Torvalds snd_iprintf(buffer, "Registers:\n\n"); 3221da177e4SLinus Torvalds for(i = 0; i < 0x20; i+=2) { 3231da177e4SLinus Torvalds spin_lock_irqsave(&emu->emu_lock, flags); 3241da177e4SLinus Torvalds value = inw(emu->port + i); 3251da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->emu_lock, flags); 3261da177e4SLinus Torvalds snd_iprintf(buffer, "Register %02X: %04X\n", i, value); 3271da177e4SLinus Torvalds } 3281da177e4SLinus Torvalds } 3291da177e4SLinus Torvalds 330e4a3d145STakashi Iwai static void snd_ca0106_proc_reg_read8(struct snd_info_entry *entry, 331e4a3d145STakashi Iwai struct snd_info_buffer *buffer) 3321da177e4SLinus Torvalds { 333e4a3d145STakashi Iwai struct snd_ca0106 *emu = entry->private_data; 3341da177e4SLinus Torvalds unsigned int value; 3351da177e4SLinus Torvalds unsigned long flags; 3361da177e4SLinus Torvalds int i; 3371da177e4SLinus Torvalds snd_iprintf(buffer, "Registers:\n\n"); 3381da177e4SLinus Torvalds for(i = 0; i < 0x20; i+=1) { 3391da177e4SLinus Torvalds spin_lock_irqsave(&emu->emu_lock, flags); 3401da177e4SLinus Torvalds value = inb(emu->port + i); 3411da177e4SLinus Torvalds spin_unlock_irqrestore(&emu->emu_lock, flags); 3421da177e4SLinus Torvalds snd_iprintf(buffer, "Register %02X: %02X\n", i, value); 3431da177e4SLinus Torvalds } 3441da177e4SLinus Torvalds } 3451da177e4SLinus Torvalds 346e4a3d145STakashi Iwai static void snd_ca0106_proc_reg_read1(struct snd_info_entry *entry, 347e4a3d145STakashi Iwai struct snd_info_buffer *buffer) 3481da177e4SLinus Torvalds { 349e4a3d145STakashi Iwai struct snd_ca0106 *emu = entry->private_data; 3501da177e4SLinus Torvalds unsigned long value; 3511da177e4SLinus Torvalds int i,j; 3521da177e4SLinus Torvalds 3531da177e4SLinus Torvalds snd_iprintf(buffer, "Registers\n"); 3541da177e4SLinus Torvalds for(i = 0; i < 0x40; i++) { 3551da177e4SLinus Torvalds snd_iprintf(buffer, "%02X: ",i); 3561da177e4SLinus Torvalds for (j = 0; j < 4; j++) { 3571da177e4SLinus Torvalds value = snd_ca0106_ptr_read(emu, i, j); 3581da177e4SLinus Torvalds snd_iprintf(buffer, "%08lX ", value); 3591da177e4SLinus Torvalds } 3601da177e4SLinus Torvalds snd_iprintf(buffer, "\n"); 3611da177e4SLinus Torvalds } 3621da177e4SLinus Torvalds } 3631da177e4SLinus Torvalds 364e4a3d145STakashi Iwai static void snd_ca0106_proc_reg_read2(struct snd_info_entry *entry, 365e4a3d145STakashi Iwai struct snd_info_buffer *buffer) 3661da177e4SLinus Torvalds { 367e4a3d145STakashi Iwai struct snd_ca0106 *emu = entry->private_data; 3681da177e4SLinus Torvalds unsigned long value; 3691da177e4SLinus Torvalds int i,j; 3701da177e4SLinus Torvalds 3711da177e4SLinus Torvalds snd_iprintf(buffer, "Registers\n"); 3721da177e4SLinus Torvalds for(i = 0x40; i < 0x80; i++) { 3731da177e4SLinus Torvalds snd_iprintf(buffer, "%02X: ",i); 3741da177e4SLinus Torvalds for (j = 0; j < 4; j++) { 3751da177e4SLinus Torvalds value = snd_ca0106_ptr_read(emu, i, j); 3761da177e4SLinus Torvalds snd_iprintf(buffer, "%08lX ", value); 3771da177e4SLinus Torvalds } 3781da177e4SLinus Torvalds snd_iprintf(buffer, "\n"); 3791da177e4SLinus Torvalds } 3801da177e4SLinus Torvalds } 3811da177e4SLinus Torvalds 382e4a3d145STakashi Iwai static void snd_ca0106_proc_reg_write(struct snd_info_entry *entry, 383e4a3d145STakashi Iwai struct snd_info_buffer *buffer) 3841da177e4SLinus Torvalds { 385e4a3d145STakashi Iwai struct snd_ca0106 *emu = entry->private_data; 3861da177e4SLinus Torvalds char line[64]; 3871da177e4SLinus Torvalds unsigned int reg, channel_id , val; 3881da177e4SLinus Torvalds while (!snd_info_get_line(buffer, line, sizeof(line))) { 3891da177e4SLinus Torvalds if (sscanf(line, "%x %x %x", ®, &channel_id, &val) != 3) 3901da177e4SLinus Torvalds continue; 39184ed1a19SRoel Kluin if (reg < 0x80 && val <= 0xffffffff && channel_id <= 3) 3921da177e4SLinus Torvalds snd_ca0106_ptr_write(emu, reg, channel_id, val); 3931da177e4SLinus Torvalds } 3941da177e4SLinus Torvalds } 3951da177e4SLinus Torvalds 396e4a3d145STakashi Iwai static void snd_ca0106_proc_i2c_write(struct snd_info_entry *entry, 397e4a3d145STakashi Iwai struct snd_info_buffer *buffer) 3987199acdcSJames Courtier-Dutton { 399e4a3d145STakashi Iwai struct snd_ca0106 *emu = entry->private_data; 4007199acdcSJames Courtier-Dutton char line[64]; 4017199acdcSJames Courtier-Dutton unsigned int reg, val; 4027199acdcSJames Courtier-Dutton while (!snd_info_get_line(buffer, line, sizeof(line))) { 4037199acdcSJames Courtier-Dutton if (sscanf(line, "%x %x", ®, &val) != 2) 4047199acdcSJames Courtier-Dutton continue; 4057199acdcSJames Courtier-Dutton if ((reg <= 0x7f) || (val <= 0x1ff)) { 4067199acdcSJames Courtier-Dutton snd_ca0106_i2c_write(emu, reg, val); 4077199acdcSJames Courtier-Dutton } 4087199acdcSJames Courtier-Dutton } 4097199acdcSJames Courtier-Dutton } 4101da177e4SLinus Torvalds 411e23e7a14SBill Pemberton int snd_ca0106_proc_init(struct snd_ca0106 *emu) 4121da177e4SLinus Torvalds { 41347f2769bSTakashi Iwai snd_card_ro_proc_new(emu->card, "iec958", emu, snd_ca0106_proc_iec958); 41447f2769bSTakashi Iwai snd_card_rw_proc_new(emu->card, "ca0106_reg32", emu, 41547f2769bSTakashi Iwai snd_ca0106_proc_reg_read32, 41647f2769bSTakashi Iwai snd_ca0106_proc_reg_write32); 41747f2769bSTakashi Iwai snd_card_ro_proc_new(emu->card, "ca0106_reg16", emu, 41847f2769bSTakashi Iwai snd_ca0106_proc_reg_read16); 41947f2769bSTakashi Iwai snd_card_ro_proc_new(emu->card, "ca0106_reg8", emu, 42047f2769bSTakashi Iwai snd_ca0106_proc_reg_read8); 42147f2769bSTakashi Iwai snd_card_rw_proc_new(emu->card, "ca0106_regs1", emu, 42247f2769bSTakashi Iwai snd_ca0106_proc_reg_read1, 42347f2769bSTakashi Iwai snd_ca0106_proc_reg_write); 42447f2769bSTakashi Iwai snd_card_rw_proc_new(emu->card, "ca0106_i2c", emu, NULL, 42547f2769bSTakashi Iwai snd_ca0106_proc_i2c_write); 42647f2769bSTakashi Iwai snd_card_ro_proc_new(emu->card, "ca0106_regs2", emu, 42747f2769bSTakashi Iwai snd_ca0106_proc_reg_read2); 4281da177e4SLinus Torvalds return 0; 4291da177e4SLinus Torvalds } 430