blob: c31f3d0877fa42f5d041a73243d6b6a4b1a669fd [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>,
3 * Takashi Iwai <tiwai@suse.de>
4 * Creative Labs, Inc.
5 * Routines for control of EMU10K1 chips / mixer routines
6 * Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com>
7 *
8 * BUGS:
9 * --
10 *
11 * TODO:
12 * --
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 *
28 */
29
30#include <sound/driver.h>
31#include <linux/time.h>
32#include <linux/init.h>
33#include <sound/core.h>
34#include <sound/emu10k1.h>
35
36#define AC97_ID_STAC9758 0x83847658
37
Takashi Iwaieb4698f2005-11-17 14:50:13 +010038static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -070039{
40 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
41 uinfo->count = 1;
42 return 0;
43}
44
Takashi Iwaieb4698f2005-11-17 14:50:13 +010045static int snd_emu10k1_spdif_get(struct snd_kcontrol *kcontrol,
46 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -070047{
Takashi Iwaieb4698f2005-11-17 14:50:13 +010048 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -070049 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
50 unsigned long flags;
51
52 spin_lock_irqsave(&emu->reg_lock, flags);
53 ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff;
54 ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff;
55 ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff;
56 ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff;
57 spin_unlock_irqrestore(&emu->reg_lock, flags);
58 return 0;
59}
60
Takashi Iwaieb4698f2005-11-17 14:50:13 +010061static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol,
62 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -070063{
64 ucontrol->value.iec958.status[0] = 0xff;
65 ucontrol->value.iec958.status[1] = 0xff;
66 ucontrol->value.iec958.status[2] = 0xff;
67 ucontrol->value.iec958.status[3] = 0xff;
68 return 0;
69}
70
Takashi Iwai0af68e52005-04-11 17:03:03 +020071#if 0
Takashi Iwaieb4698f2005-11-17 14:50:13 +010072static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -070073{
74 static char *texts[] = {"44100", "48000", "96000"};
75
76 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
77 uinfo->count = 1;
78 uinfo->value.enumerated.items = 3;
79 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
80 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
81 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
82 return 0;
83}
84
Takashi Iwaieb4698f2005-11-17 14:50:13 +010085static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol,
86 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -070087{
Takashi Iwaieb4698f2005-11-17 14:50:13 +010088 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 unsigned int tmp;
90 unsigned long flags;
91
92
93 spin_lock_irqsave(&emu->reg_lock, flags);
94 tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
95 switch (tmp & A_SPDIF_RATE_MASK) {
96 case A_SPDIF_44100:
97 ucontrol->value.enumerated.item[0] = 0;
98 break;
99 case A_SPDIF_48000:
100 ucontrol->value.enumerated.item[0] = 1;
101 break;
102 case A_SPDIF_96000:
103 ucontrol->value.enumerated.item[0] = 2;
104 break;
105 default:
106 ucontrol->value.enumerated.item[0] = 1;
107 }
108 spin_unlock_irqrestore(&emu->reg_lock, flags);
109 return 0;
110}
111
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100112static int snd_audigy_spdif_output_rate_put(struct snd_kcontrol *kcontrol,
113 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100115 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 int change;
117 unsigned int reg, val, tmp;
118 unsigned long flags;
119
120 switch(ucontrol->value.enumerated.item[0]) {
121 case 0:
122 val = A_SPDIF_44100;
123 break;
124 case 1:
125 val = A_SPDIF_48000;
126 break;
127 case 2:
128 val = A_SPDIF_96000;
129 break;
130 default:
131 val = A_SPDIF_48000;
132 break;
133 }
134
135
136 spin_lock_irqsave(&emu->reg_lock, flags);
137 reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0);
138 tmp = reg & ~A_SPDIF_RATE_MASK;
139 tmp |= val;
140 if ((change = (tmp != reg)))
141 snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp);
142 spin_unlock_irqrestore(&emu->reg_lock, flags);
143 return change;
144}
145
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100146static struct snd_kcontrol_new snd_audigy_spdif_output_rate =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147{
148 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
149 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
150 .name = "Audigy SPDIF Output Sample Rate",
151 .count = 1,
152 .info = snd_audigy_spdif_output_rate_info,
153 .get = snd_audigy_spdif_output_rate_get,
154 .put = snd_audigy_spdif_output_rate_put
155};
Takashi Iwai0af68e52005-04-11 17:03:03 +0200156#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100158static int snd_emu10k1_spdif_put(struct snd_kcontrol *kcontrol,
159 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100161 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
163 int change;
164 unsigned int val;
165 unsigned long flags;
166
167 val = (ucontrol->value.iec958.status[0] << 0) |
168 (ucontrol->value.iec958.status[1] << 8) |
169 (ucontrol->value.iec958.status[2] << 16) |
170 (ucontrol->value.iec958.status[3] << 24);
171 spin_lock_irqsave(&emu->reg_lock, flags);
172 change = val != emu->spdif_bits[idx];
173 if (change) {
174 snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val);
175 emu->spdif_bits[idx] = val;
176 }
177 spin_unlock_irqrestore(&emu->reg_lock, flags);
178 return change;
179}
180
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100181static struct snd_kcontrol_new snd_emu10k1_spdif_mask_control =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182{
183 .access = SNDRV_CTL_ELEM_ACCESS_READ,
Clemens Ladisch5549d542005-08-03 13:50:30 +0200184 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
186 .count = 4,
187 .info = snd_emu10k1_spdif_info,
188 .get = snd_emu10k1_spdif_get_mask
189};
190
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100191static struct snd_kcontrol_new snd_emu10k1_spdif_control =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192{
Clemens Ladisch5549d542005-08-03 13:50:30 +0200193 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
195 .count = 4,
196 .info = snd_emu10k1_spdif_info,
197 .get = snd_emu10k1_spdif_get,
198 .put = snd_emu10k1_spdif_put
199};
200
201
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100202static void update_emu10k1_fxrt(struct snd_emu10k1 *emu, int voice, unsigned char *route)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203{
204 if (emu->audigy) {
205 snd_emu10k1_ptr_write(emu, A_FXRT1, voice,
206 snd_emu10k1_compose_audigy_fxrt1(route));
207 snd_emu10k1_ptr_write(emu, A_FXRT2, voice,
208 snd_emu10k1_compose_audigy_fxrt2(route));
209 } else {
210 snd_emu10k1_ptr_write(emu, FXRT, voice,
211 snd_emu10k1_compose_send_routing(route));
212 }
213}
214
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100215static void update_emu10k1_send_volume(struct snd_emu10k1 *emu, int voice, unsigned char *volume)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216{
217 snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]);
218 snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]);
219 snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]);
220 snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]);
221 if (emu->audigy) {
222 unsigned int val = ((unsigned int)volume[4] << 24) |
223 ((unsigned int)volume[5] << 16) |
224 ((unsigned int)volume[6] << 8) |
225 (unsigned int)volume[7];
226 snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, val);
227 }
228}
229
230/* PCM stream controls */
231
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100232static int snd_emu10k1_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100234 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
236 uinfo->count = emu->audigy ? 3*8 : 3*4;
237 uinfo->value.integer.min = 0;
238 uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
239 return 0;
240}
241
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100242static int snd_emu10k1_send_routing_get(struct snd_kcontrol *kcontrol,
243 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244{
245 unsigned long flags;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100246 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
247 struct snd_emu10k1_pcm_mixer *mix =
248 &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 int voice, idx;
250 int num_efx = emu->audigy ? 8 : 4;
251 int mask = emu->audigy ? 0x3f : 0x0f;
252
253 spin_lock_irqsave(&emu->reg_lock, flags);
254 for (voice = 0; voice < 3; voice++)
255 for (idx = 0; idx < num_efx; idx++)
256 ucontrol->value.integer.value[(voice * num_efx) + idx] =
257 mix->send_routing[voice][idx] & mask;
258 spin_unlock_irqrestore(&emu->reg_lock, flags);
259 return 0;
260}
261
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100262static int snd_emu10k1_send_routing_put(struct snd_kcontrol *kcontrol,
263 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264{
265 unsigned long flags;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100266 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
267 struct snd_emu10k1_pcm_mixer *mix =
268 &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 int change = 0, voice, idx, val;
270 int num_efx = emu->audigy ? 8 : 4;
271 int mask = emu->audigy ? 0x3f : 0x0f;
272
273 spin_lock_irqsave(&emu->reg_lock, flags);
274 for (voice = 0; voice < 3; voice++)
275 for (idx = 0; idx < num_efx; idx++) {
276 val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask;
277 if (mix->send_routing[voice][idx] != val) {
278 mix->send_routing[voice][idx] = val;
279 change = 1;
280 }
281 }
282 if (change && mix->epcm) {
283 if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
284 update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
285 &mix->send_routing[1][0]);
286 update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number,
287 &mix->send_routing[2][0]);
288 } else if (mix->epcm->voices[0]) {
289 update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
290 &mix->send_routing[0][0]);
291 }
292 }
293 spin_unlock_irqrestore(&emu->reg_lock, flags);
294 return change;
295}
296
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100297static struct snd_kcontrol_new snd_emu10k1_send_routing_control =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298{
299 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
Clemens Ladisch67ed4162005-07-29 15:32:58 +0200300 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 .name = "EMU10K1 PCM Send Routing",
302 .count = 32,
303 .info = snd_emu10k1_send_routing_info,
304 .get = snd_emu10k1_send_routing_get,
305 .put = snd_emu10k1_send_routing_put
306};
307
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100308static int snd_emu10k1_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100310 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
312 uinfo->count = emu->audigy ? 3*8 : 3*4;
313 uinfo->value.integer.min = 0;
314 uinfo->value.integer.max = 255;
315 return 0;
316}
317
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100318static int snd_emu10k1_send_volume_get(struct snd_kcontrol *kcontrol,
319 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320{
321 unsigned long flags;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100322 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
323 struct snd_emu10k1_pcm_mixer *mix =
324 &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 int idx;
326 int num_efx = emu->audigy ? 8 : 4;
327
328 spin_lock_irqsave(&emu->reg_lock, flags);
329 for (idx = 0; idx < 3*num_efx; idx++)
330 ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx];
331 spin_unlock_irqrestore(&emu->reg_lock, flags);
332 return 0;
333}
334
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100335static int snd_emu10k1_send_volume_put(struct snd_kcontrol *kcontrol,
336 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337{
338 unsigned long flags;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100339 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
340 struct snd_emu10k1_pcm_mixer *mix =
341 &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 int change = 0, idx, val;
343 int num_efx = emu->audigy ? 8 : 4;
344
345 spin_lock_irqsave(&emu->reg_lock, flags);
346 for (idx = 0; idx < 3*num_efx; idx++) {
347 val = ucontrol->value.integer.value[idx] & 255;
348 if (mix->send_volume[idx/num_efx][idx%num_efx] != val) {
349 mix->send_volume[idx/num_efx][idx%num_efx] = val;
350 change = 1;
351 }
352 }
353 if (change && mix->epcm) {
354 if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
355 update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
356 &mix->send_volume[1][0]);
357 update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number,
358 &mix->send_volume[2][0]);
359 } else if (mix->epcm->voices[0]) {
360 update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
361 &mix->send_volume[0][0]);
362 }
363 }
364 spin_unlock_irqrestore(&emu->reg_lock, flags);
365 return change;
366}
367
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100368static struct snd_kcontrol_new snd_emu10k1_send_volume_control =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369{
370 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
Clemens Ladisch67ed4162005-07-29 15:32:58 +0200371 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 .name = "EMU10K1 PCM Send Volume",
373 .count = 32,
374 .info = snd_emu10k1_send_volume_info,
375 .get = snd_emu10k1_send_volume_get,
376 .put = snd_emu10k1_send_volume_put
377};
378
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100379static int snd_emu10k1_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380{
381 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
382 uinfo->count = 3;
383 uinfo->value.integer.min = 0;
384 uinfo->value.integer.max = 0xffff;
385 return 0;
386}
387
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100388static int snd_emu10k1_attn_get(struct snd_kcontrol *kcontrol,
389 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100391 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
392 struct snd_emu10k1_pcm_mixer *mix =
393 &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 unsigned long flags;
395 int idx;
396
397 spin_lock_irqsave(&emu->reg_lock, flags);
398 for (idx = 0; idx < 3; idx++)
399 ucontrol->value.integer.value[idx] = mix->attn[idx];
400 spin_unlock_irqrestore(&emu->reg_lock, flags);
401 return 0;
402}
403
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100404static int snd_emu10k1_attn_put(struct snd_kcontrol *kcontrol,
405 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406{
407 unsigned long flags;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100408 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
409 struct snd_emu10k1_pcm_mixer *mix =
410 &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 int change = 0, idx, val;
412
413 spin_lock_irqsave(&emu->reg_lock, flags);
414 for (idx = 0; idx < 3; idx++) {
415 val = ucontrol->value.integer.value[idx] & 0xffff;
416 if (mix->attn[idx] != val) {
417 mix->attn[idx] = val;
418 change = 1;
419 }
420 }
421 if (change && mix->epcm) {
422 if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
423 snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]);
424 snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]);
425 } else if (mix->epcm->voices[0]) {
426 snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]);
427 }
428 }
429 spin_unlock_irqrestore(&emu->reg_lock, flags);
430 return change;
431}
432
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100433static struct snd_kcontrol_new snd_emu10k1_attn_control =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434{
435 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
Clemens Ladisch67ed4162005-07-29 15:32:58 +0200436 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 .name = "EMU10K1 PCM Volume",
438 .count = 32,
439 .info = snd_emu10k1_attn_info,
440 .get = snd_emu10k1_attn_get,
441 .put = snd_emu10k1_attn_put
442};
443
444/* Mutichannel PCM stream controls */
445
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100446static int snd_emu10k1_efx_send_routing_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100448 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
450 uinfo->count = emu->audigy ? 8 : 4;
451 uinfo->value.integer.min = 0;
452 uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
453 return 0;
454}
455
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100456static int snd_emu10k1_efx_send_routing_get(struct snd_kcontrol *kcontrol,
457 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458{
459 unsigned long flags;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100460 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
461 struct snd_emu10k1_pcm_mixer *mix =
462 &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 int idx;
464 int num_efx = emu->audigy ? 8 : 4;
465 int mask = emu->audigy ? 0x3f : 0x0f;
466
467 spin_lock_irqsave(&emu->reg_lock, flags);
468 for (idx = 0; idx < num_efx; idx++)
469 ucontrol->value.integer.value[idx] =
470 mix->send_routing[0][idx] & mask;
471 spin_unlock_irqrestore(&emu->reg_lock, flags);
472 return 0;
473}
474
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100475static int snd_emu10k1_efx_send_routing_put(struct snd_kcontrol *kcontrol,
476 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477{
478 unsigned long flags;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100479 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100481 struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 int change = 0, idx, val;
483 int num_efx = emu->audigy ? 8 : 4;
484 int mask = emu->audigy ? 0x3f : 0x0f;
485
486 spin_lock_irqsave(&emu->reg_lock, flags);
487 for (idx = 0; idx < num_efx; idx++) {
488 val = ucontrol->value.integer.value[idx] & mask;
489 if (mix->send_routing[0][idx] != val) {
490 mix->send_routing[0][idx] = val;
491 change = 1;
492 }
493 }
494
495 if (change && mix->epcm) {
496 if (mix->epcm->voices[ch]) {
497 update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number,
498 &mix->send_routing[0][0]);
499 }
500 }
501 spin_unlock_irqrestore(&emu->reg_lock, flags);
502 return change;
503}
504
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100505static struct snd_kcontrol_new snd_emu10k1_efx_send_routing_control =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506{
507 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
508 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
509 .name = "Multichannel PCM Send Routing",
510 .count = 16,
511 .info = snd_emu10k1_efx_send_routing_info,
512 .get = snd_emu10k1_efx_send_routing_get,
513 .put = snd_emu10k1_efx_send_routing_put
514};
515
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100516static int snd_emu10k1_efx_send_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100518 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
520 uinfo->count = emu->audigy ? 8 : 4;
521 uinfo->value.integer.min = 0;
522 uinfo->value.integer.max = 255;
523 return 0;
524}
525
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100526static int snd_emu10k1_efx_send_volume_get(struct snd_kcontrol *kcontrol,
527 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528{
529 unsigned long flags;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100530 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
531 struct snd_emu10k1_pcm_mixer *mix =
532 &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 int idx;
534 int num_efx = emu->audigy ? 8 : 4;
535
536 spin_lock_irqsave(&emu->reg_lock, flags);
537 for (idx = 0; idx < num_efx; idx++)
538 ucontrol->value.integer.value[idx] = mix->send_volume[0][idx];
539 spin_unlock_irqrestore(&emu->reg_lock, flags);
540 return 0;
541}
542
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100543static int snd_emu10k1_efx_send_volume_put(struct snd_kcontrol *kcontrol,
544 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545{
546 unsigned long flags;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100547 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100549 struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 int change = 0, idx, val;
551 int num_efx = emu->audigy ? 8 : 4;
552
553 spin_lock_irqsave(&emu->reg_lock, flags);
554 for (idx = 0; idx < num_efx; idx++) {
555 val = ucontrol->value.integer.value[idx] & 255;
556 if (mix->send_volume[0][idx] != val) {
557 mix->send_volume[0][idx] = val;
558 change = 1;
559 }
560 }
561 if (change && mix->epcm) {
562 if (mix->epcm->voices[ch]) {
563 update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number,
564 &mix->send_volume[0][0]);
565 }
566 }
567 spin_unlock_irqrestore(&emu->reg_lock, flags);
568 return change;
569}
570
571
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100572static struct snd_kcontrol_new snd_emu10k1_efx_send_volume_control =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573{
574 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
575 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
576 .name = "Multichannel PCM Send Volume",
577 .count = 16,
578 .info = snd_emu10k1_efx_send_volume_info,
579 .get = snd_emu10k1_efx_send_volume_get,
580 .put = snd_emu10k1_efx_send_volume_put
581};
582
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100583static int snd_emu10k1_efx_attn_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584{
585 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
586 uinfo->count = 1;
587 uinfo->value.integer.min = 0;
588 uinfo->value.integer.max = 0xffff;
589 return 0;
590}
591
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100592static int snd_emu10k1_efx_attn_get(struct snd_kcontrol *kcontrol,
593 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100595 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
596 struct snd_emu10k1_pcm_mixer *mix =
597 &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 unsigned long flags;
599
600 spin_lock_irqsave(&emu->reg_lock, flags);
601 ucontrol->value.integer.value[0] = mix->attn[0];
602 spin_unlock_irqrestore(&emu->reg_lock, flags);
603 return 0;
604}
605
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100606static int snd_emu10k1_efx_attn_put(struct snd_kcontrol *kcontrol,
607 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608{
609 unsigned long flags;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100610 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100612 struct snd_emu10k1_pcm_mixer *mix = &emu->efx_pcm_mixer[ch];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 int change = 0, val;
614
615 spin_lock_irqsave(&emu->reg_lock, flags);
616 val = ucontrol->value.integer.value[0] & 0xffff;
617 if (mix->attn[0] != val) {
618 mix->attn[0] = val;
619 change = 1;
620 }
621 if (change && mix->epcm) {
622 if (mix->epcm->voices[ch]) {
623 snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]);
624 }
625 }
626 spin_unlock_irqrestore(&emu->reg_lock, flags);
627 return change;
628}
629
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100630static struct snd_kcontrol_new snd_emu10k1_efx_attn_control =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631{
632 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
633 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
634 .name = "Multichannel PCM Volume",
635 .count = 16,
636 .info = snd_emu10k1_efx_attn_info,
637 .get = snd_emu10k1_efx_attn_get,
638 .put = snd_emu10k1_efx_attn_put
639};
640
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100641static int snd_emu10k1_shared_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642{
643 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
644 uinfo->count = 1;
645 uinfo->value.integer.min = 0;
646 uinfo->value.integer.max = 1;
647 return 0;
648}
649
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100650static int snd_emu10k1_shared_spdif_get(struct snd_kcontrol *kcontrol,
651 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100653 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
655 if (emu->audigy)
656 ucontrol->value.integer.value[0] = inl(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0;
657 else
658 ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0;
659 return 0;
660}
661
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100662static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol,
663 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664{
665 unsigned long flags;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100666 struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 unsigned int reg, val;
668 int change = 0;
669
670 spin_lock_irqsave(&emu->reg_lock, flags);
671 if (emu->audigy) {
672 reg = inl(emu->port + A_IOCFG);
673 val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0;
674 change = (reg & A_IOCFG_GPOUT0) != val;
675 if (change) {
676 reg &= ~A_IOCFG_GPOUT0;
677 reg |= val;
678 outl(reg | val, emu->port + A_IOCFG);
679 }
680 }
681 reg = inl(emu->port + HCFG);
682 val = ucontrol->value.integer.value[0] ? HCFG_GPOUT0 : 0;
683 change |= (reg & HCFG_GPOUT0) != val;
684 if (change) {
685 reg &= ~HCFG_GPOUT0;
686 reg |= val;
687 outl(reg | val, emu->port + HCFG);
688 }
689 spin_unlock_irqrestore(&emu->reg_lock, flags);
690 return change;
691}
692
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100693static struct snd_kcontrol_new snd_emu10k1_shared_spdif __devinitdata =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694{
695 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
696 .name = "SB Live Analog/Digital Output Jack",
697 .info = snd_emu10k1_shared_spdif_info,
698 .get = snd_emu10k1_shared_spdif_get,
699 .put = snd_emu10k1_shared_spdif_put
700};
701
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100702static struct snd_kcontrol_new snd_audigy_shared_spdif __devinitdata =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703{
704 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
705 .name = "Audigy Analog/Digital Output Jack",
706 .info = snd_emu10k1_shared_spdif_info,
707 .get = snd_emu10k1_shared_spdif_get,
708 .put = snd_emu10k1_shared_spdif_put
709};
710
711/*
712 */
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100713static void snd_emu10k1_mixer_free_ac97(struct snd_ac97 *ac97)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100715 struct snd_emu10k1 *emu = ac97->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 emu->ac97 = NULL;
717}
718
719/*
720 */
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100721static int remove_ctl(struct snd_card *card, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100723 struct snd_ctl_elem_id id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 memset(&id, 0, sizeof(id));
725 strcpy(id.name, name);
726 id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
727 return snd_ctl_remove_id(card, &id);
728}
729
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100730static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100732 struct snd_ctl_elem_id sid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 memset(&sid, 0, sizeof(sid));
734 strcpy(sid.name, name);
735 sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
736 return snd_ctl_find_id(card, &sid);
737}
738
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100739static int rename_ctl(struct snd_card *card, const char *src, const char *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100741 struct snd_kcontrol *kctl = ctl_find(card, src);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 if (kctl) {
743 strcpy(kctl->id.name, dst);
744 return 0;
745 }
746 return -ENOENT;
747}
748
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100749int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu,
Clemens Ladisch67ed4162005-07-29 15:32:58 +0200750 int pcm_device, int multi_device)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751{
752 int err, pcm;
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100753 struct snd_kcontrol *kctl;
754 struct snd_card *card = emu->card;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 char **c;
756 static char *emu10k1_remove_ctls[] = {
757 /* no AC97 mono, surround, center/lfe */
758 "Master Mono Playback Switch",
759 "Master Mono Playback Volume",
760 "PCM Out Path & Mute",
761 "Mono Output Select",
Takashi Iwai7eae36f2006-01-05 18:40:56 +0100762 "Front Playback Switch",
763 "Front Playback Volume",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 "Surround Playback Switch",
765 "Surround Playback Volume",
766 "Center Playback Switch",
767 "Center Playback Volume",
768 "LFE Playback Switch",
769 "LFE Playback Volume",
770 NULL
771 };
772 static char *emu10k1_rename_ctls[] = {
773 "Surround Digital Playback Volume", "Surround Playback Volume",
774 "Center Digital Playback Volume", "Center Playback Volume",
775 "LFE Digital Playback Volume", "LFE Playback Volume",
776 NULL
777 };
778 static char *audigy_remove_ctls[] = {
779 /* Master/PCM controls on ac97 of Audigy has no effect */
James Courtier-Dutton21fddde2006-04-09 17:36:39 +0100780 /* On the Audigy2 the AC97 playback is piped into
781 * the Philips ADC for 24bit capture */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 "PCM Playback Switch",
783 "PCM Playback Volume",
784 "Master Mono Playback Switch",
785 "Master Mono Playback Volume",
786 "Master Playback Switch",
787 "Master Playback Volume",
788 "PCM Out Path & Mute",
789 "Mono Output Select",
790 /* remove unused AC97 capture controls */
791 "Capture Source",
792 "Capture Switch",
793 "Capture Volume",
794 "Mic Select",
795 "Video Playback Switch",
796 "Video Playback Volume",
797 "Mic Playback Switch",
798 "Mic Playback Volume",
799 NULL
800 };
801 static char *audigy_rename_ctls[] = {
802 /* use conventional names */
803 "Wave Playback Volume", "PCM Playback Volume",
804 /* "Wave Capture Volume", "PCM Capture Volume", */
805 "Wave Master Playback Volume", "Master Playback Volume",
806 "AMic Playback Volume", "Mic Playback Volume",
807 NULL
808 };
James Courtier-Dutton21fddde2006-04-09 17:36:39 +0100809 static char *audigy_remove_ctls_1361t_adc[] = {
810 /* On the Audigy2 the AC97 playback is piped into
811 * the Philips ADC for 24bit capture */
812 "PCM Playback Switch",
813 "PCM Playback Volume",
814 "Master Mono Playback Switch",
815 "Master Mono Playback Volume",
816 "Capture Source",
817 "Capture Switch",
818 "Capture Volume",
819 "Mic Capture Volume",
820 "Headphone Playback Switch",
821 "Headphone Playback Volume",
822 "3D Control - Center",
823 "3D Control - Depth",
824 "3D Control - Switch",
825 "Line2 Playback Volume",
826 "Line2 Capture Volume",
827 NULL
828 };
829 static char *audigy_rename_ctls_1361t_adc[] = {
830 "Master Playback Switch", "Master Capture Switch",
831 "Master Playback Volume", "Master Capture Volume",
832 "Wave Master Playback Volume", "Master Playback Volume",
833 "PC Speaker Playback Switch", "PC Speaker Capture Switch",
834 "PC Speaker Playback Volume", "PC Speaker Capture Volume",
835 "Phone Playback Switch", "Phone Capture Switch",
836 "Phone Playback Volume", "Phone Capture Volume",
837 "Mic Playback Switch", "Mic Capture Switch",
838 "Mic Playback Volume", "Mic Capture Volume",
839 "Line Playback Switch", "Line Capture Switch",
840 "Line Playback Volume", "Line Capture Volume",
841 "CD Playback Switch", "CD Capture Switch",
842 "CD Playback Volume", "CD Capture Volume",
843 "Aux Playback Switch", "Aux Capture Switch",
844 "Aux Playback Volume", "Aux Capture Volume",
845 "Video Playback Switch", "Video Capture Switch",
846 "Video Playback Volume", "Video Capture Volume",
847
848 NULL
849 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850
Lee Revell2b637da2005-03-30 13:51:18 +0200851 if (emu->card_capabilities->ac97_chip) {
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100852 struct snd_ac97_bus *pbus;
853 struct snd_ac97_template ac97;
854 static struct snd_ac97_bus_ops ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 .write = snd_emu10k1_ac97_write,
856 .read = snd_emu10k1_ac97_read,
857 };
858
Takashi Iwaib1508692005-10-04 13:49:32 +0200859 if ((err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus)) < 0)
860 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 pbus->no_vra = 1; /* we don't need VRA */
862
863 memset(&ac97, 0, sizeof(ac97));
864 ac97.private_data = emu;
865 ac97.private_free = snd_emu10k1_mixer_free_ac97;
866 ac97.scaps = AC97_SCAP_NO_SPDIF;
Takashi Iwaib1508692005-10-04 13:49:32 +0200867 if ((err = snd_ac97_mixer(pbus, &ac97, &emu->ac97)) < 0) {
868 if (emu->card_capabilities->ac97_chip == 1)
869 return err;
870 snd_printd(KERN_INFO "emu10k1: AC97 is optional on this board\n");
871 snd_printd(KERN_INFO" Proceeding without ac97 mixers...\n");
872 snd_device_free(emu->card, pbus);
873 goto no_ac97; /* FIXME: get rid of ugly gotos.. */
874 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 if (emu->audigy) {
876 /* set master volume to 0 dB */
Takashi Iwai4d7d7592006-01-04 16:00:48 +0100877 snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 /* set capture source to mic */
Takashi Iwai4d7d7592006-01-04 16:00:48 +0100879 snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000);
James Courtier-Dutton21fddde2006-04-09 17:36:39 +0100880 if (emu->card_capabilities->adc_1361t)
881 c = audigy_remove_ctls_1361t_adc;
882 else
883 c = audigy_remove_ctls;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 } else {
885 /*
886 * Credits for cards based on STAC9758:
887 * James Courtier-Dutton <James@superbug.demon.co.uk>
888 * Voluspa <voluspa@comhem.se>
889 */
890 if (emu->ac97->id == AC97_ID_STAC9758) {
891 emu->rear_ac97 = 1;
892 snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT);
893 }
894 /* remove unused AC97 controls */
Takashi Iwai4d7d7592006-01-04 16:00:48 +0100895 snd_ac97_write_cache(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
896 snd_ac97_write_cache(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 c = emu10k1_remove_ctls;
898 }
899 for (; *c; c++)
900 remove_ctl(card, *c);
901 } else {
Takashi Iwaif12aa402005-09-30 16:56:59 +0200902 no_ac97:
Lee Revell2b637da2005-03-30 13:51:18 +0200903 if (emu->card_capabilities->ecard)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 strcpy(emu->card->mixername, "EMU APS");
905 else if (emu->audigy)
906 strcpy(emu->card->mixername, "SB Audigy");
907 else
908 strcpy(emu->card->mixername, "Emu10k1");
909 }
910
911 if (emu->audigy)
James Courtier-Dutton21fddde2006-04-09 17:36:39 +0100912 if (emu->card_capabilities->adc_1361t)
913 c = audigy_rename_ctls_1361t_adc;
914 else
915 c = audigy_rename_ctls;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 else
917 c = emu10k1_rename_ctls;
918 for (; *c; c += 2)
919 rename_ctl(card, c[0], c[1]);
James Courtier-Dutton21fddde2006-04-09 17:36:39 +0100920
James Courtier-Duttone3b9bc02005-12-24 16:54:51 +0100921 if (emu->card_capabilities->subsystem == 0x20071102) { /* Audigy 4 Pro */
922 rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume");
923 rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume");
924 rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume");
925 rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume");
926 remove_ctl(card, "Headphone Playback Switch");
927 remove_ctl(card, "Headphone Playback Volume");
928 remove_ctl(card, "3D Control - Center");
929 remove_ctl(card, "3D Control - Depth");
930 remove_ctl(card, "3D Control - Switch");
931 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL)
933 return -ENOMEM;
Clemens Ladisch67ed4162005-07-29 15:32:58 +0200934 kctl->id.device = pcm_device;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 if ((err = snd_ctl_add(card, kctl)))
936 return err;
937 if ((kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu)) == NULL)
938 return -ENOMEM;
Clemens Ladisch67ed4162005-07-29 15:32:58 +0200939 kctl->id.device = pcm_device;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 if ((err = snd_ctl_add(card, kctl)))
941 return err;
942 if ((kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu)) == NULL)
943 return -ENOMEM;
Clemens Ladisch67ed4162005-07-29 15:32:58 +0200944 kctl->id.device = pcm_device;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 if ((err = snd_ctl_add(card, kctl)))
946 return err;
947
948 if ((kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu)) == NULL)
949 return -ENOMEM;
Clemens Ladisch67ed4162005-07-29 15:32:58 +0200950 kctl->id.device = multi_device;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 if ((err = snd_ctl_add(card, kctl)))
952 return err;
953
954 if ((kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu)) == NULL)
955 return -ENOMEM;
Clemens Ladisch67ed4162005-07-29 15:32:58 +0200956 kctl->id.device = multi_device;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 if ((err = snd_ctl_add(card, kctl)))
958 return err;
959
960 if ((kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu)) == NULL)
961 return -ENOMEM;
Clemens Ladisch67ed4162005-07-29 15:32:58 +0200962 kctl->id.device = multi_device;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 if ((err = snd_ctl_add(card, kctl)))
964 return err;
965
966 /* initialize the routing and volume table for each pcm playback stream */
967 for (pcm = 0; pcm < 32; pcm++) {
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100968 struct snd_emu10k1_pcm_mixer *mix;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 int v;
970
971 mix = &emu->pcm_mixer[pcm];
972 mix->epcm = NULL;
973
974 for (v = 0; v < 4; v++)
975 mix->send_routing[0][v] =
976 mix->send_routing[1][v] =
977 mix->send_routing[2][v] = v;
978
979 memset(&mix->send_volume, 0, sizeof(mix->send_volume));
980 mix->send_volume[0][0] = mix->send_volume[0][1] =
981 mix->send_volume[1][0] = mix->send_volume[2][1] = 255;
982
983 mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff;
984 }
985
986 /* initialize the routing and volume table for the multichannel playback stream */
987 for (pcm = 0; pcm < NUM_EFX_PLAYBACK; pcm++) {
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100988 struct snd_emu10k1_pcm_mixer *mix;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 int v;
990
991 mix = &emu->efx_pcm_mixer[pcm];
992 mix->epcm = NULL;
993
994 mix->send_routing[0][0] = pcm;
995 mix->send_routing[0][1] = (pcm == 0) ? 1 : 0;
996 for (v = 0; v < 2; v++)
997 mix->send_routing[0][2+v] = 13+v;
998 if (emu->audigy)
999 for (v = 0; v < 4; v++)
1000 mix->send_routing[0][4+v] = 60+v;
1001
1002 memset(&mix->send_volume, 0, sizeof(mix->send_volume));
1003 mix->send_volume[0][0] = 255;
1004
1005 mix->attn[0] = 0xffff;
1006 }
1007
Lee Revell2b637da2005-03-30 13:51:18 +02001008 if (! emu->card_capabilities->ecard) { /* FIXME: APS has these controls? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 /* sb live! and audigy */
1010 if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL)
1011 return -ENOMEM;
Clemens Ladisch5549d542005-08-03 13:50:30 +02001012 if (!emu->audigy)
1013 kctl->id.device = emu->pcm_efx->device;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 if ((err = snd_ctl_add(card, kctl)))
1015 return err;
1016 if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL)
1017 return -ENOMEM;
Clemens Ladisch5549d542005-08-03 13:50:30 +02001018 if (!emu->audigy)
1019 kctl->id.device = emu->pcm_efx->device;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 if ((err = snd_ctl_add(card, kctl)))
1021 return err;
1022 }
1023
James Courtier-Dutton19b99fb2005-12-04 18:03:03 +01001024 if ( emu->card_capabilities->emu1212m) {
1025 ; /* Disable the snd_audigy_spdif_shared_spdif */
1026 } else if (emu->audigy) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL)
1028 return -ENOMEM;
1029 if ((err = snd_ctl_add(card, kctl)))
1030 return err;
James Courtier-Dutton001f7582005-04-09 23:38:25 +02001031#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 if ((kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu)) == NULL)
1033 return -ENOMEM;
1034 if ((err = snd_ctl_add(card, kctl)))
1035 return err;
James Courtier-Dutton001f7582005-04-09 23:38:25 +02001036#endif
Lee Revell2b637da2005-03-30 13:51:18 +02001037 } else if (! emu->card_capabilities->ecard) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 /* sb live! */
1039 if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL)
1040 return -ENOMEM;
1041 if ((err = snd_ctl_add(card, kctl)))
1042 return err;
1043 }
Lee Revell2b637da2005-03-30 13:51:18 +02001044 if (emu->card_capabilities->ca0151_chip) { /* P16V */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 if ((err = snd_p16v_mixer(emu)))
1046 return err;
1047 }
1048
1049 return 0;
1050}