xref: /linux/sound/isa/msnd/msnd_pinnacle_mixer.c (revision 1bff292e9abec7477d43abb2b93c7fd26c44859b)
1f6c63835SKrzysztof Helt /***************************************************************************
2f6c63835SKrzysztof Helt 			  msnd_pinnacle_mixer.c  -  description
3f6c63835SKrzysztof Helt 			     -------------------
4f6c63835SKrzysztof Helt     begin		: Fre Jun 7 2002
5f6c63835SKrzysztof Helt     copyright 		: (C) 2002 by karsten wiese
6f6c63835SKrzysztof Helt     email		: annabellesgarden@yahoo.de
7f6c63835SKrzysztof Helt  ***************************************************************************/
8f6c63835SKrzysztof Helt 
9f6c63835SKrzysztof Helt /***************************************************************************
10f6c63835SKrzysztof Helt  *							      		   *
11f6c63835SKrzysztof Helt  *   This program is free software; you can redistribute it and/or modify  *
12f6c63835SKrzysztof Helt  *   it under the terms of the GNU General Public License as published by  *
13f6c63835SKrzysztof Helt  *   the Free Software Foundation; either version 2 of the License, or     *
14f6c63835SKrzysztof Helt  *   (at your option) any later version.				   *
15f6c63835SKrzysztof Helt  *									   *
16f6c63835SKrzysztof Helt  ***************************************************************************/
17f6c63835SKrzysztof Helt 
18f6c63835SKrzysztof Helt #include <linux/io.h>
19d81a6d71SPaul Gortmaker #include <linux/export.h>
20f6c63835SKrzysztof Helt 
21f6c63835SKrzysztof Helt #include <sound/core.h>
22f6c63835SKrzysztof Helt #include <sound/control.h>
23f6c63835SKrzysztof Helt #include "msnd.h"
24f6c63835SKrzysztof Helt #include "msnd_pinnacle.h"
25f6c63835SKrzysztof Helt 
26f6c63835SKrzysztof Helt 
27f6c63835SKrzysztof Helt #define MSND_MIXER_VOLUME	0
28f6c63835SKrzysztof Helt #define MSND_MIXER_PCM		1
29f6c63835SKrzysztof Helt #define MSND_MIXER_AUX		2	/* Input source 1  (aux1) */
30f6c63835SKrzysztof Helt #define MSND_MIXER_IMIX		3	/*  Recording monitor  */
31f6c63835SKrzysztof Helt #define MSND_MIXER_SYNTH	4
32f6c63835SKrzysztof Helt #define MSND_MIXER_SPEAKER	5
33f6c63835SKrzysztof Helt #define MSND_MIXER_LINE		6
34f6c63835SKrzysztof Helt #define MSND_MIXER_MIC		7
35f6c63835SKrzysztof Helt #define MSND_MIXER_RECLEV	11	/* Recording level */
36f6c63835SKrzysztof Helt #define MSND_MIXER_IGAIN	12	/* Input gain */
37f6c63835SKrzysztof Helt #define MSND_MIXER_OGAIN	13	/* Output gain */
38f6c63835SKrzysztof Helt #define MSND_MIXER_DIGITAL	17	/* Digital (input) 1 */
39f6c63835SKrzysztof Helt 
40f6c63835SKrzysztof Helt /*	Device mask bits	*/
41f6c63835SKrzysztof Helt 
42f6c63835SKrzysztof Helt #define MSND_MASK_VOLUME	(1 << MSND_MIXER_VOLUME)
43f6c63835SKrzysztof Helt #define MSND_MASK_SYNTH		(1 << MSND_MIXER_SYNTH)
44f6c63835SKrzysztof Helt #define MSND_MASK_PCM		(1 << MSND_MIXER_PCM)
45f6c63835SKrzysztof Helt #define MSND_MASK_SPEAKER	(1 << MSND_MIXER_SPEAKER)
46f6c63835SKrzysztof Helt #define MSND_MASK_LINE		(1 << MSND_MIXER_LINE)
47f6c63835SKrzysztof Helt #define MSND_MASK_MIC		(1 << MSND_MIXER_MIC)
48f6c63835SKrzysztof Helt #define MSND_MASK_IMIX		(1 << MSND_MIXER_IMIX)
49f6c63835SKrzysztof Helt #define MSND_MASK_RECLEV	(1 << MSND_MIXER_RECLEV)
50f6c63835SKrzysztof Helt #define MSND_MASK_IGAIN		(1 << MSND_MIXER_IGAIN)
51f6c63835SKrzysztof Helt #define MSND_MASK_OGAIN		(1 << MSND_MIXER_OGAIN)
52f6c63835SKrzysztof Helt #define MSND_MASK_AUX		(1 << MSND_MIXER_AUX)
53f6c63835SKrzysztof Helt #define MSND_MASK_DIGITAL	(1 << MSND_MIXER_DIGITAL)
54f6c63835SKrzysztof Helt 
55f6c63835SKrzysztof Helt static int snd_msndmix_info_mux(struct snd_kcontrol *kcontrol,
56f6c63835SKrzysztof Helt 				struct snd_ctl_elem_info *uinfo)
57f6c63835SKrzysztof Helt {
58f6c63835SKrzysztof Helt 	static char *texts[3] = {
59f6c63835SKrzysztof Helt 		"Analog", "MASS", "SPDIF",
60f6c63835SKrzysztof Helt 	};
61f6c63835SKrzysztof Helt 	struct snd_msnd *chip = snd_kcontrol_chip(kcontrol);
62f6c63835SKrzysztof Helt 	unsigned items = test_bit(F_HAVEDIGITAL, &chip->flags) ? 3 : 2;
63f6c63835SKrzysztof Helt 
64f6c63835SKrzysztof Helt 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
65f6c63835SKrzysztof Helt 	uinfo->count = 1;
66f6c63835SKrzysztof Helt 	uinfo->value.enumerated.items = items;
67f6c63835SKrzysztof Helt 	if (uinfo->value.enumerated.item >= items)
68f6c63835SKrzysztof Helt 		uinfo->value.enumerated.item = items - 1;
69f6c63835SKrzysztof Helt 	strcpy(uinfo->value.enumerated.name,
70f6c63835SKrzysztof Helt 		texts[uinfo->value.enumerated.item]);
71f6c63835SKrzysztof Helt 	return 0;
72f6c63835SKrzysztof Helt }
73f6c63835SKrzysztof Helt 
74f6c63835SKrzysztof Helt static int snd_msndmix_get_mux(struct snd_kcontrol *kcontrol,
75f6c63835SKrzysztof Helt 				struct snd_ctl_elem_value *ucontrol)
76f6c63835SKrzysztof Helt {
77f6c63835SKrzysztof Helt 	struct snd_msnd *chip = snd_kcontrol_chip(kcontrol);
78f6c63835SKrzysztof Helt 	/* MSND_MASK_IMIX is the default */
79f6c63835SKrzysztof Helt 	ucontrol->value.enumerated.item[0] = 0;
80f6c63835SKrzysztof Helt 
81f6c63835SKrzysztof Helt 	if (chip->recsrc & MSND_MASK_SYNTH) {
82f6c63835SKrzysztof Helt 		ucontrol->value.enumerated.item[0] = 1;
83f6c63835SKrzysztof Helt 	} else if ((chip->recsrc & MSND_MASK_DIGITAL) &&
84f6c63835SKrzysztof Helt 		 test_bit(F_HAVEDIGITAL, &chip->flags)) {
85f6c63835SKrzysztof Helt 		ucontrol->value.enumerated.item[0] = 2;
86f6c63835SKrzysztof Helt 	}
87f6c63835SKrzysztof Helt 
88f6c63835SKrzysztof Helt 
89f6c63835SKrzysztof Helt 	return 0;
90f6c63835SKrzysztof Helt }
91f6c63835SKrzysztof Helt 
92f6c63835SKrzysztof Helt static int snd_msndmix_set_mux(struct snd_msnd *chip, int val)
93f6c63835SKrzysztof Helt {
94f6c63835SKrzysztof Helt 	unsigned newrecsrc;
95f6c63835SKrzysztof Helt 	int change;
96f6c63835SKrzysztof Helt 	unsigned char msndbyte;
97f6c63835SKrzysztof Helt 
98f6c63835SKrzysztof Helt 	switch (val) {
99f6c63835SKrzysztof Helt 	case 0:
100f6c63835SKrzysztof Helt 		newrecsrc = MSND_MASK_IMIX;
101f6c63835SKrzysztof Helt 		msndbyte = HDEXAR_SET_ANA_IN;
102f6c63835SKrzysztof Helt 		break;
103f6c63835SKrzysztof Helt 	case 1:
104f6c63835SKrzysztof Helt 		newrecsrc = MSND_MASK_SYNTH;
105f6c63835SKrzysztof Helt 		msndbyte = HDEXAR_SET_SYNTH_IN;
106f6c63835SKrzysztof Helt 		break;
107f6c63835SKrzysztof Helt 	case 2:
108f6c63835SKrzysztof Helt 		newrecsrc = MSND_MASK_DIGITAL;
109f6c63835SKrzysztof Helt 		msndbyte = HDEXAR_SET_DAT_IN;
110f6c63835SKrzysztof Helt 		break;
111f6c63835SKrzysztof Helt 	default:
112f6c63835SKrzysztof Helt 		return -EINVAL;
113f6c63835SKrzysztof Helt 	}
114f6c63835SKrzysztof Helt 	change  = newrecsrc != chip->recsrc;
115f6c63835SKrzysztof Helt 	if (change) {
116f6c63835SKrzysztof Helt 		change = 0;
117f6c63835SKrzysztof Helt 		if (!snd_msnd_send_word(chip, 0, 0, msndbyte))
118f6c63835SKrzysztof Helt 			if (!snd_msnd_send_dsp_cmd(chip, HDEX_AUX_REQ)) {
119f6c63835SKrzysztof Helt 				chip->recsrc = newrecsrc;
120f6c63835SKrzysztof Helt 				change = 1;
121f6c63835SKrzysztof Helt 			}
122f6c63835SKrzysztof Helt 	}
123f6c63835SKrzysztof Helt 	return change;
124f6c63835SKrzysztof Helt }
125f6c63835SKrzysztof Helt 
126f6c63835SKrzysztof Helt static int snd_msndmix_put_mux(struct snd_kcontrol *kcontrol,
127f6c63835SKrzysztof Helt 				struct snd_ctl_elem_value *ucontrol)
128f6c63835SKrzysztof Helt {
129f6c63835SKrzysztof Helt 	struct snd_msnd *msnd = snd_kcontrol_chip(kcontrol);
130f6c63835SKrzysztof Helt 	return snd_msndmix_set_mux(msnd, ucontrol->value.enumerated.item[0]);
131f6c63835SKrzysztof Helt }
132f6c63835SKrzysztof Helt 
133f6c63835SKrzysztof Helt 
134f6c63835SKrzysztof Helt static int snd_msndmix_volume_info(struct snd_kcontrol *kcontrol,
135f6c63835SKrzysztof Helt 				   struct snd_ctl_elem_info *uinfo)
136f6c63835SKrzysztof Helt {
137f6c63835SKrzysztof Helt 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
138f6c63835SKrzysztof Helt 	uinfo->count = 2;
139f6c63835SKrzysztof Helt 	uinfo->value.integer.min = 0;
140f6c63835SKrzysztof Helt 	uinfo->value.integer.max = 100;
141f6c63835SKrzysztof Helt 	return 0;
142f6c63835SKrzysztof Helt }
143f6c63835SKrzysztof Helt 
144f6c63835SKrzysztof Helt static int snd_msndmix_volume_get(struct snd_kcontrol *kcontrol,
145f6c63835SKrzysztof Helt 				  struct snd_ctl_elem_value *ucontrol)
146f6c63835SKrzysztof Helt {
147f6c63835SKrzysztof Helt 	struct snd_msnd *msnd = snd_kcontrol_chip(kcontrol);
148f6c63835SKrzysztof Helt 	int addr = kcontrol->private_value;
149f6c63835SKrzysztof Helt 	unsigned long flags;
150f6c63835SKrzysztof Helt 
151f6c63835SKrzysztof Helt 	spin_lock_irqsave(&msnd->mixer_lock, flags);
152f6c63835SKrzysztof Helt 	ucontrol->value.integer.value[0] = msnd->left_levels[addr] * 100;
153f6c63835SKrzysztof Helt 	ucontrol->value.integer.value[0] /= 0xFFFF;
154f6c63835SKrzysztof Helt 	ucontrol->value.integer.value[1] = msnd->right_levels[addr] * 100;
155f6c63835SKrzysztof Helt 	ucontrol->value.integer.value[1] /= 0xFFFF;
156f6c63835SKrzysztof Helt 	spin_unlock_irqrestore(&msnd->mixer_lock, flags);
157f6c63835SKrzysztof Helt 	return 0;
158f6c63835SKrzysztof Helt }
159f6c63835SKrzysztof Helt 
160f6c63835SKrzysztof Helt #define update_volm(a, b)						\
161f6c63835SKrzysztof Helt 	do {								\
162f6c63835SKrzysztof Helt 		writew((dev->left_levels[a] >> 1) *			\
163f6c63835SKrzysztof Helt 		       readw(dev->SMA + SMA_wCurrMastVolLeft) / 0xffff,	\
164f6c63835SKrzysztof Helt 		       dev->SMA + SMA_##b##Left);			\
165f6c63835SKrzysztof Helt 		writew((dev->right_levels[a] >> 1)  *			\
166f6c63835SKrzysztof Helt 		       readw(dev->SMA + SMA_wCurrMastVolRight) / 0xffff, \
167f6c63835SKrzysztof Helt 		       dev->SMA + SMA_##b##Right);			\
168f6c63835SKrzysztof Helt 	} while (0);
169f6c63835SKrzysztof Helt 
170f6c63835SKrzysztof Helt #define update_potm(d, s, ar)						\
171f6c63835SKrzysztof Helt 	do {								\
172f6c63835SKrzysztof Helt 		writeb((dev->left_levels[d] >> 8) *			\
173f6c63835SKrzysztof Helt 		       readw(dev->SMA + SMA_wCurrMastVolLeft) / 0xffff, \
174f6c63835SKrzysztof Helt 		       dev->SMA + SMA_##s##Left);			\
175f6c63835SKrzysztof Helt 		writeb((dev->right_levels[d] >> 8) *			\
176f6c63835SKrzysztof Helt 		       readw(dev->SMA + SMA_wCurrMastVolRight) / 0xffff, \
177f6c63835SKrzysztof Helt 		       dev->SMA + SMA_##s##Right);			\
178f6c63835SKrzysztof Helt 		if (snd_msnd_send_word(dev, 0, 0, ar) == 0)		\
179f6c63835SKrzysztof Helt 			snd_msnd_send_dsp_cmd(dev, HDEX_AUX_REQ);	\
180f6c63835SKrzysztof Helt 	} while (0);
181f6c63835SKrzysztof Helt 
182f6c63835SKrzysztof Helt #define update_pot(d, s, ar)						\
183f6c63835SKrzysztof Helt 	do {								\
184f6c63835SKrzysztof Helt 		writeb(dev->left_levels[d] >> 8,			\
185f6c63835SKrzysztof Helt 		       dev->SMA + SMA_##s##Left);			\
186f6c63835SKrzysztof Helt 		writeb(dev->right_levels[d] >> 8,			\
187f6c63835SKrzysztof Helt 		       dev->SMA + SMA_##s##Right);			\
188f6c63835SKrzysztof Helt 		if (snd_msnd_send_word(dev, 0, 0, ar) == 0)		\
189f6c63835SKrzysztof Helt 			snd_msnd_send_dsp_cmd(dev, HDEX_AUX_REQ);	\
190f6c63835SKrzysztof Helt 	} while (0);
191f6c63835SKrzysztof Helt 
192f6c63835SKrzysztof Helt 
193f6c63835SKrzysztof Helt static int snd_msndmix_set(struct snd_msnd *dev, int d, int left, int right)
194f6c63835SKrzysztof Helt {
195f6c63835SKrzysztof Helt 	int bLeft, bRight;
196f6c63835SKrzysztof Helt 	int wLeft, wRight;
197f6c63835SKrzysztof Helt 	int updatemaster = 0;
198f6c63835SKrzysztof Helt 
199f6c63835SKrzysztof Helt 	if (d >= LEVEL_ENTRIES)
200f6c63835SKrzysztof Helt 		return -EINVAL;
201f6c63835SKrzysztof Helt 
202f6c63835SKrzysztof Helt 	bLeft = left * 0xff / 100;
203f6c63835SKrzysztof Helt 	wLeft = left * 0xffff / 100;
204f6c63835SKrzysztof Helt 
205f6c63835SKrzysztof Helt 	bRight = right * 0xff / 100;
206f6c63835SKrzysztof Helt 	wRight = right * 0xffff / 100;
207f6c63835SKrzysztof Helt 
208f6c63835SKrzysztof Helt 	dev->left_levels[d] = wLeft;
209f6c63835SKrzysztof Helt 	dev->right_levels[d] = wRight;
210f6c63835SKrzysztof Helt 
211f6c63835SKrzysztof Helt 	switch (d) {
212f6c63835SKrzysztof Helt 		/* master volume unscaled controls */
213f6c63835SKrzysztof Helt 	case MSND_MIXER_LINE:			/* line pot control */
214f6c63835SKrzysztof Helt 		/* scaled by IMIX in digital mix */
215f6c63835SKrzysztof Helt 		writeb(bLeft, dev->SMA + SMA_bInPotPosLeft);
216f6c63835SKrzysztof Helt 		writeb(bRight, dev->SMA + SMA_bInPotPosRight);
217f6c63835SKrzysztof Helt 		if (snd_msnd_send_word(dev, 0, 0, HDEXAR_IN_SET_POTS) == 0)
218f6c63835SKrzysztof Helt 			snd_msnd_send_dsp_cmd(dev, HDEX_AUX_REQ);
219f6c63835SKrzysztof Helt 		break;
220f6c63835SKrzysztof Helt 	case MSND_MIXER_MIC:			/* mic pot control */
221f6c63835SKrzysztof Helt 		if (dev->type == msndClassic)
222f6c63835SKrzysztof Helt 			return -EINVAL;
223f6c63835SKrzysztof Helt 		/* scaled by IMIX in digital mix */
224f6c63835SKrzysztof Helt 		writeb(bLeft, dev->SMA + SMA_bMicPotPosLeft);
225f6c63835SKrzysztof Helt 		writeb(bRight, dev->SMA + SMA_bMicPotPosRight);
226f6c63835SKrzysztof Helt 		if (snd_msnd_send_word(dev, 0, 0, HDEXAR_MIC_SET_POTS) == 0)
227f6c63835SKrzysztof Helt 			snd_msnd_send_dsp_cmd(dev, HDEX_AUX_REQ);
228f6c63835SKrzysztof Helt 		break;
229f6c63835SKrzysztof Helt 	case MSND_MIXER_VOLUME:		/* master volume */
230f6c63835SKrzysztof Helt 		writew(wLeft, dev->SMA + SMA_wCurrMastVolLeft);
231f6c63835SKrzysztof Helt 		writew(wRight, dev->SMA + SMA_wCurrMastVolRight);
232f6c63835SKrzysztof Helt 		/* fall through */
233f6c63835SKrzysztof Helt 
234f6c63835SKrzysztof Helt 	case MSND_MIXER_AUX:			/* aux pot control */
235f6c63835SKrzysztof Helt 		/* scaled by master volume */
236f6c63835SKrzysztof Helt 		/* fall through */
237f6c63835SKrzysztof Helt 
238f6c63835SKrzysztof Helt 		/* digital controls */
239f6c63835SKrzysztof Helt 	case MSND_MIXER_SYNTH:			/* synth vol (dsp mix) */
240f6c63835SKrzysztof Helt 	case MSND_MIXER_PCM:			/* pcm vol (dsp mix) */
241f6c63835SKrzysztof Helt 	case MSND_MIXER_IMIX:			/* input monitor (dsp mix) */
242f6c63835SKrzysztof Helt 		/* scaled by master volume */
243f6c63835SKrzysztof Helt 		updatemaster = 1;
244f6c63835SKrzysztof Helt 		break;
245f6c63835SKrzysztof Helt 
246f6c63835SKrzysztof Helt 	default:
247f6c63835SKrzysztof Helt 		return -EINVAL;
248f6c63835SKrzysztof Helt 	}
249f6c63835SKrzysztof Helt 
250f6c63835SKrzysztof Helt 	if (updatemaster) {
251f6c63835SKrzysztof Helt 		/* update master volume scaled controls */
252f6c63835SKrzysztof Helt 		update_volm(MSND_MIXER_PCM, wCurrPlayVol);
253f6c63835SKrzysztof Helt 		update_volm(MSND_MIXER_IMIX, wCurrInVol);
254f6c63835SKrzysztof Helt 		if (dev->type == msndPinnacle)
255f6c63835SKrzysztof Helt 			update_volm(MSND_MIXER_SYNTH, wCurrMHdrVol);
256f6c63835SKrzysztof Helt 		update_potm(MSND_MIXER_AUX, bAuxPotPos, HDEXAR_AUX_SET_POTS);
257f6c63835SKrzysztof Helt 	}
258f6c63835SKrzysztof Helt 
259f6c63835SKrzysztof Helt 	return 0;
260f6c63835SKrzysztof Helt }
261f6c63835SKrzysztof Helt 
262f6c63835SKrzysztof Helt static int snd_msndmix_volume_put(struct snd_kcontrol *kcontrol,
263f6c63835SKrzysztof Helt 				  struct snd_ctl_elem_value *ucontrol)
264f6c63835SKrzysztof Helt {
265f6c63835SKrzysztof Helt 	struct snd_msnd *msnd = snd_kcontrol_chip(kcontrol);
266f6c63835SKrzysztof Helt 	int change, addr = kcontrol->private_value;
267f6c63835SKrzysztof Helt 	int left, right;
268f6c63835SKrzysztof Helt 	unsigned long flags;
269f6c63835SKrzysztof Helt 
270f6c63835SKrzysztof Helt 	left = ucontrol->value.integer.value[0] % 101;
271f6c63835SKrzysztof Helt 	right = ucontrol->value.integer.value[1] % 101;
272f6c63835SKrzysztof Helt 	spin_lock_irqsave(&msnd->mixer_lock, flags);
273f6c63835SKrzysztof Helt 	change = msnd->left_levels[addr] != left
274f6c63835SKrzysztof Helt 		|| msnd->right_levels[addr] != right;
275f6c63835SKrzysztof Helt 	snd_msndmix_set(msnd, addr, left, right);
276f6c63835SKrzysztof Helt 	spin_unlock_irqrestore(&msnd->mixer_lock, flags);
277f6c63835SKrzysztof Helt 	return change;
278f6c63835SKrzysztof Helt }
279f6c63835SKrzysztof Helt 
280f6c63835SKrzysztof Helt 
281f6c63835SKrzysztof Helt #define DUMMY_VOLUME(xname, xindex, addr) \
282f6c63835SKrzysztof Helt { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
283f6c63835SKrzysztof Helt   .info = snd_msndmix_volume_info, \
284f6c63835SKrzysztof Helt   .get = snd_msndmix_volume_get, .put = snd_msndmix_volume_put, \
285f6c63835SKrzysztof Helt   .private_value = addr }
286f6c63835SKrzysztof Helt 
287f6c63835SKrzysztof Helt 
288f6c63835SKrzysztof Helt static struct snd_kcontrol_new snd_msnd_controls[] = {
289f6c63835SKrzysztof Helt DUMMY_VOLUME("Master Volume", 0, MSND_MIXER_VOLUME),
290f6c63835SKrzysztof Helt DUMMY_VOLUME("PCM Volume", 0, MSND_MIXER_PCM),
291f6c63835SKrzysztof Helt DUMMY_VOLUME("Aux Volume", 0, MSND_MIXER_AUX),
292f6c63835SKrzysztof Helt DUMMY_VOLUME("Line Volume", 0, MSND_MIXER_LINE),
293f6c63835SKrzysztof Helt DUMMY_VOLUME("Mic Volume", 0, MSND_MIXER_MIC),
294f6c63835SKrzysztof Helt DUMMY_VOLUME("Monitor",	0, MSND_MIXER_IMIX),
295f6c63835SKrzysztof Helt {
296f6c63835SKrzysztof Helt 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
297f6c63835SKrzysztof Helt 	.name = "Capture Source",
298f6c63835SKrzysztof Helt 	.info = snd_msndmix_info_mux,
299f6c63835SKrzysztof Helt 	.get = snd_msndmix_get_mux,
300f6c63835SKrzysztof Helt 	.put = snd_msndmix_put_mux,
301f6c63835SKrzysztof Helt }
302f6c63835SKrzysztof Helt };
303f6c63835SKrzysztof Helt 
304f6c63835SKrzysztof Helt 
305*1bff292eSBill Pemberton int snd_msndmix_new(struct snd_card *card)
306f6c63835SKrzysztof Helt {
307f6c63835SKrzysztof Helt 	struct snd_msnd *chip = card->private_data;
308f6c63835SKrzysztof Helt 	unsigned int idx;
309f6c63835SKrzysztof Helt 	int err;
310f6c63835SKrzysztof Helt 
311f6c63835SKrzysztof Helt 	if (snd_BUG_ON(!chip))
312f6c63835SKrzysztof Helt 		return -EINVAL;
313f6c63835SKrzysztof Helt 	spin_lock_init(&chip->mixer_lock);
314f6c63835SKrzysztof Helt 	strcpy(card->mixername, "MSND Pinnacle Mixer");
315f6c63835SKrzysztof Helt 
316f6c63835SKrzysztof Helt 	for (idx = 0; idx < ARRAY_SIZE(snd_msnd_controls); idx++)
317f6c63835SKrzysztof Helt 		err = snd_ctl_add(card,
318f6c63835SKrzysztof Helt 				  snd_ctl_new1(snd_msnd_controls + idx, chip));
319f6c63835SKrzysztof Helt 		if (err < 0)
320f6c63835SKrzysztof Helt 			return err;
321f6c63835SKrzysztof Helt 
322f6c63835SKrzysztof Helt 	return 0;
323f6c63835SKrzysztof Helt }
324f6c63835SKrzysztof Helt EXPORT_SYMBOL(snd_msndmix_new);
325f6c63835SKrzysztof Helt 
326f6c63835SKrzysztof Helt void snd_msndmix_setup(struct snd_msnd *dev)
327f6c63835SKrzysztof Helt {
328f6c63835SKrzysztof Helt 	update_pot(MSND_MIXER_LINE, bInPotPos, HDEXAR_IN_SET_POTS);
329f6c63835SKrzysztof Helt 	update_potm(MSND_MIXER_AUX, bAuxPotPos, HDEXAR_AUX_SET_POTS);
330f6c63835SKrzysztof Helt 	update_volm(MSND_MIXER_PCM, wCurrPlayVol);
331f6c63835SKrzysztof Helt 	update_volm(MSND_MIXER_IMIX, wCurrInVol);
332f6c63835SKrzysztof Helt 	if (dev->type == msndPinnacle) {
333f6c63835SKrzysztof Helt 		update_pot(MSND_MIXER_MIC, bMicPotPos, HDEXAR_MIC_SET_POTS);
334f6c63835SKrzysztof Helt 		update_volm(MSND_MIXER_SYNTH, wCurrMHdrVol);
335f6c63835SKrzysztof Helt 	}
336f6c63835SKrzysztof Helt }
337f6c63835SKrzysztof Helt EXPORT_SYMBOL(snd_msndmix_setup);
338f6c63835SKrzysztof Helt 
339f6c63835SKrzysztof Helt int snd_msndmix_force_recsrc(struct snd_msnd *dev, int recsrc)
340f6c63835SKrzysztof Helt {
341f6c63835SKrzysztof Helt 	dev->recsrc = -1;
342f6c63835SKrzysztof Helt 	return snd_msndmix_set_mux(dev, recsrc);
343f6c63835SKrzysztof Helt }
344f6c63835SKrzysztof Helt EXPORT_SYMBOL(snd_msndmix_force_recsrc);
345