11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Copyright (c) by Jaroslav Kysela <perex@suse.cz> 31da177e4SLinus Torvalds * Routines for Sound Blaster mixer control 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 71da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 81da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 91da177e4SLinus Torvalds * (at your option) any later version. 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, 121da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 131da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 141da177e4SLinus Torvalds * GNU General Public License for more details. 151da177e4SLinus Torvalds * 161da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 171da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 181da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 191da177e4SLinus Torvalds * 201da177e4SLinus Torvalds */ 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds #include <sound/driver.h> 231da177e4SLinus Torvalds #include <asm/io.h> 241da177e4SLinus Torvalds #include <linux/delay.h> 251da177e4SLinus Torvalds #include <linux/time.h> 261da177e4SLinus Torvalds #include <sound/core.h> 271da177e4SLinus Torvalds #include <sound/sb.h> 281da177e4SLinus Torvalds #include <sound/control.h> 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds #undef IO_DEBUG 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds void snd_sbmixer_write(sb_t *chip, unsigned char reg, unsigned char data) 331da177e4SLinus Torvalds { 341da177e4SLinus Torvalds outb(reg, SBP(chip, MIXER_ADDR)); 351da177e4SLinus Torvalds udelay(10); 361da177e4SLinus Torvalds outb(data, SBP(chip, MIXER_DATA)); 371da177e4SLinus Torvalds udelay(10); 381da177e4SLinus Torvalds #ifdef IO_DEBUG 391da177e4SLinus Torvalds snd_printk("mixer_write 0x%x 0x%x\n", reg, data); 401da177e4SLinus Torvalds #endif 411da177e4SLinus Torvalds } 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds unsigned char snd_sbmixer_read(sb_t *chip, unsigned char reg) 441da177e4SLinus Torvalds { 451da177e4SLinus Torvalds unsigned char result; 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds outb(reg, SBP(chip, MIXER_ADDR)); 481da177e4SLinus Torvalds udelay(10); 491da177e4SLinus Torvalds result = inb(SBP(chip, MIXER_DATA)); 501da177e4SLinus Torvalds udelay(10); 511da177e4SLinus Torvalds #ifdef IO_DEBUG 521da177e4SLinus Torvalds snd_printk("mixer_read 0x%x 0x%x\n", reg, result); 531da177e4SLinus Torvalds #endif 541da177e4SLinus Torvalds return result; 551da177e4SLinus Torvalds } 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds /* 581da177e4SLinus Torvalds * Single channel mixer element 591da177e4SLinus Torvalds */ 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds static int snd_sbmixer_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) 621da177e4SLinus Torvalds { 631da177e4SLinus Torvalds int mask = (kcontrol->private_value >> 24) & 0xff; 641da177e4SLinus Torvalds 651da177e4SLinus Torvalds uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; 661da177e4SLinus Torvalds uinfo->count = 1; 671da177e4SLinus Torvalds uinfo->value.integer.min = 0; 681da177e4SLinus Torvalds uinfo->value.integer.max = mask; 691da177e4SLinus Torvalds return 0; 701da177e4SLinus Torvalds } 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds static int snd_sbmixer_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) 731da177e4SLinus Torvalds { 741da177e4SLinus Torvalds sb_t *sb = snd_kcontrol_chip(kcontrol); 751da177e4SLinus Torvalds unsigned long flags; 761da177e4SLinus Torvalds int reg = kcontrol->private_value & 0xff; 771da177e4SLinus Torvalds int shift = (kcontrol->private_value >> 16) & 0xff; 781da177e4SLinus Torvalds int mask = (kcontrol->private_value >> 24) & 0xff; 791da177e4SLinus Torvalds unsigned char val; 801da177e4SLinus Torvalds 811da177e4SLinus Torvalds spin_lock_irqsave(&sb->mixer_lock, flags); 821da177e4SLinus Torvalds val = (snd_sbmixer_read(sb, reg) >> shift) & mask; 831da177e4SLinus Torvalds spin_unlock_irqrestore(&sb->mixer_lock, flags); 841da177e4SLinus Torvalds ucontrol->value.integer.value[0] = val; 851da177e4SLinus Torvalds return 0; 861da177e4SLinus Torvalds } 871da177e4SLinus Torvalds 881da177e4SLinus Torvalds static int snd_sbmixer_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) 891da177e4SLinus Torvalds { 901da177e4SLinus Torvalds sb_t *sb = snd_kcontrol_chip(kcontrol); 911da177e4SLinus Torvalds unsigned long flags; 921da177e4SLinus Torvalds int reg = kcontrol->private_value & 0xff; 931da177e4SLinus Torvalds int shift = (kcontrol->private_value >> 16) & 0x07; 941da177e4SLinus Torvalds int mask = (kcontrol->private_value >> 24) & 0xff; 951da177e4SLinus Torvalds int change; 961da177e4SLinus Torvalds unsigned char val, oval; 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds val = (ucontrol->value.integer.value[0] & mask) << shift; 991da177e4SLinus Torvalds spin_lock_irqsave(&sb->mixer_lock, flags); 1001da177e4SLinus Torvalds oval = snd_sbmixer_read(sb, reg); 1011da177e4SLinus Torvalds val = (oval & ~(mask << shift)) | val; 1021da177e4SLinus Torvalds change = val != oval; 1031da177e4SLinus Torvalds if (change) 1041da177e4SLinus Torvalds snd_sbmixer_write(sb, reg, val); 1051da177e4SLinus Torvalds spin_unlock_irqrestore(&sb->mixer_lock, flags); 1061da177e4SLinus Torvalds return change; 1071da177e4SLinus Torvalds } 1081da177e4SLinus Torvalds 1091da177e4SLinus Torvalds /* 1101da177e4SLinus Torvalds * Double channel mixer element 1111da177e4SLinus Torvalds */ 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds static int snd_sbmixer_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) 1141da177e4SLinus Torvalds { 1151da177e4SLinus Torvalds int mask = (kcontrol->private_value >> 24) & 0xff; 1161da177e4SLinus Torvalds 1171da177e4SLinus Torvalds uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; 1181da177e4SLinus Torvalds uinfo->count = 2; 1191da177e4SLinus Torvalds uinfo->value.integer.min = 0; 1201da177e4SLinus Torvalds uinfo->value.integer.max = mask; 1211da177e4SLinus Torvalds return 0; 1221da177e4SLinus Torvalds } 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds static int snd_sbmixer_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) 1251da177e4SLinus Torvalds { 1261da177e4SLinus Torvalds sb_t *sb = snd_kcontrol_chip(kcontrol); 1271da177e4SLinus Torvalds unsigned long flags; 1281da177e4SLinus Torvalds int left_reg = kcontrol->private_value & 0xff; 1291da177e4SLinus Torvalds int right_reg = (kcontrol->private_value >> 8) & 0xff; 1301da177e4SLinus Torvalds int left_shift = (kcontrol->private_value >> 16) & 0x07; 1311da177e4SLinus Torvalds int right_shift = (kcontrol->private_value >> 19) & 0x07; 1321da177e4SLinus Torvalds int mask = (kcontrol->private_value >> 24) & 0xff; 1331da177e4SLinus Torvalds unsigned char left, right; 1341da177e4SLinus Torvalds 1351da177e4SLinus Torvalds spin_lock_irqsave(&sb->mixer_lock, flags); 1361da177e4SLinus Torvalds left = (snd_sbmixer_read(sb, left_reg) >> left_shift) & mask; 1371da177e4SLinus Torvalds right = (snd_sbmixer_read(sb, right_reg) >> right_shift) & mask; 1381da177e4SLinus Torvalds spin_unlock_irqrestore(&sb->mixer_lock, flags); 1391da177e4SLinus Torvalds ucontrol->value.integer.value[0] = left; 1401da177e4SLinus Torvalds ucontrol->value.integer.value[1] = right; 1411da177e4SLinus Torvalds return 0; 1421da177e4SLinus Torvalds } 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds static int snd_sbmixer_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) 1451da177e4SLinus Torvalds { 1461da177e4SLinus Torvalds sb_t *sb = snd_kcontrol_chip(kcontrol); 1471da177e4SLinus Torvalds unsigned long flags; 1481da177e4SLinus Torvalds int left_reg = kcontrol->private_value & 0xff; 1491da177e4SLinus Torvalds int right_reg = (kcontrol->private_value >> 8) & 0xff; 1501da177e4SLinus Torvalds int left_shift = (kcontrol->private_value >> 16) & 0x07; 1511da177e4SLinus Torvalds int right_shift = (kcontrol->private_value >> 19) & 0x07; 1521da177e4SLinus Torvalds int mask = (kcontrol->private_value >> 24) & 0xff; 1531da177e4SLinus Torvalds int change; 1541da177e4SLinus Torvalds unsigned char left, right, oleft, oright; 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds left = (ucontrol->value.integer.value[0] & mask) << left_shift; 1571da177e4SLinus Torvalds right = (ucontrol->value.integer.value[1] & mask) << right_shift; 1581da177e4SLinus Torvalds spin_lock_irqsave(&sb->mixer_lock, flags); 1591da177e4SLinus Torvalds if (left_reg == right_reg) { 1601da177e4SLinus Torvalds oleft = snd_sbmixer_read(sb, left_reg); 1611da177e4SLinus Torvalds left = (oleft & ~((mask << left_shift) | (mask << right_shift))) | left | right; 1621da177e4SLinus Torvalds change = left != oleft; 1631da177e4SLinus Torvalds if (change) 1641da177e4SLinus Torvalds snd_sbmixer_write(sb, left_reg, left); 1651da177e4SLinus Torvalds } else { 1661da177e4SLinus Torvalds oleft = snd_sbmixer_read(sb, left_reg); 1671da177e4SLinus Torvalds oright = snd_sbmixer_read(sb, right_reg); 1681da177e4SLinus Torvalds left = (oleft & ~(mask << left_shift)) | left; 1691da177e4SLinus Torvalds right = (oright & ~(mask << right_shift)) | right; 1701da177e4SLinus Torvalds change = left != oleft || right != oright; 1711da177e4SLinus Torvalds if (change) { 1721da177e4SLinus Torvalds snd_sbmixer_write(sb, left_reg, left); 1731da177e4SLinus Torvalds snd_sbmixer_write(sb, right_reg, right); 1741da177e4SLinus Torvalds } 1751da177e4SLinus Torvalds } 1761da177e4SLinus Torvalds spin_unlock_irqrestore(&sb->mixer_lock, flags); 1771da177e4SLinus Torvalds return change; 1781da177e4SLinus Torvalds } 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds /* 1811da177e4SLinus Torvalds * DT-019x / ALS-007 capture/input switch 1821da177e4SLinus Torvalds */ 1831da177e4SLinus Torvalds 1841da177e4SLinus Torvalds static int snd_dt019x_input_sw_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) 1851da177e4SLinus Torvalds { 1861da177e4SLinus Torvalds static char *texts[5] = { 1871da177e4SLinus Torvalds "CD", "Mic", "Line", "Synth", "Master" 1881da177e4SLinus Torvalds }; 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 1911da177e4SLinus Torvalds uinfo->count = 1; 1921da177e4SLinus Torvalds uinfo->value.enumerated.items = 5; 1931da177e4SLinus Torvalds if (uinfo->value.enumerated.item > 4) 1941da177e4SLinus Torvalds uinfo->value.enumerated.item = 4; 1951da177e4SLinus Torvalds strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); 1961da177e4SLinus Torvalds return 0; 1971da177e4SLinus Torvalds } 1981da177e4SLinus Torvalds 1991da177e4SLinus Torvalds static int snd_dt019x_input_sw_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) 2001da177e4SLinus Torvalds { 2011da177e4SLinus Torvalds sb_t *sb = snd_kcontrol_chip(kcontrol); 2021da177e4SLinus Torvalds unsigned long flags; 2031da177e4SLinus Torvalds unsigned char oval; 2041da177e4SLinus Torvalds 2051da177e4SLinus Torvalds spin_lock_irqsave(&sb->mixer_lock, flags); 2061da177e4SLinus Torvalds oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW); 2071da177e4SLinus Torvalds spin_unlock_irqrestore(&sb->mixer_lock, flags); 2081da177e4SLinus Torvalds switch (oval & 0x07) { 2091da177e4SLinus Torvalds case SB_DT019X_CAP_CD: 2101da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 0; 2111da177e4SLinus Torvalds break; 2121da177e4SLinus Torvalds case SB_DT019X_CAP_MIC: 2131da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 1; 2141da177e4SLinus Torvalds break; 2151da177e4SLinus Torvalds case SB_DT019X_CAP_LINE: 2161da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 2; 2171da177e4SLinus Torvalds break; 2181da177e4SLinus Torvalds case SB_DT019X_CAP_MAIN: 2191da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 4; 2201da177e4SLinus Torvalds break; 2211da177e4SLinus Torvalds /* To record the synth on these cards you must record the main. */ 2221da177e4SLinus Torvalds /* Thus SB_DT019X_CAP_SYNTH == SB_DT019X_CAP_MAIN and would cause */ 2231da177e4SLinus Torvalds /* duplicate case labels if left uncommented. */ 2241da177e4SLinus Torvalds /* case SB_DT019X_CAP_SYNTH: 2251da177e4SLinus Torvalds * ucontrol->value.enumerated.item[0] = 3; 2261da177e4SLinus Torvalds * break; 2271da177e4SLinus Torvalds */ 2281da177e4SLinus Torvalds default: 2291da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 4; 2301da177e4SLinus Torvalds break; 2311da177e4SLinus Torvalds } 2321da177e4SLinus Torvalds return 0; 2331da177e4SLinus Torvalds } 2341da177e4SLinus Torvalds 2351da177e4SLinus Torvalds static int snd_dt019x_input_sw_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) 2361da177e4SLinus Torvalds { 2371da177e4SLinus Torvalds sb_t *sb = snd_kcontrol_chip(kcontrol); 2381da177e4SLinus Torvalds unsigned long flags; 2391da177e4SLinus Torvalds int change; 2401da177e4SLinus Torvalds unsigned char nval, oval; 2411da177e4SLinus Torvalds 2421da177e4SLinus Torvalds if (ucontrol->value.enumerated.item[0] > 4) 2431da177e4SLinus Torvalds return -EINVAL; 2441da177e4SLinus Torvalds switch (ucontrol->value.enumerated.item[0]) { 2451da177e4SLinus Torvalds case 0: 2461da177e4SLinus Torvalds nval = SB_DT019X_CAP_CD; 2471da177e4SLinus Torvalds break; 2481da177e4SLinus Torvalds case 1: 2491da177e4SLinus Torvalds nval = SB_DT019X_CAP_MIC; 2501da177e4SLinus Torvalds break; 2511da177e4SLinus Torvalds case 2: 2521da177e4SLinus Torvalds nval = SB_DT019X_CAP_LINE; 2531da177e4SLinus Torvalds break; 2541da177e4SLinus Torvalds case 3: 2551da177e4SLinus Torvalds nval = SB_DT019X_CAP_SYNTH; 2561da177e4SLinus Torvalds break; 2571da177e4SLinus Torvalds case 4: 2581da177e4SLinus Torvalds nval = SB_DT019X_CAP_MAIN; 2591da177e4SLinus Torvalds break; 2601da177e4SLinus Torvalds default: 2611da177e4SLinus Torvalds nval = SB_DT019X_CAP_MAIN; 2621da177e4SLinus Torvalds } 2631da177e4SLinus Torvalds spin_lock_irqsave(&sb->mixer_lock, flags); 2641da177e4SLinus Torvalds oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW); 2651da177e4SLinus Torvalds change = nval != oval; 2661da177e4SLinus Torvalds if (change) 2671da177e4SLinus Torvalds snd_sbmixer_write(sb, SB_DT019X_CAPTURE_SW, nval); 2681da177e4SLinus Torvalds spin_unlock_irqrestore(&sb->mixer_lock, flags); 2691da177e4SLinus Torvalds return change; 2701da177e4SLinus Torvalds } 2711da177e4SLinus Torvalds 2721da177e4SLinus Torvalds /* 2731da177e4SLinus Torvalds * SBPRO input multiplexer 2741da177e4SLinus Torvalds */ 2751da177e4SLinus Torvalds 2761da177e4SLinus Torvalds static int snd_sb8mixer_info_mux(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) 2771da177e4SLinus Torvalds { 2781da177e4SLinus Torvalds static char *texts[3] = { 2791da177e4SLinus Torvalds "Mic", "CD", "Line" 2801da177e4SLinus Torvalds }; 2811da177e4SLinus Torvalds 2821da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 2831da177e4SLinus Torvalds uinfo->count = 1; 2841da177e4SLinus Torvalds uinfo->value.enumerated.items = 3; 2851da177e4SLinus Torvalds if (uinfo->value.enumerated.item > 2) 2861da177e4SLinus Torvalds uinfo->value.enumerated.item = 2; 2871da177e4SLinus Torvalds strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); 2881da177e4SLinus Torvalds return 0; 2891da177e4SLinus Torvalds } 2901da177e4SLinus Torvalds 2911da177e4SLinus Torvalds 2921da177e4SLinus Torvalds static int snd_sb8mixer_get_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) 2931da177e4SLinus Torvalds { 2941da177e4SLinus Torvalds sb_t *sb = snd_kcontrol_chip(kcontrol); 2951da177e4SLinus Torvalds unsigned long flags; 2961da177e4SLinus Torvalds unsigned char oval; 2971da177e4SLinus Torvalds 2981da177e4SLinus Torvalds spin_lock_irqsave(&sb->mixer_lock, flags); 2991da177e4SLinus Torvalds oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE); 3001da177e4SLinus Torvalds spin_unlock_irqrestore(&sb->mixer_lock, flags); 3011da177e4SLinus Torvalds switch ((oval >> 0x01) & 0x03) { 3021da177e4SLinus Torvalds case SB_DSP_MIXS_CD: 3031da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 1; 3041da177e4SLinus Torvalds break; 3051da177e4SLinus Torvalds case SB_DSP_MIXS_LINE: 3061da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 2; 3071da177e4SLinus Torvalds break; 3081da177e4SLinus Torvalds default: 3091da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 0; 3101da177e4SLinus Torvalds break; 3111da177e4SLinus Torvalds } 3121da177e4SLinus Torvalds return 0; 3131da177e4SLinus Torvalds } 3141da177e4SLinus Torvalds 3151da177e4SLinus Torvalds static int snd_sb8mixer_put_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) 3161da177e4SLinus Torvalds { 3171da177e4SLinus Torvalds sb_t *sb = snd_kcontrol_chip(kcontrol); 3181da177e4SLinus Torvalds unsigned long flags; 3191da177e4SLinus Torvalds int change; 3201da177e4SLinus Torvalds unsigned char nval, oval; 3211da177e4SLinus Torvalds 3221da177e4SLinus Torvalds if (ucontrol->value.enumerated.item[0] > 2) 3231da177e4SLinus Torvalds return -EINVAL; 3241da177e4SLinus Torvalds switch (ucontrol->value.enumerated.item[0]) { 3251da177e4SLinus Torvalds case 1: 3261da177e4SLinus Torvalds nval = SB_DSP_MIXS_CD; 3271da177e4SLinus Torvalds break; 3281da177e4SLinus Torvalds case 2: 3291da177e4SLinus Torvalds nval = SB_DSP_MIXS_LINE; 3301da177e4SLinus Torvalds break; 3311da177e4SLinus Torvalds default: 3321da177e4SLinus Torvalds nval = SB_DSP_MIXS_MIC; 3331da177e4SLinus Torvalds } 3341da177e4SLinus Torvalds nval <<= 1; 3351da177e4SLinus Torvalds spin_lock_irqsave(&sb->mixer_lock, flags); 3361da177e4SLinus Torvalds oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE); 3371da177e4SLinus Torvalds nval |= oval & ~0x06; 3381da177e4SLinus Torvalds change = nval != oval; 3391da177e4SLinus Torvalds if (change) 3401da177e4SLinus Torvalds snd_sbmixer_write(sb, SB_DSP_CAPTURE_SOURCE, nval); 3411da177e4SLinus Torvalds spin_unlock_irqrestore(&sb->mixer_lock, flags); 3421da177e4SLinus Torvalds return change; 3431da177e4SLinus Torvalds } 3441da177e4SLinus Torvalds 3451da177e4SLinus Torvalds /* 3461da177e4SLinus Torvalds * SB16 input switch 3471da177e4SLinus Torvalds */ 3481da177e4SLinus Torvalds 3491da177e4SLinus Torvalds static int snd_sb16mixer_info_input_sw(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo) 3501da177e4SLinus Torvalds { 3511da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 3521da177e4SLinus Torvalds uinfo->count = 4; 3531da177e4SLinus Torvalds uinfo->value.integer.min = 0; 3541da177e4SLinus Torvalds uinfo->value.integer.max = 1; 3551da177e4SLinus Torvalds return 0; 3561da177e4SLinus Torvalds } 3571da177e4SLinus Torvalds 3581da177e4SLinus Torvalds static int snd_sb16mixer_get_input_sw(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) 3591da177e4SLinus Torvalds { 3601da177e4SLinus Torvalds sb_t *sb = snd_kcontrol_chip(kcontrol); 3611da177e4SLinus Torvalds unsigned long flags; 3621da177e4SLinus Torvalds int reg1 = kcontrol->private_value & 0xff; 3631da177e4SLinus Torvalds int reg2 = (kcontrol->private_value >> 8) & 0xff; 3641da177e4SLinus Torvalds int left_shift = (kcontrol->private_value >> 16) & 0x0f; 3651da177e4SLinus Torvalds int right_shift = (kcontrol->private_value >> 24) & 0x0f; 3661da177e4SLinus Torvalds unsigned char val1, val2; 3671da177e4SLinus Torvalds 3681da177e4SLinus Torvalds spin_lock_irqsave(&sb->mixer_lock, flags); 3691da177e4SLinus Torvalds val1 = snd_sbmixer_read(sb, reg1); 3701da177e4SLinus Torvalds val2 = snd_sbmixer_read(sb, reg2); 3711da177e4SLinus Torvalds spin_unlock_irqrestore(&sb->mixer_lock, flags); 3721da177e4SLinus Torvalds ucontrol->value.integer.value[0] = (val1 >> left_shift) & 0x01; 3731da177e4SLinus Torvalds ucontrol->value.integer.value[1] = (val2 >> left_shift) & 0x01; 3741da177e4SLinus Torvalds ucontrol->value.integer.value[2] = (val1 >> right_shift) & 0x01; 3751da177e4SLinus Torvalds ucontrol->value.integer.value[3] = (val2 >> right_shift) & 0x01; 3761da177e4SLinus Torvalds return 0; 3771da177e4SLinus Torvalds } 3781da177e4SLinus Torvalds 3791da177e4SLinus Torvalds static int snd_sb16mixer_put_input_sw(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) 3801da177e4SLinus Torvalds { 3811da177e4SLinus Torvalds sb_t *sb = snd_kcontrol_chip(kcontrol); 3821da177e4SLinus Torvalds unsigned long flags; 3831da177e4SLinus Torvalds int reg1 = kcontrol->private_value & 0xff; 3841da177e4SLinus Torvalds int reg2 = (kcontrol->private_value >> 8) & 0xff; 3851da177e4SLinus Torvalds int left_shift = (kcontrol->private_value >> 16) & 0x0f; 3861da177e4SLinus Torvalds int right_shift = (kcontrol->private_value >> 24) & 0x0f; 3871da177e4SLinus Torvalds int change; 3881da177e4SLinus Torvalds unsigned char val1, val2, oval1, oval2; 3891da177e4SLinus Torvalds 3901da177e4SLinus Torvalds spin_lock_irqsave(&sb->mixer_lock, flags); 3911da177e4SLinus Torvalds oval1 = snd_sbmixer_read(sb, reg1); 3921da177e4SLinus Torvalds oval2 = snd_sbmixer_read(sb, reg2); 3931da177e4SLinus Torvalds val1 = oval1 & ~((1 << left_shift) | (1 << right_shift)); 3941da177e4SLinus Torvalds val2 = oval2 & ~((1 << left_shift) | (1 << right_shift)); 3951da177e4SLinus Torvalds val1 |= (ucontrol->value.integer.value[0] & 1) << left_shift; 3961da177e4SLinus Torvalds val2 |= (ucontrol->value.integer.value[1] & 1) << left_shift; 3971da177e4SLinus Torvalds val1 |= (ucontrol->value.integer.value[2] & 1) << right_shift; 3981da177e4SLinus Torvalds val2 |= (ucontrol->value.integer.value[3] & 1) << right_shift; 3991da177e4SLinus Torvalds change = val1 != oval1 || val2 != oval2; 4001da177e4SLinus Torvalds if (change) { 4011da177e4SLinus Torvalds snd_sbmixer_write(sb, reg1, val1); 4021da177e4SLinus Torvalds snd_sbmixer_write(sb, reg2, val2); 4031da177e4SLinus Torvalds } 4041da177e4SLinus Torvalds spin_unlock_irqrestore(&sb->mixer_lock, flags); 4051da177e4SLinus Torvalds return change; 4061da177e4SLinus Torvalds } 4071da177e4SLinus Torvalds 4081da177e4SLinus Torvalds 4091da177e4SLinus Torvalds /* 4101da177e4SLinus Torvalds */ 4111da177e4SLinus Torvalds /* 4121da177e4SLinus Torvalds */ 4131da177e4SLinus Torvalds int snd_sbmixer_add_ctl(sb_t *chip, const char *name, int index, int type, unsigned long value) 4141da177e4SLinus Torvalds { 4151da177e4SLinus Torvalds static snd_kcontrol_new_t newctls[] = { 4161da177e4SLinus Torvalds [SB_MIX_SINGLE] = { 4171da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4181da177e4SLinus Torvalds .info = snd_sbmixer_info_single, 4191da177e4SLinus Torvalds .get = snd_sbmixer_get_single, 4201da177e4SLinus Torvalds .put = snd_sbmixer_put_single, 4211da177e4SLinus Torvalds }, 4221da177e4SLinus Torvalds [SB_MIX_DOUBLE] = { 4231da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4241da177e4SLinus Torvalds .info = snd_sbmixer_info_double, 4251da177e4SLinus Torvalds .get = snd_sbmixer_get_double, 4261da177e4SLinus Torvalds .put = snd_sbmixer_put_double, 4271da177e4SLinus Torvalds }, 4281da177e4SLinus Torvalds [SB_MIX_INPUT_SW] = { 4291da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4301da177e4SLinus Torvalds .info = snd_sb16mixer_info_input_sw, 4311da177e4SLinus Torvalds .get = snd_sb16mixer_get_input_sw, 4321da177e4SLinus Torvalds .put = snd_sb16mixer_put_input_sw, 4331da177e4SLinus Torvalds }, 4341da177e4SLinus Torvalds [SB_MIX_CAPTURE_PRO] = { 4351da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4361da177e4SLinus Torvalds .info = snd_sb8mixer_info_mux, 4371da177e4SLinus Torvalds .get = snd_sb8mixer_get_mux, 4381da177e4SLinus Torvalds .put = snd_sb8mixer_put_mux, 4391da177e4SLinus Torvalds }, 4401da177e4SLinus Torvalds [SB_MIX_CAPTURE_DT019X] = { 4411da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4421da177e4SLinus Torvalds .info = snd_dt019x_input_sw_info, 4431da177e4SLinus Torvalds .get = snd_dt019x_input_sw_get, 4441da177e4SLinus Torvalds .put = snd_dt019x_input_sw_put, 4451da177e4SLinus Torvalds }, 4461da177e4SLinus Torvalds }; 4471da177e4SLinus Torvalds snd_kcontrol_t *ctl; 4481da177e4SLinus Torvalds int err; 4491da177e4SLinus Torvalds 4501da177e4SLinus Torvalds ctl = snd_ctl_new1(&newctls[type], chip); 4511da177e4SLinus Torvalds if (! ctl) 4521da177e4SLinus Torvalds return -ENOMEM; 4531da177e4SLinus Torvalds strlcpy(ctl->id.name, name, sizeof(ctl->id.name)); 4541da177e4SLinus Torvalds ctl->id.index = index; 4551da177e4SLinus Torvalds ctl->private_value = value; 4561da177e4SLinus Torvalds if ((err = snd_ctl_add(chip->card, ctl)) < 0) { 4571da177e4SLinus Torvalds snd_ctl_free_one(ctl); 4581da177e4SLinus Torvalds return err; 4591da177e4SLinus Torvalds } 4601da177e4SLinus Torvalds return 0; 4611da177e4SLinus Torvalds } 4621da177e4SLinus Torvalds 4631da177e4SLinus Torvalds /* 4641da177e4SLinus Torvalds * SB 2.0 specific mixer elements 4651da177e4SLinus Torvalds */ 4661da177e4SLinus Torvalds 4671da177e4SLinus Torvalds static struct sbmix_elem snd_sb20_ctl_master_play_vol = 4681da177e4SLinus Torvalds SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7); 4691da177e4SLinus Torvalds static struct sbmix_elem snd_sb20_ctl_pcm_play_vol = 4701da177e4SLinus Torvalds SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3); 4711da177e4SLinus Torvalds static struct sbmix_elem snd_sb20_ctl_synth_play_vol = 4721da177e4SLinus Torvalds SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7); 4731da177e4SLinus Torvalds static struct sbmix_elem snd_sb20_ctl_cd_play_vol = 4741da177e4SLinus Torvalds SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7); 4751da177e4SLinus Torvalds 4761da177e4SLinus Torvalds static struct sbmix_elem *snd_sb20_controls[] = { 4771da177e4SLinus Torvalds &snd_sb20_ctl_master_play_vol, 4781da177e4SLinus Torvalds &snd_sb20_ctl_pcm_play_vol, 4791da177e4SLinus Torvalds &snd_sb20_ctl_synth_play_vol, 4801da177e4SLinus Torvalds &snd_sb20_ctl_cd_play_vol 4811da177e4SLinus Torvalds }; 4821da177e4SLinus Torvalds 4831da177e4SLinus Torvalds static unsigned char snd_sb20_init_values[][2] = { 4841da177e4SLinus Torvalds { SB_DSP20_MASTER_DEV, 0 }, 4851da177e4SLinus Torvalds { SB_DSP20_FM_DEV, 0 }, 4861da177e4SLinus Torvalds }; 4871da177e4SLinus Torvalds 4881da177e4SLinus Torvalds /* 4891da177e4SLinus Torvalds * SB Pro specific mixer elements 4901da177e4SLinus Torvalds */ 4911da177e4SLinus Torvalds static struct sbmix_elem snd_sbpro_ctl_master_play_vol = 4921da177e4SLinus Torvalds SB_DOUBLE("Master Playback Volume", SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7); 4931da177e4SLinus Torvalds static struct sbmix_elem snd_sbpro_ctl_pcm_play_vol = 4941da177e4SLinus Torvalds SB_DOUBLE("PCM Playback Volume", SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7); 4951da177e4SLinus Torvalds static struct sbmix_elem snd_sbpro_ctl_pcm_play_filter = 4961da177e4SLinus Torvalds SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1); 4971da177e4SLinus Torvalds static struct sbmix_elem snd_sbpro_ctl_synth_play_vol = 4981da177e4SLinus Torvalds SB_DOUBLE("Synth Playback Volume", SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7); 4991da177e4SLinus Torvalds static struct sbmix_elem snd_sbpro_ctl_cd_play_vol = 5001da177e4SLinus Torvalds SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7); 5011da177e4SLinus Torvalds static struct sbmix_elem snd_sbpro_ctl_line_play_vol = 5021da177e4SLinus Torvalds SB_DOUBLE("Line Playback Volume", SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7); 5031da177e4SLinus Torvalds static struct sbmix_elem snd_sbpro_ctl_mic_play_vol = 5041da177e4SLinus Torvalds SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3); 5051da177e4SLinus Torvalds static struct sbmix_elem snd_sbpro_ctl_capture_source = 5061da177e4SLinus Torvalds { 5071da177e4SLinus Torvalds .name = "Capture Source", 5081da177e4SLinus Torvalds .type = SB_MIX_CAPTURE_PRO 5091da177e4SLinus Torvalds }; 5101da177e4SLinus Torvalds static struct sbmix_elem snd_sbpro_ctl_capture_filter = 5111da177e4SLinus Torvalds SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1); 5121da177e4SLinus Torvalds static struct sbmix_elem snd_sbpro_ctl_capture_low_filter = 5131da177e4SLinus Torvalds SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1); 5141da177e4SLinus Torvalds 5151da177e4SLinus Torvalds static struct sbmix_elem *snd_sbpro_controls[] = { 5161da177e4SLinus Torvalds &snd_sbpro_ctl_master_play_vol, 5171da177e4SLinus Torvalds &snd_sbpro_ctl_pcm_play_vol, 5181da177e4SLinus Torvalds &snd_sbpro_ctl_pcm_play_filter, 5191da177e4SLinus Torvalds &snd_sbpro_ctl_synth_play_vol, 5201da177e4SLinus Torvalds &snd_sbpro_ctl_cd_play_vol, 5211da177e4SLinus Torvalds &snd_sbpro_ctl_line_play_vol, 5221da177e4SLinus Torvalds &snd_sbpro_ctl_mic_play_vol, 5231da177e4SLinus Torvalds &snd_sbpro_ctl_capture_source, 5241da177e4SLinus Torvalds &snd_sbpro_ctl_capture_filter, 5251da177e4SLinus Torvalds &snd_sbpro_ctl_capture_low_filter 5261da177e4SLinus Torvalds }; 5271da177e4SLinus Torvalds 5281da177e4SLinus Torvalds static unsigned char snd_sbpro_init_values[][2] = { 5291da177e4SLinus Torvalds { SB_DSP_MASTER_DEV, 0 }, 5301da177e4SLinus Torvalds { SB_DSP_PCM_DEV, 0 }, 5311da177e4SLinus Torvalds { SB_DSP_FM_DEV, 0 }, 5321da177e4SLinus Torvalds }; 5331da177e4SLinus Torvalds 5341da177e4SLinus Torvalds /* 5351da177e4SLinus Torvalds * SB16 specific mixer elements 5361da177e4SLinus Torvalds */ 5371da177e4SLinus Torvalds static struct sbmix_elem snd_sb16_ctl_master_play_vol = 5381da177e4SLinus Torvalds SB_DOUBLE("Master Playback Volume", SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31); 5391da177e4SLinus Torvalds static struct sbmix_elem snd_sb16_ctl_3d_enhance_switch = 5401da177e4SLinus Torvalds SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1); 5411da177e4SLinus Torvalds static struct sbmix_elem snd_sb16_ctl_tone_bass = 5421da177e4SLinus Torvalds SB_DOUBLE("Tone Control - Bass", SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15); 5431da177e4SLinus Torvalds static struct sbmix_elem snd_sb16_ctl_tone_treble = 5441da177e4SLinus Torvalds SB_DOUBLE("Tone Control - Treble", SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15); 5451da177e4SLinus Torvalds static struct sbmix_elem snd_sb16_ctl_pcm_play_vol = 5461da177e4SLinus Torvalds SB_DOUBLE("PCM Playback Volume", SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31); 5471da177e4SLinus Torvalds static struct sbmix_elem snd_sb16_ctl_synth_capture_route = 5481da177e4SLinus Torvalds SB16_INPUT_SW("Synth Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5); 5491da177e4SLinus Torvalds static struct sbmix_elem snd_sb16_ctl_synth_play_vol = 5501da177e4SLinus Torvalds SB_DOUBLE("Synth Playback Volume", SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31); 5511da177e4SLinus Torvalds static struct sbmix_elem snd_sb16_ctl_cd_capture_route = 5521da177e4SLinus Torvalds SB16_INPUT_SW("CD Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1); 5531da177e4SLinus Torvalds static struct sbmix_elem snd_sb16_ctl_cd_play_switch = 5541da177e4SLinus Torvalds SB_DOUBLE("CD Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1); 5551da177e4SLinus Torvalds static struct sbmix_elem snd_sb16_ctl_cd_play_vol = 5561da177e4SLinus Torvalds SB_DOUBLE("CD Playback Volume", SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31); 5571da177e4SLinus Torvalds static struct sbmix_elem snd_sb16_ctl_line_capture_route = 5581da177e4SLinus Torvalds SB16_INPUT_SW("Line Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3); 5591da177e4SLinus Torvalds static struct sbmix_elem snd_sb16_ctl_line_play_switch = 5601da177e4SLinus Torvalds SB_DOUBLE("Line Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1); 5611da177e4SLinus Torvalds static struct sbmix_elem snd_sb16_ctl_line_play_vol = 5621da177e4SLinus Torvalds SB_DOUBLE("Line Playback Volume", SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31); 5631da177e4SLinus Torvalds static struct sbmix_elem snd_sb16_ctl_mic_capture_route = 5641da177e4SLinus Torvalds SB16_INPUT_SW("Mic Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0); 5651da177e4SLinus Torvalds static struct sbmix_elem snd_sb16_ctl_mic_play_switch = 5661da177e4SLinus Torvalds SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1); 5671da177e4SLinus Torvalds static struct sbmix_elem snd_sb16_ctl_mic_play_vol = 5681da177e4SLinus Torvalds SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31); 5691da177e4SLinus Torvalds static struct sbmix_elem snd_sb16_ctl_pc_speaker_vol = 5701da177e4SLinus Torvalds SB_SINGLE("PC Speaker Volume", SB_DSP4_SPEAKER_DEV, 6, 3); 5711da177e4SLinus Torvalds static struct sbmix_elem snd_sb16_ctl_capture_vol = 5721da177e4SLinus Torvalds SB_DOUBLE("Capture Volume", SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3); 5731da177e4SLinus Torvalds static struct sbmix_elem snd_sb16_ctl_play_vol = 5741da177e4SLinus Torvalds SB_DOUBLE("Playback Volume", SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3); 5751da177e4SLinus Torvalds static struct sbmix_elem snd_sb16_ctl_auto_mic_gain = 5761da177e4SLinus Torvalds SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1); 5771da177e4SLinus Torvalds 5781da177e4SLinus Torvalds static struct sbmix_elem *snd_sb16_controls[] = { 5791da177e4SLinus Torvalds &snd_sb16_ctl_master_play_vol, 5801da177e4SLinus Torvalds &snd_sb16_ctl_3d_enhance_switch, 5811da177e4SLinus Torvalds &snd_sb16_ctl_tone_bass, 5821da177e4SLinus Torvalds &snd_sb16_ctl_tone_treble, 5831da177e4SLinus Torvalds &snd_sb16_ctl_pcm_play_vol, 5841da177e4SLinus Torvalds &snd_sb16_ctl_synth_capture_route, 5851da177e4SLinus Torvalds &snd_sb16_ctl_synth_play_vol, 5861da177e4SLinus Torvalds &snd_sb16_ctl_cd_capture_route, 5871da177e4SLinus Torvalds &snd_sb16_ctl_cd_play_switch, 5881da177e4SLinus Torvalds &snd_sb16_ctl_cd_play_vol, 5891da177e4SLinus Torvalds &snd_sb16_ctl_line_capture_route, 5901da177e4SLinus Torvalds &snd_sb16_ctl_line_play_switch, 5911da177e4SLinus Torvalds &snd_sb16_ctl_line_play_vol, 5921da177e4SLinus Torvalds &snd_sb16_ctl_mic_capture_route, 5931da177e4SLinus Torvalds &snd_sb16_ctl_mic_play_switch, 5941da177e4SLinus Torvalds &snd_sb16_ctl_mic_play_vol, 5951da177e4SLinus Torvalds &snd_sb16_ctl_pc_speaker_vol, 5961da177e4SLinus Torvalds &snd_sb16_ctl_capture_vol, 5971da177e4SLinus Torvalds &snd_sb16_ctl_play_vol, 5981da177e4SLinus Torvalds &snd_sb16_ctl_auto_mic_gain 5991da177e4SLinus Torvalds }; 6001da177e4SLinus Torvalds 6011da177e4SLinus Torvalds static unsigned char snd_sb16_init_values[][2] = { 6021da177e4SLinus Torvalds { SB_DSP4_MASTER_DEV + 0, 0 }, 6031da177e4SLinus Torvalds { SB_DSP4_MASTER_DEV + 1, 0 }, 6041da177e4SLinus Torvalds { SB_DSP4_PCM_DEV + 0, 0 }, 6051da177e4SLinus Torvalds { SB_DSP4_PCM_DEV + 1, 0 }, 6061da177e4SLinus Torvalds { SB_DSP4_SYNTH_DEV + 0, 0 }, 6071da177e4SLinus Torvalds { SB_DSP4_SYNTH_DEV + 1, 0 }, 6081da177e4SLinus Torvalds { SB_DSP4_INPUT_LEFT, 0 }, 6091da177e4SLinus Torvalds { SB_DSP4_INPUT_RIGHT, 0 }, 6101da177e4SLinus Torvalds { SB_DSP4_OUTPUT_SW, 0 }, 6111da177e4SLinus Torvalds { SB_DSP4_SPEAKER_DEV, 0 }, 6121da177e4SLinus Torvalds }; 6131da177e4SLinus Torvalds 6141da177e4SLinus Torvalds /* 6151da177e4SLinus Torvalds * DT019x specific mixer elements 6161da177e4SLinus Torvalds */ 6171da177e4SLinus Torvalds static struct sbmix_elem snd_dt019x_ctl_master_play_vol = 6181da177e4SLinus Torvalds SB_DOUBLE("Master Playback Volume", SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4,0, 15); 6191da177e4SLinus Torvalds static struct sbmix_elem snd_dt019x_ctl_pcm_play_vol = 6201da177e4SLinus Torvalds SB_DOUBLE("PCM Playback Volume", SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4,0, 15); 6211da177e4SLinus Torvalds static struct sbmix_elem snd_dt019x_ctl_synth_play_vol = 6221da177e4SLinus Torvalds SB_DOUBLE("Synth Playback Volume", SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4,0, 15); 6231da177e4SLinus Torvalds static struct sbmix_elem snd_dt019x_ctl_cd_play_vol = 6241da177e4SLinus Torvalds SB_DOUBLE("CD Playback Volume", SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4,0, 15); 6251da177e4SLinus Torvalds static struct sbmix_elem snd_dt019x_ctl_mic_play_vol = 6261da177e4SLinus Torvalds SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7); 6271da177e4SLinus Torvalds static struct sbmix_elem snd_dt019x_ctl_pc_speaker_vol = 6281da177e4SLinus Torvalds SB_SINGLE("PC Speaker Volume", SB_DT019X_SPKR_DEV, 0, 7); 6291da177e4SLinus Torvalds static struct sbmix_elem snd_dt019x_ctl_line_play_vol = 6301da177e4SLinus Torvalds SB_DOUBLE("Line Playback Volume", SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4,0, 15); 6311da177e4SLinus Torvalds static struct sbmix_elem snd_dt019x_ctl_pcm_play_switch = 6321da177e4SLinus Torvalds SB_DOUBLE("PCM Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2,1, 1); 6331da177e4SLinus Torvalds static struct sbmix_elem snd_dt019x_ctl_synth_play_switch = 6341da177e4SLinus Torvalds SB_DOUBLE("Synth Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4,3, 1); 6351da177e4SLinus Torvalds static struct sbmix_elem snd_dt019x_ctl_capture_source = 6361da177e4SLinus Torvalds { 6371da177e4SLinus Torvalds .name = "Capture Source", 6381da177e4SLinus Torvalds .type = SB_MIX_CAPTURE_DT019X 6391da177e4SLinus Torvalds }; 6401da177e4SLinus Torvalds 6411da177e4SLinus Torvalds static struct sbmix_elem *snd_dt019x_controls[] = { 6421da177e4SLinus Torvalds &snd_dt019x_ctl_master_play_vol, 6431da177e4SLinus Torvalds &snd_dt019x_ctl_pcm_play_vol, 6441da177e4SLinus Torvalds &snd_dt019x_ctl_synth_play_vol, 6451da177e4SLinus Torvalds &snd_dt019x_ctl_cd_play_vol, 6461da177e4SLinus Torvalds &snd_dt019x_ctl_mic_play_vol, 6471da177e4SLinus Torvalds &snd_dt019x_ctl_pc_speaker_vol, 6481da177e4SLinus Torvalds &snd_dt019x_ctl_line_play_vol, 6491da177e4SLinus Torvalds &snd_sb16_ctl_mic_play_switch, 6501da177e4SLinus Torvalds &snd_sb16_ctl_cd_play_switch, 6511da177e4SLinus Torvalds &snd_sb16_ctl_line_play_switch, 6521da177e4SLinus Torvalds &snd_dt019x_ctl_pcm_play_switch, 6531da177e4SLinus Torvalds &snd_dt019x_ctl_synth_play_switch, 6541da177e4SLinus Torvalds &snd_dt019x_ctl_capture_source 6551da177e4SLinus Torvalds }; 6561da177e4SLinus Torvalds 6571da177e4SLinus Torvalds static unsigned char snd_dt019x_init_values[][2] = { 6581da177e4SLinus Torvalds { SB_DT019X_MASTER_DEV, 0 }, 6591da177e4SLinus Torvalds { SB_DT019X_PCM_DEV, 0 }, 6601da177e4SLinus Torvalds { SB_DT019X_SYNTH_DEV, 0 }, 6611da177e4SLinus Torvalds { SB_DT019X_CD_DEV, 0 }, 6621da177e4SLinus Torvalds { SB_DT019X_MIC_DEV, 0 }, /* Includes PC-speaker in high nibble */ 6631da177e4SLinus Torvalds { SB_DT019X_LINE_DEV, 0 }, 6641da177e4SLinus Torvalds { SB_DSP4_OUTPUT_SW, 0 }, 6651da177e4SLinus Torvalds { SB_DT019X_OUTPUT_SW2, 0 }, 6661da177e4SLinus Torvalds { SB_DT019X_CAPTURE_SW, 0x06 }, 6671da177e4SLinus Torvalds }; 6681da177e4SLinus Torvalds 6691da177e4SLinus Torvalds /* 6701da177e4SLinus Torvalds * ALS4000 specific mixer elements 6711da177e4SLinus Torvalds */ 6721da177e4SLinus Torvalds /* FIXME: SB_ALS4000_MONO_IO_CTRL needs output select ctrl ! */ 6731da177e4SLinus Torvalds static struct sbmix_elem snd_als4000_ctl_mono_output_switch = 6741da177e4SLinus Torvalds SB_SINGLE("Mono Output Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1); 6751da177e4SLinus Torvalds /* FIXME: mono input switch also available on DT019X ? */ 6761da177e4SLinus Torvalds static struct sbmix_elem snd_als4000_ctl_mono_input_switch = 6771da177e4SLinus Torvalds SB_SINGLE("Mono Input Switch", SB_DT019X_OUTPUT_SW2, 0, 1); 6781da177e4SLinus Torvalds static struct sbmix_elem snd_als4000_ctl_mic_20db_boost = 6791da177e4SLinus Torvalds SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03); 6801da177e4SLinus Torvalds static struct sbmix_elem snd_als4000_ctl_mixer_out_to_in = 6811da177e4SLinus Torvalds SB_SINGLE("Mixer Out To In", SB_ALS4000_MIC_IN_GAIN, 7, 0x01); 6821da177e4SLinus Torvalds /* FIXME: 3D needs much more sophisticated controls, many more features ! */ 6831da177e4SLinus Torvalds static struct sbmix_elem snd_als4000_ctl_3d_output_switch = 6841da177e4SLinus Torvalds SB_SINGLE("3D Output Switch", SB_ALS4000_3D_SND_FX, 6, 0x01); 6851da177e4SLinus Torvalds static struct sbmix_elem snd_als4000_ctl_3d_output_ratio = 6861da177e4SLinus Torvalds SB_SINGLE("3D Output Ratio", SB_ALS4000_3D_SND_FX, 0, 0x07); 6871da177e4SLinus Torvalds static struct sbmix_elem snd_als4000_ctl_3d_poweroff_switch = 6881da177e4SLinus Torvalds SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01); 6891da177e4SLinus Torvalds static struct sbmix_elem snd_als4000_ctl_3d_delay = 6901da177e4SLinus Torvalds SB_SINGLE("3D Delay", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f); 69144456d37SOlaf Hering #ifdef NOT_AVAILABLE 6921da177e4SLinus Torvalds static struct sbmix_elem snd_als4000_ctl_fmdac = 6931da177e4SLinus Torvalds SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01); 6941da177e4SLinus Torvalds static struct sbmix_elem snd_als4000_ctl_qsound = 6951da177e4SLinus Torvalds SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f); 6961da177e4SLinus Torvalds #endif 6971da177e4SLinus Torvalds 6981da177e4SLinus Torvalds static struct sbmix_elem *snd_als4000_controls[] = { 6991da177e4SLinus Torvalds &snd_sb16_ctl_master_play_vol, 7001da177e4SLinus Torvalds &snd_dt019x_ctl_pcm_play_switch, 7011da177e4SLinus Torvalds &snd_sb16_ctl_pcm_play_vol, 7021da177e4SLinus Torvalds &snd_sb16_ctl_synth_capture_route, 7031da177e4SLinus Torvalds &snd_dt019x_ctl_synth_play_switch, 7041da177e4SLinus Torvalds &snd_sb16_ctl_synth_play_vol, 7051da177e4SLinus Torvalds &snd_sb16_ctl_cd_capture_route, 7061da177e4SLinus Torvalds &snd_sb16_ctl_cd_play_switch, 7071da177e4SLinus Torvalds &snd_sb16_ctl_cd_play_vol, 7081da177e4SLinus Torvalds &snd_sb16_ctl_line_capture_route, 7091da177e4SLinus Torvalds &snd_sb16_ctl_line_play_switch, 7101da177e4SLinus Torvalds &snd_sb16_ctl_line_play_vol, 7111da177e4SLinus Torvalds &snd_sb16_ctl_mic_capture_route, 7121da177e4SLinus Torvalds &snd_als4000_ctl_mic_20db_boost, 7131da177e4SLinus Torvalds &snd_sb16_ctl_auto_mic_gain, 7141da177e4SLinus Torvalds &snd_sb16_ctl_mic_play_switch, 7151da177e4SLinus Torvalds &snd_sb16_ctl_mic_play_vol, 7161da177e4SLinus Torvalds &snd_sb16_ctl_pc_speaker_vol, 7171da177e4SLinus Torvalds &snd_sb16_ctl_capture_vol, 7181da177e4SLinus Torvalds &snd_sb16_ctl_play_vol, 7191da177e4SLinus Torvalds &snd_als4000_ctl_mono_output_switch, 7201da177e4SLinus Torvalds &snd_als4000_ctl_mono_input_switch, 7211da177e4SLinus Torvalds &snd_als4000_ctl_mixer_out_to_in, 7221da177e4SLinus Torvalds &snd_als4000_ctl_3d_output_switch, 7231da177e4SLinus Torvalds &snd_als4000_ctl_3d_output_ratio, 7241da177e4SLinus Torvalds &snd_als4000_ctl_3d_delay, 7251da177e4SLinus Torvalds &snd_als4000_ctl_3d_poweroff_switch, 72644456d37SOlaf Hering #ifdef NOT_AVAILABLE 7271da177e4SLinus Torvalds &snd_als4000_ctl_fmdac, 7281da177e4SLinus Torvalds &snd_als4000_ctl_qsound, 7291da177e4SLinus Torvalds #endif 7301da177e4SLinus Torvalds }; 7311da177e4SLinus Torvalds 7321da177e4SLinus Torvalds static unsigned char snd_als4000_init_values[][2] = { 7331da177e4SLinus Torvalds { SB_DSP4_MASTER_DEV + 0, 0 }, 7341da177e4SLinus Torvalds { SB_DSP4_MASTER_DEV + 1, 0 }, 7351da177e4SLinus Torvalds { SB_DSP4_PCM_DEV + 0, 0 }, 7361da177e4SLinus Torvalds { SB_DSP4_PCM_DEV + 1, 0 }, 7371da177e4SLinus Torvalds { SB_DSP4_SYNTH_DEV + 0, 0 }, 7381da177e4SLinus Torvalds { SB_DSP4_SYNTH_DEV + 1, 0 }, 7391da177e4SLinus Torvalds { SB_DSP4_SPEAKER_DEV, 0 }, 7401da177e4SLinus Torvalds { SB_DSP4_OUTPUT_SW, 0 }, 7411da177e4SLinus Torvalds { SB_DSP4_INPUT_LEFT, 0 }, 7421da177e4SLinus Torvalds { SB_DSP4_INPUT_RIGHT, 0 }, 7431da177e4SLinus Torvalds { SB_DT019X_OUTPUT_SW2, 0 }, 7441da177e4SLinus Torvalds { SB_ALS4000_MIC_IN_GAIN, 0 }, 7451da177e4SLinus Torvalds }; 7461da177e4SLinus Torvalds 7471da177e4SLinus Torvalds 7481da177e4SLinus Torvalds /* 7491da177e4SLinus Torvalds */ 7501da177e4SLinus Torvalds static int snd_sbmixer_init(sb_t *chip, 7511da177e4SLinus Torvalds struct sbmix_elem **controls, 7521da177e4SLinus Torvalds int controls_count, 7531da177e4SLinus Torvalds unsigned char map[][2], 7541da177e4SLinus Torvalds int map_count, 7551da177e4SLinus Torvalds char *name) 7561da177e4SLinus Torvalds { 7571da177e4SLinus Torvalds unsigned long flags; 7581da177e4SLinus Torvalds snd_card_t *card = chip->card; 7591da177e4SLinus Torvalds int idx, err; 7601da177e4SLinus Torvalds 7611da177e4SLinus Torvalds /* mixer reset */ 7621da177e4SLinus Torvalds spin_lock_irqsave(&chip->mixer_lock, flags); 7631da177e4SLinus Torvalds snd_sbmixer_write(chip, 0x00, 0x00); 7641da177e4SLinus Torvalds spin_unlock_irqrestore(&chip->mixer_lock, flags); 7651da177e4SLinus Torvalds 7661da177e4SLinus Torvalds /* mute and zero volume channels */ 7671da177e4SLinus Torvalds for (idx = 0; idx < map_count; idx++) { 7681da177e4SLinus Torvalds spin_lock_irqsave(&chip->mixer_lock, flags); 7691da177e4SLinus Torvalds snd_sbmixer_write(chip, map[idx][0], map[idx][1]); 7701da177e4SLinus Torvalds spin_unlock_irqrestore(&chip->mixer_lock, flags); 7711da177e4SLinus Torvalds } 7721da177e4SLinus Torvalds 7731da177e4SLinus Torvalds for (idx = 0; idx < controls_count; idx++) { 7741da177e4SLinus Torvalds if ((err = snd_sbmixer_add_ctl_elem(chip, controls[idx])) < 0) 7751da177e4SLinus Torvalds return err; 7761da177e4SLinus Torvalds } 7771da177e4SLinus Torvalds snd_component_add(card, name); 7781da177e4SLinus Torvalds strcpy(card->mixername, name); 7791da177e4SLinus Torvalds return 0; 7801da177e4SLinus Torvalds } 7811da177e4SLinus Torvalds 7821da177e4SLinus Torvalds int snd_sbmixer_new(sb_t *chip) 7831da177e4SLinus Torvalds { 7841da177e4SLinus Torvalds snd_card_t * card; 7851da177e4SLinus Torvalds int err; 7861da177e4SLinus Torvalds 7871da177e4SLinus Torvalds snd_assert(chip != NULL && chip->card != NULL, return -EINVAL); 7881da177e4SLinus Torvalds 7891da177e4SLinus Torvalds card = chip->card; 7901da177e4SLinus Torvalds 7911da177e4SLinus Torvalds switch (chip->hardware) { 7921da177e4SLinus Torvalds case SB_HW_10: 7931da177e4SLinus Torvalds return 0; /* no mixer chip on SB1.x */ 7941da177e4SLinus Torvalds case SB_HW_20: 7951da177e4SLinus Torvalds case SB_HW_201: 7961da177e4SLinus Torvalds if ((err = snd_sbmixer_init(chip, 7971da177e4SLinus Torvalds snd_sb20_controls, 7981da177e4SLinus Torvalds ARRAY_SIZE(snd_sb20_controls), 7991da177e4SLinus Torvalds snd_sb20_init_values, 8001da177e4SLinus Torvalds ARRAY_SIZE(snd_sb20_init_values), 8011da177e4SLinus Torvalds "CTL1335")) < 0) 8021da177e4SLinus Torvalds return err; 8031da177e4SLinus Torvalds break; 8041da177e4SLinus Torvalds case SB_HW_PRO: 8051da177e4SLinus Torvalds if ((err = snd_sbmixer_init(chip, 8061da177e4SLinus Torvalds snd_sbpro_controls, 8071da177e4SLinus Torvalds ARRAY_SIZE(snd_sbpro_controls), 8081da177e4SLinus Torvalds snd_sbpro_init_values, 8091da177e4SLinus Torvalds ARRAY_SIZE(snd_sbpro_init_values), 8101da177e4SLinus Torvalds "CTL1345")) < 0) 8111da177e4SLinus Torvalds return err; 8121da177e4SLinus Torvalds break; 8131da177e4SLinus Torvalds case SB_HW_16: 8141da177e4SLinus Torvalds case SB_HW_ALS100: 8151da177e4SLinus Torvalds if ((err = snd_sbmixer_init(chip, 8161da177e4SLinus Torvalds snd_sb16_controls, 8171da177e4SLinus Torvalds ARRAY_SIZE(snd_sb16_controls), 8181da177e4SLinus Torvalds snd_sb16_init_values, 8191da177e4SLinus Torvalds ARRAY_SIZE(snd_sb16_init_values), 8201da177e4SLinus Torvalds "CTL1745")) < 0) 8211da177e4SLinus Torvalds return err; 8221da177e4SLinus Torvalds break; 8231da177e4SLinus Torvalds case SB_HW_ALS4000: 8241da177e4SLinus Torvalds if ((err = snd_sbmixer_init(chip, 8251da177e4SLinus Torvalds snd_als4000_controls, 8261da177e4SLinus Torvalds ARRAY_SIZE(snd_als4000_controls), 8271da177e4SLinus Torvalds snd_als4000_init_values, 8281da177e4SLinus Torvalds ARRAY_SIZE(snd_als4000_init_values), 8291da177e4SLinus Torvalds "ALS4000")) < 0) 8301da177e4SLinus Torvalds return err; 8311da177e4SLinus Torvalds break; 8321da177e4SLinus Torvalds case SB_HW_DT019X: 8331da177e4SLinus Torvalds if ((err = snd_sbmixer_init(chip, 8341da177e4SLinus Torvalds snd_dt019x_controls, 8351da177e4SLinus Torvalds ARRAY_SIZE(snd_dt019x_controls), 8361da177e4SLinus Torvalds snd_dt019x_init_values, 8371da177e4SLinus Torvalds ARRAY_SIZE(snd_dt019x_init_values), 8381da177e4SLinus Torvalds "DT019X")) < 0) 8391da177e4SLinus Torvalds break; 8401da177e4SLinus Torvalds default: 8411da177e4SLinus Torvalds strcpy(card->mixername, "???"); 8421da177e4SLinus Torvalds } 8431da177e4SLinus Torvalds return 0; 8441da177e4SLinus Torvalds } 845