18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) by Jaroslav Kysela <perex@perex.cz>, 48c2ecf20Sopenharmony_ci * Takashi Iwai <tiwai@suse.de> 58c2ecf20Sopenharmony_ci * Creative Labs, Inc. 68c2ecf20Sopenharmony_ci * Routines for control of EMU10K1 chips / mixer routines 78c2ecf20Sopenharmony_ci * Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Copyright (c) by James Courtier-Dutton <James@superbug.co.uk> 108c2ecf20Sopenharmony_ci * Added EMU 1010 support. 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * BUGS: 138c2ecf20Sopenharmony_ci * -- 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * TODO: 168c2ecf20Sopenharmony_ci * -- 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/time.h> 208c2ecf20Sopenharmony_ci#include <linux/init.h> 218c2ecf20Sopenharmony_ci#include <sound/core.h> 228c2ecf20Sopenharmony_ci#include <sound/emu10k1.h> 238c2ecf20Sopenharmony_ci#include <linux/delay.h> 248c2ecf20Sopenharmony_ci#include <sound/tlv.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include "p17v.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define AC97_ID_STAC9758 0x83847658 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(snd_audigy_db_scale2, -10350, 50, 1); /* WM8775 gain scale */ 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 358c2ecf20Sopenharmony_ci uinfo->count = 1; 368c2ecf20Sopenharmony_ci return 0; 378c2ecf20Sopenharmony_ci} 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic int snd_emu10k1_spdif_get(struct snd_kcontrol *kcontrol, 408c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 438c2ecf20Sopenharmony_ci unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 448c2ecf20Sopenharmony_ci unsigned long flags; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci /* Limit: emu->spdif_bits */ 478c2ecf20Sopenharmony_ci if (idx >= 3) 488c2ecf20Sopenharmony_ci return -EINVAL; 498c2ecf20Sopenharmony_ci spin_lock_irqsave(&emu->reg_lock, flags); 508c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff; 518c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff; 528c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff; 538c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff; 548c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&emu->reg_lock, flags); 558c2ecf20Sopenharmony_ci return 0; 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol, 598c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[0] = 0xff; 628c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[1] = 0xff; 638c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[2] = 0xff; 648c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[3] = 0xff; 658c2ecf20Sopenharmony_ci return 0; 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/* 698c2ecf20Sopenharmony_ci * Items labels in enum mixer controls assigning source data to 708c2ecf20Sopenharmony_ci * each destination 718c2ecf20Sopenharmony_ci */ 728c2ecf20Sopenharmony_cistatic const char * const emu1010_src_texts[] = { 738c2ecf20Sopenharmony_ci "Silence", 748c2ecf20Sopenharmony_ci "Dock Mic A", 758c2ecf20Sopenharmony_ci "Dock Mic B", 768c2ecf20Sopenharmony_ci "Dock ADC1 Left", 778c2ecf20Sopenharmony_ci "Dock ADC1 Right", 788c2ecf20Sopenharmony_ci "Dock ADC2 Left", 798c2ecf20Sopenharmony_ci "Dock ADC2 Right", 808c2ecf20Sopenharmony_ci "Dock ADC3 Left", 818c2ecf20Sopenharmony_ci "Dock ADC3 Right", 828c2ecf20Sopenharmony_ci "0202 ADC Left", 838c2ecf20Sopenharmony_ci "0202 ADC Right", 848c2ecf20Sopenharmony_ci "0202 SPDIF Left", 858c2ecf20Sopenharmony_ci "0202 SPDIF Right", 868c2ecf20Sopenharmony_ci "ADAT 0", 878c2ecf20Sopenharmony_ci "ADAT 1", 888c2ecf20Sopenharmony_ci "ADAT 2", 898c2ecf20Sopenharmony_ci "ADAT 3", 908c2ecf20Sopenharmony_ci "ADAT 4", 918c2ecf20Sopenharmony_ci "ADAT 5", 928c2ecf20Sopenharmony_ci "ADAT 6", 938c2ecf20Sopenharmony_ci "ADAT 7", 948c2ecf20Sopenharmony_ci "DSP 0", 958c2ecf20Sopenharmony_ci "DSP 1", 968c2ecf20Sopenharmony_ci "DSP 2", 978c2ecf20Sopenharmony_ci "DSP 3", 988c2ecf20Sopenharmony_ci "DSP 4", 998c2ecf20Sopenharmony_ci "DSP 5", 1008c2ecf20Sopenharmony_ci "DSP 6", 1018c2ecf20Sopenharmony_ci "DSP 7", 1028c2ecf20Sopenharmony_ci "DSP 8", 1038c2ecf20Sopenharmony_ci "DSP 9", 1048c2ecf20Sopenharmony_ci "DSP 10", 1058c2ecf20Sopenharmony_ci "DSP 11", 1068c2ecf20Sopenharmony_ci "DSP 12", 1078c2ecf20Sopenharmony_ci "DSP 13", 1088c2ecf20Sopenharmony_ci "DSP 14", 1098c2ecf20Sopenharmony_ci "DSP 15", 1108c2ecf20Sopenharmony_ci "DSP 16", 1118c2ecf20Sopenharmony_ci "DSP 17", 1128c2ecf20Sopenharmony_ci "DSP 18", 1138c2ecf20Sopenharmony_ci "DSP 19", 1148c2ecf20Sopenharmony_ci "DSP 20", 1158c2ecf20Sopenharmony_ci "DSP 21", 1168c2ecf20Sopenharmony_ci "DSP 22", 1178c2ecf20Sopenharmony_ci "DSP 23", 1188c2ecf20Sopenharmony_ci "DSP 24", 1198c2ecf20Sopenharmony_ci "DSP 25", 1208c2ecf20Sopenharmony_ci "DSP 26", 1218c2ecf20Sopenharmony_ci "DSP 27", 1228c2ecf20Sopenharmony_ci "DSP 28", 1238c2ecf20Sopenharmony_ci "DSP 29", 1248c2ecf20Sopenharmony_ci "DSP 30", 1258c2ecf20Sopenharmony_ci "DSP 31", 1268c2ecf20Sopenharmony_ci}; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci/* 1616(m) cardbus */ 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic const char * const emu1616_src_texts[] = { 1318c2ecf20Sopenharmony_ci "Silence", 1328c2ecf20Sopenharmony_ci "Dock Mic A", 1338c2ecf20Sopenharmony_ci "Dock Mic B", 1348c2ecf20Sopenharmony_ci "Dock ADC1 Left", 1358c2ecf20Sopenharmony_ci "Dock ADC1 Right", 1368c2ecf20Sopenharmony_ci "Dock ADC2 Left", 1378c2ecf20Sopenharmony_ci "Dock ADC2 Right", 1388c2ecf20Sopenharmony_ci "Dock SPDIF Left", 1398c2ecf20Sopenharmony_ci "Dock SPDIF Right", 1408c2ecf20Sopenharmony_ci "ADAT 0", 1418c2ecf20Sopenharmony_ci "ADAT 1", 1428c2ecf20Sopenharmony_ci "ADAT 2", 1438c2ecf20Sopenharmony_ci "ADAT 3", 1448c2ecf20Sopenharmony_ci "ADAT 4", 1458c2ecf20Sopenharmony_ci "ADAT 5", 1468c2ecf20Sopenharmony_ci "ADAT 6", 1478c2ecf20Sopenharmony_ci "ADAT 7", 1488c2ecf20Sopenharmony_ci "DSP 0", 1498c2ecf20Sopenharmony_ci "DSP 1", 1508c2ecf20Sopenharmony_ci "DSP 2", 1518c2ecf20Sopenharmony_ci "DSP 3", 1528c2ecf20Sopenharmony_ci "DSP 4", 1538c2ecf20Sopenharmony_ci "DSP 5", 1548c2ecf20Sopenharmony_ci "DSP 6", 1558c2ecf20Sopenharmony_ci "DSP 7", 1568c2ecf20Sopenharmony_ci "DSP 8", 1578c2ecf20Sopenharmony_ci "DSP 9", 1588c2ecf20Sopenharmony_ci "DSP 10", 1598c2ecf20Sopenharmony_ci "DSP 11", 1608c2ecf20Sopenharmony_ci "DSP 12", 1618c2ecf20Sopenharmony_ci "DSP 13", 1628c2ecf20Sopenharmony_ci "DSP 14", 1638c2ecf20Sopenharmony_ci "DSP 15", 1648c2ecf20Sopenharmony_ci "DSP 16", 1658c2ecf20Sopenharmony_ci "DSP 17", 1668c2ecf20Sopenharmony_ci "DSP 18", 1678c2ecf20Sopenharmony_ci "DSP 19", 1688c2ecf20Sopenharmony_ci "DSP 20", 1698c2ecf20Sopenharmony_ci "DSP 21", 1708c2ecf20Sopenharmony_ci "DSP 22", 1718c2ecf20Sopenharmony_ci "DSP 23", 1728c2ecf20Sopenharmony_ci "DSP 24", 1738c2ecf20Sopenharmony_ci "DSP 25", 1748c2ecf20Sopenharmony_ci "DSP 26", 1758c2ecf20Sopenharmony_ci "DSP 27", 1768c2ecf20Sopenharmony_ci "DSP 28", 1778c2ecf20Sopenharmony_ci "DSP 29", 1788c2ecf20Sopenharmony_ci "DSP 30", 1798c2ecf20Sopenharmony_ci "DSP 31", 1808c2ecf20Sopenharmony_ci}; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci/* 1848c2ecf20Sopenharmony_ci * List of data sources available for each destination 1858c2ecf20Sopenharmony_ci */ 1868c2ecf20Sopenharmony_cistatic const unsigned int emu1010_src_regs[] = { 1878c2ecf20Sopenharmony_ci EMU_SRC_SILENCE,/* 0 */ 1888c2ecf20Sopenharmony_ci EMU_SRC_DOCK_MIC_A1, /* 1 */ 1898c2ecf20Sopenharmony_ci EMU_SRC_DOCK_MIC_B1, /* 2 */ 1908c2ecf20Sopenharmony_ci EMU_SRC_DOCK_ADC1_LEFT1, /* 3 */ 1918c2ecf20Sopenharmony_ci EMU_SRC_DOCK_ADC1_RIGHT1, /* 4 */ 1928c2ecf20Sopenharmony_ci EMU_SRC_DOCK_ADC2_LEFT1, /* 5 */ 1938c2ecf20Sopenharmony_ci EMU_SRC_DOCK_ADC2_RIGHT1, /* 6 */ 1948c2ecf20Sopenharmony_ci EMU_SRC_DOCK_ADC3_LEFT1, /* 7 */ 1958c2ecf20Sopenharmony_ci EMU_SRC_DOCK_ADC3_RIGHT1, /* 8 */ 1968c2ecf20Sopenharmony_ci EMU_SRC_HAMOA_ADC_LEFT1, /* 9 */ 1978c2ecf20Sopenharmony_ci EMU_SRC_HAMOA_ADC_RIGHT1, /* 10 */ 1988c2ecf20Sopenharmony_ci EMU_SRC_HANA_SPDIF_LEFT1, /* 11 */ 1998c2ecf20Sopenharmony_ci EMU_SRC_HANA_SPDIF_RIGHT1, /* 12 */ 2008c2ecf20Sopenharmony_ci EMU_SRC_HANA_ADAT, /* 13 */ 2018c2ecf20Sopenharmony_ci EMU_SRC_HANA_ADAT+1, /* 14 */ 2028c2ecf20Sopenharmony_ci EMU_SRC_HANA_ADAT+2, /* 15 */ 2038c2ecf20Sopenharmony_ci EMU_SRC_HANA_ADAT+3, /* 16 */ 2048c2ecf20Sopenharmony_ci EMU_SRC_HANA_ADAT+4, /* 17 */ 2058c2ecf20Sopenharmony_ci EMU_SRC_HANA_ADAT+5, /* 18 */ 2068c2ecf20Sopenharmony_ci EMU_SRC_HANA_ADAT+6, /* 19 */ 2078c2ecf20Sopenharmony_ci EMU_SRC_HANA_ADAT+7, /* 20 */ 2088c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A, /* 21 */ 2098c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A+1, /* 22 */ 2108c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A+2, /* 23 */ 2118c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A+3, /* 24 */ 2128c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A+4, /* 25 */ 2138c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A+5, /* 26 */ 2148c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A+6, /* 27 */ 2158c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A+7, /* 28 */ 2168c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A+8, /* 29 */ 2178c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A+9, /* 30 */ 2188c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A+0xa, /* 31 */ 2198c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A+0xb, /* 32 */ 2208c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A+0xc, /* 33 */ 2218c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A+0xd, /* 34 */ 2228c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A+0xe, /* 35 */ 2238c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A+0xf, /* 36 */ 2248c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B, /* 37 */ 2258c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B+1, /* 38 */ 2268c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B+2, /* 39 */ 2278c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B+3, /* 40 */ 2288c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B+4, /* 41 */ 2298c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B+5, /* 42 */ 2308c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B+6, /* 43 */ 2318c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B+7, /* 44 */ 2328c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B+8, /* 45 */ 2338c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B+9, /* 46 */ 2348c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B+0xa, /* 47 */ 2358c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B+0xb, /* 48 */ 2368c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B+0xc, /* 49 */ 2378c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B+0xd, /* 50 */ 2388c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B+0xe, /* 51 */ 2398c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B+0xf, /* 52 */ 2408c2ecf20Sopenharmony_ci}; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci/* 1616(m) cardbus */ 2438c2ecf20Sopenharmony_cistatic const unsigned int emu1616_src_regs[] = { 2448c2ecf20Sopenharmony_ci EMU_SRC_SILENCE, 2458c2ecf20Sopenharmony_ci EMU_SRC_DOCK_MIC_A1, 2468c2ecf20Sopenharmony_ci EMU_SRC_DOCK_MIC_B1, 2478c2ecf20Sopenharmony_ci EMU_SRC_DOCK_ADC1_LEFT1, 2488c2ecf20Sopenharmony_ci EMU_SRC_DOCK_ADC1_RIGHT1, 2498c2ecf20Sopenharmony_ci EMU_SRC_DOCK_ADC2_LEFT1, 2508c2ecf20Sopenharmony_ci EMU_SRC_DOCK_ADC2_RIGHT1, 2518c2ecf20Sopenharmony_ci EMU_SRC_MDOCK_SPDIF_LEFT1, 2528c2ecf20Sopenharmony_ci EMU_SRC_MDOCK_SPDIF_RIGHT1, 2538c2ecf20Sopenharmony_ci EMU_SRC_MDOCK_ADAT, 2548c2ecf20Sopenharmony_ci EMU_SRC_MDOCK_ADAT+1, 2558c2ecf20Sopenharmony_ci EMU_SRC_MDOCK_ADAT+2, 2568c2ecf20Sopenharmony_ci EMU_SRC_MDOCK_ADAT+3, 2578c2ecf20Sopenharmony_ci EMU_SRC_MDOCK_ADAT+4, 2588c2ecf20Sopenharmony_ci EMU_SRC_MDOCK_ADAT+5, 2598c2ecf20Sopenharmony_ci EMU_SRC_MDOCK_ADAT+6, 2608c2ecf20Sopenharmony_ci EMU_SRC_MDOCK_ADAT+7, 2618c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A, 2628c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A+1, 2638c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A+2, 2648c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A+3, 2658c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A+4, 2668c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A+5, 2678c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A+6, 2688c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A+7, 2698c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A+8, 2708c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A+9, 2718c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A+0xa, 2728c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A+0xb, 2738c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A+0xc, 2748c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A+0xd, 2758c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A+0xe, 2768c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32A+0xf, 2778c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B, 2788c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B+1, 2798c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B+2, 2808c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B+3, 2818c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B+4, 2828c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B+5, 2838c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B+6, 2848c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B+7, 2858c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B+8, 2868c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B+9, 2878c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B+0xa, 2888c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B+0xb, 2898c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B+0xc, 2908c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B+0xd, 2918c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B+0xe, 2928c2ecf20Sopenharmony_ci EMU_SRC_ALICE_EMU32B+0xf, 2938c2ecf20Sopenharmony_ci}; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci/* 2968c2ecf20Sopenharmony_ci * Data destinations - physical EMU outputs. 2978c2ecf20Sopenharmony_ci * Each destination has an enum mixer control to choose a data source 2988c2ecf20Sopenharmony_ci */ 2998c2ecf20Sopenharmony_cistatic const unsigned int emu1010_output_dst[] = { 3008c2ecf20Sopenharmony_ci EMU_DST_DOCK_DAC1_LEFT1, /* 0 */ 3018c2ecf20Sopenharmony_ci EMU_DST_DOCK_DAC1_RIGHT1, /* 1 */ 3028c2ecf20Sopenharmony_ci EMU_DST_DOCK_DAC2_LEFT1, /* 2 */ 3038c2ecf20Sopenharmony_ci EMU_DST_DOCK_DAC2_RIGHT1, /* 3 */ 3048c2ecf20Sopenharmony_ci EMU_DST_DOCK_DAC3_LEFT1, /* 4 */ 3058c2ecf20Sopenharmony_ci EMU_DST_DOCK_DAC3_RIGHT1, /* 5 */ 3068c2ecf20Sopenharmony_ci EMU_DST_DOCK_DAC4_LEFT1, /* 6 */ 3078c2ecf20Sopenharmony_ci EMU_DST_DOCK_DAC4_RIGHT1, /* 7 */ 3088c2ecf20Sopenharmony_ci EMU_DST_DOCK_PHONES_LEFT1, /* 8 */ 3098c2ecf20Sopenharmony_ci EMU_DST_DOCK_PHONES_RIGHT1, /* 9 */ 3108c2ecf20Sopenharmony_ci EMU_DST_DOCK_SPDIF_LEFT1, /* 10 */ 3118c2ecf20Sopenharmony_ci EMU_DST_DOCK_SPDIF_RIGHT1, /* 11 */ 3128c2ecf20Sopenharmony_ci EMU_DST_HANA_SPDIF_LEFT1, /* 12 */ 3138c2ecf20Sopenharmony_ci EMU_DST_HANA_SPDIF_RIGHT1, /* 13 */ 3148c2ecf20Sopenharmony_ci EMU_DST_HAMOA_DAC_LEFT1, /* 14 */ 3158c2ecf20Sopenharmony_ci EMU_DST_HAMOA_DAC_RIGHT1, /* 15 */ 3168c2ecf20Sopenharmony_ci EMU_DST_HANA_ADAT, /* 16 */ 3178c2ecf20Sopenharmony_ci EMU_DST_HANA_ADAT+1, /* 17 */ 3188c2ecf20Sopenharmony_ci EMU_DST_HANA_ADAT+2, /* 18 */ 3198c2ecf20Sopenharmony_ci EMU_DST_HANA_ADAT+3, /* 19 */ 3208c2ecf20Sopenharmony_ci EMU_DST_HANA_ADAT+4, /* 20 */ 3218c2ecf20Sopenharmony_ci EMU_DST_HANA_ADAT+5, /* 21 */ 3228c2ecf20Sopenharmony_ci EMU_DST_HANA_ADAT+6, /* 22 */ 3238c2ecf20Sopenharmony_ci EMU_DST_HANA_ADAT+7, /* 23 */ 3248c2ecf20Sopenharmony_ci}; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci/* 1616(m) cardbus */ 3278c2ecf20Sopenharmony_cistatic const unsigned int emu1616_output_dst[] = { 3288c2ecf20Sopenharmony_ci EMU_DST_DOCK_DAC1_LEFT1, 3298c2ecf20Sopenharmony_ci EMU_DST_DOCK_DAC1_RIGHT1, 3308c2ecf20Sopenharmony_ci EMU_DST_DOCK_DAC2_LEFT1, 3318c2ecf20Sopenharmony_ci EMU_DST_DOCK_DAC2_RIGHT1, 3328c2ecf20Sopenharmony_ci EMU_DST_DOCK_DAC3_LEFT1, 3338c2ecf20Sopenharmony_ci EMU_DST_DOCK_DAC3_RIGHT1, 3348c2ecf20Sopenharmony_ci EMU_DST_MDOCK_SPDIF_LEFT1, 3358c2ecf20Sopenharmony_ci EMU_DST_MDOCK_SPDIF_RIGHT1, 3368c2ecf20Sopenharmony_ci EMU_DST_MDOCK_ADAT, 3378c2ecf20Sopenharmony_ci EMU_DST_MDOCK_ADAT+1, 3388c2ecf20Sopenharmony_ci EMU_DST_MDOCK_ADAT+2, 3398c2ecf20Sopenharmony_ci EMU_DST_MDOCK_ADAT+3, 3408c2ecf20Sopenharmony_ci EMU_DST_MDOCK_ADAT+4, 3418c2ecf20Sopenharmony_ci EMU_DST_MDOCK_ADAT+5, 3428c2ecf20Sopenharmony_ci EMU_DST_MDOCK_ADAT+6, 3438c2ecf20Sopenharmony_ci EMU_DST_MDOCK_ADAT+7, 3448c2ecf20Sopenharmony_ci EMU_DST_MANA_DAC_LEFT, 3458c2ecf20Sopenharmony_ci EMU_DST_MANA_DAC_RIGHT, 3468c2ecf20Sopenharmony_ci}; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci/* 3498c2ecf20Sopenharmony_ci * Data destinations - HANA outputs going to Alice2 (audigy) for 3508c2ecf20Sopenharmony_ci * capture (EMU32 + I2S links) 3518c2ecf20Sopenharmony_ci * Each destination has an enum mixer control to choose a data source 3528c2ecf20Sopenharmony_ci */ 3538c2ecf20Sopenharmony_cistatic const unsigned int emu1010_input_dst[] = { 3548c2ecf20Sopenharmony_ci EMU_DST_ALICE2_EMU32_0, 3558c2ecf20Sopenharmony_ci EMU_DST_ALICE2_EMU32_1, 3568c2ecf20Sopenharmony_ci EMU_DST_ALICE2_EMU32_2, 3578c2ecf20Sopenharmony_ci EMU_DST_ALICE2_EMU32_3, 3588c2ecf20Sopenharmony_ci EMU_DST_ALICE2_EMU32_4, 3598c2ecf20Sopenharmony_ci EMU_DST_ALICE2_EMU32_5, 3608c2ecf20Sopenharmony_ci EMU_DST_ALICE2_EMU32_6, 3618c2ecf20Sopenharmony_ci EMU_DST_ALICE2_EMU32_7, 3628c2ecf20Sopenharmony_ci EMU_DST_ALICE2_EMU32_8, 3638c2ecf20Sopenharmony_ci EMU_DST_ALICE2_EMU32_9, 3648c2ecf20Sopenharmony_ci EMU_DST_ALICE2_EMU32_A, 3658c2ecf20Sopenharmony_ci EMU_DST_ALICE2_EMU32_B, 3668c2ecf20Sopenharmony_ci EMU_DST_ALICE2_EMU32_C, 3678c2ecf20Sopenharmony_ci EMU_DST_ALICE2_EMU32_D, 3688c2ecf20Sopenharmony_ci EMU_DST_ALICE2_EMU32_E, 3698c2ecf20Sopenharmony_ci EMU_DST_ALICE2_EMU32_F, 3708c2ecf20Sopenharmony_ci EMU_DST_ALICE_I2S0_LEFT, 3718c2ecf20Sopenharmony_ci EMU_DST_ALICE_I2S0_RIGHT, 3728c2ecf20Sopenharmony_ci EMU_DST_ALICE_I2S1_LEFT, 3738c2ecf20Sopenharmony_ci EMU_DST_ALICE_I2S1_RIGHT, 3748c2ecf20Sopenharmony_ci EMU_DST_ALICE_I2S2_LEFT, 3758c2ecf20Sopenharmony_ci EMU_DST_ALICE_I2S2_RIGHT, 3768c2ecf20Sopenharmony_ci}; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol, 3798c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) 3848c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 49, emu1616_src_texts); 3858c2ecf20Sopenharmony_ci else 3868c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 53, emu1010_src_texts); 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cistatic int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol, 3908c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 3938c2ecf20Sopenharmony_ci unsigned int channel; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci channel = (kcontrol->private_value) & 0xff; 3968c2ecf20Sopenharmony_ci /* Limit: emu1010_output_dst, emu->emu1010.output_source */ 3978c2ecf20Sopenharmony_ci if (channel >= 24 || 3988c2ecf20Sopenharmony_ci (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 && 3998c2ecf20Sopenharmony_ci channel >= 18)) 4008c2ecf20Sopenharmony_ci return -EINVAL; 4018c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = emu->emu1010.output_source[channel]; 4028c2ecf20Sopenharmony_ci return 0; 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic int snd_emu1010_output_source_put(struct snd_kcontrol *kcontrol, 4068c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 4098c2ecf20Sopenharmony_ci unsigned int val; 4108c2ecf20Sopenharmony_ci unsigned int channel; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci val = ucontrol->value.enumerated.item[0]; 4138c2ecf20Sopenharmony_ci if (val >= 53 || 4148c2ecf20Sopenharmony_ci (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 && 4158c2ecf20Sopenharmony_ci val >= 49)) 4168c2ecf20Sopenharmony_ci return -EINVAL; 4178c2ecf20Sopenharmony_ci channel = (kcontrol->private_value) & 0xff; 4188c2ecf20Sopenharmony_ci /* Limit: emu1010_output_dst, emu->emu1010.output_source */ 4198c2ecf20Sopenharmony_ci if (channel >= 24 || 4208c2ecf20Sopenharmony_ci (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 && 4218c2ecf20Sopenharmony_ci channel >= 18)) 4228c2ecf20Sopenharmony_ci return -EINVAL; 4238c2ecf20Sopenharmony_ci if (emu->emu1010.output_source[channel] == val) 4248c2ecf20Sopenharmony_ci return 0; 4258c2ecf20Sopenharmony_ci emu->emu1010.output_source[channel] = val; 4268c2ecf20Sopenharmony_ci if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) 4278c2ecf20Sopenharmony_ci snd_emu1010_fpga_link_dst_src_write(emu, 4288c2ecf20Sopenharmony_ci emu1616_output_dst[channel], emu1616_src_regs[val]); 4298c2ecf20Sopenharmony_ci else 4308c2ecf20Sopenharmony_ci snd_emu1010_fpga_link_dst_src_write(emu, 4318c2ecf20Sopenharmony_ci emu1010_output_dst[channel], emu1010_src_regs[val]); 4328c2ecf20Sopenharmony_ci return 1; 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic int snd_emu1010_input_source_get(struct snd_kcontrol *kcontrol, 4368c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 4398c2ecf20Sopenharmony_ci unsigned int channel; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci channel = (kcontrol->private_value) & 0xff; 4428c2ecf20Sopenharmony_ci /* Limit: emu1010_input_dst, emu->emu1010.input_source */ 4438c2ecf20Sopenharmony_ci if (channel >= 22) 4448c2ecf20Sopenharmony_ci return -EINVAL; 4458c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = emu->emu1010.input_source[channel]; 4468c2ecf20Sopenharmony_ci return 0; 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cistatic int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol, 4508c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 4538c2ecf20Sopenharmony_ci unsigned int val; 4548c2ecf20Sopenharmony_ci unsigned int channel; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci val = ucontrol->value.enumerated.item[0]; 4578c2ecf20Sopenharmony_ci if (val >= 53 || 4588c2ecf20Sopenharmony_ci (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616 && 4598c2ecf20Sopenharmony_ci val >= 49)) 4608c2ecf20Sopenharmony_ci return -EINVAL; 4618c2ecf20Sopenharmony_ci channel = (kcontrol->private_value) & 0xff; 4628c2ecf20Sopenharmony_ci /* Limit: emu1010_input_dst, emu->emu1010.input_source */ 4638c2ecf20Sopenharmony_ci if (channel >= 22) 4648c2ecf20Sopenharmony_ci return -EINVAL; 4658c2ecf20Sopenharmony_ci if (emu->emu1010.input_source[channel] == val) 4668c2ecf20Sopenharmony_ci return 0; 4678c2ecf20Sopenharmony_ci emu->emu1010.input_source[channel] = val; 4688c2ecf20Sopenharmony_ci if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) 4698c2ecf20Sopenharmony_ci snd_emu1010_fpga_link_dst_src_write(emu, 4708c2ecf20Sopenharmony_ci emu1010_input_dst[channel], emu1616_src_regs[val]); 4718c2ecf20Sopenharmony_ci else 4728c2ecf20Sopenharmony_ci snd_emu1010_fpga_link_dst_src_write(emu, 4738c2ecf20Sopenharmony_ci emu1010_input_dst[channel], emu1010_src_regs[val]); 4748c2ecf20Sopenharmony_ci return 1; 4758c2ecf20Sopenharmony_ci} 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci#define EMU1010_SOURCE_OUTPUT(xname,chid) \ 4788c2ecf20Sopenharmony_ci{ \ 4798c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 4808c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ 4818c2ecf20Sopenharmony_ci .info = snd_emu1010_input_output_source_info, \ 4828c2ecf20Sopenharmony_ci .get = snd_emu1010_output_source_get, \ 4838c2ecf20Sopenharmony_ci .put = snd_emu1010_output_source_put, \ 4848c2ecf20Sopenharmony_ci .private_value = chid \ 4858c2ecf20Sopenharmony_ci} 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] = { 4888c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0), 4898c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1), 4908c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2), 4918c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3), 4928c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4), 4938c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5), 4948c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("Dock DAC4 Left Playback Enum", 6), 4958c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("Dock DAC4 Right Playback Enum", 7), 4968c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("Dock Phones Left Playback Enum", 8), 4978c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("Dock Phones Right Playback Enum", 9), 4988c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 0xa), 4998c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 0xb), 5008c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("1010 SPDIF Left Playback Enum", 0xc), 5018c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("1010 SPDIF Right Playback Enum", 0xd), 5028c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("0202 DAC Left Playback Enum", 0xe), 5038c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("0202 DAC Right Playback Enum", 0xf), 5048c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("1010 ADAT 0 Playback Enum", 0x10), 5058c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("1010 ADAT 1 Playback Enum", 0x11), 5068c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("1010 ADAT 2 Playback Enum", 0x12), 5078c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("1010 ADAT 3 Playback Enum", 0x13), 5088c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("1010 ADAT 4 Playback Enum", 0x14), 5098c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("1010 ADAT 5 Playback Enum", 0x15), 5108c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("1010 ADAT 6 Playback Enum", 0x16), 5118c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("1010 ADAT 7 Playback Enum", 0x17), 5128c2ecf20Sopenharmony_ci}; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci/* 1616(m) cardbus */ 5168c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu1616_output_enum_ctls[] = { 5178c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0), 5188c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1), 5198c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2), 5208c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("Dock DAC2 Right Playback Enum", 3), 5218c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("Dock DAC3 Left Playback Enum", 4), 5228c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("Dock DAC3 Right Playback Enum", 5), 5238c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("Dock SPDIF Left Playback Enum", 6), 5248c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("Dock SPDIF Right Playback Enum", 7), 5258c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("Dock ADAT 0 Playback Enum", 8), 5268c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("Dock ADAT 1 Playback Enum", 9), 5278c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("Dock ADAT 2 Playback Enum", 0xa), 5288c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("Dock ADAT 3 Playback Enum", 0xb), 5298c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("Dock ADAT 4 Playback Enum", 0xc), 5308c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("Dock ADAT 5 Playback Enum", 0xd), 5318c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("Dock ADAT 6 Playback Enum", 0xe), 5328c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("Dock ADAT 7 Playback Enum", 0xf), 5338c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("Mana DAC Left Playback Enum", 0x10), 5348c2ecf20Sopenharmony_ci EMU1010_SOURCE_OUTPUT("Mana DAC Right Playback Enum", 0x11), 5358c2ecf20Sopenharmony_ci}; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci#define EMU1010_SOURCE_INPUT(xname,chid) \ 5398c2ecf20Sopenharmony_ci{ \ 5408c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 5418c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ 5428c2ecf20Sopenharmony_ci .info = snd_emu1010_input_output_source_info, \ 5438c2ecf20Sopenharmony_ci .get = snd_emu1010_input_source_get, \ 5448c2ecf20Sopenharmony_ci .put = snd_emu1010_input_source_put, \ 5458c2ecf20Sopenharmony_ci .private_value = chid \ 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] = { 5498c2ecf20Sopenharmony_ci EMU1010_SOURCE_INPUT("DSP 0 Capture Enum", 0), 5508c2ecf20Sopenharmony_ci EMU1010_SOURCE_INPUT("DSP 1 Capture Enum", 1), 5518c2ecf20Sopenharmony_ci EMU1010_SOURCE_INPUT("DSP 2 Capture Enum", 2), 5528c2ecf20Sopenharmony_ci EMU1010_SOURCE_INPUT("DSP 3 Capture Enum", 3), 5538c2ecf20Sopenharmony_ci EMU1010_SOURCE_INPUT("DSP 4 Capture Enum", 4), 5548c2ecf20Sopenharmony_ci EMU1010_SOURCE_INPUT("DSP 5 Capture Enum", 5), 5558c2ecf20Sopenharmony_ci EMU1010_SOURCE_INPUT("DSP 6 Capture Enum", 6), 5568c2ecf20Sopenharmony_ci EMU1010_SOURCE_INPUT("DSP 7 Capture Enum", 7), 5578c2ecf20Sopenharmony_ci EMU1010_SOURCE_INPUT("DSP 8 Capture Enum", 8), 5588c2ecf20Sopenharmony_ci EMU1010_SOURCE_INPUT("DSP 9 Capture Enum", 9), 5598c2ecf20Sopenharmony_ci EMU1010_SOURCE_INPUT("DSP A Capture Enum", 0xa), 5608c2ecf20Sopenharmony_ci EMU1010_SOURCE_INPUT("DSP B Capture Enum", 0xb), 5618c2ecf20Sopenharmony_ci EMU1010_SOURCE_INPUT("DSP C Capture Enum", 0xc), 5628c2ecf20Sopenharmony_ci EMU1010_SOURCE_INPUT("DSP D Capture Enum", 0xd), 5638c2ecf20Sopenharmony_ci EMU1010_SOURCE_INPUT("DSP E Capture Enum", 0xe), 5648c2ecf20Sopenharmony_ci EMU1010_SOURCE_INPUT("DSP F Capture Enum", 0xf), 5658c2ecf20Sopenharmony_ci EMU1010_SOURCE_INPUT("DSP 10 Capture Enum", 0x10), 5668c2ecf20Sopenharmony_ci EMU1010_SOURCE_INPUT("DSP 11 Capture Enum", 0x11), 5678c2ecf20Sopenharmony_ci EMU1010_SOURCE_INPUT("DSP 12 Capture Enum", 0x12), 5688c2ecf20Sopenharmony_ci EMU1010_SOURCE_INPUT("DSP 13 Capture Enum", 0x13), 5698c2ecf20Sopenharmony_ci EMU1010_SOURCE_INPUT("DSP 14 Capture Enum", 0x14), 5708c2ecf20Sopenharmony_ci EMU1010_SOURCE_INPUT("DSP 15 Capture Enum", 0x15), 5718c2ecf20Sopenharmony_ci}; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci#define snd_emu1010_adc_pads_info snd_ctl_boolean_mono_info 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_cistatic int snd_emu1010_adc_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 5788c2ecf20Sopenharmony_ci{ 5798c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 5808c2ecf20Sopenharmony_ci unsigned int mask = kcontrol->private_value & 0xff; 5818c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = (emu->emu1010.adc_pads & mask) ? 1 : 0; 5828c2ecf20Sopenharmony_ci return 0; 5838c2ecf20Sopenharmony_ci} 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_cistatic int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 5868c2ecf20Sopenharmony_ci{ 5878c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 5888c2ecf20Sopenharmony_ci unsigned int mask = kcontrol->private_value & 0xff; 5898c2ecf20Sopenharmony_ci unsigned int val, cache; 5908c2ecf20Sopenharmony_ci val = ucontrol->value.integer.value[0]; 5918c2ecf20Sopenharmony_ci cache = emu->emu1010.adc_pads; 5928c2ecf20Sopenharmony_ci if (val == 1) 5938c2ecf20Sopenharmony_ci cache = cache | mask; 5948c2ecf20Sopenharmony_ci else 5958c2ecf20Sopenharmony_ci cache = cache & ~mask; 5968c2ecf20Sopenharmony_ci if (cache != emu->emu1010.adc_pads) { 5978c2ecf20Sopenharmony_ci snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, cache ); 5988c2ecf20Sopenharmony_ci emu->emu1010.adc_pads = cache; 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci return 0; 6028c2ecf20Sopenharmony_ci} 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci#define EMU1010_ADC_PADS(xname,chid) \ 6078c2ecf20Sopenharmony_ci{ \ 6088c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 6098c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ 6108c2ecf20Sopenharmony_ci .info = snd_emu1010_adc_pads_info, \ 6118c2ecf20Sopenharmony_ci .get = snd_emu1010_adc_pads_get, \ 6128c2ecf20Sopenharmony_ci .put = snd_emu1010_adc_pads_put, \ 6138c2ecf20Sopenharmony_ci .private_value = chid \ 6148c2ecf20Sopenharmony_ci} 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu1010_adc_pads[] = { 6178c2ecf20Sopenharmony_ci EMU1010_ADC_PADS("ADC1 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD1), 6188c2ecf20Sopenharmony_ci EMU1010_ADC_PADS("ADC2 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD2), 6198c2ecf20Sopenharmony_ci EMU1010_ADC_PADS("ADC3 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD3), 6208c2ecf20Sopenharmony_ci EMU1010_ADC_PADS("ADC1 14dB PAD 0202 Capture Switch", EMU_HANA_0202_ADC_PAD1), 6218c2ecf20Sopenharmony_ci}; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci#define snd_emu1010_dac_pads_info snd_ctl_boolean_mono_info 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_cistatic int snd_emu1010_dac_pads_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 6268c2ecf20Sopenharmony_ci{ 6278c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 6288c2ecf20Sopenharmony_ci unsigned int mask = kcontrol->private_value & 0xff; 6298c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = (emu->emu1010.dac_pads & mask) ? 1 : 0; 6308c2ecf20Sopenharmony_ci return 0; 6318c2ecf20Sopenharmony_ci} 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_cistatic int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 6348c2ecf20Sopenharmony_ci{ 6358c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 6368c2ecf20Sopenharmony_ci unsigned int mask = kcontrol->private_value & 0xff; 6378c2ecf20Sopenharmony_ci unsigned int val, cache; 6388c2ecf20Sopenharmony_ci val = ucontrol->value.integer.value[0]; 6398c2ecf20Sopenharmony_ci cache = emu->emu1010.dac_pads; 6408c2ecf20Sopenharmony_ci if (val == 1) 6418c2ecf20Sopenharmony_ci cache = cache | mask; 6428c2ecf20Sopenharmony_ci else 6438c2ecf20Sopenharmony_ci cache = cache & ~mask; 6448c2ecf20Sopenharmony_ci if (cache != emu->emu1010.dac_pads) { 6458c2ecf20Sopenharmony_ci snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, cache ); 6468c2ecf20Sopenharmony_ci emu->emu1010.dac_pads = cache; 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci return 0; 6508c2ecf20Sopenharmony_ci} 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci#define EMU1010_DAC_PADS(xname,chid) \ 6558c2ecf20Sopenharmony_ci{ \ 6568c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 6578c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ 6588c2ecf20Sopenharmony_ci .info = snd_emu1010_dac_pads_info, \ 6598c2ecf20Sopenharmony_ci .get = snd_emu1010_dac_pads_get, \ 6608c2ecf20Sopenharmony_ci .put = snd_emu1010_dac_pads_put, \ 6618c2ecf20Sopenharmony_ci .private_value = chid \ 6628c2ecf20Sopenharmony_ci} 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu1010_dac_pads[] = { 6658c2ecf20Sopenharmony_ci EMU1010_DAC_PADS("DAC1 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD1), 6668c2ecf20Sopenharmony_ci EMU1010_DAC_PADS("DAC2 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD2), 6678c2ecf20Sopenharmony_ci EMU1010_DAC_PADS("DAC3 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD3), 6688c2ecf20Sopenharmony_ci EMU1010_DAC_PADS("DAC4 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD4), 6698c2ecf20Sopenharmony_ci EMU1010_DAC_PADS("DAC1 0202 14dB PAD Playback Switch", EMU_HANA_0202_DAC_PAD1), 6708c2ecf20Sopenharmony_ci}; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_cistatic int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol, 6748c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 6758c2ecf20Sopenharmony_ci{ 6768c2ecf20Sopenharmony_ci static const char * const texts[4] = { 6778c2ecf20Sopenharmony_ci "44100", "48000", "SPDIF", "ADAT" 6788c2ecf20Sopenharmony_ci }; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 4, texts); 6818c2ecf20Sopenharmony_ci} 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_cistatic int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol, 6848c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 6858c2ecf20Sopenharmony_ci{ 6868c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = emu->emu1010.internal_clock; 6898c2ecf20Sopenharmony_ci return 0; 6908c2ecf20Sopenharmony_ci} 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_cistatic int snd_emu1010_internal_clock_put(struct snd_kcontrol *kcontrol, 6938c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 6948c2ecf20Sopenharmony_ci{ 6958c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 6968c2ecf20Sopenharmony_ci unsigned int val; 6978c2ecf20Sopenharmony_ci int change = 0; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci val = ucontrol->value.enumerated.item[0] ; 7008c2ecf20Sopenharmony_ci /* Limit: uinfo->value.enumerated.items = 4; */ 7018c2ecf20Sopenharmony_ci if (val >= 4) 7028c2ecf20Sopenharmony_ci return -EINVAL; 7038c2ecf20Sopenharmony_ci change = (emu->emu1010.internal_clock != val); 7048c2ecf20Sopenharmony_ci if (change) { 7058c2ecf20Sopenharmony_ci emu->emu1010.internal_clock = val; 7068c2ecf20Sopenharmony_ci switch (val) { 7078c2ecf20Sopenharmony_ci case 0: 7088c2ecf20Sopenharmony_ci /* 44100 */ 7098c2ecf20Sopenharmony_ci /* Mute all */ 7108c2ecf20Sopenharmony_ci snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 7118c2ecf20Sopenharmony_ci /* Default fallback clock 48kHz */ 7128c2ecf20Sopenharmony_ci snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_44_1K ); 7138c2ecf20Sopenharmony_ci /* Word Clock source, Internal 44.1kHz x1 */ 7148c2ecf20Sopenharmony_ci snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 7158c2ecf20Sopenharmony_ci EMU_HANA_WCLOCK_INT_44_1K | EMU_HANA_WCLOCK_1X ); 7168c2ecf20Sopenharmony_ci /* Set LEDs on Audio Dock */ 7178c2ecf20Sopenharmony_ci snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 7188c2ecf20Sopenharmony_ci EMU_HANA_DOCK_LEDS_2_44K | EMU_HANA_DOCK_LEDS_2_LOCK ); 7198c2ecf20Sopenharmony_ci /* Allow DLL to settle */ 7208c2ecf20Sopenharmony_ci msleep(10); 7218c2ecf20Sopenharmony_ci /* Unmute all */ 7228c2ecf20Sopenharmony_ci snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 7238c2ecf20Sopenharmony_ci break; 7248c2ecf20Sopenharmony_ci case 1: 7258c2ecf20Sopenharmony_ci /* 48000 */ 7268c2ecf20Sopenharmony_ci /* Mute all */ 7278c2ecf20Sopenharmony_ci snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 7288c2ecf20Sopenharmony_ci /* Default fallback clock 48kHz */ 7298c2ecf20Sopenharmony_ci snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); 7308c2ecf20Sopenharmony_ci /* Word Clock source, Internal 48kHz x1 */ 7318c2ecf20Sopenharmony_ci snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 7328c2ecf20Sopenharmony_ci EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_1X ); 7338c2ecf20Sopenharmony_ci /* Set LEDs on Audio Dock */ 7348c2ecf20Sopenharmony_ci snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 7358c2ecf20Sopenharmony_ci EMU_HANA_DOCK_LEDS_2_48K | EMU_HANA_DOCK_LEDS_2_LOCK ); 7368c2ecf20Sopenharmony_ci /* Allow DLL to settle */ 7378c2ecf20Sopenharmony_ci msleep(10); 7388c2ecf20Sopenharmony_ci /* Unmute all */ 7398c2ecf20Sopenharmony_ci snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 7408c2ecf20Sopenharmony_ci break; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci case 2: /* Take clock from S/PDIF IN */ 7438c2ecf20Sopenharmony_ci /* Mute all */ 7448c2ecf20Sopenharmony_ci snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 7458c2ecf20Sopenharmony_ci /* Default fallback clock 48kHz */ 7468c2ecf20Sopenharmony_ci snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); 7478c2ecf20Sopenharmony_ci /* Word Clock source, sync to S/PDIF input */ 7488c2ecf20Sopenharmony_ci snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 7498c2ecf20Sopenharmony_ci EMU_HANA_WCLOCK_HANA_SPDIF_IN | EMU_HANA_WCLOCK_1X ); 7508c2ecf20Sopenharmony_ci /* Set LEDs on Audio Dock */ 7518c2ecf20Sopenharmony_ci snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, 7528c2ecf20Sopenharmony_ci EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK ); 7538c2ecf20Sopenharmony_ci /* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */ 7548c2ecf20Sopenharmony_ci /* Allow DLL to settle */ 7558c2ecf20Sopenharmony_ci msleep(10); 7568c2ecf20Sopenharmony_ci /* Unmute all */ 7578c2ecf20Sopenharmony_ci snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 7588c2ecf20Sopenharmony_ci break; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci case 3: 7618c2ecf20Sopenharmony_ci /* Take clock from ADAT IN */ 7628c2ecf20Sopenharmony_ci /* Mute all */ 7638c2ecf20Sopenharmony_ci snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_MUTE ); 7648c2ecf20Sopenharmony_ci /* Default fallback clock 48kHz */ 7658c2ecf20Sopenharmony_ci snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K ); 7668c2ecf20Sopenharmony_ci /* Word Clock source, sync to ADAT input */ 7678c2ecf20Sopenharmony_ci snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, 7688c2ecf20Sopenharmony_ci EMU_HANA_WCLOCK_HANA_ADAT_IN | EMU_HANA_WCLOCK_1X ); 7698c2ecf20Sopenharmony_ci /* Set LEDs on Audio Dock */ 7708c2ecf20Sopenharmony_ci snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_LEDS_2, EMU_HANA_DOCK_LEDS_2_EXT | EMU_HANA_DOCK_LEDS_2_LOCK ); 7718c2ecf20Sopenharmony_ci /* FIXME: We should set EMU_HANA_DOCK_LEDS_2_LOCK only when clock signal is present and valid */ 7728c2ecf20Sopenharmony_ci /* Allow DLL to settle */ 7738c2ecf20Sopenharmony_ci msleep(10); 7748c2ecf20Sopenharmony_ci /* Unmute all */ 7758c2ecf20Sopenharmony_ci snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE ); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci break; 7798c2ecf20Sopenharmony_ci } 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci return change; 7828c2ecf20Sopenharmony_ci} 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu1010_internal_clock = 7858c2ecf20Sopenharmony_ci{ 7868c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 7878c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 7888c2ecf20Sopenharmony_ci .name = "Clock Internal Rate", 7898c2ecf20Sopenharmony_ci .count = 1, 7908c2ecf20Sopenharmony_ci .info = snd_emu1010_internal_clock_info, 7918c2ecf20Sopenharmony_ci .get = snd_emu1010_internal_clock_get, 7928c2ecf20Sopenharmony_ci .put = snd_emu1010_internal_clock_put 7938c2ecf20Sopenharmony_ci}; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_cistatic int snd_emu1010_optical_out_info(struct snd_kcontrol *kcontrol, 7968c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 7978c2ecf20Sopenharmony_ci{ 7988c2ecf20Sopenharmony_ci static const char * const texts[2] = { 7998c2ecf20Sopenharmony_ci "SPDIF", "ADAT" 8008c2ecf20Sopenharmony_ci }; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 2, texts); 8038c2ecf20Sopenharmony_ci} 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_cistatic int snd_emu1010_optical_out_get(struct snd_kcontrol *kcontrol, 8068c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 8078c2ecf20Sopenharmony_ci{ 8088c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = emu->emu1010.optical_out; 8118c2ecf20Sopenharmony_ci return 0; 8128c2ecf20Sopenharmony_ci} 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_cistatic int snd_emu1010_optical_out_put(struct snd_kcontrol *kcontrol, 8158c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 8168c2ecf20Sopenharmony_ci{ 8178c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 8188c2ecf20Sopenharmony_ci unsigned int val; 8198c2ecf20Sopenharmony_ci u32 tmp; 8208c2ecf20Sopenharmony_ci int change = 0; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci val = ucontrol->value.enumerated.item[0]; 8238c2ecf20Sopenharmony_ci /* Limit: uinfo->value.enumerated.items = 2; */ 8248c2ecf20Sopenharmony_ci if (val >= 2) 8258c2ecf20Sopenharmony_ci return -EINVAL; 8268c2ecf20Sopenharmony_ci change = (emu->emu1010.optical_out != val); 8278c2ecf20Sopenharmony_ci if (change) { 8288c2ecf20Sopenharmony_ci emu->emu1010.optical_out = val; 8298c2ecf20Sopenharmony_ci tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : 0) | 8308c2ecf20Sopenharmony_ci (emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : 0); 8318c2ecf20Sopenharmony_ci snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp); 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci return change; 8348c2ecf20Sopenharmony_ci} 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu1010_optical_out = { 8378c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 8388c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 8398c2ecf20Sopenharmony_ci .name = "Optical Output Mode", 8408c2ecf20Sopenharmony_ci .count = 1, 8418c2ecf20Sopenharmony_ci .info = snd_emu1010_optical_out_info, 8428c2ecf20Sopenharmony_ci .get = snd_emu1010_optical_out_get, 8438c2ecf20Sopenharmony_ci .put = snd_emu1010_optical_out_put 8448c2ecf20Sopenharmony_ci}; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_cistatic int snd_emu1010_optical_in_info(struct snd_kcontrol *kcontrol, 8478c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 8488c2ecf20Sopenharmony_ci{ 8498c2ecf20Sopenharmony_ci static const char * const texts[2] = { 8508c2ecf20Sopenharmony_ci "SPDIF", "ADAT" 8518c2ecf20Sopenharmony_ci }; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 2, texts); 8548c2ecf20Sopenharmony_ci} 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_cistatic int snd_emu1010_optical_in_get(struct snd_kcontrol *kcontrol, 8578c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 8588c2ecf20Sopenharmony_ci{ 8598c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = emu->emu1010.optical_in; 8628c2ecf20Sopenharmony_ci return 0; 8638c2ecf20Sopenharmony_ci} 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_cistatic int snd_emu1010_optical_in_put(struct snd_kcontrol *kcontrol, 8668c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 8678c2ecf20Sopenharmony_ci{ 8688c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 8698c2ecf20Sopenharmony_ci unsigned int val; 8708c2ecf20Sopenharmony_ci u32 tmp; 8718c2ecf20Sopenharmony_ci int change = 0; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci val = ucontrol->value.enumerated.item[0]; 8748c2ecf20Sopenharmony_ci /* Limit: uinfo->value.enumerated.items = 2; */ 8758c2ecf20Sopenharmony_ci if (val >= 2) 8768c2ecf20Sopenharmony_ci return -EINVAL; 8778c2ecf20Sopenharmony_ci change = (emu->emu1010.optical_in != val); 8788c2ecf20Sopenharmony_ci if (change) { 8798c2ecf20Sopenharmony_ci emu->emu1010.optical_in = val; 8808c2ecf20Sopenharmony_ci tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : 0) | 8818c2ecf20Sopenharmony_ci (emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : 0); 8828c2ecf20Sopenharmony_ci snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp); 8838c2ecf20Sopenharmony_ci } 8848c2ecf20Sopenharmony_ci return change; 8858c2ecf20Sopenharmony_ci} 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu1010_optical_in = { 8888c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 8898c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 8908c2ecf20Sopenharmony_ci .name = "Optical Input Mode", 8918c2ecf20Sopenharmony_ci .count = 1, 8928c2ecf20Sopenharmony_ci .info = snd_emu1010_optical_in_info, 8938c2ecf20Sopenharmony_ci .get = snd_emu1010_optical_in_get, 8948c2ecf20Sopenharmony_ci .put = snd_emu1010_optical_in_put 8958c2ecf20Sopenharmony_ci}; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_cistatic int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol, 8988c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 8998c2ecf20Sopenharmony_ci{ 9008c2ecf20Sopenharmony_ci#if 0 9018c2ecf20Sopenharmony_ci static const char * const texts[4] = { 9028c2ecf20Sopenharmony_ci "Unknown1", "Unknown2", "Mic", "Line" 9038c2ecf20Sopenharmony_ci }; 9048c2ecf20Sopenharmony_ci#endif 9058c2ecf20Sopenharmony_ci static const char * const texts[2] = { 9068c2ecf20Sopenharmony_ci "Mic", "Line" 9078c2ecf20Sopenharmony_ci }; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 2, texts); 9108c2ecf20Sopenharmony_ci} 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_cistatic int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol, 9138c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 9148c2ecf20Sopenharmony_ci{ 9158c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = emu->i2c_capture_source; 9188c2ecf20Sopenharmony_ci return 0; 9198c2ecf20Sopenharmony_ci} 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_cistatic int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol, 9228c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 9238c2ecf20Sopenharmony_ci{ 9248c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 9258c2ecf20Sopenharmony_ci unsigned int source_id; 9268c2ecf20Sopenharmony_ci unsigned int ngain, ogain; 9278c2ecf20Sopenharmony_ci u32 gpio; 9288c2ecf20Sopenharmony_ci int change = 0; 9298c2ecf20Sopenharmony_ci unsigned long flags; 9308c2ecf20Sopenharmony_ci u32 source; 9318c2ecf20Sopenharmony_ci /* If the capture source has changed, 9328c2ecf20Sopenharmony_ci * update the capture volume from the cached value 9338c2ecf20Sopenharmony_ci * for the particular source. 9348c2ecf20Sopenharmony_ci */ 9358c2ecf20Sopenharmony_ci source_id = ucontrol->value.enumerated.item[0]; 9368c2ecf20Sopenharmony_ci /* Limit: uinfo->value.enumerated.items = 2; */ 9378c2ecf20Sopenharmony_ci /* emu->i2c_capture_volume */ 9388c2ecf20Sopenharmony_ci if (source_id >= 2) 9398c2ecf20Sopenharmony_ci return -EINVAL; 9408c2ecf20Sopenharmony_ci change = (emu->i2c_capture_source != source_id); 9418c2ecf20Sopenharmony_ci if (change) { 9428c2ecf20Sopenharmony_ci snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */ 9438c2ecf20Sopenharmony_ci spin_lock_irqsave(&emu->emu_lock, flags); 9448c2ecf20Sopenharmony_ci gpio = inl(emu->port + A_IOCFG); 9458c2ecf20Sopenharmony_ci if (source_id==0) 9468c2ecf20Sopenharmony_ci outl(gpio | 0x4, emu->port + A_IOCFG); 9478c2ecf20Sopenharmony_ci else 9488c2ecf20Sopenharmony_ci outl(gpio & ~0x4, emu->port + A_IOCFG); 9498c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&emu->emu_lock, flags); 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci ngain = emu->i2c_capture_volume[source_id][0]; /* Left */ 9528c2ecf20Sopenharmony_ci ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ 9538c2ecf20Sopenharmony_ci if (ngain != ogain) 9548c2ecf20Sopenharmony_ci snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff)); 9558c2ecf20Sopenharmony_ci ngain = emu->i2c_capture_volume[source_id][1]; /* Right */ 9568c2ecf20Sopenharmony_ci ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */ 9578c2ecf20Sopenharmony_ci if (ngain != ogain) 9588c2ecf20Sopenharmony_ci snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci source = 1 << (source_id + 2); 9618c2ecf20Sopenharmony_ci snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */ 9628c2ecf20Sopenharmony_ci emu->i2c_capture_source = source_id; 9638c2ecf20Sopenharmony_ci } 9648c2ecf20Sopenharmony_ci return change; 9658c2ecf20Sopenharmony_ci} 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_audigy_i2c_capture_source = 9688c2ecf20Sopenharmony_ci{ 9698c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 9708c2ecf20Sopenharmony_ci .name = "Capture Source", 9718c2ecf20Sopenharmony_ci .info = snd_audigy_i2c_capture_source_info, 9728c2ecf20Sopenharmony_ci .get = snd_audigy_i2c_capture_source_get, 9738c2ecf20Sopenharmony_ci .put = snd_audigy_i2c_capture_source_put 9748c2ecf20Sopenharmony_ci}; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_cistatic int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol, 9778c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 9788c2ecf20Sopenharmony_ci{ 9798c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 9808c2ecf20Sopenharmony_ci uinfo->count = 2; 9818c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 9828c2ecf20Sopenharmony_ci uinfo->value.integer.max = 255; 9838c2ecf20Sopenharmony_ci return 0; 9848c2ecf20Sopenharmony_ci} 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_cistatic int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol, 9878c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 9888c2ecf20Sopenharmony_ci{ 9898c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 9908c2ecf20Sopenharmony_ci unsigned int source_id; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci source_id = kcontrol->private_value; 9938c2ecf20Sopenharmony_ci /* Limit: emu->i2c_capture_volume */ 9948c2ecf20Sopenharmony_ci /* capture_source: uinfo->value.enumerated.items = 2 */ 9958c2ecf20Sopenharmony_ci if (source_id >= 2) 9968c2ecf20Sopenharmony_ci return -EINVAL; 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0]; 9998c2ecf20Sopenharmony_ci ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1]; 10008c2ecf20Sopenharmony_ci return 0; 10018c2ecf20Sopenharmony_ci} 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_cistatic int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol, 10048c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 10058c2ecf20Sopenharmony_ci{ 10068c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 10078c2ecf20Sopenharmony_ci unsigned int ogain; 10088c2ecf20Sopenharmony_ci unsigned int ngain; 10098c2ecf20Sopenharmony_ci unsigned int source_id; 10108c2ecf20Sopenharmony_ci int change = 0; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci source_id = kcontrol->private_value; 10138c2ecf20Sopenharmony_ci /* Limit: emu->i2c_capture_volume */ 10148c2ecf20Sopenharmony_ci /* capture_source: uinfo->value.enumerated.items = 2 */ 10158c2ecf20Sopenharmony_ci if (source_id >= 2) 10168c2ecf20Sopenharmony_ci return -EINVAL; 10178c2ecf20Sopenharmony_ci ogain = emu->i2c_capture_volume[source_id][0]; /* Left */ 10188c2ecf20Sopenharmony_ci ngain = ucontrol->value.integer.value[0]; 10198c2ecf20Sopenharmony_ci if (ngain > 0xff) 10208c2ecf20Sopenharmony_ci return 0; 10218c2ecf20Sopenharmony_ci if (ogain != ngain) { 10228c2ecf20Sopenharmony_ci if (emu->i2c_capture_source == source_id) 10238c2ecf20Sopenharmony_ci snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) ); 10248c2ecf20Sopenharmony_ci emu->i2c_capture_volume[source_id][0] = ngain; 10258c2ecf20Sopenharmony_ci change = 1; 10268c2ecf20Sopenharmony_ci } 10278c2ecf20Sopenharmony_ci ogain = emu->i2c_capture_volume[source_id][1]; /* Right */ 10288c2ecf20Sopenharmony_ci ngain = ucontrol->value.integer.value[1]; 10298c2ecf20Sopenharmony_ci if (ngain > 0xff) 10308c2ecf20Sopenharmony_ci return 0; 10318c2ecf20Sopenharmony_ci if (ogain != ngain) { 10328c2ecf20Sopenharmony_ci if (emu->i2c_capture_source == source_id) 10338c2ecf20Sopenharmony_ci snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); 10348c2ecf20Sopenharmony_ci emu->i2c_capture_volume[source_id][1] = ngain; 10358c2ecf20Sopenharmony_ci change = 1; 10368c2ecf20Sopenharmony_ci } 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci return change; 10398c2ecf20Sopenharmony_ci} 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci#define I2C_VOLUME(xname,chid) \ 10428c2ecf20Sopenharmony_ci{ \ 10438c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 10448c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ 10458c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ 10468c2ecf20Sopenharmony_ci .info = snd_audigy_i2c_volume_info, \ 10478c2ecf20Sopenharmony_ci .get = snd_audigy_i2c_volume_get, \ 10488c2ecf20Sopenharmony_ci .put = snd_audigy_i2c_volume_put, \ 10498c2ecf20Sopenharmony_ci .tlv = { .p = snd_audigy_db_scale2 }, \ 10508c2ecf20Sopenharmony_ci .private_value = chid \ 10518c2ecf20Sopenharmony_ci} 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] = { 10558c2ecf20Sopenharmony_ci I2C_VOLUME("Mic Capture Volume", 0), 10568c2ecf20Sopenharmony_ci I2C_VOLUME("Line Capture Volume", 0) 10578c2ecf20Sopenharmony_ci}; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci#if 0 10608c2ecf20Sopenharmony_cistatic int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 10618c2ecf20Sopenharmony_ci{ 10628c2ecf20Sopenharmony_ci static const char * const texts[] = {"44100", "48000", "96000"}; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 3, texts); 10658c2ecf20Sopenharmony_ci} 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_cistatic int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol, 10688c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 10698c2ecf20Sopenharmony_ci{ 10708c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 10718c2ecf20Sopenharmony_ci unsigned int tmp; 10728c2ecf20Sopenharmony_ci unsigned long flags; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci spin_lock_irqsave(&emu->reg_lock, flags); 10768c2ecf20Sopenharmony_ci tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); 10778c2ecf20Sopenharmony_ci switch (tmp & A_SPDIF_RATE_MASK) { 10788c2ecf20Sopenharmony_ci case A_SPDIF_44100: 10798c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 0; 10808c2ecf20Sopenharmony_ci break; 10818c2ecf20Sopenharmony_ci case A_SPDIF_48000: 10828c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 1; 10838c2ecf20Sopenharmony_ci break; 10848c2ecf20Sopenharmony_ci case A_SPDIF_96000: 10858c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 2; 10868c2ecf20Sopenharmony_ci break; 10878c2ecf20Sopenharmony_ci default: 10888c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 1; 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&emu->reg_lock, flags); 10918c2ecf20Sopenharmony_ci return 0; 10928c2ecf20Sopenharmony_ci} 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_cistatic int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol, 10958c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 10968c2ecf20Sopenharmony_ci{ 10978c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 10988c2ecf20Sopenharmony_ci int change; 10998c2ecf20Sopenharmony_ci unsigned int reg, val, tmp; 11008c2ecf20Sopenharmony_ci unsigned long flags; 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci switch(ucontrol->value.enumerated.item[0]) { 11038c2ecf20Sopenharmony_ci case 0: 11048c2ecf20Sopenharmony_ci val = A_SPDIF_44100; 11058c2ecf20Sopenharmony_ci break; 11068c2ecf20Sopenharmony_ci case 1: 11078c2ecf20Sopenharmony_ci val = A_SPDIF_48000; 11088c2ecf20Sopenharmony_ci break; 11098c2ecf20Sopenharmony_ci case 2: 11108c2ecf20Sopenharmony_ci val = A_SPDIF_96000; 11118c2ecf20Sopenharmony_ci break; 11128c2ecf20Sopenharmony_ci default: 11138c2ecf20Sopenharmony_ci val = A_SPDIF_48000; 11148c2ecf20Sopenharmony_ci break; 11158c2ecf20Sopenharmony_ci } 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci spin_lock_irqsave(&emu->reg_lock, flags); 11198c2ecf20Sopenharmony_ci reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); 11208c2ecf20Sopenharmony_ci tmp = reg & ~A_SPDIF_RATE_MASK; 11218c2ecf20Sopenharmony_ci tmp |= val; 11228c2ecf20Sopenharmony_ci if ((change = (tmp != reg))) 11238c2ecf20Sopenharmony_ci snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp); 11248c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&emu->reg_lock, flags); 11258c2ecf20Sopenharmony_ci return change; 11268c2ecf20Sopenharmony_ci} 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_audigy_spdif_output_rate = 11298c2ecf20Sopenharmony_ci{ 11308c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 11318c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 11328c2ecf20Sopenharmony_ci .name = "Audigy SPDIF Output Sample Rate", 11338c2ecf20Sopenharmony_ci .count = 1, 11348c2ecf20Sopenharmony_ci .info = snd_audigy_spdif_output_rate_info, 11358c2ecf20Sopenharmony_ci .get = snd_audigy_spdif_output_rate_get, 11368c2ecf20Sopenharmony_ci .put = snd_audigy_spdif_output_rate_put 11378c2ecf20Sopenharmony_ci}; 11388c2ecf20Sopenharmony_ci#endif 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_cistatic int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol, 11418c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 11428c2ecf20Sopenharmony_ci{ 11438c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 11448c2ecf20Sopenharmony_ci unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 11458c2ecf20Sopenharmony_ci int change; 11468c2ecf20Sopenharmony_ci unsigned int val; 11478c2ecf20Sopenharmony_ci unsigned long flags; 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci /* Limit: emu->spdif_bits */ 11508c2ecf20Sopenharmony_ci if (idx >= 3) 11518c2ecf20Sopenharmony_ci return -EINVAL; 11528c2ecf20Sopenharmony_ci val = (ucontrol->value.iec958.status[0] << 0) | 11538c2ecf20Sopenharmony_ci (ucontrol->value.iec958.status[1] << 8) | 11548c2ecf20Sopenharmony_ci (ucontrol->value.iec958.status[2] << 16) | 11558c2ecf20Sopenharmony_ci (ucontrol->value.iec958.status[3] << 24); 11568c2ecf20Sopenharmony_ci spin_lock_irqsave(&emu->reg_lock, flags); 11578c2ecf20Sopenharmony_ci change = val != emu->spdif_bits[idx]; 11588c2ecf20Sopenharmony_ci if (change) { 11598c2ecf20Sopenharmony_ci snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val); 11608c2ecf20Sopenharmony_ci emu->spdif_bits[idx] = val; 11618c2ecf20Sopenharmony_ci } 11628c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&emu->reg_lock, flags); 11638c2ecf20Sopenharmony_ci return change; 11648c2ecf20Sopenharmony_ci} 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu10k1_spdif_mask_control = 11678c2ecf20Sopenharmony_ci{ 11688c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, 11698c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 11708c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), 11718c2ecf20Sopenharmony_ci .count = 3, 11728c2ecf20Sopenharmony_ci .info = snd_emu10k1_spdif_info, 11738c2ecf20Sopenharmony_ci .get = snd_emu10k1_spdif_get_mask 11748c2ecf20Sopenharmony_ci}; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu10k1_spdif_control = 11778c2ecf20Sopenharmony_ci{ 11788c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 11798c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), 11808c2ecf20Sopenharmony_ci .count = 3, 11818c2ecf20Sopenharmony_ci .info = snd_emu10k1_spdif_info, 11828c2ecf20Sopenharmony_ci .get = snd_emu10k1_spdif_get, 11838c2ecf20Sopenharmony_ci .put = snd_emu10k1_spdif_put 11848c2ecf20Sopenharmony_ci}; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_cistatic void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route) 11888c2ecf20Sopenharmony_ci{ 11898c2ecf20Sopenharmony_ci if (emu->audigy) { 11908c2ecf20Sopenharmony_ci snd_emu10k1_ptr_write(emu, A_FXRT1, voice, 11918c2ecf20Sopenharmony_ci snd_emu10k1_compose_audigy_fxrt1(route)); 11928c2ecf20Sopenharmony_ci snd_emu10k1_ptr_write(emu, A_FXRT2, voice, 11938c2ecf20Sopenharmony_ci snd_emu10k1_compose_audigy_fxrt2(route)); 11948c2ecf20Sopenharmony_ci } else { 11958c2ecf20Sopenharmony_ci snd_emu10k1_ptr_write(emu, FXRT, voice, 11968c2ecf20Sopenharmony_ci snd_emu10k1_compose_send_routing(route)); 11978c2ecf20Sopenharmony_ci } 11988c2ecf20Sopenharmony_ci} 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_cistatic void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsigned char *volume) 12018c2ecf20Sopenharmony_ci{ 12028c2ecf20Sopenharmony_ci snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]); 12038c2ecf20Sopenharmony_ci snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]); 12048c2ecf20Sopenharmony_ci snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]); 12058c2ecf20Sopenharmony_ci snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]); 12068c2ecf20Sopenharmony_ci if (emu->audigy) { 12078c2ecf20Sopenharmony_ci unsigned int val = ((unsigned int)volume[4] << 24) | 12088c2ecf20Sopenharmony_ci ((unsigned int)volume[5] << 16) | 12098c2ecf20Sopenharmony_ci ((unsigned int)volume[6] << 8) | 12108c2ecf20Sopenharmony_ci (unsigned int)volume[7]; 12118c2ecf20Sopenharmony_ci snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, val); 12128c2ecf20Sopenharmony_ci } 12138c2ecf20Sopenharmony_ci} 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci/* PCM stream controls */ 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_cistatic int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 12188c2ecf20Sopenharmony_ci{ 12198c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 12208c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 12218c2ecf20Sopenharmony_ci uinfo->count = emu->audigy ? 3*8 : 3*4; 12228c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 12238c2ecf20Sopenharmony_ci uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f; 12248c2ecf20Sopenharmony_ci return 0; 12258c2ecf20Sopenharmony_ci} 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_cistatic int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol, 12288c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 12298c2ecf20Sopenharmony_ci{ 12308c2ecf20Sopenharmony_ci unsigned long flags; 12318c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 12328c2ecf20Sopenharmony_ci struct snd_emu10k1_pcm_mixer *mix = 12338c2ecf20Sopenharmony_ci &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 12348c2ecf20Sopenharmony_ci int voice, idx; 12358c2ecf20Sopenharmony_ci int num_efx = emu->audigy ? 8 : 4; 12368c2ecf20Sopenharmony_ci int mask = emu->audigy ? 0x3f : 0x0f; 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci spin_lock_irqsave(&emu->reg_lock, flags); 12398c2ecf20Sopenharmony_ci for (voice = 0; voice < 3; voice++) 12408c2ecf20Sopenharmony_ci for (idx = 0; idx < num_efx; idx++) 12418c2ecf20Sopenharmony_ci ucontrol->value.integer.value[(voice * num_efx) + idx] = 12428c2ecf20Sopenharmony_ci mix->send_routing[voice][idx] & mask; 12438c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&emu->reg_lock, flags); 12448c2ecf20Sopenharmony_ci return 0; 12458c2ecf20Sopenharmony_ci} 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_cistatic int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol, 12488c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 12498c2ecf20Sopenharmony_ci{ 12508c2ecf20Sopenharmony_ci unsigned long flags; 12518c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 12528c2ecf20Sopenharmony_ci struct snd_emu10k1_pcm_mixer *mix = 12538c2ecf20Sopenharmony_ci &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 12548c2ecf20Sopenharmony_ci int change = 0, voice, idx, val; 12558c2ecf20Sopenharmony_ci int num_efx = emu->audigy ? 8 : 4; 12568c2ecf20Sopenharmony_ci int mask = emu->audigy ? 0x3f : 0x0f; 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci spin_lock_irqsave(&emu->reg_lock, flags); 12598c2ecf20Sopenharmony_ci for (voice = 0; voice < 3; voice++) 12608c2ecf20Sopenharmony_ci for (idx = 0; idx < num_efx; idx++) { 12618c2ecf20Sopenharmony_ci val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask; 12628c2ecf20Sopenharmony_ci if (mix->send_routing[voice][idx] != val) { 12638c2ecf20Sopenharmony_ci mix->send_routing[voice][idx] = val; 12648c2ecf20Sopenharmony_ci change = 1; 12658c2ecf20Sopenharmony_ci } 12668c2ecf20Sopenharmony_ci } 12678c2ecf20Sopenharmony_ci if (change && mix->epcm) { 12688c2ecf20Sopenharmony_ci if (mix->epcm->voices[0] && mix->epcm->voices[1]) { 12698c2ecf20Sopenharmony_ci update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number, 12708c2ecf20Sopenharmony_ci &mix->send_routing[1][0]); 12718c2ecf20Sopenharmony_ci update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number, 12728c2ecf20Sopenharmony_ci &mix->send_routing[2][0]); 12738c2ecf20Sopenharmony_ci } else if (mix->epcm->voices[0]) { 12748c2ecf20Sopenharmony_ci update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number, 12758c2ecf20Sopenharmony_ci &mix->send_routing[0][0]); 12768c2ecf20Sopenharmony_ci } 12778c2ecf20Sopenharmony_ci } 12788c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&emu->reg_lock, flags); 12798c2ecf20Sopenharmony_ci return change; 12808c2ecf20Sopenharmony_ci} 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu10k1_send_routing_control = 12838c2ecf20Sopenharmony_ci{ 12848c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 12858c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 12868c2ecf20Sopenharmony_ci .name = "EMU10K1 PCM Send Routing", 12878c2ecf20Sopenharmony_ci .count = 32, 12888c2ecf20Sopenharmony_ci .info = snd_emu10k1_send_routing_info, 12898c2ecf20Sopenharmony_ci .get = snd_emu10k1_send_routing_get, 12908c2ecf20Sopenharmony_ci .put = snd_emu10k1_send_routing_put 12918c2ecf20Sopenharmony_ci}; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_cistatic int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 12948c2ecf20Sopenharmony_ci{ 12958c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 12968c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 12978c2ecf20Sopenharmony_ci uinfo->count = emu->audigy ? 3*8 : 3*4; 12988c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 12998c2ecf20Sopenharmony_ci uinfo->value.integer.max = 255; 13008c2ecf20Sopenharmony_ci return 0; 13018c2ecf20Sopenharmony_ci} 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_cistatic int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol, 13048c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 13058c2ecf20Sopenharmony_ci{ 13068c2ecf20Sopenharmony_ci unsigned long flags; 13078c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 13088c2ecf20Sopenharmony_ci struct snd_emu10k1_pcm_mixer *mix = 13098c2ecf20Sopenharmony_ci &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 13108c2ecf20Sopenharmony_ci int idx; 13118c2ecf20Sopenharmony_ci int num_efx = emu->audigy ? 8 : 4; 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci spin_lock_irqsave(&emu->reg_lock, flags); 13148c2ecf20Sopenharmony_ci for (idx = 0; idx < 3*num_efx; idx++) 13158c2ecf20Sopenharmony_ci ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx]; 13168c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&emu->reg_lock, flags); 13178c2ecf20Sopenharmony_ci return 0; 13188c2ecf20Sopenharmony_ci} 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_cistatic int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol, 13218c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 13228c2ecf20Sopenharmony_ci{ 13238c2ecf20Sopenharmony_ci unsigned long flags; 13248c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 13258c2ecf20Sopenharmony_ci struct snd_emu10k1_pcm_mixer *mix = 13268c2ecf20Sopenharmony_ci &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 13278c2ecf20Sopenharmony_ci int change = 0, idx, val; 13288c2ecf20Sopenharmony_ci int num_efx = emu->audigy ? 8 : 4; 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci spin_lock_irqsave(&emu->reg_lock, flags); 13318c2ecf20Sopenharmony_ci for (idx = 0; idx < 3*num_efx; idx++) { 13328c2ecf20Sopenharmony_ci val = ucontrol->value.integer.value[idx] & 255; 13338c2ecf20Sopenharmony_ci if (mix->send_volume[idx/num_efx][idx%num_efx] != val) { 13348c2ecf20Sopenharmony_ci mix->send_volume[idx/num_efx][idx%num_efx] = val; 13358c2ecf20Sopenharmony_ci change = 1; 13368c2ecf20Sopenharmony_ci } 13378c2ecf20Sopenharmony_ci } 13388c2ecf20Sopenharmony_ci if (change && mix->epcm) { 13398c2ecf20Sopenharmony_ci if (mix->epcm->voices[0] && mix->epcm->voices[1]) { 13408c2ecf20Sopenharmony_ci update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number, 13418c2ecf20Sopenharmony_ci &mix->send_volume[1][0]); 13428c2ecf20Sopenharmony_ci update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number, 13438c2ecf20Sopenharmony_ci &mix->send_volume[2][0]); 13448c2ecf20Sopenharmony_ci } else if (mix->epcm->voices[0]) { 13458c2ecf20Sopenharmony_ci update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number, 13468c2ecf20Sopenharmony_ci &mix->send_volume[0][0]); 13478c2ecf20Sopenharmony_ci } 13488c2ecf20Sopenharmony_ci } 13498c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&emu->reg_lock, flags); 13508c2ecf20Sopenharmony_ci return change; 13518c2ecf20Sopenharmony_ci} 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu10k1_send_volume_control = 13548c2ecf20Sopenharmony_ci{ 13558c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 13568c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 13578c2ecf20Sopenharmony_ci .name = "EMU10K1 PCM Send Volume", 13588c2ecf20Sopenharmony_ci .count = 32, 13598c2ecf20Sopenharmony_ci .info = snd_emu10k1_send_volume_info, 13608c2ecf20Sopenharmony_ci .get = snd_emu10k1_send_volume_get, 13618c2ecf20Sopenharmony_ci .put = snd_emu10k1_send_volume_put 13628c2ecf20Sopenharmony_ci}; 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_cistatic int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 13658c2ecf20Sopenharmony_ci{ 13668c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 13678c2ecf20Sopenharmony_ci uinfo->count = 3; 13688c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 13698c2ecf20Sopenharmony_ci uinfo->value.integer.max = 0xffff; 13708c2ecf20Sopenharmony_ci return 0; 13718c2ecf20Sopenharmony_ci} 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_cistatic int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol, 13748c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 13758c2ecf20Sopenharmony_ci{ 13768c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 13778c2ecf20Sopenharmony_ci struct snd_emu10k1_pcm_mixer *mix = 13788c2ecf20Sopenharmony_ci &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 13798c2ecf20Sopenharmony_ci unsigned long flags; 13808c2ecf20Sopenharmony_ci int idx; 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci spin_lock_irqsave(&emu->reg_lock, flags); 13838c2ecf20Sopenharmony_ci for (idx = 0; idx < 3; idx++) 13848c2ecf20Sopenharmony_ci ucontrol->value.integer.value[idx] = mix->attn[idx]; 13858c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&emu->reg_lock, flags); 13868c2ecf20Sopenharmony_ci return 0; 13878c2ecf20Sopenharmony_ci} 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_cistatic int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol, 13908c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 13918c2ecf20Sopenharmony_ci{ 13928c2ecf20Sopenharmony_ci unsigned long flags; 13938c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 13948c2ecf20Sopenharmony_ci struct snd_emu10k1_pcm_mixer *mix = 13958c2ecf20Sopenharmony_ci &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 13968c2ecf20Sopenharmony_ci int change = 0, idx, val; 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci spin_lock_irqsave(&emu->reg_lock, flags); 13998c2ecf20Sopenharmony_ci for (idx = 0; idx < 3; idx++) { 14008c2ecf20Sopenharmony_ci val = ucontrol->value.integer.value[idx] & 0xffff; 14018c2ecf20Sopenharmony_ci if (mix->attn[idx] != val) { 14028c2ecf20Sopenharmony_ci mix->attn[idx] = val; 14038c2ecf20Sopenharmony_ci change = 1; 14048c2ecf20Sopenharmony_ci } 14058c2ecf20Sopenharmony_ci } 14068c2ecf20Sopenharmony_ci if (change && mix->epcm) { 14078c2ecf20Sopenharmony_ci if (mix->epcm->voices[0] && mix->epcm->voices[1]) { 14088c2ecf20Sopenharmony_ci snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]); 14098c2ecf20Sopenharmony_ci snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]); 14108c2ecf20Sopenharmony_ci } else if (mix->epcm->voices[0]) { 14118c2ecf20Sopenharmony_ci snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]); 14128c2ecf20Sopenharmony_ci } 14138c2ecf20Sopenharmony_ci } 14148c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&emu->reg_lock, flags); 14158c2ecf20Sopenharmony_ci return change; 14168c2ecf20Sopenharmony_ci} 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu10k1_attn_control = 14198c2ecf20Sopenharmony_ci{ 14208c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 14218c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 14228c2ecf20Sopenharmony_ci .name = "EMU10K1 PCM Volume", 14238c2ecf20Sopenharmony_ci .count = 32, 14248c2ecf20Sopenharmony_ci .info = snd_emu10k1_attn_info, 14258c2ecf20Sopenharmony_ci .get = snd_emu10k1_attn_get, 14268c2ecf20Sopenharmony_ci .put = snd_emu10k1_attn_put 14278c2ecf20Sopenharmony_ci}; 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci/* Mutichannel PCM stream controls */ 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_cistatic int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 14328c2ecf20Sopenharmony_ci{ 14338c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 14348c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 14358c2ecf20Sopenharmony_ci uinfo->count = emu->audigy ? 8 : 4; 14368c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 14378c2ecf20Sopenharmony_ci uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f; 14388c2ecf20Sopenharmony_ci return 0; 14398c2ecf20Sopenharmony_ci} 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_cistatic int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol, 14428c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 14438c2ecf20Sopenharmony_ci{ 14448c2ecf20Sopenharmony_ci unsigned long flags; 14458c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 14468c2ecf20Sopenharmony_ci struct snd_emu10k1_pcm_mixer *mix = 14478c2ecf20Sopenharmony_ci &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 14488c2ecf20Sopenharmony_ci int idx; 14498c2ecf20Sopenharmony_ci int num_efx = emu->audigy ? 8 : 4; 14508c2ecf20Sopenharmony_ci int mask = emu->audigy ? 0x3f : 0x0f; 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci spin_lock_irqsave(&emu->reg_lock, flags); 14538c2ecf20Sopenharmony_ci for (idx = 0; idx < num_efx; idx++) 14548c2ecf20Sopenharmony_ci ucontrol->value.integer.value[idx] = 14558c2ecf20Sopenharmony_ci mix->send_routing[0][idx] & mask; 14568c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&emu->reg_lock, flags); 14578c2ecf20Sopenharmony_ci return 0; 14588c2ecf20Sopenharmony_ci} 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_cistatic int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol, 14618c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 14628c2ecf20Sopenharmony_ci{ 14638c2ecf20Sopenharmony_ci unsigned long flags; 14648c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 14658c2ecf20Sopenharmony_ci int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 14668c2ecf20Sopenharmony_ci struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; 14678c2ecf20Sopenharmony_ci int change = 0, idx, val; 14688c2ecf20Sopenharmony_ci int num_efx = emu->audigy ? 8 : 4; 14698c2ecf20Sopenharmony_ci int mask = emu->audigy ? 0x3f : 0x0f; 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci spin_lock_irqsave(&emu->reg_lock, flags); 14728c2ecf20Sopenharmony_ci for (idx = 0; idx < num_efx; idx++) { 14738c2ecf20Sopenharmony_ci val = ucontrol->value.integer.value[idx] & mask; 14748c2ecf20Sopenharmony_ci if (mix->send_routing[0][idx] != val) { 14758c2ecf20Sopenharmony_ci mix->send_routing[0][idx] = val; 14768c2ecf20Sopenharmony_ci change = 1; 14778c2ecf20Sopenharmony_ci } 14788c2ecf20Sopenharmony_ci } 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci if (change && mix->epcm) { 14818c2ecf20Sopenharmony_ci if (mix->epcm->voices[ch]) { 14828c2ecf20Sopenharmony_ci update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number, 14838c2ecf20Sopenharmony_ci &mix->send_routing[0][0]); 14848c2ecf20Sopenharmony_ci } 14858c2ecf20Sopenharmony_ci } 14868c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&emu->reg_lock, flags); 14878c2ecf20Sopenharmony_ci return change; 14888c2ecf20Sopenharmony_ci} 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control = 14918c2ecf20Sopenharmony_ci{ 14928c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 14938c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 14948c2ecf20Sopenharmony_ci .name = "Multichannel PCM Send Routing", 14958c2ecf20Sopenharmony_ci .count = 16, 14968c2ecf20Sopenharmony_ci .info = snd_emu10k1_efx_send_routing_info, 14978c2ecf20Sopenharmony_ci .get = snd_emu10k1_efx_send_routing_get, 14988c2ecf20Sopenharmony_ci .put = snd_emu10k1_efx_send_routing_put 14998c2ecf20Sopenharmony_ci}; 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_cistatic int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 15028c2ecf20Sopenharmony_ci{ 15038c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 15048c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 15058c2ecf20Sopenharmony_ci uinfo->count = emu->audigy ? 8 : 4; 15068c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 15078c2ecf20Sopenharmony_ci uinfo->value.integer.max = 255; 15088c2ecf20Sopenharmony_ci return 0; 15098c2ecf20Sopenharmony_ci} 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_cistatic int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol, 15128c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 15138c2ecf20Sopenharmony_ci{ 15148c2ecf20Sopenharmony_ci unsigned long flags; 15158c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 15168c2ecf20Sopenharmony_ci struct snd_emu10k1_pcm_mixer *mix = 15178c2ecf20Sopenharmony_ci &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 15188c2ecf20Sopenharmony_ci int idx; 15198c2ecf20Sopenharmony_ci int num_efx = emu->audigy ? 8 : 4; 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci spin_lock_irqsave(&emu->reg_lock, flags); 15228c2ecf20Sopenharmony_ci for (idx = 0; idx < num_efx; idx++) 15238c2ecf20Sopenharmony_ci ucontrol->value.integer.value[idx] = mix->send_volume[0][idx]; 15248c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&emu->reg_lock, flags); 15258c2ecf20Sopenharmony_ci return 0; 15268c2ecf20Sopenharmony_ci} 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_cistatic int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol, 15298c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 15308c2ecf20Sopenharmony_ci{ 15318c2ecf20Sopenharmony_ci unsigned long flags; 15328c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 15338c2ecf20Sopenharmony_ci int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 15348c2ecf20Sopenharmony_ci struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; 15358c2ecf20Sopenharmony_ci int change = 0, idx, val; 15368c2ecf20Sopenharmony_ci int num_efx = emu->audigy ? 8 : 4; 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci spin_lock_irqsave(&emu->reg_lock, flags); 15398c2ecf20Sopenharmony_ci for (idx = 0; idx < num_efx; idx++) { 15408c2ecf20Sopenharmony_ci val = ucontrol->value.integer.value[idx] & 255; 15418c2ecf20Sopenharmony_ci if (mix->send_volume[0][idx] != val) { 15428c2ecf20Sopenharmony_ci mix->send_volume[0][idx] = val; 15438c2ecf20Sopenharmony_ci change = 1; 15448c2ecf20Sopenharmony_ci } 15458c2ecf20Sopenharmony_ci } 15468c2ecf20Sopenharmony_ci if (change && mix->epcm) { 15478c2ecf20Sopenharmony_ci if (mix->epcm->voices[ch]) { 15488c2ecf20Sopenharmony_ci update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number, 15498c2ecf20Sopenharmony_ci &mix->send_volume[0][0]); 15508c2ecf20Sopenharmony_ci } 15518c2ecf20Sopenharmony_ci } 15528c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&emu->reg_lock, flags); 15538c2ecf20Sopenharmony_ci return change; 15548c2ecf20Sopenharmony_ci} 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control = 15588c2ecf20Sopenharmony_ci{ 15598c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 15608c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 15618c2ecf20Sopenharmony_ci .name = "Multichannel PCM Send Volume", 15628c2ecf20Sopenharmony_ci .count = 16, 15638c2ecf20Sopenharmony_ci .info = snd_emu10k1_efx_send_volume_info, 15648c2ecf20Sopenharmony_ci .get = snd_emu10k1_efx_send_volume_get, 15658c2ecf20Sopenharmony_ci .put = snd_emu10k1_efx_send_volume_put 15668c2ecf20Sopenharmony_ci}; 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_cistatic int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 15698c2ecf20Sopenharmony_ci{ 15708c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 15718c2ecf20Sopenharmony_ci uinfo->count = 1; 15728c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 15738c2ecf20Sopenharmony_ci uinfo->value.integer.max = 0xffff; 15748c2ecf20Sopenharmony_ci return 0; 15758c2ecf20Sopenharmony_ci} 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_cistatic int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol, 15788c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 15798c2ecf20Sopenharmony_ci{ 15808c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 15818c2ecf20Sopenharmony_ci struct snd_emu10k1_pcm_mixer *mix = 15828c2ecf20Sopenharmony_ci &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; 15838c2ecf20Sopenharmony_ci unsigned long flags; 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci spin_lock_irqsave(&emu->reg_lock, flags); 15868c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = mix->attn[0]; 15878c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&emu->reg_lock, flags); 15888c2ecf20Sopenharmony_ci return 0; 15898c2ecf20Sopenharmony_ci} 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_cistatic int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol, 15928c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 15938c2ecf20Sopenharmony_ci{ 15948c2ecf20Sopenharmony_ci unsigned long flags; 15958c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 15968c2ecf20Sopenharmony_ci int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 15978c2ecf20Sopenharmony_ci struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch]; 15988c2ecf20Sopenharmony_ci int change = 0, val; 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci spin_lock_irqsave(&emu->reg_lock, flags); 16018c2ecf20Sopenharmony_ci val = ucontrol->value.integer.value[0] & 0xffff; 16028c2ecf20Sopenharmony_ci if (mix->attn[0] != val) { 16038c2ecf20Sopenharmony_ci mix->attn[0] = val; 16048c2ecf20Sopenharmony_ci change = 1; 16058c2ecf20Sopenharmony_ci } 16068c2ecf20Sopenharmony_ci if (change && mix->epcm) { 16078c2ecf20Sopenharmony_ci if (mix->epcm->voices[ch]) { 16088c2ecf20Sopenharmony_ci snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]); 16098c2ecf20Sopenharmony_ci } 16108c2ecf20Sopenharmony_ci } 16118c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&emu->reg_lock, flags); 16128c2ecf20Sopenharmony_ci return change; 16138c2ecf20Sopenharmony_ci} 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu10k1_efx_attn_control = 16168c2ecf20Sopenharmony_ci{ 16178c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 16188c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 16198c2ecf20Sopenharmony_ci .name = "Multichannel PCM Volume", 16208c2ecf20Sopenharmony_ci .count = 16, 16218c2ecf20Sopenharmony_ci .info = snd_emu10k1_efx_attn_info, 16228c2ecf20Sopenharmony_ci .get = snd_emu10k1_efx_attn_get, 16238c2ecf20Sopenharmony_ci .put = snd_emu10k1_efx_attn_put 16248c2ecf20Sopenharmony_ci}; 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci#define snd_emu10k1_shared_spdif_info snd_ctl_boolean_mono_info 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_cistatic int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol, 16298c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 16308c2ecf20Sopenharmony_ci{ 16318c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci if (emu->audigy) 16348c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = inl(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0; 16358c2ecf20Sopenharmony_ci else 16368c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0; 16378c2ecf20Sopenharmony_ci if (emu->card_capabilities->invert_shared_spdif) 16388c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = 16398c2ecf20Sopenharmony_ci !ucontrol->value.integer.value[0]; 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci return 0; 16428c2ecf20Sopenharmony_ci} 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_cistatic int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, 16458c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 16468c2ecf20Sopenharmony_ci{ 16478c2ecf20Sopenharmony_ci unsigned long flags; 16488c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 16498c2ecf20Sopenharmony_ci unsigned int reg, val, sw; 16508c2ecf20Sopenharmony_ci int change = 0; 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci sw = ucontrol->value.integer.value[0]; 16538c2ecf20Sopenharmony_ci if (emu->card_capabilities->invert_shared_spdif) 16548c2ecf20Sopenharmony_ci sw = !sw; 16558c2ecf20Sopenharmony_ci spin_lock_irqsave(&emu->reg_lock, flags); 16568c2ecf20Sopenharmony_ci if ( emu->card_capabilities->i2c_adc) { 16578c2ecf20Sopenharmony_ci /* Do nothing for Audigy 2 ZS Notebook */ 16588c2ecf20Sopenharmony_ci } else if (emu->audigy) { 16598c2ecf20Sopenharmony_ci reg = inl(emu->port + A_IOCFG); 16608c2ecf20Sopenharmony_ci val = sw ? A_IOCFG_GPOUT0 : 0; 16618c2ecf20Sopenharmony_ci change = (reg & A_IOCFG_GPOUT0) != val; 16628c2ecf20Sopenharmony_ci if (change) { 16638c2ecf20Sopenharmony_ci reg &= ~A_IOCFG_GPOUT0; 16648c2ecf20Sopenharmony_ci reg |= val; 16658c2ecf20Sopenharmony_ci outl(reg | val, emu->port + A_IOCFG); 16668c2ecf20Sopenharmony_ci } 16678c2ecf20Sopenharmony_ci } 16688c2ecf20Sopenharmony_ci reg = inl(emu->port + HCFG); 16698c2ecf20Sopenharmony_ci val = sw ? HCFG_GPOUT0 : 0; 16708c2ecf20Sopenharmony_ci change |= (reg & HCFG_GPOUT0) != val; 16718c2ecf20Sopenharmony_ci if (change) { 16728c2ecf20Sopenharmony_ci reg &= ~HCFG_GPOUT0; 16738c2ecf20Sopenharmony_ci reg |= val; 16748c2ecf20Sopenharmony_ci outl(reg | val, emu->port + HCFG); 16758c2ecf20Sopenharmony_ci } 16768c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&emu->reg_lock, flags); 16778c2ecf20Sopenharmony_ci return change; 16788c2ecf20Sopenharmony_ci} 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_emu10k1_shared_spdif = 16818c2ecf20Sopenharmony_ci{ 16828c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 16838c2ecf20Sopenharmony_ci .name = "SB Live Analog/Digital Output Jack", 16848c2ecf20Sopenharmony_ci .info = snd_emu10k1_shared_spdif_info, 16858c2ecf20Sopenharmony_ci .get = snd_emu10k1_shared_spdif_get, 16868c2ecf20Sopenharmony_ci .put = snd_emu10k1_shared_spdif_put 16878c2ecf20Sopenharmony_ci}; 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_audigy_shared_spdif = 16908c2ecf20Sopenharmony_ci{ 16918c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 16928c2ecf20Sopenharmony_ci .name = "Audigy Analog/Digital Output Jack", 16938c2ecf20Sopenharmony_ci .info = snd_emu10k1_shared_spdif_info, 16948c2ecf20Sopenharmony_ci .get = snd_emu10k1_shared_spdif_get, 16958c2ecf20Sopenharmony_ci .put = snd_emu10k1_shared_spdif_put 16968c2ecf20Sopenharmony_ci}; 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci/* workaround for too low volume on Audigy due to 16bit/24bit conversion */ 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci#define snd_audigy_capture_boost_info snd_ctl_boolean_mono_info 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_cistatic int snd_audigy_capture_boost_get(struct snd_kcontrol *kcontrol, 17038c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 17048c2ecf20Sopenharmony_ci{ 17058c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 17068c2ecf20Sopenharmony_ci unsigned int val; 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci /* FIXME: better to use a cached version */ 17098c2ecf20Sopenharmony_ci val = snd_ac97_read(emu->ac97, AC97_REC_GAIN); 17108c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = !!val; 17118c2ecf20Sopenharmony_ci return 0; 17128c2ecf20Sopenharmony_ci} 17138c2ecf20Sopenharmony_ci 17148c2ecf20Sopenharmony_cistatic int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol, 17158c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 17168c2ecf20Sopenharmony_ci{ 17178c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); 17188c2ecf20Sopenharmony_ci unsigned int val; 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci if (ucontrol->value.integer.value[0]) 17218c2ecf20Sopenharmony_ci val = 0x0f0f; 17228c2ecf20Sopenharmony_ci else 17238c2ecf20Sopenharmony_ci val = 0; 17248c2ecf20Sopenharmony_ci return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val); 17258c2ecf20Sopenharmony_ci} 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_audigy_capture_boost = 17288c2ecf20Sopenharmony_ci{ 17298c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 17308c2ecf20Sopenharmony_ci .name = "Mic Extra Boost", 17318c2ecf20Sopenharmony_ci .info = snd_audigy_capture_boost_info, 17328c2ecf20Sopenharmony_ci .get = snd_audigy_capture_boost_get, 17338c2ecf20Sopenharmony_ci .put = snd_audigy_capture_boost_put 17348c2ecf20Sopenharmony_ci}; 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci/* 17388c2ecf20Sopenharmony_ci */ 17398c2ecf20Sopenharmony_cistatic void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97) 17408c2ecf20Sopenharmony_ci{ 17418c2ecf20Sopenharmony_ci struct snd_emu10k1 *emu = ac97->private_data; 17428c2ecf20Sopenharmony_ci emu->ac97 = NULL; 17438c2ecf20Sopenharmony_ci} 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci/* 17468c2ecf20Sopenharmony_ci */ 17478c2ecf20Sopenharmony_cistatic int remove_ctl(struct snd_card *card, const char *name) 17488c2ecf20Sopenharmony_ci{ 17498c2ecf20Sopenharmony_ci struct snd_ctl_elem_id id; 17508c2ecf20Sopenharmony_ci memset(&id, 0, sizeof(id)); 17518c2ecf20Sopenharmony_ci strcpy(id.name, name); 17528c2ecf20Sopenharmony_ci id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 17538c2ecf20Sopenharmony_ci return snd_ctl_remove_id(card, &id); 17548c2ecf20Sopenharmony_ci} 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_cistatic struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name) 17578c2ecf20Sopenharmony_ci{ 17588c2ecf20Sopenharmony_ci struct snd_ctl_elem_id sid; 17598c2ecf20Sopenharmony_ci memset(&sid, 0, sizeof(sid)); 17608c2ecf20Sopenharmony_ci strcpy(sid.name, name); 17618c2ecf20Sopenharmony_ci sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 17628c2ecf20Sopenharmony_ci return snd_ctl_find_id(card, &sid); 17638c2ecf20Sopenharmony_ci} 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_cistatic int rename_ctl(struct snd_card *card, const char *src, const char *dst) 17668c2ecf20Sopenharmony_ci{ 17678c2ecf20Sopenharmony_ci struct snd_kcontrol *kctl = ctl_find(card, src); 17688c2ecf20Sopenharmony_ci if (kctl) { 17698c2ecf20Sopenharmony_ci strcpy(kctl->id.name, dst); 17708c2ecf20Sopenharmony_ci return 0; 17718c2ecf20Sopenharmony_ci } 17728c2ecf20Sopenharmony_ci return -ENOENT; 17738c2ecf20Sopenharmony_ci} 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ciint snd_emu10k1_mixer(struct snd_emu10k1 *emu, 17768c2ecf20Sopenharmony_ci int pcm_device, int multi_device) 17778c2ecf20Sopenharmony_ci{ 17788c2ecf20Sopenharmony_ci int err, pcm; 17798c2ecf20Sopenharmony_ci struct snd_kcontrol *kctl; 17808c2ecf20Sopenharmony_ci struct snd_card *card = emu->card; 17818c2ecf20Sopenharmony_ci const char * const *c; 17828c2ecf20Sopenharmony_ci static const char * const emu10k1_remove_ctls[] = { 17838c2ecf20Sopenharmony_ci /* no AC97 mono, surround, center/lfe */ 17848c2ecf20Sopenharmony_ci "Master Mono Playback Switch", 17858c2ecf20Sopenharmony_ci "Master Mono Playback Volume", 17868c2ecf20Sopenharmony_ci "PCM Out Path & Mute", 17878c2ecf20Sopenharmony_ci "Mono Output Select", 17888c2ecf20Sopenharmony_ci "Surround Playback Switch", 17898c2ecf20Sopenharmony_ci "Surround Playback Volume", 17908c2ecf20Sopenharmony_ci "Center Playback Switch", 17918c2ecf20Sopenharmony_ci "Center Playback Volume", 17928c2ecf20Sopenharmony_ci "LFE Playback Switch", 17938c2ecf20Sopenharmony_ci "LFE Playback Volume", 17948c2ecf20Sopenharmony_ci NULL 17958c2ecf20Sopenharmony_ci }; 17968c2ecf20Sopenharmony_ci static const char * const emu10k1_rename_ctls[] = { 17978c2ecf20Sopenharmony_ci "Surround Digital Playback Volume", "Surround Playback Volume", 17988c2ecf20Sopenharmony_ci "Center Digital Playback Volume", "Center Playback Volume", 17998c2ecf20Sopenharmony_ci "LFE Digital Playback Volume", "LFE Playback Volume", 18008c2ecf20Sopenharmony_ci NULL 18018c2ecf20Sopenharmony_ci }; 18028c2ecf20Sopenharmony_ci static const char * const audigy_remove_ctls[] = { 18038c2ecf20Sopenharmony_ci /* Master/PCM controls on ac97 of Audigy has no effect */ 18048c2ecf20Sopenharmony_ci /* On the Audigy2 the AC97 playback is piped into 18058c2ecf20Sopenharmony_ci * the Philips ADC for 24bit capture */ 18068c2ecf20Sopenharmony_ci "PCM Playback Switch", 18078c2ecf20Sopenharmony_ci "PCM Playback Volume", 18088c2ecf20Sopenharmony_ci "Master Playback Switch", 18098c2ecf20Sopenharmony_ci "Master Playback Volume", 18108c2ecf20Sopenharmony_ci "PCM Out Path & Mute", 18118c2ecf20Sopenharmony_ci "Mono Output Select", 18128c2ecf20Sopenharmony_ci /* remove unused AC97 capture controls */ 18138c2ecf20Sopenharmony_ci "Capture Source", 18148c2ecf20Sopenharmony_ci "Capture Switch", 18158c2ecf20Sopenharmony_ci "Capture Volume", 18168c2ecf20Sopenharmony_ci "Mic Select", 18178c2ecf20Sopenharmony_ci "Headphone Playback Switch", 18188c2ecf20Sopenharmony_ci "Headphone Playback Volume", 18198c2ecf20Sopenharmony_ci "3D Control - Center", 18208c2ecf20Sopenharmony_ci "3D Control - Depth", 18218c2ecf20Sopenharmony_ci "3D Control - Switch", 18228c2ecf20Sopenharmony_ci "Video Playback Switch", 18238c2ecf20Sopenharmony_ci "Video Playback Volume", 18248c2ecf20Sopenharmony_ci "Mic Playback Switch", 18258c2ecf20Sopenharmony_ci "Mic Playback Volume", 18268c2ecf20Sopenharmony_ci "External Amplifier", 18278c2ecf20Sopenharmony_ci NULL 18288c2ecf20Sopenharmony_ci }; 18298c2ecf20Sopenharmony_ci static const char * const audigy_rename_ctls[] = { 18308c2ecf20Sopenharmony_ci /* use conventional names */ 18318c2ecf20Sopenharmony_ci "Wave Playback Volume", "PCM Playback Volume", 18328c2ecf20Sopenharmony_ci /* "Wave Capture Volume", "PCM Capture Volume", */ 18338c2ecf20Sopenharmony_ci "Wave Master Playback Volume", "Master Playback Volume", 18348c2ecf20Sopenharmony_ci "AMic Playback Volume", "Mic Playback Volume", 18358c2ecf20Sopenharmony_ci "Master Mono Playback Switch", "Phone Output Playback Switch", 18368c2ecf20Sopenharmony_ci "Master Mono Playback Volume", "Phone Output Playback Volume", 18378c2ecf20Sopenharmony_ci NULL 18388c2ecf20Sopenharmony_ci }; 18398c2ecf20Sopenharmony_ci static const char * const audigy_rename_ctls_i2c_adc[] = { 18408c2ecf20Sopenharmony_ci //"Analog Mix Capture Volume","OLD Analog Mix Capture Volume", 18418c2ecf20Sopenharmony_ci "Line Capture Volume", "Analog Mix Capture Volume", 18428c2ecf20Sopenharmony_ci "Wave Playback Volume", "OLD PCM Playback Volume", 18438c2ecf20Sopenharmony_ci "Wave Master Playback Volume", "Master Playback Volume", 18448c2ecf20Sopenharmony_ci "AMic Playback Volume", "Old Mic Playback Volume", 18458c2ecf20Sopenharmony_ci "CD Capture Volume", "IEC958 Optical Capture Volume", 18468c2ecf20Sopenharmony_ci NULL 18478c2ecf20Sopenharmony_ci }; 18488c2ecf20Sopenharmony_ci static const char * const audigy_remove_ctls_i2c_adc[] = { 18498c2ecf20Sopenharmony_ci /* On the Audigy2 ZS Notebook 18508c2ecf20Sopenharmony_ci * Capture via WM8775 */ 18518c2ecf20Sopenharmony_ci "Mic Capture Volume", 18528c2ecf20Sopenharmony_ci "Analog Mix Capture Volume", 18538c2ecf20Sopenharmony_ci "Aux Capture Volume", 18548c2ecf20Sopenharmony_ci "IEC958 Optical Capture Volume", 18558c2ecf20Sopenharmony_ci NULL 18568c2ecf20Sopenharmony_ci }; 18578c2ecf20Sopenharmony_ci static const char * const audigy_remove_ctls_1361t_adc[] = { 18588c2ecf20Sopenharmony_ci /* On the Audigy2 the AC97 playback is piped into 18598c2ecf20Sopenharmony_ci * the Philips ADC for 24bit capture */ 18608c2ecf20Sopenharmony_ci "PCM Playback Switch", 18618c2ecf20Sopenharmony_ci "PCM Playback Volume", 18628c2ecf20Sopenharmony_ci "Capture Source", 18638c2ecf20Sopenharmony_ci "Capture Switch", 18648c2ecf20Sopenharmony_ci "Capture Volume", 18658c2ecf20Sopenharmony_ci "Mic Capture Volume", 18668c2ecf20Sopenharmony_ci "Headphone Playback Switch", 18678c2ecf20Sopenharmony_ci "Headphone Playback Volume", 18688c2ecf20Sopenharmony_ci "3D Control - Center", 18698c2ecf20Sopenharmony_ci "3D Control - Depth", 18708c2ecf20Sopenharmony_ci "3D Control - Switch", 18718c2ecf20Sopenharmony_ci "Line2 Playback Volume", 18728c2ecf20Sopenharmony_ci "Line2 Capture Volume", 18738c2ecf20Sopenharmony_ci NULL 18748c2ecf20Sopenharmony_ci }; 18758c2ecf20Sopenharmony_ci static const char * const audigy_rename_ctls_1361t_adc[] = { 18768c2ecf20Sopenharmony_ci "Master Playback Switch", "Master Capture Switch", 18778c2ecf20Sopenharmony_ci "Master Playback Volume", "Master Capture Volume", 18788c2ecf20Sopenharmony_ci "Wave Master Playback Volume", "Master Playback Volume", 18798c2ecf20Sopenharmony_ci "Beep Playback Switch", "Beep Capture Switch", 18808c2ecf20Sopenharmony_ci "Beep Playback Volume", "Beep Capture Volume", 18818c2ecf20Sopenharmony_ci "Phone Playback Switch", "Phone Capture Switch", 18828c2ecf20Sopenharmony_ci "Phone Playback Volume", "Phone Capture Volume", 18838c2ecf20Sopenharmony_ci "Mic Playback Switch", "Mic Capture Switch", 18848c2ecf20Sopenharmony_ci "Mic Playback Volume", "Mic Capture Volume", 18858c2ecf20Sopenharmony_ci "Line Playback Switch", "Line Capture Switch", 18868c2ecf20Sopenharmony_ci "Line Playback Volume", "Line Capture Volume", 18878c2ecf20Sopenharmony_ci "CD Playback Switch", "CD Capture Switch", 18888c2ecf20Sopenharmony_ci "CD Playback Volume", "CD Capture Volume", 18898c2ecf20Sopenharmony_ci "Aux Playback Switch", "Aux Capture Switch", 18908c2ecf20Sopenharmony_ci "Aux Playback Volume", "Aux Capture Volume", 18918c2ecf20Sopenharmony_ci "Video Playback Switch", "Video Capture Switch", 18928c2ecf20Sopenharmony_ci "Video Playback Volume", "Video Capture Volume", 18938c2ecf20Sopenharmony_ci "Master Mono Playback Switch", "Phone Output Playback Switch", 18948c2ecf20Sopenharmony_ci "Master Mono Playback Volume", "Phone Output Playback Volume", 18958c2ecf20Sopenharmony_ci NULL 18968c2ecf20Sopenharmony_ci }; 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci if (emu->card_capabilities->ac97_chip) { 18998c2ecf20Sopenharmony_ci struct snd_ac97_bus *pbus; 19008c2ecf20Sopenharmony_ci struct snd_ac97_template ac97; 19018c2ecf20Sopenharmony_ci static const struct snd_ac97_bus_ops ops = { 19028c2ecf20Sopenharmony_ci .write = snd_emu10k1_ac97_write, 19038c2ecf20Sopenharmony_ci .read = snd_emu10k1_ac97_read, 19048c2ecf20Sopenharmony_ci }; 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci if ((err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus)) < 0) 19078c2ecf20Sopenharmony_ci return err; 19088c2ecf20Sopenharmony_ci pbus->no_vra = 1; /* we don't need VRA */ 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci memset(&ac97, 0, sizeof(ac97)); 19118c2ecf20Sopenharmony_ci ac97.private_data = emu; 19128c2ecf20Sopenharmony_ci ac97.private_free = snd_emu10k1_mixer_free_ac97; 19138c2ecf20Sopenharmony_ci ac97.scaps = AC97_SCAP_NO_SPDIF; 19148c2ecf20Sopenharmony_ci if ((err = snd_ac97_mixer(pbus, &ac97, &emu->ac97)) < 0) { 19158c2ecf20Sopenharmony_ci if (emu->card_capabilities->ac97_chip == 1) 19168c2ecf20Sopenharmony_ci return err; 19178c2ecf20Sopenharmony_ci dev_info(emu->card->dev, 19188c2ecf20Sopenharmony_ci "AC97 is optional on this board\n"); 19198c2ecf20Sopenharmony_ci dev_info(emu->card->dev, 19208c2ecf20Sopenharmony_ci "Proceeding without ac97 mixers...\n"); 19218c2ecf20Sopenharmony_ci snd_device_free(emu->card, pbus); 19228c2ecf20Sopenharmony_ci goto no_ac97; /* FIXME: get rid of ugly gotos.. */ 19238c2ecf20Sopenharmony_ci } 19248c2ecf20Sopenharmony_ci if (emu->audigy) { 19258c2ecf20Sopenharmony_ci /* set master volume to 0 dB */ 19268c2ecf20Sopenharmony_ci snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000); 19278c2ecf20Sopenharmony_ci /* set capture source to mic */ 19288c2ecf20Sopenharmony_ci snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000); 19298c2ecf20Sopenharmony_ci /* set mono output (TAD) to mic */ 19308c2ecf20Sopenharmony_ci snd_ac97_update_bits(emu->ac97, AC97_GENERAL_PURPOSE, 19318c2ecf20Sopenharmony_ci 0x0200, 0x0200); 19328c2ecf20Sopenharmony_ci if (emu->card_capabilities->adc_1361t) 19338c2ecf20Sopenharmony_ci c = audigy_remove_ctls_1361t_adc; 19348c2ecf20Sopenharmony_ci else 19358c2ecf20Sopenharmony_ci c = audigy_remove_ctls; 19368c2ecf20Sopenharmony_ci } else { 19378c2ecf20Sopenharmony_ci /* 19388c2ecf20Sopenharmony_ci * Credits for cards based on STAC9758: 19398c2ecf20Sopenharmony_ci * James Courtier-Dutton <James@superbug.demon.co.uk> 19408c2ecf20Sopenharmony_ci * Voluspa <voluspa@comhem.se> 19418c2ecf20Sopenharmony_ci */ 19428c2ecf20Sopenharmony_ci if (emu->ac97->id == AC97_ID_STAC9758) { 19438c2ecf20Sopenharmony_ci emu->rear_ac97 = 1; 19448c2ecf20Sopenharmony_ci snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT); 19458c2ecf20Sopenharmony_ci snd_ac97_write_cache(emu->ac97, AC97_HEADPHONE, 0x0202); 19468c2ecf20Sopenharmony_ci remove_ctl(card,"Front Playback Volume"); 19478c2ecf20Sopenharmony_ci remove_ctl(card,"Front Playback Switch"); 19488c2ecf20Sopenharmony_ci } 19498c2ecf20Sopenharmony_ci /* remove unused AC97 controls */ 19508c2ecf20Sopenharmony_ci snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202); 19518c2ecf20Sopenharmony_ci snd_ac97_write_cache(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202); 19528c2ecf20Sopenharmony_ci c = emu10k1_remove_ctls; 19538c2ecf20Sopenharmony_ci } 19548c2ecf20Sopenharmony_ci for (; *c; c++) 19558c2ecf20Sopenharmony_ci remove_ctl(card, *c); 19568c2ecf20Sopenharmony_ci } else if (emu->card_capabilities->i2c_adc) { 19578c2ecf20Sopenharmony_ci c = audigy_remove_ctls_i2c_adc; 19588c2ecf20Sopenharmony_ci for (; *c; c++) 19598c2ecf20Sopenharmony_ci remove_ctl(card, *c); 19608c2ecf20Sopenharmony_ci } else { 19618c2ecf20Sopenharmony_ci no_ac97: 19628c2ecf20Sopenharmony_ci if (emu->card_capabilities->ecard) 19638c2ecf20Sopenharmony_ci strcpy(emu->card->mixername, "EMU APS"); 19648c2ecf20Sopenharmony_ci else if (emu->audigy) 19658c2ecf20Sopenharmony_ci strcpy(emu->card->mixername, "SB Audigy"); 19668c2ecf20Sopenharmony_ci else 19678c2ecf20Sopenharmony_ci strcpy(emu->card->mixername, "Emu10k1"); 19688c2ecf20Sopenharmony_ci } 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci if (emu->audigy) 19718c2ecf20Sopenharmony_ci if (emu->card_capabilities->adc_1361t) 19728c2ecf20Sopenharmony_ci c = audigy_rename_ctls_1361t_adc; 19738c2ecf20Sopenharmony_ci else if (emu->card_capabilities->i2c_adc) 19748c2ecf20Sopenharmony_ci c = audigy_rename_ctls_i2c_adc; 19758c2ecf20Sopenharmony_ci else 19768c2ecf20Sopenharmony_ci c = audigy_rename_ctls; 19778c2ecf20Sopenharmony_ci else 19788c2ecf20Sopenharmony_ci c = emu10k1_rename_ctls; 19798c2ecf20Sopenharmony_ci for (; *c; c += 2) 19808c2ecf20Sopenharmony_ci rename_ctl(card, c[0], c[1]); 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci if (emu->card_capabilities->subsystem == 0x80401102) { /* SB Live! Platinum CT4760P */ 19838c2ecf20Sopenharmony_ci remove_ctl(card, "Center Playback Volume"); 19848c2ecf20Sopenharmony_ci remove_ctl(card, "LFE Playback Volume"); 19858c2ecf20Sopenharmony_ci remove_ctl(card, "Wave Center Playback Volume"); 19868c2ecf20Sopenharmony_ci remove_ctl(card, "Wave LFE Playback Volume"); 19878c2ecf20Sopenharmony_ci } 19888c2ecf20Sopenharmony_ci if (emu->card_capabilities->subsystem == 0x20071102) { /* Audigy 4 Pro */ 19898c2ecf20Sopenharmony_ci rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume"); 19908c2ecf20Sopenharmony_ci rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume"); 19918c2ecf20Sopenharmony_ci rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume"); 19928c2ecf20Sopenharmony_ci rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume"); 19938c2ecf20Sopenharmony_ci } 19948c2ecf20Sopenharmony_ci if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL) 19958c2ecf20Sopenharmony_ci return -ENOMEM; 19968c2ecf20Sopenharmony_ci kctl->id.device = pcm_device; 19978c2ecf20Sopenharmony_ci if ((err = snd_ctl_add(card, kctl))) 19988c2ecf20Sopenharmony_ci return err; 19998c2ecf20Sopenharmony_ci if ((kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu)) == NULL) 20008c2ecf20Sopenharmony_ci return -ENOMEM; 20018c2ecf20Sopenharmony_ci kctl->id.device = pcm_device; 20028c2ecf20Sopenharmony_ci if ((err = snd_ctl_add(card, kctl))) 20038c2ecf20Sopenharmony_ci return err; 20048c2ecf20Sopenharmony_ci if ((kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu)) == NULL) 20058c2ecf20Sopenharmony_ci return -ENOMEM; 20068c2ecf20Sopenharmony_ci kctl->id.device = pcm_device; 20078c2ecf20Sopenharmony_ci if ((err = snd_ctl_add(card, kctl))) 20088c2ecf20Sopenharmony_ci return err; 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_ci if ((kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu)) == NULL) 20118c2ecf20Sopenharmony_ci return -ENOMEM; 20128c2ecf20Sopenharmony_ci kctl->id.device = multi_device; 20138c2ecf20Sopenharmony_ci if ((err = snd_ctl_add(card, kctl))) 20148c2ecf20Sopenharmony_ci return err; 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ci if ((kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu)) == NULL) 20178c2ecf20Sopenharmony_ci return -ENOMEM; 20188c2ecf20Sopenharmony_ci kctl->id.device = multi_device; 20198c2ecf20Sopenharmony_ci if ((err = snd_ctl_add(card, kctl))) 20208c2ecf20Sopenharmony_ci return err; 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci if ((kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu)) == NULL) 20238c2ecf20Sopenharmony_ci return -ENOMEM; 20248c2ecf20Sopenharmony_ci kctl->id.device = multi_device; 20258c2ecf20Sopenharmony_ci if ((err = snd_ctl_add(card, kctl))) 20268c2ecf20Sopenharmony_ci return err; 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_ci /* initialize the routing and volume table for each pcm playback stream */ 20298c2ecf20Sopenharmony_ci for (pcm = 0; pcm < 32; pcm++) { 20308c2ecf20Sopenharmony_ci struct snd_emu10k1_pcm_mixer *mix; 20318c2ecf20Sopenharmony_ci int v; 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_ci mix = &emu->pcm_mixer[pcm]; 20348c2ecf20Sopenharmony_ci mix->epcm = NULL; 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci for (v = 0; v < 4; v++) 20378c2ecf20Sopenharmony_ci mix->send_routing[0][v] = 20388c2ecf20Sopenharmony_ci mix->send_routing[1][v] = 20398c2ecf20Sopenharmony_ci mix->send_routing[2][v] = v; 20408c2ecf20Sopenharmony_ci 20418c2ecf20Sopenharmony_ci memset(&mix->send_volume, 0, sizeof(mix->send_volume)); 20428c2ecf20Sopenharmony_ci mix->send_volume[0][0] = mix->send_volume[0][1] = 20438c2ecf20Sopenharmony_ci mix->send_volume[1][0] = mix->send_volume[2][1] = 255; 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_ci mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff; 20468c2ecf20Sopenharmony_ci } 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_ci /* initialize the routing and volume table for the multichannel playback stream */ 20498c2ecf20Sopenharmony_ci for (pcm = 0; pcm < NUM_EFX_PLAYBACK; pcm++) { 20508c2ecf20Sopenharmony_ci struct snd_emu10k1_pcm_mixer *mix; 20518c2ecf20Sopenharmony_ci int v; 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_ci mix = &emu->efx_pcm_mixer[pcm]; 20548c2ecf20Sopenharmony_ci mix->epcm = NULL; 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ci mix->send_routing[0][0] = pcm; 20578c2ecf20Sopenharmony_ci mix->send_routing[0][1] = (pcm == 0) ? 1 : 0; 20588c2ecf20Sopenharmony_ci for (v = 0; v < 2; v++) 20598c2ecf20Sopenharmony_ci mix->send_routing[0][2+v] = 13+v; 20608c2ecf20Sopenharmony_ci if (emu->audigy) 20618c2ecf20Sopenharmony_ci for (v = 0; v < 4; v++) 20628c2ecf20Sopenharmony_ci mix->send_routing[0][4+v] = 60+v; 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_ci memset(&mix->send_volume, 0, sizeof(mix->send_volume)); 20658c2ecf20Sopenharmony_ci mix->send_volume[0][0] = 255; 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci mix->attn[0] = 0xffff; 20688c2ecf20Sopenharmony_ci } 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ci if (! emu->card_capabilities->ecard) { /* FIXME: APS has these controls? */ 20718c2ecf20Sopenharmony_ci /* sb live! and audigy */ 20728c2ecf20Sopenharmony_ci if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL) 20738c2ecf20Sopenharmony_ci return -ENOMEM; 20748c2ecf20Sopenharmony_ci if (!emu->audigy) 20758c2ecf20Sopenharmony_ci kctl->id.device = emu->pcm_efx->device; 20768c2ecf20Sopenharmony_ci if ((err = snd_ctl_add(card, kctl))) 20778c2ecf20Sopenharmony_ci return err; 20788c2ecf20Sopenharmony_ci if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL) 20798c2ecf20Sopenharmony_ci return -ENOMEM; 20808c2ecf20Sopenharmony_ci if (!emu->audigy) 20818c2ecf20Sopenharmony_ci kctl->id.device = emu->pcm_efx->device; 20828c2ecf20Sopenharmony_ci if ((err = snd_ctl_add(card, kctl))) 20838c2ecf20Sopenharmony_ci return err; 20848c2ecf20Sopenharmony_ci } 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci if (emu->card_capabilities->emu_model) { 20878c2ecf20Sopenharmony_ci ; /* Disable the snd_audigy_spdif_shared_spdif */ 20888c2ecf20Sopenharmony_ci } else if (emu->audigy) { 20898c2ecf20Sopenharmony_ci if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL) 20908c2ecf20Sopenharmony_ci return -ENOMEM; 20918c2ecf20Sopenharmony_ci if ((err = snd_ctl_add(card, kctl))) 20928c2ecf20Sopenharmony_ci return err; 20938c2ecf20Sopenharmony_ci#if 0 20948c2ecf20Sopenharmony_ci if ((kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu)) == NULL) 20958c2ecf20Sopenharmony_ci return -ENOMEM; 20968c2ecf20Sopenharmony_ci if ((err = snd_ctl_add(card, kctl))) 20978c2ecf20Sopenharmony_ci return err; 20988c2ecf20Sopenharmony_ci#endif 20998c2ecf20Sopenharmony_ci } else if (! emu->card_capabilities->ecard) { 21008c2ecf20Sopenharmony_ci /* sb live! */ 21018c2ecf20Sopenharmony_ci if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL) 21028c2ecf20Sopenharmony_ci return -ENOMEM; 21038c2ecf20Sopenharmony_ci if ((err = snd_ctl_add(card, kctl))) 21048c2ecf20Sopenharmony_ci return err; 21058c2ecf20Sopenharmony_ci } 21068c2ecf20Sopenharmony_ci if (emu->card_capabilities->ca0151_chip) { /* P16V */ 21078c2ecf20Sopenharmony_ci if ((err = snd_p16v_mixer(emu))) 21088c2ecf20Sopenharmony_ci return err; 21098c2ecf20Sopenharmony_ci } 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) { 21128c2ecf20Sopenharmony_ci /* 1616(m) cardbus */ 21138c2ecf20Sopenharmony_ci int i; 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(snd_emu1616_output_enum_ctls); i++) { 21168c2ecf20Sopenharmony_ci err = snd_ctl_add(card, 21178c2ecf20Sopenharmony_ci snd_ctl_new1(&snd_emu1616_output_enum_ctls[i], 21188c2ecf20Sopenharmony_ci emu)); 21198c2ecf20Sopenharmony_ci if (err < 0) 21208c2ecf20Sopenharmony_ci return err; 21218c2ecf20Sopenharmony_ci } 21228c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) { 21238c2ecf20Sopenharmony_ci err = snd_ctl_add(card, 21248c2ecf20Sopenharmony_ci snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], 21258c2ecf20Sopenharmony_ci emu)); 21268c2ecf20Sopenharmony_ci if (err < 0) 21278c2ecf20Sopenharmony_ci return err; 21288c2ecf20Sopenharmony_ci } 21298c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads) - 2; i++) { 21308c2ecf20Sopenharmony_ci err = snd_ctl_add(card, 21318c2ecf20Sopenharmony_ci snd_ctl_new1(&snd_emu1010_adc_pads[i], emu)); 21328c2ecf20Sopenharmony_ci if (err < 0) 21338c2ecf20Sopenharmony_ci return err; 21348c2ecf20Sopenharmony_ci } 21358c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads) - 2; i++) { 21368c2ecf20Sopenharmony_ci err = snd_ctl_add(card, 21378c2ecf20Sopenharmony_ci snd_ctl_new1(&snd_emu1010_dac_pads[i], emu)); 21388c2ecf20Sopenharmony_ci if (err < 0) 21398c2ecf20Sopenharmony_ci return err; 21408c2ecf20Sopenharmony_ci } 21418c2ecf20Sopenharmony_ci err = snd_ctl_add(card, 21428c2ecf20Sopenharmony_ci snd_ctl_new1(&snd_emu1010_internal_clock, emu)); 21438c2ecf20Sopenharmony_ci if (err < 0) 21448c2ecf20Sopenharmony_ci return err; 21458c2ecf20Sopenharmony_ci err = snd_ctl_add(card, 21468c2ecf20Sopenharmony_ci snd_ctl_new1(&snd_emu1010_optical_out, emu)); 21478c2ecf20Sopenharmony_ci if (err < 0) 21488c2ecf20Sopenharmony_ci return err; 21498c2ecf20Sopenharmony_ci err = snd_ctl_add(card, 21508c2ecf20Sopenharmony_ci snd_ctl_new1(&snd_emu1010_optical_in, emu)); 21518c2ecf20Sopenharmony_ci if (err < 0) 21528c2ecf20Sopenharmony_ci return err; 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci } else if (emu->card_capabilities->emu_model) { 21558c2ecf20Sopenharmony_ci /* all other e-mu cards for now */ 21568c2ecf20Sopenharmony_ci int i; 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(snd_emu1010_output_enum_ctls); i++) { 21598c2ecf20Sopenharmony_ci err = snd_ctl_add(card, 21608c2ecf20Sopenharmony_ci snd_ctl_new1(&snd_emu1010_output_enum_ctls[i], 21618c2ecf20Sopenharmony_ci emu)); 21628c2ecf20Sopenharmony_ci if (err < 0) 21638c2ecf20Sopenharmony_ci return err; 21648c2ecf20Sopenharmony_ci } 21658c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(snd_emu1010_input_enum_ctls); i++) { 21668c2ecf20Sopenharmony_ci err = snd_ctl_add(card, 21678c2ecf20Sopenharmony_ci snd_ctl_new1(&snd_emu1010_input_enum_ctls[i], 21688c2ecf20Sopenharmony_ci emu)); 21698c2ecf20Sopenharmony_ci if (err < 0) 21708c2ecf20Sopenharmony_ci return err; 21718c2ecf20Sopenharmony_ci } 21728c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(snd_emu1010_adc_pads); i++) { 21738c2ecf20Sopenharmony_ci err = snd_ctl_add(card, 21748c2ecf20Sopenharmony_ci snd_ctl_new1(&snd_emu1010_adc_pads[i], emu)); 21758c2ecf20Sopenharmony_ci if (err < 0) 21768c2ecf20Sopenharmony_ci return err; 21778c2ecf20Sopenharmony_ci } 21788c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(snd_emu1010_dac_pads); i++) { 21798c2ecf20Sopenharmony_ci err = snd_ctl_add(card, 21808c2ecf20Sopenharmony_ci snd_ctl_new1(&snd_emu1010_dac_pads[i], emu)); 21818c2ecf20Sopenharmony_ci if (err < 0) 21828c2ecf20Sopenharmony_ci return err; 21838c2ecf20Sopenharmony_ci } 21848c2ecf20Sopenharmony_ci err = snd_ctl_add(card, 21858c2ecf20Sopenharmony_ci snd_ctl_new1(&snd_emu1010_internal_clock, emu)); 21868c2ecf20Sopenharmony_ci if (err < 0) 21878c2ecf20Sopenharmony_ci return err; 21888c2ecf20Sopenharmony_ci err = snd_ctl_add(card, 21898c2ecf20Sopenharmony_ci snd_ctl_new1(&snd_emu1010_optical_out, emu)); 21908c2ecf20Sopenharmony_ci if (err < 0) 21918c2ecf20Sopenharmony_ci return err; 21928c2ecf20Sopenharmony_ci err = snd_ctl_add(card, 21938c2ecf20Sopenharmony_ci snd_ctl_new1(&snd_emu1010_optical_in, emu)); 21948c2ecf20Sopenharmony_ci if (err < 0) 21958c2ecf20Sopenharmony_ci return err; 21968c2ecf20Sopenharmony_ci } 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci if ( emu->card_capabilities->i2c_adc) { 21998c2ecf20Sopenharmony_ci int i; 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_ci err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu)); 22028c2ecf20Sopenharmony_ci if (err < 0) 22038c2ecf20Sopenharmony_ci return err; 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(snd_audigy_i2c_volume_ctls); i++) { 22068c2ecf20Sopenharmony_ci err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_volume_ctls[i], emu)); 22078c2ecf20Sopenharmony_ci if (err < 0) 22088c2ecf20Sopenharmony_ci return err; 22098c2ecf20Sopenharmony_ci } 22108c2ecf20Sopenharmony_ci } 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci if (emu->card_capabilities->ac97_chip && emu->audigy) { 22138c2ecf20Sopenharmony_ci err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_capture_boost, 22148c2ecf20Sopenharmony_ci emu)); 22158c2ecf20Sopenharmony_ci if (err < 0) 22168c2ecf20Sopenharmony_ci return err; 22178c2ecf20Sopenharmony_ci } 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_ci return 0; 22208c2ecf20Sopenharmony_ci} 2221