xref: /openbmc/linux/sound/pci/emu10k1/emumixer.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1*1da177e4SLinus Torvalds /*
2*1da177e4SLinus Torvalds  *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>,
3*1da177e4SLinus Torvalds  *                   Takashi Iwai <tiwai@suse.de>
4*1da177e4SLinus Torvalds  *                   Creative Labs, Inc.
5*1da177e4SLinus Torvalds  *  Routines for control of EMU10K1 chips / mixer routines
6*1da177e4SLinus Torvalds  *  Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com>
7*1da177e4SLinus Torvalds  *
8*1da177e4SLinus Torvalds  *  BUGS:
9*1da177e4SLinus Torvalds  *    --
10*1da177e4SLinus Torvalds  *
11*1da177e4SLinus Torvalds  *  TODO:
12*1da177e4SLinus Torvalds  *    --
13*1da177e4SLinus Torvalds  *
14*1da177e4SLinus Torvalds  *   This program is free software; you can redistribute it and/or modify
15*1da177e4SLinus Torvalds  *   it under the terms of the GNU General Public License as published by
16*1da177e4SLinus Torvalds  *   the Free Software Foundation; either version 2 of the License, or
17*1da177e4SLinus Torvalds  *   (at your option) any later version.
18*1da177e4SLinus Torvalds  *
19*1da177e4SLinus Torvalds  *   This program is distributed in the hope that it will be useful,
20*1da177e4SLinus Torvalds  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
21*1da177e4SLinus Torvalds  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22*1da177e4SLinus Torvalds  *   GNU General Public License for more details.
23*1da177e4SLinus Torvalds  *
24*1da177e4SLinus Torvalds  *   You should have received a copy of the GNU General Public License
25*1da177e4SLinus Torvalds  *   along with this program; if not, write to the Free Software
26*1da177e4SLinus Torvalds  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
27*1da177e4SLinus Torvalds  *
28*1da177e4SLinus Torvalds  */
29*1da177e4SLinus Torvalds 
30*1da177e4SLinus Torvalds #include <sound/driver.h>
31*1da177e4SLinus Torvalds #include <linux/time.h>
32*1da177e4SLinus Torvalds #include <linux/init.h>
33*1da177e4SLinus Torvalds #include <sound/core.h>
34*1da177e4SLinus Torvalds #include <sound/emu10k1.h>
35*1da177e4SLinus Torvalds 
36*1da177e4SLinus Torvalds #define AC97_ID_STAC9758	0x83847658
37*1da177e4SLinus Torvalds 
38*1da177e4SLinus Torvalds static int snd_emu10k1_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
39*1da177e4SLinus Torvalds {
40*1da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
41*1da177e4SLinus Torvalds 	uinfo->count = 1;
42*1da177e4SLinus Torvalds 	return 0;
43*1da177e4SLinus Torvalds }
44*1da177e4SLinus Torvalds 
45*1da177e4SLinus Torvalds static int snd_emu10k1_spdif_get(snd_kcontrol_t * kcontrol,
46*1da177e4SLinus Torvalds                                  snd_ctl_elem_value_t * ucontrol)
47*1da177e4SLinus Torvalds {
48*1da177e4SLinus Torvalds 	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
49*1da177e4SLinus Torvalds 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
50*1da177e4SLinus Torvalds 	unsigned long flags;
51*1da177e4SLinus Torvalds 
52*1da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
53*1da177e4SLinus Torvalds 	ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff;
54*1da177e4SLinus Torvalds 	ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff;
55*1da177e4SLinus Torvalds 	ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff;
56*1da177e4SLinus Torvalds 	ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff;
57*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
58*1da177e4SLinus Torvalds 	return 0;
59*1da177e4SLinus Torvalds }
60*1da177e4SLinus Torvalds 
61*1da177e4SLinus Torvalds static int snd_emu10k1_spdif_get_mask(snd_kcontrol_t * kcontrol,
62*1da177e4SLinus Torvalds 				      snd_ctl_elem_value_t * ucontrol)
63*1da177e4SLinus Torvalds {
64*1da177e4SLinus Torvalds 	ucontrol->value.iec958.status[0] = 0xff;
65*1da177e4SLinus Torvalds 	ucontrol->value.iec958.status[1] = 0xff;
66*1da177e4SLinus Torvalds 	ucontrol->value.iec958.status[2] = 0xff;
67*1da177e4SLinus Torvalds 	ucontrol->value.iec958.status[3] = 0xff;
68*1da177e4SLinus Torvalds 	return 0;
69*1da177e4SLinus Torvalds }
70*1da177e4SLinus Torvalds 
71*1da177e4SLinus Torvalds static int snd_audigy_spdif_output_rate_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
72*1da177e4SLinus Torvalds {
73*1da177e4SLinus Torvalds 	static char *texts[] = {"44100", "48000", "96000"};
74*1da177e4SLinus Torvalds 
75*1da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
76*1da177e4SLinus Torvalds 	uinfo->count = 1;
77*1da177e4SLinus Torvalds 	uinfo->value.enumerated.items = 3;
78*1da177e4SLinus Torvalds 	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
79*1da177e4SLinus Torvalds 		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
80*1da177e4SLinus Torvalds 	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
81*1da177e4SLinus Torvalds 	return 0;
82*1da177e4SLinus Torvalds }
83*1da177e4SLinus Torvalds 
84*1da177e4SLinus Torvalds static int snd_audigy_spdif_output_rate_get(snd_kcontrol_t * kcontrol,
85*1da177e4SLinus Torvalds                                  snd_ctl_elem_value_t * ucontrol)
86*1da177e4SLinus Torvalds {
87*1da177e4SLinus Torvalds 	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
88*1da177e4SLinus Torvalds 	unsigned int tmp;
89*1da177e4SLinus Torvalds 	unsigned long flags;
90*1da177e4SLinus Torvalds 
91*1da177e4SLinus Torvalds 
92*1da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
93*1da177e4SLinus Torvalds 	tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
94*1da177e4SLinus Torvalds 	switch (tmp & A_SPDIF_RATE_MASK) {
95*1da177e4SLinus Torvalds 	case A_SPDIF_44100:
96*1da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 0;
97*1da177e4SLinus Torvalds 		break;
98*1da177e4SLinus Torvalds 	case A_SPDIF_48000:
99*1da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
100*1da177e4SLinus Torvalds 		break;
101*1da177e4SLinus Torvalds 	case A_SPDIF_96000:
102*1da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 2;
103*1da177e4SLinus Torvalds 		break;
104*1da177e4SLinus Torvalds 	default:
105*1da177e4SLinus Torvalds 		ucontrol->value.enumerated.item[0] = 1;
106*1da177e4SLinus Torvalds 	}
107*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
108*1da177e4SLinus Torvalds 	return 0;
109*1da177e4SLinus Torvalds }
110*1da177e4SLinus Torvalds 
111*1da177e4SLinus Torvalds static int snd_audigy_spdif_output_rate_put(snd_kcontrol_t * kcontrol,
112*1da177e4SLinus Torvalds                                  snd_ctl_elem_value_t * ucontrol)
113*1da177e4SLinus Torvalds {
114*1da177e4SLinus Torvalds 	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
115*1da177e4SLinus Torvalds 	int change;
116*1da177e4SLinus Torvalds 	unsigned int reg, val, tmp;
117*1da177e4SLinus Torvalds 	unsigned long flags;
118*1da177e4SLinus Torvalds 
119*1da177e4SLinus Torvalds 	switch(ucontrol->value.enumerated.item[0]) {
120*1da177e4SLinus Torvalds 	case 0:
121*1da177e4SLinus Torvalds 		val = A_SPDIF_44100;
122*1da177e4SLinus Torvalds 		break;
123*1da177e4SLinus Torvalds 	case 1:
124*1da177e4SLinus Torvalds 		val = A_SPDIF_48000;
125*1da177e4SLinus Torvalds 		break;
126*1da177e4SLinus Torvalds 	case 2:
127*1da177e4SLinus Torvalds 		val = A_SPDIF_96000;
128*1da177e4SLinus Torvalds 		break;
129*1da177e4SLinus Torvalds 	default:
130*1da177e4SLinus Torvalds 		val = A_SPDIF_48000;
131*1da177e4SLinus Torvalds 		break;
132*1da177e4SLinus Torvalds 	}
133*1da177e4SLinus Torvalds 
134*1da177e4SLinus Torvalds 
135*1da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
136*1da177e4SLinus Torvalds 	reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
137*1da177e4SLinus Torvalds 	tmp = reg & ~A_SPDIF_RATE_MASK;
138*1da177e4SLinus Torvalds 	tmp |= val;
139*1da177e4SLinus Torvalds 	if ((change = (tmp != reg)))
140*1da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp);
141*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
142*1da177e4SLinus Torvalds 	return change;
143*1da177e4SLinus Torvalds }
144*1da177e4SLinus Torvalds 
145*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_audigy_spdif_output_rate =
146*1da177e4SLinus Torvalds {
147*1da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE,
148*1da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
149*1da177e4SLinus Torvalds 	.name =         "Audigy SPDIF Output Sample Rate",
150*1da177e4SLinus Torvalds 	.count =	1,
151*1da177e4SLinus Torvalds 	.info =         snd_audigy_spdif_output_rate_info,
152*1da177e4SLinus Torvalds 	.get =          snd_audigy_spdif_output_rate_get,
153*1da177e4SLinus Torvalds 	.put =          snd_audigy_spdif_output_rate_put
154*1da177e4SLinus Torvalds };
155*1da177e4SLinus Torvalds 
156*1da177e4SLinus Torvalds static int snd_emu10k1_spdif_put(snd_kcontrol_t * kcontrol,
157*1da177e4SLinus Torvalds                                  snd_ctl_elem_value_t * ucontrol)
158*1da177e4SLinus Torvalds {
159*1da177e4SLinus Torvalds 	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
160*1da177e4SLinus Torvalds 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
161*1da177e4SLinus Torvalds 	int change;
162*1da177e4SLinus Torvalds 	unsigned int val;
163*1da177e4SLinus Torvalds 	unsigned long flags;
164*1da177e4SLinus Torvalds 
165*1da177e4SLinus Torvalds 	val = (ucontrol->value.iec958.status[0] << 0) |
166*1da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[1] << 8) |
167*1da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[2] << 16) |
168*1da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[3] << 24);
169*1da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
170*1da177e4SLinus Torvalds 	change = val != emu->spdif_bits[idx];
171*1da177e4SLinus Torvalds 	if (change) {
172*1da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val);
173*1da177e4SLinus Torvalds 		emu->spdif_bits[idx] = val;
174*1da177e4SLinus Torvalds 	}
175*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
176*1da177e4SLinus Torvalds 	return change;
177*1da177e4SLinus Torvalds }
178*1da177e4SLinus Torvalds 
179*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_emu10k1_spdif_mask_control =
180*1da177e4SLinus Torvalds {
181*1da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
182*1da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
183*1da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
184*1da177e4SLinus Torvalds 	.count =	4,
185*1da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
186*1da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get_mask
187*1da177e4SLinus Torvalds };
188*1da177e4SLinus Torvalds 
189*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_emu10k1_spdif_control =
190*1da177e4SLinus Torvalds {
191*1da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
192*1da177e4SLinus Torvalds 	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
193*1da177e4SLinus Torvalds 	.count =	4,
194*1da177e4SLinus Torvalds 	.info =         snd_emu10k1_spdif_info,
195*1da177e4SLinus Torvalds 	.get =          snd_emu10k1_spdif_get,
196*1da177e4SLinus Torvalds 	.put =          snd_emu10k1_spdif_put
197*1da177e4SLinus Torvalds };
198*1da177e4SLinus Torvalds 
199*1da177e4SLinus Torvalds 
200*1da177e4SLinus Torvalds static void update_emu10k1_fxrt(emu10k1_t *emu, int voice, unsigned char *route)
201*1da177e4SLinus Torvalds {
202*1da177e4SLinus Torvalds 	if (emu->audigy) {
203*1da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT1, voice,
204*1da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt1(route));
205*1da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_FXRT2, voice,
206*1da177e4SLinus Torvalds 				      snd_emu10k1_compose_audigy_fxrt2(route));
207*1da177e4SLinus Torvalds 	} else {
208*1da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, FXRT, voice,
209*1da177e4SLinus Torvalds 				      snd_emu10k1_compose_send_routing(route));
210*1da177e4SLinus Torvalds 	}
211*1da177e4SLinus Torvalds }
212*1da177e4SLinus Torvalds 
213*1da177e4SLinus Torvalds static void update_emu10k1_send_volume(emu10k1_t *emu, int voice, unsigned char *volume)
214*1da177e4SLinus Torvalds {
215*1da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]);
216*1da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]);
217*1da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]);
218*1da177e4SLinus Torvalds 	snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]);
219*1da177e4SLinus Torvalds 	if (emu->audigy) {
220*1da177e4SLinus Torvalds 		unsigned int val = ((unsigned int)volume[4] << 24) |
221*1da177e4SLinus Torvalds 			((unsigned int)volume[5] << 16) |
222*1da177e4SLinus Torvalds 			((unsigned int)volume[6] << 8) |
223*1da177e4SLinus Torvalds 			(unsigned int)volume[7];
224*1da177e4SLinus Torvalds 		snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, val);
225*1da177e4SLinus Torvalds 	}
226*1da177e4SLinus Torvalds }
227*1da177e4SLinus Torvalds 
228*1da177e4SLinus Torvalds /* PCM stream controls */
229*1da177e4SLinus Torvalds 
230*1da177e4SLinus Torvalds static int snd_emu10k1_send_routing_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
231*1da177e4SLinus Torvalds {
232*1da177e4SLinus Torvalds 	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
233*1da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
234*1da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
235*1da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
236*1da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
237*1da177e4SLinus Torvalds 	return 0;
238*1da177e4SLinus Torvalds }
239*1da177e4SLinus Torvalds 
240*1da177e4SLinus Torvalds static int snd_emu10k1_send_routing_get(snd_kcontrol_t * kcontrol,
241*1da177e4SLinus Torvalds                                         snd_ctl_elem_value_t * ucontrol)
242*1da177e4SLinus Torvalds {
243*1da177e4SLinus Torvalds 	unsigned long flags;
244*1da177e4SLinus Torvalds 	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
245*1da177e4SLinus Torvalds 	emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
246*1da177e4SLinus Torvalds 	int voice, idx;
247*1da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
248*1da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
249*1da177e4SLinus Torvalds 
250*1da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
251*1da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
252*1da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++)
253*1da177e4SLinus Torvalds 			ucontrol->value.integer.value[(voice * num_efx) + idx] =
254*1da177e4SLinus Torvalds 				mix->send_routing[voice][idx] & mask;
255*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
256*1da177e4SLinus Torvalds 	return 0;
257*1da177e4SLinus Torvalds }
258*1da177e4SLinus Torvalds 
259*1da177e4SLinus Torvalds static int snd_emu10k1_send_routing_put(snd_kcontrol_t * kcontrol,
260*1da177e4SLinus Torvalds                                         snd_ctl_elem_value_t * ucontrol)
261*1da177e4SLinus Torvalds {
262*1da177e4SLinus Torvalds 	unsigned long flags;
263*1da177e4SLinus Torvalds 	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
264*1da177e4SLinus Torvalds 	emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
265*1da177e4SLinus Torvalds 	int change = 0, voice, idx, val;
266*1da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
267*1da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
268*1da177e4SLinus Torvalds 
269*1da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
270*1da177e4SLinus Torvalds 	for (voice = 0; voice < 3; voice++)
271*1da177e4SLinus Torvalds 		for (idx = 0; idx < num_efx; idx++) {
272*1da177e4SLinus Torvalds 			val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask;
273*1da177e4SLinus Torvalds 			if (mix->send_routing[voice][idx] != val) {
274*1da177e4SLinus Torvalds 				mix->send_routing[voice][idx] = val;
275*1da177e4SLinus Torvalds 				change = 1;
276*1da177e4SLinus Torvalds 			}
277*1da177e4SLinus Torvalds 		}
278*1da177e4SLinus Torvalds 	if (change && mix->epcm) {
279*1da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
280*1da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
281*1da177e4SLinus Torvalds 					    &mix->send_routing[1][0]);
282*1da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number,
283*1da177e4SLinus Torvalds 					    &mix->send_routing[2][0]);
284*1da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
285*1da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
286*1da177e4SLinus Torvalds 					    &mix->send_routing[0][0]);
287*1da177e4SLinus Torvalds 		}
288*1da177e4SLinus Torvalds 	}
289*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
290*1da177e4SLinus Torvalds 	return change;
291*1da177e4SLinus Torvalds }
292*1da177e4SLinus Torvalds 
293*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_emu10k1_send_routing_control =
294*1da177e4SLinus Torvalds {
295*1da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
296*1da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
297*1da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Routing",
298*1da177e4SLinus Torvalds 	.count =	32,
299*1da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_routing_info,
300*1da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_routing_get,
301*1da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_routing_put
302*1da177e4SLinus Torvalds };
303*1da177e4SLinus Torvalds 
304*1da177e4SLinus Torvalds static int snd_emu10k1_send_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
305*1da177e4SLinus Torvalds {
306*1da177e4SLinus Torvalds 	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
307*1da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
308*1da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 3*8 : 3*4;
309*1da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
310*1da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
311*1da177e4SLinus Torvalds 	return 0;
312*1da177e4SLinus Torvalds }
313*1da177e4SLinus Torvalds 
314*1da177e4SLinus Torvalds static int snd_emu10k1_send_volume_get(snd_kcontrol_t * kcontrol,
315*1da177e4SLinus Torvalds                                        snd_ctl_elem_value_t * ucontrol)
316*1da177e4SLinus Torvalds {
317*1da177e4SLinus Torvalds 	unsigned long flags;
318*1da177e4SLinus Torvalds 	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
319*1da177e4SLinus Torvalds 	emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
320*1da177e4SLinus Torvalds 	int idx;
321*1da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
322*1da177e4SLinus Torvalds 
323*1da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
324*1da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++)
325*1da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx];
326*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
327*1da177e4SLinus Torvalds 	return 0;
328*1da177e4SLinus Torvalds }
329*1da177e4SLinus Torvalds 
330*1da177e4SLinus Torvalds static int snd_emu10k1_send_volume_put(snd_kcontrol_t * kcontrol,
331*1da177e4SLinus Torvalds                                        snd_ctl_elem_value_t * ucontrol)
332*1da177e4SLinus Torvalds {
333*1da177e4SLinus Torvalds 	unsigned long flags;
334*1da177e4SLinus Torvalds 	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
335*1da177e4SLinus Torvalds 	emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
336*1da177e4SLinus Torvalds 	int change = 0, idx, val;
337*1da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
338*1da177e4SLinus Torvalds 
339*1da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
340*1da177e4SLinus Torvalds 	for (idx = 0; idx < 3*num_efx; idx++) {
341*1da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
342*1da177e4SLinus Torvalds 		if (mix->send_volume[idx/num_efx][idx%num_efx] != val) {
343*1da177e4SLinus Torvalds 			mix->send_volume[idx/num_efx][idx%num_efx] = val;
344*1da177e4SLinus Torvalds 			change = 1;
345*1da177e4SLinus Torvalds 		}
346*1da177e4SLinus Torvalds 	}
347*1da177e4SLinus Torvalds 	if (change && mix->epcm) {
348*1da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
349*1da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
350*1da177e4SLinus Torvalds 						   &mix->send_volume[1][0]);
351*1da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number,
352*1da177e4SLinus Torvalds 						   &mix->send_volume[2][0]);
353*1da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
354*1da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
355*1da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
356*1da177e4SLinus Torvalds 		}
357*1da177e4SLinus Torvalds 	}
358*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
359*1da177e4SLinus Torvalds 	return change;
360*1da177e4SLinus Torvalds }
361*1da177e4SLinus Torvalds 
362*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_emu10k1_send_volume_control =
363*1da177e4SLinus Torvalds {
364*1da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
365*1da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
366*1da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Send Volume",
367*1da177e4SLinus Torvalds 	.count =	32,
368*1da177e4SLinus Torvalds 	.info =         snd_emu10k1_send_volume_info,
369*1da177e4SLinus Torvalds 	.get =          snd_emu10k1_send_volume_get,
370*1da177e4SLinus Torvalds 	.put =          snd_emu10k1_send_volume_put
371*1da177e4SLinus Torvalds };
372*1da177e4SLinus Torvalds 
373*1da177e4SLinus Torvalds static int snd_emu10k1_attn_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
374*1da177e4SLinus Torvalds {
375*1da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
376*1da177e4SLinus Torvalds 	uinfo->count = 3;
377*1da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
378*1da177e4SLinus Torvalds 	uinfo->value.integer.max = 0xffff;
379*1da177e4SLinus Torvalds 	return 0;
380*1da177e4SLinus Torvalds }
381*1da177e4SLinus Torvalds 
382*1da177e4SLinus Torvalds static int snd_emu10k1_attn_get(snd_kcontrol_t * kcontrol,
383*1da177e4SLinus Torvalds                                 snd_ctl_elem_value_t * ucontrol)
384*1da177e4SLinus Torvalds {
385*1da177e4SLinus Torvalds 	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
386*1da177e4SLinus Torvalds 	emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
387*1da177e4SLinus Torvalds 	unsigned long flags;
388*1da177e4SLinus Torvalds 	int idx;
389*1da177e4SLinus Torvalds 
390*1da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
391*1da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++)
392*1da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->attn[idx];
393*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
394*1da177e4SLinus Torvalds 	return 0;
395*1da177e4SLinus Torvalds }
396*1da177e4SLinus Torvalds 
397*1da177e4SLinus Torvalds static int snd_emu10k1_attn_put(snd_kcontrol_t * kcontrol,
398*1da177e4SLinus Torvalds 				snd_ctl_elem_value_t * ucontrol)
399*1da177e4SLinus Torvalds {
400*1da177e4SLinus Torvalds 	unsigned long flags;
401*1da177e4SLinus Torvalds 	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
402*1da177e4SLinus Torvalds 	emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
403*1da177e4SLinus Torvalds 	int change = 0, idx, val;
404*1da177e4SLinus Torvalds 
405*1da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
406*1da177e4SLinus Torvalds 	for (idx = 0; idx < 3; idx++) {
407*1da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 0xffff;
408*1da177e4SLinus Torvalds 		if (mix->attn[idx] != val) {
409*1da177e4SLinus Torvalds 			mix->attn[idx] = val;
410*1da177e4SLinus Torvalds 			change = 1;
411*1da177e4SLinus Torvalds 		}
412*1da177e4SLinus Torvalds 	}
413*1da177e4SLinus Torvalds 	if (change && mix->epcm) {
414*1da177e4SLinus Torvalds 		if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
415*1da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]);
416*1da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]);
417*1da177e4SLinus Torvalds 		} else if (mix->epcm->voices[0]) {
418*1da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]);
419*1da177e4SLinus Torvalds 		}
420*1da177e4SLinus Torvalds 	}
421*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
422*1da177e4SLinus Torvalds 	return change;
423*1da177e4SLinus Torvalds }
424*1da177e4SLinus Torvalds 
425*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_emu10k1_attn_control =
426*1da177e4SLinus Torvalds {
427*1da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
428*1da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_MIXER,
429*1da177e4SLinus Torvalds 	.name =         "EMU10K1 PCM Volume",
430*1da177e4SLinus Torvalds 	.count =	32,
431*1da177e4SLinus Torvalds 	.info =         snd_emu10k1_attn_info,
432*1da177e4SLinus Torvalds 	.get =          snd_emu10k1_attn_get,
433*1da177e4SLinus Torvalds 	.put =          snd_emu10k1_attn_put
434*1da177e4SLinus Torvalds };
435*1da177e4SLinus Torvalds 
436*1da177e4SLinus Torvalds /* Mutichannel PCM stream controls */
437*1da177e4SLinus Torvalds 
438*1da177e4SLinus Torvalds static int snd_emu10k1_efx_send_routing_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
439*1da177e4SLinus Torvalds {
440*1da177e4SLinus Torvalds 	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
441*1da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
442*1da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
443*1da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
444*1da177e4SLinus Torvalds 	uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
445*1da177e4SLinus Torvalds 	return 0;
446*1da177e4SLinus Torvalds }
447*1da177e4SLinus Torvalds 
448*1da177e4SLinus Torvalds static int snd_emu10k1_efx_send_routing_get(snd_kcontrol_t * kcontrol,
449*1da177e4SLinus Torvalds                                         snd_ctl_elem_value_t * ucontrol)
450*1da177e4SLinus Torvalds {
451*1da177e4SLinus Torvalds 	unsigned long flags;
452*1da177e4SLinus Torvalds 	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
453*1da177e4SLinus Torvalds 	emu10k1_pcm_mixer_t *mix = &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
454*1da177e4SLinus Torvalds 	int idx;
455*1da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
456*1da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
457*1da177e4SLinus Torvalds 
458*1da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
459*1da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
460*1da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] =
461*1da177e4SLinus Torvalds 			mix->send_routing[0][idx] & mask;
462*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
463*1da177e4SLinus Torvalds 	return 0;
464*1da177e4SLinus Torvalds }
465*1da177e4SLinus Torvalds 
466*1da177e4SLinus Torvalds static int snd_emu10k1_efx_send_routing_put(snd_kcontrol_t * kcontrol,
467*1da177e4SLinus Torvalds                                         snd_ctl_elem_value_t * ucontrol)
468*1da177e4SLinus Torvalds {
469*1da177e4SLinus Torvalds 	unsigned long flags;
470*1da177e4SLinus Torvalds 	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
471*1da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
472*1da177e4SLinus Torvalds 	emu10k1_pcm_mixer_t *mix = &emu->efx_pcm_mixer[ch];
473*1da177e4SLinus Torvalds 	int change = 0, idx, val;
474*1da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
475*1da177e4SLinus Torvalds 	int mask = emu->audigy ? 0x3f : 0x0f;
476*1da177e4SLinus Torvalds 
477*1da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
478*1da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
479*1da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & mask;
480*1da177e4SLinus Torvalds 		if (mix->send_routing[0][idx] != val) {
481*1da177e4SLinus Torvalds 			mix->send_routing[0][idx] = val;
482*1da177e4SLinus Torvalds 			change = 1;
483*1da177e4SLinus Torvalds 		}
484*1da177e4SLinus Torvalds 	}
485*1da177e4SLinus Torvalds 
486*1da177e4SLinus Torvalds 	if (change && mix->epcm) {
487*1da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
488*1da177e4SLinus Torvalds 			update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number,
489*1da177e4SLinus Torvalds 					&mix->send_routing[0][0]);
490*1da177e4SLinus Torvalds 		}
491*1da177e4SLinus Torvalds 	}
492*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
493*1da177e4SLinus Torvalds 	return change;
494*1da177e4SLinus Torvalds }
495*1da177e4SLinus Torvalds 
496*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_emu10k1_efx_send_routing_control =
497*1da177e4SLinus Torvalds {
498*1da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
499*1da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
500*1da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Routing",
501*1da177e4SLinus Torvalds 	.count =	16,
502*1da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_routing_info,
503*1da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_routing_get,
504*1da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_routing_put
505*1da177e4SLinus Torvalds };
506*1da177e4SLinus Torvalds 
507*1da177e4SLinus Torvalds static int snd_emu10k1_efx_send_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
508*1da177e4SLinus Torvalds {
509*1da177e4SLinus Torvalds 	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
510*1da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
511*1da177e4SLinus Torvalds 	uinfo->count = emu->audigy ? 8 : 4;
512*1da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
513*1da177e4SLinus Torvalds 	uinfo->value.integer.max = 255;
514*1da177e4SLinus Torvalds 	return 0;
515*1da177e4SLinus Torvalds }
516*1da177e4SLinus Torvalds 
517*1da177e4SLinus Torvalds static int snd_emu10k1_efx_send_volume_get(snd_kcontrol_t * kcontrol,
518*1da177e4SLinus Torvalds                                        snd_ctl_elem_value_t * ucontrol)
519*1da177e4SLinus Torvalds {
520*1da177e4SLinus Torvalds 	unsigned long flags;
521*1da177e4SLinus Torvalds 	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
522*1da177e4SLinus Torvalds 	emu10k1_pcm_mixer_t *mix = &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
523*1da177e4SLinus Torvalds 	int idx;
524*1da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
525*1da177e4SLinus Torvalds 
526*1da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
527*1da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++)
528*1da177e4SLinus Torvalds 		ucontrol->value.integer.value[idx] = mix->send_volume[0][idx];
529*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
530*1da177e4SLinus Torvalds 	return 0;
531*1da177e4SLinus Torvalds }
532*1da177e4SLinus Torvalds 
533*1da177e4SLinus Torvalds static int snd_emu10k1_efx_send_volume_put(snd_kcontrol_t * kcontrol,
534*1da177e4SLinus Torvalds                                        snd_ctl_elem_value_t * ucontrol)
535*1da177e4SLinus Torvalds {
536*1da177e4SLinus Torvalds 	unsigned long flags;
537*1da177e4SLinus Torvalds 	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
538*1da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
539*1da177e4SLinus Torvalds 	emu10k1_pcm_mixer_t *mix = &emu->efx_pcm_mixer[ch];
540*1da177e4SLinus Torvalds 	int change = 0, idx, val;
541*1da177e4SLinus Torvalds 	int num_efx = emu->audigy ? 8 : 4;
542*1da177e4SLinus Torvalds 
543*1da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
544*1da177e4SLinus Torvalds 	for (idx = 0; idx < num_efx; idx++) {
545*1da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[idx] & 255;
546*1da177e4SLinus Torvalds 		if (mix->send_volume[0][idx] != val) {
547*1da177e4SLinus Torvalds 			mix->send_volume[0][idx] = val;
548*1da177e4SLinus Torvalds 			change = 1;
549*1da177e4SLinus Torvalds 		}
550*1da177e4SLinus Torvalds 	}
551*1da177e4SLinus Torvalds 	if (change && mix->epcm) {
552*1da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
553*1da177e4SLinus Torvalds 			update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number,
554*1da177e4SLinus Torvalds 						   &mix->send_volume[0][0]);
555*1da177e4SLinus Torvalds 		}
556*1da177e4SLinus Torvalds 	}
557*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
558*1da177e4SLinus Torvalds 	return change;
559*1da177e4SLinus Torvalds }
560*1da177e4SLinus Torvalds 
561*1da177e4SLinus Torvalds 
562*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_emu10k1_efx_send_volume_control =
563*1da177e4SLinus Torvalds {
564*1da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
565*1da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
566*1da177e4SLinus Torvalds 	.name =         "Multichannel PCM Send Volume",
567*1da177e4SLinus Torvalds 	.count =	16,
568*1da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_send_volume_info,
569*1da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_send_volume_get,
570*1da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_send_volume_put
571*1da177e4SLinus Torvalds };
572*1da177e4SLinus Torvalds 
573*1da177e4SLinus Torvalds static int snd_emu10k1_efx_attn_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
574*1da177e4SLinus Torvalds {
575*1da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
576*1da177e4SLinus Torvalds 	uinfo->count = 1;
577*1da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
578*1da177e4SLinus Torvalds 	uinfo->value.integer.max = 0xffff;
579*1da177e4SLinus Torvalds 	return 0;
580*1da177e4SLinus Torvalds }
581*1da177e4SLinus Torvalds 
582*1da177e4SLinus Torvalds static int snd_emu10k1_efx_attn_get(snd_kcontrol_t * kcontrol,
583*1da177e4SLinus Torvalds                                 snd_ctl_elem_value_t * ucontrol)
584*1da177e4SLinus Torvalds {
585*1da177e4SLinus Torvalds 	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
586*1da177e4SLinus Torvalds 	emu10k1_pcm_mixer_t *mix = &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
587*1da177e4SLinus Torvalds 	unsigned long flags;
588*1da177e4SLinus Torvalds 
589*1da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
590*1da177e4SLinus Torvalds 	ucontrol->value.integer.value[0] = mix->attn[0];
591*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
592*1da177e4SLinus Torvalds 	return 0;
593*1da177e4SLinus Torvalds }
594*1da177e4SLinus Torvalds 
595*1da177e4SLinus Torvalds static int snd_emu10k1_efx_attn_put(snd_kcontrol_t * kcontrol,
596*1da177e4SLinus Torvalds 				snd_ctl_elem_value_t * ucontrol)
597*1da177e4SLinus Torvalds {
598*1da177e4SLinus Torvalds 	unsigned long flags;
599*1da177e4SLinus Torvalds 	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
600*1da177e4SLinus Torvalds 	int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
601*1da177e4SLinus Torvalds 	emu10k1_pcm_mixer_t *mix = &emu->efx_pcm_mixer[ch];
602*1da177e4SLinus Torvalds 	int change = 0, val;
603*1da177e4SLinus Torvalds 
604*1da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
605*1da177e4SLinus Torvalds 	val = ucontrol->value.integer.value[0] & 0xffff;
606*1da177e4SLinus Torvalds 	if (mix->attn[0] != val) {
607*1da177e4SLinus Torvalds 		mix->attn[0] = val;
608*1da177e4SLinus Torvalds 		change = 1;
609*1da177e4SLinus Torvalds 	}
610*1da177e4SLinus Torvalds 	if (change && mix->epcm) {
611*1da177e4SLinus Torvalds 		if (mix->epcm->voices[ch]) {
612*1da177e4SLinus Torvalds 			snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]);
613*1da177e4SLinus Torvalds 		}
614*1da177e4SLinus Torvalds 	}
615*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
616*1da177e4SLinus Torvalds 	return change;
617*1da177e4SLinus Torvalds }
618*1da177e4SLinus Torvalds 
619*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_emu10k1_efx_attn_control =
620*1da177e4SLinus Torvalds {
621*1da177e4SLinus Torvalds 	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
622*1da177e4SLinus Torvalds 	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
623*1da177e4SLinus Torvalds 	.name =         "Multichannel PCM Volume",
624*1da177e4SLinus Torvalds 	.count =	16,
625*1da177e4SLinus Torvalds 	.info =         snd_emu10k1_efx_attn_info,
626*1da177e4SLinus Torvalds 	.get =          snd_emu10k1_efx_attn_get,
627*1da177e4SLinus Torvalds 	.put =          snd_emu10k1_efx_attn_put
628*1da177e4SLinus Torvalds };
629*1da177e4SLinus Torvalds 
630*1da177e4SLinus Torvalds static int snd_emu10k1_shared_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
631*1da177e4SLinus Torvalds {
632*1da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
633*1da177e4SLinus Torvalds 	uinfo->count = 1;
634*1da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
635*1da177e4SLinus Torvalds 	uinfo->value.integer.max = 1;
636*1da177e4SLinus Torvalds 	return 0;
637*1da177e4SLinus Torvalds }
638*1da177e4SLinus Torvalds 
639*1da177e4SLinus Torvalds static int snd_emu10k1_shared_spdif_get(snd_kcontrol_t * kcontrol,
640*1da177e4SLinus Torvalds 					snd_ctl_elem_value_t * ucontrol)
641*1da177e4SLinus Torvalds {
642*1da177e4SLinus Torvalds 	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
643*1da177e4SLinus Torvalds 
644*1da177e4SLinus Torvalds 	if (emu->audigy)
645*1da177e4SLinus Torvalds 		ucontrol->value.integer.value[0] = inl(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0;
646*1da177e4SLinus Torvalds 	else
647*1da177e4SLinus Torvalds 		ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0;
648*1da177e4SLinus Torvalds 	return 0;
649*1da177e4SLinus Torvalds }
650*1da177e4SLinus Torvalds 
651*1da177e4SLinus Torvalds static int snd_emu10k1_shared_spdif_put(snd_kcontrol_t * kcontrol,
652*1da177e4SLinus Torvalds 					snd_ctl_elem_value_t * ucontrol)
653*1da177e4SLinus Torvalds {
654*1da177e4SLinus Torvalds 	unsigned long flags;
655*1da177e4SLinus Torvalds 	emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
656*1da177e4SLinus Torvalds 	unsigned int reg, val;
657*1da177e4SLinus Torvalds 	int change = 0;
658*1da177e4SLinus Torvalds 
659*1da177e4SLinus Torvalds 	spin_lock_irqsave(&emu->reg_lock, flags);
660*1da177e4SLinus Torvalds 	if (emu->audigy) {
661*1da177e4SLinus Torvalds 		reg = inl(emu->port + A_IOCFG);
662*1da177e4SLinus Torvalds 		val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0;
663*1da177e4SLinus Torvalds 		change = (reg & A_IOCFG_GPOUT0) != val;
664*1da177e4SLinus Torvalds 		if (change) {
665*1da177e4SLinus Torvalds 			reg &= ~A_IOCFG_GPOUT0;
666*1da177e4SLinus Torvalds 			reg |= val;
667*1da177e4SLinus Torvalds 			outl(reg | val, emu->port + A_IOCFG);
668*1da177e4SLinus Torvalds 		}
669*1da177e4SLinus Torvalds 	}
670*1da177e4SLinus Torvalds 	reg = inl(emu->port + HCFG);
671*1da177e4SLinus Torvalds 	val = ucontrol->value.integer.value[0] ? HCFG_GPOUT0 : 0;
672*1da177e4SLinus Torvalds 	change |= (reg & HCFG_GPOUT0) != val;
673*1da177e4SLinus Torvalds 	if (change) {
674*1da177e4SLinus Torvalds 		reg &= ~HCFG_GPOUT0;
675*1da177e4SLinus Torvalds 		reg |= val;
676*1da177e4SLinus Torvalds 		outl(reg | val, emu->port + HCFG);
677*1da177e4SLinus Torvalds 	}
678*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&emu->reg_lock, flags);
679*1da177e4SLinus Torvalds 	return change;
680*1da177e4SLinus Torvalds }
681*1da177e4SLinus Torvalds 
682*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_emu10k1_shared_spdif __devinitdata =
683*1da177e4SLinus Torvalds {
684*1da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
685*1da177e4SLinus Torvalds 	.name =		"SB Live Analog/Digital Output Jack",
686*1da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
687*1da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
688*1da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
689*1da177e4SLinus Torvalds };
690*1da177e4SLinus Torvalds 
691*1da177e4SLinus Torvalds static snd_kcontrol_new_t snd_audigy_shared_spdif __devinitdata =
692*1da177e4SLinus Torvalds {
693*1da177e4SLinus Torvalds 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
694*1da177e4SLinus Torvalds 	.name =		"Audigy Analog/Digital Output Jack",
695*1da177e4SLinus Torvalds 	.info =		snd_emu10k1_shared_spdif_info,
696*1da177e4SLinus Torvalds 	.get =		snd_emu10k1_shared_spdif_get,
697*1da177e4SLinus Torvalds 	.put =		snd_emu10k1_shared_spdif_put
698*1da177e4SLinus Torvalds };
699*1da177e4SLinus Torvalds 
700*1da177e4SLinus Torvalds /*
701*1da177e4SLinus Torvalds  */
702*1da177e4SLinus Torvalds static void snd_emu10k1_mixer_free_ac97(ac97_t *ac97)
703*1da177e4SLinus Torvalds {
704*1da177e4SLinus Torvalds 	emu10k1_t *emu = ac97->private_data;
705*1da177e4SLinus Torvalds 	emu->ac97 = NULL;
706*1da177e4SLinus Torvalds }
707*1da177e4SLinus Torvalds 
708*1da177e4SLinus Torvalds /*
709*1da177e4SLinus Torvalds  */
710*1da177e4SLinus Torvalds static int remove_ctl(snd_card_t *card, const char *name)
711*1da177e4SLinus Torvalds {
712*1da177e4SLinus Torvalds 	snd_ctl_elem_id_t id;
713*1da177e4SLinus Torvalds 	memset(&id, 0, sizeof(id));
714*1da177e4SLinus Torvalds 	strcpy(id.name, name);
715*1da177e4SLinus Torvalds 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
716*1da177e4SLinus Torvalds 	return snd_ctl_remove_id(card, &id);
717*1da177e4SLinus Torvalds }
718*1da177e4SLinus Torvalds 
719*1da177e4SLinus Torvalds static snd_kcontrol_t *ctl_find(snd_card_t *card, const char *name)
720*1da177e4SLinus Torvalds {
721*1da177e4SLinus Torvalds 	snd_ctl_elem_id_t sid;
722*1da177e4SLinus Torvalds 	memset(&sid, 0, sizeof(sid));
723*1da177e4SLinus Torvalds 	strcpy(sid.name, name);
724*1da177e4SLinus Torvalds 	sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
725*1da177e4SLinus Torvalds 	return snd_ctl_find_id(card, &sid);
726*1da177e4SLinus Torvalds }
727*1da177e4SLinus Torvalds 
728*1da177e4SLinus Torvalds static int rename_ctl(snd_card_t *card, const char *src, const char *dst)
729*1da177e4SLinus Torvalds {
730*1da177e4SLinus Torvalds 	snd_kcontrol_t *kctl = ctl_find(card, src);
731*1da177e4SLinus Torvalds 	if (kctl) {
732*1da177e4SLinus Torvalds 		strcpy(kctl->id.name, dst);
733*1da177e4SLinus Torvalds 		return 0;
734*1da177e4SLinus Torvalds 	}
735*1da177e4SLinus Torvalds 	return -ENOENT;
736*1da177e4SLinus Torvalds }
737*1da177e4SLinus Torvalds 
738*1da177e4SLinus Torvalds int __devinit snd_emu10k1_mixer(emu10k1_t *emu)
739*1da177e4SLinus Torvalds {
740*1da177e4SLinus Torvalds 	int err, pcm;
741*1da177e4SLinus Torvalds 	snd_kcontrol_t *kctl;
742*1da177e4SLinus Torvalds 	snd_card_t *card = emu->card;
743*1da177e4SLinus Torvalds 	char **c;
744*1da177e4SLinus Torvalds 	static char *emu10k1_remove_ctls[] = {
745*1da177e4SLinus Torvalds 		/* no AC97 mono, surround, center/lfe */
746*1da177e4SLinus Torvalds 		"Master Mono Playback Switch",
747*1da177e4SLinus Torvalds 		"Master Mono Playback Volume",
748*1da177e4SLinus Torvalds 		"PCM Out Path & Mute",
749*1da177e4SLinus Torvalds 		"Mono Output Select",
750*1da177e4SLinus Torvalds 		"Surround Playback Switch",
751*1da177e4SLinus Torvalds 		"Surround Playback Volume",
752*1da177e4SLinus Torvalds 		"Center Playback Switch",
753*1da177e4SLinus Torvalds 		"Center Playback Volume",
754*1da177e4SLinus Torvalds 		"LFE Playback Switch",
755*1da177e4SLinus Torvalds 		"LFE Playback Volume",
756*1da177e4SLinus Torvalds 		NULL
757*1da177e4SLinus Torvalds 	};
758*1da177e4SLinus Torvalds 	static char *emu10k1_rename_ctls[] = {
759*1da177e4SLinus Torvalds 		"Surround Digital Playback Volume", "Surround Playback Volume",
760*1da177e4SLinus Torvalds 		"Center Digital Playback Volume", "Center Playback Volume",
761*1da177e4SLinus Torvalds 		"LFE Digital Playback Volume", "LFE Playback Volume",
762*1da177e4SLinus Torvalds 		NULL
763*1da177e4SLinus Torvalds 	};
764*1da177e4SLinus Torvalds 	static char *audigy_remove_ctls[] = {
765*1da177e4SLinus Torvalds 		/* Master/PCM controls on ac97 of Audigy has no effect */
766*1da177e4SLinus Torvalds 		"PCM Playback Switch",
767*1da177e4SLinus Torvalds 		"PCM Playback Volume",
768*1da177e4SLinus Torvalds 		"Master Mono Playback Switch",
769*1da177e4SLinus Torvalds 		"Master Mono Playback Volume",
770*1da177e4SLinus Torvalds 		"Master Playback Switch",
771*1da177e4SLinus Torvalds 		"Master Playback Volume",
772*1da177e4SLinus Torvalds 		"PCM Out Path & Mute",
773*1da177e4SLinus Torvalds 		"Mono Output Select",
774*1da177e4SLinus Torvalds 		/* remove unused AC97 capture controls */
775*1da177e4SLinus Torvalds 		"Capture Source",
776*1da177e4SLinus Torvalds 		"Capture Switch",
777*1da177e4SLinus Torvalds 		"Capture Volume",
778*1da177e4SLinus Torvalds 		"Mic Select",
779*1da177e4SLinus Torvalds 		"Video Playback Switch",
780*1da177e4SLinus Torvalds 		"Video Playback Volume",
781*1da177e4SLinus Torvalds 		"Mic Playback Switch",
782*1da177e4SLinus Torvalds 		"Mic Playback Volume",
783*1da177e4SLinus Torvalds 		NULL
784*1da177e4SLinus Torvalds 	};
785*1da177e4SLinus Torvalds 	static char *audigy_rename_ctls[] = {
786*1da177e4SLinus Torvalds 		/* use conventional names */
787*1da177e4SLinus Torvalds 		"Wave Playback Volume", "PCM Playback Volume",
788*1da177e4SLinus Torvalds 		/* "Wave Capture Volume", "PCM Capture Volume", */
789*1da177e4SLinus Torvalds 		"Wave Master Playback Volume", "Master Playback Volume",
790*1da177e4SLinus Torvalds 		"AMic Playback Volume", "Mic Playback Volume",
791*1da177e4SLinus Torvalds 		NULL
792*1da177e4SLinus Torvalds 	};
793*1da177e4SLinus Torvalds 
794*1da177e4SLinus Torvalds 	if (!emu->no_ac97) {
795*1da177e4SLinus Torvalds 		ac97_bus_t *pbus;
796*1da177e4SLinus Torvalds 		ac97_template_t ac97;
797*1da177e4SLinus Torvalds 		static ac97_bus_ops_t ops = {
798*1da177e4SLinus Torvalds 			.write = snd_emu10k1_ac97_write,
799*1da177e4SLinus Torvalds 			.read = snd_emu10k1_ac97_read,
800*1da177e4SLinus Torvalds 		};
801*1da177e4SLinus Torvalds 
802*1da177e4SLinus Torvalds 		if ((err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus)) < 0)
803*1da177e4SLinus Torvalds 			return err;
804*1da177e4SLinus Torvalds 		pbus->no_vra = 1; /* we don't need VRA */
805*1da177e4SLinus Torvalds 
806*1da177e4SLinus Torvalds 		memset(&ac97, 0, sizeof(ac97));
807*1da177e4SLinus Torvalds 		ac97.private_data = emu;
808*1da177e4SLinus Torvalds 		ac97.private_free = snd_emu10k1_mixer_free_ac97;
809*1da177e4SLinus Torvalds 		ac97.scaps = AC97_SCAP_NO_SPDIF;
810*1da177e4SLinus Torvalds 		if ((err = snd_ac97_mixer(pbus, &ac97, &emu->ac97)) < 0)
811*1da177e4SLinus Torvalds 			return err;
812*1da177e4SLinus Torvalds 		if (emu->audigy) {
813*1da177e4SLinus Torvalds 			/* set master volume to 0 dB */
814*1da177e4SLinus Torvalds 			snd_ac97_write(emu->ac97, AC97_MASTER, 0x0000);
815*1da177e4SLinus Torvalds 			/* set capture source to mic */
816*1da177e4SLinus Torvalds 			snd_ac97_write(emu->ac97, AC97_REC_SEL, 0x0000);
817*1da177e4SLinus Torvalds 			c = audigy_remove_ctls;
818*1da177e4SLinus Torvalds 		} else {
819*1da177e4SLinus Torvalds 			/*
820*1da177e4SLinus Torvalds 			 * Credits for cards based on STAC9758:
821*1da177e4SLinus Torvalds 			 *   James Courtier-Dutton <James@superbug.demon.co.uk>
822*1da177e4SLinus Torvalds 			 *   Voluspa <voluspa@comhem.se>
823*1da177e4SLinus Torvalds 			 */
824*1da177e4SLinus Torvalds 			if (emu->ac97->id == AC97_ID_STAC9758) {
825*1da177e4SLinus Torvalds 				emu->rear_ac97 = 1;
826*1da177e4SLinus Torvalds 				snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT);
827*1da177e4SLinus Torvalds 			}
828*1da177e4SLinus Torvalds 			/* remove unused AC97 controls */
829*1da177e4SLinus Torvalds 			snd_ac97_write(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
830*1da177e4SLinus Torvalds 			snd_ac97_write(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202);
831*1da177e4SLinus Torvalds 			c = emu10k1_remove_ctls;
832*1da177e4SLinus Torvalds 		}
833*1da177e4SLinus Torvalds 		for (; *c; c++)
834*1da177e4SLinus Torvalds 			remove_ctl(card, *c);
835*1da177e4SLinus Torvalds 	} else {
836*1da177e4SLinus Torvalds 		if (emu->APS)
837*1da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "EMU APS");
838*1da177e4SLinus Torvalds 		else if (emu->audigy)
839*1da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "SB Audigy");
840*1da177e4SLinus Torvalds 		else
841*1da177e4SLinus Torvalds 			strcpy(emu->card->mixername, "Emu10k1");
842*1da177e4SLinus Torvalds 	}
843*1da177e4SLinus Torvalds 
844*1da177e4SLinus Torvalds 	if (emu->audigy)
845*1da177e4SLinus Torvalds 		c = audigy_rename_ctls;
846*1da177e4SLinus Torvalds 	else
847*1da177e4SLinus Torvalds 		c = emu10k1_rename_ctls;
848*1da177e4SLinus Torvalds 	for (; *c; c += 2)
849*1da177e4SLinus Torvalds 		rename_ctl(card, c[0], c[1]);
850*1da177e4SLinus Torvalds 
851*1da177e4SLinus Torvalds 	if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL)
852*1da177e4SLinus Torvalds 		return -ENOMEM;
853*1da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
854*1da177e4SLinus Torvalds 		return err;
855*1da177e4SLinus Torvalds 	if ((kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu)) == NULL)
856*1da177e4SLinus Torvalds 		return -ENOMEM;
857*1da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
858*1da177e4SLinus Torvalds 		return err;
859*1da177e4SLinus Torvalds 	if ((kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu)) == NULL)
860*1da177e4SLinus Torvalds 		return -ENOMEM;
861*1da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
862*1da177e4SLinus Torvalds 		return err;
863*1da177e4SLinus Torvalds 
864*1da177e4SLinus Torvalds 	if ((kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu)) == NULL)
865*1da177e4SLinus Torvalds 		return -ENOMEM;
866*1da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
867*1da177e4SLinus Torvalds 		return err;
868*1da177e4SLinus Torvalds 
869*1da177e4SLinus Torvalds 	if ((kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu)) == NULL)
870*1da177e4SLinus Torvalds 		return -ENOMEM;
871*1da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
872*1da177e4SLinus Torvalds 		return err;
873*1da177e4SLinus Torvalds 
874*1da177e4SLinus Torvalds 	if ((kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu)) == NULL)
875*1da177e4SLinus Torvalds 		return -ENOMEM;
876*1da177e4SLinus Torvalds 	if ((err = snd_ctl_add(card, kctl)))
877*1da177e4SLinus Torvalds 		return err;
878*1da177e4SLinus Torvalds 
879*1da177e4SLinus Torvalds 	/* initialize the routing and volume table for each pcm playback stream */
880*1da177e4SLinus Torvalds 	for (pcm = 0; pcm < 32; pcm++) {
881*1da177e4SLinus Torvalds 		emu10k1_pcm_mixer_t *mix;
882*1da177e4SLinus Torvalds 		int v;
883*1da177e4SLinus Torvalds 
884*1da177e4SLinus Torvalds 		mix = &emu->pcm_mixer[pcm];
885*1da177e4SLinus Torvalds 		mix->epcm = NULL;
886*1da177e4SLinus Torvalds 
887*1da177e4SLinus Torvalds 		for (v = 0; v < 4; v++)
888*1da177e4SLinus Torvalds 			mix->send_routing[0][v] =
889*1da177e4SLinus Torvalds 				mix->send_routing[1][v] =
890*1da177e4SLinus Torvalds 				mix->send_routing[2][v] = v;
891*1da177e4SLinus Torvalds 
892*1da177e4SLinus Torvalds 		memset(&mix->send_volume, 0, sizeof(mix->send_volume));
893*1da177e4SLinus Torvalds 		mix->send_volume[0][0] = mix->send_volume[0][1] =
894*1da177e4SLinus Torvalds 		mix->send_volume[1][0] = mix->send_volume[2][1] = 255;
895*1da177e4SLinus Torvalds 
896*1da177e4SLinus Torvalds 		mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff;
897*1da177e4SLinus Torvalds 	}
898*1da177e4SLinus Torvalds 
899*1da177e4SLinus Torvalds 	/* initialize the routing and volume table for the multichannel playback stream */
900*1da177e4SLinus Torvalds 	for (pcm = 0; pcm < NUM_EFX_PLAYBACK; pcm++) {
901*1da177e4SLinus Torvalds 		emu10k1_pcm_mixer_t *mix;
902*1da177e4SLinus Torvalds 		int v;
903*1da177e4SLinus Torvalds 
904*1da177e4SLinus Torvalds 		mix = &emu->efx_pcm_mixer[pcm];
905*1da177e4SLinus Torvalds 		mix->epcm = NULL;
906*1da177e4SLinus Torvalds 
907*1da177e4SLinus Torvalds 		mix->send_routing[0][0] = pcm;
908*1da177e4SLinus Torvalds 		mix->send_routing[0][1] = (pcm == 0) ? 1 : 0;
909*1da177e4SLinus Torvalds 		for (v = 0; v < 2; v++)
910*1da177e4SLinus Torvalds 			mix->send_routing[0][2+v] = 13+v;
911*1da177e4SLinus Torvalds 		if (emu->audigy)
912*1da177e4SLinus Torvalds 			for (v = 0; v < 4; v++)
913*1da177e4SLinus Torvalds 				mix->send_routing[0][4+v] = 60+v;
914*1da177e4SLinus Torvalds 
915*1da177e4SLinus Torvalds 		memset(&mix->send_volume, 0, sizeof(mix->send_volume));
916*1da177e4SLinus Torvalds 		mix->send_volume[0][0]  = 255;
917*1da177e4SLinus Torvalds 
918*1da177e4SLinus Torvalds 		mix->attn[0] = 0xffff;
919*1da177e4SLinus Torvalds 	}
920*1da177e4SLinus Torvalds 
921*1da177e4SLinus Torvalds 	if (! emu->APS) { /* FIXME: APS has these controls? */
922*1da177e4SLinus Torvalds 		/* sb live! and audigy */
923*1da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL)
924*1da177e4SLinus Torvalds 			return -ENOMEM;
925*1da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
926*1da177e4SLinus Torvalds 			return err;
927*1da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL)
928*1da177e4SLinus Torvalds 			return -ENOMEM;
929*1da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
930*1da177e4SLinus Torvalds 			return err;
931*1da177e4SLinus Torvalds 	}
932*1da177e4SLinus Torvalds 
933*1da177e4SLinus Torvalds 	if (emu->audigy) {
934*1da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL)
935*1da177e4SLinus Torvalds 			return -ENOMEM;
936*1da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
937*1da177e4SLinus Torvalds 			return err;
938*1da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu)) == NULL)
939*1da177e4SLinus Torvalds 			return -ENOMEM;
940*1da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
941*1da177e4SLinus Torvalds 			return err;
942*1da177e4SLinus Torvalds 	} else if (! emu->APS) {
943*1da177e4SLinus Torvalds 		/* sb live! */
944*1da177e4SLinus Torvalds 		if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL)
945*1da177e4SLinus Torvalds 			return -ENOMEM;
946*1da177e4SLinus Torvalds 		if ((err = snd_ctl_add(card, kctl)))
947*1da177e4SLinus Torvalds 			return err;
948*1da177e4SLinus Torvalds 	}
949*1da177e4SLinus Torvalds 	if (emu->audigy && emu->revision == 4) { /* P16V */
950*1da177e4SLinus Torvalds 		if ((err = snd_p16v_mixer(emu)))
951*1da177e4SLinus Torvalds 			return err;
952*1da177e4SLinus Torvalds 	}
953*1da177e4SLinus Torvalds 
954*1da177e4SLinus Torvalds 	return 0;
955*1da177e4SLinus Torvalds }
956