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