1226 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.4 *5 * @File ctmixer.c6 *7 * @Brief8 * This file contains the implementation of alsa mixer device functions.9 *10 * @Author Liu Chun11 * @Date May 28 200812 */13 14 15#include "ctmixer.h"16#include "ctamixer.h"17#include <linux/slab.h>18#include <sound/core.h>19#include <sound/control.h>20#include <sound/asoundef.h>21#include <sound/pcm.h>22#include <sound/tlv.h>23 24enum CT_SUM_CTL {25 SUM_IN_F,26 SUM_IN_R,27 SUM_IN_C,28 SUM_IN_S,29 SUM_IN_F_C,30 31 NUM_CT_SUMS32};33 34enum CT_AMIXER_CTL {35 /* volume control mixers */36 AMIXER_MASTER_F,37 AMIXER_MASTER_R,38 AMIXER_MASTER_C,39 AMIXER_MASTER_S,40 AMIXER_PCM_F,41 AMIXER_PCM_R,42 AMIXER_PCM_C,43 AMIXER_PCM_S,44 AMIXER_SPDIFI,45 AMIXER_LINEIN,46 AMIXER_MIC,47 AMIXER_SPDIFO,48 AMIXER_WAVE_F,49 AMIXER_WAVE_R,50 AMIXER_WAVE_C,51 AMIXER_WAVE_S,52 AMIXER_MASTER_F_C,53 AMIXER_PCM_F_C,54 AMIXER_SPDIFI_C,55 AMIXER_LINEIN_C,56 AMIXER_MIC_C,57 58 /* this should always be the last one */59 NUM_CT_AMIXERS60};61 62enum CTALSA_MIXER_CTL {63 /* volume control mixers */64 MIXER_MASTER_P,65 MIXER_PCM_P,66 MIXER_LINEIN_P,67 MIXER_MIC_P,68 MIXER_SPDIFI_P,69 MIXER_SPDIFO_P,70 MIXER_WAVEF_P,71 MIXER_WAVER_P,72 MIXER_WAVEC_P,73 MIXER_WAVES_P,74 MIXER_MASTER_C,75 MIXER_PCM_C,76 MIXER_LINEIN_C,77 MIXER_MIC_C,78 MIXER_SPDIFI_C,79 80 /* switch control mixers */81 MIXER_PCM_C_S,82 MIXER_LINEIN_C_S,83 MIXER_MIC_C_S,84 MIXER_SPDIFI_C_S,85 MIXER_SPDIFO_P_S,86 MIXER_WAVEF_P_S,87 MIXER_WAVER_P_S,88 MIXER_WAVEC_P_S,89 MIXER_WAVES_P_S,90 MIXER_DIGITAL_IO_S,91 MIXER_IEC958_MASK,92 MIXER_IEC958_DEFAULT,93 MIXER_IEC958_STREAM,94 95 /* this should always be the last one */96 NUM_CTALSA_MIXERS97};98 99#define VOL_MIXER_START MIXER_MASTER_P100#define VOL_MIXER_END MIXER_SPDIFI_C101#define VOL_MIXER_NUM (VOL_MIXER_END - VOL_MIXER_START + 1)102#define SWH_MIXER_START MIXER_PCM_C_S103#define SWH_MIXER_END MIXER_DIGITAL_IO_S104#define SWH_CAPTURE_START MIXER_PCM_C_S105#define SWH_CAPTURE_END MIXER_SPDIFI_C_S106 107#define CHN_NUM 2108 109struct ct_kcontrol_init {110 unsigned char ctl;111 char *name;112};113 114static struct ct_kcontrol_init115ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = {116 [MIXER_MASTER_P] = {117 .ctl = 1,118 .name = "Master Playback Volume",119 },120 [MIXER_MASTER_C] = {121 .ctl = 1,122 .name = "Master Capture Volume",123 },124 [MIXER_PCM_P] = {125 .ctl = 1,126 .name = "PCM Playback Volume",127 },128 [MIXER_PCM_C] = {129 .ctl = 1,130 .name = "PCM Capture Volume",131 },132 [MIXER_LINEIN_P] = {133 .ctl = 1,134 .name = "Line Playback Volume",135 },136 [MIXER_LINEIN_C] = {137 .ctl = 1,138 .name = "Line Capture Volume",139 },140 [MIXER_MIC_P] = {141 .ctl = 1,142 .name = "Mic Playback Volume",143 },144 [MIXER_MIC_C] = {145 .ctl = 1,146 .name = "Mic Capture Volume",147 },148 [MIXER_SPDIFI_P] = {149 .ctl = 1,150 .name = "IEC958 Playback Volume",151 },152 [MIXER_SPDIFI_C] = {153 .ctl = 1,154 .name = "IEC958 Capture Volume",155 },156 [MIXER_SPDIFO_P] = {157 .ctl = 1,158 .name = "Digital Playback Volume",159 },160 [MIXER_WAVEF_P] = {161 .ctl = 1,162 .name = "Front Playback Volume",163 },164 [MIXER_WAVES_P] = {165 .ctl = 1,166 .name = "Side Playback Volume",167 },168 [MIXER_WAVEC_P] = {169 .ctl = 1,170 .name = "Center/LFE Playback Volume",171 },172 [MIXER_WAVER_P] = {173 .ctl = 1,174 .name = "Surround Playback Volume",175 },176 [MIXER_PCM_C_S] = {177 .ctl = 1,178 .name = "PCM Capture Switch",179 },180 [MIXER_LINEIN_C_S] = {181 .ctl = 1,182 .name = "Line Capture Switch",183 },184 [MIXER_MIC_C_S] = {185 .ctl = 1,186 .name = "Mic Capture Switch",187 },188 [MIXER_SPDIFI_C_S] = {189 .ctl = 1,190 .name = "IEC958 Capture Switch",191 },192 [MIXER_SPDIFO_P_S] = {193 .ctl = 1,194 .name = "Digital Playback Switch",195 },196 [MIXER_WAVEF_P_S] = {197 .ctl = 1,198 .name = "Front Playback Switch",199 },200 [MIXER_WAVES_P_S] = {201 .ctl = 1,202 .name = "Side Playback Switch",203 },204 [MIXER_WAVEC_P_S] = {205 .ctl = 1,206 .name = "Center/LFE Playback Switch",207 },208 [MIXER_WAVER_P_S] = {209 .ctl = 1,210 .name = "Surround Playback Switch",211 },212 [MIXER_DIGITAL_IO_S] = {213 .ctl = 0,214 .name = "Digit-IO Playback Switch",215 },216};217 218static void219ct_mixer_recording_select(struct ct_mixer *mixer, enum CT_AMIXER_CTL type);220 221static void222ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type);223 224/* FIXME: this static looks like it would fail if more than one card was */225/* installed. */226static struct snd_kcontrol *kctls[2] = {NULL};227 228static enum CT_AMIXER_CTL get_amixer_index(enum CTALSA_MIXER_CTL alsa_index)229{230 switch (alsa_index) {231 case MIXER_MASTER_P: return AMIXER_MASTER_F;232 case MIXER_MASTER_C: return AMIXER_MASTER_F_C;233 case MIXER_PCM_P: return AMIXER_PCM_F;234 case MIXER_PCM_C:235 case MIXER_PCM_C_S: return AMIXER_PCM_F_C;236 case MIXER_LINEIN_P: return AMIXER_LINEIN;237 case MIXER_LINEIN_C:238 case MIXER_LINEIN_C_S: return AMIXER_LINEIN_C;239 case MIXER_MIC_P: return AMIXER_MIC;240 case MIXER_MIC_C:241 case MIXER_MIC_C_S: return AMIXER_MIC_C;242 case MIXER_SPDIFI_P: return AMIXER_SPDIFI;243 case MIXER_SPDIFI_C:244 case MIXER_SPDIFI_C_S: return AMIXER_SPDIFI_C;245 case MIXER_SPDIFO_P: return AMIXER_SPDIFO;246 case MIXER_WAVEF_P: return AMIXER_WAVE_F;247 case MIXER_WAVES_P: return AMIXER_WAVE_S;248 case MIXER_WAVEC_P: return AMIXER_WAVE_C;249 case MIXER_WAVER_P: return AMIXER_WAVE_R;250 default: return NUM_CT_AMIXERS;251 }252}253 254static enum CT_AMIXER_CTL get_recording_amixer(enum CT_AMIXER_CTL index)255{256 switch (index) {257 case AMIXER_MASTER_F: return AMIXER_MASTER_F_C;258 case AMIXER_PCM_F: return AMIXER_PCM_F_C;259 case AMIXER_SPDIFI: return AMIXER_SPDIFI_C;260 case AMIXER_LINEIN: return AMIXER_LINEIN_C;261 case AMIXER_MIC: return AMIXER_MIC_C;262 default: return NUM_CT_AMIXERS;263 }264}265 266static unsigned char267get_switch_state(struct ct_mixer *mixer, enum CTALSA_MIXER_CTL type)268{269 return (mixer->switch_state & (0x1 << (type - SWH_MIXER_START)))270 ? 1 : 0;271}272 273static void274set_switch_state(struct ct_mixer *mixer,275 enum CTALSA_MIXER_CTL type, unsigned char state)276{277 if (state)278 mixer->switch_state |= (0x1 << (type - SWH_MIXER_START));279 else280 mixer->switch_state &= ~(0x1 << (type - SWH_MIXER_START));281}282 283#if 0 /* not used */284/* Map integer value ranging from 0 to 65535 to 14-bit float value ranging285 * from 2^-6 to (1+1023/1024) */286static unsigned int uint16_to_float14(unsigned int x)287{288 unsigned int i;289 290 if (x < 17)291 return 0;292 293 x *= 2031;294 x /= 65535;295 x += 16;296 297 /* i <= 6 */298 for (i = 0; !(x & 0x400); i++)299 x <<= 1;300 301 x = (((7 - i) & 0x7) << 10) | (x & 0x3ff);302 303 return x;304}305 306static unsigned int float14_to_uint16(unsigned int x)307{308 unsigned int e;309 310 if (!x)311 return x;312 313 e = (x >> 10) & 0x7;314 x &= 0x3ff;315 x += 1024;316 x >>= (7 - e);317 x -= 16;318 x *= 65535;319 x /= 2031;320 321 return x;322}323#endif /* not used */324 325#define VOL_SCALE 0x1c326#define VOL_MAX 0x100327 328static const DECLARE_TLV_DB_SCALE(ct_vol_db_scale, -6400, 25, 1);329 330static int ct_alsa_mix_volume_info(struct snd_kcontrol *kcontrol,331 struct snd_ctl_elem_info *uinfo)332{333 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;334 uinfo->count = 2;335 uinfo->value.integer.min = 0;336 uinfo->value.integer.max = VOL_MAX;337 338 return 0;339}340 341static int ct_alsa_mix_volume_get(struct snd_kcontrol *kcontrol,342 struct snd_ctl_elem_value *ucontrol)343{344 struct ct_atc *atc = snd_kcontrol_chip(kcontrol);345 enum CT_AMIXER_CTL type = get_amixer_index(kcontrol->private_value);346 struct amixer *amixer;347 int i, val;348 349 for (i = 0; i < 2; i++) {350 amixer = ((struct ct_mixer *)atc->mixer)->351 amixers[type*CHN_NUM+i];352 val = amixer->ops->get_scale(amixer) / VOL_SCALE;353 if (val < 0)354 val = 0;355 else if (val > VOL_MAX)356 val = VOL_MAX;357 ucontrol->value.integer.value[i] = val;358 }359 360 return 0;361}362 363static int ct_alsa_mix_volume_put(struct snd_kcontrol *kcontrol,364 struct snd_ctl_elem_value *ucontrol)365{366 struct ct_atc *atc = snd_kcontrol_chip(kcontrol);367 struct ct_mixer *mixer = atc->mixer;368 enum CT_AMIXER_CTL type = get_amixer_index(kcontrol->private_value);369 struct amixer *amixer;370 int i, j, val, oval, change = 0;371 372 for (i = 0; i < 2; i++) {373 val = ucontrol->value.integer.value[i];374 if (val < 0)375 val = 0;376 else if (val > VOL_MAX)377 val = VOL_MAX;378 val *= VOL_SCALE;379 amixer = mixer->amixers[type*CHN_NUM+i];380 oval = amixer->ops->get_scale(amixer);381 if (val != oval) {382 amixer->ops->set_scale(amixer, val);383 amixer->ops->commit_write(amixer);384 change = 1;385 /* Synchronize Master/PCM playback AMIXERs. */386 if (AMIXER_MASTER_F == type || AMIXER_PCM_F == type) {387 for (j = 1; j < 4; j++) {388 amixer = mixer->389 amixers[(type+j)*CHN_NUM+i];390 amixer->ops->set_scale(amixer, val);391 amixer->ops->commit_write(amixer);392 }393 }394 }395 }396 397 return change;398}399 400static struct snd_kcontrol_new vol_ctl = {401 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |402 SNDRV_CTL_ELEM_ACCESS_TLV_READ,403 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,404 .info = ct_alsa_mix_volume_info,405 .get = ct_alsa_mix_volume_get,406 .put = ct_alsa_mix_volume_put,407 .tlv = { .p = ct_vol_db_scale },408};409 410static int output_switch_info(struct snd_kcontrol *kcontrol,411 struct snd_ctl_elem_info *info)412{413 static const char *const names[3] = {414 "FP Headphones", "Headphones", "Speakers"415 };416 417 return snd_ctl_enum_info(info, 1, 3, names);418}419 420static int output_switch_get(struct snd_kcontrol *kcontrol,421 struct snd_ctl_elem_value *ucontrol)422{423 struct ct_atc *atc = snd_kcontrol_chip(kcontrol);424 ucontrol->value.enumerated.item[0] = atc->output_switch_get(atc);425 return 0;426}427 428static int output_switch_put(struct snd_kcontrol *kcontrol,429 struct snd_ctl_elem_value *ucontrol)430{431 struct ct_atc *atc = snd_kcontrol_chip(kcontrol);432 if (ucontrol->value.enumerated.item[0] > 2)433 return -EINVAL;434 return atc->output_switch_put(atc, ucontrol->value.enumerated.item[0]);435}436 437static struct snd_kcontrol_new output_ctl = {438 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,439 .name = "Analog Output Playback Enum",440 .info = output_switch_info,441 .get = output_switch_get,442 .put = output_switch_put,443};444 445static int mic_source_switch_info(struct snd_kcontrol *kcontrol,446 struct snd_ctl_elem_info *info)447{448 static const char *const names[3] = {449 "Mic", "FP Mic", "Aux"450 };451 452 return snd_ctl_enum_info(info, 1, 3, names);453}454 455static int mic_source_switch_get(struct snd_kcontrol *kcontrol,456 struct snd_ctl_elem_value *ucontrol)457{458 struct ct_atc *atc = snd_kcontrol_chip(kcontrol);459 ucontrol->value.enumerated.item[0] = atc->mic_source_switch_get(atc);460 return 0;461}462 463static int mic_source_switch_put(struct snd_kcontrol *kcontrol,464 struct snd_ctl_elem_value *ucontrol)465{466 struct ct_atc *atc = snd_kcontrol_chip(kcontrol);467 if (ucontrol->value.enumerated.item[0] > 2)468 return -EINVAL;469 return atc->mic_source_switch_put(atc,470 ucontrol->value.enumerated.item[0]);471}472 473static struct snd_kcontrol_new mic_source_ctl = {474 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,475 .name = "Mic Source Capture Enum",476 .info = mic_source_switch_info,477 .get = mic_source_switch_get,478 .put = mic_source_switch_put,479};480 481static void482do_line_mic_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type)483{484 485 if (MIXER_LINEIN_C_S == type) {486 atc->select_line_in(atc);487 set_switch_state(atc->mixer, MIXER_MIC_C_S, 0);488 snd_ctl_notify(atc->card, SNDRV_CTL_EVENT_MASK_VALUE,489 &kctls[1]->id);490 } else if (MIXER_MIC_C_S == type) {491 atc->select_mic_in(atc);492 set_switch_state(atc->mixer, MIXER_LINEIN_C_S, 0);493 snd_ctl_notify(atc->card, SNDRV_CTL_EVENT_MASK_VALUE,494 &kctls[0]->id);495 }496}497 498static void499do_digit_io_switch(struct ct_atc *atc, int state)500{501 struct ct_mixer *mixer = atc->mixer;502 503 if (state) {504 atc->select_digit_io(atc);505 atc->spdif_out_unmute(atc,506 get_switch_state(mixer, MIXER_SPDIFO_P_S));507 atc->spdif_in_unmute(atc, 1);508 atc->line_in_unmute(atc, 0);509 return;510 }511 512 if (get_switch_state(mixer, MIXER_LINEIN_C_S))513 atc->select_line_in(atc);514 else if (get_switch_state(mixer, MIXER_MIC_C_S))515 atc->select_mic_in(atc);516 517 atc->spdif_out_unmute(atc, 0);518 atc->spdif_in_unmute(atc, 0);519 atc->line_in_unmute(atc, 1);520 return;521}522 523static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state)524{525 struct ct_mixer *mixer = atc->mixer;526 struct capabilities cap = atc->capabilities(atc);527 528 /* Do changes in mixer. */529 if ((SWH_CAPTURE_START <= type) && (SWH_CAPTURE_END >= type)) {530 if (state) {531 ct_mixer_recording_select(mixer,532 get_amixer_index(type));533 } else {534 ct_mixer_recording_unselect(mixer,535 get_amixer_index(type));536 }537 }538 /* Do changes out of mixer. */539 if (!cap.dedicated_mic &&540 (MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type)) {541 if (state)542 do_line_mic_switch(atc, type);543 atc->line_in_unmute(atc, state);544 } else if (cap.dedicated_mic && (MIXER_LINEIN_C_S == type))545 atc->line_in_unmute(atc, state);546 else if (cap.dedicated_mic && (MIXER_MIC_C_S == type))547 atc->mic_unmute(atc, state);548 else if (MIXER_SPDIFI_C_S == type)549 atc->spdif_in_unmute(atc, state);550 else if (MIXER_WAVEF_P_S == type)551 atc->line_front_unmute(atc, state);552 else if (MIXER_WAVES_P_S == type)553 atc->line_surround_unmute(atc, state);554 else if (MIXER_WAVEC_P_S == type)555 atc->line_clfe_unmute(atc, state);556 else if (MIXER_WAVER_P_S == type)557 atc->line_rear_unmute(atc, state);558 else if (MIXER_SPDIFO_P_S == type)559 atc->spdif_out_unmute(atc, state);560 else if (MIXER_DIGITAL_IO_S == type)561 do_digit_io_switch(atc, state);562 563 return;564}565 566static int ct_alsa_mix_switch_info(struct snd_kcontrol *kcontrol,567 struct snd_ctl_elem_info *uinfo)568{569 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;570 uinfo->count = 1;571 uinfo->value.integer.min = 0;572 uinfo->value.integer.max = 1;573 uinfo->value.integer.step = 1;574 575 return 0;576}577 578static int ct_alsa_mix_switch_get(struct snd_kcontrol *kcontrol,579 struct snd_ctl_elem_value *ucontrol)580{581 struct ct_mixer *mixer =582 ((struct ct_atc *)snd_kcontrol_chip(kcontrol))->mixer;583 enum CTALSA_MIXER_CTL type = kcontrol->private_value;584 585 ucontrol->value.integer.value[0] = get_switch_state(mixer, type);586 return 0;587}588 589static int ct_alsa_mix_switch_put(struct snd_kcontrol *kcontrol,590 struct snd_ctl_elem_value *ucontrol)591{592 struct ct_atc *atc = snd_kcontrol_chip(kcontrol);593 struct ct_mixer *mixer = atc->mixer;594 enum CTALSA_MIXER_CTL type = kcontrol->private_value;595 int state;596 597 state = ucontrol->value.integer.value[0];598 if (get_switch_state(mixer, type) == state)599 return 0;600 601 set_switch_state(mixer, type, state);602 do_switch(atc, type, state);603 604 return 1;605}606 607static struct snd_kcontrol_new swh_ctl = {608 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,609 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,610 .info = ct_alsa_mix_switch_info,611 .get = ct_alsa_mix_switch_get,612 .put = ct_alsa_mix_switch_put613};614 615static int ct_spdif_info(struct snd_kcontrol *kcontrol,616 struct snd_ctl_elem_info *uinfo)617{618 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;619 uinfo->count = 1;620 return 0;621}622 623static int ct_spdif_get_mask(struct snd_kcontrol *kcontrol,624 struct snd_ctl_elem_value *ucontrol)625{626 ucontrol->value.iec958.status[0] = 0xff;627 ucontrol->value.iec958.status[1] = 0xff;628 ucontrol->value.iec958.status[2] = 0xff;629 ucontrol->value.iec958.status[3] = 0xff;630 return 0;631}632 633static int ct_spdif_get(struct snd_kcontrol *kcontrol,634 struct snd_ctl_elem_value *ucontrol)635{636 struct ct_atc *atc = snd_kcontrol_chip(kcontrol);637 unsigned int status;638 639 atc->spdif_out_get_status(atc, &status);640 641 if (status == 0)642 status = SNDRV_PCM_DEFAULT_CON_SPDIF;643 644 ucontrol->value.iec958.status[0] = (status >> 0) & 0xff;645 ucontrol->value.iec958.status[1] = (status >> 8) & 0xff;646 ucontrol->value.iec958.status[2] = (status >> 16) & 0xff;647 ucontrol->value.iec958.status[3] = (status >> 24) & 0xff;648 649 return 0;650}651 652static int ct_spdif_put(struct snd_kcontrol *kcontrol,653 struct snd_ctl_elem_value *ucontrol)654{655 struct ct_atc *atc = snd_kcontrol_chip(kcontrol);656 int change;657 unsigned int status, old_status;658 659 status = (ucontrol->value.iec958.status[0] << 0) |660 (ucontrol->value.iec958.status[1] << 8) |661 (ucontrol->value.iec958.status[2] << 16) |662 (ucontrol->value.iec958.status[3] << 24);663 664 atc->spdif_out_get_status(atc, &old_status);665 change = (old_status != status);666 if (change)667 atc->spdif_out_set_status(atc, status);668 669 return change;670}671 672static struct snd_kcontrol_new iec958_mask_ctl = {673 .access = SNDRV_CTL_ELEM_ACCESS_READ,674 .iface = SNDRV_CTL_ELEM_IFACE_PCM,675 .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),676 .count = 1,677 .info = ct_spdif_info,678 .get = ct_spdif_get_mask,679 .private_value = MIXER_IEC958_MASK680};681 682static struct snd_kcontrol_new iec958_default_ctl = {683 .iface = SNDRV_CTL_ELEM_IFACE_PCM,684 .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),685 .count = 1,686 .info = ct_spdif_info,687 .get = ct_spdif_get,688 .put = ct_spdif_put,689 .private_value = MIXER_IEC958_DEFAULT690};691 692static struct snd_kcontrol_new iec958_ctl = {693 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,694 .iface = SNDRV_CTL_ELEM_IFACE_PCM,695 .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM),696 .count = 1,697 .info = ct_spdif_info,698 .get = ct_spdif_get,699 .put = ct_spdif_put,700 .private_value = MIXER_IEC958_STREAM701};702 703#define NUM_IEC958_CTL 3704 705static int706ct_mixer_kcontrol_new(struct ct_mixer *mixer, struct snd_kcontrol_new *new)707{708 struct snd_kcontrol *kctl;709 int err;710 711 kctl = snd_ctl_new1(new, mixer->atc);712 if (!kctl)713 return -ENOMEM;714 715 if (SNDRV_CTL_ELEM_IFACE_PCM == kctl->id.iface)716 kctl->id.device = IEC958;717 718 err = snd_ctl_add(mixer->atc->card, kctl);719 if (err)720 return err;721 722 switch (new->private_value) {723 case MIXER_LINEIN_C_S:724 kctls[0] = kctl; break;725 case MIXER_MIC_C_S:726 kctls[1] = kctl; break;727 default:728 break;729 }730 731 return 0;732}733 734static int ct_mixer_kcontrols_create(struct ct_mixer *mixer)735{736 enum CTALSA_MIXER_CTL type;737 struct ct_atc *atc = mixer->atc;738 struct capabilities cap = atc->capabilities(atc);739 int err;740 741 /* Create snd kcontrol instances on demand */742 for (type = VOL_MIXER_START; type <= VOL_MIXER_END; type++) {743 if (ct_kcontrol_init_table[type].ctl) {744 vol_ctl.name = ct_kcontrol_init_table[type].name;745 vol_ctl.private_value = (unsigned long)type;746 err = ct_mixer_kcontrol_new(mixer, &vol_ctl);747 if (err)748 return err;749 }750 }751 752 ct_kcontrol_init_table[MIXER_DIGITAL_IO_S].ctl = cap.digit_io_switch;753 754 for (type = SWH_MIXER_START; type <= SWH_MIXER_END; type++) {755 if (ct_kcontrol_init_table[type].ctl) {756 swh_ctl.name = ct_kcontrol_init_table[type].name;757 swh_ctl.private_value = (unsigned long)type;758 err = ct_mixer_kcontrol_new(mixer, &swh_ctl);759 if (err)760 return err;761 }762 }763 764 err = ct_mixer_kcontrol_new(mixer, &iec958_mask_ctl);765 if (err)766 return err;767 768 err = ct_mixer_kcontrol_new(mixer, &iec958_default_ctl);769 if (err)770 return err;771 772 err = ct_mixer_kcontrol_new(mixer, &iec958_ctl);773 if (err)774 return err;775 776 if (cap.output_switch) {777 err = ct_mixer_kcontrol_new(mixer, &output_ctl);778 if (err)779 return err;780 }781 782 if (cap.mic_source_switch) {783 err = ct_mixer_kcontrol_new(mixer, &mic_source_ctl);784 if (err)785 return err;786 }787 atc->line_front_unmute(atc, 1);788 set_switch_state(mixer, MIXER_WAVEF_P_S, 1);789 atc->line_surround_unmute(atc, 0);790 set_switch_state(mixer, MIXER_WAVES_P_S, 0);791 atc->line_clfe_unmute(atc, 0);792 set_switch_state(mixer, MIXER_WAVEC_P_S, 0);793 atc->line_rear_unmute(atc, 0);794 set_switch_state(mixer, MIXER_WAVER_P_S, 0);795 atc->spdif_out_unmute(atc, 0);796 set_switch_state(mixer, MIXER_SPDIFO_P_S, 0);797 atc->line_in_unmute(atc, 0);798 if (cap.dedicated_mic)799 atc->mic_unmute(atc, 0);800 atc->spdif_in_unmute(atc, 0);801 set_switch_state(mixer, MIXER_PCM_C_S, 0);802 set_switch_state(mixer, MIXER_LINEIN_C_S, 0);803 set_switch_state(mixer, MIXER_SPDIFI_C_S, 0);804 805 return 0;806}807 808static void809ct_mixer_recording_select(struct ct_mixer *mixer, enum CT_AMIXER_CTL type)810{811 struct amixer *amix_d;812 struct sum *sum_c;813 int i;814 815 for (i = 0; i < 2; i++) {816 amix_d = mixer->amixers[type*CHN_NUM+i];817 sum_c = mixer->sums[SUM_IN_F_C*CHN_NUM+i];818 amix_d->ops->set_sum(amix_d, sum_c);819 amix_d->ops->commit_write(amix_d);820 }821}822 823static void824ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type)825{826 struct amixer *amix_d;827 int i;828 829 for (i = 0; i < 2; i++) {830 amix_d = mixer->amixers[type*CHN_NUM+i];831 amix_d->ops->set_sum(amix_d, NULL);832 amix_d->ops->commit_write(amix_d);833 }834}835 836static int ct_mixer_get_resources(struct ct_mixer *mixer)837{838 struct sum_mgr *sum_mgr;839 struct sum *sum;840 struct sum_desc sum_desc = {0};841 struct amixer_mgr *amixer_mgr;842 struct amixer *amixer;843 struct amixer_desc am_desc = {0};844 int err;845 int i;846 847 /* Allocate sum resources for mixer obj */848 sum_mgr = (struct sum_mgr *)mixer->atc->rsc_mgrs[SUM];849 sum_desc.msr = mixer->atc->msr;850 for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) {851 err = sum_mgr->get_sum(sum_mgr, &sum_desc, &sum);852 if (err) {853 dev_err(mixer->atc->card->dev,854 "Failed to get sum resources for front output!\n");855 break;856 }857 mixer->sums[i] = sum;858 }859 if (err)860 goto error1;861 862 /* Allocate amixer resources for mixer obj */863 amixer_mgr = (struct amixer_mgr *)mixer->atc->rsc_mgrs[AMIXER];864 am_desc.msr = mixer->atc->msr;865 for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) {866 err = amixer_mgr->get_amixer(amixer_mgr, &am_desc, &amixer);867 if (err) {868 dev_err(mixer->atc->card->dev,869 "Failed to get amixer resources for mixer obj!\n");870 break;871 }872 mixer->amixers[i] = amixer;873 }874 if (err)875 goto error2;876 877 return 0;878 879error2:880 for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) {881 if (NULL != mixer->amixers[i]) {882 amixer = mixer->amixers[i];883 amixer_mgr->put_amixer(amixer_mgr, amixer);884 mixer->amixers[i] = NULL;885 }886 }887error1:888 for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) {889 if (NULL != mixer->sums[i]) {890 sum_mgr->put_sum(sum_mgr, (struct sum *)mixer->sums[i]);891 mixer->sums[i] = NULL;892 }893 }894 895 return err;896}897 898static int ct_mixer_get_mem(struct ct_mixer **rmixer)899{900 struct ct_mixer *mixer;901 int err;902 903 *rmixer = NULL;904 /* Allocate mem for mixer obj */905 mixer = kzalloc(sizeof(*mixer), GFP_KERNEL);906 if (!mixer)907 return -ENOMEM;908 909 mixer->amixers = kcalloc(NUM_CT_AMIXERS * CHN_NUM, sizeof(void *),910 GFP_KERNEL);911 if (!mixer->amixers) {912 err = -ENOMEM;913 goto error1;914 }915 mixer->sums = kcalloc(NUM_CT_SUMS * CHN_NUM, sizeof(void *),916 GFP_KERNEL);917 if (!mixer->sums) {918 err = -ENOMEM;919 goto error2;920 }921 922 *rmixer = mixer;923 return 0;924 925error2:926 kfree(mixer->amixers);927error1:928 kfree(mixer);929 return err;930}931 932static int ct_mixer_topology_build(struct ct_mixer *mixer)933{934 struct sum *sum;935 struct amixer *amix_d, *amix_s;936 enum CT_AMIXER_CTL i, j;937 enum CT_SUM_CTL k;938 939 /* Build topology from destination to source */940 941 /* Set up Master mixer */942 for (i = AMIXER_MASTER_F, k = SUM_IN_F;943 i <= AMIXER_MASTER_S; i++, k++) {944 amix_d = mixer->amixers[i*CHN_NUM];945 sum = mixer->sums[k*CHN_NUM];946 amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);947 amix_d = mixer->amixers[i*CHN_NUM+1];948 sum = mixer->sums[k*CHN_NUM+1];949 amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);950 }951 952 /* Set up Wave-out mixer */953 for (i = AMIXER_WAVE_F, j = AMIXER_MASTER_F;954 i <= AMIXER_WAVE_S; i++, j++) {955 amix_d = mixer->amixers[i*CHN_NUM];956 amix_s = mixer->amixers[j*CHN_NUM];957 amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);958 amix_d = mixer->amixers[i*CHN_NUM+1];959 amix_s = mixer->amixers[j*CHN_NUM+1];960 amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);961 }962 963 /* Set up S/PDIF-out mixer */964 amix_d = mixer->amixers[AMIXER_SPDIFO*CHN_NUM];965 amix_s = mixer->amixers[AMIXER_MASTER_F*CHN_NUM];966 amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);967 amix_d = mixer->amixers[AMIXER_SPDIFO*CHN_NUM+1];968 amix_s = mixer->amixers[AMIXER_MASTER_F*CHN_NUM+1];969 amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);970 971 /* Set up PCM-in mixer */972 for (i = AMIXER_PCM_F, k = SUM_IN_F; i <= AMIXER_PCM_S; i++, k++) {973 amix_d = mixer->amixers[i*CHN_NUM];974 sum = mixer->sums[k*CHN_NUM];975 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);976 amix_d = mixer->amixers[i*CHN_NUM+1];977 sum = mixer->sums[k*CHN_NUM+1];978 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);979 }980 981 /* Set up Line-in mixer */982 amix_d = mixer->amixers[AMIXER_LINEIN*CHN_NUM];983 sum = mixer->sums[SUM_IN_F*CHN_NUM];984 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);985 amix_d = mixer->amixers[AMIXER_LINEIN*CHN_NUM+1];986 sum = mixer->sums[SUM_IN_F*CHN_NUM+1];987 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);988 989 /* Set up Mic-in mixer */990 amix_d = mixer->amixers[AMIXER_MIC*CHN_NUM];991 sum = mixer->sums[SUM_IN_F*CHN_NUM];992 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);993 amix_d = mixer->amixers[AMIXER_MIC*CHN_NUM+1];994 sum = mixer->sums[SUM_IN_F*CHN_NUM+1];995 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);996 997 /* Set up S/PDIF-in mixer */998 amix_d = mixer->amixers[AMIXER_SPDIFI*CHN_NUM];999 sum = mixer->sums[SUM_IN_F*CHN_NUM];1000 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);1001 amix_d = mixer->amixers[AMIXER_SPDIFI*CHN_NUM+1];1002 sum = mixer->sums[SUM_IN_F*CHN_NUM+1];1003 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);1004 1005 /* Set up Master recording mixer */1006 amix_d = mixer->amixers[AMIXER_MASTER_F_C*CHN_NUM];1007 sum = mixer->sums[SUM_IN_F_C*CHN_NUM];1008 amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);1009 amix_d = mixer->amixers[AMIXER_MASTER_F_C*CHN_NUM+1];1010 sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];1011 amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);1012 1013 /* Set up PCM-in recording mixer */1014 amix_d = mixer->amixers[AMIXER_PCM_F_C*CHN_NUM];1015 sum = mixer->sums[SUM_IN_F_C*CHN_NUM];1016 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);1017 amix_d = mixer->amixers[AMIXER_PCM_F_C*CHN_NUM+1];1018 sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];1019 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);1020 1021 /* Set up Line-in recording mixer */1022 amix_d = mixer->amixers[AMIXER_LINEIN_C*CHN_NUM];1023 sum = mixer->sums[SUM_IN_F_C*CHN_NUM];1024 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);1025 amix_d = mixer->amixers[AMIXER_LINEIN_C*CHN_NUM+1];1026 sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];1027 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);1028 1029 /* Set up Mic-in recording mixer */1030 amix_d = mixer->amixers[AMIXER_MIC_C*CHN_NUM];1031 sum = mixer->sums[SUM_IN_F_C*CHN_NUM];1032 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);1033 amix_d = mixer->amixers[AMIXER_MIC_C*CHN_NUM+1];1034 sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];1035 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);1036 1037 /* Set up S/PDIF-in recording mixer */1038 amix_d = mixer->amixers[AMIXER_SPDIFI_C*CHN_NUM];1039 sum = mixer->sums[SUM_IN_F_C*CHN_NUM];1040 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);1041 amix_d = mixer->amixers[AMIXER_SPDIFI_C*CHN_NUM+1];1042 sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];1043 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);1044 1045 return 0;1046}1047 1048static int mixer_set_input_port(struct amixer *amixer, struct rsc *rsc)1049{1050 amixer->ops->set_input(amixer, rsc);1051 amixer->ops->commit_write(amixer);1052 1053 return 0;1054}1055 1056static enum CT_AMIXER_CTL port_to_amixer(enum MIXER_PORT_T type)1057{1058 switch (type) {1059 case MIX_WAVE_FRONT: return AMIXER_WAVE_F;1060 case MIX_WAVE_SURROUND: return AMIXER_WAVE_S;1061 case MIX_WAVE_CENTLFE: return AMIXER_WAVE_C;1062 case MIX_WAVE_REAR: return AMIXER_WAVE_R;1063 case MIX_PCMO_FRONT: return AMIXER_MASTER_F_C;1064 case MIX_SPDIF_OUT: return AMIXER_SPDIFO;1065 case MIX_LINE_IN: return AMIXER_LINEIN;1066 case MIX_MIC_IN: return AMIXER_MIC;1067 case MIX_SPDIF_IN: return AMIXER_SPDIFI;1068 case MIX_PCMI_FRONT: return AMIXER_PCM_F;1069 case MIX_PCMI_SURROUND: return AMIXER_PCM_S;1070 case MIX_PCMI_CENTLFE: return AMIXER_PCM_C;1071 case MIX_PCMI_REAR: return AMIXER_PCM_R;1072 default: return 0;1073 }1074}1075 1076static int mixer_get_output_ports(struct ct_mixer *mixer,1077 enum MIXER_PORT_T type,1078 struct rsc **rleft, struct rsc **rright)1079{1080 enum CT_AMIXER_CTL amix = port_to_amixer(type);1081 1082 if (NULL != rleft)1083 *rleft = &((struct amixer *)mixer->amixers[amix*CHN_NUM])->rsc;1084 1085 if (NULL != rright)1086 *rright =1087 &((struct amixer *)mixer->amixers[amix*CHN_NUM+1])->rsc;1088 1089 return 0;1090}1091 1092static int mixer_set_input_left(struct ct_mixer *mixer,1093 enum MIXER_PORT_T type, struct rsc *rsc)1094{1095 enum CT_AMIXER_CTL amix = port_to_amixer(type);1096 1097 mixer_set_input_port(mixer->amixers[amix*CHN_NUM], rsc);1098 amix = get_recording_amixer(amix);1099 if (amix < NUM_CT_AMIXERS)1100 mixer_set_input_port(mixer->amixers[amix*CHN_NUM], rsc);1101 1102 return 0;1103}1104 1105static int1106mixer_set_input_right(struct ct_mixer *mixer,1107 enum MIXER_PORT_T type, struct rsc *rsc)1108{1109 enum CT_AMIXER_CTL amix = port_to_amixer(type);1110 1111 mixer_set_input_port(mixer->amixers[amix*CHN_NUM+1], rsc);1112 amix = get_recording_amixer(amix);1113 if (amix < NUM_CT_AMIXERS)1114 mixer_set_input_port(mixer->amixers[amix*CHN_NUM+1], rsc);1115 1116 return 0;1117}1118 1119#ifdef CONFIG_PM_SLEEP1120static int mixer_resume(struct ct_mixer *mixer)1121{1122 int i, state;1123 struct amixer *amixer;1124 1125 /* resume topology and volume gain. */1126 for (i = 0; i < NUM_CT_AMIXERS*CHN_NUM; i++) {1127 amixer = mixer->amixers[i];1128 amixer->ops->commit_write(amixer);1129 }1130 1131 /* resume switch state. */1132 for (i = SWH_MIXER_START; i <= SWH_MIXER_END; i++) {1133 state = get_switch_state(mixer, i);1134 do_switch(mixer->atc, i, state);1135 }1136 1137 return 0;1138}1139#endif1140 1141int ct_mixer_destroy(struct ct_mixer *mixer)1142{1143 struct sum_mgr *sum_mgr = (struct sum_mgr *)mixer->atc->rsc_mgrs[SUM];1144 struct amixer_mgr *amixer_mgr =1145 (struct amixer_mgr *)mixer->atc->rsc_mgrs[AMIXER];1146 struct amixer *amixer;1147 int i = 0;1148 1149 /* Release amixer resources */1150 for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) {1151 if (NULL != mixer->amixers[i]) {1152 amixer = mixer->amixers[i];1153 amixer_mgr->put_amixer(amixer_mgr, amixer);1154 }1155 }1156 1157 /* Release sum resources */1158 for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) {1159 if (NULL != mixer->sums[i])1160 sum_mgr->put_sum(sum_mgr, (struct sum *)mixer->sums[i]);1161 }1162 1163 /* Release mem assigned to mixer object */1164 kfree(mixer->sums);1165 kfree(mixer->amixers);1166 kfree(mixer);1167 1168 return 0;1169}1170 1171int ct_mixer_create(struct ct_atc *atc, struct ct_mixer **rmixer)1172{1173 struct ct_mixer *mixer;1174 int err;1175 1176 *rmixer = NULL;1177 1178 /* Allocate mem for mixer obj */1179 err = ct_mixer_get_mem(&mixer);1180 if (err)1181 return err;1182 1183 mixer->switch_state = 0;1184 mixer->atc = atc;1185 /* Set operations */1186 mixer->get_output_ports = mixer_get_output_ports;1187 mixer->set_input_left = mixer_set_input_left;1188 mixer->set_input_right = mixer_set_input_right;1189#ifdef CONFIG_PM_SLEEP1190 mixer->resume = mixer_resume;1191#endif1192 1193 /* Allocate chip resources for mixer obj */1194 err = ct_mixer_get_resources(mixer);1195 if (err)1196 goto error;1197 1198 /* Build internal mixer topology */1199 ct_mixer_topology_build(mixer);1200 1201 *rmixer = mixer;1202 1203 return 0;1204 1205error:1206 ct_mixer_destroy(mixer);1207 return err;1208}1209 1210int ct_alsa_mix_create(struct ct_atc *atc,1211 enum CTALSADEVS device,1212 const char *device_name)1213{1214 int err;1215 1216 /* Create snd kcontrol instances on demand */1217 /* vol_ctl.device = swh_ctl.device = device; */ /* better w/ device 0 */1218 err = ct_mixer_kcontrols_create((struct ct_mixer *)atc->mixer);1219 if (err)1220 return err;1221 1222 strcpy(atc->card->mixername, device_name);1223 1224 return 0;1225}1226