Linux Audio

Check our new training course

Linux BSP development engineering services

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