xref: /kernel/linux/linux-6.6/sound/isa/sb/sb_mixer.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
462306a36Sopenharmony_ci *  Routines for Sound Blaster mixer control
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/io.h>
862306a36Sopenharmony_ci#include <linux/delay.h>
962306a36Sopenharmony_ci#include <linux/time.h>
1062306a36Sopenharmony_ci#include <sound/core.h>
1162306a36Sopenharmony_ci#include <sound/sb.h>
1262306a36Sopenharmony_ci#include <sound/control.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#undef IO_DEBUG
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_civoid snd_sbmixer_write(struct snd_sb *chip, unsigned char reg, unsigned char data)
1762306a36Sopenharmony_ci{
1862306a36Sopenharmony_ci	outb(reg, SBP(chip, MIXER_ADDR));
1962306a36Sopenharmony_ci	udelay(10);
2062306a36Sopenharmony_ci	outb(data, SBP(chip, MIXER_DATA));
2162306a36Sopenharmony_ci	udelay(10);
2262306a36Sopenharmony_ci#ifdef IO_DEBUG
2362306a36Sopenharmony_ci	snd_printk(KERN_DEBUG "mixer_write 0x%x 0x%x\n", reg, data);
2462306a36Sopenharmony_ci#endif
2562306a36Sopenharmony_ci}
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ciunsigned char snd_sbmixer_read(struct snd_sb *chip, unsigned char reg)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	unsigned char result;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	outb(reg, SBP(chip, MIXER_ADDR));
3262306a36Sopenharmony_ci	udelay(10);
3362306a36Sopenharmony_ci	result = inb(SBP(chip, MIXER_DATA));
3462306a36Sopenharmony_ci	udelay(10);
3562306a36Sopenharmony_ci#ifdef IO_DEBUG
3662306a36Sopenharmony_ci	snd_printk(KERN_DEBUG "mixer_read 0x%x 0x%x\n", reg, result);
3762306a36Sopenharmony_ci#endif
3862306a36Sopenharmony_ci	return result;
3962306a36Sopenharmony_ci}
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci/*
4262306a36Sopenharmony_ci * Single channel mixer element
4362306a36Sopenharmony_ci */
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic int snd_sbmixer_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	int mask = (kcontrol->private_value >> 24) & 0xff;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
5062306a36Sopenharmony_ci	uinfo->count = 1;
5162306a36Sopenharmony_ci	uinfo->value.integer.min = 0;
5262306a36Sopenharmony_ci	uinfo->value.integer.max = mask;
5362306a36Sopenharmony_ci	return 0;
5462306a36Sopenharmony_ci}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic int snd_sbmixer_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
5962306a36Sopenharmony_ci	unsigned long flags;
6062306a36Sopenharmony_ci	int reg = kcontrol->private_value & 0xff;
6162306a36Sopenharmony_ci	int shift = (kcontrol->private_value >> 16) & 0xff;
6262306a36Sopenharmony_ci	int mask = (kcontrol->private_value >> 24) & 0xff;
6362306a36Sopenharmony_ci	unsigned char val;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	spin_lock_irqsave(&sb->mixer_lock, flags);
6662306a36Sopenharmony_ci	val = (snd_sbmixer_read(sb, reg) >> shift) & mask;
6762306a36Sopenharmony_ci	spin_unlock_irqrestore(&sb->mixer_lock, flags);
6862306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = val;
6962306a36Sopenharmony_ci	return 0;
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic int snd_sbmixer_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
7562306a36Sopenharmony_ci	unsigned long flags;
7662306a36Sopenharmony_ci	int reg = kcontrol->private_value & 0xff;
7762306a36Sopenharmony_ci	int shift = (kcontrol->private_value >> 16) & 0x07;
7862306a36Sopenharmony_ci	int mask = (kcontrol->private_value >> 24) & 0xff;
7962306a36Sopenharmony_ci	int change;
8062306a36Sopenharmony_ci	unsigned char val, oval;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	val = (ucontrol->value.integer.value[0] & mask) << shift;
8362306a36Sopenharmony_ci	spin_lock_irqsave(&sb->mixer_lock, flags);
8462306a36Sopenharmony_ci	oval = snd_sbmixer_read(sb, reg);
8562306a36Sopenharmony_ci	val = (oval & ~(mask << shift)) | val;
8662306a36Sopenharmony_ci	change = val != oval;
8762306a36Sopenharmony_ci	if (change)
8862306a36Sopenharmony_ci		snd_sbmixer_write(sb, reg, val);
8962306a36Sopenharmony_ci	spin_unlock_irqrestore(&sb->mixer_lock, flags);
9062306a36Sopenharmony_ci	return change;
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci/*
9462306a36Sopenharmony_ci * Double channel mixer element
9562306a36Sopenharmony_ci */
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic int snd_sbmixer_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	int mask = (kcontrol->private_value >> 24) & 0xff;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
10262306a36Sopenharmony_ci	uinfo->count = 2;
10362306a36Sopenharmony_ci	uinfo->value.integer.min = 0;
10462306a36Sopenharmony_ci	uinfo->value.integer.max = mask;
10562306a36Sopenharmony_ci	return 0;
10662306a36Sopenharmony_ci}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cistatic int snd_sbmixer_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
11162306a36Sopenharmony_ci	unsigned long flags;
11262306a36Sopenharmony_ci	int left_reg = kcontrol->private_value & 0xff;
11362306a36Sopenharmony_ci	int right_reg = (kcontrol->private_value >> 8) & 0xff;
11462306a36Sopenharmony_ci	int left_shift = (kcontrol->private_value >> 16) & 0x07;
11562306a36Sopenharmony_ci	int right_shift = (kcontrol->private_value >> 19) & 0x07;
11662306a36Sopenharmony_ci	int mask = (kcontrol->private_value >> 24) & 0xff;
11762306a36Sopenharmony_ci	unsigned char left, right;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	spin_lock_irqsave(&sb->mixer_lock, flags);
12062306a36Sopenharmony_ci	left = (snd_sbmixer_read(sb, left_reg) >> left_shift) & mask;
12162306a36Sopenharmony_ci	right = (snd_sbmixer_read(sb, right_reg) >> right_shift) & mask;
12262306a36Sopenharmony_ci	spin_unlock_irqrestore(&sb->mixer_lock, flags);
12362306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = left;
12462306a36Sopenharmony_ci	ucontrol->value.integer.value[1] = right;
12562306a36Sopenharmony_ci	return 0;
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic int snd_sbmixer_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
13162306a36Sopenharmony_ci	unsigned long flags;
13262306a36Sopenharmony_ci	int left_reg = kcontrol->private_value & 0xff;
13362306a36Sopenharmony_ci	int right_reg = (kcontrol->private_value >> 8) & 0xff;
13462306a36Sopenharmony_ci	int left_shift = (kcontrol->private_value >> 16) & 0x07;
13562306a36Sopenharmony_ci	int right_shift = (kcontrol->private_value >> 19) & 0x07;
13662306a36Sopenharmony_ci	int mask = (kcontrol->private_value >> 24) & 0xff;
13762306a36Sopenharmony_ci	int change;
13862306a36Sopenharmony_ci	unsigned char left, right, oleft, oright;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	left = (ucontrol->value.integer.value[0] & mask) << left_shift;
14162306a36Sopenharmony_ci	right = (ucontrol->value.integer.value[1] & mask) << right_shift;
14262306a36Sopenharmony_ci	spin_lock_irqsave(&sb->mixer_lock, flags);
14362306a36Sopenharmony_ci	if (left_reg == right_reg) {
14462306a36Sopenharmony_ci		oleft = snd_sbmixer_read(sb, left_reg);
14562306a36Sopenharmony_ci		left = (oleft & ~((mask << left_shift) | (mask << right_shift))) | left | right;
14662306a36Sopenharmony_ci		change = left != oleft;
14762306a36Sopenharmony_ci		if (change)
14862306a36Sopenharmony_ci			snd_sbmixer_write(sb, left_reg, left);
14962306a36Sopenharmony_ci	} else {
15062306a36Sopenharmony_ci		oleft = snd_sbmixer_read(sb, left_reg);
15162306a36Sopenharmony_ci		oright = snd_sbmixer_read(sb, right_reg);
15262306a36Sopenharmony_ci		left = (oleft & ~(mask << left_shift)) | left;
15362306a36Sopenharmony_ci		right = (oright & ~(mask << right_shift)) | right;
15462306a36Sopenharmony_ci		change = left != oleft || right != oright;
15562306a36Sopenharmony_ci		if (change) {
15662306a36Sopenharmony_ci			snd_sbmixer_write(sb, left_reg, left);
15762306a36Sopenharmony_ci			snd_sbmixer_write(sb, right_reg, right);
15862306a36Sopenharmony_ci		}
15962306a36Sopenharmony_ci	}
16062306a36Sopenharmony_ci	spin_unlock_irqrestore(&sb->mixer_lock, flags);
16162306a36Sopenharmony_ci	return change;
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci/*
16562306a36Sopenharmony_ci * DT-019x / ALS-007 capture/input switch
16662306a36Sopenharmony_ci */
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistatic int snd_dt019x_input_sw_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	static const char * const texts[5] = {
17162306a36Sopenharmony_ci		"CD", "Mic", "Line", "Synth", "Master"
17262306a36Sopenharmony_ci	};
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 5, texts);
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistatic int snd_dt019x_input_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
18062306a36Sopenharmony_ci	unsigned long flags;
18162306a36Sopenharmony_ci	unsigned char oval;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	spin_lock_irqsave(&sb->mixer_lock, flags);
18462306a36Sopenharmony_ci	oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW);
18562306a36Sopenharmony_ci	spin_unlock_irqrestore(&sb->mixer_lock, flags);
18662306a36Sopenharmony_ci	switch (oval & 0x07) {
18762306a36Sopenharmony_ci	case SB_DT019X_CAP_CD:
18862306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 0;
18962306a36Sopenharmony_ci		break;
19062306a36Sopenharmony_ci	case SB_DT019X_CAP_MIC:
19162306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 1;
19262306a36Sopenharmony_ci		break;
19362306a36Sopenharmony_ci	case SB_DT019X_CAP_LINE:
19462306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 2;
19562306a36Sopenharmony_ci		break;
19662306a36Sopenharmony_ci	case SB_DT019X_CAP_MAIN:
19762306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 4;
19862306a36Sopenharmony_ci		break;
19962306a36Sopenharmony_ci	/* To record the synth on these cards you must record the main.   */
20062306a36Sopenharmony_ci	/* Thus SB_DT019X_CAP_SYNTH == SB_DT019X_CAP_MAIN and would cause */
20162306a36Sopenharmony_ci	/* duplicate case labels if left uncommented. */
20262306a36Sopenharmony_ci	/* case SB_DT019X_CAP_SYNTH:
20362306a36Sopenharmony_ci	 *	ucontrol->value.enumerated.item[0] = 3;
20462306a36Sopenharmony_ci	 *	break;
20562306a36Sopenharmony_ci	 */
20662306a36Sopenharmony_ci	default:
20762306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 4;
20862306a36Sopenharmony_ci		break;
20962306a36Sopenharmony_ci	}
21062306a36Sopenharmony_ci	return 0;
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_cistatic int snd_dt019x_input_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
21462306a36Sopenharmony_ci{
21562306a36Sopenharmony_ci	struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
21662306a36Sopenharmony_ci	unsigned long flags;
21762306a36Sopenharmony_ci	int change;
21862306a36Sopenharmony_ci	unsigned char nval, oval;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	if (ucontrol->value.enumerated.item[0] > 4)
22162306a36Sopenharmony_ci		return -EINVAL;
22262306a36Sopenharmony_ci	switch (ucontrol->value.enumerated.item[0]) {
22362306a36Sopenharmony_ci	case 0:
22462306a36Sopenharmony_ci		nval = SB_DT019X_CAP_CD;
22562306a36Sopenharmony_ci		break;
22662306a36Sopenharmony_ci	case 1:
22762306a36Sopenharmony_ci		nval = SB_DT019X_CAP_MIC;
22862306a36Sopenharmony_ci		break;
22962306a36Sopenharmony_ci	case 2:
23062306a36Sopenharmony_ci		nval = SB_DT019X_CAP_LINE;
23162306a36Sopenharmony_ci		break;
23262306a36Sopenharmony_ci	case 3:
23362306a36Sopenharmony_ci		nval = SB_DT019X_CAP_SYNTH;
23462306a36Sopenharmony_ci		break;
23562306a36Sopenharmony_ci	case 4:
23662306a36Sopenharmony_ci		nval = SB_DT019X_CAP_MAIN;
23762306a36Sopenharmony_ci		break;
23862306a36Sopenharmony_ci	default:
23962306a36Sopenharmony_ci		nval = SB_DT019X_CAP_MAIN;
24062306a36Sopenharmony_ci	}
24162306a36Sopenharmony_ci	spin_lock_irqsave(&sb->mixer_lock, flags);
24262306a36Sopenharmony_ci	oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW);
24362306a36Sopenharmony_ci	change = nval != oval;
24462306a36Sopenharmony_ci	if (change)
24562306a36Sopenharmony_ci		snd_sbmixer_write(sb, SB_DT019X_CAPTURE_SW, nval);
24662306a36Sopenharmony_ci	spin_unlock_irqrestore(&sb->mixer_lock, flags);
24762306a36Sopenharmony_ci	return change;
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci/*
25162306a36Sopenharmony_ci * ALS4000 mono recording control switch
25262306a36Sopenharmony_ci */
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic int snd_als4k_mono_capture_route_info(struct snd_kcontrol *kcontrol,
25562306a36Sopenharmony_ci					     struct snd_ctl_elem_info *uinfo)
25662306a36Sopenharmony_ci{
25762306a36Sopenharmony_ci	static const char * const texts[3] = {
25862306a36Sopenharmony_ci		"L chan only", "R chan only", "L ch/2 + R ch/2"
25962306a36Sopenharmony_ci	};
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 3, texts);
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_cistatic int snd_als4k_mono_capture_route_get(struct snd_kcontrol *kcontrol,
26562306a36Sopenharmony_ci				struct snd_ctl_elem_value *ucontrol)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
26862306a36Sopenharmony_ci	unsigned long flags;
26962306a36Sopenharmony_ci	unsigned char oval;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	spin_lock_irqsave(&sb->mixer_lock, flags);
27262306a36Sopenharmony_ci	oval = snd_sbmixer_read(sb, SB_ALS4000_MONO_IO_CTRL);
27362306a36Sopenharmony_ci	spin_unlock_irqrestore(&sb->mixer_lock, flags);
27462306a36Sopenharmony_ci	oval >>= 6;
27562306a36Sopenharmony_ci	if (oval > 2)
27662306a36Sopenharmony_ci		oval = 2;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	ucontrol->value.enumerated.item[0] = oval;
27962306a36Sopenharmony_ci	return 0;
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistatic int snd_als4k_mono_capture_route_put(struct snd_kcontrol *kcontrol,
28362306a36Sopenharmony_ci				struct snd_ctl_elem_value *ucontrol)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
28662306a36Sopenharmony_ci	unsigned long flags;
28762306a36Sopenharmony_ci	int change;
28862306a36Sopenharmony_ci	unsigned char nval, oval;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	if (ucontrol->value.enumerated.item[0] > 2)
29162306a36Sopenharmony_ci		return -EINVAL;
29262306a36Sopenharmony_ci	spin_lock_irqsave(&sb->mixer_lock, flags);
29362306a36Sopenharmony_ci	oval = snd_sbmixer_read(sb, SB_ALS4000_MONO_IO_CTRL);
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	nval = (oval & ~(3 << 6))
29662306a36Sopenharmony_ci	     | (ucontrol->value.enumerated.item[0] << 6);
29762306a36Sopenharmony_ci	change = nval != oval;
29862306a36Sopenharmony_ci	if (change)
29962306a36Sopenharmony_ci		snd_sbmixer_write(sb, SB_ALS4000_MONO_IO_CTRL, nval);
30062306a36Sopenharmony_ci	spin_unlock_irqrestore(&sb->mixer_lock, flags);
30162306a36Sopenharmony_ci	return change;
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci/*
30562306a36Sopenharmony_ci * SBPRO input multiplexer
30662306a36Sopenharmony_ci */
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_cistatic int snd_sb8mixer_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
30962306a36Sopenharmony_ci{
31062306a36Sopenharmony_ci	static const char * const texts[3] = {
31162306a36Sopenharmony_ci		"Mic", "CD", "Line"
31262306a36Sopenharmony_ci	};
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, 3, texts);
31562306a36Sopenharmony_ci}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cistatic int snd_sb8mixer_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
31962306a36Sopenharmony_ci{
32062306a36Sopenharmony_ci	struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
32162306a36Sopenharmony_ci	unsigned long flags;
32262306a36Sopenharmony_ci	unsigned char oval;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	spin_lock_irqsave(&sb->mixer_lock, flags);
32562306a36Sopenharmony_ci	oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE);
32662306a36Sopenharmony_ci	spin_unlock_irqrestore(&sb->mixer_lock, flags);
32762306a36Sopenharmony_ci	switch ((oval >> 0x01) & 0x03) {
32862306a36Sopenharmony_ci	case SB_DSP_MIXS_CD:
32962306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 1;
33062306a36Sopenharmony_ci		break;
33162306a36Sopenharmony_ci	case SB_DSP_MIXS_LINE:
33262306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 2;
33362306a36Sopenharmony_ci		break;
33462306a36Sopenharmony_ci	default:
33562306a36Sopenharmony_ci		ucontrol->value.enumerated.item[0] = 0;
33662306a36Sopenharmony_ci		break;
33762306a36Sopenharmony_ci	}
33862306a36Sopenharmony_ci	return 0;
33962306a36Sopenharmony_ci}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_cistatic int snd_sb8mixer_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
34462306a36Sopenharmony_ci	unsigned long flags;
34562306a36Sopenharmony_ci	int change;
34662306a36Sopenharmony_ci	unsigned char nval, oval;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	if (ucontrol->value.enumerated.item[0] > 2)
34962306a36Sopenharmony_ci		return -EINVAL;
35062306a36Sopenharmony_ci	switch (ucontrol->value.enumerated.item[0]) {
35162306a36Sopenharmony_ci	case 1:
35262306a36Sopenharmony_ci		nval = SB_DSP_MIXS_CD;
35362306a36Sopenharmony_ci		break;
35462306a36Sopenharmony_ci	case 2:
35562306a36Sopenharmony_ci		nval = SB_DSP_MIXS_LINE;
35662306a36Sopenharmony_ci		break;
35762306a36Sopenharmony_ci	default:
35862306a36Sopenharmony_ci		nval = SB_DSP_MIXS_MIC;
35962306a36Sopenharmony_ci	}
36062306a36Sopenharmony_ci	nval <<= 1;
36162306a36Sopenharmony_ci	spin_lock_irqsave(&sb->mixer_lock, flags);
36262306a36Sopenharmony_ci	oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE);
36362306a36Sopenharmony_ci	nval |= oval & ~0x06;
36462306a36Sopenharmony_ci	change = nval != oval;
36562306a36Sopenharmony_ci	if (change)
36662306a36Sopenharmony_ci		snd_sbmixer_write(sb, SB_DSP_CAPTURE_SOURCE, nval);
36762306a36Sopenharmony_ci	spin_unlock_irqrestore(&sb->mixer_lock, flags);
36862306a36Sopenharmony_ci	return change;
36962306a36Sopenharmony_ci}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci/*
37262306a36Sopenharmony_ci * SB16 input switch
37362306a36Sopenharmony_ci */
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_cistatic int snd_sb16mixer_info_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
37662306a36Sopenharmony_ci{
37762306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
37862306a36Sopenharmony_ci	uinfo->count = 4;
37962306a36Sopenharmony_ci	uinfo->value.integer.min = 0;
38062306a36Sopenharmony_ci	uinfo->value.integer.max = 1;
38162306a36Sopenharmony_ci	return 0;
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_cistatic int snd_sb16mixer_get_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci	struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
38762306a36Sopenharmony_ci	unsigned long flags;
38862306a36Sopenharmony_ci	int reg1 = kcontrol->private_value & 0xff;
38962306a36Sopenharmony_ci	int reg2 = (kcontrol->private_value >> 8) & 0xff;
39062306a36Sopenharmony_ci	int left_shift = (kcontrol->private_value >> 16) & 0x0f;
39162306a36Sopenharmony_ci	int right_shift = (kcontrol->private_value >> 24) & 0x0f;
39262306a36Sopenharmony_ci	unsigned char val1, val2;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	spin_lock_irqsave(&sb->mixer_lock, flags);
39562306a36Sopenharmony_ci	val1 = snd_sbmixer_read(sb, reg1);
39662306a36Sopenharmony_ci	val2 = snd_sbmixer_read(sb, reg2);
39762306a36Sopenharmony_ci	spin_unlock_irqrestore(&sb->mixer_lock, flags);
39862306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = (val1 >> left_shift) & 0x01;
39962306a36Sopenharmony_ci	ucontrol->value.integer.value[1] = (val2 >> left_shift) & 0x01;
40062306a36Sopenharmony_ci	ucontrol->value.integer.value[2] = (val1 >> right_shift) & 0x01;
40162306a36Sopenharmony_ci	ucontrol->value.integer.value[3] = (val2 >> right_shift) & 0x01;
40262306a36Sopenharmony_ci	return 0;
40362306a36Sopenharmony_ci}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_cistatic int snd_sb16mixer_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
40662306a36Sopenharmony_ci{
40762306a36Sopenharmony_ci	struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
40862306a36Sopenharmony_ci	unsigned long flags;
40962306a36Sopenharmony_ci	int reg1 = kcontrol->private_value & 0xff;
41062306a36Sopenharmony_ci	int reg2 = (kcontrol->private_value >> 8) & 0xff;
41162306a36Sopenharmony_ci	int left_shift = (kcontrol->private_value >> 16) & 0x0f;
41262306a36Sopenharmony_ci	int right_shift = (kcontrol->private_value >> 24) & 0x0f;
41362306a36Sopenharmony_ci	int change;
41462306a36Sopenharmony_ci	unsigned char val1, val2, oval1, oval2;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	spin_lock_irqsave(&sb->mixer_lock, flags);
41762306a36Sopenharmony_ci	oval1 = snd_sbmixer_read(sb, reg1);
41862306a36Sopenharmony_ci	oval2 = snd_sbmixer_read(sb, reg2);
41962306a36Sopenharmony_ci	val1 = oval1 & ~((1 << left_shift) | (1 << right_shift));
42062306a36Sopenharmony_ci	val2 = oval2 & ~((1 << left_shift) | (1 << right_shift));
42162306a36Sopenharmony_ci	val1 |= (ucontrol->value.integer.value[0] & 1) << left_shift;
42262306a36Sopenharmony_ci	val2 |= (ucontrol->value.integer.value[1] & 1) << left_shift;
42362306a36Sopenharmony_ci	val1 |= (ucontrol->value.integer.value[2] & 1) << right_shift;
42462306a36Sopenharmony_ci	val2 |= (ucontrol->value.integer.value[3] & 1) << right_shift;
42562306a36Sopenharmony_ci	change = val1 != oval1 || val2 != oval2;
42662306a36Sopenharmony_ci	if (change) {
42762306a36Sopenharmony_ci		snd_sbmixer_write(sb, reg1, val1);
42862306a36Sopenharmony_ci		snd_sbmixer_write(sb, reg2, val2);
42962306a36Sopenharmony_ci	}
43062306a36Sopenharmony_ci	spin_unlock_irqrestore(&sb->mixer_lock, flags);
43162306a36Sopenharmony_ci	return change;
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci/*
43662306a36Sopenharmony_ci */
43762306a36Sopenharmony_ci/*
43862306a36Sopenharmony_ci */
43962306a36Sopenharmony_ciint snd_sbmixer_add_ctl(struct snd_sb *chip, const char *name, int index, int type, unsigned long value)
44062306a36Sopenharmony_ci{
44162306a36Sopenharmony_ci	static const struct snd_kcontrol_new newctls[] = {
44262306a36Sopenharmony_ci		[SB_MIX_SINGLE] = {
44362306a36Sopenharmony_ci			.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
44462306a36Sopenharmony_ci			.info = snd_sbmixer_info_single,
44562306a36Sopenharmony_ci			.get = snd_sbmixer_get_single,
44662306a36Sopenharmony_ci			.put = snd_sbmixer_put_single,
44762306a36Sopenharmony_ci		},
44862306a36Sopenharmony_ci		[SB_MIX_DOUBLE] = {
44962306a36Sopenharmony_ci			.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
45062306a36Sopenharmony_ci			.info = snd_sbmixer_info_double,
45162306a36Sopenharmony_ci			.get = snd_sbmixer_get_double,
45262306a36Sopenharmony_ci			.put = snd_sbmixer_put_double,
45362306a36Sopenharmony_ci		},
45462306a36Sopenharmony_ci		[SB_MIX_INPUT_SW] = {
45562306a36Sopenharmony_ci			.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
45662306a36Sopenharmony_ci			.info = snd_sb16mixer_info_input_sw,
45762306a36Sopenharmony_ci			.get = snd_sb16mixer_get_input_sw,
45862306a36Sopenharmony_ci			.put = snd_sb16mixer_put_input_sw,
45962306a36Sopenharmony_ci		},
46062306a36Sopenharmony_ci		[SB_MIX_CAPTURE_PRO] = {
46162306a36Sopenharmony_ci			.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
46262306a36Sopenharmony_ci			.info = snd_sb8mixer_info_mux,
46362306a36Sopenharmony_ci			.get = snd_sb8mixer_get_mux,
46462306a36Sopenharmony_ci			.put = snd_sb8mixer_put_mux,
46562306a36Sopenharmony_ci		},
46662306a36Sopenharmony_ci		[SB_MIX_CAPTURE_DT019X] = {
46762306a36Sopenharmony_ci			.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
46862306a36Sopenharmony_ci			.info = snd_dt019x_input_sw_info,
46962306a36Sopenharmony_ci			.get = snd_dt019x_input_sw_get,
47062306a36Sopenharmony_ci			.put = snd_dt019x_input_sw_put,
47162306a36Sopenharmony_ci		},
47262306a36Sopenharmony_ci		[SB_MIX_MONO_CAPTURE_ALS4K] = {
47362306a36Sopenharmony_ci			.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
47462306a36Sopenharmony_ci			.info = snd_als4k_mono_capture_route_info,
47562306a36Sopenharmony_ci			.get = snd_als4k_mono_capture_route_get,
47662306a36Sopenharmony_ci			.put = snd_als4k_mono_capture_route_put,
47762306a36Sopenharmony_ci		},
47862306a36Sopenharmony_ci	};
47962306a36Sopenharmony_ci	struct snd_kcontrol *ctl;
48062306a36Sopenharmony_ci	int err;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	ctl = snd_ctl_new1(&newctls[type], chip);
48362306a36Sopenharmony_ci	if (! ctl)
48462306a36Sopenharmony_ci		return -ENOMEM;
48562306a36Sopenharmony_ci	strscpy(ctl->id.name, name, sizeof(ctl->id.name));
48662306a36Sopenharmony_ci	ctl->id.index = index;
48762306a36Sopenharmony_ci	ctl->private_value = value;
48862306a36Sopenharmony_ci	err = snd_ctl_add(chip->card, ctl);
48962306a36Sopenharmony_ci	if (err < 0)
49062306a36Sopenharmony_ci		return err;
49162306a36Sopenharmony_ci	return 0;
49262306a36Sopenharmony_ci}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci/*
49562306a36Sopenharmony_ci * SB 2.0 specific mixer elements
49662306a36Sopenharmony_ci */
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_cistatic const struct sbmix_elem snd_sb20_controls[] = {
49962306a36Sopenharmony_ci	SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7),
50062306a36Sopenharmony_ci	SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3),
50162306a36Sopenharmony_ci	SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7),
50262306a36Sopenharmony_ci	SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7)
50362306a36Sopenharmony_ci};
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_cistatic const unsigned char snd_sb20_init_values[][2] = {
50662306a36Sopenharmony_ci	{ SB_DSP20_MASTER_DEV, 0 },
50762306a36Sopenharmony_ci	{ SB_DSP20_FM_DEV, 0 },
50862306a36Sopenharmony_ci};
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci/*
51162306a36Sopenharmony_ci * SB Pro specific mixer elements
51262306a36Sopenharmony_ci */
51362306a36Sopenharmony_cistatic const struct sbmix_elem snd_sbpro_controls[] = {
51462306a36Sopenharmony_ci	SB_DOUBLE("Master Playback Volume",
51562306a36Sopenharmony_ci		  SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7),
51662306a36Sopenharmony_ci	SB_DOUBLE("PCM Playback Volume",
51762306a36Sopenharmony_ci		  SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7),
51862306a36Sopenharmony_ci	SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1),
51962306a36Sopenharmony_ci	SB_DOUBLE("Synth Playback Volume",
52062306a36Sopenharmony_ci		  SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7),
52162306a36Sopenharmony_ci	SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7),
52262306a36Sopenharmony_ci	SB_DOUBLE("Line Playback Volume",
52362306a36Sopenharmony_ci		  SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7),
52462306a36Sopenharmony_ci	SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3),
52562306a36Sopenharmony_ci	{
52662306a36Sopenharmony_ci		.name = "Capture Source",
52762306a36Sopenharmony_ci		.type = SB_MIX_CAPTURE_PRO
52862306a36Sopenharmony_ci	},
52962306a36Sopenharmony_ci	SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1),
53062306a36Sopenharmony_ci	SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1)
53162306a36Sopenharmony_ci};
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_cistatic const unsigned char snd_sbpro_init_values[][2] = {
53462306a36Sopenharmony_ci	{ SB_DSP_MASTER_DEV, 0 },
53562306a36Sopenharmony_ci	{ SB_DSP_PCM_DEV, 0 },
53662306a36Sopenharmony_ci	{ SB_DSP_FM_DEV, 0 },
53762306a36Sopenharmony_ci};
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci/*
54062306a36Sopenharmony_ci * SB16 specific mixer elements
54162306a36Sopenharmony_ci */
54262306a36Sopenharmony_cistatic const struct sbmix_elem snd_sb16_controls[] = {
54362306a36Sopenharmony_ci	SB_DOUBLE("Master Playback Volume",
54462306a36Sopenharmony_ci		  SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31),
54562306a36Sopenharmony_ci	SB_DOUBLE("PCM Playback Volume",
54662306a36Sopenharmony_ci		  SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31),
54762306a36Sopenharmony_ci	SB16_INPUT_SW("Synth Capture Route",
54862306a36Sopenharmony_ci		      SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5),
54962306a36Sopenharmony_ci	SB_DOUBLE("Synth Playback Volume",
55062306a36Sopenharmony_ci		  SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31),
55162306a36Sopenharmony_ci	SB16_INPUT_SW("CD Capture Route",
55262306a36Sopenharmony_ci		      SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1),
55362306a36Sopenharmony_ci	SB_DOUBLE("CD Playback Switch",
55462306a36Sopenharmony_ci		  SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1),
55562306a36Sopenharmony_ci	SB_DOUBLE("CD Playback Volume",
55662306a36Sopenharmony_ci		  SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31),
55762306a36Sopenharmony_ci	SB16_INPUT_SW("Mic Capture Route",
55862306a36Sopenharmony_ci		      SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0),
55962306a36Sopenharmony_ci	SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1),
56062306a36Sopenharmony_ci	SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31),
56162306a36Sopenharmony_ci	SB_SINGLE("Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3),
56262306a36Sopenharmony_ci	SB_DOUBLE("Capture Volume",
56362306a36Sopenharmony_ci		  SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3),
56462306a36Sopenharmony_ci	SB_DOUBLE("Playback Volume",
56562306a36Sopenharmony_ci		  SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3),
56662306a36Sopenharmony_ci	SB16_INPUT_SW("Line Capture Route",
56762306a36Sopenharmony_ci		      SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3),
56862306a36Sopenharmony_ci	SB_DOUBLE("Line Playback Switch",
56962306a36Sopenharmony_ci		  SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1),
57062306a36Sopenharmony_ci	SB_DOUBLE("Line Playback Volume",
57162306a36Sopenharmony_ci		  SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31),
57262306a36Sopenharmony_ci	SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1),
57362306a36Sopenharmony_ci	SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1),
57462306a36Sopenharmony_ci	SB_DOUBLE("Tone Control - Bass",
57562306a36Sopenharmony_ci		  SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15),
57662306a36Sopenharmony_ci	SB_DOUBLE("Tone Control - Treble",
57762306a36Sopenharmony_ci		  SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15)
57862306a36Sopenharmony_ci};
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_cistatic const unsigned char snd_sb16_init_values[][2] = {
58162306a36Sopenharmony_ci	{ SB_DSP4_MASTER_DEV + 0, 0 },
58262306a36Sopenharmony_ci	{ SB_DSP4_MASTER_DEV + 1, 0 },
58362306a36Sopenharmony_ci	{ SB_DSP4_PCM_DEV + 0, 0 },
58462306a36Sopenharmony_ci	{ SB_DSP4_PCM_DEV + 1, 0 },
58562306a36Sopenharmony_ci	{ SB_DSP4_SYNTH_DEV + 0, 0 },
58662306a36Sopenharmony_ci	{ SB_DSP4_SYNTH_DEV + 1, 0 },
58762306a36Sopenharmony_ci	{ SB_DSP4_INPUT_LEFT, 0 },
58862306a36Sopenharmony_ci	{ SB_DSP4_INPUT_RIGHT, 0 },
58962306a36Sopenharmony_ci	{ SB_DSP4_OUTPUT_SW, 0 },
59062306a36Sopenharmony_ci	{ SB_DSP4_SPEAKER_DEV, 0 },
59162306a36Sopenharmony_ci};
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci/*
59462306a36Sopenharmony_ci * DT019x specific mixer elements
59562306a36Sopenharmony_ci */
59662306a36Sopenharmony_cistatic const struct sbmix_elem snd_dt019x_controls[] = {
59762306a36Sopenharmony_ci	/* ALS4000 below has some parts which we might be lacking,
59862306a36Sopenharmony_ci	 * e.g. snd_als4000_ctl_mono_playback_switch - check it! */
59962306a36Sopenharmony_ci	SB_DOUBLE("Master Playback Volume",
60062306a36Sopenharmony_ci		  SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4, 0, 15),
60162306a36Sopenharmony_ci	SB_DOUBLE("PCM Playback Switch",
60262306a36Sopenharmony_ci		  SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1),
60362306a36Sopenharmony_ci	SB_DOUBLE("PCM Playback Volume",
60462306a36Sopenharmony_ci		  SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4, 0, 15),
60562306a36Sopenharmony_ci	SB_DOUBLE("Synth Playback Switch",
60662306a36Sopenharmony_ci		  SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1),
60762306a36Sopenharmony_ci	SB_DOUBLE("Synth Playback Volume",
60862306a36Sopenharmony_ci		  SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4, 0, 15),
60962306a36Sopenharmony_ci	SB_DOUBLE("CD Playback Switch",
61062306a36Sopenharmony_ci		  SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1),
61162306a36Sopenharmony_ci	SB_DOUBLE("CD Playback Volume",
61262306a36Sopenharmony_ci		  SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4, 0, 15),
61362306a36Sopenharmony_ci	SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1),
61462306a36Sopenharmony_ci	SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7),
61562306a36Sopenharmony_ci	SB_SINGLE("Beep Volume", SB_DT019X_SPKR_DEV, 0,  7),
61662306a36Sopenharmony_ci	SB_DOUBLE("Line Playback Switch",
61762306a36Sopenharmony_ci		  SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1),
61862306a36Sopenharmony_ci	SB_DOUBLE("Line Playback Volume",
61962306a36Sopenharmony_ci		  SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4, 0, 15),
62062306a36Sopenharmony_ci	{
62162306a36Sopenharmony_ci		.name = "Capture Source",
62262306a36Sopenharmony_ci		.type = SB_MIX_CAPTURE_DT019X
62362306a36Sopenharmony_ci	}
62462306a36Sopenharmony_ci};
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_cistatic const unsigned char snd_dt019x_init_values[][2] = {
62762306a36Sopenharmony_ci        { SB_DT019X_MASTER_DEV, 0 },
62862306a36Sopenharmony_ci        { SB_DT019X_PCM_DEV, 0 },
62962306a36Sopenharmony_ci        { SB_DT019X_SYNTH_DEV, 0 },
63062306a36Sopenharmony_ci        { SB_DT019X_CD_DEV, 0 },
63162306a36Sopenharmony_ci        { SB_DT019X_MIC_DEV, 0 },	/* Includes PC-speaker in high nibble */
63262306a36Sopenharmony_ci        { SB_DT019X_LINE_DEV, 0 },
63362306a36Sopenharmony_ci        { SB_DSP4_OUTPUT_SW, 0 },
63462306a36Sopenharmony_ci        { SB_DT019X_OUTPUT_SW2, 0 },
63562306a36Sopenharmony_ci        { SB_DT019X_CAPTURE_SW, 0x06 },
63662306a36Sopenharmony_ci};
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci/*
63962306a36Sopenharmony_ci * ALS4000 specific mixer elements
64062306a36Sopenharmony_ci */
64162306a36Sopenharmony_cistatic const struct sbmix_elem snd_als4000_controls[] = {
64262306a36Sopenharmony_ci	SB_DOUBLE("PCM Playback Switch",
64362306a36Sopenharmony_ci		  SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1),
64462306a36Sopenharmony_ci	SB_DOUBLE("Synth Playback Switch",
64562306a36Sopenharmony_ci		  SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1),
64662306a36Sopenharmony_ci	SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03),
64762306a36Sopenharmony_ci	SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1),
64862306a36Sopenharmony_ci	{
64962306a36Sopenharmony_ci		.name = "Master Mono Capture Route",
65062306a36Sopenharmony_ci		.type = SB_MIX_MONO_CAPTURE_ALS4K
65162306a36Sopenharmony_ci	},
65262306a36Sopenharmony_ci	SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2, 0, 1),
65362306a36Sopenharmony_ci	SB_SINGLE("Analog Loopback Switch", SB_ALS4000_MIC_IN_GAIN, 7, 0x01),
65462306a36Sopenharmony_ci	SB_SINGLE("3D Control - Switch", SB_ALS4000_3D_SND_FX, 6, 0x01),
65562306a36Sopenharmony_ci	SB_SINGLE("Digital Loopback Switch",
65662306a36Sopenharmony_ci		  SB_ALS4000_CR3_CONFIGURATION, 7, 0x01),
65762306a36Sopenharmony_ci	/* FIXME: functionality of 3D controls might be swapped, I didn't find
65862306a36Sopenharmony_ci	 * a description of how to identify what is supposed to be what */
65962306a36Sopenharmony_ci	SB_SINGLE("3D Control - Level", SB_ALS4000_3D_SND_FX, 0, 0x07),
66062306a36Sopenharmony_ci	/* FIXME: maybe there's actually some standard 3D ctrl name for it?? */
66162306a36Sopenharmony_ci	SB_SINGLE("3D Control - Freq", SB_ALS4000_3D_SND_FX, 4, 0x03),
66262306a36Sopenharmony_ci	/* FIXME: ALS4000a.pdf mentions BBD (Bucket Brigade Device) time delay,
66362306a36Sopenharmony_ci	 * but what ALSA 3D attribute is that actually? "Center", "Depth",
66462306a36Sopenharmony_ci	 * "Wide" or "Space" or even "Level"? Assuming "Wide" for now... */
66562306a36Sopenharmony_ci	SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f),
66662306a36Sopenharmony_ci	SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01),
66762306a36Sopenharmony_ci	SB_SINGLE("Master Playback 8kHz / 20kHz LPF Switch",
66862306a36Sopenharmony_ci		  SB_ALS4000_FMDAC, 5, 0x01),
66962306a36Sopenharmony_ci#ifdef NOT_AVAILABLE
67062306a36Sopenharmony_ci	SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01),
67162306a36Sopenharmony_ci	SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f),
67262306a36Sopenharmony_ci#endif
67362306a36Sopenharmony_ci};
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_cistatic const unsigned char snd_als4000_init_values[][2] = {
67662306a36Sopenharmony_ci	{ SB_DSP4_MASTER_DEV + 0, 0 },
67762306a36Sopenharmony_ci	{ SB_DSP4_MASTER_DEV + 1, 0 },
67862306a36Sopenharmony_ci	{ SB_DSP4_PCM_DEV + 0, 0 },
67962306a36Sopenharmony_ci	{ SB_DSP4_PCM_DEV + 1, 0 },
68062306a36Sopenharmony_ci	{ SB_DSP4_SYNTH_DEV + 0, 0 },
68162306a36Sopenharmony_ci	{ SB_DSP4_SYNTH_DEV + 1, 0 },
68262306a36Sopenharmony_ci	{ SB_DSP4_SPEAKER_DEV, 0 },
68362306a36Sopenharmony_ci	{ SB_DSP4_OUTPUT_SW, 0 },
68462306a36Sopenharmony_ci	{ SB_DSP4_INPUT_LEFT, 0 },
68562306a36Sopenharmony_ci	{ SB_DSP4_INPUT_RIGHT, 0 },
68662306a36Sopenharmony_ci	{ SB_DT019X_OUTPUT_SW2, 0 },
68762306a36Sopenharmony_ci	{ SB_ALS4000_MIC_IN_GAIN, 0 },
68862306a36Sopenharmony_ci};
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci/*
69162306a36Sopenharmony_ci */
69262306a36Sopenharmony_cistatic int snd_sbmixer_init(struct snd_sb *chip,
69362306a36Sopenharmony_ci			    const struct sbmix_elem *controls,
69462306a36Sopenharmony_ci			    int controls_count,
69562306a36Sopenharmony_ci			    const unsigned char map[][2],
69662306a36Sopenharmony_ci			    int map_count,
69762306a36Sopenharmony_ci			    char *name)
69862306a36Sopenharmony_ci{
69962306a36Sopenharmony_ci	unsigned long flags;
70062306a36Sopenharmony_ci	struct snd_card *card = chip->card;
70162306a36Sopenharmony_ci	int idx, err;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	/* mixer reset */
70462306a36Sopenharmony_ci	spin_lock_irqsave(&chip->mixer_lock, flags);
70562306a36Sopenharmony_ci	snd_sbmixer_write(chip, 0x00, 0x00);
70662306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->mixer_lock, flags);
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	/* mute and zero volume channels */
70962306a36Sopenharmony_ci	for (idx = 0; idx < map_count; idx++) {
71062306a36Sopenharmony_ci		spin_lock_irqsave(&chip->mixer_lock, flags);
71162306a36Sopenharmony_ci		snd_sbmixer_write(chip, map[idx][0], map[idx][1]);
71262306a36Sopenharmony_ci		spin_unlock_irqrestore(&chip->mixer_lock, flags);
71362306a36Sopenharmony_ci	}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	for (idx = 0; idx < controls_count; idx++) {
71662306a36Sopenharmony_ci		err = snd_sbmixer_add_ctl_elem(chip, &controls[idx]);
71762306a36Sopenharmony_ci		if (err < 0)
71862306a36Sopenharmony_ci			return err;
71962306a36Sopenharmony_ci	}
72062306a36Sopenharmony_ci	snd_component_add(card, name);
72162306a36Sopenharmony_ci	strcpy(card->mixername, name);
72262306a36Sopenharmony_ci	return 0;
72362306a36Sopenharmony_ci}
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ciint snd_sbmixer_new(struct snd_sb *chip)
72662306a36Sopenharmony_ci{
72762306a36Sopenharmony_ci	struct snd_card *card;
72862306a36Sopenharmony_ci	int err;
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	if (snd_BUG_ON(!chip || !chip->card))
73162306a36Sopenharmony_ci		return -EINVAL;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	card = chip->card;
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	switch (chip->hardware) {
73662306a36Sopenharmony_ci	case SB_HW_10:
73762306a36Sopenharmony_ci		return 0; /* no mixer chip on SB1.x */
73862306a36Sopenharmony_ci	case SB_HW_20:
73962306a36Sopenharmony_ci	case SB_HW_201:
74062306a36Sopenharmony_ci		err = snd_sbmixer_init(chip,
74162306a36Sopenharmony_ci				       snd_sb20_controls,
74262306a36Sopenharmony_ci				       ARRAY_SIZE(snd_sb20_controls),
74362306a36Sopenharmony_ci				       snd_sb20_init_values,
74462306a36Sopenharmony_ci				       ARRAY_SIZE(snd_sb20_init_values),
74562306a36Sopenharmony_ci				       "CTL1335");
74662306a36Sopenharmony_ci		if (err < 0)
74762306a36Sopenharmony_ci			return err;
74862306a36Sopenharmony_ci		break;
74962306a36Sopenharmony_ci	case SB_HW_PRO:
75062306a36Sopenharmony_ci	case SB_HW_JAZZ16:
75162306a36Sopenharmony_ci		err = snd_sbmixer_init(chip,
75262306a36Sopenharmony_ci				       snd_sbpro_controls,
75362306a36Sopenharmony_ci				       ARRAY_SIZE(snd_sbpro_controls),
75462306a36Sopenharmony_ci				       snd_sbpro_init_values,
75562306a36Sopenharmony_ci				       ARRAY_SIZE(snd_sbpro_init_values),
75662306a36Sopenharmony_ci				       "CTL1345");
75762306a36Sopenharmony_ci		if (err < 0)
75862306a36Sopenharmony_ci			return err;
75962306a36Sopenharmony_ci		break;
76062306a36Sopenharmony_ci	case SB_HW_16:
76162306a36Sopenharmony_ci	case SB_HW_ALS100:
76262306a36Sopenharmony_ci	case SB_HW_CS5530:
76362306a36Sopenharmony_ci		err = snd_sbmixer_init(chip,
76462306a36Sopenharmony_ci				       snd_sb16_controls,
76562306a36Sopenharmony_ci				       ARRAY_SIZE(snd_sb16_controls),
76662306a36Sopenharmony_ci				       snd_sb16_init_values,
76762306a36Sopenharmony_ci				       ARRAY_SIZE(snd_sb16_init_values),
76862306a36Sopenharmony_ci				       "CTL1745");
76962306a36Sopenharmony_ci		if (err < 0)
77062306a36Sopenharmony_ci			return err;
77162306a36Sopenharmony_ci		break;
77262306a36Sopenharmony_ci	case SB_HW_ALS4000:
77362306a36Sopenharmony_ci		/* use only the first 16 controls from SB16 */
77462306a36Sopenharmony_ci		err = snd_sbmixer_init(chip,
77562306a36Sopenharmony_ci					snd_sb16_controls,
77662306a36Sopenharmony_ci					16,
77762306a36Sopenharmony_ci					snd_sb16_init_values,
77862306a36Sopenharmony_ci					ARRAY_SIZE(snd_sb16_init_values),
77962306a36Sopenharmony_ci					"ALS4000");
78062306a36Sopenharmony_ci		if (err < 0)
78162306a36Sopenharmony_ci			return err;
78262306a36Sopenharmony_ci		err = snd_sbmixer_init(chip,
78362306a36Sopenharmony_ci				       snd_als4000_controls,
78462306a36Sopenharmony_ci				       ARRAY_SIZE(snd_als4000_controls),
78562306a36Sopenharmony_ci				       snd_als4000_init_values,
78662306a36Sopenharmony_ci				       ARRAY_SIZE(snd_als4000_init_values),
78762306a36Sopenharmony_ci				       "ALS4000");
78862306a36Sopenharmony_ci		if (err < 0)
78962306a36Sopenharmony_ci			return err;
79062306a36Sopenharmony_ci		break;
79162306a36Sopenharmony_ci	case SB_HW_DT019X:
79262306a36Sopenharmony_ci		err = snd_sbmixer_init(chip,
79362306a36Sopenharmony_ci				       snd_dt019x_controls,
79462306a36Sopenharmony_ci				       ARRAY_SIZE(snd_dt019x_controls),
79562306a36Sopenharmony_ci				       snd_dt019x_init_values,
79662306a36Sopenharmony_ci				       ARRAY_SIZE(snd_dt019x_init_values),
79762306a36Sopenharmony_ci				       "DT019X");
79862306a36Sopenharmony_ci		if (err < 0)
79962306a36Sopenharmony_ci			return err;
80062306a36Sopenharmony_ci		break;
80162306a36Sopenharmony_ci	default:
80262306a36Sopenharmony_ci		strcpy(card->mixername, "???");
80362306a36Sopenharmony_ci	}
80462306a36Sopenharmony_ci	return 0;
80562306a36Sopenharmony_ci}
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci#ifdef CONFIG_PM
80862306a36Sopenharmony_cistatic const unsigned char sb20_saved_regs[] = {
80962306a36Sopenharmony_ci	SB_DSP20_MASTER_DEV,
81062306a36Sopenharmony_ci	SB_DSP20_PCM_DEV,
81162306a36Sopenharmony_ci	SB_DSP20_FM_DEV,
81262306a36Sopenharmony_ci	SB_DSP20_CD_DEV,
81362306a36Sopenharmony_ci};
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_cistatic const unsigned char sbpro_saved_regs[] = {
81662306a36Sopenharmony_ci	SB_DSP_MASTER_DEV,
81762306a36Sopenharmony_ci	SB_DSP_PCM_DEV,
81862306a36Sopenharmony_ci	SB_DSP_PLAYBACK_FILT,
81962306a36Sopenharmony_ci	SB_DSP_FM_DEV,
82062306a36Sopenharmony_ci	SB_DSP_CD_DEV,
82162306a36Sopenharmony_ci	SB_DSP_LINE_DEV,
82262306a36Sopenharmony_ci	SB_DSP_MIC_DEV,
82362306a36Sopenharmony_ci	SB_DSP_CAPTURE_SOURCE,
82462306a36Sopenharmony_ci	SB_DSP_CAPTURE_FILT,
82562306a36Sopenharmony_ci};
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_cistatic const unsigned char sb16_saved_regs[] = {
82862306a36Sopenharmony_ci	SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1,
82962306a36Sopenharmony_ci	SB_DSP4_3DSE,
83062306a36Sopenharmony_ci	SB_DSP4_BASS_DEV, SB_DSP4_BASS_DEV + 1,
83162306a36Sopenharmony_ci	SB_DSP4_TREBLE_DEV, SB_DSP4_TREBLE_DEV + 1,
83262306a36Sopenharmony_ci	SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1,
83362306a36Sopenharmony_ci	SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT,
83462306a36Sopenharmony_ci	SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1,
83562306a36Sopenharmony_ci	SB_DSP4_OUTPUT_SW,
83662306a36Sopenharmony_ci	SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1,
83762306a36Sopenharmony_ci	SB_DSP4_LINE_DEV, SB_DSP4_LINE_DEV + 1,
83862306a36Sopenharmony_ci	SB_DSP4_MIC_DEV,
83962306a36Sopenharmony_ci	SB_DSP4_SPEAKER_DEV,
84062306a36Sopenharmony_ci	SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1,
84162306a36Sopenharmony_ci	SB_DSP4_OGAIN_DEV, SB_DSP4_OGAIN_DEV + 1,
84262306a36Sopenharmony_ci	SB_DSP4_MIC_AGC
84362306a36Sopenharmony_ci};
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_cistatic const unsigned char dt019x_saved_regs[] = {
84662306a36Sopenharmony_ci	SB_DT019X_MASTER_DEV,
84762306a36Sopenharmony_ci	SB_DT019X_PCM_DEV,
84862306a36Sopenharmony_ci	SB_DT019X_SYNTH_DEV,
84962306a36Sopenharmony_ci	SB_DT019X_CD_DEV,
85062306a36Sopenharmony_ci	SB_DT019X_MIC_DEV,
85162306a36Sopenharmony_ci	SB_DT019X_SPKR_DEV,
85262306a36Sopenharmony_ci	SB_DT019X_LINE_DEV,
85362306a36Sopenharmony_ci	SB_DSP4_OUTPUT_SW,
85462306a36Sopenharmony_ci	SB_DT019X_OUTPUT_SW2,
85562306a36Sopenharmony_ci	SB_DT019X_CAPTURE_SW,
85662306a36Sopenharmony_ci};
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_cistatic const unsigned char als4000_saved_regs[] = {
85962306a36Sopenharmony_ci	/* please verify in dsheet whether regs to be added
86062306a36Sopenharmony_ci	   are actually real H/W or just dummy */
86162306a36Sopenharmony_ci	SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1,
86262306a36Sopenharmony_ci	SB_DSP4_OUTPUT_SW,
86362306a36Sopenharmony_ci	SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1,
86462306a36Sopenharmony_ci	SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT,
86562306a36Sopenharmony_ci	SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1,
86662306a36Sopenharmony_ci	SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1,
86762306a36Sopenharmony_ci	SB_DSP4_MIC_DEV,
86862306a36Sopenharmony_ci	SB_DSP4_SPEAKER_DEV,
86962306a36Sopenharmony_ci	SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1,
87062306a36Sopenharmony_ci	SB_DSP4_OGAIN_DEV, SB_DSP4_OGAIN_DEV + 1,
87162306a36Sopenharmony_ci	SB_DT019X_OUTPUT_SW2,
87262306a36Sopenharmony_ci	SB_ALS4000_MONO_IO_CTRL,
87362306a36Sopenharmony_ci	SB_ALS4000_MIC_IN_GAIN,
87462306a36Sopenharmony_ci	SB_ALS4000_FMDAC,
87562306a36Sopenharmony_ci	SB_ALS4000_3D_SND_FX,
87662306a36Sopenharmony_ci	SB_ALS4000_3D_TIME_DELAY,
87762306a36Sopenharmony_ci	SB_ALS4000_CR3_CONFIGURATION,
87862306a36Sopenharmony_ci};
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_cistatic void save_mixer(struct snd_sb *chip, const unsigned char *regs, int num_regs)
88162306a36Sopenharmony_ci{
88262306a36Sopenharmony_ci	unsigned char *val = chip->saved_regs;
88362306a36Sopenharmony_ci	if (snd_BUG_ON(num_regs > ARRAY_SIZE(chip->saved_regs)))
88462306a36Sopenharmony_ci		return;
88562306a36Sopenharmony_ci	for (; num_regs; num_regs--)
88662306a36Sopenharmony_ci		*val++ = snd_sbmixer_read(chip, *regs++);
88762306a36Sopenharmony_ci}
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_cistatic void restore_mixer(struct snd_sb *chip, const unsigned char *regs, int num_regs)
89062306a36Sopenharmony_ci{
89162306a36Sopenharmony_ci	unsigned char *val = chip->saved_regs;
89262306a36Sopenharmony_ci	if (snd_BUG_ON(num_regs > ARRAY_SIZE(chip->saved_regs)))
89362306a36Sopenharmony_ci		return;
89462306a36Sopenharmony_ci	for (; num_regs; num_regs--)
89562306a36Sopenharmony_ci		snd_sbmixer_write(chip, *regs++, *val++);
89662306a36Sopenharmony_ci}
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_civoid snd_sbmixer_suspend(struct snd_sb *chip)
89962306a36Sopenharmony_ci{
90062306a36Sopenharmony_ci	switch (chip->hardware) {
90162306a36Sopenharmony_ci	case SB_HW_20:
90262306a36Sopenharmony_ci	case SB_HW_201:
90362306a36Sopenharmony_ci		save_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs));
90462306a36Sopenharmony_ci		break;
90562306a36Sopenharmony_ci	case SB_HW_PRO:
90662306a36Sopenharmony_ci	case SB_HW_JAZZ16:
90762306a36Sopenharmony_ci		save_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs));
90862306a36Sopenharmony_ci		break;
90962306a36Sopenharmony_ci	case SB_HW_16:
91062306a36Sopenharmony_ci	case SB_HW_ALS100:
91162306a36Sopenharmony_ci	case SB_HW_CS5530:
91262306a36Sopenharmony_ci		save_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs));
91362306a36Sopenharmony_ci		break;
91462306a36Sopenharmony_ci	case SB_HW_ALS4000:
91562306a36Sopenharmony_ci		save_mixer(chip, als4000_saved_regs, ARRAY_SIZE(als4000_saved_regs));
91662306a36Sopenharmony_ci		break;
91762306a36Sopenharmony_ci	case SB_HW_DT019X:
91862306a36Sopenharmony_ci		save_mixer(chip, dt019x_saved_regs, ARRAY_SIZE(dt019x_saved_regs));
91962306a36Sopenharmony_ci		break;
92062306a36Sopenharmony_ci	default:
92162306a36Sopenharmony_ci		break;
92262306a36Sopenharmony_ci	}
92362306a36Sopenharmony_ci}
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_civoid snd_sbmixer_resume(struct snd_sb *chip)
92662306a36Sopenharmony_ci{
92762306a36Sopenharmony_ci	switch (chip->hardware) {
92862306a36Sopenharmony_ci	case SB_HW_20:
92962306a36Sopenharmony_ci	case SB_HW_201:
93062306a36Sopenharmony_ci		restore_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs));
93162306a36Sopenharmony_ci		break;
93262306a36Sopenharmony_ci	case SB_HW_PRO:
93362306a36Sopenharmony_ci	case SB_HW_JAZZ16:
93462306a36Sopenharmony_ci		restore_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs));
93562306a36Sopenharmony_ci		break;
93662306a36Sopenharmony_ci	case SB_HW_16:
93762306a36Sopenharmony_ci	case SB_HW_ALS100:
93862306a36Sopenharmony_ci	case SB_HW_CS5530:
93962306a36Sopenharmony_ci		restore_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs));
94062306a36Sopenharmony_ci		break;
94162306a36Sopenharmony_ci	case SB_HW_ALS4000:
94262306a36Sopenharmony_ci		restore_mixer(chip, als4000_saved_regs, ARRAY_SIZE(als4000_saved_regs));
94362306a36Sopenharmony_ci		break;
94462306a36Sopenharmony_ci	case SB_HW_DT019X:
94562306a36Sopenharmony_ci		restore_mixer(chip, dt019x_saved_regs, ARRAY_SIZE(dt019x_saved_regs));
94662306a36Sopenharmony_ci		break;
94762306a36Sopenharmony_ci	default:
94862306a36Sopenharmony_ci		break;
94962306a36Sopenharmony_ci	}
95062306a36Sopenharmony_ci}
95162306a36Sopenharmony_ci#endif
952