2 * Driver for Digigram VX soundcards
6 * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <sound/driver.h>
24 #include <sound/core.h>
25 #include <sound/control.h>
26 #include <sound/vx_core.h>
29 #define chip_t vx_core_t
33 * write a codec data (24bit)
35 static void vx_write_codec_reg(vx_core_t *chip, int codec, unsigned int data)
39 snd_assert(chip->ops->write_codec, return);
41 if (chip->chip_status & VX_STAT_IS_STALE)
44 spin_lock_irqsave(&chip->lock, flags);
45 chip->ops->write_codec(chip, codec, data);
46 spin_unlock_irqrestore(&chip->lock, flags);
50 * Data type used to access the Codec
54 #ifdef SNDRV_BIG_ENDIAN
65 #else /* LITTLE_ENDIAN */
79 #define SET_CDC_DATA_SEL(di,s) ((di).b.mh = (u8) (s))
80 #define SET_CDC_DATA_REG(di,r) ((di).b.ml = (u8) (r))
81 #define SET_CDC_DATA_VAL(di,d) ((di).b.ll = (u8) (d))
82 #define SET_CDC_DATA_INIT(di) ((di).l = 0L, SET_CDC_DATA_SEL(di,XX_CODEC_SELECTOR))
85 * set up codec register and write the value
86 * @codec: the codec id, 0 or 1
87 * @reg: register index
90 static void vx_set_codec_reg(vx_core_t *chip, int codec, int reg, int val)
93 /* DAC control register */
94 SET_CDC_DATA_INIT(data);
95 SET_CDC_DATA_REG(data, reg);
96 SET_CDC_DATA_VAL(data, val);
97 vx_write_codec_reg(chip, codec, data.l);
102 * vx_set_analog_output_level - set the output attenuation level
103 * @codec: the output codec, 0 or 1. (1 for VXP440 only)
104 * @left: left output level, 0 = mute
105 * @right: right output level
107 static void vx_set_analog_output_level(vx_core_t *chip, int codec, int left, int right)
109 left = chip->hw->output_level_max - left;
110 right = chip->hw->output_level_max - right;
112 if (chip->ops->akm_write) {
113 chip->ops->akm_write(chip, XX_CODEC_LEVEL_LEFT_REGISTER, left);
114 chip->ops->akm_write(chip, XX_CODEC_LEVEL_RIGHT_REGISTER, right);
116 /* convert to attenuation level: 0 = 0dB (max), 0xe3 = -113.5 dB (min) */
117 vx_set_codec_reg(chip, codec, XX_CODEC_LEVEL_LEFT_REGISTER, left);
118 vx_set_codec_reg(chip, codec, XX_CODEC_LEVEL_RIGHT_REGISTER, right);
124 * vx_toggle_dac_mute - mute/unmute DAC
125 * @mute: 0 = unmute, 1 = mute
128 #define DAC_ATTEN_MIN 0x08
129 #define DAC_ATTEN_MAX 0x38
131 void vx_toggle_dac_mute(vx_core_t *chip, int mute)
134 for (i = 0; i < chip->hw->num_codecs; i++) {
135 if (chip->ops->akm_write)
136 chip->ops->akm_write(chip, XX_CODEC_DAC_CONTROL_REGISTER, mute); /* XXX */
138 vx_set_codec_reg(chip, i, XX_CODEC_DAC_CONTROL_REGISTER,
139 mute ? DAC_ATTEN_MAX : DAC_ATTEN_MIN);
144 * vx_reset_codec - reset and initialize the codecs
146 void vx_reset_codec(vx_core_t *chip, int cold_reset)
149 int port = chip->type >= VX_TYPE_VXPOCKET ? 0x75 : 0x65;
151 chip->ops->reset_codec(chip);
153 /* AKM codecs should be initialized in reset_codec callback */
154 if (! chip->ops->akm_write) {
155 /* initialize old codecs */
156 for (i = 0; i < chip->hw->num_codecs; i++) {
157 /* DAC control register (change level when zero crossing + mute) */
158 vx_set_codec_reg(chip, i, XX_CODEC_DAC_CONTROL_REGISTER, DAC_ATTEN_MAX);
159 /* ADC control register */
160 vx_set_codec_reg(chip, i, XX_CODEC_ADC_CONTROL_REGISTER, 0x00);
161 /* Port mode register */
162 vx_set_codec_reg(chip, i, XX_CODEC_PORT_MODE_REGISTER, port);
163 /* Clock control register */
164 vx_set_codec_reg(chip, i, XX_CODEC_CLOCK_CONTROL_REGISTER, 0x00);
168 /* mute analog output */
169 for (i = 0; i < chip->hw->num_codecs; i++) {
170 chip->output_level[i][0] = 0;
171 chip->output_level[i][1] = 0;
172 vx_set_analog_output_level(chip, i, 0, 0);
177 * change the audio input source
178 * @src: the target source (VX_AUDIO_SRC_XXX)
180 static void vx_change_audio_source(vx_core_t *chip, int src)
184 if (chip->chip_status & VX_STAT_IS_STALE)
187 spin_lock_irqsave(&chip->lock, flags);
188 chip->ops->change_audio_source(chip, src);
189 spin_unlock_irqrestore(&chip->lock, flags);
194 * change the audio source if necessary and possible
195 * returns 1 if the source is actually changed.
197 int vx_sync_audio_source(vx_core_t *chip)
199 if (chip->audio_source_target == chip->audio_source ||
202 vx_change_audio_source(chip, chip->audio_source_target);
203 chip->audio_source = chip->audio_source_target;
209 * audio level, mute, monitoring
211 struct vx_audio_level {
212 unsigned int has_level: 1;
213 unsigned int has_monitor_level: 1;
214 unsigned int has_mute: 1;
215 unsigned int has_monitor_mute: 1;
217 unsigned int monitor_mute;
222 static int vx_adjust_audio_level(vx_core_t *chip, int audio, int capture,
223 struct vx_audio_level *info)
227 if (chip->chip_status & VX_STAT_IS_STALE)
230 vx_init_rmh(&rmh, CMD_AUDIO_LEVEL_ADJUST);
232 rmh.Cmd[0] |= COMMAND_RECORD_MASK;
233 /* Add Audio IO mask */
234 rmh.Cmd[1] = 1 << audio;
236 if (info->has_level) {
237 rmh.Cmd[0] |= VALID_AUDIO_IO_DIGITAL_LEVEL;
238 rmh.Cmd[2] |= info->level;
240 if (info->has_monitor_level) {
241 rmh.Cmd[0] |= VALID_AUDIO_IO_MONITORING_LEVEL;
242 rmh.Cmd[2] |= ((unsigned int)info->monitor_level << 10);
244 if (info->has_mute) {
245 rmh.Cmd[0] |= VALID_AUDIO_IO_MUTE_LEVEL;
247 rmh.Cmd[2] |= AUDIO_IO_HAS_MUTE_LEVEL;
249 if (info->has_monitor_mute) {
250 /* validate flag for M2 at least to unmute it */
251 rmh.Cmd[0] |= VALID_AUDIO_IO_MUTE_MONITORING_1 | VALID_AUDIO_IO_MUTE_MONITORING_2;
252 if (info->monitor_mute)
253 rmh.Cmd[2] |= AUDIO_IO_HAS_MUTE_MONITORING_1;
256 return vx_send_msg(chip, &rmh);
261 static int vx_read_audio_level(vx_core_t *chip, int audio, int capture,
262 struct vx_audio_level *info)
267 memset(info, 0, sizeof(*info));
268 vx_init_rmh(&rmh, CMD_GET_AUDIO_LEVELS);
270 rmh.Cmd[0] |= COMMAND_RECORD_MASK;
271 /* Add Audio IO mask */
272 rmh.Cmd[1] = 1 << audio;
273 err = vx_send_msg(chip, &rmh);
276 info.level = rmh.Stat[0] & MASK_DSP_WORD_LEVEL;
277 info.monitor_level = (rmh.Stat[0] >> 10) & MASK_DSP_WORD_LEVEL;
278 info.mute = (rmh.Stat[i] & AUDIO_IO_HAS_MUTE_LEVEL) ? 1 : 0;
279 info.monitor_mute = (rmh.Stat[i] & AUDIO_IO_HAS_MUTE_MONITORING_1) ? 1 : 0;
285 * set the monitoring level and mute state of the given audio
286 * no more static, because must be called from vx_pcm to demute monitoring
288 int vx_set_monitor_level(vx_core_t *chip, int audio, int level, int active)
290 struct vx_audio_level info;
292 memset(&info, 0, sizeof(info));
293 info.has_monitor_level = 1;
294 info.monitor_level = level;
295 info.has_monitor_mute = 1;
296 info.monitor_mute = !active;
297 chip->audio_monitor[audio] = level;
298 chip->audio_monitor_active[audio] = active;
299 return vx_adjust_audio_level(chip, audio, 0, &info); /* playback only */
304 * set the mute status of the given audio
306 static int vx_set_audio_switch(vx_core_t *chip, int audio, int active)
308 struct vx_audio_level info;
310 memset(&info, 0, sizeof(info));
313 chip->audio_active[audio] = active;
314 return vx_adjust_audio_level(chip, audio, 0, &info); /* playback only */
318 * set the mute status of the given audio
320 static int vx_set_audio_gain(vx_core_t *chip, int audio, int capture, int level)
322 struct vx_audio_level info;
324 memset(&info, 0, sizeof(info));
327 chip->audio_gain[capture][audio] = level;
328 return vx_adjust_audio_level(chip, audio, capture, &info);
332 * reset all audio levels
334 static void vx_reset_audio_levels(vx_core_t *chip)
337 struct vx_audio_level info;
339 memset(chip->audio_gain, 0, sizeof(chip->audio_gain));
340 memset(chip->audio_active, 0, sizeof(chip->audio_active));
341 memset(chip->audio_monitor, 0, sizeof(chip->audio_monitor));
342 memset(chip->audio_monitor_active, 0, sizeof(chip->audio_monitor_active));
344 for (c = 0; c < 2; c++) {
345 for (i = 0; i < chip->hw->num_ins * 2; i++) {
346 memset(&info, 0, sizeof(info));
348 info.has_monitor_level = 1;
350 info.has_monitor_mute = 1;
353 info.level = CVAL_0DB; /* default: 0dB */
354 vx_adjust_audio_level(chip, i, c, &info);
355 chip->audio_gain[c][i] = CVAL_0DB;
356 chip->audio_monitor[i] = CVAL_0DB;
363 * VU, peak meter record
366 #define VU_METER_CHANNELS 2
375 * get the VU and peak meter values
376 * @audio: the audio index
377 * @capture: 0 = playback, 1 = capture operation
378 * @info: the array of vx_vu_meter records (size = 2).
380 static int vx_get_audio_vu_meter(vx_core_t *chip, int audio, int capture, struct vx_vu_meter *info)
385 if (chip->chip_status & VX_STAT_IS_STALE)
388 vx_init_rmh(&rmh, CMD_AUDIO_VU_PIC_METER);
389 rmh.LgStat += 2 * VU_METER_CHANNELS;
391 rmh.Cmd[0] |= COMMAND_RECORD_MASK;
393 /* Add Audio IO mask */
395 for (i = 0; i < VU_METER_CHANNELS; i++)
396 rmh.Cmd[1] |= 1 << (audio + i);
397 err = vx_send_msg(chip, &rmh);
401 for (i = 0; i < 2 * VU_METER_CHANNELS; i +=2) {
402 info->saturated = (rmh.Stat[0] & (1 << (audio + i))) ? 1 : 0;
403 info->vu_level = rmh.Stat[i + 1];
404 info->peak_level = rmh.Stat[i + 2];
412 * control API entries
416 * output level control
418 static int vx_output_level_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
420 vx_core_t *chip = snd_kcontrol_chip(kcontrol);
421 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
423 uinfo->value.integer.min = 0;
424 uinfo->value.integer.max = chip->hw->output_level_max;
428 static int vx_output_level_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
430 vx_core_t *chip = snd_kcontrol_chip(kcontrol);
431 int codec = kcontrol->id.index;
432 down(&chip->mixer_mutex);
433 ucontrol->value.integer.value[0] = chip->output_level[codec][0];
434 ucontrol->value.integer.value[1] = chip->output_level[codec][1];
435 up(&chip->mixer_mutex);
439 static int vx_output_level_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
441 vx_core_t *chip = snd_kcontrol_chip(kcontrol);
442 int codec = kcontrol->id.index;
443 down(&chip->mixer_mutex);
444 if (ucontrol->value.integer.value[0] != chip->output_level[codec][0] ||
445 ucontrol->value.integer.value[1] != chip->output_level[codec][1]) {
446 vx_set_analog_output_level(chip, codec,
447 ucontrol->value.integer.value[0],
448 ucontrol->value.integer.value[1]);
449 chip->output_level[codec][0] = ucontrol->value.integer.value[0];
450 chip->output_level[codec][1] = ucontrol->value.integer.value[1];
451 up(&chip->mixer_mutex);
454 up(&chip->mixer_mutex);
458 static snd_kcontrol_new_t vx_control_output_level = {
459 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
460 .name = "Master Playback Volume",
461 .info = vx_output_level_info,
462 .get = vx_output_level_get,
463 .put = vx_output_level_put,
467 * audio source select
469 static int vx_audio_src_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
471 static char *texts_mic[3] = {
472 "Digital", "Line", "Mic"
474 static char *texts_vx2[2] = {
477 vx_core_t *chip = snd_kcontrol_chip(kcontrol);
479 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
481 if (chip->type >= VX_TYPE_VXPOCKET) {
482 uinfo->value.enumerated.items = 3;
483 if (uinfo->value.enumerated.item > 2)
484 uinfo->value.enumerated.item = 2;
485 strcpy(uinfo->value.enumerated.name,
486 texts_mic[uinfo->value.enumerated.item]);
488 uinfo->value.enumerated.items = 2;
489 if (uinfo->value.enumerated.item > 1)
490 uinfo->value.enumerated.item = 1;
491 strcpy(uinfo->value.enumerated.name,
492 texts_vx2[uinfo->value.enumerated.item]);
497 static int vx_audio_src_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
499 vx_core_t *chip = snd_kcontrol_chip(kcontrol);
500 ucontrol->value.enumerated.item[0] = chip->audio_source_target;
504 static int vx_audio_src_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
506 vx_core_t *chip = snd_kcontrol_chip(kcontrol);
507 down(&chip->mixer_mutex);
508 if (chip->audio_source_target != ucontrol->value.enumerated.item[0]) {
509 chip->audio_source_target = ucontrol->value.enumerated.item[0];
510 vx_sync_audio_source(chip);
511 up(&chip->mixer_mutex);
514 up(&chip->mixer_mutex);
518 static snd_kcontrol_new_t vx_control_audio_src = {
519 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
520 .name = "Capture Source",
521 .info = vx_audio_src_info,
522 .get = vx_audio_src_get,
523 .put = vx_audio_src_put,
529 static int vx_audio_gain_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
531 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
533 uinfo->value.integer.min = 0;
534 uinfo->value.integer.max = CVAL_MAX;
538 static int vx_audio_gain_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
540 vx_core_t *chip = snd_kcontrol_chip(kcontrol);
541 int audio = kcontrol->private_value & 0xff;
542 int capture = (kcontrol->private_value >> 8) & 1;
544 down(&chip->mixer_mutex);
545 ucontrol->value.integer.value[0] = chip->audio_gain[capture][audio];
546 ucontrol->value.integer.value[1] = chip->audio_gain[capture][audio+1];
547 up(&chip->mixer_mutex);
551 static int vx_audio_gain_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
553 vx_core_t *chip = snd_kcontrol_chip(kcontrol);
554 int audio = kcontrol->private_value & 0xff;
555 int capture = (kcontrol->private_value >> 8) & 1;
557 down(&chip->mixer_mutex);
558 if (ucontrol->value.integer.value[0] != chip->audio_gain[capture][audio] ||
559 ucontrol->value.integer.value[1] != chip->audio_gain[capture][audio+1]) {
560 vx_set_audio_gain(chip, audio, capture, ucontrol->value.integer.value[0]);
561 vx_set_audio_gain(chip, audio+1, capture, ucontrol->value.integer.value[1]);
562 up(&chip->mixer_mutex);
565 up(&chip->mixer_mutex);
569 static int vx_audio_monitor_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
571 vx_core_t *chip = snd_kcontrol_chip(kcontrol);
572 int audio = kcontrol->private_value & 0xff;
574 down(&chip->mixer_mutex);
575 ucontrol->value.integer.value[0] = chip->audio_monitor[audio];
576 ucontrol->value.integer.value[1] = chip->audio_monitor[audio+1];
577 up(&chip->mixer_mutex);
581 static int vx_audio_monitor_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
583 vx_core_t *chip = snd_kcontrol_chip(kcontrol);
584 int audio = kcontrol->private_value & 0xff;
586 down(&chip->mixer_mutex);
587 if (ucontrol->value.integer.value[0] != chip->audio_monitor[audio] ||
588 ucontrol->value.integer.value[1] != chip->audio_monitor[audio+1]) {
589 vx_set_monitor_level(chip, audio, ucontrol->value.integer.value[0],
590 chip->audio_monitor_active[audio]);
591 vx_set_monitor_level(chip, audio+1, ucontrol->value.integer.value[1],
592 chip->audio_monitor_active[audio+1]);
593 up(&chip->mixer_mutex);
596 up(&chip->mixer_mutex);
600 static int vx_audio_sw_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
602 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
604 uinfo->value.integer.min = 0;
605 uinfo->value.integer.max = 1;
609 static int vx_audio_sw_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
611 vx_core_t *chip = snd_kcontrol_chip(kcontrol);
612 int audio = kcontrol->private_value & 0xff;
614 down(&chip->mixer_mutex);
615 ucontrol->value.integer.value[0] = chip->audio_active[audio];
616 ucontrol->value.integer.value[1] = chip->audio_active[audio+1];
617 up(&chip->mixer_mutex);
621 static int vx_audio_sw_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
623 vx_core_t *chip = snd_kcontrol_chip(kcontrol);
624 int audio = kcontrol->private_value & 0xff;
626 down(&chip->mixer_mutex);
627 if (ucontrol->value.integer.value[0] != chip->audio_active[audio] ||
628 ucontrol->value.integer.value[1] != chip->audio_active[audio+1]) {
629 vx_set_audio_switch(chip, audio, ucontrol->value.integer.value[0]);
630 vx_set_audio_switch(chip, audio+1, ucontrol->value.integer.value[1]);
631 up(&chip->mixer_mutex);
634 up(&chip->mixer_mutex);
638 static int vx_monitor_sw_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
640 vx_core_t *chip = snd_kcontrol_chip(kcontrol);
641 int audio = kcontrol->private_value & 0xff;
643 down(&chip->mixer_mutex);
644 ucontrol->value.integer.value[0] = chip->audio_monitor_active[audio];
645 ucontrol->value.integer.value[1] = chip->audio_monitor_active[audio+1];
646 up(&chip->mixer_mutex);
650 static int vx_monitor_sw_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
652 vx_core_t *chip = snd_kcontrol_chip(kcontrol);
653 int audio = kcontrol->private_value & 0xff;
655 down(&chip->mixer_mutex);
656 if (ucontrol->value.integer.value[0] != chip->audio_monitor_active[audio] ||
657 ucontrol->value.integer.value[1] != chip->audio_monitor_active[audio+1]) {
658 vx_set_monitor_level(chip, audio, chip->audio_monitor[audio],
659 ucontrol->value.integer.value[0]);
660 vx_set_monitor_level(chip, audio+1, chip->audio_monitor[audio+1],
661 ucontrol->value.integer.value[1]);
662 up(&chip->mixer_mutex);
665 up(&chip->mixer_mutex);
669 static snd_kcontrol_new_t vx_control_audio_gain = {
670 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
671 /* name will be filled later */
672 .info = vx_audio_gain_info,
673 .get = vx_audio_gain_get,
674 .put = vx_audio_gain_put
676 static snd_kcontrol_new_t vx_control_output_switch = {
677 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
678 .name = "PCM Playback Switch",
679 .info = vx_audio_sw_info,
680 .get = vx_audio_sw_get,
681 .put = vx_audio_sw_put
683 static snd_kcontrol_new_t vx_control_monitor_gain = {
684 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
685 .name = "Monitoring Volume",
686 .info = vx_audio_gain_info, /* shared */
687 .get = vx_audio_monitor_get,
688 .put = vx_audio_monitor_put
690 static snd_kcontrol_new_t vx_control_monitor_switch = {
691 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
692 .name = "Monitoring Switch",
693 .info = vx_audio_sw_info, /* shared */
694 .get = vx_monitor_sw_get,
695 .put = vx_monitor_sw_put
702 static int vx_iec958_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
704 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
709 static int vx_iec958_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
711 vx_core_t *chip = snd_kcontrol_chip(kcontrol);
713 down(&chip->mixer_mutex);
714 ucontrol->value.iec958.status[0] = (chip->uer_bits >> 0) & 0xff;
715 ucontrol->value.iec958.status[1] = (chip->uer_bits >> 8) & 0xff;
716 ucontrol->value.iec958.status[2] = (chip->uer_bits >> 16) & 0xff;
717 ucontrol->value.iec958.status[3] = (chip->uer_bits >> 24) & 0xff;
718 up(&chip->mixer_mutex);
722 static int vx_iec958_mask_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol)
724 ucontrol->value.iec958.status[0] = 0xff;
725 ucontrol->value.iec958.status[1] = 0xff;
726 ucontrol->value.iec958.status[2] = 0xff;
727 ucontrol->value.iec958.status[3] = 0xff;
731 static int vx_iec958_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
733 vx_core_t *chip = snd_kcontrol_chip(kcontrol);
736 val = (ucontrol->value.iec958.status[0] << 0) |
737 (ucontrol->value.iec958.status[1] << 8) |
738 (ucontrol->value.iec958.status[2] << 16) |
739 (ucontrol->value.iec958.status[3] << 24);
740 down(&chip->mixer_mutex);
741 if (chip->uer_bits != val) {
742 chip->uer_bits = val;
743 vx_set_iec958_status(chip, val);
744 up(&chip->mixer_mutex);
747 up(&chip->mixer_mutex);
751 static snd_kcontrol_new_t vx_control_iec958_mask = {
752 .access = SNDRV_CTL_ELEM_ACCESS_READ,
753 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
754 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
755 .info = vx_iec958_info, /* shared */
756 .get = vx_iec958_mask_get,
759 static snd_kcontrol_new_t vx_control_iec958 = {
760 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
761 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
762 .info = vx_iec958_info,
763 .get = vx_iec958_get,
772 #define METER_MAX 0xff
773 #define METER_SHIFT 16
775 static int vx_vu_meter_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
777 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
779 uinfo->value.integer.min = 0;
780 uinfo->value.integer.max = METER_MAX;
784 static int vx_vu_meter_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
786 vx_core_t *chip = snd_kcontrol_chip(kcontrol);
787 struct vx_vu_meter meter[2];
788 int audio = kcontrol->private_value & 0xff;
789 int capture = (kcontrol->private_value >> 8) & 1;
791 vx_get_audio_vu_meter(chip, audio, capture, meter);
792 ucontrol->value.integer.value[0] = meter[0].vu_level >> METER_SHIFT;
793 ucontrol->value.integer.value[1] = meter[1].vu_level >> METER_SHIFT;
797 static int vx_peak_meter_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
799 vx_core_t *chip = snd_kcontrol_chip(kcontrol);
800 struct vx_vu_meter meter[2];
801 int audio = kcontrol->private_value & 0xff;
802 int capture = (kcontrol->private_value >> 8) & 1;
804 vx_get_audio_vu_meter(chip, audio, capture, meter);
805 ucontrol->value.integer.value[0] = meter[0].peak_level >> METER_SHIFT;
806 ucontrol->value.integer.value[1] = meter[1].peak_level >> METER_SHIFT;
810 static int vx_saturation_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
812 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
814 uinfo->value.integer.min = 0;
815 uinfo->value.integer.max = 1;
819 static int vx_saturation_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
821 vx_core_t *chip = snd_kcontrol_chip(kcontrol);
822 struct vx_vu_meter meter[2];
823 int audio = kcontrol->private_value & 0xff;
825 vx_get_audio_vu_meter(chip, audio, 1, meter); /* capture only */
826 ucontrol->value.integer.value[0] = meter[0].saturated;
827 ucontrol->value.integer.value[1] = meter[1].saturated;
831 static snd_kcontrol_new_t vx_control_vu_meter = {
832 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
833 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
834 /* name will be filled later */
835 .info = vx_vu_meter_info,
836 .get = vx_vu_meter_get,
839 static snd_kcontrol_new_t vx_control_peak_meter = {
840 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
841 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
842 /* name will be filled later */
843 .info = vx_vu_meter_info, /* shared */
844 .get = vx_peak_meter_get,
847 static snd_kcontrol_new_t vx_control_saturation = {
848 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
849 .name = "Input Saturation",
850 .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
851 .info = vx_saturation_info,
852 .get = vx_saturation_get,
861 int snd_vx_mixer_new(vx_core_t *chip)
865 snd_kcontrol_new_t temp;
866 snd_card_t *card = chip->card;
869 strcpy(card->mixername, card->driver);
871 /* output level controls */
872 for (i = 0; i < chip->hw->num_outs; i++) {
873 temp = vx_control_output_level;
875 if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0)
879 /* PCM volumes, switches, monitoring */
880 for (i = 0; i < chip->hw->num_outs; i++) {
882 temp = vx_control_audio_gain;
884 temp.name = "PCM Playback Volume";
885 temp.private_value = val;
886 if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0)
888 temp = vx_control_output_switch;
890 temp.private_value = val;
891 if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0)
893 temp = vx_control_monitor_gain;
895 temp.private_value = val;
896 if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0)
898 temp = vx_control_monitor_switch;
900 temp.private_value = val;
901 if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0)
904 for (i = 0; i < chip->hw->num_outs; i++) {
905 temp = vx_control_audio_gain;
907 temp.name = "PCM Capture Volume";
908 temp.private_value = (i * 2) | (1 << 8);
909 if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0)
914 if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_audio_src, chip))) < 0)
916 /* IEC958 controls */
917 if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_iec958_mask, chip))) < 0)
919 if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_iec958, chip))) < 0)
921 /* VU, peak, saturation meters */
922 for (c = 0; c < 2; c++) {
923 static char *dir[2] = { "Output", "Input" };
924 for (i = 0; i < chip->hw->num_ins; i++) {
925 int val = (i * 2) | (c << 8);
927 temp = vx_control_saturation;
929 temp.private_value = val;
930 if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0)
933 sprintf(name, "%s VU Meter", dir[c]);
934 temp = vx_control_vu_meter;
937 temp.private_value = val;
938 if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0)
940 sprintf(name, "%s Peak Meter", dir[c]);
941 temp = vx_control_peak_meter;
944 temp.private_value = val;
945 if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0)
949 vx_reset_audio_levels(chip);