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