brintos

brintos / linux-shallow public Read only

0
0
Text · 29.9 KiB · 6797fde Raw
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