All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] ALSA: dice: enable to handle several streams
@ 2016-03-07 13:35 Takashi Sakamoto
  2016-03-07 13:35 ` [PATCH 1/4] ALSA: dice: have two sets of isochronous resources/streams Takashi Sakamoto
                   ` (4 more replies)
  0 siblings, 5 replies; 9+ messages in thread
From: Takashi Sakamoto @ 2016-03-07 13:35 UTC (permalink / raw)
  To: clemens, tiwai; +Cc: alsa-devel, stefanr, ffado-devel

Hi,

This patchset updates my previous RFT, and goes for merging.
[alsa-devel] [RFT][PATCH 0/4] ALSA: dice: enabled to handle several streams
http://mailman.alsa-project.org/pipermail/alsa-devel/2016-March/105387.html

For the previous one, Stefan Richter worked as a tester with his devices
(Focusrite Saffire Pro 24 and 40), while current patchset includes changes
related to userspace interface. Therefore, I don't add Tested-by.


In previous one, ALSA dice driver uses subdevice for userspace to access
any PCM substreams. On the other hand, the design of PCM subdevice leaves
a bit cumbersome for userspace to handle several subdevices simultaneously
in one process. These PCM substreams on a batch of AMDTP streams and it's
better for ALSA dice driver to enable one process to handle them with
simpler way.

Based on this concept, this patchset adds PCM character devices, instead of
PCM subdevice. Thus, userspace applications can utilize PCM substreams via
individual PCM character devices. In configuration space of alsa-lib, via
'hw:0,0' and 'hw:0,1' if available, like:

$ arecord -l
...
card 1: Pro26000f5a [Pro26-000f5a], device 0: DICE [Pro26-000f5a]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 1: Pro26000f5a [Pro26-000f5a], device 1: DICE [Pro26-000f5a]
  Subdevices: 1/1
  Subdevice #0: subdevice #0


For the other parts, there's no code changes. Therefore, Stefan's result
still has meanings.

Changes:
 * Add additional PCM character device instead of PCM subdevice
 * Correct string entries to force-pcm
 * Improve comments

Takashi Sakamoto (4):
  ALSA: dice: have two sets of isochronous resources/streams
  ALSA: dice: handle whole available isochronous streams
  ALSA: dice: handle several PCM substreams when any isochronous streams
    are available
  ALSA: dice: force to add two pcm devices for listed models

 sound/firewire/dice/dice-midi.c   |   8 +-
 sound/firewire/dice/dice-pcm.c    | 147 +++++++++-----
 sound/firewire/dice/dice-stream.c | 398 ++++++++++++++++++++++++--------------
 sound/firewire/dice/dice.c        |  41 ++++
 sound/firewire/dice/dice.h        |  33 +++-
 5 files changed, 424 insertions(+), 203 deletions(-)

-- 
2.7.0

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/4] ALSA: dice: have two sets of isochronous resources/streams
  2016-03-07 13:35 [PATCH 0/4] ALSA: dice: enable to handle several streams Takashi Sakamoto
@ 2016-03-07 13:35 ` Takashi Sakamoto
  2016-03-07 13:35 ` [PATCH 2/4] ALSA: dice: handle whole available isochronous streams Takashi Sakamoto
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Takashi Sakamoto @ 2016-03-07 13:35 UTC (permalink / raw)
  To: clemens, tiwai; +Cc: alsa-devel, stefanr, ffado-devel

Currently ALSA dice driver handles a pair of isochronous resources for
IEC 61883-1/6 packet streaming. While, according to some documents about
ASICs named as 'Dice', several isochronous streams are available.

Here, I start to describe ASICs produced under 'Dice' name.
 * Dice II (designed by wavefront semiconductor, including TCAT's IP)
   * STD (with limited functionality of DTCP)
   * CP  (with full functionality of DTCP)
 * TCD2210/2210-E (so-called 'Dice Mini')
 * TCD2220/2220-E (so-called 'Dice Jr.')
 * TCD3070-CH (so-called 'Dice III')

Some documents are public and we can see hardware design of them. We can
find some articles about hardware internal register definitions
(not registers exported to IEEE 1394 bus).

* DICE II User Guide
  * http://www.tctechnologies.tc/archive/downloads/dice_ii_user_guide.pdf
    * 6.1 AVS Audio Receivers
      * Table 6.1: AVS Audio Receiver Memory Map
        * ARX1-ARX4
    * 6.2 AVS Audio Transmitters
      * Table 6.2: AVS Audio Transmitter Memory Map
        * ATX1, ATX2
* TCD22xx User Guide
  * http://www.tctechnologies.tc/downloads/tcd22xx_user_guide.pdf
    * 6.1 AVS Audio Receivers
      * Table 66: AVS Audio Receiver Memory Map
        * ARX1, ARX2
    * 6/2 AVS Audio Transmitters
      * Table 67: AVS Audio Transmitter Memory Map
        * ATX1, ATX2
* DICE III
  * http://www.tctechnologies.tc/downloads/TCD3070-CH.pdf
    * Dual stream 63 channel transmitter/receiver

For Dice II and TCD22xx series, maximum 16 data channels are transferred in
an AMDTP packet, while for Dice III, maximum 32 data channels are
transferred.

According to the design of the series of these ASICs, this commit allows
this driver to handle additional set of isochronous resources. For
practical reason, two pair of isochronous resources are added. As of this
commit, this driver still use a pair of the first isochronous resources.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 sound/firewire/dice/dice-midi.c   |  8 +++---
 sound/firewire/dice/dice-pcm.c    | 34 ++++++++++++++----------
 sound/firewire/dice/dice-stream.c | 54 +++++++++++++++++++--------------------
 sound/firewire/dice/dice.h        | 31 +++++++++++++++++++---
 4 files changed, 79 insertions(+), 48 deletions(-)

diff --git a/sound/firewire/dice/dice-midi.c b/sound/firewire/dice/dice-midi.c
index 2461311..a040617 100644
--- a/sound/firewire/dice/dice-midi.c
+++ b/sound/firewire/dice/dice-midi.c
@@ -52,10 +52,10 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
 	spin_lock_irqsave(&dice->lock, flags);
 
 	if (up)
-		amdtp_am824_midi_trigger(&dice->tx_stream,
+		amdtp_am824_midi_trigger(&dice->tx_stream[0],
 					  substrm->number, substrm);
 	else
-		amdtp_am824_midi_trigger(&dice->tx_stream,
+		amdtp_am824_midi_trigger(&dice->tx_stream[0],
 					  substrm->number, NULL);
 
 	spin_unlock_irqrestore(&dice->lock, flags);
@@ -69,10 +69,10 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
 	spin_lock_irqsave(&dice->lock, flags);
 
 	if (up)
-		amdtp_am824_midi_trigger(&dice->rx_stream,
+		amdtp_am824_midi_trigger(&dice->rx_stream[0],
 					 substrm->number, substrm);
 	else
-		amdtp_am824_midi_trigger(&dice->rx_stream,
+		amdtp_am824_midi_trigger(&dice->rx_stream[0],
 					 substrm->number, NULL);
 
 	spin_unlock_irqrestore(&dice->lock, flags);
diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c
index a5c9b58..e252949 100644
--- a/sound/firewire/dice/dice-pcm.c
+++ b/sound/firewire/dice/dice-pcm.c
@@ -22,7 +22,7 @@ static int limit_channels_and_rates(struct snd_dice *dice,
 	 * Retrieve current Multi Bit Linear Audio data channel and limit to
 	 * it.
 	 */
-	if (stream == &dice->tx_stream) {
+	if (stream == &dice->tx_stream[0]) {
 		err = snd_dice_transaction_read_tx(dice, TX_NUMBER_AUDIO,
 						   reg, sizeof(reg));
 	} else {
@@ -74,10 +74,10 @@ static int init_hw_info(struct snd_dice *dice,
 
 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
 		hw->formats = AM824_IN_PCM_FORMAT_BITS;
-		stream = &dice->tx_stream;
+		stream = &dice->tx_stream[0];
 	} else {
 		hw->formats = AM824_OUT_PCM_FORMAT_BITS;
-		stream = &dice->rx_stream;
+		stream = &dice->rx_stream[0];
 	}
 
 	err = limit_channels_and_rates(dice, runtime, stream);
@@ -122,6 +122,7 @@ static int capture_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *hw_params)
 {
 	struct snd_dice *dice = substream->private_data;
+	struct amdtp_stream *stream = &dice->tx_stream[0];
 	int err;
 
 	err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
@@ -135,7 +136,7 @@ static int capture_hw_params(struct snd_pcm_substream *substream,
 		mutex_unlock(&dice->mutex);
 	}
 
-	amdtp_am824_set_pcm_format(&dice->tx_stream, params_format(hw_params));
+	amdtp_am824_set_pcm_format(stream, params_format(hw_params));
 
 	return 0;
 }
@@ -143,6 +144,7 @@ static int playback_hw_params(struct snd_pcm_substream *substream,
 			      struct snd_pcm_hw_params *hw_params)
 {
 	struct snd_dice *dice = substream->private_data;
+	struct amdtp_stream *stream = &dice->rx_stream[0];
 	int err;
 
 	err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
@@ -156,7 +158,7 @@ static int playback_hw_params(struct snd_pcm_substream *substream,
 		mutex_unlock(&dice->mutex);
 	}
 
-	amdtp_am824_set_pcm_format(&dice->rx_stream, params_format(hw_params));
+	amdtp_am824_set_pcm_format(stream, params_format(hw_params));
 
 	return 0;
 }
@@ -196,26 +198,28 @@ static int playback_hw_free(struct snd_pcm_substream *substream)
 static int capture_prepare(struct snd_pcm_substream *substream)
 {
 	struct snd_dice *dice = substream->private_data;
+	struct amdtp_stream *stream = &dice->tx_stream[0];
 	int err;
 
 	mutex_lock(&dice->mutex);
 	err = snd_dice_stream_start_duplex(dice, substream->runtime->rate);
 	mutex_unlock(&dice->mutex);
 	if (err >= 0)
-		amdtp_stream_pcm_prepare(&dice->tx_stream);
+		amdtp_stream_pcm_prepare(stream);
 
 	return 0;
 }
 static int playback_prepare(struct snd_pcm_substream *substream)
 {
 	struct snd_dice *dice = substream->private_data;
+	struct amdtp_stream *stream = &dice->rx_stream[0];
 	int err;
 
 	mutex_lock(&dice->mutex);
 	err = snd_dice_stream_start_duplex(dice, substream->runtime->rate);
 	mutex_unlock(&dice->mutex);
 	if (err >= 0)
-		amdtp_stream_pcm_prepare(&dice->rx_stream);
+		amdtp_stream_pcm_prepare(stream);
 
 	return err;
 }
@@ -223,13 +227,14 @@ static int playback_prepare(struct snd_pcm_substream *substream)
 static int capture_trigger(struct snd_pcm_substream *substream, int cmd)
 {
 	struct snd_dice *dice = substream->private_data;
+	struct amdtp_stream *stream = &dice->tx_stream[0];
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
-		amdtp_stream_pcm_trigger(&dice->tx_stream, substream);
+		amdtp_stream_pcm_trigger(stream, substream);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
-		amdtp_stream_pcm_trigger(&dice->tx_stream, NULL);
+		amdtp_stream_pcm_trigger(stream, NULL);
 		break;
 	default:
 		return -EINVAL;
@@ -240,13 +245,14 @@ static int capture_trigger(struct snd_pcm_substream *substream, int cmd)
 static int playback_trigger(struct snd_pcm_substream *substream, int cmd)
 {
 	struct snd_dice *dice = substream->private_data;
+	struct amdtp_stream *stream = &dice->rx_stream[0];
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
-		amdtp_stream_pcm_trigger(&dice->rx_stream, substream);
+		amdtp_stream_pcm_trigger(stream, substream);
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
-		amdtp_stream_pcm_trigger(&dice->rx_stream, NULL);
+		amdtp_stream_pcm_trigger(stream, NULL);
 		break;
 	default:
 		return -EINVAL;
@@ -258,14 +264,16 @@ static int playback_trigger(struct snd_pcm_substream *substream, int cmd)
 static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream)
 {
 	struct snd_dice *dice = substream->private_data;
+	struct amdtp_stream *stream = &dice->tx_stream[0];
 
-	return amdtp_stream_pcm_pointer(&dice->tx_stream);
+	return amdtp_stream_pcm_pointer(stream);
 }
 static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream)
 {
 	struct snd_dice *dice = substream->private_data;
+	struct amdtp_stream *stream = &dice->rx_stream[0];
 
-	return amdtp_stream_pcm_pointer(&dice->rx_stream);
+	return amdtp_stream_pcm_pointer(stream);
 }
 
 int snd_dice_create_pcm(struct snd_dice *dice)
diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c
index df035b1..15d581d 100644
--- a/sound/firewire/dice/dice-stream.c
+++ b/sound/firewire/dice/dice-stream.c
@@ -72,7 +72,7 @@ static void release_resources(struct snd_dice *dice,
 
 	/* Reset channel number */
 	channel = cpu_to_be32((u32)-1);
-	if (resources == &dice->tx_resources)
+	if (resources == &dice->tx_resources[0])
 		snd_dice_transaction_write_tx(dice, TX_ISOCHRONOUS,
 					      &channel, sizeof(channel));
 	else
@@ -96,7 +96,7 @@ static int keep_resources(struct snd_dice *dice,
 
 	/* Set channel number */
 	channel = cpu_to_be32(resources->channel);
-	if (resources == &dice->tx_resources)
+	if (resources == &dice->tx_resources[0])
 		err = snd_dice_transaction_write_tx(dice, TX_ISOCHRONOUS,
 						    &channel, sizeof(channel));
 	else
@@ -113,10 +113,10 @@ static void stop_stream(struct snd_dice *dice, struct amdtp_stream *stream)
 	amdtp_stream_pcm_abort(stream);
 	amdtp_stream_stop(stream);
 
-	if (stream == &dice->tx_stream)
-		release_resources(dice, &dice->tx_resources);
+	if (stream == &dice->tx_stream[0])
+		release_resources(dice, &dice->tx_resources[0]);
 	else
-		release_resources(dice, &dice->rx_resources);
+		release_resources(dice, &dice->rx_resources[0]);
 }
 
 static int start_stream(struct snd_dice *dice, struct amdtp_stream *stream,
@@ -128,12 +128,12 @@ static int start_stream(struct snd_dice *dice, struct amdtp_stream *stream,
 	bool double_pcm_frames;
 	int err;
 
-	if (stream == &dice->tx_stream) {
-		resources = &dice->tx_resources;
+	if (stream == &dice->tx_stream[0]) {
+		resources = &dice->tx_resources[0];
 		err = snd_dice_transaction_read_tx(dice, TX_NUMBER_AUDIO,
 						   reg, sizeof(reg));
 	} else {
-		resources = &dice->rx_resources;
+		resources = &dice->rx_resources[0];
 		err = snd_dice_transaction_read_rx(dice, RX_NUMBER_AUDIO,
 						   reg, sizeof(reg));
 	}
@@ -200,8 +200,8 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate)
 	if (dice->substreams_counter == 0)
 		goto end;
 
-	master = &dice->rx_stream;
-	slave  = &dice->tx_stream;
+	master = &dice->rx_stream[0];
+	slave  = &dice->tx_stream[0];
 
 	/* Some packet queueing errors. */
 	if (amdtp_streaming_error(master) || amdtp_streaming_error(slave))
@@ -275,8 +275,8 @@ void snd_dice_stream_stop_duplex(struct snd_dice *dice)
 
 	snd_dice_transaction_clear_enable(dice);
 
-	stop_stream(dice, &dice->tx_stream);
-	stop_stream(dice, &dice->rx_stream);
+	stop_stream(dice, &dice->tx_stream[0]);
+	stop_stream(dice, &dice->rx_stream[0]);
 }
 
 static int init_stream(struct snd_dice *dice, struct amdtp_stream *stream)
@@ -285,11 +285,11 @@ static int init_stream(struct snd_dice *dice, struct amdtp_stream *stream)
 	struct fw_iso_resources *resources;
 	enum amdtp_stream_direction dir;
 
-	if (stream == &dice->tx_stream) {
-		resources = &dice->tx_resources;
+	if (stream == &dice->tx_stream[0]) {
+		resources = &dice->tx_resources[0];
 		dir = AMDTP_IN_STREAM;
 	} else {
-		resources = &dice->rx_resources;
+		resources = &dice->rx_resources[0];
 		dir = AMDTP_OUT_STREAM;
 	}
 
@@ -315,10 +315,10 @@ static void destroy_stream(struct snd_dice *dice, struct amdtp_stream *stream)
 {
 	struct fw_iso_resources *resources;
 
-	if (stream == &dice->tx_stream)
-		resources = &dice->tx_resources;
+	if (stream == &dice->tx_stream[0])
+		resources = &dice->tx_resources[0];
 	else
-		resources = &dice->rx_resources;
+		resources = &dice->rx_resources[0];
 
 	amdtp_stream_destroy(stream);
 	fw_iso_resources_destroy(resources);
@@ -330,13 +330,13 @@ int snd_dice_stream_init_duplex(struct snd_dice *dice)
 
 	dice->substreams_counter = 0;
 
-	err = init_stream(dice, &dice->tx_stream);
+	err = init_stream(dice, &dice->tx_stream[0]);
 	if (err < 0)
 		goto end;
 
-	err = init_stream(dice, &dice->rx_stream);
+	err = init_stream(dice, &dice->rx_stream[0]);
 	if (err < 0)
-		destroy_stream(dice, &dice->tx_stream);
+		destroy_stream(dice, &dice->tx_stream[0]);
 end:
 	return err;
 }
@@ -345,8 +345,8 @@ void snd_dice_stream_destroy_duplex(struct snd_dice *dice)
 {
 	snd_dice_transaction_clear_enable(dice);
 
-	destroy_stream(dice, &dice->tx_stream);
-	destroy_stream(dice, &dice->rx_stream);
+	destroy_stream(dice, &dice->tx_stream[0]);
+	destroy_stream(dice, &dice->rx_stream[0]);
 
 	dice->substreams_counter = 0;
 }
@@ -363,11 +363,11 @@ void snd_dice_stream_update_duplex(struct snd_dice *dice)
 	 */
 	dice->global_enabled = false;
 
-	stop_stream(dice, &dice->rx_stream);
-	stop_stream(dice, &dice->tx_stream);
+	stop_stream(dice, &dice->rx_stream[0]);
+	stop_stream(dice, &dice->tx_stream[0]);
 
-	fw_iso_resources_update(&dice->rx_resources);
-	fw_iso_resources_update(&dice->tx_resources);
+	fw_iso_resources_update(&dice->rx_resources[0]);
+	fw_iso_resources_update(&dice->tx_resources[0]);
 }
 
 static void dice_lock_changed(struct snd_dice *dice)
diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h
index 423cdba..8fba87d 100644
--- a/sound/firewire/dice/dice.h
+++ b/sound/firewire/dice/dice.h
@@ -39,6 +39,29 @@
 #include "../lib.h"
 #include "dice-interface.h"
 
+/*
+ * This module support maximum 2 pairs of tx/rx isochronous streams for
+ * our convinience.
+ *
+ * In documents for ASICs called with a name of 'DICE':
+ *  - ASIC for DICE II:
+ *   - Maximum 2 tx and 4 rx are supported.
+ *   - A packet supports maximum 16 data channels.
+ *  - TCD2210/2210-E (so-called 'Dice Mini'):
+ *   - Maximum 2 tx and 2 rx are supported.
+ *   - A packet supports maximum 16 data channels.
+ *  - TCD2220/2220-E (so-called 'Dice Jr.')
+ *   - 2 tx and 2 rx are supported.
+ *   - A packet supports maximum 16 data channels.
+ *  - TCD3070-CH (so-called 'Dice III')
+ *   - Maximum 2 tx and 2 rx are supported.
+ *   - A packet supports maximum 32 data channels.
+ *
+ * For the above, MIDI conformant data channel is just on the first isochronous
+ * stream.
+ */
+#define MAX_STREAMS	2
+
 struct snd_dice {
 	struct snd_card *card;
 	struct fw_unit *unit;
@@ -67,10 +90,10 @@ struct snd_dice {
 	wait_queue_head_t hwdep_wait;
 
 	/* For streaming */
-	struct fw_iso_resources tx_resources;
-	struct fw_iso_resources rx_resources;
-	struct amdtp_stream tx_stream;
-	struct amdtp_stream rx_stream;
+	struct fw_iso_resources tx_resources[MAX_STREAMS];
+	struct fw_iso_resources rx_resources[MAX_STREAMS];
+	struct amdtp_stream tx_stream[MAX_STREAMS];
+	struct amdtp_stream rx_stream[MAX_STREAMS];
 	bool global_enabled;
 	struct completion clock_accepted;
 	unsigned int substreams_counter;
-- 
2.7.0

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/4] ALSA: dice: handle whole available isochronous streams
  2016-03-07 13:35 [PATCH 0/4] ALSA: dice: enable to handle several streams Takashi Sakamoto
  2016-03-07 13:35 ` [PATCH 1/4] ALSA: dice: have two sets of isochronous resources/streams Takashi Sakamoto
@ 2016-03-07 13:35 ` Takashi Sakamoto
  2016-03-09 15:29   ` Takashi Iwai
  2016-03-07 13:35 ` [PATCH 3/4] ALSA: dice: handle several PCM substreams when any isochronous streams are available Takashi Sakamoto
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 9+ messages in thread
From: Takashi Sakamoto @ 2016-03-07 13:35 UTC (permalink / raw)
  To: clemens, tiwai; +Cc: alsa-devel, stefanr, ffado-devel

This commit enables ALSA dice driver to handle whole available streams.

In Dice, certain registers represent the number of available streams at
current sampling transfer frequency for both directions. The parameters
of each stream are represented in a block of register. This block is
aligned sequentially. These streams start simultaneously by writing
enable bit to a register.

This commit operates these registers when starting/stopping streams.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 sound/firewire/dice/dice-stream.c | 398 ++++++++++++++++++++++++--------------
 1 file changed, 255 insertions(+), 143 deletions(-)

diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c
index 15d581d..2077f18 100644
--- a/sound/firewire/dice/dice-stream.c
+++ b/sound/firewire/dice/dice-stream.c
@@ -65,85 +65,84 @@ static int ensure_phase_lock(struct snd_dice *dice)
 	return 0;
 }
 
-static void release_resources(struct snd_dice *dice,
-			      struct fw_iso_resources *resources)
+static int get_register_params(struct snd_dice *dice, unsigned int params[4])
 {
-	__be32 channel;
-
-	/* Reset channel number */
-	channel = cpu_to_be32((u32)-1);
-	if (resources == &dice->tx_resources[0])
-		snd_dice_transaction_write_tx(dice, TX_ISOCHRONOUS,
-					      &channel, sizeof(channel));
-	else
-		snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS,
-					      &channel, sizeof(channel));
-
-	fw_iso_resources_free(resources);
-}
-
-static int keep_resources(struct snd_dice *dice,
-			  struct fw_iso_resources *resources,
-			  unsigned int max_payload_bytes)
-{
-	__be32 channel;
+	__be32 reg[2];
 	int err;
 
-	err = fw_iso_resources_allocate(resources, max_payload_bytes,
-				fw_parent_device(dice->unit)->max_speed);
+	err = snd_dice_transaction_read_tx(dice, TX_NUMBER, reg, sizeof(reg));
 	if (err < 0)
-		goto end;
+		return err;
+	params[0] = min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS);
+	params[1] = be32_to_cpu(reg[1]) * 4;
 
-	/* Set channel number */
-	channel = cpu_to_be32(resources->channel);
-	if (resources == &dice->tx_resources[0])
-		err = snd_dice_transaction_write_tx(dice, TX_ISOCHRONOUS,
-						    &channel, sizeof(channel));
-	else
-		err = snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS,
-						    &channel, sizeof(channel));
+	err = snd_dice_transaction_read_rx(dice, RX_NUMBER, reg, sizeof(reg));
 	if (err < 0)
-		release_resources(dice, resources);
-end:
-	return err;
+		return err;
+	params[2] = min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS);
+	params[3] = be32_to_cpu(reg[1]) * 4;
+
+	return 0;
 }
 
-static void stop_stream(struct snd_dice *dice, struct amdtp_stream *stream)
+static void release_resources(struct snd_dice *dice)
 {
-	amdtp_stream_pcm_abort(stream);
-	amdtp_stream_stop(stream);
+	unsigned int i;
+
+	for (i = 0; i < MAX_STREAMS; i++) {
+		if (amdtp_stream_running(&dice->tx_stream[i])) {
+			amdtp_stream_pcm_abort(&dice->tx_stream[i]);
+			amdtp_stream_stop(&dice->tx_stream[i]);
+		}
+		if (amdtp_stream_running(&dice->rx_stream[i])) {
+			amdtp_stream_pcm_abort(&dice->rx_stream[i]);
+			amdtp_stream_stop(&dice->rx_stream[i]);
+		}
 
-	if (stream == &dice->tx_stream[0])
-		release_resources(dice, &dice->tx_resources[0]);
-	else
-		release_resources(dice, &dice->rx_resources[0]);
+		fw_iso_resources_free(&dice->tx_resources[i]);
+		fw_iso_resources_free(&dice->rx_resources[i]);
+	}
 }
 
-static int start_stream(struct snd_dice *dice, struct amdtp_stream *stream,
-			unsigned int rate)
+static void stop_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
+			 unsigned int count, unsigned int size)
 {
+	__be32 reg;
+	unsigned int i;
+
+	for (i = 0; i < count; i++) {
+		reg = cpu_to_be32((u32)-1);
+		if (dir == AMDTP_IN_STREAM) {
+			snd_dice_transaction_write_tx(dice,
+						size * i + TX_ISOCHRONOUS,
+						&reg, sizeof(reg));
+		} else {
+			snd_dice_transaction_write_rx(dice,
+						size * i + RX_ISOCHRONOUS,
+						&reg, sizeof(reg));
+		}
+	}
+}
+
+static int keep_resources(struct snd_dice *dice,
+			  enum amdtp_stream_direction dir, unsigned int index,
+			  unsigned int rate, unsigned int pcm_chs,
+			  unsigned int midi_ports)
+{
+	struct amdtp_stream *stream;
 	struct fw_iso_resources *resources;
-	__be32 reg[2];
-	unsigned int i, pcm_chs, midi_ports;
 	bool double_pcm_frames;
+	unsigned int i;
 	int err;
 
-	if (stream == &dice->tx_stream[0]) {
-		resources = &dice->tx_resources[0];
-		err = snd_dice_transaction_read_tx(dice, TX_NUMBER_AUDIO,
-						   reg, sizeof(reg));
+	if (dir == AMDTP_IN_STREAM) {
+		stream = &dice->tx_stream[index];
+		resources = &dice->tx_resources[index];
 	} else {
-		resources = &dice->rx_resources[0];
-		err = snd_dice_transaction_read_rx(dice, RX_NUMBER_AUDIO,
-						   reg, sizeof(reg));
+		stream = &dice->rx_stream[index];
+		resources = &dice->rx_resources[index];
 	}
 
-	if (err < 0)
-		goto end;
-
-	pcm_chs = be32_to_cpu(reg[0]);
-	midi_ports = be32_to_cpu(reg[1]);
-
 	/*
 	 * At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in
 	 * one data block of AMDTP packet. Thus sampling transfer frequency is
@@ -163,7 +162,7 @@ static int start_stream(struct snd_dice *dice, struct amdtp_stream *stream,
 	err = amdtp_am824_set_parameters(stream, rate, pcm_chs, midi_ports,
 					 double_pcm_frames);
 	if (err < 0)
-		goto end;
+		return err;
 
 	if (double_pcm_frames) {
 		pcm_chs /= 2;
@@ -175,122 +174,208 @@ static int start_stream(struct snd_dice *dice, struct amdtp_stream *stream,
 		}
 	}
 
-	err = keep_resources(dice, resources,
-			     amdtp_stream_get_max_payload(stream));
-	if (err < 0) {
-		dev_err(&dice->unit->device,
-			"fail to keep isochronous resources\n");
-		goto end;
+	return fw_iso_resources_allocate(resources,
+				amdtp_stream_get_max_payload(stream),
+				fw_parent_device(dice->unit)->max_speed);
+}
+
+static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
+			 unsigned int rate, unsigned int count,
+			 unsigned int size)
+{
+	__be32 reg[2];
+	unsigned int i, pcm_chs, midi_ports;
+	struct amdtp_stream *streams;
+	struct fw_iso_resources *resources;
+	int err = 0;
+
+	if (dir == AMDTP_IN_STREAM) {
+		streams = dice->tx_stream;
+		resources = dice->tx_resources;
+	} else {
+		streams = dice->rx_stream;
+		resources = dice->rx_resources;
+	}
+
+	for (i = 0; i < count; i++) {
+		if (dir == AMDTP_IN_STREAM) {
+			err = snd_dice_transaction_read_tx(dice,
+						size * i + TX_NUMBER_AUDIO,
+						reg, sizeof(reg));
+		} else {
+			err = snd_dice_transaction_read_rx(dice,
+						size * i + RX_NUMBER_AUDIO,
+						reg, sizeof(reg));
+		}
+		if (err < 0)
+			return err;
+		pcm_chs = be32_to_cpu(reg[0]);
+		midi_ports = be32_to_cpu(reg[1]);
+
+		err = keep_resources(dice, dir, i, rate, pcm_chs, midi_ports);
+		if (err < 0)
+			return err;
+
+		reg[0] = cpu_to_be32(resources[i].channel);
+		if (dir == AMDTP_IN_STREAM) {
+			err = snd_dice_transaction_write_tx(dice,
+						size * i + TX_ISOCHRONOUS,
+						reg, sizeof(reg[0]));
+		} else {
+			err = snd_dice_transaction_write_rx(dice,
+						size * i + RX_ISOCHRONOUS,
+						reg, sizeof(reg[0]));
+		}
+		if (err < 0)
+			return err;
+
+		err = amdtp_stream_start(&streams[i], resources[i].channel,
+				fw_parent_device(dice->unit)->max_speed);
+		if (err < 0)
+			return err;
 	}
 
-	err = amdtp_stream_start(stream, resources->channel,
-				 fw_parent_device(dice->unit)->max_speed);
-	if (err < 0)
-		release_resources(dice, resources);
-end:
 	return err;
 }
 
+/*
+ * MEMO: After this function, there're two states of streams:
+ *  - None streams are running.
+ *  - All streams are running.
+ */
 int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate)
 {
-	struct amdtp_stream *master, *slave;
 	unsigned int curr_rate;
-	int err = 0;
+	unsigned int i;
+	unsigned int reg_params[4];
+	bool need_to_start;
+	int err;
 
 	if (dice->substreams_counter == 0)
-		goto end;
-
-	master = &dice->rx_stream[0];
-	slave  = &dice->tx_stream[0];
+		return -EIO;
 
-	/* Some packet queueing errors. */
-	if (amdtp_streaming_error(master) || amdtp_streaming_error(slave))
-		stop_stream(dice, master);
+	err = get_register_params(dice, reg_params);
+	if (err < 0)
+		return err;
 
-	/* Stop stream if rate is different. */
 	err = snd_dice_transaction_get_rate(dice, &curr_rate);
 	if (err < 0) {
 		dev_err(&dice->unit->device,
 			"fail to get sampling rate\n");
-		goto end;
+		return err;
 	}
 	if (rate == 0)
 		rate = curr_rate;
-	if (rate != curr_rate) {
-		err = -EINVAL;
-		goto end;
+	if (rate != curr_rate)
+		return -EINVAL;
+
+	/* Judge to need to restart streams. */
+	for (i = 0; i < MAX_STREAMS; i++) {
+		if (i < reg_params[0]) {
+			if (amdtp_streaming_error(&dice->tx_stream[i]) ||
+			    !amdtp_stream_running(&dice->tx_stream[i]))
+				break;
+		}
+		if (i < reg_params[2]) {
+			if (amdtp_streaming_error(&dice->rx_stream[i]) ||
+			    !amdtp_stream_running(&dice->rx_stream[i]))
+				break;
+		}
 	}
+	need_to_start = (i < MAX_STREAMS);
 
-	if (!amdtp_stream_running(master)) {
-		stop_stream(dice, slave);
+	if (need_to_start) {
+		/* Stop transmission. */
 		snd_dice_transaction_clear_enable(dice);
+		stop_streams(dice, AMDTP_IN_STREAM, reg_params[0],
+			     reg_params[1]);
+		stop_streams(dice, AMDTP_OUT_STREAM, reg_params[2],
+			     reg_params[3]);
+		release_resources(dice);
 
 		err = ensure_phase_lock(dice);
 		if (err < 0) {
 			dev_err(&dice->unit->device,
 				"fail to ensure phase lock\n");
-			goto end;
+			return err;
 		}
 
 		/* Start both streams. */
-		err = start_stream(dice, master, rate);
-		if (err < 0) {
-			dev_err(&dice->unit->device,
-				"fail to start AMDTP master stream\n");
-			goto end;
-		}
-		err = start_stream(dice, slave, rate);
-		if (err < 0) {
-			dev_err(&dice->unit->device,
-				"fail to start AMDTP slave stream\n");
-			stop_stream(dice, master);
-			goto end;
-		}
+		err = start_streams(dice, AMDTP_IN_STREAM, rate, reg_params[0],
+				    reg_params[1]);
+		if (err < 0)
+			goto error;
+		err = start_streams(dice, AMDTP_OUT_STREAM, rate, reg_params[2],
+				    reg_params[3]);
+		if (err < 0)
+			goto error;
+
 		err = snd_dice_transaction_set_enable(dice);
 		if (err < 0) {
 			dev_err(&dice->unit->device,
 				"fail to enable interface\n");
-			stop_stream(dice, master);
-			stop_stream(dice, slave);
-			goto end;
+			goto error;
 		}
 
-		/* Wait first callbacks */
-		if (!amdtp_stream_wait_callback(master, CALLBACK_TIMEOUT) ||
-		    !amdtp_stream_wait_callback(slave, CALLBACK_TIMEOUT)) {
-			snd_dice_transaction_clear_enable(dice);
-			stop_stream(dice, master);
-			stop_stream(dice, slave);
-			err = -ETIMEDOUT;
+		for (i = 0; i < MAX_STREAMS; i++) {
+			if ((i < reg_params[0] &&
+			    !amdtp_stream_wait_callback(&dice->tx_stream[i],
+							CALLBACK_TIMEOUT)) ||
+			    (i < reg_params[2] &&
+			     !amdtp_stream_wait_callback(&dice->rx_stream[i],
+							 CALLBACK_TIMEOUT))) {
+				err = -ETIMEDOUT;
+				goto error;
+			}
 		}
 	}
-end:
+
+	return err;
+error:
+	snd_dice_transaction_clear_enable(dice);
+	stop_streams(dice, AMDTP_IN_STREAM, reg_params[0], reg_params[1]);
+	stop_streams(dice, AMDTP_OUT_STREAM, reg_params[2], reg_params[3]);
+	release_resources(dice);
 	return err;
 }
 
+/*
+ * MEMO: After this function, there're two states of streams:
+ *  - None streams are running.
+ *  - All streams are running.
+ */
 void snd_dice_stream_stop_duplex(struct snd_dice *dice)
 {
+	unsigned int reg_params[4];
+
 	if (dice->substreams_counter > 0)
 		return;
 
 	snd_dice_transaction_clear_enable(dice);
 
-	stop_stream(dice, &dice->tx_stream[0]);
-	stop_stream(dice, &dice->rx_stream[0]);
+	if (get_register_params(dice, reg_params) == 0) {
+		stop_streams(dice, AMDTP_IN_STREAM, reg_params[0],
+			     reg_params[1]);
+		stop_streams(dice, AMDTP_OUT_STREAM, reg_params[2],
+			     reg_params[3]);
+	}
+
+	release_resources(dice);
 }
 
-static int init_stream(struct snd_dice *dice, struct amdtp_stream *stream)
+static int init_stream(struct snd_dice *dice, enum amdtp_stream_direction dir,
+		       unsigned int index)
 {
-	int err;
+	struct amdtp_stream *stream;
 	struct fw_iso_resources *resources;
-	enum amdtp_stream_direction dir;
+	int err;
 
-	if (stream == &dice->tx_stream[0]) {
-		resources = &dice->tx_resources[0];
-		dir = AMDTP_IN_STREAM;
+	if (dir == AMDTP_IN_STREAM) {
+		stream = &dice->tx_stream[index];
+		resources = &dice->tx_resources[index];
 	} else {
-		resources = &dice->rx_resources[0];
-		dir = AMDTP_OUT_STREAM;
+		stream = &dice->rx_stream[index];
+		resources = &dice->rx_resources[index];
 	}
 
 	err = fw_iso_resources_init(resources, dice->unit);
@@ -311,14 +396,20 @@ end:
  * This function should be called before starting streams or after stopping
  * streams.
  */
-static void destroy_stream(struct snd_dice *dice, struct amdtp_stream *stream)
+static void destroy_stream(struct snd_dice *dice,
+			   enum amdtp_stream_direction dir,
+			   unsigned int index)
 {
+	struct amdtp_stream *stream;
 	struct fw_iso_resources *resources;
 
-	if (stream == &dice->tx_stream[0])
-		resources = &dice->tx_resources[0];
-	else
-		resources = &dice->rx_resources[0];
+	if (dir == AMDTP_IN_STREAM) {
+		stream = &dice->tx_stream[index];
+		resources = &dice->tx_resources[index];
+	} else {
+		stream = &dice->rx_stream[index];
+		resources = &dice->rx_resources[index];
+	}
 
 	amdtp_stream_destroy(stream);
 	fw_iso_resources_destroy(resources);
@@ -326,33 +417,53 @@ static void destroy_stream(struct snd_dice *dice, struct amdtp_stream *stream)
 
 int snd_dice_stream_init_duplex(struct snd_dice *dice)
 {
-	int err;
+	int i, err;
 
-	dice->substreams_counter = 0;
-
-	err = init_stream(dice, &dice->tx_stream[0]);
-	if (err < 0)
-		goto end;
+	for (i = 0; i < MAX_STREAMS; i++) {
+		err = init_stream(dice, AMDTP_IN_STREAM, i);
+		if (err < 0) {
+			for (; i >= 0; i--)
+				destroy_stream(dice, AMDTP_OUT_STREAM, i);
+			goto end;
+		}
+	}
 
-	err = init_stream(dice, &dice->rx_stream[0]);
-	if (err < 0)
-		destroy_stream(dice, &dice->tx_stream[0]);
+	for (i = 0; i < MAX_STREAMS; i++) {
+		err = init_stream(dice, AMDTP_OUT_STREAM, i);
+		if (err < 0) {
+			for (; i >= 0; i--)
+				destroy_stream(dice, AMDTP_OUT_STREAM, i);
+			for (i = 0; i < MAX_STREAMS; i++)
+				destroy_stream(dice, AMDTP_IN_STREAM, i);
+			break;
+		}
+	}
 end:
 	return err;
 }
 
 void snd_dice_stream_destroy_duplex(struct snd_dice *dice)
 {
+	unsigned int reg_params[4];
+
 	snd_dice_transaction_clear_enable(dice);
 
-	destroy_stream(dice, &dice->tx_stream[0]);
-	destroy_stream(dice, &dice->rx_stream[0]);
+	if (get_register_params(dice, reg_params) == 0) {
+		stop_streams(dice, AMDTP_IN_STREAM, reg_params[0],
+			     reg_params[1]);
+		stop_streams(dice, AMDTP_OUT_STREAM, reg_params[2],
+			     reg_params[3]);
+	}
+
+	release_resources(dice);
 
 	dice->substreams_counter = 0;
 }
 
 void snd_dice_stream_update_duplex(struct snd_dice *dice)
 {
+	unsigned int reg_params[4];
+
 	/*
 	 * On a bus reset, the DICE firmware disables streaming and then goes
 	 * off contemplating its own navel for hundreds of milliseconds before
@@ -363,11 +474,12 @@ void snd_dice_stream_update_duplex(struct snd_dice *dice)
 	 */
 	dice->global_enabled = false;
 
-	stop_stream(dice, &dice->rx_stream[0]);
-	stop_stream(dice, &dice->tx_stream[0]);
-
-	fw_iso_resources_update(&dice->rx_resources[0]);
-	fw_iso_resources_update(&dice->tx_resources[0]);
+	if (get_register_params(dice, reg_params) == 0) {
+		stop_streams(dice, AMDTP_IN_STREAM, reg_params[0],
+			     reg_params[1]);
+		stop_streams(dice, AMDTP_OUT_STREAM, reg_params[2],
+			     reg_params[3]);
+	}
 }
 
 static void dice_lock_changed(struct snd_dice *dice)
-- 
2.7.0

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 3/4] ALSA: dice: handle several PCM substreams when any isochronous streams are available
  2016-03-07 13:35 [PATCH 0/4] ALSA: dice: enable to handle several streams Takashi Sakamoto
  2016-03-07 13:35 ` [PATCH 1/4] ALSA: dice: have two sets of isochronous resources/streams Takashi Sakamoto
  2016-03-07 13:35 ` [PATCH 2/4] ALSA: dice: handle whole available isochronous streams Takashi Sakamoto
@ 2016-03-07 13:35 ` Takashi Sakamoto
  2016-03-07 13:35 ` [PATCH 4/4] ALSA: dice: force to add two pcm devices for listed models Takashi Sakamoto
  2016-03-09 13:15 ` [PATCH 0/4] ALSA: dice: enable to handle several streams Takashi Sakamoto
  4 siblings, 0 replies; 9+ messages in thread
From: Takashi Sakamoto @ 2016-03-07 13:35 UTC (permalink / raw)
  To: clemens, tiwai; +Cc: alsa-devel, stefanr, ffado-devel

In former commits, ALSA dice driver can handle available isochronous
streams. This commit adds support for several PCM substreams on the
streams.

The additional PCM substreams are available via another ALSA PCM character
devices so that one ALSA PCM application can handle them without cumbersome
operations. For example, two PCM substreams are available on each stream,
two ALSA character devices are added for them. In configuration space of
alsa-lib, it's represented with 'hw:0,0' and 'hw:0,1'.

The PCM substreams are constraint to parameters of the corresponding
streams. If the PCM substreams are unavailable for some reasons,
open(2) to ALSA PCM character device returns error and reports ENXIO.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 sound/firewire/dice/dice-pcm.c | 121 +++++++++++++++++++++++++----------------
 1 file changed, 75 insertions(+), 46 deletions(-)

diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c
index e252949..05e2e18 100644
--- a/sound/firewire/dice/dice-pcm.c
+++ b/sound/firewire/dice/dice-pcm.c
@@ -11,28 +11,34 @@
 
 static int limit_channels_and_rates(struct snd_dice *dice,
 				    struct snd_pcm_runtime *runtime,
-				    struct amdtp_stream *stream)
+				    enum amdtp_stream_direction dir,
+				    unsigned int index, unsigned int size)
 {
 	struct snd_pcm_hardware *hw = &runtime->hw;
+	struct amdtp_stream *stream;
 	unsigned int rate;
-	__be32 reg[2];
+	__be32 reg;
 	int err;
 
 	/*
 	 * Retrieve current Multi Bit Linear Audio data channel and limit to
 	 * it.
 	 */
-	if (stream == &dice->tx_stream[0]) {
-		err = snd_dice_transaction_read_tx(dice, TX_NUMBER_AUDIO,
-						   reg, sizeof(reg));
+	if (dir == AMDTP_IN_STREAM) {
+		stream = &dice->tx_stream[index];
+		err = snd_dice_transaction_read_tx(dice,
+				size * index + TX_NUMBER_AUDIO,
+				&reg, sizeof(reg));
 	} else {
-		err = snd_dice_transaction_read_rx(dice, RX_NUMBER_AUDIO,
-						   reg, sizeof(reg));
+		stream = &dice->rx_stream[index];
+		err = snd_dice_transaction_read_rx(dice,
+				size * index + RX_NUMBER_AUDIO,
+				&reg, sizeof(reg));
 	}
 	if (err < 0)
 		return err;
 
-	hw->channels_min = hw->channels_max = be32_to_cpu(reg[0]);
+	hw->channels_min = hw->channels_max = be32_to_cpu(reg);
 
 	/* Retrieve current sampling transfer frequency and limit to it. */
 	err = snd_dice_transaction_get_rate(dice, &rate);
@@ -62,7 +68,10 @@ static int init_hw_info(struct snd_dice *dice,
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_pcm_hardware *hw = &runtime->hw;
+	enum amdtp_stream_direction dir;
 	struct amdtp_stream *stream;
+	__be32 reg[2];
+	unsigned int count, size;
 	int err;
 
 	hw->info = SNDRV_PCM_INFO_MMAP |
@@ -74,13 +83,28 @@ static int init_hw_info(struct snd_dice *dice,
 
 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
 		hw->formats = AM824_IN_PCM_FORMAT_BITS;
-		stream = &dice->tx_stream[0];
+		dir = AMDTP_IN_STREAM;
+		stream = &dice->tx_stream[substream->pcm->device];
+		err = snd_dice_transaction_read_tx(dice, TX_NUMBER, reg,
+						   sizeof(reg));
 	} else {
 		hw->formats = AM824_OUT_PCM_FORMAT_BITS;
-		stream = &dice->rx_stream[0];
+		dir = AMDTP_OUT_STREAM;
+		stream = &dice->rx_stream[substream->pcm->device];
+		err = snd_dice_transaction_read_rx(dice, RX_NUMBER, reg,
+						   sizeof(reg));
 	}
 
-	err = limit_channels_and_rates(dice, runtime, stream);
+	if (err < 0)
+		return err;
+
+	count = min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS);
+	if (substream->pcm->device >= count)
+		return -ENXIO;
+
+	size = be32_to_cpu(reg[1]) * 4;
+	err = limit_channels_and_rates(dice, substream->runtime, dir,
+				       substream->pcm->device, size);
 	if (err < 0)
 		return err;
 	limit_period_and_buffer(hw);
@@ -122,7 +146,7 @@ static int capture_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *hw_params)
 {
 	struct snd_dice *dice = substream->private_data;
-	struct amdtp_stream *stream = &dice->tx_stream[0];
+	struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
 	int err;
 
 	err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
@@ -144,7 +168,7 @@ static int playback_hw_params(struct snd_pcm_substream *substream,
 			      struct snd_pcm_hw_params *hw_params)
 {
 	struct snd_dice *dice = substream->private_data;
-	struct amdtp_stream *stream = &dice->rx_stream[0];
+	struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
 	int err;
 
 	err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
@@ -198,7 +222,7 @@ static int playback_hw_free(struct snd_pcm_substream *substream)
 static int capture_prepare(struct snd_pcm_substream *substream)
 {
 	struct snd_dice *dice = substream->private_data;
-	struct amdtp_stream *stream = &dice->tx_stream[0];
+	struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
 	int err;
 
 	mutex_lock(&dice->mutex);
@@ -212,7 +236,7 @@ static int capture_prepare(struct snd_pcm_substream *substream)
 static int playback_prepare(struct snd_pcm_substream *substream)
 {
 	struct snd_dice *dice = substream->private_data;
-	struct amdtp_stream *stream = &dice->rx_stream[0];
+	struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
 	int err;
 
 	mutex_lock(&dice->mutex);
@@ -227,7 +251,7 @@ static int playback_prepare(struct snd_pcm_substream *substream)
 static int capture_trigger(struct snd_pcm_substream *substream, int cmd)
 {
 	struct snd_dice *dice = substream->private_data;
-	struct amdtp_stream *stream = &dice->tx_stream[0];
+	struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
@@ -245,7 +269,7 @@ static int capture_trigger(struct snd_pcm_substream *substream, int cmd)
 static int playback_trigger(struct snd_pcm_substream *substream, int cmd)
 {
 	struct snd_dice *dice = substream->private_data;
-	struct amdtp_stream *stream = &dice->rx_stream[0];
+	struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
@@ -264,14 +288,14 @@ static int playback_trigger(struct snd_pcm_substream *substream, int cmd)
 static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream)
 {
 	struct snd_dice *dice = substream->private_data;
-	struct amdtp_stream *stream = &dice->tx_stream[0];
+	struct amdtp_stream *stream = &dice->tx_stream[substream->pcm->device];
 
 	return amdtp_stream_pcm_pointer(stream);
 }
 static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream)
 {
 	struct snd_dice *dice = substream->private_data;
-	struct amdtp_stream *stream = &dice->rx_stream[0];
+	struct amdtp_stream *stream = &dice->rx_stream[substream->pcm->device];
 
 	return amdtp_stream_pcm_pointer(stream);
 }
@@ -304,40 +328,45 @@ int snd_dice_create_pcm(struct snd_dice *dice)
 	};
 	__be32 reg;
 	struct snd_pcm *pcm;
-	unsigned int capture, playback;
+	unsigned int i, max_capture, max_playback, capture, playback;
 	int err;
 
-	/*
-	 * Check whether PCM substreams are required.
-	 *
-	 * TODO: in the case that any PCM substreams are not avail at a certain
-	 * sampling transfer frequency?
-	 */
-	err = snd_dice_transaction_read_tx(dice, TX_NUMBER_AUDIO,
-					   &reg, sizeof(reg));
-	if (err < 0)
-		return err;
-	if (be32_to_cpu(reg) > 0)
-		capture = 1;
-
-	err = snd_dice_transaction_read_rx(dice, RX_NUMBER_AUDIO,
-					   &reg, sizeof(reg));
+	/* Check whether PCM substreams are required. */
+	max_capture = max_playback = 0;
+	err = snd_dice_transaction_read_tx(dice, TX_NUMBER, &reg, sizeof(reg));
 	if (err < 0)
 		return err;
-	if (be32_to_cpu(reg) > 0)
-		playback = 1;
+	max_capture = min_t(unsigned int, be32_to_cpu(reg), MAX_STREAMS);
 
-	err = snd_pcm_new(dice->card, "DICE", 0, playback, capture, &pcm);
+	err = snd_dice_transaction_read_rx(dice, RX_NUMBER, &reg, sizeof(reg));
 	if (err < 0)
 		return err;
-	pcm->private_data = dice;
-	strcpy(pcm->name, dice->card->shortname);
-
-	if (capture > 0)
-		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
-
-	if (playback > 0)
-		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
+	max_playback = min_t(unsigned int, be32_to_cpu(reg), MAX_STREAMS);
+
+	for (i = 0; i < MAX_STREAMS; i++) {
+		capture = playback = 0;
+		if (i < max_capture)
+			capture = 1;
+		if (i < max_playback)
+			playback = 1;
+		if (capture == 0 && playback == 0)
+			break;
+
+		err = snd_pcm_new(dice->card, "DICE", i, playback, capture,
+				  &pcm);
+		if (err < 0)
+			return err;
+		pcm->private_data = dice;
+		strcpy(pcm->name, dice->card->shortname);
+
+		if (capture > 0)
+			snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
+					&capture_ops);
+
+		if (playback > 0)
+			snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+					&playback_ops);
+	}
 
 	return 0;
 }
-- 
2.7.0

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 4/4] ALSA: dice: force to add two pcm devices for listed models
  2016-03-07 13:35 [PATCH 0/4] ALSA: dice: enable to handle several streams Takashi Sakamoto
                   ` (2 preceding siblings ...)
  2016-03-07 13:35 ` [PATCH 3/4] ALSA: dice: handle several PCM substreams when any isochronous streams are available Takashi Sakamoto
@ 2016-03-07 13:35 ` Takashi Sakamoto
  2016-03-09 13:15 ` [PATCH 0/4] ALSA: dice: enable to handle several streams Takashi Sakamoto
  4 siblings, 0 replies; 9+ messages in thread
From: Takashi Sakamoto @ 2016-03-07 13:35 UTC (permalink / raw)
  To: clemens, tiwai; +Cc: alsa-devel, stefanr, ffado-devel

Some models reduce the number of available isochronous streams for higher
sampling transfer frequency. Such models bring an issue about how to add
PCM substreams. When at lower sampling transfer frequency, the
models reports whole available streams, thus this driver can add enough
number of PCM substreams at probing time. On the other hand, at higher
sampling transfer frequency, this driver can just add reduced number of
PCM substreams. After probed, even if the sampling transfer frequency is
changed to lower rate, fewer PCM substreams are actually available. This
is inconvenience.

For the reason, this commit adds a list so that this driver assume models
on the list to have two pairs of PCM substreams. This list keeps the name
of model in which the number of available streams differs depending on
sampling transfer frequency.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 sound/firewire/dice/dice-pcm.c | 24 +++++++++++++++---------
 sound/firewire/dice/dice.c     | 41 +++++++++++++++++++++++++++++++++++++++++
 sound/firewire/dice/dice.h     |  2 ++
 3 files changed, 58 insertions(+), 9 deletions(-)

diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c
index 05e2e18..4aa0249 100644
--- a/sound/firewire/dice/dice-pcm.c
+++ b/sound/firewire/dice/dice-pcm.c
@@ -332,16 +332,22 @@ int snd_dice_create_pcm(struct snd_dice *dice)
 	int err;
 
 	/* Check whether PCM substreams are required. */
-	max_capture = max_playback = 0;
-	err = snd_dice_transaction_read_tx(dice, TX_NUMBER, &reg, sizeof(reg));
-	if (err < 0)
-		return err;
-	max_capture = min_t(unsigned int, be32_to_cpu(reg), MAX_STREAMS);
+	if (dice->force_two_pcms) {
+		max_capture = max_playback = 2;
+	} else {
+		max_capture = max_playback = 0;
+		err = snd_dice_transaction_read_tx(dice, TX_NUMBER, &reg,
+						   sizeof(reg));
+		if (err < 0)
+			return err;
+		max_capture = min_t(unsigned int, be32_to_cpu(reg), MAX_STREAMS);
 
-	err = snd_dice_transaction_read_rx(dice, RX_NUMBER, &reg, sizeof(reg));
-	if (err < 0)
-		return err;
-	max_playback = min_t(unsigned int, be32_to_cpu(reg), MAX_STREAMS);
+		err = snd_dice_transaction_read_rx(dice, RX_NUMBER, &reg,
+						   sizeof(reg));
+		if (err < 0)
+			return err;
+		max_playback = min_t(unsigned int, be32_to_cpu(reg), MAX_STREAMS);
+	}
 
 	for (i = 0; i < MAX_STREAMS; i++) {
 		capture = playback = 0;
diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c
index f7303a6..8b64aef 100644
--- a/sound/firewire/dice/dice.c
+++ b/sound/firewire/dice/dice.c
@@ -13,6 +13,8 @@ MODULE_LICENSE("GPL v2");
 
 #define OUI_WEISS		0x001c6a
 #define OUI_LOUD		0x000ff2
+#define OUI_FOCUSRITE		0x00130e
+#define OUI_TCELECTRONIC	0x001486
 
 #define DICE_CATEGORY_ID	0x04
 #define WEISS_CATEGORY_ID	0x00
@@ -20,6 +22,36 @@ MODULE_LICENSE("GPL v2");
 
 #define PROBE_DELAY_MS		(2 * MSEC_PER_SEC)
 
+/*
+ * Some models support several isochronous channels, while these streams are not
+ * always available. In this case, add the model name to this list.
+ */
+static bool force_two_pcm_support(struct fw_unit *unit)
+{
+	const char *const models[] = {
+		/* TC Electronic models. */
+		"StudioKonnekt48",
+		/* Focusrite models. */
+		"SAFFIRE_PRO_40",
+		"LIQUID_SAFFIRE_56",
+		"SAFFIRE_PRO_40_1",
+	};
+	char model[32];
+	unsigned int i;
+	int err;
+
+	err = fw_csr_string(unit->directory, CSR_MODEL, model, sizeof(model));
+	if (err < 0)
+		return false;
+
+	for (i = 0; i < ARRAY_SIZE(models); i++) {
+		if (strcmp(models[i], model) == 0)
+			break;
+	}
+
+	return i < ARRAY_SIZE(models);
+}
+
 static int check_dice_category(struct fw_unit *unit)
 {
 	struct fw_device *device = fw_parent_device(unit);
@@ -44,6 +76,12 @@ static int check_dice_category(struct fw_unit *unit)
 			break;
 		}
 	}
+
+	if (vendor == OUI_FOCUSRITE || vendor == OUI_TCELECTRONIC) {
+		if (force_two_pcm_support(unit))
+			return 0;
+	}
+
 	if (vendor == OUI_WEISS)
 		category = WEISS_CATEGORY_ID;
 	else if (vendor == OUI_LOUD)
@@ -150,6 +188,9 @@ static void do_registration(struct work_struct *work)
 	if (err < 0)
 		return;
 
+	if (force_two_pcm_support(dice->unit))
+		dice->force_two_pcms = true;
+
 	err = snd_dice_transaction_init(dice);
 	if (err < 0)
 		goto error;
diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h
index 8fba87d..e6c0785 100644
--- a/sound/firewire/dice/dice.h
+++ b/sound/firewire/dice/dice.h
@@ -97,6 +97,8 @@ struct snd_dice {
 	bool global_enabled;
 	struct completion clock_accepted;
 	unsigned int substreams_counter;
+
+	bool force_two_pcms;
 };
 
 enum snd_dice_addr_type {
-- 
2.7.0

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 0/4] ALSA: dice: enable to handle several streams
  2016-03-07 13:35 [PATCH 0/4] ALSA: dice: enable to handle several streams Takashi Sakamoto
                   ` (3 preceding siblings ...)
  2016-03-07 13:35 ` [PATCH 4/4] ALSA: dice: force to add two pcm devices for listed models Takashi Sakamoto
@ 2016-03-09 13:15 ` Takashi Sakamoto
  2016-03-09 15:27   ` Takashi Iwai
  4 siblings, 1 reply; 9+ messages in thread
From: Takashi Sakamoto @ 2016-03-09 13:15 UTC (permalink / raw)
  To: clemens, tiwai; +Cc: alsa-devel, stefanr, ffado-devel

Hi,

On mar 7 2016 22:35, Takashi Sakamoto wrote:
> Hi,
> 
> This patchset updates my previous RFT, and goes for merging.
> [alsa-devel] [RFT][PATCH 0/4] ALSA: dice: enabled to handle several streams
> http://mailman.alsa-project.org/pipermail/alsa-devel/2016-March/105387.html
> 
> For the previous one, Stefan Richter worked as a tester with his devices
> (Focusrite Saffire Pro 24 and 40), while current patchset includes changes
> related to userspace interface. Therefore, I don't add Tested-by.
> 
> 
> In previous one, ALSA dice driver uses subdevice for userspace to access
> any PCM substreams. On the other hand, the design of PCM subdevice leaves
> a bit cumbersome for userspace to handle several subdevices simultaneously
> in one process. These PCM substreams on a batch of AMDTP streams and it's
> better for ALSA dice driver to enable one process to handle them with
> simpler way.
> 
> Based on this concept, this patchset adds PCM character devices, instead of
> PCM subdevice. Thus, userspace applications can utilize PCM substreams via
> individual PCM character devices. In configuration space of alsa-lib, via
> 'hw:0,0' and 'hw:0,1' if available, like:
> 
> $ arecord -l
> ...
> card 1: Pro26000f5a [Pro26-000f5a], device 0: DICE [Pro26-000f5a]
>   Subdevices: 1/1
>   Subdevice #0: subdevice #0
> card 1: Pro26000f5a [Pro26-000f5a], device 1: DICE [Pro26-000f5a]
>   Subdevices: 1/1
>   Subdevice #0: subdevice #0
> 
> 
> For the other parts, there's no code changes. Therefore, Stefan's result
> still has meanings.
> 
> Changes:
>  * Add additional PCM character device instead of PCM subdevice
>  * Correct string entries to force-pcm
>  * Improve comments
> 
> Takashi Sakamoto (4):
>   ALSA: dice: have two sets of isochronous resources/streams
>   ALSA: dice: handle whole available isochronous streams
>   ALSA: dice: handle several PCM substreams when any isochronous streams
>     are available
>   ALSA: dice: force to add two pcm devices for listed models
> 
>  sound/firewire/dice/dice-midi.c   |   8 +-
>  sound/firewire/dice/dice-pcm.c    | 147 +++++++++-----
>  sound/firewire/dice/dice-stream.c | 398 ++++++++++++++++++++++++--------------
>  sound/firewire/dice/dice.c        |  41 ++++
>  sound/firewire/dice/dice.h        |  33 +++-
>  5 files changed, 424 insertions(+), 203 deletions(-)

I strongly request to merge this patchset to linux-next for 4.6 kernel.
For already supported models, this patchset basically adds no changes
except for actual codes. Therefore few possibilities of regressions.


Regards

Takashi Sakamoto

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 0/4] ALSA: dice: enable to handle several streams
  2016-03-09 13:15 ` [PATCH 0/4] ALSA: dice: enable to handle several streams Takashi Sakamoto
@ 2016-03-09 15:27   ` Takashi Iwai
  2016-03-09 22:00     ` Stefan Richter
  0 siblings, 1 reply; 9+ messages in thread
From: Takashi Iwai @ 2016-03-09 15:27 UTC (permalink / raw)
  To: Takashi Sakamoto; +Cc: alsa-devel, stefanr, clemens, ffado-devel

On Wed, 09 Mar 2016 14:15:03 +0100,
Takashi Sakamoto wrote:
> 
> Hi,
> 
> On mar 7 2016 22:35, Takashi Sakamoto wrote:
> > Hi,
> > 
> > This patchset updates my previous RFT, and goes for merging.
> > [alsa-devel] [RFT][PATCH 0/4] ALSA: dice: enabled to handle several streams
> > http://mailman.alsa-project.org/pipermail/alsa-devel/2016-March/105387.html
> > 
> > For the previous one, Stefan Richter worked as a tester with his devices
> > (Focusrite Saffire Pro 24 and 40), while current patchset includes changes
> > related to userspace interface. Therefore, I don't add Tested-by.
> > 
> > 
> > In previous one, ALSA dice driver uses subdevice for userspace to access
> > any PCM substreams. On the other hand, the design of PCM subdevice leaves
> > a bit cumbersome for userspace to handle several subdevices simultaneously
> > in one process. These PCM substreams on a batch of AMDTP streams and it's
> > better for ALSA dice driver to enable one process to handle them with
> > simpler way.
> > 
> > Based on this concept, this patchset adds PCM character devices, instead of
> > PCM subdevice. Thus, userspace applications can utilize PCM substreams via
> > individual PCM character devices. In configuration space of alsa-lib, via
> > 'hw:0,0' and 'hw:0,1' if available, like:
> > 
> > $ arecord -l
> > ...
> > card 1: Pro26000f5a [Pro26-000f5a], device 0: DICE [Pro26-000f5a]
> >   Subdevices: 1/1
> >   Subdevice #0: subdevice #0
> > card 1: Pro26000f5a [Pro26-000f5a], device 1: DICE [Pro26-000f5a]
> >   Subdevices: 1/1
> >   Subdevice #0: subdevice #0
> > 
> > 
> > For the other parts, there's no code changes. Therefore, Stefan's result
> > still has meanings.
> > 
> > Changes:
> >  * Add additional PCM character device instead of PCM subdevice
> >  * Correct string entries to force-pcm
> >  * Improve comments
> > 
> > Takashi Sakamoto (4):
> >   ALSA: dice: have two sets of isochronous resources/streams
> >   ALSA: dice: handle whole available isochronous streams
> >   ALSA: dice: handle several PCM substreams when any isochronous streams
> >     are available
> >   ALSA: dice: force to add two pcm devices for listed models
> > 
> >  sound/firewire/dice/dice-midi.c   |   8 +-
> >  sound/firewire/dice/dice-pcm.c    | 147 +++++++++-----
> >  sound/firewire/dice/dice-stream.c | 398 ++++++++++++++++++++++++--------------
> >  sound/firewire/dice/dice.c        |  41 ++++
> >  sound/firewire/dice/dice.h        |  33 +++-
> >  5 files changed, 424 insertions(+), 203 deletions(-)
> 
> I strongly request to merge this patchset to linux-next for 4.6 kernel.
> For already supported models, this patchset basically adds no changes
> except for actual codes. Therefore few possibilities of regressions.

I expected some tested-by tags or such, but OK, it's fine to merge
without that.  There are minor nitpicks, but they can be improved
later.

Now applied all patches.


thanks,

Takashi

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/4] ALSA: dice: handle whole available isochronous streams
  2016-03-07 13:35 ` [PATCH 2/4] ALSA: dice: handle whole available isochronous streams Takashi Sakamoto
@ 2016-03-09 15:29   ` Takashi Iwai
  0 siblings, 0 replies; 9+ messages in thread
From: Takashi Iwai @ 2016-03-09 15:29 UTC (permalink / raw)
  To: Takashi Sakamoto; +Cc: alsa-devel, stefanr, clemens, ffado-devel

On Mon, 07 Mar 2016 14:35:43 +0100,
Takashi Sakamoto wrote:
> 
> This commit enables ALSA dice driver to handle whole available streams.
> 
> In Dice, certain registers represent the number of available streams at
> current sampling transfer frequency for both directions. The parameters
> of each stream are represented in a block of register. This block is
> aligned sequentially. These streams start simultaneously by writing
> enable bit to a register.
> 
> This commit operates these registers when starting/stopping streams.
> 
> Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
> ---
>  sound/firewire/dice/dice-stream.c | 398 ++++++++++++++++++++++++--------------
>  1 file changed, 255 insertions(+), 143 deletions(-)
> 
> diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c
> index 15d581d..2077f18 100644
> --- a/sound/firewire/dice/dice-stream.c
> +++ b/sound/firewire/dice/dice-stream.c
> @@ -65,85 +65,84 @@ static int ensure_phase_lock(struct snd_dice *dice)
>  	return 0;
>  }
>  
> -static void release_resources(struct snd_dice *dice,
> -			      struct fw_iso_resources *resources)
> +static int get_register_params(struct snd_dice *dice, unsigned int params[4])
>  {
> -	__be32 channel;
> -
> -	/* Reset channel number */
> -	channel = cpu_to_be32((u32)-1);
> -	if (resources == &dice->tx_resources[0])
> -		snd_dice_transaction_write_tx(dice, TX_ISOCHRONOUS,
> -					      &channel, sizeof(channel));
> -	else
> -		snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS,
> -					      &channel, sizeof(channel));
> -
> -	fw_iso_resources_free(resources);
> -}
> -
> -static int keep_resources(struct snd_dice *dice,
> -			  struct fw_iso_resources *resources,
> -			  unsigned int max_payload_bytes)
> -{
> -	__be32 channel;
> +	__be32 reg[2];
>  	int err;
>  
> -	err = fw_iso_resources_allocate(resources, max_payload_bytes,
> -				fw_parent_device(dice->unit)->max_speed);
> +	err = snd_dice_transaction_read_tx(dice, TX_NUMBER, reg, sizeof(reg));
>  	if (err < 0)
> -		goto end;
> +		return err;
> +	params[0] = min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS);
> +	params[1] = be32_to_cpu(reg[1]) * 4;
>  
> -	/* Set channel number */
> -	channel = cpu_to_be32(resources->channel);
> -	if (resources == &dice->tx_resources[0])
> -		err = snd_dice_transaction_write_tx(dice, TX_ISOCHRONOUS,
> -						    &channel, sizeof(channel));
> -	else
> -		err = snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS,
> -						    &channel, sizeof(channel));
> +	err = snd_dice_transaction_read_rx(dice, RX_NUMBER, reg, sizeof(reg));
>  	if (err < 0)
> -		release_resources(dice, resources);
> -end:
> -	return err;
> +		return err;
> +	params[2] = min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS);
> +	params[3] = be32_to_cpu(reg[1]) * 4;

These "parameters" are not necessarily an array since each field has a
strict definition.  A more readable code would be to define a struct
instead.


thanks,

Takashi

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 0/4] ALSA: dice: enable to handle several streams
  2016-03-09 15:27   ` Takashi Iwai
@ 2016-03-09 22:00     ` Stefan Richter
  0 siblings, 0 replies; 9+ messages in thread
From: Stefan Richter @ 2016-03-09 22:00 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel, clemens, ffado-devel, Takashi Sakamoto

On Mar 09 Takashi Iwai wrote:
> On Wed, 09 Mar 2016 14:15:03 +0100, Takashi Sakamoto wrote:
> > On mar 7 2016 22:35, Takashi Sakamoto wrote:  
> > > Takashi Sakamoto (4):
> > >   ALSA: dice: have two sets of isochronous resources/streams
> > >   ALSA: dice: handle whole available isochronous streams
> > >   ALSA: dice: handle several PCM substreams when any isochronous streams
> > >     are available
> > >   ALSA: dice: force to add two pcm devices for listed models
> > > 
> > >  sound/firewire/dice/dice-midi.c   |   8 +-
> > >  sound/firewire/dice/dice-pcm.c    | 147 +++++++++-----
> > >  sound/firewire/dice/dice-stream.c | 398 ++++++++++++++++++++++++--------------
> > >  sound/firewire/dice/dice.c        |  41 ++++
> > >  sound/firewire/dice/dice.h        |  33 +++-
> > >  5 files changed, 424 insertions(+), 203 deletions(-)  
> > 
> > I strongly request to merge this patchset to linux-next for 4.6 kernel.
> > For already supported models, this patchset basically adds no changes
> > except for actual codes. Therefore few possibilities of regressions.  
> 
> I expected some tested-by tags or such, but OK, it's fine to merge
> without that.  There are minor nitpicks, but they can be improved
> later.
> 
> Now applied all patches.

I now tested this version of these four patches too, in the same way as
the previous version from March 5.
kernel: v4.5-rc6 plus
    ALSA: dice: limit to current sampling transfer frequency
    ALSA: dice: limit stream to current sampling transfer frequency.
    ALSA: dice: add MIDI ports according to current number of MIDI substreams
    ALSA: dice: get the number of MBLA data channel at opening PCM substream
    ALSA: dice: purge generating channel cache
    ALSA: dice: ensure phase lock before starting streaming
    ALSA: dice: change notification mask to detect lock status change
    ALSA: dice: old firmware optimization for Dice notification
    ALSA: dice: drop duplex streams synchronization to transfer own time stamps
cherry-picked from tiwai/sound.git, and current 4 patches applied on top.
Host: AMD64, Texas Instruments XIO2213B FireWire adapter.
Audio devices tested:  Focusrite Saffire PRO 24 and PRO 40.
Again no regression with PRO 24 or PRO 40, previously inaccessible higher
channels of the PRO 40 are now accessible (now as devices 0 and 1 on the
respective ALSA card), older muting quirk of the PRO 40 at 88.2/96 kHz still
happens with or without the 9+4 dice patches.
-- 
Stefan Richter
-======----- --== -=--=
http://arcgraph.de/sr/

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2016-03-09 22:00 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-03-07 13:35 [PATCH 0/4] ALSA: dice: enable to handle several streams Takashi Sakamoto
2016-03-07 13:35 ` [PATCH 1/4] ALSA: dice: have two sets of isochronous resources/streams Takashi Sakamoto
2016-03-07 13:35 ` [PATCH 2/4] ALSA: dice: handle whole available isochronous streams Takashi Sakamoto
2016-03-09 15:29   ` Takashi Iwai
2016-03-07 13:35 ` [PATCH 3/4] ALSA: dice: handle several PCM substreams when any isochronous streams are available Takashi Sakamoto
2016-03-07 13:35 ` [PATCH 4/4] ALSA: dice: force to add two pcm devices for listed models Takashi Sakamoto
2016-03-09 13:15 ` [PATCH 0/4] ALSA: dice: enable to handle several streams Takashi Sakamoto
2016-03-09 15:27   ` Takashi Iwai
2016-03-09 22:00     ` Stefan Richter

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.