@@ -60,7 +60,8 @@ struct snd_oxfw {
};
int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw);
-int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw);
+int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw, unsigned int rate,
+ unsigned int pcm_channels);
void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw);
void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw);
void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw);
@@ -170,36 +170,10 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
struct snd_oxfw *oxfw = substream->private_data;
- int err;
-
- snd_oxfw_stream_stop_simplex(oxfw);
-
- err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
- params_buffer_bytes(hw_params));
- if (err < 0)
- goto error;
-
- amdtp_stream_set_parameters(&oxfw->rx_stream,
- params_rate(hw_params),
- params_channels(hw_params),
- 0);
- amdtp_stream_set_pcm_format(&oxfw->rx_stream,
- params_format(hw_params));
-
- err = avc_general_set_sig_fmt(oxfw->unit, params_rate(hw_params),
- AVC_GENERAL_PLUG_DIR_IN, 0);
- if (err < 0) {
- dev_err(&oxfw->unit->device, "failed to set sample rate\n");
- goto err_buffer;
- }
-
- return 0;
-
-err_buffer:
- snd_pcm_lib_free_vmalloc_buffer(substream);
-error:
- return err;
+ amdtp_stream_set_pcm_format(&oxfw->rx_stream, params_format(hw_params));
+ return snd_pcm_lib_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(hw_params));
}
static int pcm_hw_free(struct snd_pcm_substream *substream)
@@ -214,11 +188,11 @@ static int pcm_hw_free(struct snd_pcm_substream *substream)
static int pcm_prepare(struct snd_pcm_substream *substream)
{
struct snd_oxfw *oxfw = substream->private_data;
+ struct snd_pcm_runtime *runtime = substream->runtime;
int err;
- snd_oxfw_stream_stop_simplex(oxfw);
-
- err = snd_oxfw_stream_start_simplex(oxfw);
+ err = snd_oxfw_stream_start_simplex(oxfw, runtime->rate,
+ runtime->channels);
if (err < 0)
goto end;
@@ -8,6 +8,8 @@
#include "oxfw.h"
+#define CALLBACK_TIMEOUT 200
+
/*
* According to their datasheet:
* OXFW970: 32.0/44.1/48.0/96.0 Khz, 8 audio channels I/O
@@ -48,29 +50,104 @@ static int stop_stream(struct snd_oxfw *oxfw)
cmp_connection_break(&oxfw->in_conn);
}
-int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw)
+static int start_stream(struct snd_oxfw *oxfw, unsigned int rate,
+ unsigned int pcm_channels)
{
- int err = 0;
+ struct snd_oxfw_stream_formation *formations;
+ unsigned int i, midi_ports;
+ struct amdtp_stream *stream;
+ struct cmp_connection *conn;
+ int err;
- mutex_lock(&oxfw->mutex);
+ stream = &oxfw->rx_stream;
+ formations = oxfw->rx_stream_formations;
+ conn = &oxfw->in_conn;
+
+ /* Get stream formation */
+ for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
+ if (formations[i].rate != rate)
+ continue;
+ if ((pcm_channels == 0) ||
+ (formations[i].pcm == pcm_channels))
+ break;
+ }
+ if (i == SND_OXFW_STREAM_FORMAT_ENTRIES) {
+ err = -EINVAL;
+ goto end;
+ }
- if (amdtp_streaming_error(&oxfw->rx_stream))
- stop_stream(oxfw);
+ pcm_channels = formations[i].pcm;
+ midi_ports = formations[i].midi;
- if (amdtp_stream_running(&oxfw->rx_stream))
+ /* The stream should have one pcm channels at least */
+ if (pcm_channels == 0) {
+ err = -EINVAL;
goto end;
+ }
+ amdtp_stream_set_parameters(stream, rate, pcm_channels, midi_ports);
- err = cmp_connection_establish(&oxfw->in_conn,
- amdtp_stream_get_max_payload(&oxfw->rx_stream));
+ /* Establish connection */
+ err = cmp_connection_establish(conn,
+ amdtp_stream_get_max_payload(stream));
if (err < 0)
goto end;
- err = amdtp_stream_start(&oxfw->rx_stream,
- oxfw->in_conn.resources.channel,
- oxfw->in_conn.speed);
+ /* Start stream */
+ err = amdtp_stream_start(stream,
+ conn->resources.channel,
+ conn->speed);
+ if (err < 0) {
+ cmp_connection_break(conn);
+ goto end;
+ }
+
+ /* Wait first callback */
+ err = amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT);
if (err < 0)
stop_stream(oxfw);
end:
+ return err;
+}
+
+int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw, unsigned int rate,
+ unsigned int pcm_channels)
+{
+ unsigned int curr_rate;
+ int err = 0;
+
+ mutex_lock(&oxfw->mutex);
+
+ /* packet queueing error */
+ if (amdtp_streaming_error(&oxfw->rx_stream))
+ stop_stream(oxfw);
+
+ /* arrange sampling rate */
+ err = avc_general_get_sig_fmt(oxfw->unit, &curr_rate,
+ AVC_GENERAL_PLUG_DIR_IN, 0);
+ if (err < 0) {
+ dev_err(&oxfw->unit->device,
+ "fail to get sampling rate: %d\n", err);
+ goto end;
+ }
+ if (curr_rate != rate) {
+ stop_stream(oxfw);
+
+ err = avc_general_set_sig_fmt(oxfw->unit, rate,
+ AVC_GENERAL_PLUG_DIR_IN, 0);
+ if (err < 0) {
+ dev_err(&oxfw->unit->device,
+ "fail to set sampling rate: %d\n", err);
+ goto end;
+ }
+ }
+
+ if (!amdtp_stream_running(&oxfw->rx_stream)) {
+ err = start_stream(oxfw, rate, pcm_channels);
+ if (err < 0)
+ dev_err(&oxfw->unit->device,
+ "fail to start stream: %d\n", err);
+ }
+end:
mutex_unlock(&oxfw->mutex);
return err;
}
In past commit, this driver can keep stream formations for each sampling rate. So its stream functionality can decide stream formations when given some parameters. This commit moves related codes from PCM functionality to stream functionality. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> --- sound/firewire/oxfw/oxfw.h | 3 +- sound/firewire/oxfw/oxfw_pcm.c | 38 +++------------ sound/firewire/oxfw/oxfw_stream.c | 99 ++++++++++++++++++++++++++++++++++----- 3 files changed, 96 insertions(+), 44 deletions(-)