[alsa-devel] [PATCH 00/17] firewire: share the size of period for both playback and capture PCM substreams
Hi,
This patchset is a preparation for enhancement of AMDTP domain that I addressed to my previous patchset: https://mailman.alsa-project.org/pipermail/alsa-devel/2019-July/152430.html
When queued packets for several IT/IR contexts in the same domain are handled in hardware IRQ context for an IT context, the number of events in the packets are mostly the same for each of contexts. This means that the size of period for PCM substreams associated to the contexts is also the same.
At present, PCM substreams for the contexts can have own size of period. This commit adds a member into AMDTP domain to share the size of period for PCM substreams on AMDTP streams in the same domain.
This patchset includes optimization to detect whether isochronous resources for AMDTP streams are reserved or not in pcm.open callback.
Takashi Sakamoto (17): firewire-lib: add a member into AMDTP domain for events per period bebob: register the size of PCM period to AMDTP domain fireworks: register the size of PCM period to AMDTP domain oxfw: register the size of PCM period to AMDTP domain dice: register the size of PCM period to AMDTP domain firewire-digi00x: register the size of PCM period to AMDTP domain firewire-tascam: register the size of PCM period to AMDTP domain firewire-motu: register the size of PCM period to AMDTP domain fireface: register the size of PCM period to AMDTP domain bebob: use the same size of period for PCM substream in AMDTP streams fireworks: use the same size of period for PCM substream in AMDTP streams oxfw: use the same size of period for PCM substream in AMDTP streams dice: use the same size of period for PCM substream in AMDTP streams firewire-digi00x: use the same size of period for PCM substream in AMDTP streams firewire-tascam: use the same size of period for PCM substream in AMDTP streams firewire-motu: use the same size of period for PCM substream in AMDTP streams fireface: use the same size of period for PCM substreams in AMDTP streams
sound/firewire/amdtp-stream.c | 4 ++ sound/firewire/amdtp-stream.h | 10 +++++ sound/firewire/bebob/bebob.h | 3 +- sound/firewire/bebob/bebob_midi.c | 2 +- sound/firewire/bebob/bebob_pcm.c | 43 ++++++++++++------ sound/firewire/bebob/bebob_stream.c | 11 ++++- sound/firewire/dice/dice-midi.c | 2 +- sound/firewire/dice/dice-pcm.c | 50 +++++++++++++++------ sound/firewire/dice/dice-stream.c | 8 +++- sound/firewire/dice/dice.h | 3 +- sound/firewire/digi00x/digi00x-midi.c | 2 +- sound/firewire/digi00x/digi00x-pcm.c | 39 ++++++++++++---- sound/firewire/digi00x/digi00x-stream.c | 11 ++++- sound/firewire/digi00x/digi00x.h | 3 +- sound/firewire/fireface/ff-pcm.c | 32 ++++++++++--- sound/firewire/fireface/ff-stream.c | 11 ++++- sound/firewire/fireface/ff.h | 3 +- sound/firewire/fireworks/fireworks.h | 3 +- sound/firewire/fireworks/fireworks_midi.c | 2 +- sound/firewire/fireworks/fireworks_pcm.c | 43 +++++++++++++----- sound/firewire/fireworks/fireworks_stream.c | 11 ++++- sound/firewire/motu/motu-midi.c | 2 +- sound/firewire/motu/motu-pcm.c | 33 ++++++++++---- sound/firewire/motu/motu-stream.c | 11 ++++- sound/firewire/motu/motu.h | 3 +- sound/firewire/oxfw/oxfw-midi.c | 4 +- sound/firewire/oxfw/oxfw-pcm.c | 45 +++++++++++++------ sound/firewire/oxfw/oxfw-stream.c | 12 ++++- sound/firewire/oxfw/oxfw.h | 3 +- sound/firewire/tascam/tascam-pcm.c | 38 ++++++++++++---- sound/firewire/tascam/tascam-stream.c | 11 ++++- sound/firewire/tascam/tascam.h | 3 +- 32 files changed, 354 insertions(+), 107 deletions(-)
In IEC 61883-6, it's called as 'event' what has presentation time represented by timestamp in CIP header. Although the ratio of the number of event against the number of data block is different depending on event data type represented by the specific field in CIP header, it's just one in the most cases supported by ALSA IEC 61883-1/6 engine.
In 1394 OHCI specification, applications can schedule hardware IRQ by configuring descriptor with IRQ flag for packet against each isochronous cycle. For future commit, I use the hardware IRQ for isoc IT context to acknowledge the elapse of PCM period for both playback/capture directions on AMDTP streams in the same domain.
This commit is a preparation for the above idea. This commit adds a member into AMDTP domain structure to record the number of PCM frames.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/amdtp-stream.c | 4 ++++ sound/firewire/amdtp-stream.h | 10 ++++++++++ 2 files changed, 14 insertions(+)
diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index e50e28f77e74..838f695b20de 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -1143,6 +1143,8 @@ int amdtp_domain_init(struct amdtp_domain *d) { INIT_LIST_HEAD(&d->streams);
+ d->events_per_period = 0; + return 0; } EXPORT_SYMBOL_GPL(amdtp_domain_init); @@ -1221,5 +1223,7 @@ void amdtp_domain_stop(struct amdtp_domain *d)
amdtp_stream_stop(s); } + + d->events_per_period = 0; } EXPORT_SYMBOL_GPL(amdtp_domain_stop); diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index bbbca964b9b4..d95a4ed15f20 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -272,6 +272,8 @@ static inline bool amdtp_stream_wait_callback(struct amdtp_stream *s,
struct amdtp_domain { struct list_head streams; + + unsigned int events_per_period; };
int amdtp_domain_init(struct amdtp_domain *d); @@ -283,4 +285,12 @@ int amdtp_domain_add_stream(struct amdtp_domain *d, struct amdtp_stream *s, int amdtp_domain_start(struct amdtp_domain *d); void amdtp_domain_stop(struct amdtp_domain *d);
+static inline int amdtp_domain_set_events_per_period(struct amdtp_domain *d, + unsigned int events_per_period) +{ + d->events_per_period = events_per_period; + + return 0; +} + #endif
This commit is a preparation to share the size of PCM period between PCM substreams on AMDTP streams in the same domain. At this time, the size of PCM period in PCM substream which starts AMDTP streams in the same domain is recorded.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/bebob/bebob.h | 3 ++- sound/firewire/bebob/bebob_midi.c | 2 +- sound/firewire/bebob/bebob_pcm.c | 4 +++- sound/firewire/bebob/bebob_stream.c | 11 ++++++++++- 4 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/sound/firewire/bebob/bebob.h b/sound/firewire/bebob/bebob.h index 356d6ba60959..8738c1d8abf7 100644 --- a/sound/firewire/bebob/bebob.h +++ b/sound/firewire/bebob/bebob.h @@ -217,7 +217,8 @@ int snd_bebob_stream_get_clock_src(struct snd_bebob *bebob, enum snd_bebob_clock_type *src); int snd_bebob_stream_discover(struct snd_bebob *bebob); int snd_bebob_stream_init_duplex(struct snd_bebob *bebob); -int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate); +int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate, + unsigned int frames_per_period); int snd_bebob_stream_start_duplex(struct snd_bebob *bebob); void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob); void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob); diff --git a/sound/firewire/bebob/bebob_midi.c b/sound/firewire/bebob/bebob_midi.c index 4d8805fa8a00..e8f9edf50be5 100644 --- a/sound/firewire/bebob/bebob_midi.c +++ b/sound/firewire/bebob/bebob_midi.c @@ -17,7 +17,7 @@ static int midi_open(struct snd_rawmidi_substream *substream) return err;
mutex_lock(&bebob->mutex); - err = snd_bebob_stream_reserve_duplex(bebob, 0); + err = snd_bebob_stream_reserve_duplex(bebob, 0, 0); if (err >= 0) { ++bebob->substreams_counter; err = snd_bebob_stream_start_duplex(bebob); diff --git a/sound/firewire/bebob/bebob_pcm.c b/sound/firewire/bebob/bebob_pcm.c index 0fb9eed46837..3b2227abf8a9 100644 --- a/sound/firewire/bebob/bebob_pcm.c +++ b/sound/firewire/bebob/bebob_pcm.c @@ -197,9 +197,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); + unsigned int frames_per_period = params_period_size(hw_params);
mutex_lock(&bebob->mutex); - err = snd_bebob_stream_reserve_duplex(bebob, rate); + err = snd_bebob_stream_reserve_duplex(bebob, rate, + frames_per_period); if (err >= 0) ++bebob->substreams_counter; mutex_unlock(&bebob->mutex); diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index 73fee991bd75..f1db3ddc3e00 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c @@ -554,7 +554,8 @@ static int keep_resources(struct snd_bebob *bebob, struct amdtp_stream *stream, return cmp_connection_reserve(conn, amdtp_stream_get_max_payload(stream)); }
-int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate) +int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate, + unsigned int frames_per_period) { unsigned int curr_rate; int err; @@ -607,6 +608,14 @@ int snd_bebob_stream_reserve_duplex(struct snd_bebob *bebob, unsigned int rate) cmp_connection_release(&bebob->out_conn); return err; } + + err = amdtp_domain_set_events_per_period(&bebob->domain, + frames_per_period); + if (err < 0) { + cmp_connection_release(&bebob->out_conn); + cmp_connection_release(&bebob->in_conn); + return err; + } }
return 0;
This commit is a preparation to share the size of PCM period between PCM substreams on AMDTP streams in the same domain. At this time, the size of PCM period in PCM substream which starts AMDTP streams in the same domain is recorded.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/fireworks/fireworks.h | 3 ++- sound/firewire/fireworks/fireworks_midi.c | 2 +- sound/firewire/fireworks/fireworks_pcm.c | 4 +++- sound/firewire/fireworks/fireworks_stream.c | 11 ++++++++++- 4 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/sound/firewire/fireworks/fireworks.h b/sound/firewire/fireworks/fireworks.h index 4cda297f8438..fc5f945a49ff 100644 --- a/sound/firewire/fireworks/fireworks.h +++ b/sound/firewire/fireworks/fireworks.h @@ -207,7 +207,8 @@ int snd_efw_command_get_sampling_rate(struct snd_efw *efw, unsigned int *rate); int snd_efw_command_set_sampling_rate(struct snd_efw *efw, unsigned int rate);
int snd_efw_stream_init_duplex(struct snd_efw *efw); -int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate); +int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate, + unsigned int frames_per_period); int snd_efw_stream_start_duplex(struct snd_efw *efw); void snd_efw_stream_stop_duplex(struct snd_efw *efw); void snd_efw_stream_update_duplex(struct snd_efw *efw); diff --git a/sound/firewire/fireworks/fireworks_midi.c b/sound/firewire/fireworks/fireworks_midi.c index a9f4a9630d15..e593f842ee8f 100644 --- a/sound/firewire/fireworks/fireworks_midi.c +++ b/sound/firewire/fireworks/fireworks_midi.c @@ -17,7 +17,7 @@ static int midi_open(struct snd_rawmidi_substream *substream) goto end;
mutex_lock(&efw->mutex); - err = snd_efw_stream_reserve_duplex(efw, 0); + err = snd_efw_stream_reserve_duplex(efw, 0, 0); if (err >= 0) { ++efw->substreams_counter; err = snd_efw_stream_start_duplex(efw); diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c index a7025dccc754..35fc95283423 100644 --- a/sound/firewire/fireworks/fireworks_pcm.c +++ b/sound/firewire/fireworks/fireworks_pcm.c @@ -231,9 +231,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); + unsigned int frames_per_period = params_period_size(hw_params);
mutex_lock(&efw->mutex); - err = snd_efw_stream_reserve_duplex(efw, rate); + err = snd_efw_stream_reserve_duplex(efw, rate, + frames_per_period); if (err >= 0) ++efw->substreams_counter; mutex_unlock(&efw->mutex); diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index f2de304d2f26..0787d5c3b01b 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -181,7 +181,8 @@ static int keep_resources(struct snd_efw *efw, struct amdtp_stream *stream, return cmp_connection_reserve(conn, amdtp_stream_get_max_payload(stream)); }
-int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate) +int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate, + unsigned int frames_per_period) { unsigned int curr_rate; int err; @@ -228,6 +229,14 @@ int snd_efw_stream_reserve_duplex(struct snd_efw *efw, unsigned int rate) cmp_connection_release(&efw->in_conn); return err; } + + err = amdtp_domain_set_events_per_period(&efw->domain, + frames_per_period); + if (err < 0) { + cmp_connection_release(&efw->in_conn); + cmp_connection_release(&efw->out_conn); + return err; + } }
return 0;
This commit is a preparation to share the size of PCM period between PCM substreams on AMDTP streams in the same domain. At this time, the size of PCM period in PCM substream which starts AMDTP streams in the same domain is recorded.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/oxfw/oxfw-midi.c | 4 ++-- sound/firewire/oxfw/oxfw-pcm.c | 6 ++++-- sound/firewire/oxfw/oxfw-stream.c | 12 +++++++++++- sound/firewire/oxfw/oxfw.h | 3 ++- 4 files changed, 19 insertions(+), 6 deletions(-)
diff --git a/sound/firewire/oxfw/oxfw-midi.c b/sound/firewire/oxfw/oxfw-midi.c index 9bdec08cb8ea..72db7a17d0ad 100644 --- a/sound/firewire/oxfw/oxfw-midi.c +++ b/sound/firewire/oxfw/oxfw-midi.c @@ -18,7 +18,7 @@ static int midi_capture_open(struct snd_rawmidi_substream *substream)
mutex_lock(&oxfw->mutex);
- err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, 0, 0); + err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, 0, 0, 0); if (err >= 0) { ++oxfw->substreams_count; err = snd_oxfw_stream_start_duplex(oxfw); @@ -45,7 +45,7 @@ static int midi_playback_open(struct snd_rawmidi_substream *substream)
mutex_lock(&oxfw->mutex);
- err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream, 0, 0); + err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream, 0, 0, 0); if (err >= 0) { ++oxfw->substreams_count; err = snd_oxfw_stream_start_duplex(oxfw); diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c index 7c6d1c277d4d..2d1b5038f7f6 100644 --- a/sound/firewire/oxfw/oxfw-pcm.c +++ b/sound/firewire/oxfw/oxfw-pcm.c @@ -221,10 +221,11 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream, if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); unsigned int channels = params_channels(hw_params); + unsigned int frames_per_period = params_period_size(hw_params);
mutex_lock(&oxfw->mutex); err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream, - rate, channels); + rate, channels, frames_per_period); if (err >= 0) ++oxfw->substreams_count; mutex_unlock(&oxfw->mutex); @@ -246,10 +247,11 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream, if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); unsigned int channels = params_channels(hw_params); + unsigned int frames_per_period = params_period_size(hw_params);
mutex_lock(&oxfw->mutex); err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream, - rate, channels); + rate, channels, frames_per_period); if (err >= 0) ++oxfw->substreams_count; mutex_unlock(&oxfw->mutex); diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index 3c9a796b6526..7d2e88c5b73d 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c @@ -244,7 +244,8 @@ static int keep_resources(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw, struct amdtp_stream *stream, - unsigned int rate, unsigned int pcm_channels) + unsigned int rate, unsigned int pcm_channels, + unsigned int frames_per_period) { struct snd_oxfw_stream_formation formation; enum avc_general_plug_dir dir; @@ -305,6 +306,15 @@ int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw, return err; } } + + err = amdtp_domain_set_events_per_period(&oxfw->domain, + frames_per_period); + if (err < 0) { + cmp_connection_release(&oxfw->in_conn); + if (oxfw->has_output) + cmp_connection_release(&oxfw->out_conn); + return err; + } }
return 0; diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index c9627b8c5d6e..422746ef2439 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -103,7 +103,8 @@ int avc_general_inquiry_sig_fmt(struct fw_unit *unit, unsigned int rate, int snd_oxfw_stream_init_duplex(struct snd_oxfw *oxfw); int snd_oxfw_stream_reserve_duplex(struct snd_oxfw *oxfw, struct amdtp_stream *stream, - unsigned int rate, unsigned int pcm_channels); + unsigned int rate, unsigned int pcm_channels, + unsigned int frames_per_period); int snd_oxfw_stream_start_duplex(struct snd_oxfw *oxfw); void snd_oxfw_stream_stop_duplex(struct snd_oxfw *oxfw); void snd_oxfw_stream_destroy_duplex(struct snd_oxfw *oxfw);
This commit is a preparation to share the size of PCM period between PCM substreams on AMDTP streams in the same domain. At this time, the size of PCM period in PCM substream which starts AMDTP streams in the same domain is recorded.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/dice/dice-midi.c | 2 +- sound/firewire/dice/dice-pcm.c | 7 ++++++- sound/firewire/dice/dice-stream.c | 8 +++++++- sound/firewire/dice/dice.h | 3 ++- 4 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/sound/firewire/dice/dice-midi.c b/sound/firewire/dice/dice-midi.c index c9e19bddfc09..69c3c06bd7aa 100644 --- a/sound/firewire/dice/dice-midi.c +++ b/sound/firewire/dice/dice-midi.c @@ -17,7 +17,7 @@ static int midi_open(struct snd_rawmidi_substream *substream)
mutex_lock(&dice->mutex);
- err = snd_dice_stream_reserve_duplex(dice, 0); + err = snd_dice_stream_reserve_duplex(dice, 0, 0); if (err >= 0) { ++dice->substreams_counter; err = snd_dice_stream_start_duplex(dice); diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index 94a4dccfc381..570456a7751d 100644 --- a/sound/firewire/dice/dice-pcm.c +++ b/sound/firewire/dice/dice-pcm.c @@ -243,9 +243,14 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); + unsigned int events_per_period = params_period_size(hw_params);
mutex_lock(&dice->mutex); - err = snd_dice_stream_reserve_duplex(dice, rate); + // For double_pcm_frame quirk. + if (rate > 96000) + events_per_period /= 2; + err = snd_dice_stream_reserve_duplex(dice, rate, + events_per_period); if (err >= 0) ++dice->substreams_counter; mutex_unlock(&dice->mutex); diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index f6a8627ae5a2..ef36bf588d11 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -278,7 +278,8 @@ static void finish_session(struct snd_dice *dice, struct reg_params *tx_params, snd_dice_transaction_clear_enable(dice); }
-int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate) +int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate, + unsigned int events_per_period) { unsigned int curr_rate; int err; @@ -324,6 +325,11 @@ int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate) &rx_params); if (err < 0) goto error; + + err = amdtp_domain_set_events_per_period(&dice->domain, + events_per_period); + if (err < 0) + goto error; }
return 0; diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h index fa6d74303f54..1f9e3502974e 100644 --- a/sound/firewire/dice/dice.h +++ b/sound/firewire/dice/dice.h @@ -210,7 +210,8 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice); void snd_dice_stream_stop_duplex(struct snd_dice *dice); int snd_dice_stream_init_duplex(struct snd_dice *dice); void snd_dice_stream_destroy_duplex(struct snd_dice *dice); -int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate); +int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate, + unsigned int events_per_period); void snd_dice_stream_update_duplex(struct snd_dice *dice); int snd_dice_stream_detect_current_formats(struct snd_dice *dice);
This commit is a preparation to share the size of PCM period between PCM substreams on AMDTP streams in the same domain. At this time, the size of PCM period in PCM substream which starts AMDTP streams in the same domain is recorded.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/digi00x/digi00x-midi.c | 2 +- sound/firewire/digi00x/digi00x-pcm.c | 4 +++- sound/firewire/digi00x/digi00x-stream.c | 11 ++++++++++- sound/firewire/digi00x/digi00x.h | 3 ++- 4 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/sound/firewire/digi00x/digi00x-midi.c b/sound/firewire/digi00x/digi00x-midi.c index 2b57ece89101..a407e795d8e7 100644 --- a/sound/firewire/digi00x/digi00x-midi.c +++ b/sound/firewire/digi00x/digi00x-midi.c @@ -17,7 +17,7 @@ static int midi_open(struct snd_rawmidi_substream *substream) return err;
mutex_lock(&dg00x->mutex); - err = snd_dg00x_stream_reserve_duplex(dg00x, 0); + err = snd_dg00x_stream_reserve_duplex(dg00x, 0, 0); if (err >= 0) { ++dg00x->substreams_counter; err = snd_dg00x_stream_start_duplex(dg00x); diff --git a/sound/firewire/digi00x/digi00x-pcm.c b/sound/firewire/digi00x/digi00x-pcm.c index 18e561b26625..9ced309d61fa 100644 --- a/sound/firewire/digi00x/digi00x-pcm.c +++ b/sound/firewire/digi00x/digi00x-pcm.c @@ -167,9 +167,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); + unsigned int frames_per_period = params_period_size(hw_params);
mutex_lock(&dg00x->mutex); - err = snd_dg00x_stream_reserve_duplex(dg00x, rate); + err = snd_dg00x_stream_reserve_duplex(dg00x, rate, + frames_per_period); if (err >= 0) ++dg00x->substreams_counter; mutex_unlock(&dg00x->mutex); diff --git a/sound/firewire/digi00x/digi00x-stream.c b/sound/firewire/digi00x/digi00x-stream.c index d6a92460060f..96d331e47b07 100644 --- a/sound/firewire/digi00x/digi00x-stream.c +++ b/sound/firewire/digi00x/digi00x-stream.c @@ -283,7 +283,8 @@ void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x) destroy_stream(dg00x, &dg00x->tx_stream); }
-int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate) +int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate, + unsigned int frames_per_period) { unsigned int curr_rate; int err; @@ -315,6 +316,14 @@ int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate) fw_iso_resources_free(&dg00x->rx_resources); return err; } + + err = amdtp_domain_set_events_per_period(&dg00x->domain, + frames_per_period); + if (err < 0) { + fw_iso_resources_free(&dg00x->rx_resources); + fw_iso_resources_free(&dg00x->tx_resources); + return err; + } }
return 0; diff --git a/sound/firewire/digi00x/digi00x.h b/sound/firewire/digi00x/digi00x.h index 8041c65f2736..d93694282568 100644 --- a/sound/firewire/digi00x/digi00x.h +++ b/sound/firewire/digi00x/digi00x.h @@ -141,7 +141,8 @@ int snd_dg00x_stream_get_clock(struct snd_dg00x *dg00x, int snd_dg00x_stream_check_external_clock(struct snd_dg00x *dg00x, bool *detect); int snd_dg00x_stream_init_duplex(struct snd_dg00x *dg00x); -int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate); +int snd_dg00x_stream_reserve_duplex(struct snd_dg00x *dg00x, unsigned int rate, + unsigned int frames_per_period); int snd_dg00x_stream_start_duplex(struct snd_dg00x *dg00x); void snd_dg00x_stream_stop_duplex(struct snd_dg00x *dg00x); void snd_dg00x_stream_update_duplex(struct snd_dg00x *dg00x);
This commit is a preparation to share the size of PCM period between PCM substreams on AMDTP streams in the same domain. At this time, the size of PCM period in PCM substream which starts AMDTP streams in the same domain is recorded.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/tascam/tascam-pcm.c | 4 +++- sound/firewire/tascam/tascam-stream.c | 11 ++++++++++- sound/firewire/tascam/tascam.h | 3 ++- 3 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/sound/firewire/tascam/tascam-pcm.c b/sound/firewire/tascam/tascam-pcm.c index 2377732caa52..cea26d5eff1a 100644 --- a/sound/firewire/tascam/tascam-pcm.c +++ b/sound/firewire/tascam/tascam-pcm.c @@ -99,9 +99,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); + unsigned int frames_per_period = params_period_size(hw_params);
mutex_lock(&tscm->mutex); - err = snd_tscm_stream_reserve_duplex(tscm, rate); + err = snd_tscm_stream_reserve_duplex(tscm, rate, + frames_per_period); if (err >= 0) ++tscm->substreams_counter; mutex_unlock(&tscm->mutex); diff --git a/sound/firewire/tascam/tascam-stream.c b/sound/firewire/tascam/tascam-stream.c index adf69a520b80..8c04a0ad17d9 100644 --- a/sound/firewire/tascam/tascam-stream.c +++ b/sound/firewire/tascam/tascam-stream.c @@ -383,7 +383,8 @@ void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm) destroy_stream(tscm, &tscm->tx_stream); }
-int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate) +int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate, + unsigned int frames_per_period) { unsigned int curr_rate; int err; @@ -413,6 +414,14 @@ int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate) fw_iso_resources_free(&tscm->tx_resources); return err; } + + err = amdtp_domain_set_events_per_period(&tscm->domain, + frames_per_period); + if (err < 0) { + fw_iso_resources_free(&tscm->tx_resources); + fw_iso_resources_free(&tscm->rx_resources); + return err; + } }
return 0; diff --git a/sound/firewire/tascam/tascam.h b/sound/firewire/tascam/tascam.h index 15bd335fa07f..32e72a25bf46 100644 --- a/sound/firewire/tascam/tascam.h +++ b/sound/firewire/tascam/tascam.h @@ -168,7 +168,8 @@ int snd_tscm_stream_get_clock(struct snd_tscm *tscm, int snd_tscm_stream_init_duplex(struct snd_tscm *tscm); void snd_tscm_stream_update_duplex(struct snd_tscm *tscm); void snd_tscm_stream_destroy_duplex(struct snd_tscm *tscm); -int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate); +int snd_tscm_stream_reserve_duplex(struct snd_tscm *tscm, unsigned int rate, + unsigned int frames_per_period); int snd_tscm_stream_start_duplex(struct snd_tscm *tscm, unsigned int rate); void snd_tscm_stream_stop_duplex(struct snd_tscm *tscm);
This commit is a preparation to share the size of PCM period between PCM substreams on AMDTP streams in the same domain. At this time, the size of PCM period in PCM substream which starts AMDTP streams in the same domain is recorded.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/motu/motu-midi.c | 2 +- sound/firewire/motu/motu-pcm.c | 4 +++- sound/firewire/motu/motu-stream.c | 11 ++++++++++- sound/firewire/motu/motu.h | 3 ++- 4 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/sound/firewire/motu/motu-midi.c b/sound/firewire/motu/motu-midi.c index 46a0035df31e..997dd6c8ec31 100644 --- a/sound/firewire/motu/motu-midi.c +++ b/sound/firewire/motu/motu-midi.c @@ -17,7 +17,7 @@ static int midi_open(struct snd_rawmidi_substream *substream)
mutex_lock(&motu->mutex);
- err = snd_motu_stream_reserve_duplex(motu, 0); + err = snd_motu_stream_reserve_duplex(motu, 0, 0); if (err >= 0) { ++motu->substreams_counter; err = snd_motu_stream_start_duplex(motu); diff --git a/sound/firewire/motu/motu-pcm.c b/sound/firewire/motu/motu-pcm.c index aa2e584da6fe..9a54c562494b 100644 --- a/sound/firewire/motu/motu-pcm.c +++ b/sound/firewire/motu/motu-pcm.c @@ -202,9 +202,11 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); + unsigned int frames_per_period = params_period_size(hw_params);
mutex_lock(&motu->mutex); - err = snd_motu_stream_reserve_duplex(motu, rate); + err = snd_motu_stream_reserve_duplex(motu, rate, + frames_per_period); if (err >= 0) ++motu->substreams_counter; mutex_unlock(&motu->mutex); diff --git a/sound/firewire/motu/motu-stream.c b/sound/firewire/motu/motu-stream.c index 813e38e6a86e..52b7c375bb0b 100644 --- a/sound/firewire/motu/motu-stream.c +++ b/sound/firewire/motu/motu-stream.c @@ -133,7 +133,8 @@ int snd_motu_stream_cache_packet_formats(struct snd_motu *motu) return 0; }
-int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate) +int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate, + unsigned int frames_per_period) { unsigned int curr_rate; int err; @@ -171,6 +172,14 @@ int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate) fw_iso_resources_free(&motu->tx_resources); return err; } + + err = amdtp_domain_set_events_per_period(&motu->domain, + frames_per_period); + if (err < 0) { + fw_iso_resources_free(&motu->tx_resources); + fw_iso_resources_free(&motu->rx_resources); + return err; + } }
return 0; diff --git a/sound/firewire/motu/motu.h b/sound/firewire/motu/motu.h index 350ee2c16f4a..a419e6e7daed 100644 --- a/sound/firewire/motu/motu.h +++ b/sound/firewire/motu/motu.h @@ -154,7 +154,8 @@ void snd_motu_transaction_unregister(struct snd_motu *motu); int snd_motu_stream_init_duplex(struct snd_motu *motu); void snd_motu_stream_destroy_duplex(struct snd_motu *motu); int snd_motu_stream_cache_packet_formats(struct snd_motu *motu); -int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate); +int snd_motu_stream_reserve_duplex(struct snd_motu *motu, unsigned int rate, + unsigned int frames_per_period); int snd_motu_stream_start_duplex(struct snd_motu *motu); void snd_motu_stream_stop_duplex(struct snd_motu *motu); int snd_motu_stream_lock_try(struct snd_motu *motu);
This commit is a preparation to share the size of PCM period between PCM substreams on AMDTP streams in the same domain. At this time, the size of PCM period in PCM substream which starts AMDTP streams in the same domain is recorded.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/fireface/ff-pcm.c | 3 ++- sound/firewire/fireface/ff-stream.c | 11 ++++++++++- sound/firewire/fireface/ff.h | 3 ++- 3 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/sound/firewire/fireface/ff-pcm.c b/sound/firewire/fireface/ff-pcm.c index 9eab3ad283ce..4f2208202494 100644 --- a/sound/firewire/fireface/ff-pcm.c +++ b/sound/firewire/fireface/ff-pcm.c @@ -211,9 +211,10 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { unsigned int rate = params_rate(hw_params); + unsigned int frames_per_period = params_period_size(hw_params);
mutex_lock(&ff->mutex); - err = snd_ff_stream_reserve_duplex(ff, rate); + err = snd_ff_stream_reserve_duplex(ff, rate, frames_per_period); if (err >= 0) ++ff->substreams_counter; mutex_unlock(&ff->mutex); diff --git a/sound/firewire/fireface/ff-stream.c b/sound/firewire/fireface/ff-stream.c index e8e6f9fd6433..d05e7d3055e1 100644 --- a/sound/firewire/fireface/ff-stream.c +++ b/sound/firewire/fireface/ff-stream.c @@ -106,7 +106,8 @@ void snd_ff_stream_destroy_duplex(struct snd_ff *ff) destroy_stream(ff, &ff->tx_stream); }
-int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate) +int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate, + unsigned int frames_per_period) { unsigned int curr_rate; enum snd_ff_clock_src src; @@ -150,6 +151,14 @@ int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate) err = ff->spec->protocol->allocate_resources(ff, rate); if (err < 0) return err; + + err = amdtp_domain_set_events_per_period(&ff->domain, + frames_per_period); + if (err < 0) { + fw_iso_resources_free(&ff->tx_resources); + fw_iso_resources_free(&ff->rx_resources); + return err; + } }
return 0; diff --git a/sound/firewire/fireface/ff.h b/sound/firewire/fireface/ff.h index b4c22ca6079e..970d4ae571ee 100644 --- a/sound/firewire/fireface/ff.h +++ b/sound/firewire/fireface/ff.h @@ -139,7 +139,8 @@ int snd_ff_stream_get_multiplier_mode(enum cip_sfc sfc, enum snd_ff_stream_mode *mode); int snd_ff_stream_init_duplex(struct snd_ff *ff); void snd_ff_stream_destroy_duplex(struct snd_ff *ff); -int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate); +int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate, + unsigned int frames_per_period); int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate); void snd_ff_stream_stop_duplex(struct snd_ff *ff); void snd_ff_stream_update_duplex(struct snd_ff *ff);
In current implementation, when opening a PCM substream, it's needed to check whether the opposite PCM substream runs. This is to assign effectual constraints (e.g. sampling rate) to opened PCM substream.
The number of PCM substreams and MIDI substreams on AMDTP streams in domain is recorded in own structure. Usage of this count is an alternative of the above check. This is better because the count is incremented in pcm.hw_params earlier than pcm.trigger.
This idea has one issue because it's incremented for MIDI substreams as well. In current implementation, for a case that any MIDI substream run and a PCM substream is going to start, PCM application to start the PCM substream can decide hardware parameters by restart packet streaming. Just checking the substream count can brings regression.
Now AMDTP domain structure has a member for the size of PCM period in PCM substream which starts AMDTP streams in domain. When the value has zero and the substream count is greater than 1, it means that any MIDI substream starts AMDTP streams in domain. Usage of the value can resolve the above issue.
This commit replaces the check with the substream count and the value for the size of PCM period.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/bebob/bebob_pcm.c | 39 ++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 12 deletions(-)
diff --git a/sound/firewire/bebob/bebob_pcm.c b/sound/firewire/bebob/bebob_pcm.c index 3b2227abf8a9..516c9874f4a1 100644 --- a/sound/firewire/bebob/bebob_pcm.c +++ b/sound/firewire/bebob/bebob_pcm.c @@ -129,18 +129,17 @@ pcm_init_hw_params(struct snd_bebob *bebob, return err; }
-static int -pcm_open(struct snd_pcm_substream *substream) +static int pcm_open(struct snd_pcm_substream *substream) { struct snd_bebob *bebob = substream->private_data; const struct snd_bebob_rate_spec *spec = bebob->spec->rate; - unsigned int sampling_rate; + struct amdtp_domain *d = &bebob->domain; enum snd_bebob_clock_type src; int err;
err = snd_bebob_stream_lock_try(bebob); if (err < 0) - goto end; + return err;
err = pcm_init_hw_params(bebob, substream); if (err < 0) @@ -150,15 +149,19 @@ pcm_open(struct snd_pcm_substream *substream) if (err < 0) goto err_locked;
- /* - * When source of clock is internal or any PCM stream are running, - * the available sampling rate is limited at current sampling rate. - */ + mutex_lock(&bebob->mutex); + + // When source of clock is not internal or any stream is reserved for + // transmission of PCM frames, the available sampling rate is limited + // at current one. if (src == SND_BEBOB_CLOCK_TYPE_EXTERNAL || - amdtp_stream_pcm_running(&bebob->tx_stream) || - amdtp_stream_pcm_running(&bebob->rx_stream)) { + (bebob->substreams_counter > 0 && d->events_per_period > 0)) { + unsigned int frames_per_period = d->events_per_period; + unsigned int sampling_rate; + err = spec->get(bebob, &sampling_rate); if (err < 0) { + mutex_unlock(&bebob->mutex); dev_err(&bebob->unit->device, "fail to get sampling rate: %d\n", err); goto err_locked; @@ -166,11 +169,23 @@ pcm_open(struct snd_pcm_substream *substream)
substream->runtime->hw.rate_min = sampling_rate; substream->runtime->hw.rate_max = sampling_rate; + + if (frames_per_period > 0) { + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + frames_per_period, frames_per_period); + if (err < 0) { + mutex_unlock(&bebob->mutex); + goto err_locked; + } + } }
+ mutex_unlock(&bebob->mutex); + snd_pcm_set_sync(substream); -end: - return err; + + return 0; err_locked: snd_bebob_stream_lock_release(bebob); return err;
In current implementation, when opening a PCM substream, it's needed to check whether the opposite PCM substream runs. This is to assign effectual constraints (e.g. sampling rate) to opened PCM substream.
The number of PCM substreams and MIDI substreams on AMDTP streams in domain is recorded in own structure. Usage of this count is an alternative of the above check. This is better because the count is incremented in pcm.hw_params earlier than pcm.trigger.
This idea has one issue because it's incremented for MIDI substreams as well. In current implementation, for a case that any MIDI substream run and a PCM substream is going to start, PCM application to start the PCM substream can decide hardware parameters by restart packet streaming. Just checking the substream count can brings regression.
Now AMDTP domain structure has a member for the size of PCM period in PCM substream which starts AMDTP streams in domain. When the value has zero and the substream count is greater than 1, it means that any MIDI substream starts AMDTP streams in domain. Usage of the value can resolve the above issue.
This commit replaces the check with the substream count and the value for the size of PCM period.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/fireworks/fireworks_pcm.c | 39 +++++++++++++++++------- 1 file changed, 28 insertions(+), 11 deletions(-)
diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c index 35fc95283423..314d1f8b8344 100644 --- a/sound/firewire/fireworks/fireworks_pcm.c +++ b/sound/firewire/fireworks/fireworks_pcm.c @@ -173,13 +173,13 @@ pcm_init_hw_params(struct snd_efw *efw, static int pcm_open(struct snd_pcm_substream *substream) { struct snd_efw *efw = substream->private_data; - unsigned int sampling_rate; + struct amdtp_domain *d = &efw->domain; enum snd_efw_clock_source clock_source; int err;
err = snd_efw_stream_lock_try(efw); if (err < 0) - goto end; + return err;
err = pcm_init_hw_params(efw, substream); if (err < 0) @@ -189,23 +189,40 @@ static int pcm_open(struct snd_pcm_substream *substream) if (err < 0) goto err_locked;
- /* - * When source of clock is not internal or any PCM streams are running, - * available sampling rate is limited at current sampling rate. - */ + mutex_lock(&efw->mutex); + + // When source of clock is not internal or any stream is reserved for + // transmission of PCM frames, the available sampling rate is limited + // at current one. if ((clock_source != SND_EFW_CLOCK_SOURCE_INTERNAL) || - amdtp_stream_pcm_running(&efw->tx_stream) || - amdtp_stream_pcm_running(&efw->rx_stream)) { + (efw->substreams_counter > 0 && d->events_per_period > 0)) { + unsigned int frames_per_period = d->events_per_period; + unsigned int sampling_rate; + err = snd_efw_command_get_sampling_rate(efw, &sampling_rate); - if (err < 0) + if (err < 0) { + mutex_unlock(&efw->mutex); goto err_locked; + } substream->runtime->hw.rate_min = sampling_rate; substream->runtime->hw.rate_max = sampling_rate; + + if (frames_per_period > 0) { + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + frames_per_period, frames_per_period); + if (err < 0) { + mutex_unlock(&efw->mutex); + goto err_locked; + } + } }
+ mutex_unlock(&efw->mutex); + snd_pcm_set_sync(substream); -end: - return err; + + return 0; err_locked: snd_efw_stream_lock_release(efw); return err;
In current implementation, when opening a PCM substream, it's needed to check whether the opposite PCM substream runs. This is to assign effectual constraints (e.g. sampling rate) to opened PCM substream.
The number of PCM substreams and MIDI substreams on AMDTP streams in domain is recorded in own structure. Usage of this count is an alternative of the above check. This is better because the count is incremented in pcm.hw_params earlier than pcm.trigger.
This idea has one issue because it's incremented for MIDI substreams as well. In current implementation, for a case that any MIDI substream run and a PCM substream is going to start, PCM application to start the PCM substream can decide hardware parameters by restart packet streaming. Just checking the substream count can brings regression.
Now AMDTP domain structure has a member for the size of PCM period in PCM substream which starts AMDTP streams in domain. When the value has zero and the substream count is greater than 1, it means that any MIDI substream starts AMDTP streams in domain. Usage of the value can resolve the above issue.
This commit replaces the check with the substream count and the value for the size of PCM period.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/oxfw/oxfw-pcm.c | 39 ++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 11 deletions(-)
diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c index 2d1b5038f7f6..f3e25898d270 100644 --- a/sound/firewire/oxfw/oxfw-pcm.c +++ b/sound/firewire/oxfw/oxfw-pcm.c @@ -170,30 +170,47 @@ static int limit_to_current_params(struct snd_pcm_substream *substream) static int pcm_open(struct snd_pcm_substream *substream) { struct snd_oxfw *oxfw = substream->private_data; + struct amdtp_domain *d = &oxfw->domain; int err;
err = snd_oxfw_stream_lock_try(oxfw); if (err < 0) - goto end; + return err;
err = init_hw_params(oxfw, substream); if (err < 0) goto err_locked;
- /* - * When any PCM streams are already running, the available sampling - * rate is limited at current value. - */ - if (amdtp_stream_pcm_running(&oxfw->tx_stream) || - amdtp_stream_pcm_running(&oxfw->rx_stream)) { + mutex_lock(&oxfw->mutex); + + // When source of clock is not internal or any stream is reserved for + // transmission of PCM frames, the available sampling rate is limited + // at current one. + if (oxfw->substreams_count > 0 && d->events_per_period > 0) { + unsigned int frames_per_period = d->events_per_period; + err = limit_to_current_params(substream); - if (err < 0) - goto end; + if (err < 0) { + mutex_unlock(&oxfw->mutex); + goto err_locked; + } + + if (frames_per_period > 0) { + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + frames_per_period, frames_per_period); + if (err < 0) { + mutex_unlock(&oxfw->mutex); + goto err_locked; + } + } }
+ mutex_unlock(&oxfw->mutex); + snd_pcm_set_sync(substream); -end: - return err; + + return 0; err_locked: snd_oxfw_stream_lock_release(oxfw); return err;
In current implementation, when opening a PCM substream, it's needed to check whether the opposite PCM substream runs. This is to assign effectual constraints (e.g. sampling rate) to opened PCM substream.
The number of PCM substreams and MIDI substreams on AMDTP streams in domain is recorded in own structure. Usage of this count is an alternative of the above check. This is better because the count is incremented in pcm.hw_params earlier than pcm.trigger.
This idea has one issue because it's incremented for MIDI substreams as well. In current implementation, for a case that any MIDI substream run and a PCM substream is going to start, PCM application to start the PCM substream can decide hardware parameters by restart packet streaming. Just checking the substream count can brings regression.
Now AMDTP domain structure has a member for the size of PCM period in PCM substream which starts AMDTP streams in domain. When the value has zero and the substream count is greater than 1, it means that any MIDI substream starts AMDTP streams in domain. Usage of the value can resolve the above issue.
This commit replaces the check with the substream count and the value for the size of PCM period.
Dice hardware has a quirk called as 'Dual Wire'. For a case of higher sampling transmission frequency, this commit performs calculations between the number of PCM frames and the number of events in AMDTP stream.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/dice/dice-pcm.c | 43 ++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 12 deletions(-)
diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index 570456a7751d..813c9ffbeced 100644 --- a/sound/firewire/dice/dice-pcm.c +++ b/sound/firewire/dice/dice-pcm.c @@ -164,13 +164,14 @@ static int init_hw_info(struct snd_dice *dice, static int pcm_open(struct snd_pcm_substream *substream) { struct snd_dice *dice = substream->private_data; + struct amdtp_domain *d = &dice->domain; unsigned int source; bool internal; int err;
err = snd_dice_stream_lock_try(dice); if (err < 0) - goto end; + return err;
err = init_hw_info(dice, substream); if (err < 0) @@ -195,27 +196,45 @@ static int pcm_open(struct snd_pcm_substream *substream) break; }
- /* - * When source of clock is not internal or any PCM streams are running, - * available sampling rate is limited at current sampling rate. - */ + mutex_lock(&dice->mutex); + + // When source of clock is not internal or any stream is reserved for + // transmission of PCM frames, the available sampling rate is limited + // at current one. if (!internal || - amdtp_stream_pcm_running(&dice->tx_stream[0]) || - amdtp_stream_pcm_running(&dice->tx_stream[1]) || - amdtp_stream_pcm_running(&dice->rx_stream[0]) || - amdtp_stream_pcm_running(&dice->rx_stream[1])) { + (dice->substreams_counter > 0 && d->events_per_period > 0)) { + unsigned int frames_per_period = d->events_per_period; unsigned int rate;
err = snd_dice_transaction_get_rate(dice, &rate); - if (err < 0) + if (err < 0) { + mutex_unlock(&dice->mutex); goto err_locked; + } + substream->runtime->hw.rate_min = rate; substream->runtime->hw.rate_max = rate; + + if (frames_per_period > 0) { + // For double_pcm_frame quirk. + if (rate > 96000) + frames_per_period *= 2; + + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + frames_per_period, frames_per_period); + if (err < 0) { + mutex_unlock(&dice->mutex); + goto err_locked; + } + } }
+ mutex_unlock(&dice->mutex); + snd_pcm_set_sync(substream); -end: - return err; + + return 0; err_locked: snd_dice_stream_lock_release(dice); return err;
In current implementation, when opening a PCM substream, it's needed to check whether the opposite PCM substream runs. This is to assign effectual constraints (e.g. sampling rate) to opened PCM substream.
The number of PCM substreams and MIDI substreams on AMDTP streams in domain is recorded in own structure. Usage of this count is an alternative of the above check. This is better because the count is incremented in pcm.hw_params earlier than pcm.trigger.
This idea has one issue because it's incremented for MIDI substreams as well. In current implementation, for a case that any MIDI substream run and a PCM substream is going to start, PCM application to start the PCM substream can decide hardware parameters by restart packet streaming. Just checking the substream count can brings regression.
Now AMDTP domain structure has a member for the size of PCM period in PCM substream which starts AMDTP streams in domain. When the value has zero and the substream count is greater than 1, it means that any MIDI substream starts AMDTP streams in domain. Usage of the value can resolve the above issue.
This commit replaces the check with the substream count and the value for the size of PCM period.
I note that DOT AMDTP protocol has a quirk to use different transmission method of IEC 61883-6 for tx/rx streams; non-blocking in tx stream and blocking in rx stream. Although the difference of transmission method between tx/rx streams precisely brings different timing for a certain amount of events due to their different calculation for data blocks per packet, it's possible to approximate enough amount of events mostly has the same timing. Actually current ALSA IEC 61883-1/6 engine uses large amount of data blocks for each hardware IRQ (=16 packets).
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/digi00x/digi00x-pcm.c | 35 ++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 7 deletions(-)
diff --git a/sound/firewire/digi00x/digi00x-pcm.c b/sound/firewire/digi00x/digi00x-pcm.c index 9ced309d61fa..8dbfb3ff17f6 100644 --- a/sound/firewire/digi00x/digi00x-pcm.c +++ b/sound/firewire/digi00x/digi00x-pcm.c @@ -100,14 +100,14 @@ static int pcm_init_hw_params(struct snd_dg00x *dg00x, static int pcm_open(struct snd_pcm_substream *substream) { struct snd_dg00x *dg00x = substream->private_data; + struct amdtp_domain *d = &dg00x->domain; enum snd_dg00x_clock clock; bool detect; - unsigned int rate; int err;
err = snd_dg00x_stream_lock_try(dg00x); if (err < 0) - goto end; + return err;
err = pcm_init_hw_params(dg00x, substream); if (err < 0) @@ -127,19 +127,40 @@ static int pcm_open(struct snd_pcm_substream *substream) } }
+ mutex_lock(&dg00x->mutex); + + // When source of clock is not internal or any stream is reserved for + // transmission of PCM frames, the available sampling rate is limited + // at current one. if ((clock != SND_DG00X_CLOCK_INTERNAL) || - amdtp_stream_pcm_running(&dg00x->rx_stream) || - amdtp_stream_pcm_running(&dg00x->tx_stream)) { + (dg00x->substreams_counter > 0 && d->events_per_period > 0)) { + unsigned int frames_per_period = d->events_per_period; + unsigned int rate; + err = snd_dg00x_stream_get_external_rate(dg00x, &rate); - if (err < 0) + if (err < 0) { + mutex_unlock(&dg00x->mutex); goto err_locked; + } substream->runtime->hw.rate_min = rate; substream->runtime->hw.rate_max = rate; + + if (frames_per_period > 0) { + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + frames_per_period, frames_per_period); + if (err < 0) { + mutex_unlock(&dg00x->mutex); + goto err_locked; + } + } }
+ mutex_unlock(&dg00x->mutex); + snd_pcm_set_sync(substream); -end: - return err; + + return 0; err_locked: snd_dg00x_stream_lock_release(dg00x); return err;
In current implementation, when opening a PCM substream, it's needed to check whether the opposite PCM substream runs. This is to assign effectual constraints (e.g. sampling rate) to opened PCM substream.
The number of PCM substreams on AMDTP streams in domain is recorded in own structure. Usage of this count is an alternative of the above check. This is better because the count is incremented in pcm.hw_params earlier than pcm.trigger.
This commit replaces the check with the substream count and the value for the size of PCM period. Unlike the other drivers in ALSA firewire stack, no MIDI substream is multiplexed into AMDTP stream.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/tascam/tascam-pcm.c | 34 +++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 8 deletions(-)
diff --git a/sound/firewire/tascam/tascam-pcm.c b/sound/firewire/tascam/tascam-pcm.c index cea26d5eff1a..6cd3a420fbdf 100644 --- a/sound/firewire/tascam/tascam-pcm.c +++ b/sound/firewire/tascam/tascam-pcm.c @@ -43,13 +43,13 @@ static int pcm_init_hw_params(struct snd_tscm *tscm, static int pcm_open(struct snd_pcm_substream *substream) { struct snd_tscm *tscm = substream->private_data; + struct amdtp_domain *d = &tscm->domain; enum snd_tscm_clock clock; - unsigned int rate; int err;
err = snd_tscm_stream_lock_try(tscm); if (err < 0) - goto end; + return err;
err = pcm_init_hw_params(tscm, substream); if (err < 0) @@ -59,19 +59,37 @@ static int pcm_open(struct snd_pcm_substream *substream) if (err < 0) goto err_locked;
- if (clock != SND_TSCM_CLOCK_INTERNAL || - amdtp_stream_pcm_running(&tscm->rx_stream) || - amdtp_stream_pcm_running(&tscm->tx_stream)) { + mutex_lock(&tscm->mutex); + + // When source of clock is not internal or any stream is reserved for + // transmission of PCM frames, the available sampling rate is limited + // at current one. + if (clock != SND_TSCM_CLOCK_INTERNAL || tscm->substreams_counter > 0) { + unsigned int frames_per_period = d->events_per_period; + unsigned int rate; + err = snd_tscm_stream_get_rate(tscm, &rate); - if (err < 0) + if (err < 0) { + mutex_unlock(&tscm->mutex); goto err_locked; + } substream->runtime->hw.rate_min = rate; substream->runtime->hw.rate_max = rate; + + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + frames_per_period, frames_per_period); + if (err < 0) { + mutex_unlock(&tscm->mutex); + goto err_locked; + } }
+ mutex_unlock(&tscm->mutex); + snd_pcm_set_sync(substream); -end: - return err; + + return 0; err_locked: snd_tscm_stream_lock_release(tscm); return err;
In current implementation, when opening a PCM substream, it's needed to check whether the opposite PCM substream runs. This is to assign effectual constraints (e.g. sampling rate) to opened PCM substream.
The number of PCM substreams and MIDI substreams on AMDTP streams in domain is recorded in own structure. Usage of this count is an alternative of the above check. This is better because the count is incremented in pcm.hw_params earlier than pcm.trigger.
This idea has one issue because it's incremented for MIDI substreams as well. In current implementation, for a case that any MIDI substream run and a PCM substream is going to start, PCM application to start the PCM substream can decide hardware parameters by restart packet streaming. Just checking the substream count can brings regression.
Now AMDTP domain structure has a member for the size of PCM period in PCM substream which starts AMDTP streams in domain. When the value has zero and the substream count is greater than 1, it means that any MIDI substream starts AMDTP streams in domain. Usage of the value can resolve the above issue.
This commit replaces the check with the substream count and the value for the size of PCM period.
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/motu/motu-pcm.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-)
diff --git a/sound/firewire/motu/motu-pcm.c b/sound/firewire/motu/motu-pcm.c index 9a54c562494b..7bbf8b86a33d 100644 --- a/sound/firewire/motu/motu-pcm.c +++ b/sound/firewire/motu/motu-pcm.c @@ -134,8 +134,8 @@ static int pcm_open(struct snd_pcm_substream *substream) { struct snd_motu *motu = substream->private_data; const struct snd_motu_protocol *const protocol = motu->spec->protocol; + struct amdtp_domain *d = &motu->domain; enum snd_motu_clock_source src; - unsigned int rate; int err;
err = snd_motu_stream_lock_try(motu); @@ -152,28 +152,41 @@ static int pcm_open(struct snd_pcm_substream *substream) if (err < 0) goto err_locked;
- /* - * When source of clock is not internal or any PCM streams are running, - * available sampling rate is limited at current sampling rate. - */ err = protocol->get_clock_source(motu, &src); if (err < 0) goto err_locked; + + // When source of clock is not internal or any stream is reserved for + // transmission of PCM frames, the available sampling rate is limited + // at current one. if (src != SND_MOTU_CLOCK_SOURCE_INTERNAL || - amdtp_stream_pcm_running(&motu->tx_stream) || - amdtp_stream_pcm_running(&motu->rx_stream)) { + (motu->substreams_counter > 0 && d->events_per_period > 0)) { + unsigned int frames_per_period = d->events_per_period; + unsigned int rate; + err = protocol->get_clock_rate(motu, &rate); if (err < 0) goto err_locked; + substream->runtime->hw.rate_min = rate; substream->runtime->hw.rate_max = rate; + + if (frames_per_period > 0) { + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + frames_per_period, frames_per_period); + if (err < 0) { + mutex_unlock(&motu->mutex); + goto err_locked; + } + } }
snd_pcm_set_sync(substream);
mutex_unlock(&motu->mutex);
- return err; + return 0; err_locked: mutex_unlock(&motu->mutex); snd_motu_stream_lock_release(motu);
In current implementation, when opening a PCM substream, it's needed to check whether the opposite PCM substream runs. This is to assign effectual constraints (e.g. sampling rate) to opened PCM substream.
The number of PCM substreams on AMDTP streams in domain is recorded in own structure. Usage of this count is an alternative of the above check. This is better because the count is incremented in pcm.hw_params earlier than pcm.trigger.
This commit replaces the check with the substream count and the value for the size of PCM period. Unlike the other drivers in ALSA firewire stack, no MIDI substream is multiplexed into AMDTP stream.
I note that Fireface AMDTP protocol has a quirk that tx stream includes blank isochronous cycle. The packet for blank cycle is equivalent to empty or NODATA packet in IEC 61883-6, thus the protocol is similar to blocking transmission method of IEC 61883-6. On the other hand, rx stream adopts non-blocking transmission method. Although the difference of transmission method between tx/rx streams precisely brings different timing for a certain amount of events due to their different calculation for data blocks per packet, it's possible to approximate enough amount of events mostly has the same timing. Actually current ALSA IEC 61883-1/6 engine uses large amount of data blocks for each hardware IRQ (=16 packets).
Signed-off-by: Takashi Sakamoto o-takashi@sakamocchi.jp --- sound/firewire/fireface/ff-pcm.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-)
diff --git a/sound/firewire/fireface/ff-pcm.c b/sound/firewire/fireface/ff-pcm.c index 4f2208202494..415bc9ccd1c7 100644 --- a/sound/firewire/fireface/ff-pcm.c +++ b/sound/firewire/fireface/ff-pcm.c @@ -139,6 +139,7 @@ static int pcm_init_hw_params(struct snd_ff *ff, static int pcm_open(struct snd_pcm_substream *substream) { struct snd_ff *ff = substream->private_data; + struct amdtp_domain *d = &ff->domain; unsigned int rate; enum snd_ff_clock_src src; int i, err; @@ -155,16 +156,21 @@ static int pcm_open(struct snd_pcm_substream *substream) if (err < 0) goto release_lock;
+ mutex_lock(&ff->mutex); + + // When source of clock is not internal or any stream is reserved for + // transmission of PCM frames, the available sampling rate is limited + // at current one. if (src != SND_FF_CLOCK_SRC_INTERNAL) { for (i = 0; i < CIP_SFC_COUNT; ++i) { if (amdtp_rate_table[i] == rate) break; } - /* - * The unit is configured at sampling frequency which packet - * streaming engine can't support. - */ + + // The unit is configured at sampling frequency which packet + // streaming engine can't support. if (i >= CIP_SFC_COUNT) { + mutex_unlock(&ff->mutex); err = -EIO; goto release_lock; } @@ -172,14 +178,25 @@ static int pcm_open(struct snd_pcm_substream *substream) substream->runtime->hw.rate_min = rate; substream->runtime->hw.rate_max = rate; } else { - if (amdtp_stream_pcm_running(&ff->rx_stream) || - amdtp_stream_pcm_running(&ff->tx_stream)) { + if (ff->substreams_counter > 0) { + unsigned int frames_per_period = d->events_per_period; + rate = amdtp_rate_table[ff->rx_stream.sfc]; substream->runtime->hw.rate_min = rate; substream->runtime->hw.rate_max = rate; + + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_SIZE, + frames_per_period, frames_per_period); + if (err < 0) { + mutex_unlock(&ff->mutex); + goto release_lock; + } } }
+ mutex_unlock(&ff->mutex); + snd_pcm_set_sync(substream);
return 0;
On Mon, 07 Oct 2019 13:05:15 +0200, Takashi Sakamoto wrote:
Hi,
This patchset is a preparation for enhancement of AMDTP domain that I addressed to my previous patchset: https://mailman.alsa-project.org/pipermail/alsa-devel/2019-July/152430.html
When queued packets for several IT/IR contexts in the same domain are handled in hardware IRQ context for an IT context, the number of events in the packets are mostly the same for each of contexts. This means that the size of period for PCM substreams associated to the contexts is also the same.
At present, PCM substreams for the contexts can have own size of period. This commit adds a member into AMDTP domain to share the size of period for PCM substreams on AMDTP streams in the same domain.
This patchset includes optimization to detect whether isochronous resources for AMDTP streams are reserved or not in pcm.open callback.
Takashi Sakamoto (17): firewire-lib: add a member into AMDTP domain for events per period bebob: register the size of PCM period to AMDTP domain fireworks: register the size of PCM period to AMDTP domain oxfw: register the size of PCM period to AMDTP domain dice: register the size of PCM period to AMDTP domain firewire-digi00x: register the size of PCM period to AMDTP domain firewire-tascam: register the size of PCM period to AMDTP domain firewire-motu: register the size of PCM period to AMDTP domain fireface: register the size of PCM period to AMDTP domain bebob: use the same size of period for PCM substream in AMDTP streams fireworks: use the same size of period for PCM substream in AMDTP streams oxfw: use the same size of period for PCM substream in AMDTP streams dice: use the same size of period for PCM substream in AMDTP streams firewire-digi00x: use the same size of period for PCM substream in AMDTP streams firewire-tascam: use the same size of period for PCM substream in AMDTP streams firewire-motu: use the same size of period for PCM substream in AMDTP streams fireface: use the same size of period for PCM substreams in AMDTP streams
Applied all 17 patches now (with the correction of subject prefix).
thanks,
Takashi
participants (2)
-
Takashi Iwai
-
Takashi Sakamoto