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 32029d64b0STakashi Iwai void snd_sbmixer_write(struct snd_sb *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 3999b359baSTakashi Iwai snd_printk(KERN_DEBUG "mixer_write 0x%x 0x%x\n", reg, data); 401da177e4SLinus Torvalds #endif 411da177e4SLinus Torvalds } 421da177e4SLinus Torvalds 43029d64b0STakashi Iwai unsigned char snd_sbmixer_read(struct snd_sb *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 5299b359baSTakashi Iwai snd_printk(KERN_DEBUG "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 61029d64b0STakashi Iwai static int snd_sbmixer_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *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 72029d64b0STakashi Iwai static int snd_sbmixer_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 731da177e4SLinus Torvalds { 74029d64b0STakashi Iwai struct snd_sb *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 88029d64b0STakashi Iwai static int snd_sbmixer_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 891da177e4SLinus Torvalds { 90029d64b0STakashi Iwai struct snd_sb *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 113029d64b0STakashi Iwai static int snd_sbmixer_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *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 124029d64b0STakashi Iwai static int snd_sbmixer_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 1251da177e4SLinus Torvalds { 126029d64b0STakashi Iwai struct snd_sb *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 144029d64b0STakashi Iwai static int snd_sbmixer_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 1451da177e4SLinus Torvalds { 146029d64b0STakashi Iwai struct snd_sb *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 184029d64b0STakashi Iwai static int snd_dt019x_input_sw_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *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 199029d64b0STakashi Iwai static int snd_dt019x_input_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 2001da177e4SLinus Torvalds { 201029d64b0STakashi Iwai struct snd_sb *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 235029d64b0STakashi Iwai static int snd_dt019x_input_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 2361da177e4SLinus Torvalds { 237029d64b0STakashi Iwai struct snd_sb *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 276029d64b0STakashi Iwai static int snd_sb8mixer_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *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 292029d64b0STakashi Iwai static int snd_sb8mixer_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 2931da177e4SLinus Torvalds { 294029d64b0STakashi Iwai struct snd_sb *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 315029d64b0STakashi Iwai static int snd_sb8mixer_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 3161da177e4SLinus Torvalds { 317029d64b0STakashi Iwai struct snd_sb *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 349029d64b0STakashi Iwai static int snd_sb16mixer_info_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *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 358029d64b0STakashi Iwai static int snd_sb16mixer_get_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 3591da177e4SLinus Torvalds { 360029d64b0STakashi Iwai struct snd_sb *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 379029d64b0STakashi Iwai static int snd_sb16mixer_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 3801da177e4SLinus Torvalds { 381029d64b0STakashi Iwai struct snd_sb *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 */ 413029d64b0STakashi Iwai int snd_sbmixer_add_ctl(struct snd_sb *chip, const char *name, int index, int type, unsigned long value) 4141da177e4SLinus Torvalds { 415029d64b0STakashi Iwai static struct snd_kcontrol_new 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 }; 447029d64b0STakashi Iwai struct snd_kcontrol *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! */ 673ba7301c7SAndreas Mohr static struct sbmix_elem snd_als4000_ctl_master_mono_playback_switch = 674ba7301c7SAndreas Mohr SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1); 675ba7301c7SAndreas Mohr static struct sbmix_elem snd_als4000_ctl_master_mono_capture_route = 676ba7301c7SAndreas Mohr SB_SINGLE("Master Mono Capture Route", SB_ALS4000_MONO_IO_CTRL, 6, 0x03); 677ba7301c7SAndreas Mohr /* FIXME: mono playback switch also available on DT019X? */ 678ba7301c7SAndreas Mohr static struct sbmix_elem snd_als4000_ctl_mono_playback_switch = 679ba7301c7SAndreas Mohr SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2, 0, 1); 6801da177e4SLinus Torvalds static struct sbmix_elem snd_als4000_ctl_mic_20db_boost = 6811da177e4SLinus Torvalds SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03); 682ba7301c7SAndreas Mohr static struct sbmix_elem snd_als4000_ctl_mixer_loopback = 683ba7301c7SAndreas Mohr SB_SINGLE("Analog Loopback", SB_ALS4000_MIC_IN_GAIN, 7, 0x01); 684ba7301c7SAndreas Mohr /* FIXME: functionality of 3D controls might be swapped, I didn't find 685ba7301c7SAndreas Mohr * a description of how to identify what is supposed to be what */ 686ba7301c7SAndreas Mohr static struct sbmix_elem snd_als4000_3d_control_switch = 687ba7301c7SAndreas Mohr SB_SINGLE("3D Control - Switch", SB_ALS4000_3D_SND_FX, 6, 0x01); 688ba7301c7SAndreas Mohr static struct sbmix_elem snd_als4000_3d_control_ratio = 689ba7301c7SAndreas Mohr SB_SINGLE("3D Control - Level", SB_ALS4000_3D_SND_FX, 0, 0x07); 690ba7301c7SAndreas Mohr static struct sbmix_elem snd_als4000_3d_control_freq = 691ba7301c7SAndreas Mohr /* FIXME: maybe there's actually some standard 3D ctrl name for it?? */ 692ba7301c7SAndreas Mohr SB_SINGLE("3D Control - Freq", SB_ALS4000_3D_SND_FX, 4, 0x03); 693ba7301c7SAndreas Mohr static struct sbmix_elem snd_als4000_3d_control_delay = 694ba7301c7SAndreas Mohr /* FIXME: ALS4000a.pdf mentions BBD (Bucket Brigade Device) time delay, 695ba7301c7SAndreas Mohr * but what ALSA 3D attribute is that actually? "Center", "Depth", 696ba7301c7SAndreas Mohr * "Wide" or "Space" or even "Level"? Assuming "Wide" for now... */ 697ba7301c7SAndreas Mohr SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f); 698ba7301c7SAndreas Mohr static struct sbmix_elem snd_als4000_3d_control_poweroff_switch = 6991da177e4SLinus Torvalds SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01); 70044456d37SOlaf Hering #ifdef NOT_AVAILABLE 7011da177e4SLinus Torvalds static struct sbmix_elem snd_als4000_ctl_fmdac = 7021da177e4SLinus Torvalds SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01); 7031da177e4SLinus Torvalds static struct sbmix_elem snd_als4000_ctl_qsound = 7041da177e4SLinus Torvalds SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f); 7051da177e4SLinus Torvalds #endif 7061da177e4SLinus Torvalds 7071da177e4SLinus Torvalds static struct sbmix_elem *snd_als4000_controls[] = { 7081da177e4SLinus Torvalds &snd_sb16_ctl_master_play_vol, 7091da177e4SLinus Torvalds &snd_dt019x_ctl_pcm_play_switch, 7101da177e4SLinus Torvalds &snd_sb16_ctl_pcm_play_vol, 7111da177e4SLinus Torvalds &snd_sb16_ctl_synth_capture_route, 7121da177e4SLinus Torvalds &snd_dt019x_ctl_synth_play_switch, 7131da177e4SLinus Torvalds &snd_sb16_ctl_synth_play_vol, 7141da177e4SLinus Torvalds &snd_sb16_ctl_cd_capture_route, 7151da177e4SLinus Torvalds &snd_sb16_ctl_cd_play_switch, 7161da177e4SLinus Torvalds &snd_sb16_ctl_cd_play_vol, 7171da177e4SLinus Torvalds &snd_sb16_ctl_line_capture_route, 7181da177e4SLinus Torvalds &snd_sb16_ctl_line_play_switch, 7191da177e4SLinus Torvalds &snd_sb16_ctl_line_play_vol, 7201da177e4SLinus Torvalds &snd_sb16_ctl_mic_capture_route, 7211da177e4SLinus Torvalds &snd_als4000_ctl_mic_20db_boost, 7221da177e4SLinus Torvalds &snd_sb16_ctl_auto_mic_gain, 7231da177e4SLinus Torvalds &snd_sb16_ctl_mic_play_switch, 7241da177e4SLinus Torvalds &snd_sb16_ctl_mic_play_vol, 7251da177e4SLinus Torvalds &snd_sb16_ctl_pc_speaker_vol, 7261da177e4SLinus Torvalds &snd_sb16_ctl_capture_vol, 7271da177e4SLinus Torvalds &snd_sb16_ctl_play_vol, 728ba7301c7SAndreas Mohr &snd_als4000_ctl_master_mono_playback_switch, 729ba7301c7SAndreas Mohr &snd_als4000_ctl_master_mono_capture_route, 730ba7301c7SAndreas Mohr &snd_als4000_ctl_mono_playback_switch, 731ba7301c7SAndreas Mohr &snd_als4000_ctl_mixer_loopback, 732ba7301c7SAndreas Mohr &snd_als4000_3d_control_switch, 733ba7301c7SAndreas Mohr &snd_als4000_3d_control_ratio, 734ba7301c7SAndreas Mohr &snd_als4000_3d_control_freq, 735ba7301c7SAndreas Mohr &snd_als4000_3d_control_delay, 736ba7301c7SAndreas Mohr &snd_als4000_3d_control_poweroff_switch, 73744456d37SOlaf Hering #ifdef NOT_AVAILABLE 7381da177e4SLinus Torvalds &snd_als4000_ctl_fmdac, 7391da177e4SLinus Torvalds &snd_als4000_ctl_qsound, 7401da177e4SLinus Torvalds #endif 7411da177e4SLinus Torvalds }; 7421da177e4SLinus Torvalds 7431da177e4SLinus Torvalds static unsigned char snd_als4000_init_values[][2] = { 7441da177e4SLinus Torvalds { SB_DSP4_MASTER_DEV + 0, 0 }, 7451da177e4SLinus Torvalds { SB_DSP4_MASTER_DEV + 1, 0 }, 7461da177e4SLinus Torvalds { SB_DSP4_PCM_DEV + 0, 0 }, 7471da177e4SLinus Torvalds { SB_DSP4_PCM_DEV + 1, 0 }, 7481da177e4SLinus Torvalds { SB_DSP4_SYNTH_DEV + 0, 0 }, 7491da177e4SLinus Torvalds { SB_DSP4_SYNTH_DEV + 1, 0 }, 7501da177e4SLinus Torvalds { SB_DSP4_SPEAKER_DEV, 0 }, 7511da177e4SLinus Torvalds { SB_DSP4_OUTPUT_SW, 0 }, 7521da177e4SLinus Torvalds { SB_DSP4_INPUT_LEFT, 0 }, 7531da177e4SLinus Torvalds { SB_DSP4_INPUT_RIGHT, 0 }, 7541da177e4SLinus Torvalds { SB_DT019X_OUTPUT_SW2, 0 }, 7551da177e4SLinus Torvalds { SB_ALS4000_MIC_IN_GAIN, 0 }, 7561da177e4SLinus Torvalds }; 7571da177e4SLinus Torvalds 7581da177e4SLinus Torvalds 7591da177e4SLinus Torvalds /* 7601da177e4SLinus Torvalds */ 761029d64b0STakashi Iwai static int snd_sbmixer_init(struct snd_sb *chip, 7621da177e4SLinus Torvalds struct sbmix_elem **controls, 7631da177e4SLinus Torvalds int controls_count, 7641da177e4SLinus Torvalds unsigned char map[][2], 7651da177e4SLinus Torvalds int map_count, 7661da177e4SLinus Torvalds char *name) 7671da177e4SLinus Torvalds { 7681da177e4SLinus Torvalds unsigned long flags; 769029d64b0STakashi Iwai struct snd_card *card = chip->card; 7701da177e4SLinus Torvalds int idx, err; 7711da177e4SLinus Torvalds 7721da177e4SLinus Torvalds /* mixer reset */ 7731da177e4SLinus Torvalds spin_lock_irqsave(&chip->mixer_lock, flags); 7741da177e4SLinus Torvalds snd_sbmixer_write(chip, 0x00, 0x00); 7751da177e4SLinus Torvalds spin_unlock_irqrestore(&chip->mixer_lock, flags); 7761da177e4SLinus Torvalds 7771da177e4SLinus Torvalds /* mute and zero volume channels */ 7781da177e4SLinus Torvalds for (idx = 0; idx < map_count; idx++) { 7791da177e4SLinus Torvalds spin_lock_irqsave(&chip->mixer_lock, flags); 7801da177e4SLinus Torvalds snd_sbmixer_write(chip, map[idx][0], map[idx][1]); 7811da177e4SLinus Torvalds spin_unlock_irqrestore(&chip->mixer_lock, flags); 7821da177e4SLinus Torvalds } 7831da177e4SLinus Torvalds 7841da177e4SLinus Torvalds for (idx = 0; idx < controls_count; idx++) { 7851da177e4SLinus Torvalds if ((err = snd_sbmixer_add_ctl_elem(chip, controls[idx])) < 0) 7861da177e4SLinus Torvalds return err; 7871da177e4SLinus Torvalds } 7881da177e4SLinus Torvalds snd_component_add(card, name); 7891da177e4SLinus Torvalds strcpy(card->mixername, name); 7901da177e4SLinus Torvalds return 0; 7911da177e4SLinus Torvalds } 7921da177e4SLinus Torvalds 793029d64b0STakashi Iwai int snd_sbmixer_new(struct snd_sb *chip) 7941da177e4SLinus Torvalds { 795029d64b0STakashi Iwai struct snd_card *card; 7961da177e4SLinus Torvalds int err; 7971da177e4SLinus Torvalds 7981da177e4SLinus Torvalds snd_assert(chip != NULL && chip->card != NULL, return -EINVAL); 7991da177e4SLinus Torvalds 8001da177e4SLinus Torvalds card = chip->card; 8011da177e4SLinus Torvalds 8021da177e4SLinus Torvalds switch (chip->hardware) { 8031da177e4SLinus Torvalds case SB_HW_10: 8041da177e4SLinus Torvalds return 0; /* no mixer chip on SB1.x */ 8051da177e4SLinus Torvalds case SB_HW_20: 8061da177e4SLinus Torvalds case SB_HW_201: 8071da177e4SLinus Torvalds if ((err = snd_sbmixer_init(chip, 8081da177e4SLinus Torvalds snd_sb20_controls, 8091da177e4SLinus Torvalds ARRAY_SIZE(snd_sb20_controls), 8101da177e4SLinus Torvalds snd_sb20_init_values, 8111da177e4SLinus Torvalds ARRAY_SIZE(snd_sb20_init_values), 8121da177e4SLinus Torvalds "CTL1335")) < 0) 8131da177e4SLinus Torvalds return err; 8141da177e4SLinus Torvalds break; 8151da177e4SLinus Torvalds case SB_HW_PRO: 8161da177e4SLinus Torvalds if ((err = snd_sbmixer_init(chip, 8171da177e4SLinus Torvalds snd_sbpro_controls, 8181da177e4SLinus Torvalds ARRAY_SIZE(snd_sbpro_controls), 8191da177e4SLinus Torvalds snd_sbpro_init_values, 8201da177e4SLinus Torvalds ARRAY_SIZE(snd_sbpro_init_values), 8211da177e4SLinus Torvalds "CTL1345")) < 0) 8221da177e4SLinus Torvalds return err; 8231da177e4SLinus Torvalds break; 8241da177e4SLinus Torvalds case SB_HW_16: 8251da177e4SLinus Torvalds case SB_HW_ALS100: 8261da177e4SLinus Torvalds if ((err = snd_sbmixer_init(chip, 8271da177e4SLinus Torvalds snd_sb16_controls, 8281da177e4SLinus Torvalds ARRAY_SIZE(snd_sb16_controls), 8291da177e4SLinus Torvalds snd_sb16_init_values, 8301da177e4SLinus Torvalds ARRAY_SIZE(snd_sb16_init_values), 8311da177e4SLinus Torvalds "CTL1745")) < 0) 8321da177e4SLinus Torvalds return err; 8331da177e4SLinus Torvalds break; 8341da177e4SLinus Torvalds case SB_HW_ALS4000: 8351da177e4SLinus Torvalds if ((err = snd_sbmixer_init(chip, 8361da177e4SLinus Torvalds snd_als4000_controls, 8371da177e4SLinus Torvalds ARRAY_SIZE(snd_als4000_controls), 8381da177e4SLinus Torvalds snd_als4000_init_values, 8391da177e4SLinus Torvalds ARRAY_SIZE(snd_als4000_init_values), 8401da177e4SLinus Torvalds "ALS4000")) < 0) 8411da177e4SLinus Torvalds return err; 8421da177e4SLinus Torvalds break; 8431da177e4SLinus Torvalds case SB_HW_DT019X: 8441da177e4SLinus Torvalds if ((err = snd_sbmixer_init(chip, 8451da177e4SLinus Torvalds snd_dt019x_controls, 8461da177e4SLinus Torvalds ARRAY_SIZE(snd_dt019x_controls), 8471da177e4SLinus Torvalds snd_dt019x_init_values, 8481da177e4SLinus Torvalds ARRAY_SIZE(snd_dt019x_init_values), 8491da177e4SLinus Torvalds "DT019X")) < 0) 8501da177e4SLinus Torvalds break; 8511da177e4SLinus Torvalds default: 8521da177e4SLinus Torvalds strcpy(card->mixername, "???"); 8531da177e4SLinus Torvalds } 8541da177e4SLinus Torvalds return 0; 8551da177e4SLinus Torvalds } 8565bdb6a16STakashi Iwai 8575bdb6a16STakashi Iwai #ifdef CONFIG_PM 8585bdb6a16STakashi Iwai static unsigned char sb20_saved_regs[] = { 8595bdb6a16STakashi Iwai SB_DSP20_MASTER_DEV, 8605bdb6a16STakashi Iwai SB_DSP20_PCM_DEV, 8615bdb6a16STakashi Iwai SB_DSP20_FM_DEV, 8625bdb6a16STakashi Iwai SB_DSP20_CD_DEV, 8635bdb6a16STakashi Iwai }; 8645bdb6a16STakashi Iwai 8655bdb6a16STakashi Iwai static unsigned char sbpro_saved_regs[] = { 8665bdb6a16STakashi Iwai SB_DSP_MASTER_DEV, 8675bdb6a16STakashi Iwai SB_DSP_PCM_DEV, 8685bdb6a16STakashi Iwai SB_DSP_PLAYBACK_FILT, 8695bdb6a16STakashi Iwai SB_DSP_FM_DEV, 8705bdb6a16STakashi Iwai SB_DSP_CD_DEV, 8715bdb6a16STakashi Iwai SB_DSP_LINE_DEV, 8725bdb6a16STakashi Iwai SB_DSP_MIC_DEV, 8735bdb6a16STakashi Iwai SB_DSP_CAPTURE_SOURCE, 8745bdb6a16STakashi Iwai SB_DSP_CAPTURE_FILT, 8755bdb6a16STakashi Iwai }; 8765bdb6a16STakashi Iwai 8775bdb6a16STakashi Iwai static unsigned char sb16_saved_regs[] = { 8785bdb6a16STakashi Iwai SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1, 8795bdb6a16STakashi Iwai SB_DSP4_3DSE, 8805bdb6a16STakashi Iwai SB_DSP4_BASS_DEV, SB_DSP4_BASS_DEV + 1, 8815bdb6a16STakashi Iwai SB_DSP4_TREBLE_DEV, SB_DSP4_TREBLE_DEV + 1, 8825bdb6a16STakashi Iwai SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1, 8835bdb6a16STakashi Iwai SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 8845bdb6a16STakashi Iwai SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1, 8855bdb6a16STakashi Iwai SB_DSP4_OUTPUT_SW, 8865bdb6a16STakashi Iwai SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1, 8875bdb6a16STakashi Iwai SB_DSP4_LINE_DEV, SB_DSP4_LINE_DEV + 1, 8885bdb6a16STakashi Iwai SB_DSP4_MIC_DEV, 8895bdb6a16STakashi Iwai SB_DSP4_SPEAKER_DEV, 8905bdb6a16STakashi Iwai SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1, 8915bdb6a16STakashi Iwai SB_DSP4_OGAIN_DEV, SB_DSP4_OGAIN_DEV + 1, 8925bdb6a16STakashi Iwai SB_DSP4_MIC_AGC 8935bdb6a16STakashi Iwai }; 8945bdb6a16STakashi Iwai 8955bdb6a16STakashi Iwai static unsigned char dt019x_saved_regs[] = { 8965bdb6a16STakashi Iwai SB_DT019X_MASTER_DEV, 8975bdb6a16STakashi Iwai SB_DT019X_PCM_DEV, 8985bdb6a16STakashi Iwai SB_DT019X_SYNTH_DEV, 8995bdb6a16STakashi Iwai SB_DT019X_CD_DEV, 9005bdb6a16STakashi Iwai SB_DT019X_MIC_DEV, 9015bdb6a16STakashi Iwai SB_DT019X_SPKR_DEV, 9025bdb6a16STakashi Iwai SB_DT019X_LINE_DEV, 9035bdb6a16STakashi Iwai SB_DSP4_OUTPUT_SW, 9045bdb6a16STakashi Iwai SB_DT019X_OUTPUT_SW2, 9055bdb6a16STakashi Iwai SB_DT019X_CAPTURE_SW, 9065bdb6a16STakashi Iwai }; 9075bdb6a16STakashi Iwai 9085bdb6a16STakashi Iwai static unsigned char als4000_saved_regs[] = { 9095bdb6a16STakashi Iwai SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1, 9105bdb6a16STakashi Iwai SB_DSP4_OUTPUT_SW, 9115bdb6a16STakashi Iwai SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1, 9125bdb6a16STakashi Iwai SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 9135bdb6a16STakashi Iwai SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1, 9145bdb6a16STakashi Iwai SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1, 9155bdb6a16STakashi Iwai SB_DSP4_MIC_AGC, 9165bdb6a16STakashi Iwai SB_DSP4_MIC_DEV, 9175bdb6a16STakashi Iwai SB_DSP4_SPEAKER_DEV, 9185bdb6a16STakashi Iwai SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1, 9195bdb6a16STakashi Iwai SB_DSP4_OGAIN_DEV, SB_DSP4_OGAIN_DEV + 1, 9205bdb6a16STakashi Iwai SB_DT019X_OUTPUT_SW2, 9215bdb6a16STakashi Iwai SB_ALS4000_MONO_IO_CTRL, 9225bdb6a16STakashi Iwai SB_ALS4000_MIC_IN_GAIN, 9235bdb6a16STakashi Iwai SB_ALS4000_3D_SND_FX, 9245bdb6a16STakashi Iwai SB_ALS4000_3D_TIME_DELAY, 9255bdb6a16STakashi Iwai }; 9265bdb6a16STakashi Iwai 9275bdb6a16STakashi Iwai static void save_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs) 9285bdb6a16STakashi Iwai { 9295bdb6a16STakashi Iwai unsigned char *val = chip->saved_regs; 9305bdb6a16STakashi Iwai snd_assert(num_regs > ARRAY_SIZE(chip->saved_regs), return); 9315bdb6a16STakashi Iwai for (; num_regs; num_regs--) 9325bdb6a16STakashi Iwai *val++ = snd_sbmixer_read(chip, *regs++); 9335bdb6a16STakashi Iwai } 9345bdb6a16STakashi Iwai 9355bdb6a16STakashi Iwai static void restore_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs) 9365bdb6a16STakashi Iwai { 9375bdb6a16STakashi Iwai unsigned char *val = chip->saved_regs; 9385bdb6a16STakashi Iwai snd_assert(num_regs > ARRAY_SIZE(chip->saved_regs), return); 9395bdb6a16STakashi Iwai for (; num_regs; num_regs--) 9405bdb6a16STakashi Iwai snd_sbmixer_write(chip, *regs++, *val++); 9415bdb6a16STakashi Iwai } 9425bdb6a16STakashi Iwai 9435bdb6a16STakashi Iwai void snd_sbmixer_suspend(struct snd_sb *chip) 9445bdb6a16STakashi Iwai { 9455bdb6a16STakashi Iwai switch (chip->hardware) { 9465bdb6a16STakashi Iwai case SB_HW_20: 9475bdb6a16STakashi Iwai case SB_HW_201: 9485bdb6a16STakashi Iwai save_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs)); 9495bdb6a16STakashi Iwai break; 9505bdb6a16STakashi Iwai case SB_HW_PRO: 9515bdb6a16STakashi Iwai save_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs)); 9525bdb6a16STakashi Iwai break; 9535bdb6a16STakashi Iwai case SB_HW_16: 9545bdb6a16STakashi Iwai case SB_HW_ALS100: 9555bdb6a16STakashi Iwai save_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs)); 9565bdb6a16STakashi Iwai break; 9575bdb6a16STakashi Iwai case SB_HW_ALS4000: 9585bdb6a16STakashi Iwai save_mixer(chip, als4000_saved_regs, ARRAY_SIZE(als4000_saved_regs)); 9595bdb6a16STakashi Iwai break; 9605bdb6a16STakashi Iwai case SB_HW_DT019X: 9615bdb6a16STakashi Iwai save_mixer(chip, dt019x_saved_regs, ARRAY_SIZE(dt019x_saved_regs)); 9625bdb6a16STakashi Iwai break; 9635bdb6a16STakashi Iwai default: 9645bdb6a16STakashi Iwai break; 9655bdb6a16STakashi Iwai } 9665bdb6a16STakashi Iwai } 9675bdb6a16STakashi Iwai 9685bdb6a16STakashi Iwai void snd_sbmixer_resume(struct snd_sb *chip) 9695bdb6a16STakashi Iwai { 9705bdb6a16STakashi Iwai switch (chip->hardware) { 9715bdb6a16STakashi Iwai case SB_HW_20: 9725bdb6a16STakashi Iwai case SB_HW_201: 9735bdb6a16STakashi Iwai restore_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs)); 9745bdb6a16STakashi Iwai break; 9755bdb6a16STakashi Iwai case SB_HW_PRO: 9765bdb6a16STakashi Iwai restore_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs)); 9775bdb6a16STakashi Iwai break; 9785bdb6a16STakashi Iwai case SB_HW_16: 9795bdb6a16STakashi Iwai case SB_HW_ALS100: 9805bdb6a16STakashi Iwai restore_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs)); 9815bdb6a16STakashi Iwai break; 9825bdb6a16STakashi Iwai case SB_HW_ALS4000: 9835bdb6a16STakashi Iwai restore_mixer(chip, als4000_saved_regs, ARRAY_SIZE(als4000_saved_regs)); 9845bdb6a16STakashi Iwai break; 9855bdb6a16STakashi Iwai case SB_HW_DT019X: 9865bdb6a16STakashi Iwai restore_mixer(chip, dt019x_saved_regs, ARRAY_SIZE(dt019x_saved_regs)); 9875bdb6a16STakashi Iwai break; 9885bdb6a16STakashi Iwai default: 9895bdb6a16STakashi Iwai break; 9905bdb6a16STakashi Iwai } 9915bdb6a16STakashi Iwai } 9925bdb6a16STakashi Iwai #endif 993