1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | #define __NO_VERSION__ |
3 | /* |
4 | * Driver for Digigram pcxhr compatible soundcards |
5 | * |
6 | * mixer callbacks |
7 | * |
8 | * Copyright (c) 2004 by Digigram <alsa@digigram.com> |
9 | */ |
10 | |
11 | #include <linux/time.h> |
12 | #include <linux/interrupt.h> |
13 | #include <linux/init.h> |
14 | #include <linux/mutex.h> |
15 | #include <sound/core.h> |
16 | #include "pcxhr.h" |
17 | #include "pcxhr_hwdep.h" |
18 | #include "pcxhr_core.h" |
19 | #include <sound/control.h> |
20 | #include <sound/tlv.h> |
21 | #include <sound/asoundef.h> |
22 | #include "pcxhr_mixer.h" |
23 | #include "pcxhr_mix22.h" |
24 | |
25 | #define PCXHR_LINE_CAPTURE_LEVEL_MIN 0 /* -112.0 dB */ |
26 | #define PCXHR_LINE_CAPTURE_LEVEL_MAX 255 /* +15.5 dB */ |
27 | #define PCXHR_LINE_CAPTURE_ZERO_LEVEL 224 /* 0.0 dB ( 0 dBu -> 0 dBFS ) */ |
28 | |
29 | #define PCXHR_LINE_PLAYBACK_LEVEL_MIN 0 /* -104.0 dB */ |
30 | #define PCXHR_LINE_PLAYBACK_LEVEL_MAX 128 /* +24.0 dB */ |
31 | #define PCXHR_LINE_PLAYBACK_ZERO_LEVEL 104 /* 0.0 dB ( 0 dBFS -> 0 dBu ) */ |
32 | |
33 | static const DECLARE_TLV_DB_SCALE(db_scale_analog_capture, -11200, 50, 1550); |
34 | static const DECLARE_TLV_DB_SCALE(db_scale_analog_playback, -10400, 100, 2400); |
35 | |
36 | static const DECLARE_TLV_DB_SCALE(db_scale_a_hr222_capture, -11150, 50, 1600); |
37 | static const DECLARE_TLV_DB_SCALE(db_scale_a_hr222_playback, -2550, 50, 2400); |
38 | |
39 | static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, |
40 | int is_capture, int channel) |
41 | { |
42 | int err, vol; |
43 | struct pcxhr_rmh rmh; |
44 | |
45 | pcxhr_init_rmh(rmh: &rmh, cmd: CMD_ACCESS_IO_WRITE); |
46 | if (is_capture) { |
47 | rmh.cmd[0] |= IO_NUM_REG_IN_ANA_LEVEL; |
48 | rmh.cmd[2] = chip->analog_capture_volume[channel]; |
49 | } else { |
50 | rmh.cmd[0] |= IO_NUM_REG_OUT_ANA_LEVEL; |
51 | if (chip->analog_playback_active[channel]) |
52 | vol = chip->analog_playback_volume[channel]; |
53 | else |
54 | vol = PCXHR_LINE_PLAYBACK_LEVEL_MIN; |
55 | /* playback analog levels are inversed */ |
56 | rmh.cmd[2] = PCXHR_LINE_PLAYBACK_LEVEL_MAX - vol; |
57 | } |
58 | rmh.cmd[1] = 1 << ((2 * chip->chip_idx) + channel); /* audio mask */ |
59 | rmh.cmd_len = 3; |
60 | err = pcxhr_send_msg(mgr: chip->mgr, rmh: &rmh); |
61 | if (err < 0) { |
62 | dev_dbg(chip->card->dev, |
63 | "error update_analog_audio_level card(%d)" |
64 | " is_capture(%d) err(%x)\n" , |
65 | chip->chip_idx, is_capture, err); |
66 | return -EINVAL; |
67 | } |
68 | return 0; |
69 | } |
70 | |
71 | /* |
72 | * analog level control |
73 | */ |
74 | static int pcxhr_analog_vol_info(struct snd_kcontrol *kcontrol, |
75 | struct snd_ctl_elem_info *uinfo) |
76 | { |
77 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); |
78 | |
79 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
80 | uinfo->count = 2; |
81 | if (kcontrol->private_value == 0) { /* playback */ |
82 | if (chip->mgr->is_hr_stereo) { |
83 | uinfo->value.integer.min = |
84 | HR222_LINE_PLAYBACK_LEVEL_MIN; /* -25 dB */ |
85 | uinfo->value.integer.max = |
86 | HR222_LINE_PLAYBACK_LEVEL_MAX; /* +24 dB */ |
87 | } else { |
88 | uinfo->value.integer.min = |
89 | PCXHR_LINE_PLAYBACK_LEVEL_MIN; /*-104 dB */ |
90 | uinfo->value.integer.max = |
91 | PCXHR_LINE_PLAYBACK_LEVEL_MAX; /* +24 dB */ |
92 | } |
93 | } else { /* capture */ |
94 | if (chip->mgr->is_hr_stereo) { |
95 | uinfo->value.integer.min = |
96 | HR222_LINE_CAPTURE_LEVEL_MIN; /*-112 dB */ |
97 | uinfo->value.integer.max = |
98 | HR222_LINE_CAPTURE_LEVEL_MAX; /* +15.5 dB */ |
99 | } else { |
100 | uinfo->value.integer.min = |
101 | PCXHR_LINE_CAPTURE_LEVEL_MIN; /*-112 dB */ |
102 | uinfo->value.integer.max = |
103 | PCXHR_LINE_CAPTURE_LEVEL_MAX; /* +15.5 dB */ |
104 | } |
105 | } |
106 | return 0; |
107 | } |
108 | |
109 | static int pcxhr_analog_vol_get(struct snd_kcontrol *kcontrol, |
110 | struct snd_ctl_elem_value *ucontrol) |
111 | { |
112 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); |
113 | mutex_lock(&chip->mgr->mixer_mutex); |
114 | if (kcontrol->private_value == 0) { /* playback */ |
115 | ucontrol->value.integer.value[0] = chip->analog_playback_volume[0]; |
116 | ucontrol->value.integer.value[1] = chip->analog_playback_volume[1]; |
117 | } else { /* capture */ |
118 | ucontrol->value.integer.value[0] = chip->analog_capture_volume[0]; |
119 | ucontrol->value.integer.value[1] = chip->analog_capture_volume[1]; |
120 | } |
121 | mutex_unlock(lock: &chip->mgr->mixer_mutex); |
122 | return 0; |
123 | } |
124 | |
125 | static int pcxhr_analog_vol_put(struct snd_kcontrol *kcontrol, |
126 | struct snd_ctl_elem_value *ucontrol) |
127 | { |
128 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); |
129 | int changed = 0; |
130 | int is_capture, i; |
131 | |
132 | mutex_lock(&chip->mgr->mixer_mutex); |
133 | is_capture = (kcontrol->private_value != 0); |
134 | for (i = 0; i < 2; i++) { |
135 | int new_volume = ucontrol->value.integer.value[i]; |
136 | int *stored_volume = is_capture ? |
137 | &chip->analog_capture_volume[i] : |
138 | &chip->analog_playback_volume[i]; |
139 | if (is_capture) { |
140 | if (chip->mgr->is_hr_stereo) { |
141 | if (new_volume < HR222_LINE_CAPTURE_LEVEL_MIN || |
142 | new_volume > HR222_LINE_CAPTURE_LEVEL_MAX) |
143 | continue; |
144 | } else { |
145 | if (new_volume < PCXHR_LINE_CAPTURE_LEVEL_MIN || |
146 | new_volume > PCXHR_LINE_CAPTURE_LEVEL_MAX) |
147 | continue; |
148 | } |
149 | } else { |
150 | if (chip->mgr->is_hr_stereo) { |
151 | if (new_volume < HR222_LINE_PLAYBACK_LEVEL_MIN || |
152 | new_volume > HR222_LINE_PLAYBACK_LEVEL_MAX) |
153 | continue; |
154 | } else { |
155 | if (new_volume < PCXHR_LINE_PLAYBACK_LEVEL_MIN || |
156 | new_volume > PCXHR_LINE_PLAYBACK_LEVEL_MAX) |
157 | continue; |
158 | } |
159 | } |
160 | if (*stored_volume != new_volume) { |
161 | *stored_volume = new_volume; |
162 | changed = 1; |
163 | if (chip->mgr->is_hr_stereo) |
164 | hr222_update_analog_audio_level(chip, |
165 | is_capture, channel: i); |
166 | else |
167 | pcxhr_update_analog_audio_level(chip, |
168 | is_capture, channel: i); |
169 | } |
170 | } |
171 | mutex_unlock(lock: &chip->mgr->mixer_mutex); |
172 | return changed; |
173 | } |
174 | |
175 | static const struct snd_kcontrol_new pcxhr_control_analog_level = { |
176 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
177 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | |
178 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), |
179 | /* name will be filled later */ |
180 | .info = pcxhr_analog_vol_info, |
181 | .get = pcxhr_analog_vol_get, |
182 | .put = pcxhr_analog_vol_put, |
183 | /* tlv will be filled later */ |
184 | }; |
185 | |
186 | /* shared */ |
187 | |
188 | #define pcxhr_sw_info snd_ctl_boolean_stereo_info |
189 | |
190 | static int pcxhr_audio_sw_get(struct snd_kcontrol *kcontrol, |
191 | struct snd_ctl_elem_value *ucontrol) |
192 | { |
193 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); |
194 | |
195 | mutex_lock(&chip->mgr->mixer_mutex); |
196 | ucontrol->value.integer.value[0] = chip->analog_playback_active[0]; |
197 | ucontrol->value.integer.value[1] = chip->analog_playback_active[1]; |
198 | mutex_unlock(lock: &chip->mgr->mixer_mutex); |
199 | return 0; |
200 | } |
201 | |
202 | static int pcxhr_audio_sw_put(struct snd_kcontrol *kcontrol, |
203 | struct snd_ctl_elem_value *ucontrol) |
204 | { |
205 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); |
206 | int i, changed = 0; |
207 | mutex_lock(&chip->mgr->mixer_mutex); |
208 | for(i = 0; i < 2; i++) { |
209 | if (chip->analog_playback_active[i] != |
210 | ucontrol->value.integer.value[i]) { |
211 | chip->analog_playback_active[i] = |
212 | !!ucontrol->value.integer.value[i]; |
213 | changed = 1; |
214 | /* update playback levels */ |
215 | if (chip->mgr->is_hr_stereo) |
216 | hr222_update_analog_audio_level(chip, is_capture: 0, channel: i); |
217 | else |
218 | pcxhr_update_analog_audio_level(chip, is_capture: 0, channel: i); |
219 | } |
220 | } |
221 | mutex_unlock(lock: &chip->mgr->mixer_mutex); |
222 | return changed; |
223 | } |
224 | |
225 | static const struct snd_kcontrol_new pcxhr_control_output_switch = { |
226 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
227 | .name = "Master Playback Switch" , |
228 | .info = pcxhr_sw_info, /* shared */ |
229 | .get = pcxhr_audio_sw_get, |
230 | .put = pcxhr_audio_sw_put |
231 | }; |
232 | |
233 | |
234 | #define PCXHR_DIGITAL_LEVEL_MIN 0x000 /* -110 dB */ |
235 | #define PCXHR_DIGITAL_LEVEL_MAX 0x1ff /* +18 dB */ |
236 | #define PCXHR_DIGITAL_ZERO_LEVEL 0x1b7 /* 0 dB */ |
237 | |
238 | static const DECLARE_TLV_DB_SCALE(db_scale_digital, -10975, 25, 1800); |
239 | |
240 | #define MORE_THAN_ONE_STREAM_LEVEL 0x000001 |
241 | #define VALID_STREAM_PAN_LEVEL_MASK 0x800000 |
242 | #define VALID_STREAM_LEVEL_MASK 0x400000 |
243 | #define VALID_STREAM_LEVEL_1_MASK 0x200000 |
244 | #define VALID_STREAM_LEVEL_2_MASK 0x100000 |
245 | |
246 | static int pcxhr_update_playback_stream_level(struct snd_pcxhr* chip, int idx) |
247 | { |
248 | int err; |
249 | struct pcxhr_rmh rmh; |
250 | struct pcxhr_pipe *pipe = &chip->playback_pipe; |
251 | int left, right; |
252 | |
253 | if (chip->digital_playback_active[idx][0]) |
254 | left = chip->digital_playback_volume[idx][0]; |
255 | else |
256 | left = PCXHR_DIGITAL_LEVEL_MIN; |
257 | if (chip->digital_playback_active[idx][1]) |
258 | right = chip->digital_playback_volume[idx][1]; |
259 | else |
260 | right = PCXHR_DIGITAL_LEVEL_MIN; |
261 | |
262 | pcxhr_init_rmh(rmh: &rmh, cmd: CMD_STREAM_OUT_LEVEL_ADJUST); |
263 | /* add pipe and stream mask */ |
264 | pcxhr_set_pipe_cmd_params(rmh: &rmh, capture: 0, param1: pipe->first_audio, param2: 0, param3: 1<<idx); |
265 | /* volume left->left / right->right panoramic level */ |
266 | rmh.cmd[0] |= MORE_THAN_ONE_STREAM_LEVEL; |
267 | rmh.cmd[2] = VALID_STREAM_PAN_LEVEL_MASK | VALID_STREAM_LEVEL_1_MASK; |
268 | rmh.cmd[2] |= (left << 10); |
269 | rmh.cmd[3] = VALID_STREAM_PAN_LEVEL_MASK | VALID_STREAM_LEVEL_2_MASK; |
270 | rmh.cmd[3] |= right; |
271 | rmh.cmd_len = 4; |
272 | |
273 | err = pcxhr_send_msg(mgr: chip->mgr, rmh: &rmh); |
274 | if (err < 0) { |
275 | dev_dbg(chip->card->dev, "error update_playback_stream_level " |
276 | "card(%d) err(%x)\n" , chip->chip_idx, err); |
277 | return -EINVAL; |
278 | } |
279 | return 0; |
280 | } |
281 | |
282 | #define AUDIO_IO_HAS_MUTE_LEVEL 0x400000 |
283 | #define AUDIO_IO_HAS_MUTE_MONITOR_1 0x200000 |
284 | #define VALID_AUDIO_IO_DIGITAL_LEVEL 0x000001 |
285 | #define VALID_AUDIO_IO_MONITOR_LEVEL 0x000002 |
286 | #define VALID_AUDIO_IO_MUTE_LEVEL 0x000004 |
287 | #define VALID_AUDIO_IO_MUTE_MONITOR_1 0x000008 |
288 | |
289 | static int pcxhr_update_audio_pipe_level(struct snd_pcxhr *chip, |
290 | int capture, int channel) |
291 | { |
292 | int err; |
293 | struct pcxhr_rmh rmh; |
294 | struct pcxhr_pipe *pipe; |
295 | |
296 | if (capture) |
297 | pipe = &chip->capture_pipe[0]; |
298 | else |
299 | pipe = &chip->playback_pipe; |
300 | |
301 | pcxhr_init_rmh(rmh: &rmh, cmd: CMD_AUDIO_LEVEL_ADJUST); |
302 | /* add channel mask */ |
303 | pcxhr_set_pipe_cmd_params(rmh: &rmh, capture, param1: 0, param2: 0, |
304 | param3: 1 << (channel + pipe->first_audio)); |
305 | /* TODO : if mask (3 << pipe->first_audio) is used, left and right |
306 | * channel will be programmed to the same params */ |
307 | if (capture) { |
308 | rmh.cmd[0] |= VALID_AUDIO_IO_DIGITAL_LEVEL; |
309 | /* VALID_AUDIO_IO_MUTE_LEVEL not yet handled |
310 | * (capture pipe level) */ |
311 | rmh.cmd[2] = chip->digital_capture_volume[channel]; |
312 | } else { |
313 | rmh.cmd[0] |= VALID_AUDIO_IO_MONITOR_LEVEL | |
314 | VALID_AUDIO_IO_MUTE_MONITOR_1; |
315 | /* VALID_AUDIO_IO_DIGITAL_LEVEL and VALID_AUDIO_IO_MUTE_LEVEL |
316 | * not yet handled (playback pipe level) |
317 | */ |
318 | rmh.cmd[2] = chip->monitoring_volume[channel] << 10; |
319 | if (chip->monitoring_active[channel] == 0) |
320 | rmh.cmd[2] |= AUDIO_IO_HAS_MUTE_MONITOR_1; |
321 | } |
322 | rmh.cmd_len = 3; |
323 | |
324 | err = pcxhr_send_msg(mgr: chip->mgr, rmh: &rmh); |
325 | if (err < 0) { |
326 | dev_dbg(chip->card->dev, |
327 | "error update_audio_level(%d) err=%x\n" , |
328 | chip->chip_idx, err); |
329 | return -EINVAL; |
330 | } |
331 | return 0; |
332 | } |
333 | |
334 | |
335 | /* shared */ |
336 | static int pcxhr_digital_vol_info(struct snd_kcontrol *kcontrol, |
337 | struct snd_ctl_elem_info *uinfo) |
338 | { |
339 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
340 | uinfo->count = 2; |
341 | uinfo->value.integer.min = PCXHR_DIGITAL_LEVEL_MIN; /* -109.5 dB */ |
342 | uinfo->value.integer.max = PCXHR_DIGITAL_LEVEL_MAX; /* 18.0 dB */ |
343 | return 0; |
344 | } |
345 | |
346 | |
347 | static int pcxhr_pcm_vol_get(struct snd_kcontrol *kcontrol, |
348 | struct snd_ctl_elem_value *ucontrol) |
349 | { |
350 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); |
351 | int idx = snd_ctl_get_ioffidx(kctl: kcontrol, id: &ucontrol->id); /* index */ |
352 | int *stored_volume; |
353 | int is_capture = kcontrol->private_value; |
354 | |
355 | mutex_lock(&chip->mgr->mixer_mutex); |
356 | if (is_capture) /* digital capture */ |
357 | stored_volume = chip->digital_capture_volume; |
358 | else /* digital playback */ |
359 | stored_volume = chip->digital_playback_volume[idx]; |
360 | ucontrol->value.integer.value[0] = stored_volume[0]; |
361 | ucontrol->value.integer.value[1] = stored_volume[1]; |
362 | mutex_unlock(lock: &chip->mgr->mixer_mutex); |
363 | return 0; |
364 | } |
365 | |
366 | static int pcxhr_pcm_vol_put(struct snd_kcontrol *kcontrol, |
367 | struct snd_ctl_elem_value *ucontrol) |
368 | { |
369 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); |
370 | int idx = snd_ctl_get_ioffidx(kctl: kcontrol, id: &ucontrol->id); /* index */ |
371 | int changed = 0; |
372 | int is_capture = kcontrol->private_value; |
373 | int *stored_volume; |
374 | int i; |
375 | |
376 | mutex_lock(&chip->mgr->mixer_mutex); |
377 | if (is_capture) /* digital capture */ |
378 | stored_volume = chip->digital_capture_volume; |
379 | else /* digital playback */ |
380 | stored_volume = chip->digital_playback_volume[idx]; |
381 | for (i = 0; i < 2; i++) { |
382 | int vol = ucontrol->value.integer.value[i]; |
383 | if (vol < PCXHR_DIGITAL_LEVEL_MIN || |
384 | vol > PCXHR_DIGITAL_LEVEL_MAX) |
385 | continue; |
386 | if (stored_volume[i] != vol) { |
387 | stored_volume[i] = vol; |
388 | changed = 1; |
389 | if (is_capture) /* update capture volume */ |
390 | pcxhr_update_audio_pipe_level(chip, capture: 1, channel: i); |
391 | } |
392 | } |
393 | if (!is_capture && changed) /* update playback volume */ |
394 | pcxhr_update_playback_stream_level(chip, idx); |
395 | mutex_unlock(lock: &chip->mgr->mixer_mutex); |
396 | return changed; |
397 | } |
398 | |
399 | static const struct snd_kcontrol_new snd_pcxhr_pcm_vol = |
400 | { |
401 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
402 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | |
403 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), |
404 | /* name will be filled later */ |
405 | /* count will be filled later */ |
406 | .info = pcxhr_digital_vol_info, /* shared */ |
407 | .get = pcxhr_pcm_vol_get, |
408 | .put = pcxhr_pcm_vol_put, |
409 | .tlv = { .p = db_scale_digital }, |
410 | }; |
411 | |
412 | |
413 | static int pcxhr_pcm_sw_get(struct snd_kcontrol *kcontrol, |
414 | struct snd_ctl_elem_value *ucontrol) |
415 | { |
416 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); |
417 | int idx = snd_ctl_get_ioffidx(kctl: kcontrol, id: &ucontrol->id); /* index */ |
418 | |
419 | mutex_lock(&chip->mgr->mixer_mutex); |
420 | ucontrol->value.integer.value[0] = chip->digital_playback_active[idx][0]; |
421 | ucontrol->value.integer.value[1] = chip->digital_playback_active[idx][1]; |
422 | mutex_unlock(lock: &chip->mgr->mixer_mutex); |
423 | return 0; |
424 | } |
425 | |
426 | static int pcxhr_pcm_sw_put(struct snd_kcontrol *kcontrol, |
427 | struct snd_ctl_elem_value *ucontrol) |
428 | { |
429 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); |
430 | int changed = 0; |
431 | int idx = snd_ctl_get_ioffidx(kctl: kcontrol, id: &ucontrol->id); /* index */ |
432 | int i, j; |
433 | |
434 | mutex_lock(&chip->mgr->mixer_mutex); |
435 | j = idx; |
436 | for (i = 0; i < 2; i++) { |
437 | if (chip->digital_playback_active[j][i] != |
438 | ucontrol->value.integer.value[i]) { |
439 | chip->digital_playback_active[j][i] = |
440 | !!ucontrol->value.integer.value[i]; |
441 | changed = 1; |
442 | } |
443 | } |
444 | if (changed) |
445 | pcxhr_update_playback_stream_level(chip, idx); |
446 | mutex_unlock(lock: &chip->mgr->mixer_mutex); |
447 | return changed; |
448 | } |
449 | |
450 | static const struct snd_kcontrol_new pcxhr_control_pcm_switch = { |
451 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
452 | .name = "PCM Playback Switch" , |
453 | .count = PCXHR_PLAYBACK_STREAMS, |
454 | .info = pcxhr_sw_info, /* shared */ |
455 | .get = pcxhr_pcm_sw_get, |
456 | .put = pcxhr_pcm_sw_put |
457 | }; |
458 | |
459 | |
460 | /* |
461 | * monitoring level control |
462 | */ |
463 | |
464 | static int pcxhr_monitor_vol_get(struct snd_kcontrol *kcontrol, |
465 | struct snd_ctl_elem_value *ucontrol) |
466 | { |
467 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); |
468 | mutex_lock(&chip->mgr->mixer_mutex); |
469 | ucontrol->value.integer.value[0] = chip->monitoring_volume[0]; |
470 | ucontrol->value.integer.value[1] = chip->monitoring_volume[1]; |
471 | mutex_unlock(lock: &chip->mgr->mixer_mutex); |
472 | return 0; |
473 | } |
474 | |
475 | static int pcxhr_monitor_vol_put(struct snd_kcontrol *kcontrol, |
476 | struct snd_ctl_elem_value *ucontrol) |
477 | { |
478 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); |
479 | int changed = 0; |
480 | int i; |
481 | |
482 | mutex_lock(&chip->mgr->mixer_mutex); |
483 | for (i = 0; i < 2; i++) { |
484 | if (chip->monitoring_volume[i] != |
485 | ucontrol->value.integer.value[i]) { |
486 | chip->monitoring_volume[i] = |
487 | ucontrol->value.integer.value[i]; |
488 | if (chip->monitoring_active[i]) |
489 | /* update monitoring volume and mute */ |
490 | /* do only when monitoring is unmuted */ |
491 | pcxhr_update_audio_pipe_level(chip, capture: 0, channel: i); |
492 | changed = 1; |
493 | } |
494 | } |
495 | mutex_unlock(lock: &chip->mgr->mixer_mutex); |
496 | return changed; |
497 | } |
498 | |
499 | static const struct snd_kcontrol_new pcxhr_control_monitor_vol = { |
500 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
501 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | |
502 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), |
503 | .name = "Monitoring Playback Volume" , |
504 | .info = pcxhr_digital_vol_info, /* shared */ |
505 | .get = pcxhr_monitor_vol_get, |
506 | .put = pcxhr_monitor_vol_put, |
507 | .tlv = { .p = db_scale_digital }, |
508 | }; |
509 | |
510 | /* |
511 | * monitoring switch control |
512 | */ |
513 | |
514 | static int pcxhr_monitor_sw_get(struct snd_kcontrol *kcontrol, |
515 | struct snd_ctl_elem_value *ucontrol) |
516 | { |
517 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); |
518 | mutex_lock(&chip->mgr->mixer_mutex); |
519 | ucontrol->value.integer.value[0] = chip->monitoring_active[0]; |
520 | ucontrol->value.integer.value[1] = chip->monitoring_active[1]; |
521 | mutex_unlock(lock: &chip->mgr->mixer_mutex); |
522 | return 0; |
523 | } |
524 | |
525 | static int pcxhr_monitor_sw_put(struct snd_kcontrol *kcontrol, |
526 | struct snd_ctl_elem_value *ucontrol) |
527 | { |
528 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); |
529 | int changed = 0; |
530 | int i; |
531 | |
532 | mutex_lock(&chip->mgr->mixer_mutex); |
533 | for (i = 0; i < 2; i++) { |
534 | if (chip->monitoring_active[i] != |
535 | ucontrol->value.integer.value[i]) { |
536 | chip->monitoring_active[i] = |
537 | !!ucontrol->value.integer.value[i]; |
538 | changed |= (1<<i); /* mask 0x01 and 0x02 */ |
539 | } |
540 | } |
541 | if (changed & 0x01) |
542 | /* update left monitoring volume and mute */ |
543 | pcxhr_update_audio_pipe_level(chip, capture: 0, channel: 0); |
544 | if (changed & 0x02) |
545 | /* update right monitoring volume and mute */ |
546 | pcxhr_update_audio_pipe_level(chip, capture: 0, channel: 1); |
547 | |
548 | mutex_unlock(lock: &chip->mgr->mixer_mutex); |
549 | return (changed != 0); |
550 | } |
551 | |
552 | static const struct snd_kcontrol_new pcxhr_control_monitor_sw = { |
553 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
554 | .name = "Monitoring Playback Switch" , |
555 | .info = pcxhr_sw_info, /* shared */ |
556 | .get = pcxhr_monitor_sw_get, |
557 | .put = pcxhr_monitor_sw_put |
558 | }; |
559 | |
560 | |
561 | |
562 | /* |
563 | * audio source select |
564 | */ |
565 | #define PCXHR_SOURCE_AUDIO01_UER 0x000100 |
566 | #define PCXHR_SOURCE_AUDIO01_SYNC 0x000200 |
567 | #define PCXHR_SOURCE_AUDIO23_UER 0x000400 |
568 | #define PCXHR_SOURCE_AUDIO45_UER 0x001000 |
569 | #define PCXHR_SOURCE_AUDIO67_UER 0x040000 |
570 | |
571 | static int pcxhr_set_audio_source(struct snd_pcxhr* chip) |
572 | { |
573 | struct pcxhr_rmh rmh; |
574 | unsigned int mask, reg; |
575 | unsigned int codec; |
576 | int err, changed; |
577 | |
578 | switch (chip->chip_idx) { |
579 | case 0 : mask = PCXHR_SOURCE_AUDIO01_UER; codec = CS8420_01_CS; break; |
580 | case 1 : mask = PCXHR_SOURCE_AUDIO23_UER; codec = CS8420_23_CS; break; |
581 | case 2 : mask = PCXHR_SOURCE_AUDIO45_UER; codec = CS8420_45_CS; break; |
582 | case 3 : mask = PCXHR_SOURCE_AUDIO67_UER; codec = CS8420_67_CS; break; |
583 | default: return -EINVAL; |
584 | } |
585 | if (chip->audio_capture_source != 0) { |
586 | reg = mask; /* audio source from digital plug */ |
587 | } else { |
588 | reg = 0; /* audio source from analog plug */ |
589 | } |
590 | /* set the input source */ |
591 | pcxhr_write_io_num_reg_cont(mgr: chip->mgr, mask, value: reg, changed: &changed); |
592 | /* resync them (otherwise channel inversion possible) */ |
593 | if (changed) { |
594 | pcxhr_init_rmh(rmh: &rmh, cmd: CMD_RESYNC_AUDIO_INPUTS); |
595 | rmh.cmd[0] |= (1 << chip->chip_idx); |
596 | err = pcxhr_send_msg(mgr: chip->mgr, rmh: &rmh); |
597 | if (err) |
598 | return err; |
599 | } |
600 | if (chip->mgr->board_aes_in_192k) { |
601 | int i; |
602 | unsigned int src_config = 0xC0; |
603 | /* update all src configs with one call */ |
604 | for (i = 0; (i < 4) && (i < chip->mgr->capture_chips); i++) { |
605 | if (chip->mgr->chip[i]->audio_capture_source == 2) |
606 | src_config |= (1 << (3 - i)); |
607 | } |
608 | /* set codec SRC on off */ |
609 | pcxhr_init_rmh(rmh: &rmh, cmd: CMD_ACCESS_IO_WRITE); |
610 | rmh.cmd_len = 2; |
611 | rmh.cmd[0] |= IO_NUM_REG_CONFIG_SRC; |
612 | rmh.cmd[1] = src_config; |
613 | err = pcxhr_send_msg(mgr: chip->mgr, rmh: &rmh); |
614 | } else { |
615 | int use_src = 0; |
616 | if (chip->audio_capture_source == 2) |
617 | use_src = 1; |
618 | /* set codec SRC on off */ |
619 | pcxhr_init_rmh(rmh: &rmh, cmd: CMD_ACCESS_IO_WRITE); |
620 | rmh.cmd_len = 3; |
621 | rmh.cmd[0] |= IO_NUM_UER_CHIP_REG; |
622 | rmh.cmd[1] = codec; |
623 | rmh.cmd[2] = ((CS8420_DATA_FLOW_CTL & CHIP_SIG_AND_MAP_SPI) | |
624 | (use_src ? 0x41 : 0x54)); |
625 | err = pcxhr_send_msg(mgr: chip->mgr, rmh: &rmh); |
626 | if (err) |
627 | return err; |
628 | rmh.cmd[2] = ((CS8420_CLOCK_SRC_CTL & CHIP_SIG_AND_MAP_SPI) | |
629 | (use_src ? 0x41 : 0x49)); |
630 | err = pcxhr_send_msg(mgr: chip->mgr, rmh: &rmh); |
631 | } |
632 | return err; |
633 | } |
634 | |
635 | static int pcxhr_audio_src_info(struct snd_kcontrol *kcontrol, |
636 | struct snd_ctl_elem_info *uinfo) |
637 | { |
638 | static const char *texts[5] = { |
639 | "Line" , "Digital" , "Digi+SRC" , "Mic" , "Line+Mic" |
640 | }; |
641 | int i; |
642 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); |
643 | |
644 | i = 2; /* no SRC, no Mic available */ |
645 | if (chip->mgr->board_has_aes1) { |
646 | i = 3; /* SRC available */ |
647 | if (chip->mgr->board_has_mic) |
648 | i = 5; /* Mic and MicroMix available */ |
649 | } |
650 | return snd_ctl_enum_info(info: uinfo, channels: 1, items: i, names: texts); |
651 | } |
652 | |
653 | static int pcxhr_audio_src_get(struct snd_kcontrol *kcontrol, |
654 | struct snd_ctl_elem_value *ucontrol) |
655 | { |
656 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); |
657 | ucontrol->value.enumerated.item[0] = chip->audio_capture_source; |
658 | return 0; |
659 | } |
660 | |
661 | static int pcxhr_audio_src_put(struct snd_kcontrol *kcontrol, |
662 | struct snd_ctl_elem_value *ucontrol) |
663 | { |
664 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); |
665 | int ret = 0; |
666 | int i = 2; /* no SRC, no Mic available */ |
667 | if (chip->mgr->board_has_aes1) { |
668 | i = 3; /* SRC available */ |
669 | if (chip->mgr->board_has_mic) |
670 | i = 5; /* Mic and MicroMix available */ |
671 | } |
672 | if (ucontrol->value.enumerated.item[0] >= i) |
673 | return -EINVAL; |
674 | mutex_lock(&chip->mgr->mixer_mutex); |
675 | if (chip->audio_capture_source != ucontrol->value.enumerated.item[0]) { |
676 | chip->audio_capture_source = ucontrol->value.enumerated.item[0]; |
677 | if (chip->mgr->is_hr_stereo) |
678 | hr222_set_audio_source(chip); |
679 | else |
680 | pcxhr_set_audio_source(chip); |
681 | ret = 1; |
682 | } |
683 | mutex_unlock(lock: &chip->mgr->mixer_mutex); |
684 | return ret; |
685 | } |
686 | |
687 | static const struct snd_kcontrol_new pcxhr_control_audio_src = { |
688 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
689 | .name = "Capture Source" , |
690 | .info = pcxhr_audio_src_info, |
691 | .get = pcxhr_audio_src_get, |
692 | .put = pcxhr_audio_src_put, |
693 | }; |
694 | |
695 | |
696 | /* |
697 | * clock type selection |
698 | * enum pcxhr_clock_type { |
699 | * PCXHR_CLOCK_TYPE_INTERNAL = 0, |
700 | * PCXHR_CLOCK_TYPE_WORD_CLOCK, |
701 | * PCXHR_CLOCK_TYPE_AES_SYNC, |
702 | * PCXHR_CLOCK_TYPE_AES_1, |
703 | * PCXHR_CLOCK_TYPE_AES_2, |
704 | * PCXHR_CLOCK_TYPE_AES_3, |
705 | * PCXHR_CLOCK_TYPE_AES_4, |
706 | * PCXHR_CLOCK_TYPE_MAX = PCXHR_CLOCK_TYPE_AES_4, |
707 | * HR22_CLOCK_TYPE_INTERNAL = PCXHR_CLOCK_TYPE_INTERNAL, |
708 | * HR22_CLOCK_TYPE_AES_SYNC, |
709 | * HR22_CLOCK_TYPE_AES_1, |
710 | * HR22_CLOCK_TYPE_MAX = HR22_CLOCK_TYPE_AES_1, |
711 | * }; |
712 | */ |
713 | |
714 | static int pcxhr_clock_type_info(struct snd_kcontrol *kcontrol, |
715 | struct snd_ctl_elem_info *uinfo) |
716 | { |
717 | static const char *textsPCXHR[7] = { |
718 | "Internal" , "WordClock" , "AES Sync" , |
719 | "AES 1" , "AES 2" , "AES 3" , "AES 4" |
720 | }; |
721 | static const char *textsHR22[3] = { |
722 | "Internal" , "AES Sync" , "AES 1" |
723 | }; |
724 | const char **texts; |
725 | struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); |
726 | int clock_items = 2; /* at least Internal and AES Sync clock */ |
727 | if (mgr->board_has_aes1) { |
728 | clock_items += mgr->capture_chips; /* add AES x */ |
729 | if (!mgr->is_hr_stereo) |
730 | clock_items += 1; /* add word clock */ |
731 | } |
732 | if (mgr->is_hr_stereo) { |
733 | texts = textsHR22; |
734 | snd_BUG_ON(clock_items > (HR22_CLOCK_TYPE_MAX+1)); |
735 | } else { |
736 | texts = textsPCXHR; |
737 | snd_BUG_ON(clock_items > (PCXHR_CLOCK_TYPE_MAX+1)); |
738 | } |
739 | return snd_ctl_enum_info(info: uinfo, channels: 1, items: clock_items, names: texts); |
740 | } |
741 | |
742 | static int pcxhr_clock_type_get(struct snd_kcontrol *kcontrol, |
743 | struct snd_ctl_elem_value *ucontrol) |
744 | { |
745 | struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); |
746 | ucontrol->value.enumerated.item[0] = mgr->use_clock_type; |
747 | return 0; |
748 | } |
749 | |
750 | static int pcxhr_clock_type_put(struct snd_kcontrol *kcontrol, |
751 | struct snd_ctl_elem_value *ucontrol) |
752 | { |
753 | struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); |
754 | int rate, ret = 0; |
755 | unsigned int clock_items = 2; /* at least Internal and AES Sync clock */ |
756 | if (mgr->board_has_aes1) { |
757 | clock_items += mgr->capture_chips; /* add AES x */ |
758 | if (!mgr->is_hr_stereo) |
759 | clock_items += 1; /* add word clock */ |
760 | } |
761 | if (ucontrol->value.enumerated.item[0] >= clock_items) |
762 | return -EINVAL; |
763 | mutex_lock(&mgr->mixer_mutex); |
764 | if (mgr->use_clock_type != ucontrol->value.enumerated.item[0]) { |
765 | mutex_lock(&mgr->setup_mutex); |
766 | mgr->use_clock_type = ucontrol->value.enumerated.item[0]; |
767 | rate = 0; |
768 | if (mgr->use_clock_type != PCXHR_CLOCK_TYPE_INTERNAL) { |
769 | pcxhr_get_external_clock(mgr, clock_type: mgr->use_clock_type, |
770 | sample_rate: &rate); |
771 | } else { |
772 | rate = mgr->sample_rate; |
773 | if (!rate) |
774 | rate = 48000; |
775 | } |
776 | if (rate) { |
777 | pcxhr_set_clock(mgr, rate); |
778 | if (mgr->sample_rate) |
779 | mgr->sample_rate = rate; |
780 | } |
781 | mutex_unlock(lock: &mgr->setup_mutex); |
782 | ret = 1; /* return 1 even if the set was not done. ok ? */ |
783 | } |
784 | mutex_unlock(lock: &mgr->mixer_mutex); |
785 | return ret; |
786 | } |
787 | |
788 | static const struct snd_kcontrol_new pcxhr_control_clock_type = { |
789 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
790 | .name = "Clock Mode" , |
791 | .info = pcxhr_clock_type_info, |
792 | .get = pcxhr_clock_type_get, |
793 | .put = pcxhr_clock_type_put, |
794 | }; |
795 | |
796 | /* |
797 | * clock rate control |
798 | * specific control that scans the sample rates on the external plugs |
799 | */ |
800 | static int pcxhr_clock_rate_info(struct snd_kcontrol *kcontrol, |
801 | struct snd_ctl_elem_info *uinfo) |
802 | { |
803 | struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); |
804 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
805 | uinfo->count = 3 + mgr->capture_chips; |
806 | uinfo->value.integer.min = 0; /* clock not present */ |
807 | uinfo->value.integer.max = 192000; /* max sample rate 192 kHz */ |
808 | return 0; |
809 | } |
810 | |
811 | static int pcxhr_clock_rate_get(struct snd_kcontrol *kcontrol, |
812 | struct snd_ctl_elem_value *ucontrol) |
813 | { |
814 | struct pcxhr_mgr *mgr = snd_kcontrol_chip(kcontrol); |
815 | int i, err, rate; |
816 | |
817 | mutex_lock(&mgr->mixer_mutex); |
818 | for(i = 0; i < 3 + mgr->capture_chips; i++) { |
819 | if (i == PCXHR_CLOCK_TYPE_INTERNAL) |
820 | rate = mgr->sample_rate_real; |
821 | else { |
822 | err = pcxhr_get_external_clock(mgr, clock_type: i, sample_rate: &rate); |
823 | if (err) |
824 | break; |
825 | } |
826 | ucontrol->value.integer.value[i] = rate; |
827 | } |
828 | mutex_unlock(lock: &mgr->mixer_mutex); |
829 | return 0; |
830 | } |
831 | |
832 | static const struct snd_kcontrol_new pcxhr_control_clock_rate = { |
833 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
834 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, |
835 | .name = "Clock Rates" , |
836 | .info = pcxhr_clock_rate_info, |
837 | .get = pcxhr_clock_rate_get, |
838 | }; |
839 | |
840 | /* |
841 | * IEC958 status bits |
842 | */ |
843 | static int pcxhr_iec958_info(struct snd_kcontrol *kcontrol, |
844 | struct snd_ctl_elem_info *uinfo) |
845 | { |
846 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; |
847 | uinfo->count = 1; |
848 | return 0; |
849 | } |
850 | |
851 | static int pcxhr_iec958_capture_byte(struct snd_pcxhr *chip, |
852 | int aes_idx, unsigned char *aes_bits) |
853 | { |
854 | int i, err; |
855 | unsigned char temp; |
856 | struct pcxhr_rmh rmh; |
857 | |
858 | pcxhr_init_rmh(rmh: &rmh, cmd: CMD_ACCESS_IO_READ); |
859 | rmh.cmd[0] |= IO_NUM_UER_CHIP_REG; |
860 | switch (chip->chip_idx) { |
861 | /* instead of CS8420_01_CS use CS8416_01_CS for AES SYNC plug */ |
862 | case 0: rmh.cmd[1] = CS8420_01_CS; break; |
863 | case 1: rmh.cmd[1] = CS8420_23_CS; break; |
864 | case 2: rmh.cmd[1] = CS8420_45_CS; break; |
865 | case 3: rmh.cmd[1] = CS8420_67_CS; break; |
866 | default: return -EINVAL; |
867 | } |
868 | if (chip->mgr->board_aes_in_192k) { |
869 | switch (aes_idx) { |
870 | case 0: rmh.cmd[2] = CS8416_CSB0; break; |
871 | case 1: rmh.cmd[2] = CS8416_CSB1; break; |
872 | case 2: rmh.cmd[2] = CS8416_CSB2; break; |
873 | case 3: rmh.cmd[2] = CS8416_CSB3; break; |
874 | case 4: rmh.cmd[2] = CS8416_CSB4; break; |
875 | default: return -EINVAL; |
876 | } |
877 | } else { |
878 | switch (aes_idx) { |
879 | /* instead of CS8420_CSB0 use CS8416_CSBx for AES SYNC plug */ |
880 | case 0: rmh.cmd[2] = CS8420_CSB0; break; |
881 | case 1: rmh.cmd[2] = CS8420_CSB1; break; |
882 | case 2: rmh.cmd[2] = CS8420_CSB2; break; |
883 | case 3: rmh.cmd[2] = CS8420_CSB3; break; |
884 | case 4: rmh.cmd[2] = CS8420_CSB4; break; |
885 | default: return -EINVAL; |
886 | } |
887 | } |
888 | /* size and code the chip id for the fpga */ |
889 | rmh.cmd[1] &= 0x0fffff; |
890 | /* chip signature + map for spi read */ |
891 | rmh.cmd[2] &= CHIP_SIG_AND_MAP_SPI; |
892 | rmh.cmd_len = 3; |
893 | err = pcxhr_send_msg(mgr: chip->mgr, rmh: &rmh); |
894 | if (err) |
895 | return err; |
896 | |
897 | if (chip->mgr->board_aes_in_192k) { |
898 | temp = (unsigned char)rmh.stat[1]; |
899 | } else { |
900 | temp = 0; |
901 | /* reversed bit order (not with CS8416_01_CS) */ |
902 | for (i = 0; i < 8; i++) { |
903 | temp <<= 1; |
904 | if (rmh.stat[1] & (1 << i)) |
905 | temp |= 1; |
906 | } |
907 | } |
908 | dev_dbg(chip->card->dev, "read iec958 AES %d byte %d = 0x%x\n" , |
909 | chip->chip_idx, aes_idx, temp); |
910 | *aes_bits = temp; |
911 | return 0; |
912 | } |
913 | |
914 | static int pcxhr_iec958_get(struct snd_kcontrol *kcontrol, |
915 | struct snd_ctl_elem_value *ucontrol) |
916 | { |
917 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); |
918 | unsigned char aes_bits; |
919 | int i, err; |
920 | |
921 | mutex_lock(&chip->mgr->mixer_mutex); |
922 | for(i = 0; i < 5; i++) { |
923 | if (kcontrol->private_value == 0) /* playback */ |
924 | aes_bits = chip->aes_bits[i]; |
925 | else { /* capture */ |
926 | if (chip->mgr->is_hr_stereo) |
927 | err = hr222_iec958_capture_byte(chip, aes_idx: i, |
928 | aes_bits: &aes_bits); |
929 | else |
930 | err = pcxhr_iec958_capture_byte(chip, aes_idx: i, |
931 | aes_bits: &aes_bits); |
932 | if (err) |
933 | break; |
934 | } |
935 | ucontrol->value.iec958.status[i] = aes_bits; |
936 | } |
937 | mutex_unlock(lock: &chip->mgr->mixer_mutex); |
938 | return 0; |
939 | } |
940 | |
941 | static int pcxhr_iec958_mask_get(struct snd_kcontrol *kcontrol, |
942 | struct snd_ctl_elem_value *ucontrol) |
943 | { |
944 | int i; |
945 | for (i = 0; i < 5; i++) |
946 | ucontrol->value.iec958.status[i] = 0xff; |
947 | return 0; |
948 | } |
949 | |
950 | static int pcxhr_iec958_update_byte(struct snd_pcxhr *chip, |
951 | int aes_idx, unsigned char aes_bits) |
952 | { |
953 | int i, err, cmd; |
954 | unsigned char new_bits = aes_bits; |
955 | unsigned char old_bits = chip->aes_bits[aes_idx]; |
956 | struct pcxhr_rmh rmh; |
957 | |
958 | for (i = 0; i < 8; i++) { |
959 | if ((old_bits & 0x01) != (new_bits & 0x01)) { |
960 | cmd = chip->chip_idx & 0x03; /* chip index 0..3 */ |
961 | if (chip->chip_idx > 3) |
962 | /* new bit used if chip_idx>3 (PCX1222HR) */ |
963 | cmd |= 1 << 22; |
964 | cmd |= ((aes_idx << 3) + i) << 2; /* add bit offset */ |
965 | cmd |= (new_bits & 0x01) << 23; /* add bit value */ |
966 | pcxhr_init_rmh(rmh: &rmh, cmd: CMD_ACCESS_IO_WRITE); |
967 | rmh.cmd[0] |= IO_NUM_REG_CUER; |
968 | rmh.cmd[1] = cmd; |
969 | rmh.cmd_len = 2; |
970 | dev_dbg(chip->card->dev, |
971 | "write iec958 AES %d byte %d bit %d (cmd %x)\n" , |
972 | chip->chip_idx, aes_idx, i, cmd); |
973 | err = pcxhr_send_msg(mgr: chip->mgr, rmh: &rmh); |
974 | if (err) |
975 | return err; |
976 | } |
977 | old_bits >>= 1; |
978 | new_bits >>= 1; |
979 | } |
980 | chip->aes_bits[aes_idx] = aes_bits; |
981 | return 0; |
982 | } |
983 | |
984 | static int pcxhr_iec958_put(struct snd_kcontrol *kcontrol, |
985 | struct snd_ctl_elem_value *ucontrol) |
986 | { |
987 | struct snd_pcxhr *chip = snd_kcontrol_chip(kcontrol); |
988 | int i, changed = 0; |
989 | |
990 | /* playback */ |
991 | mutex_lock(&chip->mgr->mixer_mutex); |
992 | for (i = 0; i < 5; i++) { |
993 | if (ucontrol->value.iec958.status[i] != chip->aes_bits[i]) { |
994 | if (chip->mgr->is_hr_stereo) |
995 | hr222_iec958_update_byte(chip, aes_idx: i, |
996 | aes_bits: ucontrol->value.iec958.status[i]); |
997 | else |
998 | pcxhr_iec958_update_byte(chip, aes_idx: i, |
999 | aes_bits: ucontrol->value.iec958.status[i]); |
1000 | changed = 1; |
1001 | } |
1002 | } |
1003 | mutex_unlock(lock: &chip->mgr->mixer_mutex); |
1004 | return changed; |
1005 | } |
1006 | |
1007 | static const struct snd_kcontrol_new pcxhr_control_playback_iec958_mask = { |
1008 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
1009 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
1010 | .name = SNDRV_CTL_NAME_IEC958("" ,PLAYBACK,MASK), |
1011 | .info = pcxhr_iec958_info, |
1012 | .get = pcxhr_iec958_mask_get |
1013 | }; |
1014 | static const struct snd_kcontrol_new pcxhr_control_playback_iec958 = { |
1015 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
1016 | .name = SNDRV_CTL_NAME_IEC958("" ,PLAYBACK,DEFAULT), |
1017 | .info = pcxhr_iec958_info, |
1018 | .get = pcxhr_iec958_get, |
1019 | .put = pcxhr_iec958_put, |
1020 | .private_value = 0 /* playback */ |
1021 | }; |
1022 | |
1023 | static const struct snd_kcontrol_new pcxhr_control_capture_iec958_mask = { |
1024 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
1025 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
1026 | .name = SNDRV_CTL_NAME_IEC958("" ,CAPTURE,MASK), |
1027 | .info = pcxhr_iec958_info, |
1028 | .get = pcxhr_iec958_mask_get |
1029 | }; |
1030 | static const struct snd_kcontrol_new pcxhr_control_capture_iec958 = { |
1031 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
1032 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
1033 | .name = SNDRV_CTL_NAME_IEC958("" ,CAPTURE,DEFAULT), |
1034 | .info = pcxhr_iec958_info, |
1035 | .get = pcxhr_iec958_get, |
1036 | .private_value = 1 /* capture */ |
1037 | }; |
1038 | |
1039 | static void pcxhr_init_audio_levels(struct snd_pcxhr *chip) |
1040 | { |
1041 | int i; |
1042 | |
1043 | for (i = 0; i < 2; i++) { |
1044 | if (chip->nb_streams_play) { |
1045 | int j; |
1046 | /* at boot time the digital volumes are unmuted 0dB */ |
1047 | for (j = 0; j < PCXHR_PLAYBACK_STREAMS; j++) { |
1048 | chip->digital_playback_active[j][i] = 1; |
1049 | chip->digital_playback_volume[j][i] = |
1050 | PCXHR_DIGITAL_ZERO_LEVEL; |
1051 | } |
1052 | /* after boot, only two bits are set on the uer |
1053 | * interface |
1054 | */ |
1055 | chip->aes_bits[0] = (IEC958_AES0_PROFESSIONAL | |
1056 | IEC958_AES0_PRO_FS_48000); |
1057 | #ifdef CONFIG_SND_DEBUG |
1058 | /* analog volumes for playback |
1059 | * (is LEVEL_MIN after boot) |
1060 | */ |
1061 | chip->analog_playback_active[i] = 1; |
1062 | if (chip->mgr->is_hr_stereo) |
1063 | chip->analog_playback_volume[i] = |
1064 | HR222_LINE_PLAYBACK_ZERO_LEVEL; |
1065 | else { |
1066 | chip->analog_playback_volume[i] = |
1067 | PCXHR_LINE_PLAYBACK_ZERO_LEVEL; |
1068 | pcxhr_update_analog_audio_level(chip, is_capture: 0, channel: i); |
1069 | } |
1070 | #endif |
1071 | /* stereo cards need to be initialised after boot */ |
1072 | if (chip->mgr->is_hr_stereo) |
1073 | hr222_update_analog_audio_level(chip, is_capture: 0, channel: i); |
1074 | } |
1075 | if (chip->nb_streams_capt) { |
1076 | /* at boot time the digital volumes are unmuted 0dB */ |
1077 | chip->digital_capture_volume[i] = |
1078 | PCXHR_DIGITAL_ZERO_LEVEL; |
1079 | chip->analog_capture_active = 1; |
1080 | #ifdef CONFIG_SND_DEBUG |
1081 | /* analog volumes for playback |
1082 | * (is LEVEL_MIN after boot) |
1083 | */ |
1084 | if (chip->mgr->is_hr_stereo) |
1085 | chip->analog_capture_volume[i] = |
1086 | HR222_LINE_CAPTURE_ZERO_LEVEL; |
1087 | else { |
1088 | chip->analog_capture_volume[i] = |
1089 | PCXHR_LINE_CAPTURE_ZERO_LEVEL; |
1090 | pcxhr_update_analog_audio_level(chip, is_capture: 1, channel: i); |
1091 | } |
1092 | #endif |
1093 | /* stereo cards need to be initialised after boot */ |
1094 | if (chip->mgr->is_hr_stereo) |
1095 | hr222_update_analog_audio_level(chip, is_capture: 1, channel: i); |
1096 | } |
1097 | } |
1098 | |
1099 | return; |
1100 | } |
1101 | |
1102 | |
1103 | int pcxhr_create_mixer(struct pcxhr_mgr *mgr) |
1104 | { |
1105 | struct snd_pcxhr *chip; |
1106 | int err, i; |
1107 | |
1108 | mutex_init(&mgr->mixer_mutex); /* can be in another place */ |
1109 | |
1110 | for (i = 0; i < mgr->num_cards; i++) { |
1111 | struct snd_kcontrol_new temp; |
1112 | chip = mgr->chip[i]; |
1113 | |
1114 | if (chip->nb_streams_play) { |
1115 | /* analog output level control */ |
1116 | temp = pcxhr_control_analog_level; |
1117 | temp.name = "Master Playback Volume" ; |
1118 | temp.private_value = 0; /* playback */ |
1119 | if (mgr->is_hr_stereo) |
1120 | temp.tlv.p = db_scale_a_hr222_playback; |
1121 | else |
1122 | temp.tlv.p = db_scale_analog_playback; |
1123 | err = snd_ctl_add(card: chip->card, |
1124 | kcontrol: snd_ctl_new1(kcontrolnew: &temp, private_data: chip)); |
1125 | if (err < 0) |
1126 | return err; |
1127 | |
1128 | /* output mute controls */ |
1129 | err = snd_ctl_add(card: chip->card, |
1130 | kcontrol: snd_ctl_new1(kcontrolnew: &pcxhr_control_output_switch, |
1131 | private_data: chip)); |
1132 | if (err < 0) |
1133 | return err; |
1134 | |
1135 | temp = snd_pcxhr_pcm_vol; |
1136 | temp.name = "PCM Playback Volume" ; |
1137 | temp.count = PCXHR_PLAYBACK_STREAMS; |
1138 | temp.private_value = 0; /* playback */ |
1139 | err = snd_ctl_add(card: chip->card, |
1140 | kcontrol: snd_ctl_new1(kcontrolnew: &temp, private_data: chip)); |
1141 | if (err < 0) |
1142 | return err; |
1143 | |
1144 | err = snd_ctl_add(card: chip->card, |
1145 | kcontrol: snd_ctl_new1(kcontrolnew: &pcxhr_control_pcm_switch, private_data: chip)); |
1146 | if (err < 0) |
1147 | return err; |
1148 | |
1149 | /* IEC958 controls */ |
1150 | err = snd_ctl_add(card: chip->card, |
1151 | kcontrol: snd_ctl_new1(kcontrolnew: &pcxhr_control_playback_iec958_mask, |
1152 | private_data: chip)); |
1153 | if (err < 0) |
1154 | return err; |
1155 | |
1156 | err = snd_ctl_add(card: chip->card, |
1157 | kcontrol: snd_ctl_new1(kcontrolnew: &pcxhr_control_playback_iec958, |
1158 | private_data: chip)); |
1159 | if (err < 0) |
1160 | return err; |
1161 | } |
1162 | if (chip->nb_streams_capt) { |
1163 | /* analog input level control */ |
1164 | temp = pcxhr_control_analog_level; |
1165 | temp.name = "Line Capture Volume" ; |
1166 | temp.private_value = 1; /* capture */ |
1167 | if (mgr->is_hr_stereo) |
1168 | temp.tlv.p = db_scale_a_hr222_capture; |
1169 | else |
1170 | temp.tlv.p = db_scale_analog_capture; |
1171 | |
1172 | err = snd_ctl_add(card: chip->card, |
1173 | kcontrol: snd_ctl_new1(kcontrolnew: &temp, private_data: chip)); |
1174 | if (err < 0) |
1175 | return err; |
1176 | |
1177 | temp = snd_pcxhr_pcm_vol; |
1178 | temp.name = "PCM Capture Volume" ; |
1179 | temp.count = 1; |
1180 | temp.private_value = 1; /* capture */ |
1181 | |
1182 | err = snd_ctl_add(card: chip->card, |
1183 | kcontrol: snd_ctl_new1(kcontrolnew: &temp, private_data: chip)); |
1184 | if (err < 0) |
1185 | return err; |
1186 | |
1187 | /* Audio source */ |
1188 | err = snd_ctl_add(card: chip->card, |
1189 | kcontrol: snd_ctl_new1(kcontrolnew: &pcxhr_control_audio_src, private_data: chip)); |
1190 | if (err < 0) |
1191 | return err; |
1192 | |
1193 | /* IEC958 controls */ |
1194 | err = snd_ctl_add(card: chip->card, |
1195 | kcontrol: snd_ctl_new1(kcontrolnew: &pcxhr_control_capture_iec958_mask, |
1196 | private_data: chip)); |
1197 | if (err < 0) |
1198 | return err; |
1199 | |
1200 | err = snd_ctl_add(card: chip->card, |
1201 | kcontrol: snd_ctl_new1(kcontrolnew: &pcxhr_control_capture_iec958, |
1202 | private_data: chip)); |
1203 | if (err < 0) |
1204 | return err; |
1205 | |
1206 | if (mgr->is_hr_stereo) { |
1207 | err = hr222_add_mic_controls(chip); |
1208 | if (err < 0) |
1209 | return err; |
1210 | } |
1211 | } |
1212 | /* monitoring only if playback and capture device available */ |
1213 | if (chip->nb_streams_capt > 0 && chip->nb_streams_play > 0) { |
1214 | /* monitoring */ |
1215 | err = snd_ctl_add(card: chip->card, |
1216 | kcontrol: snd_ctl_new1(kcontrolnew: &pcxhr_control_monitor_vol, private_data: chip)); |
1217 | if (err < 0) |
1218 | return err; |
1219 | |
1220 | err = snd_ctl_add(card: chip->card, |
1221 | kcontrol: snd_ctl_new1(kcontrolnew: &pcxhr_control_monitor_sw, private_data: chip)); |
1222 | if (err < 0) |
1223 | return err; |
1224 | } |
1225 | |
1226 | if (i == 0) { |
1227 | /* clock mode only one control per pcxhr */ |
1228 | err = snd_ctl_add(card: chip->card, |
1229 | kcontrol: snd_ctl_new1(kcontrolnew: &pcxhr_control_clock_type, private_data: mgr)); |
1230 | if (err < 0) |
1231 | return err; |
1232 | /* non standard control used to scan |
1233 | * the external clock presence/frequencies |
1234 | */ |
1235 | err = snd_ctl_add(card: chip->card, |
1236 | kcontrol: snd_ctl_new1(kcontrolnew: &pcxhr_control_clock_rate, private_data: mgr)); |
1237 | if (err < 0) |
1238 | return err; |
1239 | } |
1240 | |
1241 | /* init values for the mixer data */ |
1242 | pcxhr_init_audio_levels(chip); |
1243 | } |
1244 | |
1245 | return 0; |
1246 | } |
1247 | |