Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6df22525 authored by Patrick Lai's avatar Patrick Lai Committed by Gerrit - the friendly Code Review server
Browse files

ASoC: msm: qdsp6v2: separate multi channel map for playback and record



During concurrency testing scenario which starting multi channel playback
followed by multi channel recording, it was found that channel map of
recording is over written by channel map of playback. This results in
failure to open ADM COPP as wrong channel mapping is being passed.

Separate multi channel map to playback and recording and make explicit
check to decide on which channel map to use during adm open call.

Change-Id: Ib355b95632f0f20b2062eb38b906c9d17aa827e5
CRs-fixed: 799164
Signed-off-by: default avatarPatrick Lai <plai@codeaurora.org>
Signed-off-by: default avatarPhani Kumar Uppalapati <phaniu@codeaurora.org>
parent 32d0ae45
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -87,9 +87,9 @@ void adm_ec_ref_rx_id(int port_id);

int adm_get_lowlatency_copp_id(int port_id);

void adm_set_multi_ch_map(char *channel_map);
int adm_set_multi_ch_map(char *channel_map, int path);

void adm_get_multi_ch_map(char *channel_map);
int adm_get_multi_ch_map(char *channel_map, int path);

int adm_validate_and_get_port_index(int port_id);

+3 −3
Original line number Diff line number Diff line
/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -472,7 +472,7 @@ static int msm_qti_pp_get_channel_map_mixer(struct snd_kcontrol *kcontrol,
	char channel_map[PCM_FORMAT_MAX_NUM_CHANNEL];
	int i;

	adm_get_multi_ch_map(channel_map);
	adm_get_multi_ch_map(channel_map, ADM_PATH_PLAYBACK);
	for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
		ucontrol->value.integer.value[i] = (unsigned) channel_map[i];
	return 0;
@@ -486,7 +486,7 @@ static int msm_qti_pp_put_channel_map_mixer(struct snd_kcontrol *kcontrol,

	for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
		channel_map[i] = (char)(ucontrol->value.integer.value[i]);
	adm_set_multi_ch_map(channel_map);
	adm_set_multi_ch_map(channel_map, ADM_PATH_PLAYBACK);

	return 0;
}
+121 −57
Original line number Diff line number Diff line
@@ -83,8 +83,15 @@ struct adm_multi_ch_map {
	char channel_mapping[PCM_FORMAT_MAX_NUM_CHANNEL];
};

static struct adm_multi_ch_map multi_ch_map = { false,
#define ADM_MCH_MAP_IDX_PLAYBACK 0
#define ADM_MCH_MAP_IDX_REC 1
static struct adm_multi_ch_map multi_ch_maps[2] = {
							{ false,
							{0, 0, 0, 0, 0, 0, 0, 0}
							},
							{ false,
							{0, 0, 0, 0, 0, 0, 0, 0}
							}
};

static int adm_get_parameters[MAX_COPPS_PER_PORT * ADM_GET_PARAMETER_LENGTH];
@@ -994,19 +1001,45 @@ static void adm_callback_debug_print(struct apr_client_data *data)
			__func__, data->opcode, data->payload_size);
}

void adm_set_multi_ch_map(char *channel_map)
int adm_set_multi_ch_map(char *channel_map, int path)
{
	memcpy(multi_ch_map.channel_mapping, channel_map,
	int idx;

	if (path == ADM_PATH_PLAYBACK) {
		idx = ADM_MCH_MAP_IDX_PLAYBACK;
	} else if (path == ADM_PATH_LIVE_REC) {
		idx = ADM_MCH_MAP_IDX_REC;
	} else {
		pr_err("%s: invalid attempt to set path %d\n", __func__, path);
		return -EINVAL;
	}

	memcpy(multi_ch_maps[idx].channel_mapping, channel_map,
		PCM_FORMAT_MAX_NUM_CHANNEL);
	multi_ch_map.set_channel_map = true;
	multi_ch_maps[idx].set_channel_map = true;

	return 0;
}

void adm_get_multi_ch_map(char *channel_map)
int adm_get_multi_ch_map(char *channel_map, int path)
{
	if (multi_ch_map.set_channel_map) {
		memcpy(channel_map, multi_ch_map.channel_mapping,
	int idx;

	if (path == ADM_PATH_PLAYBACK) {
		idx = ADM_MCH_MAP_IDX_PLAYBACK;
	} else if (path == ADM_PATH_LIVE_REC) {
		idx = ADM_MCH_MAP_IDX_REC;
	} else {
		pr_err("%s: invalid attempt to get path %d\n", __func__, path);
		return -EINVAL;
	}

	if (multi_ch_maps[idx].set_channel_map) {
		memcpy(channel_map, multi_ch_maps[idx].channel_mapping,
		       PCM_FORMAT_MAX_NUM_CHANNEL);
	}

	return 0;
}

static int32_t adm_callback(struct apr_client_data *data, void *priv)
@@ -1814,6 +1847,79 @@ fail_cmd:
	return ret;
}

int adm_arrange_mch_map(struct adm_cmd_device_open_v5 *open, int path,
			 int channel_mode)
{
	int rc = 0, idx;

	memset(open->dev_channel_mapping, 0,
	       PCM_FORMAT_MAX_NUM_CHANNEL);

	if (channel_mode == 1)	{
		open->dev_channel_mapping[0] = PCM_CHANNEL_FC;
	} else if (channel_mode == 2) {
		open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
		open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
	} else if (channel_mode == 3)	{
		open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
		open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
		open->dev_channel_mapping[2] = PCM_CHANNEL_FC;
	} else if (channel_mode == 4) {
		open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
		open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
		open->dev_channel_mapping[2] = PCM_CHANNEL_LS;
		open->dev_channel_mapping[3] = PCM_CHANNEL_RS;
	} else if (channel_mode == 5) {
		open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
		open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
		open->dev_channel_mapping[2] = PCM_CHANNEL_FC;
		open->dev_channel_mapping[3] = PCM_CHANNEL_LS;
		open->dev_channel_mapping[4] = PCM_CHANNEL_RS;
	} else if (channel_mode == 6) {
		open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
		open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
		open->dev_channel_mapping[2] = PCM_CHANNEL_LFE;
		open->dev_channel_mapping[3] = PCM_CHANNEL_FC;
		open->dev_channel_mapping[4] = PCM_CHANNEL_LS;
		open->dev_channel_mapping[5] = PCM_CHANNEL_RS;
	} else if (channel_mode == 8) {
		open->dev_channel_mapping[0] = PCM_CHANNEL_FL;
		open->dev_channel_mapping[1] = PCM_CHANNEL_FR;
		open->dev_channel_mapping[2] = PCM_CHANNEL_LFE;
		open->dev_channel_mapping[3] = PCM_CHANNEL_FC;
		open->dev_channel_mapping[4] = PCM_CHANNEL_LS;
		open->dev_channel_mapping[5] = PCM_CHANNEL_RS;
		open->dev_channel_mapping[6] = PCM_CHANNEL_LB;
		open->dev_channel_mapping[7] = PCM_CHANNEL_RB;
	} else {
		pr_err("%s: invalid num_chan %d\n", __func__,
			channel_mode);
		rc = -EINVAL;
		goto inval_ch_mod;
	}

	switch (path) {
	case ADM_PATH_PLAYBACK:
		idx = ADM_MCH_MAP_IDX_PLAYBACK;
		break;
	case ADM_PATH_LIVE_REC:
		idx = ADM_MCH_MAP_IDX_REC;
		break;
	default:
		goto non_mch_path;
		break;
	};

	if ((open->dev_num_channel > 2) && multi_ch_maps[idx].set_channel_map)
		memcpy(open->dev_channel_mapping,
		       multi_ch_maps[idx].channel_mapping,
		       PCM_FORMAT_MAX_NUM_CHANNEL);

non_mch_path:
inval_ch_mod:
	return rc;
}

int adm_open(int port_id, int path, int rate, int channel_mode, int topology,
	     int perf_mode, uint16_t bit_width, int app_type, int acdb_id)
{
@@ -1963,53 +2069,11 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology,
		WARN_ON((perf_mode == ULTRA_LOW_LATENCY_PCM_MODE) &&
			(rate != ULL_SUPPORTED_SAMPLE_RATE));
		open.sample_rate  = rate;
		memset(open.dev_channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);

		if (channel_mode == 1)	{
			open.dev_channel_mapping[0] = PCM_CHANNEL_FC;
		} else if (channel_mode == 2) {
			open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
			open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
		} else if (channel_mode == 3)	{
			open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
			open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
			open.dev_channel_mapping[2] = PCM_CHANNEL_FC;
		} else if (channel_mode == 4) {
			open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
			open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
			open.dev_channel_mapping[2] = PCM_CHANNEL_LS;
			open.dev_channel_mapping[3] = PCM_CHANNEL_RS;
		} else if (channel_mode == 5) {
			open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
			open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
			open.dev_channel_mapping[2] = PCM_CHANNEL_FC;
			open.dev_channel_mapping[3] = PCM_CHANNEL_LS;
			open.dev_channel_mapping[4] = PCM_CHANNEL_RS;
		} else if (channel_mode == 6) {
			open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
			open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
			open.dev_channel_mapping[2] = PCM_CHANNEL_LFE;
			open.dev_channel_mapping[3] = PCM_CHANNEL_FC;
			open.dev_channel_mapping[4] = PCM_CHANNEL_LS;
			open.dev_channel_mapping[5] = PCM_CHANNEL_RS;
		} else if (channel_mode == 8) {
			open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
			open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
			open.dev_channel_mapping[2] = PCM_CHANNEL_LFE;
			open.dev_channel_mapping[3] = PCM_CHANNEL_FC;
			open.dev_channel_mapping[4] = PCM_CHANNEL_LS;
			open.dev_channel_mapping[5] = PCM_CHANNEL_RS;
			open.dev_channel_mapping[6] = PCM_CHANNEL_LB;
			open.dev_channel_mapping[7] = PCM_CHANNEL_RB;
		} else {
			pr_err("%s: invalid num_chan %d\n", __func__,
					channel_mode);
			return -EINVAL;
		}
		if ((open.dev_num_channel > 2) && multi_ch_map.set_channel_map)
			memcpy(open.dev_channel_mapping,
			       multi_ch_map.channel_mapping,
			       PCM_FORMAT_MAX_NUM_CHANNEL);
		ret = adm_arrange_mch_map(&open, path, channel_mode);

		if (ret)
			return ret;

		pr_debug("%s: port_id=0x%x rate=%d topology_id=0x%X\n",
			__func__, open.endpoint_id_1, open.sample_rate,