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 | #define __NO_VERSION__
|
---|
31 | #include <sound/driver.h>
|
---|
32 | #include <linux/time.h>
|
---|
33 | #include <sound/core.h>
|
---|
34 | #include <sound/emu10k1.h>
|
---|
35 |
|
---|
36 | #define AC97_ID_STAC9758 0x83847658
|
---|
37 |
|
---|
38 | static 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 |
|
---|
45 | static 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 |
|
---|
61 | static 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 |
|
---|
71 | static 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 |
|
---|
84 | static 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 |
|
---|
111 | static 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 |
|
---|
145 | static snd_kcontrol_new_t snd_audigy_spdif_output_rate =
|
---|
146 | {
|
---|
147 | SNDRV_CTL_ELEM_IFACE_MIXER,0,0,
|
---|
148 | "Audigy SPDIF Output Sample Rate", 0,
|
---|
149 | SNDRV_CTL_ELEM_ACCESS_READWRITE,
|
---|
150 | 1,
|
---|
151 | snd_audigy_spdif_output_rate_info,
|
---|
152 | snd_audigy_spdif_output_rate_get,
|
---|
153 | snd_audigy_spdif_output_rate_put, 0
|
---|
154 | };
|
---|
155 |
|
---|
156 | static 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 |
|
---|
179 | static snd_kcontrol_new_t snd_emu10k1_spdif_mask_control =
|
---|
180 | {
|
---|
181 | SNDRV_CTL_ELEM_IFACE_PCM,0,0,
|
---|
182 | SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
|
---|
183 | 0,SNDRV_CTL_ELEM_ACCESS_READ,4,
|
---|
184 | snd_emu10k1_spdif_info,
|
---|
185 | snd_emu10k1_spdif_get_mask,0,0
|
---|
186 | };
|
---|
187 |
|
---|
188 | static snd_kcontrol_new_t snd_emu10k1_spdif_control =
|
---|
189 | {
|
---|
190 | SNDRV_CTL_ELEM_IFACE_PCM,0,0,
|
---|
191 | SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),0,0,4,
|
---|
192 | snd_emu10k1_spdif_info,
|
---|
193 | snd_emu10k1_spdif_get,
|
---|
194 | snd_emu10k1_spdif_put,0
|
---|
195 | };
|
---|
196 |
|
---|
197 | static void update_emu10k1_fxrt(emu10k1_t *emu, int voice, unsigned char *route)
|
---|
198 | {
|
---|
199 | if (emu->audigy) {
|
---|
200 | snd_emu10k1_ptr_write(emu, A_FXRT1, voice,
|
---|
201 | snd_emu10k1_compose_audigy_fxrt1(route));
|
---|
202 | snd_emu10k1_ptr_write(emu, A_FXRT2, voice,
|
---|
203 | snd_emu10k1_compose_audigy_fxrt2(route));
|
---|
204 | } else {
|
---|
205 | snd_emu10k1_ptr_write(emu, FXRT, voice,
|
---|
206 | snd_emu10k1_compose_send_routing(route));
|
---|
207 | }
|
---|
208 | }
|
---|
209 |
|
---|
210 | static void update_emu10k1_send_volume(emu10k1_t *emu, int voice, unsigned char *volume)
|
---|
211 | {
|
---|
212 | snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]);
|
---|
213 | snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]);
|
---|
214 | snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]);
|
---|
215 | snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]);
|
---|
216 | if (emu->audigy) {
|
---|
217 | unsigned int val = ((unsigned int)volume[4] << 24) |
|
---|
218 | ((unsigned int)volume[5] << 16) |
|
---|
219 | ((unsigned int)volume[6] << 8) |
|
---|
220 | (unsigned int)volume[7];
|
---|
221 | snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, val);
|
---|
222 | }
|
---|
223 | }
|
---|
224 |
|
---|
225 | /* PCM stream controls */
|
---|
226 |
|
---|
227 | static int snd_emu10k1_send_routing_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
|
---|
228 | {
|
---|
229 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
|
---|
230 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
---|
231 | uinfo->count = emu->audigy ? 3*8 : 3*4;
|
---|
232 | uinfo->value.integer.min = 0;
|
---|
233 | uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
|
---|
234 | return 0;
|
---|
235 | }
|
---|
236 |
|
---|
237 | static int snd_emu10k1_send_routing_get(snd_kcontrol_t * kcontrol,
|
---|
238 | snd_ctl_elem_value_t * ucontrol)
|
---|
239 | {
|
---|
240 | unsigned long flags;
|
---|
241 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
|
---|
242 | emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
|
---|
243 | int voice, idx;
|
---|
244 | int num_efx = emu->audigy ? 8 : 4;
|
---|
245 | int mask = emu->audigy ? 0x3f : 0x0f;
|
---|
246 |
|
---|
247 | spin_lock_irqsave(&emu->reg_lock, flags);
|
---|
248 | for (voice = 0; voice < 3; voice++)
|
---|
249 | for (idx = 0; idx < num_efx; idx++)
|
---|
250 | ucontrol->value.integer.value[(voice * num_efx) + idx] =
|
---|
251 | mix->send_routing[voice][idx] & mask;
|
---|
252 | spin_unlock_irqrestore(&emu->reg_lock, flags);
|
---|
253 | return 0;
|
---|
254 | }
|
---|
255 |
|
---|
256 | static int snd_emu10k1_send_routing_put(snd_kcontrol_t * kcontrol,
|
---|
257 | snd_ctl_elem_value_t * ucontrol)
|
---|
258 | {
|
---|
259 | unsigned long flags;
|
---|
260 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
|
---|
261 | emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
|
---|
262 | int change = 0, voice, idx, val;
|
---|
263 | int num_efx = emu->audigy ? 8 : 4;
|
---|
264 | int mask = emu->audigy ? 0x3f : 0x0f;
|
---|
265 |
|
---|
266 | spin_lock_irqsave(&emu->reg_lock, flags);
|
---|
267 | for (voice = 0; voice < 3; voice++)
|
---|
268 | for (idx = 0; idx < num_efx; idx++) {
|
---|
269 | val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask;
|
---|
270 | if (mix->send_routing[voice][idx] != val) {
|
---|
271 | mix->send_routing[voice][idx] = val;
|
---|
272 | change = 1;
|
---|
273 | }
|
---|
274 | }
|
---|
275 | if (change && mix->epcm) {
|
---|
276 | if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
|
---|
277 | update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
|
---|
278 | &mix->send_routing[1][0]);
|
---|
279 | update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number,
|
---|
280 | &mix->send_routing[2][0]);
|
---|
281 | } else if (mix->epcm->voices[0]) {
|
---|
282 | update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number,
|
---|
283 | &mix->send_routing[0][0]);
|
---|
284 | }
|
---|
285 | }
|
---|
286 | spin_unlock_irqrestore(&emu->reg_lock, flags);
|
---|
287 | return change;
|
---|
288 | }
|
---|
289 |
|
---|
290 | static snd_kcontrol_new_t snd_emu10k1_send_routing_control =
|
---|
291 | {
|
---|
292 | SNDRV_CTL_ELEM_IFACE_PCM,0,0,
|
---|
293 | "EMU10K1 PCM Send Routing",0,
|
---|
294 | SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,32,
|
---|
295 | snd_emu10k1_send_routing_info,
|
---|
296 | snd_emu10k1_send_routing_get,
|
---|
297 | snd_emu10k1_send_routing_put,0
|
---|
298 | };
|
---|
299 |
|
---|
300 | static int snd_emu10k1_send_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
|
---|
301 | {
|
---|
302 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
|
---|
303 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
---|
304 | uinfo->count = emu->audigy ? 3*8 : 3*4;
|
---|
305 | uinfo->value.integer.min = 0;
|
---|
306 | uinfo->value.integer.max = 255;
|
---|
307 | return 0;
|
---|
308 | }
|
---|
309 |
|
---|
310 | static int snd_emu10k1_send_volume_get(snd_kcontrol_t * kcontrol,
|
---|
311 | snd_ctl_elem_value_t * ucontrol)
|
---|
312 | {
|
---|
313 | unsigned long flags;
|
---|
314 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
|
---|
315 | emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
|
---|
316 | int idx;
|
---|
317 | int num_efx = emu->audigy ? 8 : 4;
|
---|
318 |
|
---|
319 | spin_lock_irqsave(&emu->reg_lock, flags);
|
---|
320 | for (idx = 0; idx < 3*num_efx; idx++)
|
---|
321 | ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx];
|
---|
322 | spin_unlock_irqrestore(&emu->reg_lock, flags);
|
---|
323 | return 0;
|
---|
324 | }
|
---|
325 |
|
---|
326 | static int snd_emu10k1_send_volume_put(snd_kcontrol_t * kcontrol,
|
---|
327 | snd_ctl_elem_value_t * ucontrol)
|
---|
328 | {
|
---|
329 | unsigned long flags;
|
---|
330 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
|
---|
331 | emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
|
---|
332 | int change = 0, idx, val;
|
---|
333 | int num_efx = emu->audigy ? 8 : 4;
|
---|
334 |
|
---|
335 | spin_lock_irqsave(&emu->reg_lock, flags);
|
---|
336 | for (idx = 0; idx < 3*num_efx; idx++) {
|
---|
337 | val = ucontrol->value.integer.value[idx] & 255;
|
---|
338 | if (mix->send_volume[idx/num_efx][idx%num_efx] != val) {
|
---|
339 | mix->send_volume[idx/num_efx][idx%num_efx] = val;
|
---|
340 | change = 1;
|
---|
341 | }
|
---|
342 | }
|
---|
343 | if (change && mix->epcm) {
|
---|
344 | if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
|
---|
345 | update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
|
---|
346 | &mix->send_volume[1][0]);
|
---|
347 | update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number,
|
---|
348 | &mix->send_volume[2][0]);
|
---|
349 | } else if (mix->epcm->voices[0]) {
|
---|
350 | update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number,
|
---|
351 | &mix->send_volume[0][0]);
|
---|
352 | }
|
---|
353 | }
|
---|
354 | spin_unlock_irqrestore(&emu->reg_lock, flags);
|
---|
355 | return change;
|
---|
356 | }
|
---|
357 |
|
---|
358 | static snd_kcontrol_new_t snd_emu10k1_send_volume_control =
|
---|
359 | {
|
---|
360 | SNDRV_CTL_ELEM_IFACE_PCM,0,0,
|
---|
361 | "EMU10K1 PCM Send Volume",0,
|
---|
362 | SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,32,
|
---|
363 | snd_emu10k1_send_volume_info,
|
---|
364 | snd_emu10k1_send_volume_get,
|
---|
365 | snd_emu10k1_send_volume_put,0
|
---|
366 | };
|
---|
367 |
|
---|
368 | static int snd_emu10k1_attn_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
|
---|
369 | {
|
---|
370 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
---|
371 | uinfo->count = 3;
|
---|
372 | uinfo->value.integer.min = 0;
|
---|
373 | uinfo->value.integer.max = 0xffff;
|
---|
374 | return 0;
|
---|
375 | }
|
---|
376 |
|
---|
377 | static int snd_emu10k1_attn_get(snd_kcontrol_t * kcontrol,
|
---|
378 | snd_ctl_elem_value_t * ucontrol)
|
---|
379 | {
|
---|
380 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
|
---|
381 | emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
|
---|
382 | unsigned long flags;
|
---|
383 | int idx;
|
---|
384 |
|
---|
385 | spin_lock_irqsave(&emu->reg_lock, flags);
|
---|
386 | for (idx = 0; idx < 3; idx++)
|
---|
387 | ucontrol->value.integer.value[idx] = mix->attn[idx];
|
---|
388 | spin_unlock_irqrestore(&emu->reg_lock, flags);
|
---|
389 | return 0;
|
---|
390 | }
|
---|
391 |
|
---|
392 | static int snd_emu10k1_attn_put(snd_kcontrol_t * kcontrol,
|
---|
393 | snd_ctl_elem_value_t * ucontrol)
|
---|
394 | {
|
---|
395 | unsigned long flags;
|
---|
396 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
|
---|
397 | emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
|
---|
398 | int change = 0, idx, val;
|
---|
399 |
|
---|
400 | spin_lock_irqsave(&emu->reg_lock, flags);
|
---|
401 | for (idx = 0; idx < 3; idx++) {
|
---|
402 | val = ucontrol->value.integer.value[idx] & 0xffff;
|
---|
403 | if (mix->attn[idx] != val) {
|
---|
404 | mix->attn[idx] = val;
|
---|
405 | change = 1;
|
---|
406 | }
|
---|
407 | }
|
---|
408 | if (change && mix->epcm) {
|
---|
409 | if (mix->epcm->voices[0] && mix->epcm->voices[1]) {
|
---|
410 | snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]);
|
---|
411 | snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]);
|
---|
412 | } else if (mix->epcm->voices[0]) {
|
---|
413 | snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]);
|
---|
414 | }
|
---|
415 | }
|
---|
416 | spin_unlock_irqrestore(&emu->reg_lock, flags);
|
---|
417 | return change;
|
---|
418 | }
|
---|
419 |
|
---|
420 | static snd_kcontrol_new_t snd_emu10k1_attn_control =
|
---|
421 | {
|
---|
422 | SNDRV_CTL_ELEM_IFACE_PCM,0,0,
|
---|
423 | "EMU10K1 PCM Volume",0,
|
---|
424 | SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,32,
|
---|
425 | snd_emu10k1_attn_info,
|
---|
426 | snd_emu10k1_attn_get,
|
---|
427 | snd_emu10k1_attn_put,0
|
---|
428 | };
|
---|
429 |
|
---|
430 | /* Mutichannel PCM stream controls */
|
---|
431 |
|
---|
432 | static int snd_emu10k1_efx_send_routing_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
|
---|
433 | {
|
---|
434 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
|
---|
435 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
---|
436 | uinfo->count = emu->audigy ? 8 : 4;
|
---|
437 | uinfo->value.integer.min = 0;
|
---|
438 | uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f;
|
---|
439 | return 0;
|
---|
440 | }
|
---|
441 |
|
---|
442 | static int snd_emu10k1_efx_send_routing_get(snd_kcontrol_t * kcontrol,
|
---|
443 | snd_ctl_elem_value_t * ucontrol)
|
---|
444 | {
|
---|
445 | unsigned long flags;
|
---|
446 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
|
---|
447 | emu10k1_pcm_mixer_t *mix = &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
|
---|
448 | int idx;
|
---|
449 | int num_efx = emu->audigy ? 8 : 4;
|
---|
450 | int mask = emu->audigy ? 0x3f : 0x0f;
|
---|
451 |
|
---|
452 | spin_lock_irqsave(&emu->reg_lock, flags);
|
---|
453 | for (idx = 0; idx < num_efx; idx++)
|
---|
454 | ucontrol->value.integer.value[idx] =
|
---|
455 | mix->send_routing[0][idx] & mask;
|
---|
456 | spin_unlock_irqrestore(&emu->reg_lock, flags);
|
---|
457 | return 0;
|
---|
458 | }
|
---|
459 |
|
---|
460 | static int snd_emu10k1_efx_send_routing_put(snd_kcontrol_t * kcontrol,
|
---|
461 | snd_ctl_elem_value_t * ucontrol)
|
---|
462 | {
|
---|
463 | unsigned long flags;
|
---|
464 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
|
---|
465 | int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
|
---|
466 | emu10k1_pcm_mixer_t *mix = &emu->efx_pcm_mixer[ch];
|
---|
467 | int change = 0, idx, val;
|
---|
468 | int num_efx = emu->audigy ? 8 : 4;
|
---|
469 | int mask = emu->audigy ? 0x3f : 0x0f;
|
---|
470 |
|
---|
471 | spin_lock_irqsave(&emu->reg_lock, flags);
|
---|
472 | for (idx = 0; idx < num_efx; idx++) {
|
---|
473 | val = ucontrol->value.integer.value[idx] & mask;
|
---|
474 | if (mix->send_routing[0][idx] != val) {
|
---|
475 | mix->send_routing[0][idx] = val;
|
---|
476 | change = 1;
|
---|
477 | }
|
---|
478 | }
|
---|
479 | if (change && mix->epcm) {
|
---|
480 | if (mix->epcm->voices[ch]) {
|
---|
481 | update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number,
|
---|
482 | &mix->send_routing[0][0]);
|
---|
483 | }
|
---|
484 | }
|
---|
485 | spin_unlock_irqrestore(&emu->reg_lock, flags);
|
---|
486 | return change;
|
---|
487 | }
|
---|
488 |
|
---|
489 | static snd_kcontrol_new_t snd_emu10k1_efx_send_routing_control =
|
---|
490 | {
|
---|
491 | SNDRV_CTL_ELEM_IFACE_PCM,0,0,
|
---|
492 | "Multichannel PCM Send Routing",0,
|
---|
493 | SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
|
---|
494 | 16,
|
---|
495 | snd_emu10k1_efx_send_routing_info,
|
---|
496 | snd_emu10k1_efx_send_routing_get,
|
---|
497 | snd_emu10k1_efx_send_routing_put,0
|
---|
498 | };
|
---|
499 |
|
---|
500 | static int snd_emu10k1_efx_send_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
|
---|
501 | {
|
---|
502 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
|
---|
503 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
---|
504 | uinfo->count = emu->audigy ? 8 : 4;
|
---|
505 | uinfo->value.integer.min = 0;
|
---|
506 | uinfo->value.integer.max = 255;
|
---|
507 | return 0;
|
---|
508 | }
|
---|
509 |
|
---|
510 | static int snd_emu10k1_efx_send_volume_get(snd_kcontrol_t * kcontrol,
|
---|
511 | snd_ctl_elem_value_t * ucontrol)
|
---|
512 | {
|
---|
513 | unsigned long flags;
|
---|
514 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
|
---|
515 | emu10k1_pcm_mixer_t *mix = &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
|
---|
516 | int idx;
|
---|
517 | int num_efx = emu->audigy ? 8 : 4;
|
---|
518 |
|
---|
519 | spin_lock_irqsave(&emu->reg_lock, flags);
|
---|
520 | for (idx = 0; idx < num_efx; idx++)
|
---|
521 | ucontrol->value.integer.value[idx] = mix->send_volume[0][idx];
|
---|
522 | spin_unlock_irqrestore(&emu->reg_lock, flags);
|
---|
523 | return 0;
|
---|
524 | }
|
---|
525 |
|
---|
526 | static int snd_emu10k1_efx_send_volume_put(snd_kcontrol_t * kcontrol,
|
---|
527 | snd_ctl_elem_value_t * ucontrol)
|
---|
528 | {
|
---|
529 | unsigned long flags;
|
---|
530 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
|
---|
531 | int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
|
---|
532 | emu10k1_pcm_mixer_t *mix = &emu->efx_pcm_mixer[ch];
|
---|
533 | int change = 0, idx, val;
|
---|
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 | val = ucontrol->value.integer.value[idx] & 255;
|
---|
539 | if (mix->send_volume[0][idx] != val) {
|
---|
540 | mix->send_volume[0][idx] = val;
|
---|
541 | change = 1;
|
---|
542 | }
|
---|
543 | }
|
---|
544 | if (change && mix->epcm) {
|
---|
545 | if (mix->epcm->voices[ch]) {
|
---|
546 | update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number,
|
---|
547 | &mix->send_volume[0][0]);
|
---|
548 | }
|
---|
549 | }
|
---|
550 | spin_unlock_irqrestore(&emu->reg_lock, flags);
|
---|
551 | return change;
|
---|
552 | }
|
---|
553 |
|
---|
554 |
|
---|
555 | static snd_kcontrol_new_t snd_emu10k1_efx_send_volume_control =
|
---|
556 | {
|
---|
557 | SNDRV_CTL_ELEM_IFACE_PCM,0,0,
|
---|
558 | "Multichannel PCM Send Volume",0,
|
---|
559 | SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
|
---|
560 | 16,
|
---|
561 | snd_emu10k1_efx_send_volume_info,
|
---|
562 | snd_emu10k1_efx_send_volume_get,
|
---|
563 | snd_emu10k1_efx_send_volume_put,0
|
---|
564 | };
|
---|
565 |
|
---|
566 | static int snd_emu10k1_efx_attn_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
|
---|
567 | {
|
---|
568 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
---|
569 | uinfo->count = 1;
|
---|
570 | uinfo->value.integer.min = 0;
|
---|
571 | uinfo->value.integer.max = 0xffff;
|
---|
572 | return 0;
|
---|
573 | }
|
---|
574 |
|
---|
575 | static int snd_emu10k1_efx_attn_get(snd_kcontrol_t * kcontrol,
|
---|
576 | snd_ctl_elem_value_t * ucontrol)
|
---|
577 | {
|
---|
578 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
|
---|
579 | emu10k1_pcm_mixer_t *mix = &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)];
|
---|
580 | unsigned long flags;
|
---|
581 |
|
---|
582 | spin_lock_irqsave(&emu->reg_lock, flags);
|
---|
583 | ucontrol->value.integer.value[0] = mix->attn[0];
|
---|
584 | spin_unlock_irqrestore(&emu->reg_lock, flags);
|
---|
585 | return 0;
|
---|
586 | }
|
---|
587 |
|
---|
588 | static int snd_emu10k1_efx_attn_put(snd_kcontrol_t * kcontrol,
|
---|
589 | snd_ctl_elem_value_t * ucontrol)
|
---|
590 | {
|
---|
591 | unsigned long flags;
|
---|
592 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
|
---|
593 | int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
|
---|
594 | emu10k1_pcm_mixer_t *mix = &emu->efx_pcm_mixer[ch];
|
---|
595 | int change = 0, val;
|
---|
596 |
|
---|
597 | spin_lock_irqsave(&emu->reg_lock, flags);
|
---|
598 | val = ucontrol->value.integer.value[0] & 0xffff;
|
---|
599 | if (mix->attn[0] != val) {
|
---|
600 | mix->attn[0] = val;
|
---|
601 | change = 1;
|
---|
602 | }
|
---|
603 | if (change && mix->epcm) {
|
---|
604 | if (mix->epcm->voices[ch]) {
|
---|
605 | snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]);
|
---|
606 | }
|
---|
607 | }
|
---|
608 | spin_unlock_irqrestore(&emu->reg_lock, flags);
|
---|
609 | return change;
|
---|
610 | }
|
---|
611 |
|
---|
612 | static snd_kcontrol_new_t snd_emu10k1_efx_attn_control =
|
---|
613 | {
|
---|
614 | SNDRV_CTL_ELEM_IFACE_PCM,0,0,
|
---|
615 | "Multichannel PCM Volume",0,
|
---|
616 | SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
|
---|
617 | 16,
|
---|
618 | snd_emu10k1_efx_attn_info,
|
---|
619 | snd_emu10k1_efx_attn_get,
|
---|
620 | snd_emu10k1_efx_attn_put,0
|
---|
621 | };
|
---|
622 |
|
---|
623 | static int snd_emu10k1_shared_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
|
---|
624 | {
|
---|
625 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
|
---|
626 | uinfo->count = 1;
|
---|
627 | uinfo->value.integer.min = 0;
|
---|
628 | uinfo->value.integer.max = 1;
|
---|
629 | return 0;
|
---|
630 | }
|
---|
631 |
|
---|
632 | static int snd_emu10k1_shared_spdif_get(snd_kcontrol_t * kcontrol,
|
---|
633 | snd_ctl_elem_value_t * ucontrol)
|
---|
634 | {
|
---|
635 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
|
---|
636 |
|
---|
637 | if (emu->audigy)
|
---|
638 | ucontrol->value.integer.value[0] = inl(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0;
|
---|
639 | else
|
---|
640 | ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0;
|
---|
641 | return 0;
|
---|
642 | }
|
---|
643 |
|
---|
644 | static int snd_emu10k1_shared_spdif_put(snd_kcontrol_t * kcontrol,
|
---|
645 | snd_ctl_elem_value_t * ucontrol)
|
---|
646 | {
|
---|
647 | unsigned long flags;
|
---|
648 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol);
|
---|
649 | unsigned int reg, val;
|
---|
650 | int change = 0;
|
---|
651 |
|
---|
652 | spin_lock_irqsave(&emu->reg_lock, flags);
|
---|
653 | if (emu->audigy) {
|
---|
654 | reg = inl(emu->port + A_IOCFG);
|
---|
655 | val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0;
|
---|
656 | change = (reg & A_IOCFG_GPOUT0) != val;
|
---|
657 | if (change) {
|
---|
658 | reg &= ~A_IOCFG_GPOUT0;
|
---|
659 | reg |= val;
|
---|
660 | outl(reg | val, emu->port + A_IOCFG);
|
---|
661 | }
|
---|
662 | }
|
---|
663 | reg = inl(emu->port + HCFG);
|
---|
664 | val = ucontrol->value.integer.value[0] ? HCFG_GPOUT0 : 0;
|
---|
665 | change |= (reg & HCFG_GPOUT0) != val;
|
---|
666 | if (change) {
|
---|
667 | reg &= ~HCFG_GPOUT0;
|
---|
668 | reg |= val;
|
---|
669 | outl(reg | val, emu->port + HCFG);
|
---|
670 | }
|
---|
671 | spin_unlock_irqrestore(&emu->reg_lock, flags);
|
---|
672 | return change;
|
---|
673 | }
|
---|
674 |
|
---|
675 | static snd_kcontrol_new_t snd_emu10k1_shared_spdif __devinitdata =
|
---|
676 | {
|
---|
677 | SNDRV_CTL_ELEM_IFACE_MIXER,0,0,
|
---|
678 | "SB Live Analog/Digital Output Jack",0,0,0,
|
---|
679 | snd_emu10k1_shared_spdif_info,
|
---|
680 | snd_emu10k1_shared_spdif_get,
|
---|
681 | snd_emu10k1_shared_spdif_put,0
|
---|
682 | };
|
---|
683 |
|
---|
684 | static snd_kcontrol_new_t snd_audigy_shared_spdif __devinitdata =
|
---|
685 | {
|
---|
686 | SNDRV_CTL_ELEM_IFACE_MIXER,0,0,
|
---|
687 | "Audigy Analog/Digital Output Jack",0,0,0,
|
---|
688 | snd_emu10k1_shared_spdif_info,
|
---|
689 | snd_emu10k1_shared_spdif_get,
|
---|
690 | snd_emu10k1_shared_spdif_put,0
|
---|
691 | };
|
---|
692 |
|
---|
693 | /*
|
---|
694 | */
|
---|
695 | static void snd_emu10k1_mixer_free_ac97(ac97_t *ac97)
|
---|
696 | {
|
---|
697 | emu10k1_t *emu = ac97->private_data;
|
---|
698 | emu->ac97 = NULL;
|
---|
699 | }
|
---|
700 |
|
---|
701 | /*
|
---|
702 | */
|
---|
703 | static int remove_ctl(snd_card_t *card, const char *name)
|
---|
704 | {
|
---|
705 | snd_ctl_elem_id_t id;
|
---|
706 | memset(&id, 0, sizeof(id));
|
---|
707 | strcpy(id.name, name);
|
---|
708 | id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
---|
709 | return snd_ctl_remove_id(card, &id);
|
---|
710 | }
|
---|
711 |
|
---|
712 | static snd_kcontrol_t *ctl_find(snd_card_t *card, const char *name)
|
---|
713 | {
|
---|
714 | snd_ctl_elem_id_t sid;
|
---|
715 | memset(&sid, 0, sizeof(sid));
|
---|
716 | strcpy(sid.name, name);
|
---|
717 | sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
|
---|
718 | return snd_ctl_find_id(card, &sid);
|
---|
719 | }
|
---|
720 |
|
---|
721 | static int rename_ctl(snd_card_t *card, const char *src, const char *dst)
|
---|
722 | {
|
---|
723 | snd_kcontrol_t *kctl = ctl_find(card, src);
|
---|
724 | if (kctl) {
|
---|
725 | strcpy(kctl->id.name, dst);
|
---|
726 | return 0;
|
---|
727 | }
|
---|
728 | return -ENOENT;
|
---|
729 | }
|
---|
730 |
|
---|
731 | int __devinit snd_emu10k1_mixer(emu10k1_t *emu,
|
---|
732 | int pcm_device, int multi_device)
|
---|
733 | {
|
---|
734 | int err, pcm;
|
---|
735 | snd_kcontrol_t *kctl;
|
---|
736 | snd_card_t *card = emu->card;
|
---|
737 | char **c;
|
---|
738 | static char *emu10k1_remove_ctls[] = {
|
---|
739 | /* no AC97 mono, surround, center/lfe */
|
---|
740 | "Master Mono Playback Switch",
|
---|
741 | "Master Mono Playback Volume",
|
---|
742 | "PCM Out Path & Mute",
|
---|
743 | "Mono Output Select",
|
---|
744 | "Surround Playback Switch",
|
---|
745 | "Surround Playback Volume",
|
---|
746 | "Center Playback Switch",
|
---|
747 | "Center Playback Volume",
|
---|
748 | "LFE Playback Switch",
|
---|
749 | "LFE Playback Volume",
|
---|
750 | NULL
|
---|
751 | };
|
---|
752 | static char *emu10k1_rename_ctls[] = {
|
---|
753 | "Surround Digital Playback Volume", "Surround Playback Volume",
|
---|
754 | "Center Digital Playback Volume", "Center Playback Volume",
|
---|
755 | "LFE Digital Playback Volume", "LFE Playback Volume",
|
---|
756 | NULL
|
---|
757 | };
|
---|
758 | static char *audigy_remove_ctls[] = {
|
---|
759 | /* Master/PCM controls on ac97 of Audigy has no effect */
|
---|
760 | "PCM Playback Switch",
|
---|
761 | "PCM Playback Volume",
|
---|
762 | "Master Mono Playback Switch",
|
---|
763 | "Master Mono Playback Volume",
|
---|
764 | "Master Playback Switch",
|
---|
765 | "Master Playback Volume",
|
---|
766 | "PCM Out Path & Mute",
|
---|
767 | "Mono Output Select",
|
---|
768 | /* remove unused AC97 capture controls */
|
---|
769 | "Capture Source",
|
---|
770 | "Capture Switch",
|
---|
771 | "Capture Volume",
|
---|
772 | "Mic Select",
|
---|
773 | "Video Playback Switch",
|
---|
774 | "Video Playback Volume",
|
---|
775 | "Mic Playback Switch",
|
---|
776 | "Mic Playback Volume",
|
---|
777 | NULL
|
---|
778 | };
|
---|
779 | static char *audigy_rename_ctls[] = {
|
---|
780 | /* use conventional names */
|
---|
781 | "Wave Playback Volume", "PCM Playback Volume",
|
---|
782 | /* "Wave Capture Volume", "PCM Capture Volume", */
|
---|
783 | "Wave Master Playback Volume", "Master Playback Volume",
|
---|
784 | "AMic Playback Volume", "Mic Playback Volume",
|
---|
785 | NULL
|
---|
786 | };
|
---|
787 |
|
---|
788 | if (emu->card_capabilities->ac97_chip) {
|
---|
789 | ac97_bus_t *pbus;
|
---|
790 | ac97_template_t ac97;
|
---|
791 | static ac97_bus_ops_t ops = {
|
---|
792 | 0,snd_emu10k1_ac97_write,
|
---|
793 | snd_emu10k1_ac97_read,0,0
|
---|
794 | };
|
---|
795 |
|
---|
796 | if ((err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus)) < 0)
|
---|
797 | return err;
|
---|
798 |
|
---|
799 | pbus->no_vra = 1; /* we don't need VRA */
|
---|
800 | memset(&ac97, 0, sizeof(ac97));
|
---|
801 | ac97.private_data = emu;
|
---|
802 | ac97.private_free = snd_emu10k1_mixer_free_ac97;
|
---|
803 | ac97.scaps = AC97_SCAP_NO_SPDIF;
|
---|
804 | if ((err = snd_ac97_mixer(pbus, &ac97, &emu->ac97)) < 0) {
|
---|
805 | if (emu->card_capabilities->ac97_chip == 1)
|
---|
806 | return err;
|
---|
807 | snd_printd(KERN_INFO "emu10k1: AC97 is optional on this board\n");
|
---|
808 | snd_printd(KERN_INFO" Proceeding without ac97 mixers...\n");
|
---|
809 | snd_device_free(emu->card, pbus);
|
---|
810 | goto no_ac97; /* FIXME: get rid of ugly gotos.. */
|
---|
811 | }
|
---|
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 | if (emu->ac97->id == AC97_ID_STAC9758) {
|
---|
820 | emu->rear_ac97 = 1;
|
---|
821 | snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT);
|
---|
822 | }
|
---|
823 | /* remove unused AC97 controls */
|
---|
824 | snd_ac97_write(emu->ac97, AC97_SURROUND_MASTER, 0x0202);
|
---|
825 | snd_ac97_write(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202);
|
---|
826 | c = emu10k1_remove_ctls;
|
---|
827 | }
|
---|
828 | for (; *c; c++)
|
---|
829 | remove_ctl(card, *c);
|
---|
830 | } else {
|
---|
831 | no_ac97:
|
---|
832 | if (emu->card_capabilities->ecard)
|
---|
833 | strcpy(emu->card->mixername, "EMU APS");
|
---|
834 | else if (emu->audigy)
|
---|
835 | strcpy(emu->card->mixername, "SB Audigy");
|
---|
836 | else
|
---|
837 | strcpy(emu->card->mixername, "Emu10k1");
|
---|
838 | }
|
---|
839 |
|
---|
840 | if (emu->audigy)
|
---|
841 | c = audigy_rename_ctls;
|
---|
842 | else
|
---|
843 | c = emu10k1_rename_ctls;
|
---|
844 | for (; *c; c += 2)
|
---|
845 | rename_ctl(card, c[0], c[1]);
|
---|
846 |
|
---|
847 | if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL)
|
---|
848 | return -ENOMEM;
|
---|
849 | kctl->id.device = pcm_device;
|
---|
850 | if ((err = snd_ctl_add(card, kctl)))
|
---|
851 | return err;
|
---|
852 | if ((kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu)) == NULL)
|
---|
853 | return -ENOMEM;
|
---|
854 | kctl->id.device = pcm_device;
|
---|
855 | if ((err = snd_ctl_add(card, kctl)))
|
---|
856 | return err;
|
---|
857 | if ((kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu)) == NULL)
|
---|
858 | return -ENOMEM;
|
---|
859 | kctl->id.device = pcm_device;
|
---|
860 | if ((err = snd_ctl_add(card, kctl)))
|
---|
861 | return err;
|
---|
862 |
|
---|
863 | if ((kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu)) == NULL)
|
---|
864 | return -ENOMEM;
|
---|
865 | kctl->id.device = multi_device;
|
---|
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 | kctl->id.device = multi_device;
|
---|
872 | if ((err = snd_ctl_add(card, kctl)))
|
---|
873 | return err;
|
---|
874 |
|
---|
875 | if ((kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu)) == NULL)
|
---|
876 | return -ENOMEM;
|
---|
877 | kctl->id.device = multi_device;
|
---|
878 | if ((err = snd_ctl_add(card, kctl)))
|
---|
879 | return err;
|
---|
880 |
|
---|
881 | /* initialize the routing and volume table for each pcm playback stream */
|
---|
882 | for (pcm = 0; pcm < 32; pcm++) {
|
---|
883 | emu10k1_pcm_mixer_t *mix;
|
---|
884 | int v;
|
---|
885 |
|
---|
886 | mix = &emu->pcm_mixer[pcm];
|
---|
887 | mix->epcm = NULL;
|
---|
888 |
|
---|
889 | for (v = 0; v < 4; v++)
|
---|
890 | mix->send_routing[0][v] =
|
---|
891 | mix->send_routing[1][v] =
|
---|
892 | mix->send_routing[2][v] = v;
|
---|
893 |
|
---|
894 | memset(&mix->send_volume, 0, sizeof(mix->send_volume));
|
---|
895 | mix->send_volume[0][0] = mix->send_volume[0][1] =
|
---|
896 | mix->send_volume[1][0] = mix->send_volume[2][1] = 255;
|
---|
897 |
|
---|
898 | mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff;
|
---|
899 | }
|
---|
900 |
|
---|
901 | /* initialize the routing and volume table for the multichannel playback stream */
|
---|
902 | for (pcm = 0; pcm < NUM_EFX_PLAYBACK; pcm++) {
|
---|
903 | emu10k1_pcm_mixer_t *mix;
|
---|
904 | int v;
|
---|
905 |
|
---|
906 | mix = &emu->efx_pcm_mixer[pcm];
|
---|
907 | mix->epcm = NULL;
|
---|
908 |
|
---|
909 | mix->send_routing[0][0] = pcm;
|
---|
910 | mix->send_routing[0][1] = (pcm == 0) ? 1 : 0;
|
---|
911 | for (v = 0; v < 2; v++)
|
---|
912 | mix->send_routing[0][2+v] = 13+v;
|
---|
913 | if (emu->audigy)
|
---|
914 | for (v = 0; v < 4; v++)
|
---|
915 | mix->send_routing[0][4+v] = 60+v;
|
---|
916 |
|
---|
917 | memset(&mix->send_volume, 0, sizeof(mix->send_volume));
|
---|
918 | mix->send_volume[0][0] = 255;
|
---|
919 |
|
---|
920 | mix->attn[0] = 0xffff;
|
---|
921 | }
|
---|
922 |
|
---|
923 | if (! emu->card_capabilities->ecard) { /* FIXME: APS has these controls? */
|
---|
924 | /* sb live! and audigy */
|
---|
925 | if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL)
|
---|
926 | return -ENOMEM;
|
---|
927 | if (!emu->audigy)
|
---|
928 | kctl->id.device = emu->pcm_efx->device;
|
---|
929 | if ((err = snd_ctl_add(card, kctl)))
|
---|
930 | return err;
|
---|
931 | if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL)
|
---|
932 | return -ENOMEM;
|
---|
933 | if (!emu->audigy)
|
---|
934 | kctl->id.device = emu->pcm_efx->device;
|
---|
935 | if ((err = snd_ctl_add(card, kctl)))
|
---|
936 | return err;
|
---|
937 | }
|
---|
938 |
|
---|
939 | if (emu->audigy) {
|
---|
940 | if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL)
|
---|
941 | return -ENOMEM;
|
---|
942 | if ((err = snd_ctl_add(card, kctl)))
|
---|
943 | return err;
|
---|
944 | #if 0
|
---|
945 | if ((kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu)) == NULL)
|
---|
946 | return -ENOMEM;
|
---|
947 | if ((err = snd_ctl_add(card, kctl)))
|
---|
948 | return err;
|
---|
949 | #endif
|
---|
950 | } else if (! emu->card_capabilities->ecard) {
|
---|
951 | /* sb live! */
|
---|
952 | if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL)
|
---|
953 | return -ENOMEM;
|
---|
954 | if ((err = snd_ctl_add(card, kctl)))
|
---|
955 | return err;
|
---|
956 | }
|
---|
957 | if (emu->card_capabilities->ca0151_chip) { /* P16V */
|
---|
958 | if ((err = snd_p16v_mixer(emu)))
|
---|
959 | return err;
|
---|
960 | }
|
---|
961 | return 0;
|
---|
962 | }
|
---|