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

Commit 20358d44 authored by Takashi Sakamoto's avatar Takashi Sakamoto Committed by Takashi Iwai
Browse files

ALSA: oxfw: start duplex streams if supported



It's inconvenient to handle two isochronous context separately
each other. This commit unifies the counters to handle the two
at the same time.

Signed-off-by: default avatarTakashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 521b2e11
Loading
Loading
Loading
Loading
+49 −53
Original line number Diff line number Diff line
@@ -254,96 +254,92 @@ int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw,
				  struct amdtp_stream *stream,
				  unsigned int rate, unsigned int pcm_channels)
{
	struct amdtp_stream *opposite;
	struct snd_oxfw_stream_formation formation;
	enum avc_general_plug_dir dir;
	unsigned int substreams, opposite_substreams;
	int err = 0;

	if (stream == &oxfw->tx_stream) {
		substreams = oxfw->capture_substreams;
		opposite = &oxfw->rx_stream;
		opposite_substreams = oxfw->playback_substreams;
		dir = AVC_GENERAL_PLUG_DIR_OUT;
	} else {
		substreams = oxfw->playback_substreams;
		opposite_substreams = oxfw->capture_substreams;

		if (oxfw->has_output)
			opposite = &oxfw->rx_stream;
		else
			opposite = NULL;
	if (oxfw->capture_substreams == 0 && oxfw->playback_substreams == 0)
		return -EIO;

		dir = AVC_GENERAL_PLUG_DIR_IN;
	// Considering JACK/FFADO streaming:
	// TODO: This can be removed hwdep functionality becomes popular.
	err = check_connection_used_by_others(oxfw, &oxfw->rx_stream);
	if (err < 0)
		return err;
	if (oxfw->has_output) {
		err = check_connection_used_by_others(oxfw, &oxfw->tx_stream);
		if (err < 0)
			return err;
	}

	if (substreams == 0)
		goto end;

	/*
	 * Considering JACK/FFADO streaming:
	 * TODO: This can be removed hwdep functionality becomes popular.
	 */
	err = check_connection_used_by_others(oxfw, stream);
	if (err < 0)
		goto end;
	if (stream == &oxfw->tx_stream)
		dir = AVC_GENERAL_PLUG_DIR_OUT;
	else
		dir = AVC_GENERAL_PLUG_DIR_IN;

	err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation);
	if (err < 0)
		goto end;
		return err;
	if (rate == 0)
		rate = formation.rate;
	if (pcm_channels == 0)
		pcm_channels = formation.pcm;

	if (formation.rate != rate || formation.pcm != pcm_channels ||
	    amdtp_streaming_error(stream)) {
		if (opposite != NULL) {
			err = check_connection_used_by_others(oxfw, opposite);
			if (err < 0)
				goto end;
			stop_stream(oxfw, opposite);
		}
		stop_stream(oxfw, stream);
	    amdtp_streaming_error(&oxfw->rx_stream) ||
	    amdtp_streaming_error(&oxfw->tx_stream)) {
		stop_stream(oxfw, &oxfw->rx_stream);
		if (oxfw->has_output)
			stop_stream(oxfw, &oxfw->tx_stream);

		err = set_stream_format(oxfw, stream, rate, pcm_channels);
		if (err < 0) {
			dev_err(&oxfw->unit->device,
				"fail to set stream format: %d\n", err);
			goto end;
			return err;
		}
	}

		/* Start opposite stream if needed. */
		if (opposite && !amdtp_stream_running(opposite) &&
		    (opposite_substreams > 0)) {
			err = start_stream(oxfw, opposite);
	if (!amdtp_stream_running(&oxfw->rx_stream)) {
		err = start_stream(oxfw, &oxfw->rx_stream);
		if (err < 0) {
			dev_err(&oxfw->unit->device,
					"fail to restart stream: %d\n", err);
				goto end;
			}
				"fail to start rx stream: %d\n", err);
			goto error;
		}
	}

	/* Start requested stream. */
	if (!amdtp_stream_running(stream)) {
		err = start_stream(oxfw, stream);
		if (err < 0)
	if (oxfw->has_output) {
		if (!amdtp_stream_running(&oxfw->tx_stream)) {
			err = start_stream(oxfw, &oxfw->tx_stream);
			if (err < 0) {
				dev_err(&oxfw->unit->device,
				"fail to start stream: %d\n", err);
					"fail to start tx stream: %d\n", err);
				goto error;
			}
		}
	}

	return 0;
error:
	stop_stream(oxfw, &oxfw->rx_stream);
	cmp_connection_break(&oxfw->in_conn);
	if (oxfw->has_output) {
		stop_stream(oxfw, &oxfw->tx_stream);
		cmp_connection_break(&oxfw->out_conn);
	}
end:
	return err;
}

void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw,
				  struct amdtp_stream *stream)
{
	if (((stream == &oxfw->tx_stream) && (oxfw->capture_substreams > 0)) ||
	    ((stream == &oxfw->rx_stream) && (oxfw->playback_substreams > 0)))
		return;
	if (oxfw->capture_substreams == 0 && oxfw->playback_substreams == 0) {
		stop_stream(oxfw, &oxfw->rx_stream);

	stop_stream(oxfw, stream);
		if (oxfw->has_output)
			stop_stream(oxfw, &oxfw->tx_stream);
	}
}

/*