diff options
author | Markus Bollinger <bollinger@digigram.com> | 2005-12-06 07:55:26 -0500 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2006-01-03 06:30:26 -0500 |
commit | e12229b4d2b7863b1baaeca759aa87703bf9fdf8 (patch) | |
tree | 64e43c92fd1f675c29cb6002557ef04156713cbf /sound/pci/pcxhr/pcxhr_mixer.c | |
parent | 46a1736d7c07687e7456f72b238a68034fd5a624 (diff) |
[ALSA] Add PCXHR driver
Modules: Documentation,PCI drivers,Digigram PCXHR driver
Add Digigram PCXHR driver.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/pcxhr/pcxhr_mixer.c')
-rw-r--r-- | sound/pci/pcxhr/pcxhr_mixer.c | 1020 |
1 files changed, 1020 insertions, 0 deletions
diff --git a/sound/pci/pcxhr/pcxhr_mixer.c b/sound/pci/pcxhr/pcxhr_mixer.c new file mode 100644 index 000000000000..760e733ac25e --- /dev/null +++ b/sound/pci/pcxhr/pcxhr_mixer.c | |||
@@ -0,0 +1,1020 @@ | |||
1 | #define __NO_VERSION__ | ||
2 | /* | ||
3 | * Driver for Digigram pcxhr compatible soundcards | ||
4 | * | ||
5 | * mixer callbacks | ||
6 | * | ||
7 | * Copyright (c) 2004 by Digigram <alsa@digigram.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | |||
24 | #include <sound/driver.h> | ||
25 | #include <linux/time.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <sound/core.h> | ||
29 | #include "pcxhr.h" | ||
30 | #include "pcxhr_hwdep.h" | ||
31 | #include "pcxhr_core.h" | ||
32 | #include <sound/control.h> | ||
33 | #include <sound/asoundef.h> | ||
34 | #include "pcxhr_mixer.h" | ||
35 | |||
36 | |||
37 | #define PCXHR_ANALOG_CAPTURE_LEVEL_MIN 0 /* -96.0 dB */ | ||
38 | #define PCXHR_ANALOG_CAPTURE_LEVEL_MAX 255 /* +31.5 dB */ | ||
39 | #define PCXHR_ANALOG_CAPTURE_ZERO_LEVEL 224 /* +16.0 dB ( +31.5 dB - fix level +15.5 dB ) */ | ||
40 | |||
41 | #define PCXHR_ANALOG_PLAYBACK_LEVEL_MIN 0 /* -128.0 dB */ | ||
42 | #define PCXHR_ANALOG_PLAYBACK_LEVEL_MAX 128 /* 0.0 dB */ | ||
43 | #define PCXHR_ANALOG_PLAYBACK_ZERO_LEVEL 104 /* -24.0 dB ( 0.0 dB - fix level +24.0 dB ) */ | ||
44 | |||
45 | static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, int is_capture, int channel) | ||
46 | { | ||
47 | int err, vol; | ||
48 | struct pcxhr_rmh rmh; | ||
49 | |||
50 | pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); | ||
51 | if (is_capture) { | ||
52 | rmh.cmd[0] |= IO_NUM_REG_IN_ANA_LEVEL; | ||
53 | rmh.cmd[2] = chip->analog_capture_volume[channel]; | ||
54 | } else { | ||
55 | rmh.cmd[0] |= IO_NUM_REG_OUT_ANA_LEVEL; | ||
56 | if (chip->analog_playback_active[channel]) | ||
57 | vol = chip->analog_playback_volume[channel]; | ||
58 | else | ||
59 | vol = PCXHR_ANALOG_PLAYBACK_LEVEL_MIN; | ||
60 | rmh.cmd[2] = PCXHR_ANALOG_PLAYBACK_LEVEL_MAX - vol; /* playback analog levels are inversed */ | ||
61 | } | ||
62 | rmh.cmd[1] = 1 << ((2 * chip->chip_idx) + channel); /* audio mask */ | ||
63 | rmh.cmd_len = 3; | ||
64 | err = pcxhr_send_msg(chip->mgr, &rmh); | ||
65 | if (err < 0) { | ||
66 | snd_printk(KERN_DEBUG "error update_analog_audio_level card(%d) " | ||
67 | "is_capture(%d) err(%x)\n", chip->chip_idx, is_capture, err); | ||
68 | return -EINVAL; | ||
69 | } | ||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | /* | ||
74 | * analog level control | ||
75 | */ | ||
76 | static int pcxhr_analog_vol_info(struct snd_kcontrol *kcontrol, | ||
77 | struct snd_ctl_elem_info *uinfo) | ||
78 | { | ||
79 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
80 | uinfo->count = 2; | ||
81 | if (kcontrol->private_value == 0) { /* playback */ | ||
82 | uinfo->value.integer.min = PCXHR_ANALOG_PLAYBACK_LEVEL_MIN; /* -128 dB */ | ||
83 | uinfo->value.integer.max = PCXHR_ANALOG_PLAYBACK_LEVEL_MAX; /* 0 dB */ | ||
84 | } else { /* capture */ | ||
85 | uinfo->value.integer.min = PCXHR_ANALOG_CAPTURE_LEVEL_MIN; /* -96 dB */ | ||
86 | uinfo->value.integer.max = PCXHR_ANALOG_CAPTURE_LEVEL_MAX; /* 31.5 dB */ | ||
87 | } | ||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | static int pcxhr_analog_vol_get(struct snd_kcontrol *kcontrol, | ||
92 | struct snd_ctl_elem_value *ucontrol) | ||
93 | { | ||
94 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | ||
95 | down(&chip->mgr->mixer_mutex); | ||
96 | if (kcontrol->private_value == 0) { /* playback */ | ||
97 | ucontrol->value.integer.value[0] = chip->analog_playback_volume[0]; | ||
98 | ucontrol->value.integer.value[1] = chip->analog_playback_volume[1]; | ||
99 | } else { /* capture */ | ||
100 | ucontrol->value.integer.value[0] = chip->analog_capture_volume[0]; | ||
101 | ucontrol->value.integer.value[1] = chip->analog_capture_volume[1]; | ||
102 | } | ||
103 | up(&chip->mgr->mixer_mutex); | ||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static int pcxhr_analog_vol_put(struct snd_kcontrol *kcontrol, | ||
108 | struct snd_ctl_elem_value *ucontrol) | ||
109 | { | ||
110 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | ||
111 | int changed = 0; | ||
112 | int is_capture, i; | ||
113 | |||
114 | down(&chip->mgr->mixer_mutex); | ||
115 | is_capture = (kcontrol->private_value != 0); | ||
116 | for (i = 0; i < 2; i++) { | ||
117 | int new_volume = ucontrol->value.integer.value[i]; | ||
118 | int* stored_volume = is_capture ? &chip->analog_capture_volume[i] : | ||
119 | &chip->analog_playback_volume[i]; | ||
120 | if (*stored_volume != new_volume) { | ||
121 | *stored_volume = new_volume; | ||
122 | changed = 1; | ||
123 | pcxhr_update_analog_audio_level(chip, is_capture, i); | ||
124 | } | ||
125 | } | ||
126 | up(&chip->mgr->mixer_mutex); | ||
127 | return changed; | ||
128 | } | ||
129 | |||
130 | static struct snd_kcontrol_new pcxhr_control_analog_level = { | ||
131 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
132 | /* name will be filled later */ | ||
133 | .info = pcxhr_analog_vol_info, | ||
134 | .get = pcxhr_analog_vol_get, | ||
135 | .put = pcxhr_analog_vol_put, | ||
136 | }; | ||
137 | |||
138 | /* shared */ | ||
139 | static int pcxhr_sw_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | ||
140 | { | ||
141 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
142 | uinfo->count = 2; | ||
143 | uinfo->value.integer.min = 0; | ||
144 | uinfo->value.integer.max = 1; | ||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | static int pcxhr_audio_sw_get(struct snd_kcontrol *kcontrol, | ||
149 | struct snd_ctl_elem_value *ucontrol) | ||
150 | { | ||
151 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | ||
152 | |||
153 | down(&chip->mgr->mixer_mutex); | ||
154 | ucontrol->value.integer.value[0] = chip->analog_playback_active[0]; | ||
155 | ucontrol->value.integer.value[1] = chip->analog_playback_active[1]; | ||
156 | up(&chip->mgr->mixer_mutex); | ||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static int pcxhr_audio_sw_put(struct snd_kcontrol *kcontrol, | ||
161 | struct snd_ctl_elem_value *ucontrol) | ||
162 | { | ||
163 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | ||
164 | int i, changed = 0; | ||
165 | down(&chip->mgr->mixer_mutex); | ||
166 | for(i = 0; i < 2; i++) { | ||
167 | if (chip->analog_playback_active[i] != ucontrol->value.integer.value[i]) { | ||
168 | chip->analog_playback_active[i] = ucontrol->value.integer.value[i]; | ||
169 | changed = 1; | ||
170 | pcxhr_update_analog_audio_level(chip, 0, i); /* update playback levels */ | ||
171 | } | ||
172 | } | ||
173 | up(&chip->mgr->mixer_mutex); | ||
174 | return changed; | ||
175 | } | ||
176 | |||
177 | static struct snd_kcontrol_new pcxhr_control_output_switch = { | ||
178 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
179 | .name = "Master Playback Switch", | ||
180 | .info = pcxhr_sw_info, /* shared */ | ||
181 | .get = pcxhr_audio_sw_get, | ||
182 | .put = pcxhr_audio_sw_put | ||
183 | }; | ||
184 | |||
185 | |||
186 | #define PCXHR_DIGITAL_LEVEL_MIN 0x000 /* -110 dB */ | ||
187 | #define PCXHR_DIGITAL_LEVEL_MAX 0x1ff /* +18 dB */ | ||
188 | #define PCXHR_DIGITAL_ZERO_LEVEL 0x1b7 /* 0 dB */ | ||
189 | |||
190 | |||
191 | #define MORE_THAN_ONE_STREAM_LEVEL 0x000001 | ||
192 | #define VALID_STREAM_PAN_LEVEL_MASK 0x800000 | ||
193 | #define VALID_STREAM_LEVEL_MASK 0x400000 | ||
194 | #define VALID_STREAM_LEVEL_1_MASK 0x200000 | ||
195 | #define VALID_STREAM_LEVEL_2_MASK 0x100000 | ||
196 | |||
197 | static int pcxhr_update_playback_stream_level(struct snd_pcxhr* chip, int idx) | ||
198 | { | ||
199 | int err; | ||
200 | struct pcxhr_rmh rmh; | ||
201 | struct pcxhr_pipe *pipe = &chip->playback_pipe; | ||
202 | int left, right; | ||
203 | |||
204 | if (chip->digital_playback_active[idx][0]) | ||
205 | left = chip->digital_playback_volume[idx][0]; | ||
206 | else | ||
207 | left = PCXHR_DIGITAL_LEVEL_MIN; | ||
208 | if (chip->digital_playback_active[idx][1]) | ||
209 | right = chip->digital_playback_volume[idx][1]; | ||
210 | else | ||
211 | right = PCXHR_DIGITAL_LEVEL_MIN; | ||
212 | |||
213 | pcxhr_init_rmh(&rmh, CMD_STREAM_OUT_LEVEL_ADJUST); | ||
214 | /* add pipe and stream mask */ | ||
215 | pcxhr_set_pipe_cmd_params(&rmh, 0, pipe->first_audio, 0, 1<<idx); | ||
216 | /* volume left->left / right->right panoramic level */ | ||
217 | rmh.cmd[0] |= MORE_THAN_ONE_STREAM_LEVEL; | ||
218 | rmh.cmd[2] = VALID_STREAM_PAN_LEVEL_MASK | VALID_STREAM_LEVEL_1_MASK; | ||
219 | rmh.cmd[2] |= (left << 10); | ||
220 | rmh.cmd[3] = VALID_STREAM_PAN_LEVEL_MASK | VALID_STREAM_LEVEL_2_MASK; | ||
221 | rmh.cmd[3] |= right; | ||
222 | rmh.cmd_len = 4; | ||
223 | |||
224 | err = pcxhr_send_msg(chip->mgr, &rmh); | ||
225 | if (err < 0) { | ||
226 | snd_printk(KERN_DEBUG "error update_playback_stream_level " | ||
227 | "card(%d) err(%x)\n", chip->chip_idx, err); | ||
228 | return -EINVAL; | ||
229 | } | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | #define AUDIO_IO_HAS_MUTE_LEVEL 0x400000 | ||
234 | #define AUDIO_IO_HAS_MUTE_MONITOR_1 0x200000 | ||
235 | #define VALID_AUDIO_IO_DIGITAL_LEVEL 0x000001 | ||
236 | #define VALID_AUDIO_IO_MONITOR_LEVEL 0x000002 | ||
237 | #define VALID_AUDIO_IO_MUTE_LEVEL 0x000004 | ||
238 | #define VALID_AUDIO_IO_MUTE_MONITOR_1 0x000008 | ||
239 | |||
240 | static int pcxhr_update_audio_pipe_level(struct snd_pcxhr* chip, int capture, int channel) | ||
241 | { | ||
242 | int err; | ||
243 | struct pcxhr_rmh rmh; | ||
244 | struct pcxhr_pipe *pipe; | ||
245 | |||
246 | if (capture) | ||
247 | pipe = &chip->capture_pipe[0]; | ||
248 | else | ||
249 | pipe = &chip->playback_pipe; | ||
250 | |||
251 | pcxhr_init_rmh(&rmh, CMD_AUDIO_LEVEL_ADJUST); | ||
252 | /* add channel mask */ | ||
253 | pcxhr_set_pipe_cmd_params(&rmh, capture, 0, 0, 1 << (channel + pipe->first_audio)); | ||
254 | /* TODO : if mask (3 << pipe->first_audio) is used, left and right channel | ||
255 | * will be programmed to the same params | ||
256 | */ | ||
257 | if (capture) { | ||
258 | rmh.cmd[0] |= VALID_AUDIO_IO_DIGITAL_LEVEL; | ||
259 | /* VALID_AUDIO_IO_MUTE_LEVEL not yet handled (capture pipe level) */ | ||
260 | rmh.cmd[2] = chip->digital_capture_volume[channel]; | ||
261 | } else { | ||
262 | rmh.cmd[0] |= VALID_AUDIO_IO_MONITOR_LEVEL | VALID_AUDIO_IO_MUTE_MONITOR_1; | ||
263 | /* VALID_AUDIO_IO_DIGITAL_LEVEL and VALID_AUDIO_IO_MUTE_LEVEL not yet | ||
264 | * handled (playback pipe level) | ||
265 | */ | ||
266 | rmh.cmd[2] = chip->monitoring_volume[channel] << 10; | ||
267 | if (chip->monitoring_active[channel] == 0) | ||
268 | rmh.cmd[2] |= AUDIO_IO_HAS_MUTE_MONITOR_1; | ||
269 | } | ||
270 | rmh.cmd_len = 3; | ||
271 | |||
272 | err = pcxhr_send_msg(chip->mgr, &rmh); | ||
273 | if(err<0) { | ||
274 | snd_printk(KERN_DEBUG "error update_audio_level card(%d) err(%x)\n", | ||
275 | chip->chip_idx, err); | ||
276 | return -EINVAL; | ||
277 | } | ||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | |||
282 | /* shared */ | ||
283 | static int pcxhr_digital_vol_info(struct snd_kcontrol *kcontrol, | ||
284 | struct snd_ctl_elem_info *uinfo) | ||
285 | { | ||
286 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
287 | uinfo->count = 2; | ||
288 | uinfo->value.integer.min = PCXHR_DIGITAL_LEVEL_MIN; /* -109.5 dB */ | ||
289 | uinfo->value.integer.max = PCXHR_DIGITAL_LEVEL_MAX; /* 18.0 dB */ | ||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | |||
294 | static int pcxhr_pcm_vol_get(struct snd_kcontrol *kcontrol, | ||
295 | struct snd_ctl_elem_value *ucontrol) | ||
296 | { | ||
297 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | ||
298 | int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ | ||
299 | int *stored_volume; | ||
300 | int is_capture = kcontrol->private_value; | ||
301 | |||
302 | down(&chip->mgr->mixer_mutex); | ||
303 | if (is_capture) | ||
304 | stored_volume = chip->digital_capture_volume; /* digital capture */ | ||
305 | else | ||
306 | stored_volume = chip->digital_playback_volume[idx]; /* digital playback */ | ||
307 | ucontrol->value.integer.value[0] = stored_volume[0]; | ||
308 | ucontrol->value.integer.value[1] = stored_volume[1]; | ||
309 | up(&chip->mgr->mixer_mutex); | ||
310 | return 0; | ||
311 | } | ||
312 | |||
313 | static int pcxhr_pcm_vol_put(struct snd_kcontrol *kcontrol, | ||
314 | struct snd_ctl_elem_value *ucontrol) | ||
315 | { | ||
316 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | ||
317 | int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ | ||
318 | int changed = 0; | ||
319 | int is_capture = kcontrol->private_value; | ||
320 | int *stored_volume; | ||
321 | int i; | ||
322 | |||
323 | down(&chip->mgr->mixer_mutex); | ||
324 | if (is_capture) | ||
325 | stored_volume = chip->digital_capture_volume; /* digital capture */ | ||
326 | else | ||
327 | stored_volume = chip->digital_playback_volume[idx]; /* digital playback */ | ||
328 | for (i = 0; i < 2; i++) { | ||
329 | if (stored_volume[i] != ucontrol->value.integer.value[i]) { | ||
330 | stored_volume[i] = ucontrol->value.integer.value[i]; | ||
331 | changed = 1; | ||
332 | if (is_capture) /* update capture volume */ | ||
333 | pcxhr_update_audio_pipe_level(chip, 1, i); | ||
334 | } | ||
335 | } | ||
336 | if (! is_capture && changed) | ||
337 | pcxhr_update_playback_stream_level(chip, idx); /* update playback volume */ | ||
338 | up(&chip->mgr->mixer_mutex); | ||
339 | return changed; | ||
340 | } | ||
341 | |||
342 | static struct snd_kcontrol_new snd_pcxhr_pcm_vol = | ||
343 | { | ||
344 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
345 | /* name will be filled later */ | ||
346 | /* count will be filled later */ | ||
347 | .info = pcxhr_digital_vol_info, /* shared */ | ||
348 | .get = pcxhr_pcm_vol_get, | ||
349 | .put = pcxhr_pcm_vol_put, | ||
350 | }; | ||
351 | |||
352 | |||
353 | static int pcxhr_pcm_sw_get(struct snd_kcontrol *kcontrol, | ||
354 | struct snd_ctl_elem_value *ucontrol) | ||
355 | { | ||
356 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | ||
357 | int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ | ||
358 | |||
359 | down(&chip->mgr->mixer_mutex); | ||
360 | ucontrol->value.integer.value[0] = chip->digital_playback_active[idx][0]; | ||
361 | ucontrol->value.integer.value[1] = chip->digital_playback_active[idx][1]; | ||
362 | up(&chip->mgr->mixer_mutex); | ||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | static int pcxhr_pcm_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
367 | { | ||
368 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | ||
369 | int changed = 0; | ||
370 | int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ | ||
371 | int i, j; | ||
372 | |||
373 | down(&chip->mgr->mixer_mutex); | ||
374 | j = idx; | ||
375 | for (i = 0; i < 2; i++) { | ||
376 | if (chip->digital_playback_active[j][i] != ucontrol->value.integer.value[i]) { | ||
377 | chip->digital_playback_active[j][i] = ucontrol->value.integer.value[i]; | ||
378 | changed = 1; | ||
379 | } | ||
380 | } | ||
381 | if (changed) | ||
382 | pcxhr_update_playback_stream_level(chip, idx); | ||
383 | up(&chip->mgr->mixer_mutex); | ||
384 | return changed; | ||
385 | } | ||
386 | |||
387 | static struct snd_kcontrol_new pcxhr_control_pcm_switch = { | ||
388 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
389 | .name = "PCM Playback Switch", | ||
390 | .count = PCXHR_PLAYBACK_STREAMS, | ||
391 | .info = pcxhr_sw_info, /* shared */ | ||
392 | .get = pcxhr_pcm_sw_get, | ||
393 | .put = pcxhr_pcm_sw_put | ||
394 | }; | ||
395 | |||
396 | |||
397 | /* | ||
398 | * monitoring level control | ||
399 | */ | ||
400 | |||
401 | static int pcxhr_monitor_vol_get(struct snd_kcontrol *kcontrol, | ||
402 | struct snd_ctl_elem_value *ucontrol) | ||
403 | { | ||
404 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | ||
405 | down(&chip->mgr->mixer_mutex); | ||
406 | ucontrol->value.integer.value[0] = chip->monitoring_volume[0]; | ||
407 | ucontrol->value.integer.value[1] = chip->monitoring_volume[1]; | ||
408 | up(&chip->mgr->mixer_mutex); | ||
409 | return 0; | ||
410 | } | ||
411 | |||
412 | static int pcxhr_monitor_vol_put(struct snd_kcontrol *kcontrol, | ||
413 | struct snd_ctl_elem_value *ucontrol) | ||
414 | { | ||
415 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | ||
416 | int changed = 0; | ||
417 | int i; | ||
418 | |||
419 | down(&chip->mgr->mixer_mutex); | ||
420 | for (i = 0; i < 2; i++) { | ||
421 | if (chip->monitoring_volume[i] != ucontrol->value.integer.value[i]) { | ||
422 | chip->monitoring_volume[i] = ucontrol->value.integer.value[i]; | ||
423 | if(chip->monitoring_active[i]) /* do only when monitoring is unmuted */ | ||
424 | /* update monitoring volume and mute */ | ||
425 | pcxhr_update_audio_pipe_level(chip, 0, i); | ||
426 | changed = 1; | ||
427 | } | ||
428 | } | ||
429 | up(&chip->mgr->mixer_mutex); | ||
430 | return changed; | ||
431 | } | ||
432 | |||
433 | static struct snd_kcontrol_new pcxhr_control_monitor_vol = { | ||
434 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
435 | .name = "Monitoring Volume", | ||
436 | .info = pcxhr_digital_vol_info, /* shared */ | ||
437 | .get = pcxhr_monitor_vol_get, | ||
438 | .put = pcxhr_monitor_vol_put, | ||
439 | }; | ||
440 | |||
441 | /* | ||
442 | * monitoring switch control | ||
443 | */ | ||
444 | |||
445 | static int pcxhr_monitor_sw_get(struct snd_kcontrol *kcontrol, | ||
446 | struct snd_ctl_elem_value *ucontrol) | ||
447 | { | ||
448 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | ||
449 | down(&chip->mgr->mixer_mutex); | ||
450 | ucontrol->value.integer.value[0] = chip->monitoring_active[0]; | ||
451 | ucontrol->value.integer.value[1] = chip->monitoring_active[1]; | ||
452 | up(&chip->mgr->mixer_mutex); | ||
453 | return 0; | ||
454 | } | ||
455 | |||
456 | static int pcxhr_monitor_sw_put(struct snd_kcontrol *kcontrol, | ||
457 | struct snd_ctl_elem_value *ucontrol) | ||
458 | { | ||
459 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | ||
460 | int changed = 0; | ||
461 | int i; | ||
462 | |||
463 | down(&chip->mgr->mixer_mutex); | ||
464 | for (i = 0; i < 2; i++) { | ||
465 | if (chip->monitoring_active[i] != ucontrol->value.integer.value[i]) { | ||
466 | chip->monitoring_active[i] = ucontrol->value.integer.value[i]; | ||
467 | changed |= (1<<i); /* mask 0x01 and 0x02 */ | ||
468 | } | ||
469 | } | ||
470 | if(changed & 0x01) | ||
471 | /* update left monitoring volume and mute */ | ||
472 | pcxhr_update_audio_pipe_level(chip, 0, 0); | ||
473 | if(changed & 0x02) | ||
474 | /* update right monitoring volume and mute */ | ||
475 | pcxhr_update_audio_pipe_level(chip, 0, 1); | ||
476 | |||
477 | up(&chip->mgr->mixer_mutex); | ||
478 | return (changed != 0); | ||
479 | } | ||
480 | |||
481 | static struct snd_kcontrol_new pcxhr_control_monitor_sw = { | ||
482 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
483 | .name = "Monitoring Switch", | ||
484 | .info = pcxhr_sw_info, /* shared */ | ||
485 | .get = pcxhr_monitor_sw_get, | ||
486 | .put = pcxhr_monitor_sw_put | ||
487 | }; | ||
488 | |||
489 | |||
490 | |||
491 | /* | ||
492 | * audio source select | ||
493 | */ | ||
494 | #define PCXHR_SOURCE_AUDIO01_UER 0x000100 | ||
495 | #define PCXHR_SOURCE_AUDIO01_SYNC 0x000200 | ||
496 | #define PCXHR_SOURCE_AUDIO23_UER 0x000400 | ||
497 | #define PCXHR_SOURCE_AUDIO45_UER 0x001000 | ||
498 | #define PCXHR_SOURCE_AUDIO67_UER 0x040000 | ||
499 | |||
500 | static int pcxhr_set_audio_source(struct snd_pcxhr* chip) | ||
501 | { | ||
502 | struct pcxhr_rmh rmh; | ||
503 | unsigned int mask, reg; | ||
504 | unsigned int codec; | ||
505 | int err, use_src, changed; | ||
506 | |||
507 | switch (chip->chip_idx) { | ||
508 | case 0 : mask = PCXHR_SOURCE_AUDIO01_UER; codec = CS8420_01_CS; break; | ||
509 | case 1 : mask = PCXHR_SOURCE_AUDIO23_UER; codec = CS8420_23_CS; break; | ||
510 | case 2 : mask = PCXHR_SOURCE_AUDIO45_UER; codec = CS8420_45_CS; break; | ||
511 | case 3 : mask = PCXHR_SOURCE_AUDIO67_UER; codec = CS8420_67_CS; break; | ||
512 | default: return -EINVAL; | ||
513 | } | ||
514 | reg = 0; /* audio source from analog plug */ | ||
515 | use_src = 0; /* do not activate codec SRC */ | ||
516 | |||
517 | if (chip->audio_capture_source != 0) { | ||
518 | reg = mask; /* audio source from digital plug */ | ||
519 | if (chip->audio_capture_source == 2) | ||
520 | use_src = 1; | ||
521 | } | ||
522 | /* set the input source */ | ||
523 | pcxhr_write_io_num_reg_cont(chip->mgr, mask, reg, &changed); | ||
524 | /* resync them (otherwise channel inversion possible) */ | ||
525 | if (changed) { | ||
526 | pcxhr_init_rmh(&rmh, CMD_RESYNC_AUDIO_INPUTS); | ||
527 | rmh.cmd[0] |= (1 << chip->chip_idx); | ||
528 | err = pcxhr_send_msg(chip->mgr, &rmh); | ||
529 | if (err) | ||
530 | return err; | ||
531 | } | ||
532 | pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); /* set codec SRC on off */ | ||
533 | rmh.cmd_len = 3; | ||
534 | rmh.cmd[0] |= IO_NUM_UER_CHIP_REG; | ||
535 | rmh.cmd[1] = codec; | ||
536 | rmh.cmd[2] = (CS8420_DATA_FLOW_CTL & CHIP_SIG_AND_MAP_SPI) | (use_src ? 0x41 : 0x54); | ||
537 | err = pcxhr_send_msg(chip->mgr, &rmh); | ||
538 | if(err) | ||
539 | return err; | ||
540 | rmh.cmd[2] = (CS8420_CLOCK_SRC_CTL & CHIP_SIG_AND_MAP_SPI) | (use_src ? 0x41 : 0x49); | ||
541 | err = pcxhr_send_msg(chip->mgr, &rmh); | ||
542 | return err; | ||
543 | } | ||
544 | |||
545 | static int pcxhr_audio_src_info(struct snd_kcontrol *kcontrol, | ||
546 | struct snd_ctl_elem_info *uinfo) | ||
547 | { | ||
548 | static char *texts[3] = {"Analog", "Digital", "Digi+SRC"}; | ||
549 | |||
550 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
551 | uinfo->count = 1; | ||
552 | uinfo->value.enumerated.items = 3; | ||
553 | if (uinfo->value.enumerated.item > 2) | ||
554 | uinfo->value.enumerated.item = 2; | ||
555 | strcpy(uinfo->value.enumerated.name, | ||
556 | texts[uinfo->value.enumerated.item]); | ||
557 | return 0; | ||
558 | } | ||
559 | |||
560 | static int pcxhr_audio_src_get(struct snd_kcontrol *kcontrol, | ||
561 | struct snd_ctl_elem_value *ucontrol) | ||
562 | { | ||
563 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | ||
564 | ucontrol->value.enumerated.item[0] = chip->audio_capture_source; | ||
565 | return 0; | ||
566 | } | ||
567 | |||
568 | static int pcxhr_audio_src_put(struct snd_kcontrol *kcontrol, | ||
569 | struct snd_ctl_elem_value *ucontrol) | ||
570 | { | ||
571 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | ||
572 | int ret = 0; | ||
573 | |||
574 | down(&chip->mgr->mixer_mutex); | ||
575 | if (chip->audio_capture_source != ucontrol->value.enumerated.item[0]) { | ||
576 | chip->audio_capture_source = ucontrol->value.enumerated.item[0]; | ||
577 | pcxhr_set_audio_source(chip); | ||
578 | ret = 1; | ||
579 | } | ||
580 | up(&chip->mgr->mixer_mutex); | ||
581 | return ret; | ||
582 | } | ||
583 | |||
584 | static struct snd_kcontrol_new pcxhr_control_audio_src = { | ||
585 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
586 | .name = "Capture Source", | ||
587 | .info = pcxhr_audio_src_info, | ||
588 | .get = pcxhr_audio_src_get, | ||
589 | .put = pcxhr_audio_src_put, | ||
590 | }; | ||
591 | |||
592 | |||
593 | /* | ||
594 | * clock type selection | ||
595 | * enum pcxhr_clock_type { | ||
596 | * PCXHR_CLOCK_TYPE_INTERNAL = 0, | ||
597 | * PCXHR_CLOCK_TYPE_WORD_CLOCK, | ||
598 | * PCXHR_CLOCK_TYPE_AES_SYNC, | ||
599 | * PCXHR_CLOCK_TYPE_AES_1, | ||
600 | * PCXHR_CLOCK_TYPE_AES_2, | ||
601 | * PCXHR_CLOCK_TYPE_AES_3, | ||
602 | * PCXHR_CLOCK_TYPE_AES_4, | ||
603 | * }; | ||
604 | */ | ||
605 | |||
606 | static int pcxhr_clock_type_info(struct snd_kcontrol *kcontrol, | ||
607 | struct snd_ctl_elem_info *uinfo) | ||
608 | { | ||
609 | static char *texts[7] = { | ||
610 | "Internal", "WordClock", "AES Sync", "AES 1", "AES 2", "AES 3", "AES 4" | ||
611 | }; | ||
612 | struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); | ||
613 | int clock_items = 3 + mgr->capture_chips; | ||
614 | |||
615 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
616 | uinfo->count = 1; | ||
617 | uinfo->value.enumerated.items = clock_items; | ||
618 | if (uinfo->value.enumerated.item >= clock_items) | ||
619 | uinfo->value.enumerated.item = clock_items-1; | ||
620 | strcpy(uinfo->value.enumerated.name, | ||
621 | texts[uinfo->value.enumerated.item]); | ||
622 | return 0; | ||
623 | } | ||
624 | |||
625 | static int pcxhr_clock_type_get(struct snd_kcontrol *kcontrol, | ||
626 | struct snd_ctl_elem_value *ucontrol) | ||
627 | { | ||
628 | struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); | ||
629 | ucontrol->value.enumerated.item[0] = mgr->use_clock_type; | ||
630 | return 0; | ||
631 | } | ||
632 | |||
633 | static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol, | ||
634 | struct snd_ctl_elem_value *ucontrol) | ||
635 | { | ||
636 | struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); | ||
637 | int rate, ret = 0; | ||
638 | |||
639 | down(&mgr->mixer_mutex); | ||
640 | if (mgr->use_clock_type != ucontrol->value.enumerated.item[0]) { | ||
641 | down(&mgr->setup_mutex); | ||
642 | mgr->use_clock_type = ucontrol->value.enumerated.item[0]; | ||
643 | if (mgr->use_clock_type) | ||
644 | pcxhr_get_external_clock(mgr, mgr->use_clock_type, &rate); | ||
645 | else | ||
646 | rate = mgr->sample_rate; | ||
647 | if (rate) { | ||
648 | pcxhr_set_clock(mgr, rate); | ||
649 | if (mgr->sample_rate) | ||
650 | mgr->sample_rate = rate; | ||
651 | } | ||
652 | up(&mgr->setup_mutex); | ||
653 | ret = 1; /* return 1 even if the set was not done. ok ? */ | ||
654 | } | ||
655 | up(&mgr->mixer_mutex); | ||
656 | return ret; | ||
657 | } | ||
658 | |||
659 | static struct snd_kcontrol_new pcxhr_control_clock_type = { | ||
660 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
661 | .name = "Clock Mode", | ||
662 | .info = pcxhr_clock_type_info, | ||
663 | .get = pcxhr_clock_type_get, | ||
664 | .put = pcxhr_clock_type_put, | ||
665 | }; | ||
666 | |||
667 | /* | ||
668 | * clock rate control | ||
669 | * specific control that scans the sample rates on the external plugs | ||
670 | */ | ||
671 | static int pcxhr_clock_rate_info(struct snd_kcontrol *kcontrol, | ||
672 | struct snd_ctl_elem_info *uinfo) | ||
673 | { | ||
674 | struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); | ||
675 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
676 | uinfo->count = 3 + mgr->capture_chips; | ||
677 | uinfo->value.integer.min = 0; /* clock not present */ | ||
678 | uinfo->value.integer.max = 192000; /* max sample rate 192 kHz */ | ||
679 | return 0; | ||
680 | } | ||
681 | |||
682 | static int pcxhr_clock_rate_get(struct snd_kcontrol *kcontrol, | ||
683 | struct snd_ctl_elem_value *ucontrol) | ||
684 | { | ||
685 | struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); | ||
686 | int i, err, rate; | ||
687 | |||
688 | down(&mgr->mixer_mutex); | ||
689 | for(i = 0; i < 3 + mgr->capture_chips; i++) { | ||
690 | if (i == PCXHR_CLOCK_TYPE_INTERNAL) | ||
691 | rate = mgr->sample_rate_real; | ||
692 | else { | ||
693 | err = pcxhr_get_external_clock(mgr, i, &rate); | ||
694 | if (err) | ||
695 | break; | ||
696 | } | ||
697 | ucontrol->value.integer.value[i] = rate; | ||
698 | } | ||
699 | up(&mgr->mixer_mutex); | ||
700 | return 0; | ||
701 | } | ||
702 | |||
703 | static struct snd_kcontrol_new pcxhr_control_clock_rate = { | ||
704 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
705 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, | ||
706 | .name = "Clock Rates", | ||
707 | .info = pcxhr_clock_rate_info, | ||
708 | .get = pcxhr_clock_rate_get, | ||
709 | }; | ||
710 | |||
711 | /* | ||
712 | * IEC958 status bits | ||
713 | */ | ||
714 | static int pcxhr_iec958_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | ||
715 | { | ||
716 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; | ||
717 | uinfo->count = 1; | ||
718 | return 0; | ||
719 | } | ||
720 | |||
721 | static int pcxhr_iec958_capture_byte(struct snd_pcxhr *chip, int aes_idx, unsigned char* aes_bits) | ||
722 | { | ||
723 | int i, err; | ||
724 | unsigned char temp; | ||
725 | struct pcxhr_rmh rmh; | ||
726 | |||
727 | pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_READ); | ||
728 | rmh.cmd[0] |= IO_NUM_UER_CHIP_REG; | ||
729 | switch (chip->chip_idx) { | ||
730 | case 0: rmh.cmd[1] = CS8420_01_CS; break; /* use CS8416_01_CS for AES SYNC plug */ | ||
731 | case 1: rmh.cmd[1] = CS8420_23_CS; break; | ||
732 | case 2: rmh.cmd[1] = CS8420_45_CS; break; | ||
733 | case 3: rmh.cmd[1] = CS8420_67_CS; break; | ||
734 | default: return -EINVAL; | ||
735 | } | ||
736 | switch (aes_idx) { | ||
737 | case 0: rmh.cmd[2] = CS8420_CSB0; break; /* use CS8416_CSBx for AES SYNC plug */ | ||
738 | case 1: rmh.cmd[2] = CS8420_CSB1; break; | ||
739 | case 2: rmh.cmd[2] = CS8420_CSB2; break; | ||
740 | case 3: rmh.cmd[2] = CS8420_CSB3; break; | ||
741 | case 4: rmh.cmd[2] = CS8420_CSB4; break; | ||
742 | default: return -EINVAL; | ||
743 | } | ||
744 | rmh.cmd[1] &= 0x0fffff; /* size and code the chip id for the fpga */ | ||
745 | rmh.cmd[2] &= CHIP_SIG_AND_MAP_SPI; /* chip signature + map for spi read */ | ||
746 | rmh.cmd_len = 3; | ||
747 | err = pcxhr_send_msg(chip->mgr, &rmh); | ||
748 | if (err) | ||
749 | return err; | ||
750 | temp = 0; | ||
751 | for (i = 0; i < 8; i++) { | ||
752 | /* attention : reversed bit order (not with CS8416_01_CS) */ | ||
753 | temp <<= 1; | ||
754 | if (rmh.stat[1] & (1 << i)) | ||
755 | temp |= 1; | ||
756 | } | ||
757 | snd_printdd("read iec958 AES %d byte %d = 0x%x\n", chip->chip_idx, aes_idx, temp); | ||
758 | *aes_bits = temp; | ||
759 | return 0; | ||
760 | } | ||
761 | |||
762 | static int pcxhr_iec958_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
763 | { | ||
764 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | ||
765 | unsigned char aes_bits; | ||
766 | int i, err; | ||
767 | |||
768 | down(&chip->mgr->mixer_mutex); | ||
769 | for(i = 0; i < 5; i++) { | ||
770 | if (kcontrol->private_value == 0) /* playback */ | ||
771 | aes_bits = chip->aes_bits[i]; | ||
772 | else { /* capture */ | ||
773 | err = pcxhr_iec958_capture_byte(chip, i, &aes_bits); | ||
774 | if (err) | ||
775 | break; | ||
776 | } | ||
777 | ucontrol->value.iec958.status[i] = aes_bits; | ||
778 | } | ||
779 | up(&chip->mgr->mixer_mutex); | ||
780 | return 0; | ||
781 | } | ||
782 | |||
783 | static int pcxhr_iec958_mask_get(struct snd_kcontrol *kcontrol, | ||
784 | struct snd_ctl_elem_value *ucontrol) | ||
785 | { | ||
786 | int i; | ||
787 | for (i = 0; i < 5; i++) | ||
788 | ucontrol->value.iec958.status[i] = 0xff; | ||
789 | return 0; | ||
790 | } | ||
791 | |||
792 | static int pcxhr_iec958_update_byte(struct snd_pcxhr *chip, int aes_idx, unsigned char aes_bits) | ||
793 | { | ||
794 | int i, err, cmd; | ||
795 | unsigned char new_bits = aes_bits; | ||
796 | unsigned char old_bits = chip->aes_bits[aes_idx]; | ||
797 | struct pcxhr_rmh rmh; | ||
798 | |||
799 | for (i = 0; i < 8; i++) { | ||
800 | if ((old_bits & 0x01) != (new_bits & 0x01)) { | ||
801 | cmd = chip->chip_idx & 0x03; /* chip index 0..3 */ | ||
802 | if(chip->chip_idx > 3) | ||
803 | /* new bit used if chip_idx>3 (PCX1222HR) */ | ||
804 | cmd |= 1 << 22; | ||
805 | cmd |= ((aes_idx << 3) + i) << 2; /* add bit offset */ | ||
806 | cmd |= (new_bits & 0x01) << 23; /* add bit value */ | ||
807 | pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE); | ||
808 | rmh.cmd[0] |= IO_NUM_REG_CUER; | ||
809 | rmh.cmd[1] = cmd; | ||
810 | rmh.cmd_len = 2; | ||
811 | snd_printdd("write iec958 AES %d byte %d bit %d (cmd %x)\n", | ||
812 | chip->chip_idx, aes_idx, i, cmd); | ||
813 | err = pcxhr_send_msg(chip->mgr, &rmh); | ||
814 | if (err) | ||
815 | return err; | ||
816 | } | ||
817 | old_bits >>= 1; | ||
818 | new_bits >>= 1; | ||
819 | } | ||
820 | chip->aes_bits[aes_idx] = aes_bits; | ||
821 | return 0; | ||
822 | } | ||
823 | |||
824 | static int pcxhr_iec958_put(struct snd_kcontrol *kcontrol, | ||
825 | struct snd_ctl_elem_value *ucontrol) | ||
826 | { | ||
827 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); | ||
828 | int i, changed = 0; | ||
829 | |||
830 | /* playback */ | ||
831 | down(&chip->mgr->mixer_mutex); | ||
832 | for (i = 0; i < 5; i++) { | ||
833 | if (ucontrol->value.iec958.status[i] != chip->aes_bits[i]) { | ||
834 | pcxhr_iec958_update_byte(chip, i, ucontrol->value.iec958.status[i]); | ||
835 | changed = 1; | ||
836 | } | ||
837 | } | ||
838 | up(&chip->mgr->mixer_mutex); | ||
839 | return changed; | ||
840 | } | ||
841 | |||
842 | static struct snd_kcontrol_new pcxhr_control_playback_iec958_mask = { | ||
843 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
844 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
845 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), | ||
846 | .info = pcxhr_iec958_info, | ||
847 | .get = pcxhr_iec958_mask_get | ||
848 | }; | ||
849 | static struct snd_kcontrol_new pcxhr_control_playback_iec958 = { | ||
850 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
851 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), | ||
852 | .info = pcxhr_iec958_info, | ||
853 | .get = pcxhr_iec958_get, | ||
854 | .put = pcxhr_iec958_put, | ||
855 | .private_value = 0 /* playback */ | ||
856 | }; | ||
857 | |||
858 | static struct snd_kcontrol_new pcxhr_control_capture_iec958_mask = { | ||
859 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
860 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
861 | .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,MASK), | ||
862 | .info = pcxhr_iec958_info, | ||
863 | .get = pcxhr_iec958_mask_get | ||
864 | }; | ||
865 | static struct snd_kcontrol_new pcxhr_control_capture_iec958 = { | ||
866 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
867 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
868 | .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT), | ||
869 | .info = pcxhr_iec958_info, | ||
870 | .get = pcxhr_iec958_get, | ||
871 | .private_value = 1 /* capture */ | ||
872 | }; | ||
873 | |||
874 | static void pcxhr_init_audio_levels(struct snd_pcxhr *chip) | ||
875 | { | ||
876 | int i; | ||
877 | |||
878 | for (i = 0; i < 2; i++) { | ||
879 | if (chip->nb_streams_play) { | ||
880 | int j; | ||
881 | /* at boot time the digital volumes are unmuted 0dB */ | ||
882 | for (j = 0; j < PCXHR_PLAYBACK_STREAMS; j++) { | ||
883 | chip->digital_playback_active[j][i] = 1; | ||
884 | chip->digital_playback_volume[j][i] = PCXHR_DIGITAL_ZERO_LEVEL; | ||
885 | } | ||
886 | /* after boot, only two bits are set on the uer interface */ | ||
887 | chip->aes_bits[0] = IEC958_AES0_PROFESSIONAL | IEC958_AES0_PRO_FS_48000; | ||
888 | /* only for test purpose, remove later */ | ||
889 | #ifdef CONFIG_SND_DEBUG | ||
890 | /* analog volumes for playback (is LEVEL_MIN after boot) */ | ||
891 | chip->analog_playback_active[i] = 1; | ||
892 | chip->analog_playback_volume[i] = PCXHR_ANALOG_PLAYBACK_ZERO_LEVEL; | ||
893 | pcxhr_update_analog_audio_level(chip, 0, i); | ||
894 | #endif | ||
895 | /* test end */ | ||
896 | } | ||
897 | if (chip->nb_streams_capt) { | ||
898 | /* at boot time the digital volumes are unmuted 0dB */ | ||
899 | chip->digital_capture_volume[i] = PCXHR_DIGITAL_ZERO_LEVEL; | ||
900 | /* only for test purpose, remove later */ | ||
901 | #ifdef CONFIG_SND_DEBUG | ||
902 | /* analog volumes for playback (is LEVEL_MIN after boot) */ | ||
903 | chip->analog_capture_volume[i] = PCXHR_ANALOG_CAPTURE_ZERO_LEVEL; | ||
904 | pcxhr_update_analog_audio_level(chip, 1, i); | ||
905 | #endif | ||
906 | /* test end */ | ||
907 | } | ||
908 | } | ||
909 | |||
910 | return; | ||
911 | } | ||
912 | |||
913 | |||
914 | int pcxhr_create_mixer(struct pcxhr_mgr *mgr) | ||
915 | { | ||
916 | struct snd_pcxhr *chip; | ||
917 | int err, i; | ||
918 | |||
919 | init_MUTEX(&mgr->mixer_mutex); /* can be in another place */ | ||
920 | |||
921 | for (i = 0; i < mgr->num_cards; i++) { | ||
922 | struct snd_kcontrol_new temp; | ||
923 | chip = mgr->chip[i]; | ||
924 | |||
925 | if (chip->nb_streams_play) { | ||
926 | /* analog output level control */ | ||
927 | temp = pcxhr_control_analog_level; | ||
928 | temp.name = "Master Playback Volume"; | ||
929 | temp.private_value = 0; /* playback */ | ||
930 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) | ||
931 | return err; | ||
932 | /* output mute controls */ | ||
933 | if ((err = snd_ctl_add(chip->card, | ||
934 | snd_ctl_new1(&pcxhr_control_output_switch, | ||
935 | chip))) < 0) | ||
936 | return err; | ||
937 | |||
938 | temp = snd_pcxhr_pcm_vol; | ||
939 | temp.name = "PCM Playback Volume"; | ||
940 | temp.count = PCXHR_PLAYBACK_STREAMS; | ||
941 | temp.private_value = 0; /* playback */ | ||
942 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) | ||
943 | return err; | ||
944 | |||
945 | if ((err = snd_ctl_add(chip->card, | ||
946 | snd_ctl_new1(&pcxhr_control_pcm_switch, | ||
947 | chip))) < 0) | ||
948 | return err; | ||
949 | |||
950 | /* IEC958 controls */ | ||
951 | if ((err = snd_ctl_add(chip->card, | ||
952 | snd_ctl_new1(&pcxhr_control_playback_iec958_mask, | ||
953 | chip))) < 0) | ||
954 | return err; | ||
955 | if ((err = snd_ctl_add(chip->card, | ||
956 | snd_ctl_new1(&pcxhr_control_playback_iec958, | ||
957 | chip))) < 0) | ||
958 | return err; | ||
959 | } | ||
960 | if (chip->nb_streams_capt) { | ||
961 | /* analog input level control only on first two chips !*/ | ||
962 | temp = pcxhr_control_analog_level; | ||
963 | temp.name = "Master Capture Volume"; | ||
964 | temp.private_value = 1; /* capture */ | ||
965 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) | ||
966 | return err; | ||
967 | |||
968 | temp = snd_pcxhr_pcm_vol; | ||
969 | temp.name = "PCM Capture Volume"; | ||
970 | temp.count = 1; | ||
971 | temp.private_value = 1; /* capture */ | ||
972 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) | ||
973 | return err; | ||
974 | /* Audio source */ | ||
975 | if ((err = snd_ctl_add(chip->card, | ||
976 | snd_ctl_new1(&pcxhr_control_audio_src, | ||
977 | chip))) < 0) | ||
978 | return err; | ||
979 | /* IEC958 controls */ | ||
980 | if ((err = snd_ctl_add(chip->card, | ||
981 | snd_ctl_new1(&pcxhr_control_capture_iec958_mask, | ||
982 | chip))) < 0) | ||
983 | return err; | ||
984 | if ((err = snd_ctl_add(chip->card, | ||
985 | snd_ctl_new1(&pcxhr_control_capture_iec958, | ||
986 | chip))) < 0) | ||
987 | return err; | ||
988 | } | ||
989 | /* monitoring only if playback and capture device available */ | ||
990 | if (chip->nb_streams_capt > 0 && chip->nb_streams_play > 0) { | ||
991 | /* monitoring */ | ||
992 | if ((err = snd_ctl_add(chip->card, | ||
993 | snd_ctl_new1(&pcxhr_control_monitor_vol, | ||
994 | chip))) < 0) | ||
995 | return err; | ||
996 | if ((err = snd_ctl_add(chip->card, | ||
997 | snd_ctl_new1(&pcxhr_control_monitor_sw, | ||
998 | chip))) < 0) | ||
999 | return err; | ||
1000 | } | ||
1001 | |||
1002 | if (i == 0) { | ||
1003 | /* clock mode only one control per pcxhr */ | ||
1004 | if ((err = snd_ctl_add(chip->card, | ||
1005 | snd_ctl_new1(&pcxhr_control_clock_type, | ||
1006 | mgr))) < 0) | ||
1007 | return err; | ||
1008 | /* non standard control used to scan the external clock presence/frequencies */ | ||
1009 | if ((err = snd_ctl_add(chip->card, | ||
1010 | snd_ctl_new1(&pcxhr_control_clock_rate, | ||
1011 | mgr))) < 0) | ||
1012 | return err; | ||
1013 | } | ||
1014 | |||
1015 | /* init values for the mixer data */ | ||
1016 | pcxhr_init_audio_levels(chip); | ||
1017 | } | ||
1018 | |||
1019 | return 0; | ||
1020 | } | ||