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

Commit 54e9070b authored by Vaibhav Agarwal's avatar Vaibhav Agarwal Committed by Greg Kroah-Hartman
Browse files

greybus: audio: Reorder gb_deactivate sequence to avoid protocol error



gb_activate_tx/rx is triggered from _prepare() & gb_deactivate
from shutdown(). This may cause protocol error in case shutdown
executes without _prepare due to some hw_params failure.

Also, reorganise _prepare & _shutdown calls to make it more
readable & cleaner.

Signed-off-by: default avatarVaibhav Agarwal <vaibhav.agarwal@linaro.org>
Reviewed-by: default avatarMark Greer <mgreer@animalcreek.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@google.com>
parent 2b8c2b51
Loading
Loading
Loading
Loading
+171 −96
Original line number Diff line number Diff line
@@ -395,12 +395,88 @@ static int gbcodec_startup(struct snd_pcm_substream *substream,
	return ret;
}

static int gbmodule_shutdown_tx(struct gbaudio_module_info *module,
				struct gbaudio_data_connection *data,
				int codec_state, struct device *dev)
{
	int ret, module_state;
	__u16 i2s_port, cportid;

	module_state = module->ctrlstate[0];
	if (module_state == GBAUDIO_CODEC_SHUTDOWN) {
		dev_dbg(dev, "%s: module already configured\n",
			module->name);
		return 0;
	}

	if (codec_state == GBAUDIO_CODEC_STOP) {
		ret = gb_audio_apbridgea_shutdown_tx(data->connection, 0);
		if (ret)
			return ret;
	}

	/* deactivate */
	cportid = data->connection->intf_cport_id;
	if (module_state >= GBAUDIO_CODEC_PREPARE) {
		ret = gb_audio_gb_deactivate_tx(module->mgmt_connection,
						cportid);
		if (ret)
			return ret;
	}

	/* unregister cport */
	i2s_port = 0;	/* fixed for now */
	cportid = data->connection->hd_cport_id;
	ret = gb_audio_apbridgea_unregister_cport(data->connection, i2s_port,
						  cportid,
						  AUDIO_APBRIDGEA_DIRECTION_TX);

	return ret;
}

static int gbmodule_shutdown_rx(struct gbaudio_module_info *module,
				struct gbaudio_data_connection *data,
				int codec_state, struct device *dev)
{
	int ret, module_state;
	__u16 i2s_port, cportid;

	module_state = module->ctrlstate[1];
	if (module_state == GBAUDIO_CODEC_SHUTDOWN) {
		dev_dbg(dev, "%s: module already configured\n",
			module->name);
		return 0;
	}

	if (codec_state == GBAUDIO_CODEC_STOP) {
		ret = gb_audio_apbridgea_shutdown_rx(data->connection, 0);
		if (ret)
			return ret;
	}

	/* deactivate */
	cportid = data->connection->intf_cport_id;
	if (module_state >= GBAUDIO_CODEC_PREPARE) {
		ret = gb_audio_gb_deactivate_rx(module->mgmt_connection,
						cportid);
		if (ret)
			return ret;
	}

	/* unregister cport */
	i2s_port = 0;	/* fixed for now */
	cportid = data->connection->hd_cport_id;
	ret = gb_audio_apbridgea_unregister_cport(data->connection, i2s_port,
						  cportid,
						  AUDIO_APBRIDGEA_DIRECTION_RX);

	return ret;
}

static void gbcodec_shutdown(struct snd_pcm_substream *substream,
			     struct snd_soc_dai *dai)
{
	int ret;
	__u16 i2s_port, cportid;
	int state, module_state;
	int ret, state;
	struct gbaudio_module_info *module;
	struct gbaudio_data_connection *data;
	struct gbaudio_codec_info *codec = dev_get_drvdata(dai->dev);
@@ -423,14 +499,6 @@ static void gbcodec_shutdown(struct snd_pcm_substream *substream,
			mutex_unlock(&module->lock);
			continue;
		}
		module_state = module->ctrlstate[substream->stream];
		if (module_state == GBAUDIO_CODEC_SHUTDOWN) {
			dev_dbg(codec->dev, "%s: module already configured\n",
				module->name);
			mutex_unlock(&module->lock);
			continue;
		}

		/* find the dai */
		data = find_data(module, dai->name);
		if (!data) {
@@ -440,32 +508,18 @@ static void gbcodec_shutdown(struct snd_pcm_substream *substream,
			continue;
		}

		/* deactivate */
		cportid = data->connection->intf_cport_id;
		switch (substream->stream) {
		case SNDRV_PCM_STREAM_CAPTURE:
			ret = gb_audio_gb_deactivate_rx(module->mgmt_connection,
							cportid);
			/* unregister cport */
			i2s_port = 0;	/* fixed for now */
			cportid = data->connection->hd_cport_id;
			ret = gb_audio_apbridgea_unregister_cport(
					data->connection, i2s_port, cportid,
					AUDIO_APBRIDGEA_DIRECTION_RX);
			break;
		case SNDRV_PCM_STREAM_PLAYBACK:
			ret = gb_audio_gb_deactivate_tx(module->mgmt_connection,
							cportid);
			/* unregister cport */
			i2s_port = 0;	/* fixed for now */
			cportid = data->connection->hd_cport_id;
			ret = gb_audio_apbridgea_unregister_cport(
					data->connection, i2s_port, cportid,
					AUDIO_APBRIDGEA_DIRECTION_TX);
			ret = gbmodule_shutdown_tx(module, data, state,
						   dai->dev);
			break;
		case SNDRV_PCM_STREAM_CAPTURE:
			ret = gbmodule_shutdown_rx(module, data, state,
						   dai->dev);
			break;
		}
		dev_dbg(dai->dev, "Unregister %s:%d DAI, ret:%d\n", dai->name,
			cportid, ret);
		dev_dbg(dai->dev, "Unregister %s DAI, ret:%d\n", dai->name,
			ret);
		state = GBAUDIO_CODEC_SHUTDOWN;
		module->ctrlstate[substream->stream] = state;
		dev_dbg(dai->dev, "%s: state:%d\n", module->name, state);
@@ -589,14 +643,82 @@ static int gbcodec_hw_params(struct snd_pcm_substream *substream,
	return ret;
}

static int gbmodule_prepare_tx(struct gbaudio_module_info *module,
			       struct gbaudio_data_connection *data,
			       int codec_state, struct device *dev)
{
	int ret;
	uint16_t data_cport;

	data_cport = data->connection->intf_cport_id;
	ret = gb_audio_gb_set_tx_data_size(module->mgmt_connection, data_cport,
					   192);
	if (ret) {
		dev_err(dev, "%d:Error during set_tx_data_size, cport:%d\n",
			ret, data_cport);
		return ret;
	}
	if (codec_state < GBAUDIO_CODEC_PREPARE) {
		ret = gb_audio_apbridgea_set_tx_data_size(data->connection, 0,
							  192);
		if (ret) {
			dev_err(dev,
				"%d:Error during apbridgea set_tx_data_size, cport\n",
				ret);
			return ret;
		}
	}
	ret = gb_audio_gb_activate_tx(module->mgmt_connection,
				      data_cport);
	if (ret)
		dev_err(dev, "%s:Error during activate stream,%d\n",
			module->name, ret);

	return ret;
}

static int gbmodule_prepare_rx(struct gbaudio_module_info *module,
			       struct gbaudio_data_connection *data,
			       int codec_state, struct device *dev)
{
	int ret;
	uint16_t data_cport;

	data_cport = data->connection->intf_cport_id;

	ret = gb_audio_gb_set_rx_data_size(module->mgmt_connection, data_cport,
					   192);
	if (ret) {
		dev_err(dev, "%d:Error during set_rx_data_size, cport:%d\n",
			ret, data_cport);
		return ret;
	}
	if (codec_state < GBAUDIO_CODEC_PREPARE) {
		ret = gb_audio_apbridgea_set_rx_data_size(data->connection, 0,
							  192);
		if (ret) {
			dev_err(dev,
				"%d:Error during apbridgea_set_rx_data_size\n",
				ret);
			return ret;
		}
	}
	ret = gb_audio_gb_activate_rx(module->mgmt_connection,
				      data_cport);
	if (ret)
		dev_err(dev, "%s:Error during activate stream,%d\n",
			module->name, ret);

	return ret;
}

static int gbcodec_prepare(struct snd_pcm_substream *substream,
			   struct snd_soc_dai *dai)
{
	int ret;
	uint16_t data_cport;
	struct gbaudio_data_connection *data;
	struct gbaudio_module_info *module;
	int state;
	struct gbaudio_data_connection *data;
	struct gbaudio_codec_info *codec = dev_get_drvdata(dai->dev);

	mutex_lock(&codec->lock);
@@ -623,71 +745,24 @@ static int gbcodec_prepare(struct snd_pcm_substream *substream,
			mutex_unlock(&module->lock);
			continue;
		}
		/* deactivate rx/tx */
		data_cport = data->connection->intf_cport_id;

		switch (substream->stream) {
		case SNDRV_PCM_STREAM_PLAYBACK:
			ret = gbmodule_prepare_tx(module, data, state,
						  dai->dev);
			break;
		case SNDRV_PCM_STREAM_CAPTURE:
			ret = gb_audio_gb_set_rx_data_size(
						module->mgmt_connection,
						data_cport, 192);
			if (ret) {
				dev_err(dai->dev,
					"%d:Error during set_rx_data_size, cport:%d\n",
					ret, data_cport);
				mutex_unlock(&module->lock);
				goto func_exit;
			}
			if (state < GBAUDIO_CODEC_PREPARE) {
				ret = gb_audio_apbridgea_set_rx_data_size(
							data->connection, 0,
							192);
				if (ret) {
					dev_err(dai->dev,
				"%d:Error during apbridgea_set_rx_data_size\n",
				ret);
					mutex_unlock(&module->lock);
					goto func_exit;
				}
			}
			ret = gb_audio_gb_activate_rx(module->mgmt_connection,
						      data_cport);
			if (ret)
				dev_err(dai->dev,
					"%s:Error during activate stream,%d\n",
					module->name, ret);
			ret = gbmodule_prepare_rx(module, data, state,
						  dai->dev);
			break;
		case SNDRV_PCM_STREAM_PLAYBACK:
			ret = gb_audio_gb_set_tx_data_size(
						module->mgmt_connection,
						data_cport, 192);
			if (ret) {
				dev_err(dai->dev,
					"%d:Error during module set_tx_data_size, cport:%d\n",
					ret, data_cport);
				mutex_unlock(&module->lock);
				goto func_exit;
		}
			if (state < GBAUDIO_CODEC_PREPARE) {
				ret = gb_audio_apbridgea_set_tx_data_size(
							data->connection, 0,
							192);
		if (ret == -ENODEV)
			continue;
		if (ret) {
					dev_err(dai->dev,
						"%d:Error during apbridgea set_tx_data_size, cport\n",
						ret);
			mutex_unlock(&module->lock);
			goto func_exit;
		}
			}
			ret = gb_audio_gb_activate_tx(module->mgmt_connection,
						      data_cport);
			if (ret)
				dev_err(dai->dev,
					"%s:Error during activate stream,%d\n",
					module->name, ret);
			break;
		}

		state = GBAUDIO_CODEC_PREPARE;
		module->ctrlstate[substream->stream] = state;
		dev_dbg(dai->dev, "%s: state:%d\n", module->name, state);
@@ -697,7 +772,7 @@ static int gbcodec_prepare(struct snd_pcm_substream *substream,

func_exit:
	mutex_unlock(&codec->lock);
	return 0;
	return ret;
}

static int gbcodec_trigger(struct snd_pcm_substream *substream, int cmd,