aboutsummaryrefslogtreecommitdiffstats
path: root/sound/firewire/oxfw/oxfw-stream.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--sound/firewire/oxfw/oxfw-stream.c67
1 files changed, 41 insertions, 26 deletions
diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c
index 80c9dc13f1b5..f4a702def397 100644
--- a/sound/firewire/oxfw/oxfw-stream.c
+++ b/sound/firewire/oxfw/oxfw-stream.c
@@ -9,7 +9,7 @@
#include <linux/delay.h>
#define AVC_GENERIC_FRAME_MAXIMUM_BYTES 512
-#define CALLBACK_TIMEOUT 200
+#define READY_TIMEOUT_MS 600
/*
* According to datasheet of Oxford Semiconductor:
@@ -153,12 +153,30 @@ static int init_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
struct cmp_connection *conn;
enum cmp_direction c_dir;
enum amdtp_stream_direction s_dir;
+ unsigned int flags = 0;
int err;
+ if (!(oxfw->quirks & SND_OXFW_QUIRK_BLOCKING_TRANSMISSION))
+ flags |= CIP_NONBLOCKING;
+ else
+ flags |= CIP_BLOCKING;
+
+ // OXFW 970/971 has no function to generate playback timing according to the sequence
+ // of value in syt field, thus the packet should include NO_INFO value in the field.
+ // However, some models just ignore data blocks in packet with NO_INFO for audio data
+ // processing.
+ if (!(oxfw->quirks & SND_OXFW_QUIRK_IGNORE_NO_INFO_PACKET))
+ flags |= CIP_UNAWARE_SYT;
+
if (stream == &oxfw->tx_stream) {
conn = &oxfw->out_conn;
c_dir = CMP_OUTPUT;
s_dir = AMDTP_IN_STREAM;
+
+ if (oxfw->quirks & SND_OXFW_QUIRK_JUMBO_PAYLOAD)
+ flags |= CIP_JUMBO_PAYLOAD;
+ if (oxfw->quirks & SND_OXFW_QUIRK_WRONG_DBS)
+ flags |= CIP_WRONG_DBS;
} else {
conn = &oxfw->in_conn;
c_dir = CMP_INPUT;
@@ -169,24 +187,12 @@ static int init_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
if (err < 0)
return err;
- err = amdtp_am824_init(stream, oxfw->unit, s_dir, CIP_NONBLOCKING);
+ err = amdtp_am824_init(stream, oxfw->unit, s_dir, flags);
if (err < 0) {
cmp_connection_destroy(conn);
return err;
}
- /*
- * OXFW starts to transmit packets with non-zero dbc.
- * OXFW postpone transferring packets till handling any asynchronous
- * packets. As a result, next isochronous packet includes more data
- * blocks than IEC 61883-6 defines.
- */
- if (stream == &oxfw->tx_stream) {
- oxfw->tx_stream.flags |= CIP_JUMBO_PAYLOAD;
- if (oxfw->wrong_dbs)
- oxfw->tx_stream.flags |= CIP_WRONG_DBS;
- }
-
return 0;
}
@@ -338,6 +344,9 @@ int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw)
}
if (!amdtp_stream_running(&oxfw->rx_stream)) {
+ unsigned int tx_init_skip_cycles = 0;
+ bool replay_seq = false;
+
err = start_stream(oxfw, &oxfw->rx_stream);
if (err < 0) {
dev_err(&oxfw->unit->device,
@@ -353,26 +362,32 @@ int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw)
"fail to prepare tx stream: %d\n", err);
goto error;
}
+
+ if (oxfw->quirks & SND_OXFW_QUIRK_JUMBO_PAYLOAD) {
+ // Just after changing sampling transfer frequency, many cycles are
+ // skipped for packet transmission.
+ tx_init_skip_cycles = 400;
+ } else if (oxfw->quirks & SND_OXFW_QUIRK_VOLUNTARY_RECOVERY) {
+ // It takes a bit time for target device to adjust event frequency
+ // according to nominal event frequency in isochronous packets from
+ // ALSA oxfw driver.
+ tx_init_skip_cycles = 4000;
+ } else {
+ replay_seq = true;
+ }
}
- err = amdtp_domain_start(&oxfw->domain, 0);
+ // NOTE: The device ignores presentation time expressed by the value of syt field
+ // of CIP header in received packets. The sequence of the number of data blocks per
+ // packet is important for media clock recovery.
+ err = amdtp_domain_start(&oxfw->domain, tx_init_skip_cycles, replay_seq, false);
if (err < 0)
goto error;
- // Wait first packet.
- if (!amdtp_stream_wait_callback(&oxfw->rx_stream,
- CALLBACK_TIMEOUT)) {
+ if (!amdtp_domain_wait_ready(&oxfw->domain, READY_TIMEOUT_MS)) {
err = -ETIMEDOUT;
goto error;
}
-
- if (oxfw->has_output) {
- if (!amdtp_stream_wait_callback(&oxfw->tx_stream,
- CALLBACK_TIMEOUT)) {
- err = -ETIMEDOUT;
- goto error;
- }
- }
}
return 0;