[alsa-devel] [PATCH 00/19] ALSA: firewire: introduce AMDTP domain

Hi,
This patchset is to implement AMDTP domain I addressed in my previous patchset: https://mailman.alsa-project.org/pipermail/alsa-devel/2019-July/152430.html
My work for libhinoko[1][2] allows me to sniff actual packet transmission between devices and drivers in Windows/Mac OS for long period (e.g. 1 hour). As a result, some supported devices don't follow packet sequences transferred by the drivers. They expect drivers to parse isoc packets in tx stream and recover frequency of data block then transfer isoc packets as rx stream.
(I note that no specification describes this mechanism as long as I know. In the specification, clock recovery is one-way from transmitter to receivers, thus recovered clock is not necessarily used for transmission from the receiver to the transmitter.)
For the clock recovery in driver side, several isoc contexts should be handled in one time to parse packets in incoming stream and to build packets in outgoing stream. The AMDTP domain is designed for this purpose.
In this time, the AMDTP domain implements the functionalities to start/stop a couple of isoc contexts for some AMDTP streams. Each context still runs in own handler for scheduled hardware IRQs. I'll post further work after merged.
[1] https://mailman.alsa-project.org/pipermail/alsa-devel/2019-April/147862.html [2] https://github.com/takaswie/libhinoko
Takashi Sakamoto (19): ALSA: firewire-lib: add AMDTP domain structure to handle several isoc context in one interrupt callback ALSA: firewire-lib: add a kernel API to stop a couple of AMDTP streams in AMDTP domain ALSA: firewire-lib: add a kernel API to add AMDTP stream into AMDTP domain ALSA: firewire-lib: add a kernel API to start AMDTP streams in AMDTP domain ALSA: fireworks: code refactoring for initialization/destruction of AMDTP streams ALSA: fireworks: code refactoring for bus reset handler ALSA: firewire-digi00x: code refactoring for initialization/destruction of AMDTP stream ALSA: firewire-tascam: code refactoring for initialization/destruction of AMDTP stream ALSA: firewire-motu: code refactoring for initialization/destruction of AMDTP stream ALSA: fireface: code refactoring for initialization/destruction of AMDTP stream ALSA: bebob: support AMDTP domain ALSA: fireworks: support AMDTP domain ALSA: oxfw: support AMDTP domain ALSA: dice: support AMDTP domain ALSA: firewire-digi00x: support AMDTP domain ALSA: firewire-tascam: support AMDTP domain ALSA: firewire-motu: support AMDTP domain ALSA: fireface: support AMDTP domain ALSA: firewire-lib: localize kernel APIs to start/stop each AMDTP stream
sound/firewire/amdtp-stream.c | 94 ++++++++++- sound/firewire/amdtp-stream.h | 20 ++- sound/firewire/bebob/bebob.h | 2 + sound/firewire/bebob/bebob_stream.c | 62 +++---- sound/firewire/dice/dice-stream.c | 32 +++- sound/firewire/dice/dice.h | 2 + sound/firewire/digi00x/digi00x-stream.c | 106 +++++++----- sound/firewire/digi00x/digi00x.h | 2 + sound/firewire/fireface/ff-stream.c | 96 ++++++----- sound/firewire/fireface/ff.h | 2 + sound/firewire/fireworks/fireworks.h | 2 + sound/firewire/fireworks/fireworks_stream.c | 176 ++++++++++---------- sound/firewire/motu/motu-stream.c | 131 +++++++-------- sound/firewire/motu/motu.h | 2 + sound/firewire/oxfw/oxfw-stream.c | 72 ++++---- sound/firewire/oxfw/oxfw.h | 2 + sound/firewire/tascam/tascam-stream.c | 123 ++++++++------ sound/firewire/tascam/tascam.h | 2 + 18 files changed, 558 insertions(+), 370 deletions(-)

This commit adds 'struct amdtp_domain' structure. This structure has list of instance of AMDTP stream to handle a couple of isochronous contexts.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/amdtp-stream.c | 22 ++++++++++++++++++++++ sound/firewire/amdtp-stream.h | 7 +++++++ 2 files changed, 29 insertions(+)
diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 369e75e33120..02077696fa77 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -1136,3 +1136,25 @@ void amdtp_stream_pcm_abort(struct amdtp_stream *s) snd_pcm_stop_xrun(pcm); } EXPORT_SYMBOL(amdtp_stream_pcm_abort); + +/** + * amdtp_domain_init - initialize an AMDTP domain structure + * @d: the AMDTP domain to initialize. + */ +int amdtp_domain_init(struct amdtp_domain *d) +{ + INIT_LIST_HEAD(&d->streams); + + return 0; +} +EXPORT_SYMBOL_GPL(amdtp_domain_init); + +/** + * amdtp_domain_destroy - destroy an AMDTP domain structure + * @d: the AMDTP domain to destroy. + */ +void amdtp_domain_destroy(struct amdtp_domain *d) +{ + WARN_ON(!list_empty(&d->streams)); +} +EXPORT_SYMBOL_GPL(amdtp_domain_destroy); diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index 50041fa884d9..2378db4b4195 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -267,4 +267,11 @@ static inline bool amdtp_stream_wait_callback(struct amdtp_stream *s, msecs_to_jiffies(timeout)) > 0; }
+struct amdtp_domain { + struct list_head streams; +}; + +int amdtp_domain_init(struct amdtp_domain *d); +void amdtp_domain_destroy(struct amdtp_domain *d); + #endif

This commit adds a kernel API to stop a couple of isochronous contexts for AMDTP streams. The API is not protected with any lock primitive. Callers should use this with enough lock against concurrent access.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/amdtp-stream.c | 16 ++++++++++++++++ sound/firewire/amdtp-stream.h | 5 +++++ 2 files changed, 21 insertions(+)
diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 02077696fa77..31fc90f76443 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -1158,3 +1158,19 @@ void amdtp_domain_destroy(struct amdtp_domain *d) WARN_ON(!list_empty(&d->streams)); } EXPORT_SYMBOL_GPL(amdtp_domain_destroy); + +/** + * amdtp_domain_stop - stop sending packets for isoc context in the same domain. + * @d: the AMDTP domain to which the isoc contexts belong. + */ +void amdtp_domain_stop(struct amdtp_domain *d) +{ + struct amdtp_stream *s, *next; + + list_for_each_entry_safe(s, next, &d->streams, list) { + list_del(&s->list); + + amdtp_stream_stop(s); + } +} +EXPORT_SYMBOL_GPL(amdtp_domain_stop); diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index 2378db4b4195..ab2a69180240 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -170,6 +170,9 @@ struct amdtp_stream { /* For backends to process data blocks. */ void *protocol; amdtp_stream_process_ctx_payloads_t process_ctx_payloads; + + // For domain. + struct list_head list; };
int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit, @@ -274,4 +277,6 @@ struct amdtp_domain { int amdtp_domain_init(struct amdtp_domain *d); void amdtp_domain_destroy(struct amdtp_domain *d);
+void amdtp_domain_stop(struct amdtp_domain *d); + #endif

This commit adds a kernel API to insert AMDTP stream to list in AMDTP domain.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/amdtp-stream.c | 26 ++++++++++++++++++++++++++ sound/firewire/amdtp-stream.h | 5 +++++ 2 files changed, 31 insertions(+)
diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 31fc90f76443..fa7989ee4769 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -1159,6 +1159,32 @@ void amdtp_domain_destroy(struct amdtp_domain *d) } EXPORT_SYMBOL_GPL(amdtp_domain_destroy);
+/** + * amdtp_domain_add_stream - register isoc context into the domain. + * @d: the AMDTP domain. + * @s: the AMDTP stream. + * @channel: the isochronous channel on the bus. + * @speed: firewire speed code. + */ +int amdtp_domain_add_stream(struct amdtp_domain *d, struct amdtp_stream *s, + int channel, int speed) +{ + struct amdtp_stream *tmp; + + list_for_each_entry(tmp, &d->streams, list) { + if (s == tmp) + return -EBUSY; + } + + list_add(&s->list, &d->streams); + + s->channel = channel; + s->speed = speed; + + return 0; +} +EXPORT_SYMBOL_GPL(amdtp_domain_add_stream); + /** * amdtp_domain_stop - stop sending packets for isoc context in the same domain. * @d: the AMDTP domain to which the isoc contexts belong. diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index ab2a69180240..4b102fd7529d 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -172,6 +172,8 @@ struct amdtp_stream { amdtp_stream_process_ctx_payloads_t process_ctx_payloads;
// For domain. + int channel; + int speed; struct list_head list; };
@@ -277,6 +279,9 @@ struct amdtp_domain { int amdtp_domain_init(struct amdtp_domain *d); void amdtp_domain_destroy(struct amdtp_domain *d);
+int amdtp_domain_add_stream(struct amdtp_domain *d, struct amdtp_stream *s, + int channel, int speed); + void amdtp_domain_stop(struct amdtp_domain *d);
#endif

This commit adds a kernel API to start a couple of isochronous contexts for some AMDTP streams.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/amdtp-stream.c | 24 ++++++++++++++++++++++++ sound/firewire/amdtp-stream.h | 1 + 2 files changed, 25 insertions(+)
diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index fa7989ee4769..158d210caea7 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -1185,6 +1185,30 @@ int amdtp_domain_add_stream(struct amdtp_domain *d, struct amdtp_stream *s, } EXPORT_SYMBOL_GPL(amdtp_domain_add_stream);
+/** + * amdtp_domain_start - start sending packets for isoc context in the domain. + * @d: the AMDTP domain. + */ +int amdtp_domain_start(struct amdtp_domain *d) +{ + struct amdtp_stream *s; + int err = 0; + + list_for_each_entry(s, &d->streams, list) { + err = amdtp_stream_start(s, s->channel, s->speed); + if (err < 0) + break; + } + + if (err < 0) { + list_for_each_entry(s, &d->streams, list) + amdtp_stream_stop(s); + } + + return err; +} +EXPORT_SYMBOL_GPL(amdtp_domain_start); + /** * amdtp_domain_stop - stop sending packets for isoc context in the same domain. * @d: the AMDTP domain to which the isoc contexts belong. diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index 4b102fd7529d..15d471660a43 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -282,6 +282,7 @@ void amdtp_domain_destroy(struct amdtp_domain *d); int amdtp_domain_add_stream(struct amdtp_domain *d, struct amdtp_stream *s, int channel, int speed);
+int amdtp_domain_start(struct amdtp_domain *d); void amdtp_domain_stop(struct amdtp_domain *d);
#endif

This commit is a preparation to support AMDTP domain.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/fireworks/fireworks_stream.c | 77 ++++++++++----------- 1 file changed, 36 insertions(+), 41 deletions(-)
diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index 385fc9686365..0f62c50055e9 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -8,8 +8,7 @@
#define CALLBACK_TIMEOUT 100
-static int -init_stream(struct snd_efw *efw, struct amdtp_stream *stream) +static int init_stream(struct snd_efw *efw, struct amdtp_stream *stream) { struct cmp_connection *conn; enum cmp_direction c_dir; @@ -28,14 +27,37 @@ init_stream(struct snd_efw *efw, struct amdtp_stream *stream)
err = cmp_connection_init(conn, efw->unit, c_dir, 0); if (err < 0) - goto end; + return err;
err = amdtp_am824_init(stream, efw->unit, s_dir, CIP_BLOCKING); if (err < 0) { amdtp_stream_destroy(stream); cmp_connection_destroy(conn); + return err; } -end: + + if (stream == &efw->tx_stream) { + // Fireworks transmits NODATA packets with TAG0. + efw->tx_stream.flags |= CIP_EMPTY_WITH_TAG0; + // Fireworks has its own meaning for dbc. + efw->tx_stream.flags |= CIP_DBC_IS_END_EVENT; + // Fireworks reset dbc at bus reset. + efw->tx_stream.flags |= CIP_SKIP_DBC_ZERO_CHECK; + // But Recent firmwares starts packets with non-zero dbc. + // Driver version 5.7.6 installs firmware version 5.7.3. + if (efw->is_fireworks3 && + (efw->firmware_version == 0x5070000 || + efw->firmware_version == 0x5070300 || + efw->firmware_version == 0x5080000)) + efw->tx_stream.flags |= CIP_UNALIGHED_DBC; + // AudioFire9 always reports wrong dbs. + if (efw->is_af9) + efw->tx_stream.flags |= CIP_WRONG_DBS; + // Firmware version 5.5 reports fixed interval for dbc. + if (efw->firmware_version == 0x5050000) + efw->tx_stream.ctx_data.tx.dbc_interval = 8; + } + return err; }
@@ -83,22 +105,16 @@ static int start_stream(struct snd_efw *efw, struct amdtp_stream *stream, return 0; }
-/* - * This function should be called before starting the stream or after stopping - * the streams. - */ -static void -destroy_stream(struct snd_efw *efw, struct amdtp_stream *stream) +// This function should be called before starting the stream or after stopping +// the streams. +static void destroy_stream(struct snd_efw *efw, struct amdtp_stream *stream) { - struct cmp_connection *conn; + amdtp_stream_destroy(stream);
if (stream == &efw->tx_stream) - conn = &efw->out_conn; + cmp_connection_destroy(&efw->out_conn); else - conn = &efw->in_conn; - - amdtp_stream_destroy(stream); - cmp_connection_destroy(conn); + cmp_connection_destroy(&efw->in_conn); }
static int @@ -131,42 +147,21 @@ int snd_efw_stream_init_duplex(struct snd_efw *efw)
err = init_stream(efw, &efw->tx_stream); if (err < 0) - goto end; - /* Fireworks transmits NODATA packets with TAG0. */ - efw->tx_stream.flags |= CIP_EMPTY_WITH_TAG0; - /* Fireworks has its own meaning for dbc. */ - efw->tx_stream.flags |= CIP_DBC_IS_END_EVENT; - /* Fireworks reset dbc at bus reset. */ - efw->tx_stream.flags |= CIP_SKIP_DBC_ZERO_CHECK; - /* - * But Recent firmwares starts packets with non-zero dbc. - * Driver version 5.7.6 installs firmware version 5.7.3. - */ - if (efw->is_fireworks3 && - (efw->firmware_version == 0x5070000 || - efw->firmware_version == 0x5070300 || - efw->firmware_version == 0x5080000)) - efw->tx_stream.flags |= CIP_UNALIGHED_DBC; - /* AudioFire9 always reports wrong dbs. */ - if (efw->is_af9) - efw->tx_stream.flags |= CIP_WRONG_DBS; - /* Firmware version 5.5 reports fixed interval for dbc. */ - if (efw->firmware_version == 0x5050000) - efw->tx_stream.ctx_data.tx.dbc_interval = 8; + return err;
err = init_stream(efw, &efw->rx_stream); if (err < 0) { destroy_stream(efw, &efw->tx_stream); - goto end; + return err; }
- /* set IEC61883 compliant mode (actually not fully compliant...) */ + // set IEC61883 compliant mode (actually not fully compliant...). err = snd_efw_command_set_tx_mode(efw, SND_EFW_TRANSPORT_MODE_IEC61883); if (err < 0) { destroy_stream(efw, &efw->tx_stream); destroy_stream(efw, &efw->rx_stream); } -end: + return err; }

This commit is a preparation to support AMDTP domain.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/fireworks/fireworks_stream.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-)
diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index 0f62c50055e9..af340491dc43 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -299,14 +299,11 @@ void snd_efw_stream_stop_duplex(struct snd_efw *efw)
void snd_efw_stream_update_duplex(struct snd_efw *efw) { - if (cmp_connection_update(&efw->out_conn) < 0 || - cmp_connection_update(&efw->in_conn) < 0) { - stop_stream(efw, &efw->rx_stream); - stop_stream(efw, &efw->tx_stream); - } else { - amdtp_stream_update(&efw->rx_stream); - amdtp_stream_update(&efw->tx_stream); - } + stop_stream(efw, &efw->rx_stream); + stop_stream(efw, &efw->tx_stream); + + amdtp_stream_pcm_abort(&efw->rx_stream); + amdtp_stream_pcm_abort(&efw->tx_stream); }
void snd_efw_stream_destroy_duplex(struct snd_efw *efw)

This commit is a preparation to support AMDTP domain.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/digi00x/digi00x-stream.c | 65 ++++++++++++++++--------- 1 file changed, 42 insertions(+), 23 deletions(-)
diff --git a/sound/firewire/digi00x/digi00x-stream.c b/sound/firewire/digi00x/digi00x-stream.c index 3e77dbd3ee22..cff193f00a97 100644 --- a/sound/firewire/digi00x/digi00x-stream.c +++ b/sound/firewire/digi00x/digi00x-stream.c @@ -218,43 +218,62 @@ static int keep_resources(struct snd_dg00x *dg00x, struct amdtp_stream *stream, fw_parent_device(dg00x->unit)->max_speed); }
-int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x) +static int init_stream(struct snd_dg00x *dg00x, struct amdtp_stream *s) { + struct fw_iso_resources *resources; + enum amdtp_stream_direction dir; int err;
- /* For out-stream. */ - err = fw_iso_resources_init(&dg00x->rx_resources, dg00x->unit); + if (s == &dg00x->tx_stream) { + resources = &dg00x->tx_resources; + dir = AMDTP_IN_STREAM; + } else { + resources = &dg00x->rx_resources; + dir = AMDTP_OUT_STREAM; + } + + err = fw_iso_resources_init(resources, dg00x->unit); if (err < 0) - goto error; - err = amdtp_dot_init(&dg00x->rx_stream, dg00x->unit, AMDTP_OUT_STREAM); + return err; + + err = amdtp_dot_init(s, dg00x->unit, dir); if (err < 0) - goto error; + fw_iso_resources_destroy(resources); + + return err; +}
- /* For in-stream. */ - err = fw_iso_resources_init(&dg00x->tx_resources, dg00x->unit); +static void destroy_stream(struct snd_dg00x *dg00x, struct amdtp_stream *s) +{ + amdtp_stream_destroy(s); + + if (s == &dg00x->tx_stream) + fw_iso_resources_destroy(&dg00x->tx_resources); + else + fw_iso_resources_destroy(&dg00x->rx_resources); +} + +int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x) +{ + int err; + + err = init_stream(dg00x, &dg00x->rx_stream); if (err < 0) - goto error; - err = amdtp_dot_init(&dg00x->tx_stream, dg00x->unit, AMDTP_IN_STREAM); + return err; + + err = init_stream(dg00x, &dg00x->tx_stream); if (err < 0) - goto error; + destroy_stream(dg00x, &dg00x->rx_stream);
- return 0; -error: - snd_dg00x_stream_destroy_duplex(dg00x); return err; }
-/* - * This function should be called before starting streams or after stopping - * streams. - */ +// This function should be called before starting streams or after stopping +// streams. void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x) { - amdtp_stream_destroy(&dg00x->rx_stream); - fw_iso_resources_destroy(&dg00x->rx_resources); - - amdtp_stream_destroy(&dg00x->tx_stream); - fw_iso_resources_destroy(&dg00x->tx_resources); + destroy_stream(dg00x, &dg00x->rx_stream); + destroy_stream(dg00x, &dg00x->tx_stream); }
int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate)

This commit is a preparation to support AMDTP domain.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/tascam/tascam-stream.c | 71 +++++++++++++++++---------- 1 file changed, 44 insertions(+), 27 deletions(-)
diff --git a/sound/firewire/tascam/tascam-stream.c b/sound/firewire/tascam/tascam-stream.c index e852e46ebe6f..d5e77036e0ee 100644 --- a/sound/firewire/tascam/tascam-stream.c +++ b/sound/firewire/tascam/tascam-stream.c @@ -287,38 +287,60 @@ static int keep_resources(struct snd_tscm *tscm, unsigned int rate, fw_parent_device(tscm->unit)->max_speed); }
-int snd_tscm_stream_init_duplex(struct snd_tscm *tscm) +static int init_stream(struct snd_tscm *tscm, struct amdtp_stream *s) { + struct fw_iso_resources *resources; + enum amdtp_stream_direction dir; unsigned int pcm_channels; int err;
- /* For out-stream. */ - err = fw_iso_resources_init(&tscm->rx_resources, tscm->unit); - if (err < 0) - return err; - pcm_channels = tscm->spec->pcm_playback_analog_channels; + if (s == &tscm->tx_stream) { + resources = &tscm->tx_resources; + dir = AMDTP_IN_STREAM; + pcm_channels = tscm->spec->pcm_capture_analog_channels; + } else { + resources = &tscm->rx_resources; + dir = AMDTP_OUT_STREAM; + pcm_channels = tscm->spec->pcm_playback_analog_channels; + } + if (tscm->spec->has_adat) pcm_channels += 8; if (tscm->spec->has_spdif) pcm_channels += 2; - err = amdtp_tscm_init(&tscm->rx_stream, tscm->unit, AMDTP_OUT_STREAM, - pcm_channels); + + err = fw_iso_resources_init(resources, tscm->unit); if (err < 0) return err;
- /* For in-stream. */ - err = fw_iso_resources_init(&tscm->tx_resources, tscm->unit); + err = amdtp_tscm_init(s, tscm->unit, dir, pcm_channels); + if (err < 0) + fw_iso_resources_free(resources); + + return err; +} + +static void destroy_stream(struct snd_tscm *tscm, struct amdtp_stream *s) +{ + amdtp_stream_destroy(s); + + if (s == &tscm->tx_stream) + fw_iso_resources_destroy(&tscm->tx_resources); + else + fw_iso_resources_destroy(&tscm->rx_resources); +} + +int snd_tscm_stream_init_duplex(struct snd_tscm *tscm) +{ + int err; + + err = init_stream(tscm, &tscm->tx_stream); if (err < 0) return err; - pcm_channels = tscm->spec->pcm_capture_analog_channels; - if (tscm->spec->has_adat) - pcm_channels += 8; - if (tscm->spec->has_spdif) - pcm_channels += 2; - err = amdtp_tscm_init(&tscm->tx_stream, tscm->unit, AMDTP_IN_STREAM, - pcm_channels); + + err = init_stream(tscm, &tscm->rx_stream); if (err < 0) - amdtp_stream_destroy(&tscm->rx_stream); + destroy_stream(tscm, &tscm->tx_stream);
return err; } @@ -333,17 +355,12 @@ void snd_tscm_stream_update_duplex(struct snd_tscm *tscm) amdtp_stream_stop(&tscm->rx_stream); }
-/* - * This function should be called before starting streams or after stopping - * streams. - */ +// This function should be called before starting streams or after stopping +// streams. void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm) { - amdtp_stream_destroy(&tscm->rx_stream); - amdtp_stream_destroy(&tscm->tx_stream); - - fw_iso_resources_destroy(&tscm->rx_resources); - fw_iso_resources_destroy(&tscm->tx_resources); + destroy_stream(tscm, &tscm->rx_stream); + destroy_stream(tscm, &tscm->tx_stream); }
int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate)

This commit is a preparation to support AMDTP domain.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/motu/motu-stream.c | 48 ++++++++++++------------------- 1 file changed, 19 insertions(+), 29 deletions(-)
diff --git a/sound/firewire/motu/motu-stream.c b/sound/firewire/motu/motu-stream.c index 2bbb335e8de1..cc9f34426a47 100644 --- a/sound/firewire/motu/motu-stream.c +++ b/sound/firewire/motu/motu-stream.c @@ -300,62 +300,52 @@ void snd_motu_stream_stop_duplex(struct snd_motu *motu) } }
-static int init_stream(struct snd_motu *motu, enum amdtp_stream_direction dir) +static int init_stream(struct snd_motu *motu, struct amdtp_stream *s) { - int err; - struct amdtp_stream *stream; struct fw_iso_resources *resources; + enum amdtp_stream_direction dir; + int err;
- if (dir == AMDTP_IN_STREAM) { - stream = &motu->tx_stream; + if (s == &motu->tx_stream) { resources = &motu->tx_resources; + dir = AMDTP_IN_STREAM; } else { - stream = &motu->rx_stream; resources = &motu->rx_resources; + dir = AMDTP_OUT_STREAM; }
err = fw_iso_resources_init(resources, motu->unit); if (err < 0) return err;
- err = amdtp_motu_init(stream, motu->unit, dir, motu->spec->protocol); - if (err < 0) { - amdtp_stream_destroy(stream); + err = amdtp_motu_init(s, motu->unit, dir, motu->spec->protocol); + if (err < 0) fw_iso_resources_destroy(resources); - }
return err; }
-static void destroy_stream(struct snd_motu *motu, - enum amdtp_stream_direction dir) +static void destroy_stream(struct snd_motu *motu, struct amdtp_stream *s) { - struct amdtp_stream *stream; - struct fw_iso_resources *resources; + amdtp_stream_destroy(s);
- if (dir == AMDTP_IN_STREAM) { - stream = &motu->tx_stream; - resources = &motu->tx_resources; - } else { - stream = &motu->rx_stream; - resources = &motu->rx_resources; - } - - amdtp_stream_destroy(stream); - fw_iso_resources_destroy(resources); + if (s == &motu->tx_stream) + fw_iso_resources_destroy(&motu->tx_resources); + else + fw_iso_resources_destroy(&motu->rx_resources); }
int snd_motu_stream_init_duplex(struct snd_motu *motu) { int err;
- err = init_stream(motu, AMDTP_IN_STREAM); + err = init_stream(motu, &motu->tx_stream); if (err < 0) return err;
- err = init_stream(motu, AMDTP_OUT_STREAM); + err = init_stream(motu, &motu->rx_stream); if (err < 0) - destroy_stream(motu, AMDTP_IN_STREAM); + destroy_stream(motu, &motu->tx_stream);
return err; } @@ -366,8 +356,8 @@ int snd_motu_stream_init_duplex(struct snd_motu *motu) */ void snd_motu_stream_destroy_duplex(struct snd_motu *motu) { - destroy_stream(motu, AMDTP_IN_STREAM); - destroy_stream(motu, AMDTP_OUT_STREAM); + destroy_stream(motu, &motu->rx_stream); + destroy_stream(motu, &motu->tx_stream);
motu->substreams_counter = 0; }

This commit is a preparation to support AMDTP domain.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/fireface/ff-stream.c | 39 ++++++++++++++--------------- 1 file changed, 19 insertions(+), 20 deletions(-)
diff --git a/sound/firewire/fireface/ff-stream.c b/sound/firewire/fireface/ff-stream.c index 4208b8004d1a..e4710204f481 100644 --- a/sound/firewire/fireface/ff-stream.c +++ b/sound/firewire/fireface/ff-stream.c @@ -39,54 +39,53 @@ static inline void finish_session(struct snd_ff *ff) ff->spec->protocol->switch_fetching_mode(ff, false); }
-static int init_stream(struct snd_ff *ff, enum amdtp_stream_direction dir) +static int init_stream(struct snd_ff *ff, struct amdtp_stream *s) { - int err; struct fw_iso_resources *resources; - struct amdtp_stream *stream; + enum amdtp_stream_direction dir; + int err;
- if (dir == AMDTP_IN_STREAM) { + if (s == &ff->tx_stream) { resources = &ff->tx_resources; - stream = &ff->tx_stream; + dir = AMDTP_IN_STREAM; } else { resources = &ff->rx_resources; - stream = &ff->rx_stream; + dir = AMDTP_OUT_STREAM; }
err = fw_iso_resources_init(resources, ff->unit); if (err < 0) return err;
- err = amdtp_ff_init(stream, ff->unit, dir); + err = amdtp_ff_init(s, ff->unit, dir); if (err < 0) fw_iso_resources_destroy(resources);
return err; }
-static void destroy_stream(struct snd_ff *ff, enum amdtp_stream_direction dir) +static void destroy_stream(struct snd_ff *ff, struct amdtp_stream *s) { - if (dir == AMDTP_IN_STREAM) { - amdtp_stream_destroy(&ff->tx_stream); + amdtp_stream_destroy(s); + + if (s == &ff->tx_stream) fw_iso_resources_destroy(&ff->tx_resources); - } else { - amdtp_stream_destroy(&ff->rx_stream); + else fw_iso_resources_destroy(&ff->rx_resources); - } }
int snd_ff_stream_init_duplex(struct snd_ff *ff) { int err;
- err = init_stream(ff, AMDTP_OUT_STREAM); + err = init_stream(ff, &ff->rx_stream); if (err < 0) - goto end; + return err;
- err = init_stream(ff, AMDTP_IN_STREAM); + err = init_stream(ff, &ff->tx_stream); if (err < 0) - destroy_stream(ff, AMDTP_OUT_STREAM); -end: + destroy_stream(ff, &ff->rx_stream); + return err; }
@@ -96,8 +95,8 @@ int snd_ff_stream_init_duplex(struct snd_ff *ff) */ void snd_ff_stream_destroy_duplex(struct snd_ff *ff) { - destroy_stream(ff, AMDTP_IN_STREAM); - destroy_stream(ff, AMDTP_OUT_STREAM); + destroy_stream(ff, &ff->rx_stream); + destroy_stream(ff, &ff->tx_stream); }
int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate)

This commit adds AMDTP domain support for ALSA bebob driver.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/bebob/bebob.h | 2 + sound/firewire/bebob/bebob_stream.c | 62 +++++++++++++---------------- 2 files changed, 29 insertions(+), 35 deletions(-)
diff --git a/sound/firewire/bebob/bebob.h b/sound/firewire/bebob/bebob.h index 9e0b689fe34a..356d6ba60959 100644 --- a/sound/firewire/bebob/bebob.h +++ b/sound/firewire/bebob/bebob.h @@ -115,6 +115,8 @@ struct snd_bebob {
/* For BeBoB version quirk. */ unsigned int version; + + struct amdtp_domain domain; };
static inline int diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index 334dc7c96e1d..73fee991bd75 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -445,10 +445,9 @@ start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream) goto end; }
- /* start amdtp stream */ - err = amdtp_stream_start(stream, - conn->resources.channel, - conn->speed); + // start amdtp stream. + err = amdtp_domain_add_stream(&bebob->domain, stream, + conn->resources.channel, conn->speed); end: return err; } @@ -523,7 +522,13 @@ int snd_bebob_stream_init_duplex(struct snd_bebob *bebob) return err; }
- return 0; + err = amdtp_domain_init(&bebob->domain); + if (err < 0) { + destroy_stream(bebob, &bebob->tx_stream); + destroy_stream(bebob, &bebob->rx_stream); + } + + return err; }
static int keep_resources(struct snd_bebob *bebob, struct amdtp_stream *stream, @@ -566,9 +571,7 @@ int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate) if (rate == 0) rate = curr_rate; if (curr_rate != rate) { - amdtp_stream_stop(&bebob->tx_stream); - amdtp_stream_stop(&bebob->rx_stream); - + amdtp_domain_stop(&bebob->domain); break_both_connections(bebob);
cmp_connection_release(&bebob->out_conn); @@ -620,9 +623,7 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob) // packet queueing error or detecting discontinuity if (amdtp_streaming_error(&bebob->rx_stream) || amdtp_streaming_error(&bebob->tx_stream)) { - amdtp_stream_stop(&bebob->rx_stream); - amdtp_stream_stop(&bebob->tx_stream); - + amdtp_domain_stop(&bebob->domain); break_both_connections(bebob); }
@@ -640,11 +641,16 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob) return err;
err = start_stream(bebob, &bebob->rx_stream); - if (err < 0) { - dev_err(&bebob->unit->device, - "fail to run AMDTP master stream:%d\n", err); + if (err < 0) + goto error; + + err = start_stream(bebob, &bebob->tx_stream); + if (err < 0) + goto error; + + err = amdtp_domain_start(&bebob->domain); + if (err < 0) goto error; - }
// NOTE: // The firmware customized by M-Audio uses these commands to @@ -660,21 +666,8 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob) }
if (!amdtp_stream_wait_callback(&bebob->rx_stream, - CALLBACK_TIMEOUT)) { - err = -ETIMEDOUT; - goto error; - } - } - - if (!amdtp_stream_running(&bebob->tx_stream)) { - err = start_stream(bebob, &bebob->tx_stream); - if (err < 0) { - dev_err(&bebob->unit->device, - "fail to run AMDTP slave stream:%d\n", err); - goto error; - } - - if (!amdtp_stream_wait_callback(&bebob->tx_stream, + CALLBACK_TIMEOUT) || + !amdtp_stream_wait_callback(&bebob->tx_stream, CALLBACK_TIMEOUT)) { err = -ETIMEDOUT; goto error; @@ -683,8 +676,7 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob)
return 0; error: - amdtp_stream_stop(&bebob->tx_stream); - amdtp_stream_stop(&bebob->rx_stream); + amdtp_domain_stop(&bebob->domain); break_both_connections(bebob); return err; } @@ -692,9 +684,7 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob) void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob) { if (bebob->substreams_counter == 0) { - amdtp_stream_stop(&bebob->rx_stream); - amdtp_stream_stop(&bebob->tx_stream); - + amdtp_domain_stop(&bebob->domain); break_both_connections(bebob);
cmp_connection_release(&bebob->out_conn); @@ -708,6 +698,8 @@ void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob) */ void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob) { + amdtp_domain_destroy(&bebob->domain); + destroy_stream(bebob, &bebob->tx_stream); destroy_stream(bebob, &bebob->rx_stream); }

This commit adds AMDTP domain support for ALSA fireworks driver.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/fireworks/fireworks.h | 2 + sound/firewire/fireworks/fireworks_stream.c | 92 +++++++++++---------- 2 files changed, 51 insertions(+), 43 deletions(-)
diff --git a/sound/firewire/fireworks/fireworks.h b/sound/firewire/fireworks/fireworks.h index 31efd4b53b4f..4cda297f8438 100644 --- a/sound/firewire/fireworks/fireworks.h +++ b/sound/firewire/fireworks/fireworks.h @@ -107,6 +107,8 @@ struct snd_efw { u8 *resp_buf; u8 *pull_ptr; u8 *push_ptr; + + struct amdtp_domain domain; };
int snd_efw_transaction_cmd(struct fw_unit *unit, diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index af340491dc43..f2de304d2f26 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -61,17 +61,6 @@ static int init_stream(struct snd_efw *efw, struct amdtp_stream *stream) return err; }
-static void -stop_stream(struct snd_efw *efw, struct amdtp_stream *stream) -{ - amdtp_stream_stop(stream); - - if (stream == &efw->tx_stream) - cmp_connection_break(&efw->out_conn); - else - cmp_connection_break(&efw->in_conn); -} - static int start_stream(struct snd_efw *efw, struct amdtp_stream *stream, unsigned int rate) { @@ -89,19 +78,13 @@ static int start_stream(struct snd_efw *efw, struct amdtp_stream *stream, return err;
// Start amdtp stream. - err = amdtp_stream_start(stream, conn->resources.channel, conn->speed); + err = amdtp_domain_add_stream(&efw->domain, stream, + conn->resources.channel, conn->speed); if (err < 0) { cmp_connection_break(conn); return err; }
- // Wait first callback. - if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) { - amdtp_stream_stop(stream); - cmp_connection_break(conn); - return -ETIMEDOUT; - } - return 0; }
@@ -155,6 +138,13 @@ int snd_efw_stream_init_duplex(struct snd_efw *efw) return err; }
+ err = amdtp_domain_init(&efw->domain); + if (err < 0) { + destroy_stream(efw, &efw->tx_stream); + destroy_stream(efw, &efw->rx_stream); + return err; + } + // set IEC61883 compliant mode (actually not fully compliant...). err = snd_efw_command_set_tx_mode(efw, SND_EFW_TRANSPORT_MODE_IEC61883); if (err < 0) { @@ -209,8 +199,10 @@ int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate) if (rate == 0) rate = curr_rate; if (rate != curr_rate) { - stop_stream(efw, &efw->tx_stream); - stop_stream(efw, &efw->rx_stream); + amdtp_domain_stop(&efw->domain); + + cmp_connection_break(&efw->out_conn); + cmp_connection_break(&efw->in_conn);
cmp_connection_release(&efw->out_conn); cmp_connection_release(&efw->in_conn); @@ -250,47 +242,57 @@ int snd_efw_stream_start_duplex(struct snd_efw *efw) if (efw->substreams_counter == 0) return -EIO;
- err = snd_efw_command_get_sampling_rate(efw, &rate); - if (err < 0) - return err; - if (amdtp_streaming_error(&efw->rx_stream) || amdtp_streaming_error(&efw->tx_stream)) { - stop_stream(efw, &efw->rx_stream); - stop_stream(efw, &efw->tx_stream); + amdtp_domain_stop(&efw->domain); + cmp_connection_break(&efw->out_conn); + cmp_connection_break(&efw->in_conn); }
- /* master should be always running */ + err = snd_efw_command_get_sampling_rate(efw, &rate); + if (err < 0) + return err; + if (!amdtp_stream_running(&efw->rx_stream)) { err = start_stream(efw, &efw->rx_stream, rate); - if (err < 0) { - dev_err(&efw->unit->device, - "fail to start AMDTP master stream:%d\n", err); + if (err < 0) goto error; - } - }
- if (!amdtp_stream_running(&efw->tx_stream)) { err = start_stream(efw, &efw->tx_stream, rate); - if (err < 0) { - dev_err(&efw->unit->device, - "fail to start AMDTP slave stream:%d\n", err); + if (err < 0) + goto error; + + err = amdtp_domain_start(&efw->domain); + if (err < 0) + goto error; + + // Wait first callback. + if (!amdtp_stream_wait_callback(&efw->rx_stream, + CALLBACK_TIMEOUT) || + !amdtp_stream_wait_callback(&efw->tx_stream, + CALLBACK_TIMEOUT)) { + err = -ETIMEDOUT; goto error; } }
return 0; error: - stop_stream(efw, &efw->rx_stream); - stop_stream(efw, &efw->tx_stream); + amdtp_domain_stop(&efw->domain); + + cmp_connection_break(&efw->out_conn); + cmp_connection_break(&efw->in_conn); + return err; }
void snd_efw_stream_stop_duplex(struct snd_efw *efw) { if (efw->substreams_counter == 0) { - stop_stream(efw, &efw->tx_stream); - stop_stream(efw, &efw->rx_stream); + amdtp_domain_stop(&efw->domain); + + cmp_connection_break(&efw->out_conn); + cmp_connection_break(&efw->in_conn);
cmp_connection_release(&efw->out_conn); cmp_connection_release(&efw->in_conn); @@ -299,8 +301,10 @@ void snd_efw_stream_stop_duplex(struct snd_efw *efw)
void snd_efw_stream_update_duplex(struct snd_efw *efw) { - stop_stream(efw, &efw->rx_stream); - stop_stream(efw, &efw->tx_stream); + amdtp_domain_stop(&efw->domain); + + cmp_connection_break(&efw->out_conn); + cmp_connection_break(&efw->in_conn);
amdtp_stream_pcm_abort(&efw->rx_stream); amdtp_stream_pcm_abort(&efw->tx_stream); @@ -308,6 +312,8 @@ void snd_efw_stream_update_duplex(struct snd_efw *efw)
void snd_efw_stream_destroy_duplex(struct snd_efw *efw) { + amdtp_domain_destroy(&efw->domain); + destroy_stream(efw, &efw->rx_stream); destroy_stream(efw, &efw->tx_stream); }

This commit adds AMDTP domain support for ALSA oxfw driver.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/oxfw/oxfw-stream.c | 72 ++++++++++++++++++------------- sound/firewire/oxfw/oxfw.h | 2 + 2 files changed, 45 insertions(+), 29 deletions(-)
diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index 74c972d25c66..0318dc4dcc55 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -114,19 +114,13 @@ static int start_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream) if (err < 0) return err;
- err = amdtp_stream_start(stream, conn->resources.channel, conn->speed); + err = amdtp_domain_add_stream(&oxfw->domain, stream, + conn->resources.channel, conn->speed); if (err < 0) { cmp_connection_break(conn); return err; }
- // Wait first packet. - if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) { - amdtp_stream_stop(stream); - cmp_connection_break(conn); - return -ETIMEDOUT; - } - return 0; }
@@ -280,12 +274,12 @@ int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw, pcm_channels = formation.pcm; } if (formation.rate != rate || formation.pcm != pcm_channels) { - amdtp_stream_stop(&oxfw->rx_stream); + amdtp_domain_stop(&oxfw->domain); + cmp_connection_break(&oxfw->in_conn); cmp_connection_release(&oxfw->in_conn);
if (oxfw->has_output) { - amdtp_stream_stop(&oxfw->tx_stream); cmp_connection_break(&oxfw->out_conn); cmp_connection_release(&oxfw->out_conn); } @@ -325,55 +319,66 @@ int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw)
if (amdtp_streaming_error(&oxfw->rx_stream) || amdtp_streaming_error(&oxfw->tx_stream)) { - amdtp_stream_stop(&oxfw->rx_stream); - cmp_connection_break(&oxfw->in_conn); + amdtp_domain_stop(&oxfw->domain);
- if (oxfw->has_output) { - amdtp_stream_stop(&oxfw->tx_stream); + cmp_connection_break(&oxfw->in_conn); + if (oxfw->has_output) cmp_connection_break(&oxfw->out_conn); - } }
if (!amdtp_stream_running(&oxfw->rx_stream)) { err = start_stream(oxfw, &oxfw->rx_stream); if (err < 0) { dev_err(&oxfw->unit->device, - "fail to start rx stream: %d\n", err); + "fail to prepare rx stream: %d\n", err); goto error; } - }
- if (oxfw->has_output) { - if (!amdtp_stream_running(&oxfw->tx_stream)) { + if (oxfw->has_output && + !amdtp_stream_running(&oxfw->tx_stream)) { err = start_stream(oxfw, &oxfw->tx_stream); if (err < 0) { dev_err(&oxfw->unit->device, - "fail to start tx stream: %d\n", err); + "fail to prepare tx stream: %d\n", err); goto error; } } + + err = amdtp_domain_start(&oxfw->domain); + if (err < 0) + goto error; + + // Wait first packet. + if (!amdtp_stream_wait_callback(&oxfw->rx_stream, + CALLBACK_TIMEOUT) || + !amdtp_stream_wait_callback(&oxfw->tx_stream, + CALLBACK_TIMEOUT)) { + err = -ETIMEDOUT; + goto error; + } + }
return 0; error: - amdtp_stream_stop(&oxfw->rx_stream); + amdtp_domain_stop(&oxfw->domain); + cmp_connection_break(&oxfw->in_conn); - if (oxfw->has_output) { - amdtp_stream_stop(&oxfw->tx_stream); + if (oxfw->has_output) cmp_connection_break(&oxfw->out_conn); - } + return err; }
void snd_oxfw_stream_stop_duplex(struct snd_oxfw *oxfw) { if (oxfw->substreams_count == 0) { - amdtp_stream_stop(&oxfw->rx_stream); + amdtp_domain_stop(&oxfw->domain); + cmp_connection_break(&oxfw->in_conn); cmp_connection_release(&oxfw->in_conn);
if (oxfw->has_output) { - amdtp_stream_stop(&oxfw->tx_stream); cmp_connection_break(&oxfw->out_conn); cmp_connection_release(&oxfw->out_conn); } @@ -409,13 +414,22 @@ int snd_oxfw_stream_init_duplex(struct snd_oxfw *oxfw) } }
- return 0; + err = amdtp_domain_init(&oxfw->domain); + if (err < 0) { + destroy_stream(oxfw, &oxfw->rx_stream); + if (oxfw->has_output) + destroy_stream(oxfw, &oxfw->tx_stream); + } + + return err; }
// This function should be called before starting the stream or after stopping // the streams. void snd_oxfw_stream_destroy_duplex(struct snd_oxfw *oxfw) { + amdtp_domain_destroy(&oxfw->domain); + destroy_stream(oxfw, &oxfw->rx_stream);
if (oxfw->has_output) @@ -424,13 +438,13 @@ void snd_oxfw_stream_destroy_duplex(struct snd_oxfw *oxfw)
void snd_oxfw_stream_update_duplex(struct snd_oxfw *oxfw) { - amdtp_stream_stop(&oxfw->rx_stream); + amdtp_domain_stop(&oxfw->domain); + cmp_connection_break(&oxfw->in_conn);
amdtp_stream_pcm_abort(&oxfw->rx_stream);
if (oxfw->has_output) { - amdtp_stream_stop(&oxfw->tx_stream); cmp_connection_break(&oxfw->out_conn);
amdtp_stream_pcm_abort(&oxfw->tx_stream); diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index cb69ab87bb14..c9627b8c5d6e 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -63,6 +63,8 @@ struct snd_oxfw {
const struct ieee1394_device_id *entry; void *spec; + + struct amdtp_domain domain; };
/*

This commit adds AMDTP domain support for ALSA dice driver.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/dice/dice-stream.c | 32 ++++++++++++++++++++++++------- sound/firewire/dice/dice.h | 2 ++ 2 files changed, 27 insertions(+), 7 deletions(-)
diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index a9f0c77734c3..af8c5a2c28f3 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -154,14 +154,10 @@ static void stop_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, for (i = 0; i < params->count; i++) { reg = cpu_to_be32((u32)-1); if (dir == AMDTP_IN_STREAM) { - amdtp_stream_stop(&dice->tx_stream[i]); - snd_dice_transaction_write_tx(dice, params->size * i + TX_ISOCHRONOUS, ®, sizeof(reg)); } else { - amdtp_stream_stop(&dice->rx_stream[i]); - snd_dice_transaction_write_rx(dice, params->size * i + RX_ISOCHRONOUS, ®, sizeof(reg)); @@ -297,10 +293,11 @@ int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate) if (dice->substreams_counter == 0 || curr_rate != rate) { struct reg_params tx_params, rx_params;
+ amdtp_domain_stop(&dice->domain); + err = get_register_params(dice, &tx_params, &rx_params); if (err < 0) return err; - finish_session(dice, &tx_params, &rx_params);
release_resources(dice); @@ -377,7 +374,8 @@ static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, return err; }
- err = amdtp_stream_start(stream, resources->channel, max_speed); + err = amdtp_domain_add_stream(&dice->domain, stream, + resources->channel, max_speed); if (err < 0) return err; } @@ -410,6 +408,7 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice) for (i = 0; i < MAX_STREAMS; ++i) { if (amdtp_streaming_error(&dice->tx_stream[i]) || amdtp_streaming_error(&dice->rx_stream[i])) { + amdtp_domain_stop(&dice->domain); finish_session(dice, &tx_params, &rx_params); break; } @@ -456,6 +455,10 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice) goto error; }
+ err = amdtp_domain_start(&dice->domain); + if (err < 0) + goto error; + for (i = 0; i < MAX_STREAMS; i++) { if ((i < tx_params.count && !amdtp_stream_wait_callback(&dice->tx_stream[i], @@ -471,6 +474,7 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice)
return 0; error: + amdtp_domain_stop(&dice->domain); finish_session(dice, &tx_params, &rx_params); return err; } @@ -485,8 +489,10 @@ void snd_dice_stream_stop_duplex(struct snd_dice *dice) struct reg_params tx_params, rx_params;
if (dice->substreams_counter == 0) { - if (get_register_params(dice, &tx_params, &rx_params) >= 0) + if (get_register_params(dice, &tx_params, &rx_params) >= 0) { + amdtp_domain_stop(&dice->domain); finish_session(dice, &tx_params, &rx_params); + }
release_resources(dice); } @@ -567,6 +573,14 @@ int snd_dice_stream_init_duplex(struct snd_dice *dice) break; } } + + err = amdtp_domain_init(&dice->domain); + if (err < 0) { + for (i = 0; i < MAX_STREAMS; ++i) { + destroy_stream(dice, AMDTP_OUT_STREAM, i); + destroy_stream(dice, AMDTP_IN_STREAM, i); + } + } end: return err; } @@ -579,6 +593,8 @@ void snd_dice_stream_destroy_duplex(struct snd_dice *dice) destroy_stream(dice, AMDTP_IN_STREAM, i); destroy_stream(dice, AMDTP_OUT_STREAM, i); } + + amdtp_domain_destroy(&dice->domain); }
void snd_dice_stream_update_duplex(struct snd_dice *dice) @@ -596,6 +612,8 @@ void snd_dice_stream_update_duplex(struct snd_dice *dice) dice->global_enabled = false;
if (get_register_params(dice, &tx_params, &rx_params) == 0) { + amdtp_domain_stop(&dice->domain); + stop_streams(dice, AMDTP_IN_STREAM, &tx_params); stop_streams(dice, AMDTP_OUT_STREAM, &rx_params); } diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h index c6304e5e9fc4..fa6d74303f54 100644 --- a/sound/firewire/dice/dice.h +++ b/sound/firewire/dice/dice.h @@ -112,6 +112,8 @@ struct snd_dice { bool global_enabled; struct completion clock_accepted; unsigned int substreams_counter; + + struct amdtp_domain domain; };
enum snd_dice_addr_type {

This commit adds AMDTP domain support for ALSA firewire-digi00x driver.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/digi00x/digi00x-stream.c | 55 ++++++++++++++----------- sound/firewire/digi00x/digi00x.h | 2 + 2 files changed, 33 insertions(+), 24 deletions(-)
diff --git a/sound/firewire/digi00x/digi00x-stream.c b/sound/firewire/digi00x/digi00x-stream.c index cff193f00a97..d6a92460060f 100644 --- a/sound/firewire/digi00x/digi00x-stream.c +++ b/sound/firewire/digi00x/digi00x-stream.c @@ -126,9 +126,6 @@ static void finish_session(struct snd_dg00x *dg00x) { __be32 data;
- amdtp_stream_stop(&dg00x->tx_stream); - amdtp_stream_stop(&dg00x->rx_stream); - data = cpu_to_be32(0x00000003); snd_fw_transaction(dg00x->unit, TCODE_WRITE_QUADLET_REQUEST, DG00X_ADDR_BASE + DG00X_OFFSET_STREAMING_SET, @@ -265,13 +262,23 @@ int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x) if (err < 0) destroy_stream(dg00x, &dg00x->rx_stream);
+ err = amdtp_domain_init(&dg00x->domain); + if (err < 0) { + destroy_stream(dg00x, &dg00x->rx_stream); + destroy_stream(dg00x, &dg00x->tx_stream); + } + return err; }
-// This function should be called before starting streams or after stopping -// streams. +/* + * This function should be called before starting streams or after stopping + * streams. + */ void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x) { + amdtp_domain_destroy(&dg00x->domain); + destroy_stream(dg00x, &dg00x->rx_stream); destroy_stream(dg00x, &dg00x->tx_stream); } @@ -288,6 +295,8 @@ int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate) rate = curr_rate;
if (dg00x->substreams_counter == 0 || curr_rate != rate) { + amdtp_domain_stop(&dg00x->domain); + finish_session(dg00x);
fw_iso_resources_free(&dg00x->tx_resources); @@ -320,8 +329,10 @@ int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x) return 0;
if (amdtp_streaming_error(&dg00x->tx_stream) || - amdtp_streaming_error(&dg00x->rx_stream)) + amdtp_streaming_error(&dg00x->rx_stream)) { + amdtp_domain_stop(&dg00x->domain); finish_session(dg00x); + }
if (generation != fw_parent_device(dg00x->unit)->card->generation) { err = fw_iso_resources_update(&dg00x->tx_resources); @@ -338,36 +349,30 @@ int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x) * which source of clock is used. */ if (!amdtp_stream_running(&dg00x->rx_stream)) { + int spd = fw_parent_device(dg00x->unit)->max_speed; + err = begin_session(dg00x); if (err < 0) goto error;
- err = amdtp_stream_start(&dg00x->rx_stream, - dg00x->rx_resources.channel, - fw_parent_device(dg00x->unit)->max_speed); + err = amdtp_domain_add_stream(&dg00x->domain, &dg00x->rx_stream, + dg00x->rx_resources.channel, spd); if (err < 0) goto error;
- if (!amdtp_stream_wait_callback(&dg00x->rx_stream, - CALLBACK_TIMEOUT)) { - err = -ETIMEDOUT; + err = amdtp_domain_add_stream(&dg00x->domain, &dg00x->tx_stream, + dg00x->tx_resources.channel, spd); + if (err < 0) goto error; - } - }
- /* - * The value of SYT field in transmitted packets is always 0x0000. Thus, - * duplex streams with timestamp synchronization cannot be built. - */ - if (!amdtp_stream_running(&dg00x->tx_stream)) { - err = amdtp_stream_start(&dg00x->tx_stream, - dg00x->tx_resources.channel, - fw_parent_device(dg00x->unit)->max_speed); + err = amdtp_domain_start(&dg00x->domain); if (err < 0) goto error;
- if (!amdtp_stream_wait_callback(&dg00x->tx_stream, - CALLBACK_TIMEOUT)) { + if (!amdtp_stream_wait_callback(&dg00x->rx_stream, + CALLBACK_TIMEOUT) || + !amdtp_stream_wait_callback(&dg00x->tx_stream, + CALLBACK_TIMEOUT)) { err = -ETIMEDOUT; goto error; } @@ -375,6 +380,7 @@ int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x)
return 0; error: + amdtp_domain_stop(&dg00x->domain); finish_session(dg00x);
return err; @@ -383,6 +389,7 @@ int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x) void snd_dg00x_stream_stop_duplex(struct snd_dg00x *dg00x) { if (dg00x->substreams_counter == 0) { + amdtp_domain_stop(&dg00x->domain); finish_session(dg00x);
fw_iso_resources_free(&dg00x->tx_resources); diff --git a/sound/firewire/digi00x/digi00x.h b/sound/firewire/digi00x/digi00x.h index 0994d191ccda..8041c65f2736 100644 --- a/sound/firewire/digi00x/digi00x.h +++ b/sound/firewire/digi00x/digi00x.h @@ -59,6 +59,8 @@ struct snd_dg00x {
/* Console models have additional MIDI ports for control surface. */ bool is_console; + + struct amdtp_domain domain; };
#define DG00X_ADDR_BASE 0xffffe0000000ull

This commit adds AMDTP domain support for ALSA firewire-tascam driver.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/tascam/tascam-stream.c | 54 ++++++++++++++++----------- sound/firewire/tascam/tascam.h | 2 + 2 files changed, 34 insertions(+), 22 deletions(-)
diff --git a/sound/firewire/tascam/tascam-stream.c b/sound/firewire/tascam/tascam-stream.c index d5e77036e0ee..9e2dc2fe3271 100644 --- a/sound/firewire/tascam/tascam-stream.c +++ b/sound/firewire/tascam/tascam-stream.c @@ -180,9 +180,6 @@ static void finish_session(struct snd_tscm *tscm) { __be32 reg;
- amdtp_stream_stop(&tscm->rx_stream); - amdtp_stream_stop(&tscm->tx_stream); - reg = 0; snd_fw_transaction(tscm->unit, TCODE_WRITE_QUADLET_REQUEST, TSCM_ADDR_BASE + TSCM_OFFSET_START_STREAMING, @@ -339,8 +336,16 @@ int snd_tscm_stream_init_duplex(struct snd_tscm *tscm) return err;
err = init_stream(tscm, &tscm->rx_stream); - if (err < 0) + if (err < 0) { + destroy_stream(tscm, &tscm->tx_stream); + return err; + } + + err = amdtp_domain_init(&tscm->domain); + if (err < 0) { destroy_stream(tscm, &tscm->tx_stream); + destroy_stream(tscm, &tscm->rx_stream); + }
return err; } @@ -348,17 +353,18 @@ int snd_tscm_stream_init_duplex(struct snd_tscm *tscm) // At bus reset, streaming is stopped and some registers are clear. void snd_tscm_stream_update_duplex(struct snd_tscm *tscm) { - amdtp_stream_pcm_abort(&tscm->tx_stream); - amdtp_stream_stop(&tscm->tx_stream); + amdtp_domain_stop(&tscm->domain);
+ amdtp_stream_pcm_abort(&tscm->tx_stream); amdtp_stream_pcm_abort(&tscm->rx_stream); - amdtp_stream_stop(&tscm->rx_stream); }
// This function should be called before starting streams or after stopping // streams. void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm) { + amdtp_domain_destroy(&tscm->domain); + destroy_stream(tscm, &tscm->rx_stream); destroy_stream(tscm, &tscm->tx_stream); } @@ -373,6 +379,8 @@ int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate) return err;
if (tscm->substreams_counter == 0 || rate != curr_rate) { + amdtp_domain_stop(&tscm->domain); + finish_session(tscm);
fw_iso_resources_free(&tscm->tx_resources); @@ -405,8 +413,10 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate) return 0;
if (amdtp_streaming_error(&tscm->rx_stream) || - amdtp_streaming_error(&tscm->tx_stream)) + amdtp_streaming_error(&tscm->tx_stream)) { + amdtp_domain_stop(&tscm->domain); finish_session(tscm); + }
if (generation != fw_parent_device(tscm->unit)->card->generation) { err = fw_iso_resources_update(&tscm->tx_resources); @@ -419,6 +429,8 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate) }
if (!amdtp_stream_running(&tscm->rx_stream)) { + int spd = fw_parent_device(tscm->unit)->max_speed; + err = set_stream_formats(tscm, rate); if (err < 0) goto error; @@ -427,27 +439,23 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate) if (err < 0) goto error;
- err = amdtp_stream_start(&tscm->rx_stream, - tscm->rx_resources.channel, - fw_parent_device(tscm->unit)->max_speed); + err = amdtp_domain_add_stream(&tscm->domain, &tscm->rx_stream, + tscm->rx_resources.channel, spd); if (err < 0) goto error;
- if (!amdtp_stream_wait_callback(&tscm->rx_stream, - CALLBACK_TIMEOUT)) { - err = -ETIMEDOUT; + err = amdtp_domain_add_stream(&tscm->domain, &tscm->tx_stream, + tscm->tx_resources.channel, spd); + if (err < 0) goto error; - } - }
- if (!amdtp_stream_running(&tscm->tx_stream)) { - err = amdtp_stream_start(&tscm->tx_stream, - tscm->tx_resources.channel, - fw_parent_device(tscm->unit)->max_speed); + err = amdtp_domain_start(&tscm->domain); if (err < 0) - goto error; + return err;
- if (!amdtp_stream_wait_callback(&tscm->tx_stream, + if (!amdtp_stream_wait_callback(&tscm->rx_stream, + CALLBACK_TIMEOUT) || + !amdtp_stream_wait_callback(&tscm->tx_stream, CALLBACK_TIMEOUT)) { err = -ETIMEDOUT; goto error; @@ -456,6 +464,7 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate)
return 0; error: + amdtp_domain_stop(&tscm->domain); finish_session(tscm);
return err; @@ -464,6 +473,7 @@ int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate) void snd_tscm_stream_stop_duplex(struct snd_tscm *tscm) { if (tscm->substreams_counter == 0) { + amdtp_domain_stop(&tscm->domain); finish_session(tscm);
fw_iso_resources_free(&tscm->tx_resources); diff --git a/sound/firewire/tascam/tascam.h b/sound/firewire/tascam/tascam.h index 734e5bb9c3da..64a2e4d2bbfe 100644 --- a/sound/firewire/tascam/tascam.h +++ b/sound/firewire/tascam/tascam.h @@ -97,6 +97,8 @@ struct snd_tscm { struct snd_firewire_tascam_change queue[SND_TSCM_QUEUE_COUNT]; unsigned int pull_pos; unsigned int push_pos; + + struct amdtp_domain domain; };
#define TSCM_ADDR_BASE 0xffff00000000ull

This commit adds AMDTP domain support for ALSA firewire-motu driver.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/motu/motu-stream.c | 83 +++++++++++++++---------------- sound/firewire/motu/motu.h | 2 + 2 files changed, 42 insertions(+), 43 deletions(-)
diff --git a/sound/firewire/motu/motu-stream.c b/sound/firewire/motu/motu-stream.c index cc9f34426a47..813e38e6a86e 100644 --- a/sound/firewire/motu/motu-stream.c +++ b/sound/firewire/motu/motu-stream.c @@ -92,9 +92,6 @@ static void finish_session(struct snd_motu *motu) if (err < 0) return;
- amdtp_stream_stop(&motu->tx_stream); - amdtp_stream_stop(&motu->rx_stream); - err = snd_motu_transaction_read(motu, ISOC_COMM_CONTROL_OFFSET, ®, sizeof(reg)); if (err < 0) @@ -109,27 +106,6 @@ static void finish_session(struct snd_motu *motu) sizeof(reg)); }
-static int start_isoc_ctx(struct snd_motu *motu, struct amdtp_stream *stream) -{ - struct fw_iso_resources *resources; - int err; - - if (stream == &motu->rx_stream) - resources = &motu->rx_resources; - else - resources = &motu->tx_resources; - - err = amdtp_stream_start(stream, resources->channel, - fw_parent_device(motu->unit)->max_speed); - if (err < 0) - return err; - - if (!amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT)) - return -ETIMEDOUT; - - return 0; -} - int snd_motu_stream_cache_packet_formats(struct snd_motu *motu) { int err; @@ -169,6 +145,7 @@ int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate) rate = curr_rate;
if (motu->substreams_counter == 0 || curr_rate != rate) { + amdtp_domain_stop(&motu->domain); finish_session(motu);
fw_iso_resources_free(&motu->tx_resources); @@ -234,8 +211,10 @@ int snd_motu_stream_start_duplex(struct snd_motu *motu) return 0;
if (amdtp_streaming_error(&motu->rx_stream) || - amdtp_streaming_error(&motu->tx_stream)) + amdtp_streaming_error(&motu->tx_stream)) { + amdtp_domain_stop(&motu->domain); finish_session(motu); + }
if (generation != fw_parent_device(motu->unit)->card->generation) { err = fw_iso_resources_update(&motu->rx_resources); @@ -248,6 +227,8 @@ int snd_motu_stream_start_duplex(struct snd_motu *motu) }
if (!amdtp_stream_running(&motu->rx_stream)) { + int spd = fw_parent_device(motu->unit)->max_speed; + err = ensure_packet_formats(motu); if (err < 0) return err; @@ -259,26 +240,32 @@ int snd_motu_stream_start_duplex(struct snd_motu *motu) goto stop_streams; }
- err = start_isoc_ctx(motu, &motu->rx_stream); - if (err < 0) { - dev_err(&motu->unit->device, - "fail to start IT context: %d\n", err); + err = amdtp_domain_add_stream(&motu->domain, &motu->tx_stream, + motu->tx_resources.channel, spd); + if (err < 0) goto stop_streams; - }
- err = motu->spec->protocol->switch_fetching_mode(motu, true); - if (err < 0) { - dev_err(&motu->unit->device, - "fail to enable frame fetching: %d\n", err); + err = amdtp_domain_add_stream(&motu->domain, &motu->rx_stream, + motu->rx_resources.channel, spd); + if (err < 0) + goto stop_streams; + + err = amdtp_domain_start(&motu->domain); + if (err < 0) + goto stop_streams; + + if (!amdtp_stream_wait_callback(&motu->tx_stream, + CALLBACK_TIMEOUT) || + !amdtp_stream_wait_callback(&motu->rx_stream, + CALLBACK_TIMEOUT)) { + err = -ETIMEDOUT; goto stop_streams; } - }
- if (!amdtp_stream_running(&motu->tx_stream)) { - err = start_isoc_ctx(motu, &motu->tx_stream); + err = motu->spec->protocol->switch_fetching_mode(motu, true); if (err < 0) { dev_err(&motu->unit->device, - "fail to start IR context: %d", err); + "fail to enable frame fetching: %d\n", err); goto stop_streams; } } @@ -286,6 +273,7 @@ int snd_motu_stream_start_duplex(struct snd_motu *motu) return 0;
stop_streams: + amdtp_domain_stop(&motu->domain); finish_session(motu); return err; } @@ -293,6 +281,7 @@ int snd_motu_stream_start_duplex(struct snd_motu *motu) void snd_motu_stream_stop_duplex(struct snd_motu *motu) { if (motu->substreams_counter == 0) { + amdtp_domain_stop(&motu->domain); finish_session(motu);
fw_iso_resources_free(&motu->tx_resources); @@ -344,18 +333,26 @@ int snd_motu_stream_init_duplex(struct snd_motu *motu) return err;
err = init_stream(motu, &motu->rx_stream); - if (err < 0) + if (err < 0) { destroy_stream(motu, &motu->tx_stream); + return err; + } + + err = amdtp_domain_init(&motu->domain); + if (err < 0) { + destroy_stream(motu, &motu->tx_stream); + destroy_stream(motu, &motu->rx_stream); + }
return err; }
-/* - * This function should be called before starting streams or after stopping - * streams. - */ +// This function should be called before starting streams or after stopping +// streams. void snd_motu_stream_destroy_duplex(struct snd_motu *motu) { + amdtp_domain_destroy(&motu->domain); + destroy_stream(motu, &motu->rx_stream); destroy_stream(motu, &motu->tx_stream);
diff --git a/sound/firewire/motu/motu.h b/sound/firewire/motu/motu.h index 09d1451d7de4..350ee2c16f4a 100644 --- a/sound/firewire/motu/motu.h +++ b/sound/firewire/motu/motu.h @@ -69,6 +69,8 @@ struct snd_motu { int dev_lock_count; bool dev_lock_changed; wait_queue_head_t hwdep_wait; + + struct amdtp_domain domain; };
enum snd_motu_spec_flags {

This commit adds AMDTP domain support for ALSA fireface driver.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/fireface/ff-stream.c | 57 +++++++++++++++++------------ sound/firewire/fireface/ff.h | 2 + 2 files changed, 35 insertions(+), 24 deletions(-)
diff --git a/sound/firewire/fireface/ff-stream.c b/sound/firewire/fireface/ff-stream.c index e4710204f481..e8e6f9fd6433 100644 --- a/sound/firewire/fireface/ff-stream.c +++ b/sound/firewire/fireface/ff-stream.c @@ -32,9 +32,6 @@ int snd_ff_stream_get_multiplier_mode(enum cip_sfc sfc,
static inline void finish_session(struct snd_ff *ff) { - amdtp_stream_stop(&ff->tx_stream); - amdtp_stream_stop(&ff->rx_stream); - ff->spec->protocol->finish_session(ff); ff->spec->protocol->switch_fetching_mode(ff, false); } @@ -83,8 +80,16 @@ int snd_ff_stream_init_duplex(struct snd_ff *ff) return err;
err = init_stream(ff, &ff->tx_stream); - if (err < 0) + if (err < 0) { destroy_stream(ff, &ff->rx_stream); + return err; + } + + err = amdtp_domain_init(&ff->domain); + if (err < 0) { + destroy_stream(ff, &ff->rx_stream); + destroy_stream(ff, &ff->tx_stream); + }
return err; } @@ -95,6 +100,8 @@ int snd_ff_stream_init_duplex(struct snd_ff *ff) */ void snd_ff_stream_destroy_duplex(struct snd_ff *ff) { + amdtp_domain_destroy(&ff->domain); + destroy_stream(ff, &ff->rx_stream); destroy_stream(ff, &ff->tx_stream); } @@ -113,6 +120,7 @@ int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate) enum snd_ff_stream_mode mode; int i;
+ amdtp_domain_stop(&ff->domain); finish_session(ff);
fw_iso_resources_free(&ff->tx_resources); @@ -155,51 +163,52 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate) return 0;
if (amdtp_streaming_error(&ff->tx_stream) || - amdtp_streaming_error(&ff->rx_stream)) + amdtp_streaming_error(&ff->rx_stream)) { + amdtp_domain_stop(&ff->domain); finish_session(ff); + }
/* * Regardless of current source of clock signal, drivers transfer some * packets. Then, the device transfers packets. */ if (!amdtp_stream_running(&ff->rx_stream)) { + int spd = fw_parent_device(ff->unit)->max_speed; + err = ff->spec->protocol->begin_session(ff, rate); if (err < 0) goto error;
- err = amdtp_stream_start(&ff->rx_stream, - ff->rx_resources.channel, - fw_parent_device(ff->unit)->max_speed); + err = amdtp_domain_add_stream(&ff->domain, &ff->rx_stream, + ff->rx_resources.channel, spd); if (err < 0) goto error;
- if (!amdtp_stream_wait_callback(&ff->rx_stream, - CALLBACK_TIMEOUT_MS)) { - err = -ETIMEDOUT; - goto error; - } - - err = ff->spec->protocol->switch_fetching_mode(ff, true); + err = amdtp_domain_add_stream(&ff->domain, &ff->tx_stream, + ff->tx_resources.channel, spd); if (err < 0) goto error; - }
- if (!amdtp_stream_running(&ff->tx_stream)) { - err = amdtp_stream_start(&ff->tx_stream, - ff->tx_resources.channel, - fw_parent_device(ff->unit)->max_speed); + err = amdtp_domain_start(&ff->domain); if (err < 0) goto error;
- if (!amdtp_stream_wait_callback(&ff->tx_stream, + if (!amdtp_stream_wait_callback(&ff->rx_stream, + CALLBACK_TIMEOUT_MS) || + !amdtp_stream_wait_callback(&ff->tx_stream, CALLBACK_TIMEOUT_MS)) { err = -ETIMEDOUT; goto error; } + + err = ff->spec->protocol->switch_fetching_mode(ff, true); + if (err < 0) + goto error; }
return 0; error: + amdtp_domain_stop(&ff->domain); finish_session(ff);
return err; @@ -208,6 +217,7 @@ int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate) void snd_ff_stream_stop_duplex(struct snd_ff *ff) { if (ff->substreams_counter == 0) { + amdtp_domain_stop(&ff->domain); finish_session(ff);
fw_iso_resources_free(&ff->tx_resources); @@ -217,12 +227,11 @@ void snd_ff_stream_stop_duplex(struct snd_ff *ff)
void snd_ff_stream_update_duplex(struct snd_ff *ff) { + amdtp_domain_stop(&ff->domain); + // The device discontinue to transfer packets. amdtp_stream_pcm_abort(&ff->tx_stream); - amdtp_stream_stop(&ff->tx_stream); - amdtp_stream_pcm_abort(&ff->rx_stream); - amdtp_stream_stop(&ff->rx_stream); }
void snd_ff_stream_lock_changed(struct snd_ff *ff) diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h index 36dd0c75b9f7..b4c22ca6079e 100644 --- a/sound/firewire/fireface/ff.h +++ b/sound/firewire/fireface/ff.h @@ -91,6 +91,8 @@ struct snd_ff { int dev_lock_count; bool dev_lock_changed; wait_queue_head_t hwdep_wait; + + struct amdtp_domain domain; };
enum snd_ff_clock_src {

As a result to support AMDTP domain, no drivers call kernel APIs to start/stop each AMDTP stream. This commit localize these APIs.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/amdtp-stream.c | 6 ++---- sound/firewire/amdtp-stream.h | 2 -- 2 files changed, 2 insertions(+), 6 deletions(-)
diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 158d210caea7..1a92855c7647 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -894,7 +894,7 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context, * amdtp_stream_set_parameters() and it must be started before any PCM or MIDI * device can be started. */ -int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed) +static int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed) { static const struct { unsigned int data_block; @@ -1027,7 +1027,6 @@ int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed)
return err; } -EXPORT_SYMBOL(amdtp_stream_start);
/** * amdtp_stream_pcm_pointer - get the PCM buffer position @@ -1098,7 +1097,7 @@ EXPORT_SYMBOL(amdtp_stream_update); * All PCM and MIDI devices of the stream must be stopped before the stream * itself can be stopped. */ -void amdtp_stream_stop(struct amdtp_stream *s) +static void amdtp_stream_stop(struct amdtp_stream *s) { mutex_lock(&s->mutex);
@@ -1118,7 +1117,6 @@ void amdtp_stream_stop(struct amdtp_stream *s)
mutex_unlock(&s->mutex); } -EXPORT_SYMBOL(amdtp_stream_stop);
/** * amdtp_stream_pcm_abort - abort the running PCM device diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index 15d471660a43..bbbca964b9b4 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -188,9 +188,7 @@ int amdtp_stream_set_parameters(struct amdtp_stream *s, unsigned int rate, unsigned int data_block_quadlets); unsigned int amdtp_stream_get_max_payload(struct amdtp_stream *s);
-int amdtp_stream_start(struct amdtp_stream *s, int channel, int speed); void amdtp_stream_update(struct amdtp_stream *s); -void amdtp_stream_stop(struct amdtp_stream *s);
int amdtp_stream_add_pcm_hw_constraints(struct amdtp_stream *s, struct snd_pcm_runtime *runtime);

On Sun, 04 Aug 2019 08:21:19 +0200, Takashi Sakamoto wrote:
Hi,
This patchset is to implement AMDTP domain I addressed in my previous patchset: https://mailman.alsa-project.org/pipermail/alsa-devel/2019-July/152430.html
My work for libhinoko[1][2] allows me to sniff actual packet transmission between devices and drivers in Windows/Mac OS for long period (e.g. 1 hour). As a result, some supported devices don't follow packet sequences transferred by the drivers. They expect drivers to parse isoc packets in tx stream and recover frequency of data block then transfer isoc packets as rx stream.
(I note that no specification describes this mechanism as long as I know. In the specification, clock recovery is one-way from transmitter to receivers, thus recovered clock is not necessarily used for transmission from the receiver to the transmitter.)
For the clock recovery in driver side, several isoc contexts should be handled in one time to parse packets in incoming stream and to build packets in outgoing stream. The AMDTP domain is designed for this purpose.
In this time, the AMDTP domain implements the functionalities to start/stop a couple of isoc contexts for some AMDTP streams. Each context still runs in own handler for scheduled hardware IRQs. I'll post further work after merged.
[1] https://mailman.alsa-project.org/pipermail/alsa-devel/2019-April/147862.html [2] https://github.com/takaswie/libhinoko
Takashi Sakamoto (19): ALSA: firewire-lib: add AMDTP domain structure to handle several isoc context in one interrupt callback ALSA: firewire-lib: add a kernel API to stop a couple of AMDTP streams in AMDTP domain ALSA: firewire-lib: add a kernel API to add AMDTP stream into AMDTP domain ALSA: firewire-lib: add a kernel API to start AMDTP streams in AMDTP domain ALSA: fireworks: code refactoring for initialization/destruction of AMDTP streams ALSA: fireworks: code refactoring for bus reset handler ALSA: firewire-digi00x: code refactoring for initialization/destruction of AMDTP stream ALSA: firewire-tascam: code refactoring for initialization/destruction of AMDTP stream ALSA: firewire-motu: code refactoring for initialization/destruction of AMDTP stream ALSA: fireface: code refactoring for initialization/destruction of AMDTP stream ALSA: bebob: support AMDTP domain ALSA: fireworks: support AMDTP domain ALSA: oxfw: support AMDTP domain ALSA: dice: support AMDTP domain ALSA: firewire-digi00x: support AMDTP domain ALSA: firewire-tascam: support AMDTP domain ALSA: firewire-motu: support AMDTP domain ALSA: fireface: support AMDTP domain ALSA: firewire-lib: localize kernel APIs to start/stop each AMDTP stream
Applied all patches now. Thanks.
Takashi
participants (2)
-
Takashi Iwai
-
Takashi Sakamoto