cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

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", &reg, &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", &reg, &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", &reg, &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}