1/*
2 *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
3 *  Routines for Sound Blaster mixer control
4 *
5 *
6 *   This program is free software; you can redistribute it and/or modify
7 *   it under the terms of the GNU General Public License as published by
8 *   the Free Software Foundation; either version 2 of the License, or
9 *   (at your option) any later version.
10 *
11 *   This program is distributed in the hope that it will be useful,
12 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 *   GNU General Public License for more details.
15 *
16 *   You should have received a copy of the GNU General Public License
17 *   along with this program; if not, write to the Free Software
18 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 *
20 */
21
22#include <sound/driver.h>
23#include <asm/io.h>
24#include <linux/delay.h>
25#include <linux/time.h>
26#include <sound/core.h>
27#include <sound/sb.h>
28#include <sound/control.h>
29
30#undef IO_DEBUG
31
32void snd_sbmixer_write(struct snd_sb *chip, unsigned char reg, unsigned char data)
33{
34	outb(reg, SBP(chip, MIXER_ADDR));
35	udelay(10);
36	outb(data, SBP(chip, MIXER_DATA));
37	udelay(10);
38#ifdef IO_DEBUG
39	snd_printk(KERN_DEBUG "mixer_write 0x%x 0x%x\n", reg, data);
40#endif
41}
42
43unsigned char snd_sbmixer_read(struct snd_sb *chip, unsigned char reg)
44{
45	unsigned char result;
46
47	outb(reg, SBP(chip, MIXER_ADDR));
48	udelay(10);
49	result = inb(SBP(chip, MIXER_DATA));
50	udelay(10);
51#ifdef IO_DEBUG
52	snd_printk(KERN_DEBUG "mixer_read 0x%x 0x%x\n", reg, result);
53#endif
54	return result;
55}
56
57/*
58 * Single channel mixer element
59 */
60
61static int snd_sbmixer_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
62{
63	int mask = (kcontrol->private_value >> 24) & 0xff;
64
65	uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
66	uinfo->count = 1;
67	uinfo->value.integer.min = 0;
68	uinfo->value.integer.max = mask;
69	return 0;
70}
71
72static int snd_sbmixer_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
73{
74	struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
75	unsigned long flags;
76	int reg = kcontrol->private_value & 0xff;
77	int shift = (kcontrol->private_value >> 16) & 0xff;
78	int mask = (kcontrol->private_value >> 24) & 0xff;
79	unsigned char val;
80
81	spin_lock_irqsave(&sb->mixer_lock, flags);
82	val = (snd_sbmixer_read(sb, reg) >> shift) & mask;
83	spin_unlock_irqrestore(&sb->mixer_lock, flags);
84	ucontrol->value.integer.value[0] = val;
85	return 0;
86}
87
88static int snd_sbmixer_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
89{
90	struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
91	unsigned long flags;
92	int reg = kcontrol->private_value & 0xff;
93	int shift = (kcontrol->private_value >> 16) & 0x07;
94	int mask = (kcontrol->private_value >> 24) & 0xff;
95	int change;
96	unsigned char val, oval;
97
98	val = (ucontrol->value.integer.value[0] & mask) << shift;
99	spin_lock_irqsave(&sb->mixer_lock, flags);
100	oval = snd_sbmixer_read(sb, reg);
101	val = (oval & ~(mask << shift)) | val;
102	change = val != oval;
103	if (change)
104		snd_sbmixer_write(sb, reg, val);
105	spin_unlock_irqrestore(&sb->mixer_lock, flags);
106	return change;
107}
108
109/*
110 * Double channel mixer element
111 */
112
113static int snd_sbmixer_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
114{
115	int mask = (kcontrol->private_value >> 24) & 0xff;
116
117	uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
118	uinfo->count = 2;
119	uinfo->value.integer.min = 0;
120	uinfo->value.integer.max = mask;
121	return 0;
122}
123
124static int snd_sbmixer_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
125{
126	struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
127	unsigned long flags;
128	int left_reg = kcontrol->private_value & 0xff;
129	int right_reg = (kcontrol->private_value >> 8) & 0xff;
130	int left_shift = (kcontrol->private_value >> 16) & 0x07;
131	int right_shift = (kcontrol->private_value >> 19) & 0x07;
132	int mask = (kcontrol->private_value >> 24) & 0xff;
133	unsigned char left, right;
134
135	spin_lock_irqsave(&sb->mixer_lock, flags);
136	left = (snd_sbmixer_read(sb, left_reg) >> left_shift) & mask;
137	right = (snd_sbmixer_read(sb, right_reg) >> right_shift) & mask;
138	spin_unlock_irqrestore(&sb->mixer_lock, flags);
139	ucontrol->value.integer.value[0] = left;
140	ucontrol->value.integer.value[1] = right;
141	return 0;
142}
143
144static int snd_sbmixer_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
145{
146	struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
147	unsigned long flags;
148	int left_reg = kcontrol->private_value & 0xff;
149	int right_reg = (kcontrol->private_value >> 8) & 0xff;
150	int left_shift = (kcontrol->private_value >> 16) & 0x07;
151	int right_shift = (kcontrol->private_value >> 19) & 0x07;
152	int mask = (kcontrol->private_value >> 24) & 0xff;
153	int change;
154	unsigned char left, right, oleft, oright;
155
156	left = (ucontrol->value.integer.value[0] & mask) << left_shift;
157	right = (ucontrol->value.integer.value[1] & mask) << right_shift;
158	spin_lock_irqsave(&sb->mixer_lock, flags);
159	if (left_reg == right_reg) {
160		oleft = snd_sbmixer_read(sb, left_reg);
161		left = (oleft & ~((mask << left_shift) | (mask << right_shift))) | left | right;
162		change = left != oleft;
163		if (change)
164			snd_sbmixer_write(sb, left_reg, left);
165	} else {
166		oleft = snd_sbmixer_read(sb, left_reg);
167		oright = snd_sbmixer_read(sb, right_reg);
168		left = (oleft & ~(mask << left_shift)) | left;
169		right = (oright & ~(mask << right_shift)) | right;
170		change = left != oleft || right != oright;
171		if (change) {
172			snd_sbmixer_write(sb, left_reg, left);
173			snd_sbmixer_write(sb, right_reg, right);
174		}
175	}
176	spin_unlock_irqrestore(&sb->mixer_lock, flags);
177	return change;
178}
179
180/*
181 * DT-019x / ALS-007 capture/input switch
182 */
183
184static int snd_dt019x_input_sw_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
185{
186	static char *texts[5] = {
187		"CD", "Mic", "Line", "Synth", "Master"
188	};
189
190	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
191	uinfo->count = 1;
192	uinfo->value.enumerated.items = 5;
193	if (uinfo->value.enumerated.item > 4)
194		uinfo->value.enumerated.item = 4;
195	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
196	return 0;
197}
198
199static int snd_dt019x_input_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
200{
201	struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
202	unsigned long flags;
203	unsigned char oval;
204
205	spin_lock_irqsave(&sb->mixer_lock, flags);
206	oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW);
207	spin_unlock_irqrestore(&sb->mixer_lock, flags);
208	switch (oval & 0x07) {
209	case SB_DT019X_CAP_CD:
210		ucontrol->value.enumerated.item[0] = 0;
211		break;
212	case SB_DT019X_CAP_MIC:
213		ucontrol->value.enumerated.item[0] = 1;
214		break;
215	case SB_DT019X_CAP_LINE:
216		ucontrol->value.enumerated.item[0] = 2;
217		break;
218	case SB_DT019X_CAP_MAIN:
219		ucontrol->value.enumerated.item[0] = 4;
220		break;
221	/* To record the synth on these cards you must record the main.   */
222	/* Thus SB_DT019X_CAP_SYNTH == SB_DT019X_CAP_MAIN and would cause */
223	/* duplicate case labels if left uncommented. */
224	/* case SB_DT019X_CAP_SYNTH:
225	 *	ucontrol->value.enumerated.item[0] = 3;
226	 *	break;
227	 */
228	default:
229		ucontrol->value.enumerated.item[0] = 4;
230		break;
231	}
232	return 0;
233}
234
235static int snd_dt019x_input_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
236{
237	struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
238	unsigned long flags;
239	int change;
240	unsigned char nval, oval;
241
242	if (ucontrol->value.enumerated.item[0] > 4)
243		return -EINVAL;
244	switch (ucontrol->value.enumerated.item[0]) {
245	case 0:
246		nval = SB_DT019X_CAP_CD;
247		break;
248	case 1:
249		nval = SB_DT019X_CAP_MIC;
250		break;
251	case 2:
252		nval = SB_DT019X_CAP_LINE;
253		break;
254	case 3:
255		nval = SB_DT019X_CAP_SYNTH;
256		break;
257	case 4:
258		nval = SB_DT019X_CAP_MAIN;
259		break;
260	default:
261		nval = SB_DT019X_CAP_MAIN;
262	}
263	spin_lock_irqsave(&sb->mixer_lock, flags);
264	oval = snd_sbmixer_read(sb, SB_DT019X_CAPTURE_SW);
265	change = nval != oval;
266	if (change)
267		snd_sbmixer_write(sb, SB_DT019X_CAPTURE_SW, nval);
268	spin_unlock_irqrestore(&sb->mixer_lock, flags);
269	return change;
270}
271
272/*
273 * SBPRO input multiplexer
274 */
275
276static int snd_sb8mixer_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
277{
278	static char *texts[3] = {
279		"Mic", "CD", "Line"
280	};
281
282	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
283	uinfo->count = 1;
284	uinfo->value.enumerated.items = 3;
285	if (uinfo->value.enumerated.item > 2)
286		uinfo->value.enumerated.item = 2;
287	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
288	return 0;
289}
290
291
292static int snd_sb8mixer_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
293{
294	struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
295	unsigned long flags;
296	unsigned char oval;
297
298	spin_lock_irqsave(&sb->mixer_lock, flags);
299	oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE);
300	spin_unlock_irqrestore(&sb->mixer_lock, flags);
301	switch ((oval >> 0x01) & 0x03) {
302	case SB_DSP_MIXS_CD:
303		ucontrol->value.enumerated.item[0] = 1;
304		break;
305	case SB_DSP_MIXS_LINE:
306		ucontrol->value.enumerated.item[0] = 2;
307		break;
308	default:
309		ucontrol->value.enumerated.item[0] = 0;
310		break;
311	}
312	return 0;
313}
314
315static int snd_sb8mixer_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
316{
317	struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
318	unsigned long flags;
319	int change;
320	unsigned char nval, oval;
321
322	if (ucontrol->value.enumerated.item[0] > 2)
323		return -EINVAL;
324	switch (ucontrol->value.enumerated.item[0]) {
325	case 1:
326		nval = SB_DSP_MIXS_CD;
327		break;
328	case 2:
329		nval = SB_DSP_MIXS_LINE;
330		break;
331	default:
332		nval = SB_DSP_MIXS_MIC;
333	}
334	nval <<= 1;
335	spin_lock_irqsave(&sb->mixer_lock, flags);
336	oval = snd_sbmixer_read(sb, SB_DSP_CAPTURE_SOURCE);
337	nval |= oval & ~0x06;
338	change = nval != oval;
339	if (change)
340		snd_sbmixer_write(sb, SB_DSP_CAPTURE_SOURCE, nval);
341	spin_unlock_irqrestore(&sb->mixer_lock, flags);
342	return change;
343}
344
345/*
346 * SB16 input switch
347 */
348
349static int snd_sb16mixer_info_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
350{
351	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
352	uinfo->count = 4;
353	uinfo->value.integer.min = 0;
354	uinfo->value.integer.max = 1;
355	return 0;
356}
357
358static int snd_sb16mixer_get_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
359{
360	struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
361	unsigned long flags;
362	int reg1 = kcontrol->private_value & 0xff;
363	int reg2 = (kcontrol->private_value >> 8) & 0xff;
364	int left_shift = (kcontrol->private_value >> 16) & 0x0f;
365	int right_shift = (kcontrol->private_value >> 24) & 0x0f;
366	unsigned char val1, val2;
367
368	spin_lock_irqsave(&sb->mixer_lock, flags);
369	val1 = snd_sbmixer_read(sb, reg1);
370	val2 = snd_sbmixer_read(sb, reg2);
371	spin_unlock_irqrestore(&sb->mixer_lock, flags);
372	ucontrol->value.integer.value[0] = (val1 >> left_shift) & 0x01;
373	ucontrol->value.integer.value[1] = (val2 >> left_shift) & 0x01;
374	ucontrol->value.integer.value[2] = (val1 >> right_shift) & 0x01;
375	ucontrol->value.integer.value[3] = (val2 >> right_shift) & 0x01;
376	return 0;
377}
378
379static int snd_sb16mixer_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
380{
381	struct snd_sb *sb = snd_kcontrol_chip(kcontrol);
382	unsigned long flags;
383	int reg1 = kcontrol->private_value & 0xff;
384	int reg2 = (kcontrol->private_value >> 8) & 0xff;
385	int left_shift = (kcontrol->private_value >> 16) & 0x0f;
386	int right_shift = (kcontrol->private_value >> 24) & 0x0f;
387	int change;
388	unsigned char val1, val2, oval1, oval2;
389
390	spin_lock_irqsave(&sb->mixer_lock, flags);
391	oval1 = snd_sbmixer_read(sb, reg1);
392	oval2 = snd_sbmixer_read(sb, reg2);
393	val1 = oval1 & ~((1 << left_shift) | (1 << right_shift));
394	val2 = oval2 & ~((1 << left_shift) | (1 << right_shift));
395	val1 |= (ucontrol->value.integer.value[0] & 1) << left_shift;
396	val2 |= (ucontrol->value.integer.value[1] & 1) << left_shift;
397	val1 |= (ucontrol->value.integer.value[2] & 1) << right_shift;
398	val2 |= (ucontrol->value.integer.value[3] & 1) << right_shift;
399	change = val1 != oval1 || val2 != oval2;
400	if (change) {
401		snd_sbmixer_write(sb, reg1, val1);
402		snd_sbmixer_write(sb, reg2, val2);
403	}
404	spin_unlock_irqrestore(&sb->mixer_lock, flags);
405	return change;
406}
407
408
409/*
410 */
411/*
412 */
413int snd_sbmixer_add_ctl(struct snd_sb *chip, const char *name, int index, int type, unsigned long value)
414{
415	static struct snd_kcontrol_new newctls[] = {
416		[SB_MIX_SINGLE] = {
417			.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
418			.info = snd_sbmixer_info_single,
419			.get = snd_sbmixer_get_single,
420			.put = snd_sbmixer_put_single,
421		},
422		[SB_MIX_DOUBLE] = {
423			.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
424			.info = snd_sbmixer_info_double,
425			.get = snd_sbmixer_get_double,
426			.put = snd_sbmixer_put_double,
427		},
428		[SB_MIX_INPUT_SW] = {
429			.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
430			.info = snd_sb16mixer_info_input_sw,
431			.get = snd_sb16mixer_get_input_sw,
432			.put = snd_sb16mixer_put_input_sw,
433		},
434		[SB_MIX_CAPTURE_PRO] = {
435			.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
436			.info = snd_sb8mixer_info_mux,
437			.get = snd_sb8mixer_get_mux,
438			.put = snd_sb8mixer_put_mux,
439		},
440		[SB_MIX_CAPTURE_DT019X] = {
441			.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
442			.info = snd_dt019x_input_sw_info,
443			.get = snd_dt019x_input_sw_get,
444			.put = snd_dt019x_input_sw_put,
445		},
446	};
447	struct snd_kcontrol *ctl;
448	int err;
449
450	ctl = snd_ctl_new1(&newctls[type], chip);
451	if (! ctl)
452		return -ENOMEM;
453	strlcpy(ctl->id.name, name, sizeof(ctl->id.name));
454	ctl->id.index = index;
455	ctl->private_value = value;
456	if ((err = snd_ctl_add(chip->card, ctl)) < 0)
457		return err;
458	return 0;
459}
460
461/*
462 * SB 2.0 specific mixer elements
463 */
464
465static struct sbmix_elem snd_sb20_ctl_master_play_vol =
466	SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7);
467static struct sbmix_elem snd_sb20_ctl_pcm_play_vol =
468	SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3);
469static struct sbmix_elem snd_sb20_ctl_synth_play_vol =
470	SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7);
471static struct sbmix_elem snd_sb20_ctl_cd_play_vol =
472	SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7);
473
474static struct sbmix_elem *snd_sb20_controls[] = {
475	&snd_sb20_ctl_master_play_vol,
476	&snd_sb20_ctl_pcm_play_vol,
477	&snd_sb20_ctl_synth_play_vol,
478	&snd_sb20_ctl_cd_play_vol
479};
480
481static unsigned char snd_sb20_init_values[][2] = {
482	{ SB_DSP20_MASTER_DEV, 0 },
483	{ SB_DSP20_FM_DEV, 0 },
484};
485
486/*
487 * SB Pro specific mixer elements
488 */
489static struct sbmix_elem snd_sbpro_ctl_master_play_vol =
490	SB_DOUBLE("Master Playback Volume", SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7);
491static struct sbmix_elem snd_sbpro_ctl_pcm_play_vol =
492	SB_DOUBLE("PCM Playback Volume", SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7);
493static struct sbmix_elem snd_sbpro_ctl_pcm_play_filter =
494	SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1);
495static struct sbmix_elem snd_sbpro_ctl_synth_play_vol =
496	SB_DOUBLE("Synth Playback Volume", SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7);
497static struct sbmix_elem snd_sbpro_ctl_cd_play_vol =
498	SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7);
499static struct sbmix_elem snd_sbpro_ctl_line_play_vol =
500	SB_DOUBLE("Line Playback Volume", SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7);
501static struct sbmix_elem snd_sbpro_ctl_mic_play_vol =
502	SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3);
503static struct sbmix_elem snd_sbpro_ctl_capture_source =
504	{
505		.name = "Capture Source",
506		.type = SB_MIX_CAPTURE_PRO
507	};
508static struct sbmix_elem snd_sbpro_ctl_capture_filter =
509	SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1);
510static struct sbmix_elem snd_sbpro_ctl_capture_low_filter =
511	SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1);
512
513static struct sbmix_elem *snd_sbpro_controls[] = {
514	&snd_sbpro_ctl_master_play_vol,
515	&snd_sbpro_ctl_pcm_play_vol,
516	&snd_sbpro_ctl_pcm_play_filter,
517	&snd_sbpro_ctl_synth_play_vol,
518	&snd_sbpro_ctl_cd_play_vol,
519	&snd_sbpro_ctl_line_play_vol,
520	&snd_sbpro_ctl_mic_play_vol,
521	&snd_sbpro_ctl_capture_source,
522	&snd_sbpro_ctl_capture_filter,
523	&snd_sbpro_ctl_capture_low_filter
524};
525
526static unsigned char snd_sbpro_init_values[][2] = {
527	{ SB_DSP_MASTER_DEV, 0 },
528	{ SB_DSP_PCM_DEV, 0 },
529	{ SB_DSP_FM_DEV, 0 },
530};
531
532/*
533 * SB16 specific mixer elements
534 */
535static struct sbmix_elem snd_sb16_ctl_master_play_vol =
536	SB_DOUBLE("Master Playback Volume", SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31);
537static struct sbmix_elem snd_sb16_ctl_3d_enhance_switch =
538	SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1);
539static struct sbmix_elem snd_sb16_ctl_tone_bass =
540	SB_DOUBLE("Tone Control - Bass", SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15);
541static struct sbmix_elem snd_sb16_ctl_tone_treble =
542	SB_DOUBLE("Tone Control - Treble", SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15);
543static struct sbmix_elem snd_sb16_ctl_pcm_play_vol =
544	SB_DOUBLE("PCM Playback Volume", SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31);
545static struct sbmix_elem snd_sb16_ctl_synth_capture_route =
546	SB16_INPUT_SW("Synth Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5);
547static struct sbmix_elem snd_sb16_ctl_synth_play_vol =
548	SB_DOUBLE("Synth Playback Volume", SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31);
549static struct sbmix_elem snd_sb16_ctl_cd_capture_route =
550	SB16_INPUT_SW("CD Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1);
551static struct sbmix_elem snd_sb16_ctl_cd_play_switch =
552	SB_DOUBLE("CD Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1);
553static struct sbmix_elem snd_sb16_ctl_cd_play_vol =
554	SB_DOUBLE("CD Playback Volume", SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31);
555static struct sbmix_elem snd_sb16_ctl_line_capture_route =
556	SB16_INPUT_SW("Line Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3);
557static struct sbmix_elem snd_sb16_ctl_line_play_switch =
558	SB_DOUBLE("Line Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1);
559static struct sbmix_elem snd_sb16_ctl_line_play_vol =
560	SB_DOUBLE("Line Playback Volume", SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31);
561static struct sbmix_elem snd_sb16_ctl_mic_capture_route =
562	SB16_INPUT_SW("Mic Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0);
563static struct sbmix_elem snd_sb16_ctl_mic_play_switch =
564	SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1);
565static struct sbmix_elem snd_sb16_ctl_mic_play_vol =
566	SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31);
567static struct sbmix_elem snd_sb16_ctl_pc_speaker_vol =
568	SB_SINGLE("PC Speaker Volume", SB_DSP4_SPEAKER_DEV, 6, 3);
569static struct sbmix_elem snd_sb16_ctl_capture_vol =
570	SB_DOUBLE("Capture Volume", SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3);
571static struct sbmix_elem snd_sb16_ctl_play_vol =
572	SB_DOUBLE("Playback Volume", SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3);
573static struct sbmix_elem snd_sb16_ctl_auto_mic_gain =
574	SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1);
575
576static struct sbmix_elem *snd_sb16_controls[] = {
577	&snd_sb16_ctl_master_play_vol,
578	&snd_sb16_ctl_3d_enhance_switch,
579	&snd_sb16_ctl_tone_bass,
580	&snd_sb16_ctl_tone_treble,
581	&snd_sb16_ctl_pcm_play_vol,
582	&snd_sb16_ctl_synth_capture_route,
583	&snd_sb16_ctl_synth_play_vol,
584	&snd_sb16_ctl_cd_capture_route,
585	&snd_sb16_ctl_cd_play_switch,
586	&snd_sb16_ctl_cd_play_vol,
587	&snd_sb16_ctl_line_capture_route,
588	&snd_sb16_ctl_line_play_switch,
589	&snd_sb16_ctl_line_play_vol,
590	&snd_sb16_ctl_mic_capture_route,
591	&snd_sb16_ctl_mic_play_switch,
592	&snd_sb16_ctl_mic_play_vol,
593	&snd_sb16_ctl_pc_speaker_vol,
594	&snd_sb16_ctl_capture_vol,
595	&snd_sb16_ctl_play_vol,
596	&snd_sb16_ctl_auto_mic_gain
597};
598
599static unsigned char snd_sb16_init_values[][2] = {
600	{ SB_DSP4_MASTER_DEV + 0, 0 },
601	{ SB_DSP4_MASTER_DEV + 1, 0 },
602	{ SB_DSP4_PCM_DEV + 0, 0 },
603	{ SB_DSP4_PCM_DEV + 1, 0 },
604	{ SB_DSP4_SYNTH_DEV + 0, 0 },
605	{ SB_DSP4_SYNTH_DEV + 1, 0 },
606	{ SB_DSP4_INPUT_LEFT, 0 },
607	{ SB_DSP4_INPUT_RIGHT, 0 },
608	{ SB_DSP4_OUTPUT_SW, 0 },
609	{ SB_DSP4_SPEAKER_DEV, 0 },
610};
611
612/*
613 * DT019x specific mixer elements
614 */
615static struct sbmix_elem snd_dt019x_ctl_master_play_vol =
616	SB_DOUBLE("Master Playback Volume", SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4,0, 15);
617static struct sbmix_elem snd_dt019x_ctl_pcm_play_vol =
618	SB_DOUBLE("PCM Playback Volume", SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4,0, 15);
619static struct sbmix_elem snd_dt019x_ctl_synth_play_vol =
620	SB_DOUBLE("Synth Playback Volume", SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4,0, 15);
621static struct sbmix_elem snd_dt019x_ctl_cd_play_vol =
622	SB_DOUBLE("CD Playback Volume", SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4,0, 15);
623static struct sbmix_elem snd_dt019x_ctl_mic_play_vol =
624	SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7);
625static struct sbmix_elem snd_dt019x_ctl_pc_speaker_vol =
626	SB_SINGLE("PC Speaker Volume", SB_DT019X_SPKR_DEV, 0,  7);
627static struct sbmix_elem snd_dt019x_ctl_line_play_vol =
628	SB_DOUBLE("Line Playback Volume", SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4,0, 15);
629static struct sbmix_elem snd_dt019x_ctl_pcm_play_switch =
630	SB_DOUBLE("PCM Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2,1, 1);
631static struct sbmix_elem snd_dt019x_ctl_synth_play_switch =
632	SB_DOUBLE("Synth Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4,3, 1);
633static struct sbmix_elem snd_dt019x_ctl_capture_source =
634	{
635		.name = "Capture Source",
636		.type = SB_MIX_CAPTURE_DT019X
637	};
638
639static struct sbmix_elem *snd_dt019x_controls[] = {
640	&snd_dt019x_ctl_master_play_vol,
641	&snd_dt019x_ctl_pcm_play_vol,
642	&snd_dt019x_ctl_synth_play_vol,
643	&snd_dt019x_ctl_cd_play_vol,
644	&snd_dt019x_ctl_mic_play_vol,
645	&snd_dt019x_ctl_pc_speaker_vol,
646	&snd_dt019x_ctl_line_play_vol,
647	&snd_sb16_ctl_mic_play_switch,
648	&snd_sb16_ctl_cd_play_switch,
649	&snd_sb16_ctl_line_play_switch,
650	&snd_dt019x_ctl_pcm_play_switch,
651	&snd_dt019x_ctl_synth_play_switch,
652	&snd_dt019x_ctl_capture_source
653};
654
655static unsigned char snd_dt019x_init_values[][2] = {
656        { SB_DT019X_MASTER_DEV, 0 },
657        { SB_DT019X_PCM_DEV, 0 },
658        { SB_DT019X_SYNTH_DEV, 0 },
659        { SB_DT019X_CD_DEV, 0 },
660        { SB_DT019X_MIC_DEV, 0 },	/* Includes PC-speaker in high nibble */
661        { SB_DT019X_LINE_DEV, 0 },
662        { SB_DSP4_OUTPUT_SW, 0 },
663        { SB_DT019X_OUTPUT_SW2, 0 },
664        { SB_DT019X_CAPTURE_SW, 0x06 },
665};
666
667/*
668 * ALS4000 specific mixer elements
669 */
670static struct sbmix_elem snd_als4000_ctl_master_mono_playback_switch =
671	SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1);
672static struct sbmix_elem snd_als4000_ctl_master_mono_capture_route =
673	SB_SINGLE("Master Mono Capture Route", SB_ALS4000_MONO_IO_CTRL, 6, 0x03);
674static struct sbmix_elem snd_als4000_ctl_mono_playback_switch =
675	SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2, 0, 1);
676static struct sbmix_elem snd_als4000_ctl_mic_20db_boost =
677	SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03);
678static struct sbmix_elem snd_als4000_ctl_mixer_loopback =
679	SB_SINGLE("Analog Loopback", SB_ALS4000_MIC_IN_GAIN, 7, 0x01);
680static struct sbmix_elem snd_als4000_3d_control_switch =
681	SB_SINGLE("3D Control - Switch", SB_ALS4000_3D_SND_FX, 6, 0x01);
682static struct sbmix_elem snd_als4000_3d_control_ratio =
683	SB_SINGLE("3D Control - Level", SB_ALS4000_3D_SND_FX, 0, 0x07);
684static struct sbmix_elem snd_als4000_3d_control_freq =
685	SB_SINGLE("3D Control - Freq", SB_ALS4000_3D_SND_FX, 4, 0x03);
686static struct sbmix_elem snd_als4000_3d_control_delay =
687	SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f);
688static struct sbmix_elem snd_als4000_3d_control_poweroff_switch =
689	SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01);
690#ifdef NOT_AVAILABLE
691static struct sbmix_elem snd_als4000_ctl_fmdac =
692	SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01);
693static struct sbmix_elem snd_als4000_ctl_qsound =
694	SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f);
695#endif
696
697static struct sbmix_elem *snd_als4000_controls[] = {
698	&snd_sb16_ctl_master_play_vol,
699	&snd_dt019x_ctl_pcm_play_switch,
700	&snd_sb16_ctl_pcm_play_vol,
701	&snd_sb16_ctl_synth_capture_route,
702	&snd_dt019x_ctl_synth_play_switch,
703	&snd_sb16_ctl_synth_play_vol,
704	&snd_sb16_ctl_cd_capture_route,
705	&snd_sb16_ctl_cd_play_switch,
706	&snd_sb16_ctl_cd_play_vol,
707	&snd_sb16_ctl_line_capture_route,
708	&snd_sb16_ctl_line_play_switch,
709	&snd_sb16_ctl_line_play_vol,
710	&snd_sb16_ctl_mic_capture_route,
711	&snd_als4000_ctl_mic_20db_boost,
712	&snd_sb16_ctl_auto_mic_gain,
713	&snd_sb16_ctl_mic_play_switch,
714	&snd_sb16_ctl_mic_play_vol,
715	&snd_sb16_ctl_pc_speaker_vol,
716	&snd_sb16_ctl_capture_vol,
717	&snd_sb16_ctl_play_vol,
718	&snd_als4000_ctl_master_mono_playback_switch,
719	&snd_als4000_ctl_master_mono_capture_route,
720	&snd_als4000_ctl_mono_playback_switch,
721	&snd_als4000_ctl_mixer_loopback,
722	&snd_als4000_3d_control_switch,
723	&snd_als4000_3d_control_ratio,
724	&snd_als4000_3d_control_freq,
725	&snd_als4000_3d_control_delay,
726	&snd_als4000_3d_control_poweroff_switch,
727#ifdef NOT_AVAILABLE
728	&snd_als4000_ctl_fmdac,
729	&snd_als4000_ctl_qsound,
730#endif
731};
732
733static unsigned char snd_als4000_init_values[][2] = {
734	{ SB_DSP4_MASTER_DEV + 0, 0 },
735	{ SB_DSP4_MASTER_DEV + 1, 0 },
736	{ SB_DSP4_PCM_DEV + 0, 0 },
737	{ SB_DSP4_PCM_DEV + 1, 0 },
738	{ SB_DSP4_SYNTH_DEV + 0, 0 },
739	{ SB_DSP4_SYNTH_DEV + 1, 0 },
740	{ SB_DSP4_SPEAKER_DEV, 0 },
741	{ SB_DSP4_OUTPUT_SW, 0 },
742	{ SB_DSP4_INPUT_LEFT, 0 },
743	{ SB_DSP4_INPUT_RIGHT, 0 },
744	{ SB_DT019X_OUTPUT_SW2, 0 },
745	{ SB_ALS4000_MIC_IN_GAIN, 0 },
746};
747
748
749/*
750 */
751static int snd_sbmixer_init(struct snd_sb *chip,
752			    struct sbmix_elem **controls,
753			    int controls_count,
754			    unsigned char map[][2],
755			    int map_count,
756			    char *name)
757{
758	unsigned long flags;
759	struct snd_card *card = chip->card;
760	int idx, err;
761
762	/* mixer reset */
763	spin_lock_irqsave(&chip->mixer_lock, flags);
764	snd_sbmixer_write(chip, 0x00, 0x00);
765	spin_unlock_irqrestore(&chip->mixer_lock, flags);
766
767	/* mute and zero volume channels */
768	for (idx = 0; idx < map_count; idx++) {
769		spin_lock_irqsave(&chip->mixer_lock, flags);
770		snd_sbmixer_write(chip, map[idx][0], map[idx][1]);
771		spin_unlock_irqrestore(&chip->mixer_lock, flags);
772	}
773
774	for (idx = 0; idx < controls_count; idx++) {
775		if ((err = snd_sbmixer_add_ctl_elem(chip, controls[idx])) < 0)
776			return err;
777	}
778	snd_component_add(card, name);
779	strcpy(card->mixername, name);
780	return 0;
781}
782
783int snd_sbmixer_new(struct snd_sb *chip)
784{
785	struct snd_card *card;
786	int err;
787
788	snd_assert(chip != NULL && chip->card != NULL, return -EINVAL);
789
790	card = chip->card;
791
792	switch (chip->hardware) {
793	case SB_HW_10:
794		return 0; /* no mixer chip on SB1.x */
795	case SB_HW_20:
796	case SB_HW_201:
797		if ((err = snd_sbmixer_init(chip,
798					    snd_sb20_controls,
799					    ARRAY_SIZE(snd_sb20_controls),
800					    snd_sb20_init_values,
801					    ARRAY_SIZE(snd_sb20_init_values),
802					    "CTL1335")) < 0)
803			return err;
804		break;
805	case SB_HW_PRO:
806		if ((err = snd_sbmixer_init(chip,
807					    snd_sbpro_controls,
808					    ARRAY_SIZE(snd_sbpro_controls),
809					    snd_sbpro_init_values,
810					    ARRAY_SIZE(snd_sbpro_init_values),
811					    "CTL1345")) < 0)
812			return err;
813		break;
814	case SB_HW_16:
815	case SB_HW_ALS100:
816		if ((err = snd_sbmixer_init(chip,
817					    snd_sb16_controls,
818					    ARRAY_SIZE(snd_sb16_controls),
819					    snd_sb16_init_values,
820					    ARRAY_SIZE(snd_sb16_init_values),
821					    "CTL1745")) < 0)
822			return err;
823		break;
824	case SB_HW_ALS4000:
825		if ((err = snd_sbmixer_init(chip,
826					    snd_als4000_controls,
827					    ARRAY_SIZE(snd_als4000_controls),
828					    snd_als4000_init_values,
829					    ARRAY_SIZE(snd_als4000_init_values),
830					    "ALS4000")) < 0)
831			return err;
832		break;
833	case SB_HW_DT019X:
834		if ((err = snd_sbmixer_init(chip,
835					    snd_dt019x_controls,
836					    ARRAY_SIZE(snd_dt019x_controls),
837					    snd_dt019x_init_values,
838					    ARRAY_SIZE(snd_dt019x_init_values),
839					    "DT019X")) < 0)
840		break;
841	default:
842		strcpy(card->mixername, "???");
843	}
844	return 0;
845}
846
847#ifdef CONFIG_PM
848static unsigned char sb20_saved_regs[] = {
849	SB_DSP20_MASTER_DEV,
850	SB_DSP20_PCM_DEV,
851	SB_DSP20_FM_DEV,
852	SB_DSP20_CD_DEV,
853};
854
855static unsigned char sbpro_saved_regs[] = {
856	SB_DSP_MASTER_DEV,
857	SB_DSP_PCM_DEV,
858	SB_DSP_PLAYBACK_FILT,
859	SB_DSP_FM_DEV,
860	SB_DSP_CD_DEV,
861	SB_DSP_LINE_DEV,
862	SB_DSP_MIC_DEV,
863	SB_DSP_CAPTURE_SOURCE,
864	SB_DSP_CAPTURE_FILT,
865};
866
867static unsigned char sb16_saved_regs[] = {
868	SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1,
869	SB_DSP4_3DSE,
870	SB_DSP4_BASS_DEV, SB_DSP4_BASS_DEV + 1,
871	SB_DSP4_TREBLE_DEV, SB_DSP4_TREBLE_DEV + 1,
872	SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1,
873	SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT,
874	SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1,
875	SB_DSP4_OUTPUT_SW,
876	SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1,
877	SB_DSP4_LINE_DEV, SB_DSP4_LINE_DEV + 1,
878	SB_DSP4_MIC_DEV,
879	SB_DSP4_SPEAKER_DEV,
880	SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1,
881	SB_DSP4_OGAIN_DEV, SB_DSP4_OGAIN_DEV + 1,
882	SB_DSP4_MIC_AGC
883};
884
885static unsigned char dt019x_saved_regs[] = {
886	SB_DT019X_MASTER_DEV,
887	SB_DT019X_PCM_DEV,
888	SB_DT019X_SYNTH_DEV,
889	SB_DT019X_CD_DEV,
890	SB_DT019X_MIC_DEV,
891	SB_DT019X_SPKR_DEV,
892	SB_DT019X_LINE_DEV,
893	SB_DSP4_OUTPUT_SW,
894	SB_DT019X_OUTPUT_SW2,
895	SB_DT019X_CAPTURE_SW,
896};
897
898static unsigned char als4000_saved_regs[] = {
899	SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1,
900	SB_DSP4_OUTPUT_SW,
901	SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1,
902	SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT,
903	SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1,
904	SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1,
905	SB_DSP4_MIC_AGC,
906	SB_DSP4_MIC_DEV,
907	SB_DSP4_SPEAKER_DEV,
908	SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1,
909	SB_DSP4_OGAIN_DEV, SB_DSP4_OGAIN_DEV + 1,
910	SB_DT019X_OUTPUT_SW2,
911	SB_ALS4000_MONO_IO_CTRL,
912	SB_ALS4000_MIC_IN_GAIN,
913	SB_ALS4000_3D_SND_FX,
914	SB_ALS4000_3D_TIME_DELAY,
915};
916
917static void save_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs)
918{
919	unsigned char *val = chip->saved_regs;
920	snd_assert(num_regs > ARRAY_SIZE(chip->saved_regs), return);
921	for (; num_regs; num_regs--)
922		*val++ = snd_sbmixer_read(chip, *regs++);
923}
924
925static void restore_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs)
926{
927	unsigned char *val = chip->saved_regs;
928	snd_assert(num_regs > ARRAY_SIZE(chip->saved_regs), return);
929	for (; num_regs; num_regs--)
930		snd_sbmixer_write(chip, *regs++, *val++);
931}
932
933void snd_sbmixer_suspend(struct snd_sb *chip)
934{
935	switch (chip->hardware) {
936	case SB_HW_20:
937	case SB_HW_201:
938		save_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs));
939		break;
940	case SB_HW_PRO:
941		save_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs));
942		break;
943	case SB_HW_16:
944	case SB_HW_ALS100:
945		save_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs));
946		break;
947	case SB_HW_ALS4000:
948		save_mixer(chip, als4000_saved_regs, ARRAY_SIZE(als4000_saved_regs));
949		break;
950	case SB_HW_DT019X:
951		save_mixer(chip, dt019x_saved_regs, ARRAY_SIZE(dt019x_saved_regs));
952		break;
953	default:
954		break;
955	}
956}
957
958void snd_sbmixer_resume(struct snd_sb *chip)
959{
960	switch (chip->hardware) {
961	case SB_HW_20:
962	case SB_HW_201:
963		restore_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs));
964		break;
965	case SB_HW_PRO:
966		restore_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs));
967		break;
968	case SB_HW_16:
969	case SB_HW_ALS100:
970		restore_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs));
971		break;
972	case SB_HW_ALS4000:
973		restore_mixer(chip, als4000_saved_regs, ARRAY_SIZE(als4000_saved_regs));
974		break;
975	case SB_HW_DT019X:
976		restore_mixer(chip, dt019x_saved_regs, ARRAY_SIZE(dt019x_saved_regs));
977		break;
978	default:
979		break;
980	}
981}
982#endif
983