11da177e4SLinus Torvalds /* 2c1017a4cSJaroslav Kysela * Copyright (c) by Jaroslav Kysela <perex@perex.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 <asm/io.h> 231da177e4SLinus Torvalds #include <linux/delay.h> 241da177e4SLinus Torvalds #include <linux/time.h> 251da177e4SLinus Torvalds #include <sound/core.h> 261da177e4SLinus Torvalds #include <sound/sb.h> 271da177e4SLinus Torvalds #include <sound/control.h> 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds #undef IO_DEBUG 301da177e4SLinus Torvalds 31029d64b0STakashi Iwai void snd_sbmixer_write(struct snd_sb *chip, unsigned char reg, unsigned char data) 321da177e4SLinus Torvalds { 331da177e4SLinus Torvalds outb(reg, SBP(chip, MIXER_ADDR)); 341da177e4SLinus Torvalds udelay(10); 351da177e4SLinus Torvalds outb(data, SBP(chip, MIXER_DATA)); 361da177e4SLinus Torvalds udelay(10); 371da177e4SLinus Torvalds #ifdef IO_DEBUG 3899b359baSTakashi Iwai snd_printk(KERN_DEBUG "mixer_write 0x%x 0x%x\n", reg, data); 391da177e4SLinus Torvalds #endif 401da177e4SLinus Torvalds } 411da177e4SLinus Torvalds 42029d64b0STakashi Iwai unsigned char snd_sbmixer_read(struct snd_sb *chip, unsigned char reg) 431da177e4SLinus Torvalds { 441da177e4SLinus Torvalds unsigned char result; 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds outb(reg, SBP(chip, MIXER_ADDR)); 471da177e4SLinus Torvalds udelay(10); 481da177e4SLinus Torvalds result = inb(SBP(chip, MIXER_DATA)); 491da177e4SLinus Torvalds udelay(10); 501da177e4SLinus Torvalds #ifdef IO_DEBUG 5199b359baSTakashi Iwai snd_printk(KERN_DEBUG "mixer_read 0x%x 0x%x\n", reg, result); 521da177e4SLinus Torvalds #endif 531da177e4SLinus Torvalds return result; 541da177e4SLinus Torvalds } 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds /* 571da177e4SLinus Torvalds * Single channel mixer element 581da177e4SLinus Torvalds */ 591da177e4SLinus Torvalds 60029d64b0STakashi Iwai static int snd_sbmixer_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 611da177e4SLinus Torvalds { 621da177e4SLinus Torvalds int mask = (kcontrol->private_value >> 24) & 0xff; 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; 651da177e4SLinus Torvalds uinfo->count = 1; 661da177e4SLinus Torvalds uinfo->value.integer.min = 0; 671da177e4SLinus Torvalds uinfo->value.integer.max = mask; 681da177e4SLinus Torvalds return 0; 691da177e4SLinus Torvalds } 701da177e4SLinus Torvalds 71029d64b0STakashi Iwai static int snd_sbmixer_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 721da177e4SLinus Torvalds { 73029d64b0STakashi Iwai struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 741da177e4SLinus Torvalds unsigned long flags; 751da177e4SLinus Torvalds int reg = kcontrol->private_value & 0xff; 761da177e4SLinus Torvalds int shift = (kcontrol->private_value >> 16) & 0xff; 771da177e4SLinus Torvalds int mask = (kcontrol->private_value >> 24) & 0xff; 781da177e4SLinus Torvalds unsigned char val; 791da177e4SLinus Torvalds 801da177e4SLinus Torvalds spin_lock_irqsave(&sb->mixer_lock, flags); 811da177e4SLinus Torvalds val = (snd_sbmixer_read(sb, reg) >> shift) & mask; 821da177e4SLinus Torvalds spin_unlock_irqrestore(&sb->mixer_lock, flags); 831da177e4SLinus Torvalds ucontrol->value.integer.value[0] = val; 841da177e4SLinus Torvalds return 0; 851da177e4SLinus Torvalds } 861da177e4SLinus Torvalds 87029d64b0STakashi Iwai static int snd_sbmixer_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 881da177e4SLinus Torvalds { 89029d64b0STakashi Iwai struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 901da177e4SLinus Torvalds unsigned long flags; 911da177e4SLinus Torvalds int reg = kcontrol->private_value & 0xff; 921da177e4SLinus Torvalds int shift = (kcontrol->private_value >> 16) & 0x07; 931da177e4SLinus Torvalds int mask = (kcontrol->private_value >> 24) & 0xff; 941da177e4SLinus Torvalds int change; 951da177e4SLinus Torvalds unsigned char val, oval; 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds val = (ucontrol->value.integer.value[0] & mask) << shift; 981da177e4SLinus Torvalds spin_lock_irqsave(&sb->mixer_lock, flags); 991da177e4SLinus Torvalds oval = snd_sbmixer_read(sb, reg); 1001da177e4SLinus Torvalds val = (oval & ~(mask << shift)) | val; 1011da177e4SLinus Torvalds change = val != oval; 1021da177e4SLinus Torvalds if (change) 1031da177e4SLinus Torvalds snd_sbmixer_write(sb, reg, val); 1041da177e4SLinus Torvalds spin_unlock_irqrestore(&sb->mixer_lock, flags); 1051da177e4SLinus Torvalds return change; 1061da177e4SLinus Torvalds } 1071da177e4SLinus Torvalds 1081da177e4SLinus Torvalds /* 1091da177e4SLinus Torvalds * Double channel mixer element 1101da177e4SLinus Torvalds */ 1111da177e4SLinus Torvalds 112029d64b0STakashi Iwai static int snd_sbmixer_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 1131da177e4SLinus Torvalds { 1141da177e4SLinus Torvalds int mask = (kcontrol->private_value >> 24) & 0xff; 1151da177e4SLinus Torvalds 1161da177e4SLinus Torvalds uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; 1171da177e4SLinus Torvalds uinfo->count = 2; 1181da177e4SLinus Torvalds uinfo->value.integer.min = 0; 1191da177e4SLinus Torvalds uinfo->value.integer.max = mask; 1201da177e4SLinus Torvalds return 0; 1211da177e4SLinus Torvalds } 1221da177e4SLinus Torvalds 123029d64b0STakashi Iwai static int snd_sbmixer_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 1241da177e4SLinus Torvalds { 125029d64b0STakashi Iwai struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 1261da177e4SLinus Torvalds unsigned long flags; 1271da177e4SLinus Torvalds int left_reg = kcontrol->private_value & 0xff; 1281da177e4SLinus Torvalds int right_reg = (kcontrol->private_value >> 8) & 0xff; 1291da177e4SLinus Torvalds int left_shift = (kcontrol->private_value >> 16) & 0x07; 1301da177e4SLinus Torvalds int right_shift = (kcontrol->private_value >> 19) & 0x07; 1311da177e4SLinus Torvalds int mask = (kcontrol->private_value >> 24) & 0xff; 1321da177e4SLinus Torvalds unsigned char left, right; 1331da177e4SLinus Torvalds 1341da177e4SLinus Torvalds spin_lock_irqsave(&sb->mixer_lock, flags); 1351da177e4SLinus Torvalds left = (snd_sbmixer_read(sb, left_reg) >> left_shift) & mask; 1361da177e4SLinus Torvalds right = (snd_sbmixer_read(sb, right_reg) >> right_shift) & mask; 1371da177e4SLinus Torvalds spin_unlock_irqrestore(&sb->mixer_lock, flags); 1381da177e4SLinus Torvalds ucontrol->value.integer.value[0] = left; 1391da177e4SLinus Torvalds ucontrol->value.integer.value[1] = right; 1401da177e4SLinus Torvalds return 0; 1411da177e4SLinus Torvalds } 1421da177e4SLinus Torvalds 143029d64b0STakashi Iwai static int snd_sbmixer_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 1441da177e4SLinus Torvalds { 145029d64b0STakashi Iwai struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 1461da177e4SLinus Torvalds unsigned long flags; 1471da177e4SLinus Torvalds int left_reg = kcontrol->private_value & 0xff; 1481da177e4SLinus Torvalds int right_reg = (kcontrol->private_value >> 8) & 0xff; 1491da177e4SLinus Torvalds int left_shift = (kcontrol->private_value >> 16) & 0x07; 1501da177e4SLinus Torvalds int right_shift = (kcontrol->private_value >> 19) & 0x07; 1511da177e4SLinus Torvalds int mask = (kcontrol->private_value >> 24) & 0xff; 1521da177e4SLinus Torvalds int change; 1531da177e4SLinus Torvalds unsigned char left, right, oleft, oright; 1541da177e4SLinus Torvalds 1551da177e4SLinus Torvalds left = (ucontrol->value.integer.value[0] & mask) << left_shift; 1561da177e4SLinus Torvalds right = (ucontrol->value.integer.value[1] & mask) << right_shift; 1571da177e4SLinus Torvalds spin_lock_irqsave(&sb->mixer_lock, flags); 1581da177e4SLinus Torvalds if (left_reg == right_reg) { 1591da177e4SLinus Torvalds oleft = snd_sbmixer_read(sb, left_reg); 1601da177e4SLinus Torvalds left = (oleft & ~((mask << left_shift) | (mask << right_shift))) | left | right; 1611da177e4SLinus Torvalds change = left != oleft; 1621da177e4SLinus Torvalds if (change) 1631da177e4SLinus Torvalds snd_sbmixer_write(sb, left_reg, left); 1641da177e4SLinus Torvalds } else { 1651da177e4SLinus Torvalds oleft = snd_sbmixer_read(sb, left_reg); 1661da177e4SLinus Torvalds oright = snd_sbmixer_read(sb, right_reg); 1671da177e4SLinus Torvalds left = (oleft & ~(mask << left_shift)) | left; 1681da177e4SLinus Torvalds right = (oright & ~(mask << right_shift)) | right; 1691da177e4SLinus Torvalds change = left != oleft || right != oright; 1701da177e4SLinus Torvalds if (change) { 1711da177e4SLinus Torvalds snd_sbmixer_write(sb, left_reg, left); 1721da177e4SLinus Torvalds snd_sbmixer_write(sb, right_reg, right); 1731da177e4SLinus Torvalds } 1741da177e4SLinus Torvalds } 1751da177e4SLinus Torvalds spin_unlock_irqrestore(&sb->mixer_lock, flags); 1761da177e4SLinus Torvalds return change; 1771da177e4SLinus Torvalds } 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds /* 1801da177e4SLinus Torvalds * DT-019x / ALS-007 capture/input switch 1811da177e4SLinus Torvalds */ 1821da177e4SLinus Torvalds 183029d64b0STakashi Iwai static int snd_dt019x_input_sw_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 1841da177e4SLinus Torvalds { 1856b9e1288STakashi Iwai static const char * const texts[5] = { 1861da177e4SLinus Torvalds "CD", "Mic", "Line", "Synth", "Master" 1871da177e4SLinus Torvalds }; 1881da177e4SLinus Torvalds 1896b9e1288STakashi Iwai return snd_ctl_enum_info(uinfo, 1, 5, texts); 1901da177e4SLinus Torvalds } 1911da177e4SLinus Torvalds 192029d64b0STakashi Iwai static int snd_dt019x_input_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 1931da177e4SLinus Torvalds { 194029d64b0STakashi Iwai struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 1951da177e4SLinus Torvalds unsigned long flags; 1961da177e4SLinus Torvalds unsigned char oval; 1971da177e4SLinus Torvalds 1981da177e4SLinus Torvalds spin_lock_irqsave(&sb->mixer_lock, flags); 1991da177e4SLinus Torvalds oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW); 2001da177e4SLinus Torvalds spin_unlock_irqrestore(&sb->mixer_lock, flags); 2011da177e4SLinus Torvalds switch (oval & 0x07) { 2021da177e4SLinus Torvalds case SB_DT019X_CAP_CD: 2031da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 0; 2041da177e4SLinus Torvalds break; 2051da177e4SLinus Torvalds case SB_DT019X_CAP_MIC: 2061da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 1; 2071da177e4SLinus Torvalds break; 2081da177e4SLinus Torvalds case SB_DT019X_CAP_LINE: 2091da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 2; 2101da177e4SLinus Torvalds break; 2111da177e4SLinus Torvalds case SB_DT019X_CAP_MAIN: 2121da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 4; 2131da177e4SLinus Torvalds break; 2141da177e4SLinus Torvalds /* To record the synth on these cards you must record the main. */ 2151da177e4SLinus Torvalds /* Thus SB_DT019X_CAP_SYNTH == SB_DT019X_CAP_MAIN and would cause */ 2161da177e4SLinus Torvalds /* duplicate case labels if left uncommented. */ 2171da177e4SLinus Torvalds /* case SB_DT019X_CAP_SYNTH: 2181da177e4SLinus Torvalds * ucontrol->value.enumerated.item[0] = 3; 2191da177e4SLinus Torvalds * break; 2201da177e4SLinus Torvalds */ 2211da177e4SLinus Torvalds default: 2221da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 4; 2231da177e4SLinus Torvalds break; 2241da177e4SLinus Torvalds } 2251da177e4SLinus Torvalds return 0; 2261da177e4SLinus Torvalds } 2271da177e4SLinus Torvalds 228029d64b0STakashi Iwai static int snd_dt019x_input_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 2291da177e4SLinus Torvalds { 230029d64b0STakashi Iwai struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 2311da177e4SLinus Torvalds unsigned long flags; 2321da177e4SLinus Torvalds int change; 2331da177e4SLinus Torvalds unsigned char nval, oval; 2341da177e4SLinus Torvalds 2351da177e4SLinus Torvalds if (ucontrol->value.enumerated.item[0] > 4) 2361da177e4SLinus Torvalds return -EINVAL; 2371da177e4SLinus Torvalds switch (ucontrol->value.enumerated.item[0]) { 2381da177e4SLinus Torvalds case 0: 2391da177e4SLinus Torvalds nval = SB_DT019X_CAP_CD; 2401da177e4SLinus Torvalds break; 2411da177e4SLinus Torvalds case 1: 2421da177e4SLinus Torvalds nval = SB_DT019X_CAP_MIC; 2431da177e4SLinus Torvalds break; 2441da177e4SLinus Torvalds case 2: 2451da177e4SLinus Torvalds nval = SB_DT019X_CAP_LINE; 2461da177e4SLinus Torvalds break; 2471da177e4SLinus Torvalds case 3: 2481da177e4SLinus Torvalds nval = SB_DT019X_CAP_SYNTH; 2491da177e4SLinus Torvalds break; 2501da177e4SLinus Torvalds case 4: 2511da177e4SLinus Torvalds nval = SB_DT019X_CAP_MAIN; 2521da177e4SLinus Torvalds break; 2531da177e4SLinus Torvalds default: 2541da177e4SLinus Torvalds nval = SB_DT019X_CAP_MAIN; 2551da177e4SLinus Torvalds } 2561da177e4SLinus Torvalds spin_lock_irqsave(&sb->mixer_lock, flags); 2571da177e4SLinus Torvalds oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW); 2581da177e4SLinus Torvalds change = nval != oval; 2591da177e4SLinus Torvalds if (change) 2601da177e4SLinus Torvalds snd_sbmixer_write(sb, SB_DT019X_CAPTURE_SW, nval); 2611da177e4SLinus Torvalds spin_unlock_irqrestore(&sb->mixer_lock, flags); 2621da177e4SLinus Torvalds return change; 2631da177e4SLinus Torvalds } 2641da177e4SLinus Torvalds 2651da177e4SLinus Torvalds /* 266ce71bfd1SAndreas Mohr * ALS4000 mono recording control switch 267ce71bfd1SAndreas Mohr */ 268ce71bfd1SAndreas Mohr 269ce71bfd1SAndreas Mohr static int snd_als4k_mono_capture_route_info(struct snd_kcontrol *kcontrol, 270ce71bfd1SAndreas Mohr struct snd_ctl_elem_info *uinfo) 271ce71bfd1SAndreas Mohr { 2726b9e1288STakashi Iwai static const char * const texts[3] = { 273ce71bfd1SAndreas Mohr "L chan only", "R chan only", "L ch/2 + R ch/2" 274ce71bfd1SAndreas Mohr }; 275ce71bfd1SAndreas Mohr 2766b9e1288STakashi Iwai return snd_ctl_enum_info(uinfo, 1, 3, texts); 277ce71bfd1SAndreas Mohr } 278ce71bfd1SAndreas Mohr 279ce71bfd1SAndreas Mohr static int snd_als4k_mono_capture_route_get(struct snd_kcontrol *kcontrol, 280ce71bfd1SAndreas Mohr struct snd_ctl_elem_value *ucontrol) 281ce71bfd1SAndreas Mohr { 282ce71bfd1SAndreas Mohr struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 283ce71bfd1SAndreas Mohr unsigned long flags; 284ce71bfd1SAndreas Mohr unsigned char oval; 285ce71bfd1SAndreas Mohr 286ce71bfd1SAndreas Mohr spin_lock_irqsave(&sb->mixer_lock, flags); 287ce71bfd1SAndreas Mohr oval = snd_sbmixer_read(sb, SB_ALS4000_MONO_IO_CTRL); 288ce71bfd1SAndreas Mohr spin_unlock_irqrestore(&sb->mixer_lock, flags); 289ce71bfd1SAndreas Mohr oval >>= 6; 290ce71bfd1SAndreas Mohr if (oval > 2) 291ce71bfd1SAndreas Mohr oval = 2; 292ce71bfd1SAndreas Mohr 293ce71bfd1SAndreas Mohr ucontrol->value.enumerated.item[0] = oval; 294ce71bfd1SAndreas Mohr return 0; 295ce71bfd1SAndreas Mohr } 296ce71bfd1SAndreas Mohr 297ce71bfd1SAndreas Mohr static int snd_als4k_mono_capture_route_put(struct snd_kcontrol *kcontrol, 298ce71bfd1SAndreas Mohr struct snd_ctl_elem_value *ucontrol) 299ce71bfd1SAndreas Mohr { 300ce71bfd1SAndreas Mohr struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 301ce71bfd1SAndreas Mohr unsigned long flags; 302ce71bfd1SAndreas Mohr int change; 303ce71bfd1SAndreas Mohr unsigned char nval, oval; 304ce71bfd1SAndreas Mohr 305ce71bfd1SAndreas Mohr if (ucontrol->value.enumerated.item[0] > 2) 306ce71bfd1SAndreas Mohr return -EINVAL; 307ce71bfd1SAndreas Mohr spin_lock_irqsave(&sb->mixer_lock, flags); 308ce71bfd1SAndreas Mohr oval = snd_sbmixer_read(sb, SB_ALS4000_MONO_IO_CTRL); 309ce71bfd1SAndreas Mohr 310ce71bfd1SAndreas Mohr nval = (oval & ~(3 << 6)) 311ce71bfd1SAndreas Mohr | (ucontrol->value.enumerated.item[0] << 6); 312ce71bfd1SAndreas Mohr change = nval != oval; 313ce71bfd1SAndreas Mohr if (change) 314ce71bfd1SAndreas Mohr snd_sbmixer_write(sb, SB_ALS4000_MONO_IO_CTRL, nval); 315ce71bfd1SAndreas Mohr spin_unlock_irqrestore(&sb->mixer_lock, flags); 316ce71bfd1SAndreas Mohr return change; 317ce71bfd1SAndreas Mohr } 318ce71bfd1SAndreas Mohr 319ce71bfd1SAndreas Mohr /* 3201da177e4SLinus Torvalds * SBPRO input multiplexer 3211da177e4SLinus Torvalds */ 3221da177e4SLinus Torvalds 323029d64b0STakashi Iwai static int snd_sb8mixer_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 3241da177e4SLinus Torvalds { 3256b9e1288STakashi Iwai static const char * const texts[3] = { 3261da177e4SLinus Torvalds "Mic", "CD", "Line" 3271da177e4SLinus Torvalds }; 3281da177e4SLinus Torvalds 3296b9e1288STakashi Iwai return snd_ctl_enum_info(uinfo, 1, 3, texts); 3301da177e4SLinus Torvalds } 3311da177e4SLinus Torvalds 3321da177e4SLinus Torvalds 333029d64b0STakashi Iwai static int snd_sb8mixer_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 3341da177e4SLinus Torvalds { 335029d64b0STakashi Iwai struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 3361da177e4SLinus Torvalds unsigned long flags; 3371da177e4SLinus Torvalds unsigned char oval; 3381da177e4SLinus Torvalds 3391da177e4SLinus Torvalds spin_lock_irqsave(&sb->mixer_lock, flags); 3401da177e4SLinus Torvalds oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE); 3411da177e4SLinus Torvalds spin_unlock_irqrestore(&sb->mixer_lock, flags); 3421da177e4SLinus Torvalds switch ((oval >> 0x01) & 0x03) { 3431da177e4SLinus Torvalds case SB_DSP_MIXS_CD: 3441da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 1; 3451da177e4SLinus Torvalds break; 3461da177e4SLinus Torvalds case SB_DSP_MIXS_LINE: 3471da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 2; 3481da177e4SLinus Torvalds break; 3491da177e4SLinus Torvalds default: 3501da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = 0; 3511da177e4SLinus Torvalds break; 3521da177e4SLinus Torvalds } 3531da177e4SLinus Torvalds return 0; 3541da177e4SLinus Torvalds } 3551da177e4SLinus Torvalds 356029d64b0STakashi Iwai static int snd_sb8mixer_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 3571da177e4SLinus Torvalds { 358029d64b0STakashi Iwai struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 3591da177e4SLinus Torvalds unsigned long flags; 3601da177e4SLinus Torvalds int change; 3611da177e4SLinus Torvalds unsigned char nval, oval; 3621da177e4SLinus Torvalds 3631da177e4SLinus Torvalds if (ucontrol->value.enumerated.item[0] > 2) 3641da177e4SLinus Torvalds return -EINVAL; 3651da177e4SLinus Torvalds switch (ucontrol->value.enumerated.item[0]) { 3661da177e4SLinus Torvalds case 1: 3671da177e4SLinus Torvalds nval = SB_DSP_MIXS_CD; 3681da177e4SLinus Torvalds break; 3691da177e4SLinus Torvalds case 2: 3701da177e4SLinus Torvalds nval = SB_DSP_MIXS_LINE; 3711da177e4SLinus Torvalds break; 3721da177e4SLinus Torvalds default: 3731da177e4SLinus Torvalds nval = SB_DSP_MIXS_MIC; 3741da177e4SLinus Torvalds } 3751da177e4SLinus Torvalds nval <<= 1; 3761da177e4SLinus Torvalds spin_lock_irqsave(&sb->mixer_lock, flags); 3771da177e4SLinus Torvalds oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE); 3781da177e4SLinus Torvalds nval |= oval & ~0x06; 3791da177e4SLinus Torvalds change = nval != oval; 3801da177e4SLinus Torvalds if (change) 3811da177e4SLinus Torvalds snd_sbmixer_write(sb, SB_DSP_CAPTURE_SOURCE, nval); 3821da177e4SLinus Torvalds spin_unlock_irqrestore(&sb->mixer_lock, flags); 3831da177e4SLinus Torvalds return change; 3841da177e4SLinus Torvalds } 3851da177e4SLinus Torvalds 3861da177e4SLinus Torvalds /* 3871da177e4SLinus Torvalds * SB16 input switch 3881da177e4SLinus Torvalds */ 3891da177e4SLinus Torvalds 390029d64b0STakashi Iwai static int snd_sb16mixer_info_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 3911da177e4SLinus Torvalds { 3921da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 3931da177e4SLinus Torvalds uinfo->count = 4; 3941da177e4SLinus Torvalds uinfo->value.integer.min = 0; 3951da177e4SLinus Torvalds uinfo->value.integer.max = 1; 3961da177e4SLinus Torvalds return 0; 3971da177e4SLinus Torvalds } 3981da177e4SLinus Torvalds 399029d64b0STakashi Iwai static int snd_sb16mixer_get_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 4001da177e4SLinus Torvalds { 401029d64b0STakashi Iwai struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 4021da177e4SLinus Torvalds unsigned long flags; 4031da177e4SLinus Torvalds int reg1 = kcontrol->private_value & 0xff; 4041da177e4SLinus Torvalds int reg2 = (kcontrol->private_value >> 8) & 0xff; 4051da177e4SLinus Torvalds int left_shift = (kcontrol->private_value >> 16) & 0x0f; 4061da177e4SLinus Torvalds int right_shift = (kcontrol->private_value >> 24) & 0x0f; 4071da177e4SLinus Torvalds unsigned char val1, val2; 4081da177e4SLinus Torvalds 4091da177e4SLinus Torvalds spin_lock_irqsave(&sb->mixer_lock, flags); 4101da177e4SLinus Torvalds val1 = snd_sbmixer_read(sb, reg1); 4111da177e4SLinus Torvalds val2 = snd_sbmixer_read(sb, reg2); 4121da177e4SLinus Torvalds spin_unlock_irqrestore(&sb->mixer_lock, flags); 4131da177e4SLinus Torvalds ucontrol->value.integer.value[0] = (val1 >> left_shift) & 0x01; 4141da177e4SLinus Torvalds ucontrol->value.integer.value[1] = (val2 >> left_shift) & 0x01; 4151da177e4SLinus Torvalds ucontrol->value.integer.value[2] = (val1 >> right_shift) & 0x01; 4161da177e4SLinus Torvalds ucontrol->value.integer.value[3] = (val2 >> right_shift) & 0x01; 4171da177e4SLinus Torvalds return 0; 4181da177e4SLinus Torvalds } 4191da177e4SLinus Torvalds 420029d64b0STakashi Iwai static int snd_sb16mixer_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 4211da177e4SLinus Torvalds { 422029d64b0STakashi Iwai struct snd_sb *sb = snd_kcontrol_chip(kcontrol); 4231da177e4SLinus Torvalds unsigned long flags; 4241da177e4SLinus Torvalds int reg1 = kcontrol->private_value & 0xff; 4251da177e4SLinus Torvalds int reg2 = (kcontrol->private_value >> 8) & 0xff; 4261da177e4SLinus Torvalds int left_shift = (kcontrol->private_value >> 16) & 0x0f; 4271da177e4SLinus Torvalds int right_shift = (kcontrol->private_value >> 24) & 0x0f; 4281da177e4SLinus Torvalds int change; 4291da177e4SLinus Torvalds unsigned char val1, val2, oval1, oval2; 4301da177e4SLinus Torvalds 4311da177e4SLinus Torvalds spin_lock_irqsave(&sb->mixer_lock, flags); 4321da177e4SLinus Torvalds oval1 = snd_sbmixer_read(sb, reg1); 4331da177e4SLinus Torvalds oval2 = snd_sbmixer_read(sb, reg2); 4341da177e4SLinus Torvalds val1 = oval1 & ~((1 << left_shift) | (1 << right_shift)); 4351da177e4SLinus Torvalds val2 = oval2 & ~((1 << left_shift) | (1 << right_shift)); 4361da177e4SLinus Torvalds val1 |= (ucontrol->value.integer.value[0] & 1) << left_shift; 4371da177e4SLinus Torvalds val2 |= (ucontrol->value.integer.value[1] & 1) << left_shift; 4381da177e4SLinus Torvalds val1 |= (ucontrol->value.integer.value[2] & 1) << right_shift; 4391da177e4SLinus Torvalds val2 |= (ucontrol->value.integer.value[3] & 1) << right_shift; 4401da177e4SLinus Torvalds change = val1 != oval1 || val2 != oval2; 4411da177e4SLinus Torvalds if (change) { 4421da177e4SLinus Torvalds snd_sbmixer_write(sb, reg1, val1); 4431da177e4SLinus Torvalds snd_sbmixer_write(sb, reg2, val2); 4441da177e4SLinus Torvalds } 4451da177e4SLinus Torvalds spin_unlock_irqrestore(&sb->mixer_lock, flags); 4461da177e4SLinus Torvalds return change; 4471da177e4SLinus Torvalds } 4481da177e4SLinus Torvalds 4491da177e4SLinus Torvalds 4501da177e4SLinus Torvalds /* 4511da177e4SLinus Torvalds */ 4521da177e4SLinus Torvalds /* 4531da177e4SLinus Torvalds */ 454029d64b0STakashi Iwai int snd_sbmixer_add_ctl(struct snd_sb *chip, const char *name, int index, int type, unsigned long value) 4551da177e4SLinus Torvalds { 456029d64b0STakashi Iwai static struct snd_kcontrol_new newctls[] = { 4571da177e4SLinus Torvalds [SB_MIX_SINGLE] = { 4581da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4591da177e4SLinus Torvalds .info = snd_sbmixer_info_single, 4601da177e4SLinus Torvalds .get = snd_sbmixer_get_single, 4611da177e4SLinus Torvalds .put = snd_sbmixer_put_single, 4621da177e4SLinus Torvalds }, 4631da177e4SLinus Torvalds [SB_MIX_DOUBLE] = { 4641da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4651da177e4SLinus Torvalds .info = snd_sbmixer_info_double, 4661da177e4SLinus Torvalds .get = snd_sbmixer_get_double, 4671da177e4SLinus Torvalds .put = snd_sbmixer_put_double, 4681da177e4SLinus Torvalds }, 4691da177e4SLinus Torvalds [SB_MIX_INPUT_SW] = { 4701da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4711da177e4SLinus Torvalds .info = snd_sb16mixer_info_input_sw, 4721da177e4SLinus Torvalds .get = snd_sb16mixer_get_input_sw, 4731da177e4SLinus Torvalds .put = snd_sb16mixer_put_input_sw, 4741da177e4SLinus Torvalds }, 4751da177e4SLinus Torvalds [SB_MIX_CAPTURE_PRO] = { 4761da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4771da177e4SLinus Torvalds .info = snd_sb8mixer_info_mux, 4781da177e4SLinus Torvalds .get = snd_sb8mixer_get_mux, 4791da177e4SLinus Torvalds .put = snd_sb8mixer_put_mux, 4801da177e4SLinus Torvalds }, 4811da177e4SLinus Torvalds [SB_MIX_CAPTURE_DT019X] = { 4821da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4831da177e4SLinus Torvalds .info = snd_dt019x_input_sw_info, 4841da177e4SLinus Torvalds .get = snd_dt019x_input_sw_get, 4851da177e4SLinus Torvalds .put = snd_dt019x_input_sw_put, 4861da177e4SLinus Torvalds }, 487ce71bfd1SAndreas Mohr [SB_MIX_MONO_CAPTURE_ALS4K] = { 488ce71bfd1SAndreas Mohr .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 489ce71bfd1SAndreas Mohr .info = snd_als4k_mono_capture_route_info, 490ce71bfd1SAndreas Mohr .get = snd_als4k_mono_capture_route_get, 491ce71bfd1SAndreas Mohr .put = snd_als4k_mono_capture_route_put, 492ce71bfd1SAndreas Mohr }, 4931da177e4SLinus Torvalds }; 494029d64b0STakashi Iwai struct snd_kcontrol *ctl; 4951da177e4SLinus Torvalds int err; 4961da177e4SLinus Torvalds 4971da177e4SLinus Torvalds ctl = snd_ctl_new1(&newctls[type], chip); 4981da177e4SLinus Torvalds if (! ctl) 4991da177e4SLinus Torvalds return -ENOMEM; 5001da177e4SLinus Torvalds strlcpy(ctl->id.name, name, sizeof(ctl->id.name)); 5011da177e4SLinus Torvalds ctl->id.index = index; 5021da177e4SLinus Torvalds ctl->private_value = value; 503bcc54f9aSDave Jones if ((err = snd_ctl_add(chip->card, ctl)) < 0) 5041da177e4SLinus Torvalds return err; 5051da177e4SLinus Torvalds return 0; 5061da177e4SLinus Torvalds } 5071da177e4SLinus Torvalds 5081da177e4SLinus Torvalds /* 5091da177e4SLinus Torvalds * SB 2.0 specific mixer elements 5101da177e4SLinus Torvalds */ 5111da177e4SLinus Torvalds 51274c2b45bSKrzysztof Helt static struct sbmix_elem snd_sb20_controls[] = { 51374c2b45bSKrzysztof Helt SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7), 51474c2b45bSKrzysztof Helt SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3), 51574c2b45bSKrzysztof Helt SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7), 51674c2b45bSKrzysztof Helt SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7) 5171da177e4SLinus Torvalds }; 5181da177e4SLinus Torvalds 5191da177e4SLinus Torvalds static unsigned char snd_sb20_init_values[][2] = { 5201da177e4SLinus Torvalds { SB_DSP20_MASTER_DEV, 0 }, 5211da177e4SLinus Torvalds { SB_DSP20_FM_DEV, 0 }, 5221da177e4SLinus Torvalds }; 5231da177e4SLinus Torvalds 5241da177e4SLinus Torvalds /* 5251da177e4SLinus Torvalds * SB Pro specific mixer elements 5261da177e4SLinus Torvalds */ 52774c2b45bSKrzysztof Helt static struct sbmix_elem snd_sbpro_controls[] = { 52874c2b45bSKrzysztof Helt SB_DOUBLE("Master Playback Volume", 52974c2b45bSKrzysztof Helt SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7), 53074c2b45bSKrzysztof Helt SB_DOUBLE("PCM Playback Volume", 53174c2b45bSKrzysztof Helt SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7), 53274c2b45bSKrzysztof Helt SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1), 53374c2b45bSKrzysztof Helt SB_DOUBLE("Synth Playback Volume", 53474c2b45bSKrzysztof Helt SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7), 53574c2b45bSKrzysztof Helt SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7), 53674c2b45bSKrzysztof Helt SB_DOUBLE("Line Playback Volume", 53774c2b45bSKrzysztof Helt SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7), 53874c2b45bSKrzysztof Helt SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3), 5391da177e4SLinus Torvalds { 5401da177e4SLinus Torvalds .name = "Capture Source", 5411da177e4SLinus Torvalds .type = SB_MIX_CAPTURE_PRO 54274c2b45bSKrzysztof Helt }, 54374c2b45bSKrzysztof Helt SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1), 54474c2b45bSKrzysztof Helt SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1) 5451da177e4SLinus Torvalds }; 5461da177e4SLinus Torvalds 5471da177e4SLinus Torvalds static unsigned char snd_sbpro_init_values[][2] = { 5481da177e4SLinus Torvalds { SB_DSP_MASTER_DEV, 0 }, 5491da177e4SLinus Torvalds { SB_DSP_PCM_DEV, 0 }, 5501da177e4SLinus Torvalds { SB_DSP_FM_DEV, 0 }, 5511da177e4SLinus Torvalds }; 5521da177e4SLinus Torvalds 5531da177e4SLinus Torvalds /* 5541da177e4SLinus Torvalds * SB16 specific mixer elements 5551da177e4SLinus Torvalds */ 55674c2b45bSKrzysztof Helt static struct sbmix_elem snd_sb16_controls[] = { 55774c2b45bSKrzysztof Helt SB_DOUBLE("Master Playback Volume", 55874c2b45bSKrzysztof Helt SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31), 55974c2b45bSKrzysztof Helt SB_DOUBLE("PCM Playback Volume", 56074c2b45bSKrzysztof Helt SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31), 56174c2b45bSKrzysztof Helt SB16_INPUT_SW("Synth Capture Route", 56274c2b45bSKrzysztof Helt SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5), 56374c2b45bSKrzysztof Helt SB_DOUBLE("Synth Playback Volume", 56474c2b45bSKrzysztof Helt SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31), 56574c2b45bSKrzysztof Helt SB16_INPUT_SW("CD Capture Route", 56674c2b45bSKrzysztof Helt SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1), 56774c2b45bSKrzysztof Helt SB_DOUBLE("CD Playback Switch", 56874c2b45bSKrzysztof Helt SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1), 56974c2b45bSKrzysztof Helt SB_DOUBLE("CD Playback Volume", 57074c2b45bSKrzysztof Helt SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31), 57174c2b45bSKrzysztof Helt SB16_INPUT_SW("Mic Capture Route", 57274c2b45bSKrzysztof Helt SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0), 57374c2b45bSKrzysztof Helt SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1), 57474c2b45bSKrzysztof Helt SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31), 57574c2b45bSKrzysztof Helt SB_SINGLE("Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3), 57674c2b45bSKrzysztof Helt SB_DOUBLE("Capture Volume", 57774c2b45bSKrzysztof Helt SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3), 57874c2b45bSKrzysztof Helt SB_DOUBLE("Playback Volume", 57974c2b45bSKrzysztof Helt SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3), 58074c2b45bSKrzysztof Helt SB16_INPUT_SW("Line Capture Route", 58174c2b45bSKrzysztof Helt SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3), 58274c2b45bSKrzysztof Helt SB_DOUBLE("Line Playback Switch", 58374c2b45bSKrzysztof Helt SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1), 58474c2b45bSKrzysztof Helt SB_DOUBLE("Line Playback Volume", 58574c2b45bSKrzysztof Helt SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31), 58674c2b45bSKrzysztof Helt SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1), 58774c2b45bSKrzysztof Helt SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1), 58874c2b45bSKrzysztof Helt SB_DOUBLE("Tone Control - Bass", 58974c2b45bSKrzysztof Helt SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15), 59074c2b45bSKrzysztof Helt SB_DOUBLE("Tone Control - Treble", 59174c2b45bSKrzysztof Helt SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15) 5921da177e4SLinus Torvalds }; 5931da177e4SLinus Torvalds 5941da177e4SLinus Torvalds static unsigned char snd_sb16_init_values[][2] = { 5951da177e4SLinus Torvalds { SB_DSP4_MASTER_DEV + 0, 0 }, 5961da177e4SLinus Torvalds { SB_DSP4_MASTER_DEV + 1, 0 }, 5971da177e4SLinus Torvalds { SB_DSP4_PCM_DEV + 0, 0 }, 5981da177e4SLinus Torvalds { SB_DSP4_PCM_DEV + 1, 0 }, 5991da177e4SLinus Torvalds { SB_DSP4_SYNTH_DEV + 0, 0 }, 6001da177e4SLinus Torvalds { SB_DSP4_SYNTH_DEV + 1, 0 }, 6011da177e4SLinus Torvalds { SB_DSP4_INPUT_LEFT, 0 }, 6021da177e4SLinus Torvalds { SB_DSP4_INPUT_RIGHT, 0 }, 6031da177e4SLinus Torvalds { SB_DSP4_OUTPUT_SW, 0 }, 6041da177e4SLinus Torvalds { SB_DSP4_SPEAKER_DEV, 0 }, 6051da177e4SLinus Torvalds }; 6061da177e4SLinus Torvalds 6071da177e4SLinus Torvalds /* 6081da177e4SLinus Torvalds * DT019x specific mixer elements 6091da177e4SLinus Torvalds */ 61074c2b45bSKrzysztof Helt static struct sbmix_elem snd_dt019x_controls[] = { 61174c2b45bSKrzysztof Helt /* ALS4000 below has some parts which we might be lacking, 61274c2b45bSKrzysztof Helt * e.g. snd_als4000_ctl_mono_playback_switch - check it! */ 61374c2b45bSKrzysztof Helt SB_DOUBLE("Master Playback Volume", 61474c2b45bSKrzysztof Helt SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4, 0, 15), 61574c2b45bSKrzysztof Helt SB_DOUBLE("PCM Playback Switch", 61674c2b45bSKrzysztof Helt SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1), 61774c2b45bSKrzysztof Helt SB_DOUBLE("PCM Playback Volume", 61874c2b45bSKrzysztof Helt SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4, 0, 15), 61974c2b45bSKrzysztof Helt SB_DOUBLE("Synth Playback Switch", 62074c2b45bSKrzysztof Helt SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1), 62174c2b45bSKrzysztof Helt SB_DOUBLE("Synth Playback Volume", 62274c2b45bSKrzysztof Helt SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4, 0, 15), 62374c2b45bSKrzysztof Helt SB_DOUBLE("CD Playback Switch", 62474c2b45bSKrzysztof Helt SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1), 62574c2b45bSKrzysztof Helt SB_DOUBLE("CD Playback Volume", 62674c2b45bSKrzysztof Helt SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4, 0, 15), 62774c2b45bSKrzysztof Helt SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1), 62874c2b45bSKrzysztof Helt SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7), 62974c2b45bSKrzysztof Helt SB_SINGLE("Beep Volume", SB_DT019X_SPKR_DEV, 0, 7), 63074c2b45bSKrzysztof Helt SB_DOUBLE("Line Playback Switch", 63174c2b45bSKrzysztof Helt SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1), 63274c2b45bSKrzysztof Helt SB_DOUBLE("Line Playback Volume", 63374c2b45bSKrzysztof Helt SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4, 0, 15), 6341da177e4SLinus Torvalds { 6351da177e4SLinus Torvalds .name = "Capture Source", 6361da177e4SLinus Torvalds .type = SB_MIX_CAPTURE_DT019X 63774c2b45bSKrzysztof Helt } 6381da177e4SLinus Torvalds }; 6391da177e4SLinus Torvalds 6401da177e4SLinus Torvalds static unsigned char snd_dt019x_init_values[][2] = { 6411da177e4SLinus Torvalds { SB_DT019X_MASTER_DEV, 0 }, 6421da177e4SLinus Torvalds { SB_DT019X_PCM_DEV, 0 }, 6431da177e4SLinus Torvalds { SB_DT019X_SYNTH_DEV, 0 }, 6441da177e4SLinus Torvalds { SB_DT019X_CD_DEV, 0 }, 6451da177e4SLinus Torvalds { SB_DT019X_MIC_DEV, 0 }, /* Includes PC-speaker in high nibble */ 6461da177e4SLinus Torvalds { SB_DT019X_LINE_DEV, 0 }, 6471da177e4SLinus Torvalds { SB_DSP4_OUTPUT_SW, 0 }, 6481da177e4SLinus Torvalds { SB_DT019X_OUTPUT_SW2, 0 }, 6491da177e4SLinus Torvalds { SB_DT019X_CAPTURE_SW, 0x06 }, 6501da177e4SLinus Torvalds }; 6511da177e4SLinus Torvalds 6521da177e4SLinus Torvalds /* 6531da177e4SLinus Torvalds * ALS4000 specific mixer elements 6541da177e4SLinus Torvalds */ 65574c2b45bSKrzysztof Helt static struct sbmix_elem snd_als4000_controls[] = { 65674c2b45bSKrzysztof Helt SB_DOUBLE("PCM Playback Switch", 65774c2b45bSKrzysztof Helt SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1), 65874c2b45bSKrzysztof Helt SB_DOUBLE("Synth Playback Switch", 65974c2b45bSKrzysztof Helt SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1), 66074c2b45bSKrzysztof Helt SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03), 66174c2b45bSKrzysztof Helt SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1), 66274c2b45bSKrzysztof Helt { 663ce71bfd1SAndreas Mohr .name = "Master Mono Capture Route", 664ce71bfd1SAndreas Mohr .type = SB_MIX_MONO_CAPTURE_ALS4K 66574c2b45bSKrzysztof Helt }, 66674c2b45bSKrzysztof Helt SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2, 0, 1), 66774c2b45bSKrzysztof Helt SB_SINGLE("Analog Loopback Switch", SB_ALS4000_MIC_IN_GAIN, 7, 0x01), 66874c2b45bSKrzysztof Helt SB_SINGLE("3D Control - Switch", SB_ALS4000_3D_SND_FX, 6, 0x01), 669ce71bfd1SAndreas Mohr SB_SINGLE("Digital Loopback Switch", 67074c2b45bSKrzysztof Helt SB_ALS4000_CR3_CONFIGURATION, 7, 0x01), 671ba7301c7SAndreas Mohr /* FIXME: functionality of 3D controls might be swapped, I didn't find 672ba7301c7SAndreas Mohr * a description of how to identify what is supposed to be what */ 67374c2b45bSKrzysztof Helt SB_SINGLE("3D Control - Level", SB_ALS4000_3D_SND_FX, 0, 0x07), 674ba7301c7SAndreas Mohr /* FIXME: maybe there's actually some standard 3D ctrl name for it?? */ 67574c2b45bSKrzysztof Helt SB_SINGLE("3D Control - Freq", SB_ALS4000_3D_SND_FX, 4, 0x03), 676ba7301c7SAndreas Mohr /* FIXME: ALS4000a.pdf mentions BBD (Bucket Brigade Device) time delay, 677ba7301c7SAndreas Mohr * but what ALSA 3D attribute is that actually? "Center", "Depth", 678ba7301c7SAndreas Mohr * "Wide" or "Space" or even "Level"? Assuming "Wide" for now... */ 67974c2b45bSKrzysztof Helt SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f), 68074c2b45bSKrzysztof Helt SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01), 681ce71bfd1SAndreas Mohr SB_SINGLE("Master Playback 8kHz / 20kHz LPF Switch", 68274c2b45bSKrzysztof Helt SB_ALS4000_FMDAC, 5, 0x01), 68344456d37SOlaf Hering #ifdef NOT_AVAILABLE 68474c2b45bSKrzysztof Helt SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01), 68574c2b45bSKrzysztof Helt SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f), 6861da177e4SLinus Torvalds #endif 6871da177e4SLinus Torvalds }; 6881da177e4SLinus Torvalds 6891da177e4SLinus Torvalds static unsigned char snd_als4000_init_values[][2] = { 6901da177e4SLinus Torvalds { SB_DSP4_MASTER_DEV + 0, 0 }, 6911da177e4SLinus Torvalds { SB_DSP4_MASTER_DEV + 1, 0 }, 6921da177e4SLinus Torvalds { SB_DSP4_PCM_DEV + 0, 0 }, 6931da177e4SLinus Torvalds { SB_DSP4_PCM_DEV + 1, 0 }, 6941da177e4SLinus Torvalds { SB_DSP4_SYNTH_DEV + 0, 0 }, 6951da177e4SLinus Torvalds { SB_DSP4_SYNTH_DEV + 1, 0 }, 6961da177e4SLinus Torvalds { SB_DSP4_SPEAKER_DEV, 0 }, 6971da177e4SLinus Torvalds { SB_DSP4_OUTPUT_SW, 0 }, 6981da177e4SLinus Torvalds { SB_DSP4_INPUT_LEFT, 0 }, 6991da177e4SLinus Torvalds { SB_DSP4_INPUT_RIGHT, 0 }, 7001da177e4SLinus Torvalds { SB_DT019X_OUTPUT_SW2, 0 }, 7011da177e4SLinus Torvalds { SB_ALS4000_MIC_IN_GAIN, 0 }, 7021da177e4SLinus Torvalds }; 7031da177e4SLinus Torvalds 7041da177e4SLinus Torvalds /* 7051da177e4SLinus Torvalds */ 706029d64b0STakashi Iwai static int snd_sbmixer_init(struct snd_sb *chip, 70774c2b45bSKrzysztof Helt struct sbmix_elem *controls, 7081da177e4SLinus Torvalds int controls_count, 7091da177e4SLinus Torvalds unsigned char map[][2], 7101da177e4SLinus Torvalds int map_count, 7111da177e4SLinus Torvalds char *name) 7121da177e4SLinus Torvalds { 7131da177e4SLinus Torvalds unsigned long flags; 714029d64b0STakashi Iwai struct snd_card *card = chip->card; 7151da177e4SLinus Torvalds int idx, err; 7161da177e4SLinus Torvalds 7171da177e4SLinus Torvalds /* mixer reset */ 7181da177e4SLinus Torvalds spin_lock_irqsave(&chip->mixer_lock, flags); 7191da177e4SLinus Torvalds snd_sbmixer_write(chip, 0x00, 0x00); 7201da177e4SLinus Torvalds spin_unlock_irqrestore(&chip->mixer_lock, flags); 7211da177e4SLinus Torvalds 7221da177e4SLinus Torvalds /* mute and zero volume channels */ 7231da177e4SLinus Torvalds for (idx = 0; idx < map_count; idx++) { 7241da177e4SLinus Torvalds spin_lock_irqsave(&chip->mixer_lock, flags); 7251da177e4SLinus Torvalds snd_sbmixer_write(chip, map[idx][0], map[idx][1]); 7261da177e4SLinus Torvalds spin_unlock_irqrestore(&chip->mixer_lock, flags); 7271da177e4SLinus Torvalds } 7281da177e4SLinus Torvalds 7291da177e4SLinus Torvalds for (idx = 0; idx < controls_count; idx++) { 73074c2b45bSKrzysztof Helt err = snd_sbmixer_add_ctl_elem(chip, &controls[idx]); 73174c2b45bSKrzysztof Helt if (err < 0) 7321da177e4SLinus Torvalds return err; 7331da177e4SLinus Torvalds } 7341da177e4SLinus Torvalds snd_component_add(card, name); 7351da177e4SLinus Torvalds strcpy(card->mixername, name); 7361da177e4SLinus Torvalds return 0; 7371da177e4SLinus Torvalds } 7381da177e4SLinus Torvalds 739029d64b0STakashi Iwai int snd_sbmixer_new(struct snd_sb *chip) 7401da177e4SLinus Torvalds { 741029d64b0STakashi Iwai struct snd_card *card; 7421da177e4SLinus Torvalds int err; 7431da177e4SLinus Torvalds 744622207dcSTakashi Iwai if (snd_BUG_ON(!chip || !chip->card)) 745622207dcSTakashi Iwai return -EINVAL; 7461da177e4SLinus Torvalds 7471da177e4SLinus Torvalds card = chip->card; 7481da177e4SLinus Torvalds 7491da177e4SLinus Torvalds switch (chip->hardware) { 7501da177e4SLinus Torvalds case SB_HW_10: 7511da177e4SLinus Torvalds return 0; /* no mixer chip on SB1.x */ 7521da177e4SLinus Torvalds case SB_HW_20: 7531da177e4SLinus Torvalds case SB_HW_201: 7541da177e4SLinus Torvalds if ((err = snd_sbmixer_init(chip, 7551da177e4SLinus Torvalds snd_sb20_controls, 7561da177e4SLinus Torvalds ARRAY_SIZE(snd_sb20_controls), 7571da177e4SLinus Torvalds snd_sb20_init_values, 7581da177e4SLinus Torvalds ARRAY_SIZE(snd_sb20_init_values), 7591da177e4SLinus Torvalds "CTL1335")) < 0) 7601da177e4SLinus Torvalds return err; 7611da177e4SLinus Torvalds break; 7621da177e4SLinus Torvalds case SB_HW_PRO: 763ad8decb7SKrzysztof Helt case SB_HW_JAZZ16: 7641da177e4SLinus Torvalds if ((err = snd_sbmixer_init(chip, 7651da177e4SLinus Torvalds snd_sbpro_controls, 7661da177e4SLinus Torvalds ARRAY_SIZE(snd_sbpro_controls), 7671da177e4SLinus Torvalds snd_sbpro_init_values, 7681da177e4SLinus Torvalds ARRAY_SIZE(snd_sbpro_init_values), 7691da177e4SLinus Torvalds "CTL1345")) < 0) 7701da177e4SLinus Torvalds return err; 7711da177e4SLinus Torvalds break; 7721da177e4SLinus Torvalds case SB_HW_16: 7731da177e4SLinus Torvalds case SB_HW_ALS100: 774621887aeSTakashi Iwai case SB_HW_CS5530: 7751da177e4SLinus Torvalds if ((err = snd_sbmixer_init(chip, 7761da177e4SLinus Torvalds snd_sb16_controls, 7771da177e4SLinus Torvalds ARRAY_SIZE(snd_sb16_controls), 7781da177e4SLinus Torvalds snd_sb16_init_values, 7791da177e4SLinus Torvalds ARRAY_SIZE(snd_sb16_init_values), 7801da177e4SLinus Torvalds "CTL1745")) < 0) 7811da177e4SLinus Torvalds return err; 7821da177e4SLinus Torvalds break; 7831da177e4SLinus Torvalds case SB_HW_ALS4000: 78474c2b45bSKrzysztof Helt /* use only the first 16 controls from SB16 */ 78574c2b45bSKrzysztof Helt err = snd_sbmixer_init(chip, 78674c2b45bSKrzysztof Helt snd_sb16_controls, 78774c2b45bSKrzysztof Helt 16, 78874c2b45bSKrzysztof Helt snd_sb16_init_values, 78974c2b45bSKrzysztof Helt ARRAY_SIZE(snd_sb16_init_values), 79074c2b45bSKrzysztof Helt "ALS4000"); 79174c2b45bSKrzysztof Helt if (err < 0) 79274c2b45bSKrzysztof Helt return err; 7931da177e4SLinus Torvalds if ((err = snd_sbmixer_init(chip, 7941da177e4SLinus Torvalds snd_als4000_controls, 7951da177e4SLinus Torvalds ARRAY_SIZE(snd_als4000_controls), 7961da177e4SLinus Torvalds snd_als4000_init_values, 7971da177e4SLinus Torvalds ARRAY_SIZE(snd_als4000_init_values), 7981da177e4SLinus Torvalds "ALS4000")) < 0) 7991da177e4SLinus Torvalds return err; 8001da177e4SLinus Torvalds break; 8011da177e4SLinus Torvalds case SB_HW_DT019X: 802665ebe92SDan Carpenter err = snd_sbmixer_init(chip, 8031da177e4SLinus Torvalds snd_dt019x_controls, 8041da177e4SLinus Torvalds ARRAY_SIZE(snd_dt019x_controls), 8051da177e4SLinus Torvalds snd_dt019x_init_values, 8061da177e4SLinus Torvalds ARRAY_SIZE(snd_dt019x_init_values), 807665ebe92SDan Carpenter "DT019X"); 808665ebe92SDan Carpenter if (err < 0) 809665ebe92SDan Carpenter return err; 8101da177e4SLinus Torvalds break; 8111da177e4SLinus Torvalds default: 8121da177e4SLinus Torvalds strcpy(card->mixername, "???"); 8131da177e4SLinus Torvalds } 8141da177e4SLinus Torvalds return 0; 8151da177e4SLinus Torvalds } 8165bdb6a16STakashi Iwai 8175bdb6a16STakashi Iwai #ifdef CONFIG_PM 8185bdb6a16STakashi Iwai static unsigned char sb20_saved_regs[] = { 8195bdb6a16STakashi Iwai SB_DSP20_MASTER_DEV, 8205bdb6a16STakashi Iwai SB_DSP20_PCM_DEV, 8215bdb6a16STakashi Iwai SB_DSP20_FM_DEV, 8225bdb6a16STakashi Iwai SB_DSP20_CD_DEV, 8235bdb6a16STakashi Iwai }; 8245bdb6a16STakashi Iwai 8255bdb6a16STakashi Iwai static unsigned char sbpro_saved_regs[] = { 8265bdb6a16STakashi Iwai SB_DSP_MASTER_DEV, 8275bdb6a16STakashi Iwai SB_DSP_PCM_DEV, 8285bdb6a16STakashi Iwai SB_DSP_PLAYBACK_FILT, 8295bdb6a16STakashi Iwai SB_DSP_FM_DEV, 8305bdb6a16STakashi Iwai SB_DSP_CD_DEV, 8315bdb6a16STakashi Iwai SB_DSP_LINE_DEV, 8325bdb6a16STakashi Iwai SB_DSP_MIC_DEV, 8335bdb6a16STakashi Iwai SB_DSP_CAPTURE_SOURCE, 8345bdb6a16STakashi Iwai SB_DSP_CAPTURE_FILT, 8355bdb6a16STakashi Iwai }; 8365bdb6a16STakashi Iwai 8375bdb6a16STakashi Iwai static unsigned char sb16_saved_regs[] = { 8385bdb6a16STakashi Iwai SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1, 8395bdb6a16STakashi Iwai SB_DSP4_3DSE, 8405bdb6a16STakashi Iwai SB_DSP4_BASS_DEV, SB_DSP4_BASS_DEV + 1, 8415bdb6a16STakashi Iwai SB_DSP4_TREBLE_DEV, SB_DSP4_TREBLE_DEV + 1, 8425bdb6a16STakashi Iwai SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1, 8435bdb6a16STakashi Iwai SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 8445bdb6a16STakashi Iwai SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1, 8455bdb6a16STakashi Iwai SB_DSP4_OUTPUT_SW, 8465bdb6a16STakashi Iwai SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1, 8475bdb6a16STakashi Iwai SB_DSP4_LINE_DEV, SB_DSP4_LINE_DEV + 1, 8485bdb6a16STakashi Iwai SB_DSP4_MIC_DEV, 8495bdb6a16STakashi Iwai SB_DSP4_SPEAKER_DEV, 8505bdb6a16STakashi Iwai SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1, 8515bdb6a16STakashi Iwai SB_DSP4_OGAIN_DEV, SB_DSP4_OGAIN_DEV + 1, 8525bdb6a16STakashi Iwai SB_DSP4_MIC_AGC 8535bdb6a16STakashi Iwai }; 8545bdb6a16STakashi Iwai 8555bdb6a16STakashi Iwai static unsigned char dt019x_saved_regs[] = { 8565bdb6a16STakashi Iwai SB_DT019X_MASTER_DEV, 8575bdb6a16STakashi Iwai SB_DT019X_PCM_DEV, 8585bdb6a16STakashi Iwai SB_DT019X_SYNTH_DEV, 8595bdb6a16STakashi Iwai SB_DT019X_CD_DEV, 8605bdb6a16STakashi Iwai SB_DT019X_MIC_DEV, 8615bdb6a16STakashi Iwai SB_DT019X_SPKR_DEV, 8625bdb6a16STakashi Iwai SB_DT019X_LINE_DEV, 8635bdb6a16STakashi Iwai SB_DSP4_OUTPUT_SW, 8645bdb6a16STakashi Iwai SB_DT019X_OUTPUT_SW2, 8655bdb6a16STakashi Iwai SB_DT019X_CAPTURE_SW, 8665bdb6a16STakashi Iwai }; 8675bdb6a16STakashi Iwai 8685bdb6a16STakashi Iwai static unsigned char als4000_saved_regs[] = { 869ce71bfd1SAndreas Mohr /* please verify in dsheet whether regs to be added 870ce71bfd1SAndreas Mohr are actually real H/W or just dummy */ 8715bdb6a16STakashi Iwai SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1, 8725bdb6a16STakashi Iwai SB_DSP4_OUTPUT_SW, 8735bdb6a16STakashi Iwai SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1, 8745bdb6a16STakashi Iwai SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 8755bdb6a16STakashi Iwai SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1, 8765bdb6a16STakashi Iwai SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1, 8775bdb6a16STakashi Iwai SB_DSP4_MIC_DEV, 8785bdb6a16STakashi Iwai SB_DSP4_SPEAKER_DEV, 8795bdb6a16STakashi Iwai SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1, 8805bdb6a16STakashi Iwai SB_DSP4_OGAIN_DEV, SB_DSP4_OGAIN_DEV + 1, 8815bdb6a16STakashi Iwai SB_DT019X_OUTPUT_SW2, 8825bdb6a16STakashi Iwai SB_ALS4000_MONO_IO_CTRL, 8835bdb6a16STakashi Iwai SB_ALS4000_MIC_IN_GAIN, 884ce71bfd1SAndreas Mohr SB_ALS4000_FMDAC, 8855bdb6a16STakashi Iwai SB_ALS4000_3D_SND_FX, 8865bdb6a16STakashi Iwai SB_ALS4000_3D_TIME_DELAY, 887ce71bfd1SAndreas Mohr SB_ALS4000_CR3_CONFIGURATION, 8885bdb6a16STakashi Iwai }; 8895bdb6a16STakashi Iwai 8905bdb6a16STakashi Iwai static void save_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs) 8915bdb6a16STakashi Iwai { 8925bdb6a16STakashi Iwai unsigned char *val = chip->saved_regs; 893622207dcSTakashi Iwai if (snd_BUG_ON(num_regs > ARRAY_SIZE(chip->saved_regs))) 894622207dcSTakashi Iwai return; 8955bdb6a16STakashi Iwai for (; num_regs; num_regs--) 8965bdb6a16STakashi Iwai *val++ = snd_sbmixer_read(chip, *regs++); 8975bdb6a16STakashi Iwai } 8985bdb6a16STakashi Iwai 8995bdb6a16STakashi Iwai static void restore_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs) 9005bdb6a16STakashi Iwai { 9015bdb6a16STakashi Iwai unsigned char *val = chip->saved_regs; 902622207dcSTakashi Iwai if (snd_BUG_ON(num_regs > ARRAY_SIZE(chip->saved_regs))) 903622207dcSTakashi Iwai return; 9045bdb6a16STakashi Iwai for (; num_regs; num_regs--) 9055bdb6a16STakashi Iwai snd_sbmixer_write(chip, *regs++, *val++); 9065bdb6a16STakashi Iwai } 9075bdb6a16STakashi Iwai 9085bdb6a16STakashi Iwai void snd_sbmixer_suspend(struct snd_sb *chip) 9095bdb6a16STakashi Iwai { 9105bdb6a16STakashi Iwai switch (chip->hardware) { 9115bdb6a16STakashi Iwai case SB_HW_20: 9125bdb6a16STakashi Iwai case SB_HW_201: 9135bdb6a16STakashi Iwai save_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs)); 9145bdb6a16STakashi Iwai break; 9155bdb6a16STakashi Iwai case SB_HW_PRO: 916ad8decb7SKrzysztof Helt case SB_HW_JAZZ16: 9175bdb6a16STakashi Iwai save_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs)); 9185bdb6a16STakashi Iwai break; 9195bdb6a16STakashi Iwai case SB_HW_16: 9205bdb6a16STakashi Iwai case SB_HW_ALS100: 921621887aeSTakashi Iwai case SB_HW_CS5530: 9225bdb6a16STakashi Iwai save_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs)); 9235bdb6a16STakashi Iwai break; 9245bdb6a16STakashi Iwai case SB_HW_ALS4000: 9255bdb6a16STakashi Iwai save_mixer(chip, als4000_saved_regs, ARRAY_SIZE(als4000_saved_regs)); 9265bdb6a16STakashi Iwai break; 9275bdb6a16STakashi Iwai case SB_HW_DT019X: 9285bdb6a16STakashi Iwai save_mixer(chip, dt019x_saved_regs, ARRAY_SIZE(dt019x_saved_regs)); 9295bdb6a16STakashi Iwai break; 9305bdb6a16STakashi Iwai default: 9315bdb6a16STakashi Iwai break; 9325bdb6a16STakashi Iwai } 9335bdb6a16STakashi Iwai } 9345bdb6a16STakashi Iwai 9355bdb6a16STakashi Iwai void snd_sbmixer_resume(struct snd_sb *chip) 9365bdb6a16STakashi Iwai { 9375bdb6a16STakashi Iwai switch (chip->hardware) { 9385bdb6a16STakashi Iwai case SB_HW_20: 9395bdb6a16STakashi Iwai case SB_HW_201: 9405bdb6a16STakashi Iwai restore_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs)); 9415bdb6a16STakashi Iwai break; 9425bdb6a16STakashi Iwai case SB_HW_PRO: 943ad8decb7SKrzysztof Helt case SB_HW_JAZZ16: 9445bdb6a16STakashi Iwai restore_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs)); 9455bdb6a16STakashi Iwai break; 9465bdb6a16STakashi Iwai case SB_HW_16: 9475bdb6a16STakashi Iwai case SB_HW_ALS100: 948621887aeSTakashi Iwai case SB_HW_CS5530: 9495bdb6a16STakashi Iwai restore_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs)); 9505bdb6a16STakashi Iwai break; 9515bdb6a16STakashi Iwai case SB_HW_ALS4000: 9525bdb6a16STakashi Iwai restore_mixer(chip, als4000_saved_regs, ARRAY_SIZE(als4000_saved_regs)); 9535bdb6a16STakashi Iwai break; 9545bdb6a16STakashi Iwai case SB_HW_DT019X: 9555bdb6a16STakashi Iwai restore_mixer(chip, dt019x_saved_regs, ARRAY_SIZE(dt019x_saved_regs)); 9565bdb6a16STakashi Iwai break; 9575bdb6a16STakashi Iwai default: 9585bdb6a16STakashi Iwai break; 9595bdb6a16STakashi Iwai } 9605bdb6a16STakashi Iwai } 9615bdb6a16STakashi Iwai #endif 962