alsa-devel.alsa-project.org archive mirror
 help / color / mirror / Atom feed
From: Clemens Ladisch <clemens@ladisch.de>
To: Takashi Iwai <tiwai@suse.de>
Cc: alsa-devel@alsa-project.org, linux1394-devel@lists.sourceforge.net
Subject: [PATCH] [23/29] ALSA: dice: dynamic sample rate selection
Date: Mon, 21 Oct 2013 21:34:00 +0200	[thread overview]
Message-ID: <526581A8.7090708@ladisch.de> (raw)
In-Reply-To: <52657E3B.7040205@ladisch.de>

Instead of relying of some control panel application to configure some
fixed sample rate, allow applications to set it automatically.

Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
---
 sound/firewire/dice.c |  137 ++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 102 insertions(+), 35 deletions(-)

diff --git a/sound/firewire/dice.c b/sound/firewire/dice.c
index e6bba6d..61dd00c 100644
--- a/sound/firewire/dice.c
+++ b/sound/firewire/dice.c
@@ -70,6 +70,17 @@ static const unsigned int dice_rates[] = {
 	[6] = 192000,
 };

+static unsigned int rate_to_index(unsigned int rate)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(dice_rates); ++i)
+		if (dice_rates[i] == rate)
+			return i;
+
+	return 0;
+}
+
 static unsigned int rate_index_to_mode(unsigned int rate_index)
 {
 	return ((int)rate_index - 1) / 2;
@@ -302,6 +313,59 @@ static void dice_notification(struct fw_card *card, struct fw_request *request,
 	wake_up(&dice->hwdep_wait);
 }

+static int dice_rate_constraint(struct snd_pcm_hw_params *params,
+				struct snd_pcm_hw_rule *rule)
+{
+	struct dice *dice = rule->private;
+	const struct snd_interval *channels =
+		hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+	struct snd_interval *rate =
+		hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+	struct snd_interval allowed_rates = {
+		.min = UINT_MAX, .max = 0, .integer = 1
+	};
+	unsigned int i, mode;
+
+	for (i = 0; i < ARRAY_SIZE(dice_rates); ++i) {
+		mode = rate_index_to_mode(i);
+		if ((dice->clock_caps & (1 << i)) &&
+		    snd_interval_test(channels, dice->rx_channels[mode])) {
+			allowed_rates.min = min(allowed_rates.min,
+						dice_rates[i]);
+			allowed_rates.max = max(allowed_rates.max,
+						dice_rates[i]);
+		}
+	}
+
+	return snd_interval_refine(rate, &allowed_rates);
+}
+
+static int dice_channels_constraint(struct snd_pcm_hw_params *params,
+				    struct snd_pcm_hw_rule *rule)
+{
+	struct dice *dice = rule->private;
+	const struct snd_interval *rate =
+		hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
+	struct snd_interval *channels =
+		hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+	struct snd_interval allowed_channels = {
+		.min = UINT_MAX, .max = 0, .integer = 1
+	};
+	unsigned int i, mode;
+
+	for (i = 0; i < ARRAY_SIZE(dice_rates); ++i)
+		if ((dice->clock_caps & (1 << i)) &&
+		    snd_interval_test(rate, dice_rates[i])) {
+			mode = rate_index_to_mode(i);
+			allowed_channels.min = min(allowed_channels.min,
+						   dice->rx_channels[mode]);
+			allowed_channels.max = max(allowed_channels.max,
+						   dice->rx_channels[mode]);
+		}
+
+	return snd_interval_refine(channels, &allowed_channels);
+}
+
 static int dice_open(struct snd_pcm_substream *substream)
 {
 	static const struct snd_pcm_hardware hardware = {
@@ -311,6 +375,8 @@ static int dice_open(struct snd_pcm_substream *substream)
 			SNDRV_PCM_INFO_INTERLEAVED |
 			SNDRV_PCM_INFO_BLOCK_TRANSFER,
 		.formats = AMDTP_OUT_PCM_FORMAT_BITS,
+		.channels_min = UINT_MAX,
+		.channels_max = 0,
 		.buffer_bytes_max = 16 * 1024 * 1024,
 		.period_bytes_min = 1,
 		.period_bytes_max = UINT_MAX,
@@ -319,53 +385,46 @@ static int dice_open(struct snd_pcm_substream *substream)
 	};
 	struct dice *dice = substream->private_data;
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	__be32 clock_sel, data[2];
-	unsigned int rate_index, number_audio, number_midi;
+	unsigned int i;
 	int err;

 	err = dice_try_lock(dice);
 	if (err < 0)
 		goto error;

-	err = snd_fw_transaction(dice->unit, TCODE_READ_QUADLET_REQUEST,
-				 global_address(dice, GLOBAL_CLOCK_SELECT),
-				 &clock_sel, 4, 0);
-	if (err < 0)
-		goto err_lock;
-	rate_index = (be32_to_cpu(clock_sel) & CLOCK_RATE_MASK)
-							>> CLOCK_RATE_SHIFT;
-	if (rate_index >= ARRAY_SIZE(dice_rates)) {
-		err = -ENXIO;
-		goto err_lock;
-	}
-
-	err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
-				 rx_address(dice, RX_NUMBER_AUDIO),
-				 data, 2 * 4, 0);
-	if (err < 0)
-		goto err_lock;
-	number_audio = be32_to_cpu(data[0]);
-	number_midi = be32_to_cpu(data[1]);
-
 	runtime->hw = hardware;

-	runtime->hw.rates = snd_pcm_rate_to_rate_bit(dice_rates[rate_index]);
+	for (i = 0; i < ARRAY_SIZE(dice_rates); ++i)
+		if (dice->clock_caps & (1 << i))
+			runtime->hw.rates |=
+				snd_pcm_rate_to_rate_bit(dice_rates[i]);
 	snd_pcm_limit_hw_rates(runtime);

-	runtime->hw.channels_min = number_audio;
-	runtime->hw.channels_max = number_audio;
+	for (i = 0; i < 3; ++i)
+		if (dice->rx_channels[i]) {
+			runtime->hw.channels_min = min(runtime->hw.channels_min,
+						       dice->rx_channels[i]);
+			runtime->hw.channels_max = max(runtime->hw.channels_max,
+						       dice->rx_channels[i]);
+		}

-	amdtp_out_stream_set_parameters(&dice->stream, dice_rates[rate_index],
-					number_audio, number_midi);
+	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+				  dice_rate_constraint, dice,
+				  SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+	if (err < 0)
+		goto err_lock;
+	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+				  dice_channels_constraint, dice,
+				  SNDRV_PCM_HW_PARAM_RATE, -1);
+	if (err < 0)
+		goto err_lock;

 	err = snd_pcm_hw_constraint_step(runtime, 0,
-					 SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
-					 amdtp_syt_intervals[rate_index]);
+					 SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 32);
 	if (err < 0)
 		goto err_lock;
 	err = snd_pcm_hw_constraint_step(runtime, 0,
-					 SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
-					 amdtp_syt_intervals[rate_index]);
+					 SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 32);
 	if (err < 0)
 		goto err_lock;

@@ -502,6 +561,7 @@ static int dice_hw_params(struct snd_pcm_substream *substream,
 			  struct snd_pcm_hw_params *hw_params)
 {
 	struct dice *dice = substream->private_data;
+	unsigned int rate_index, mode;
 	int err;

 	mutex_lock(&dice->mutex);
@@ -511,15 +571,22 @@ static int dice_hw_params(struct snd_pcm_substream *substream,
 	err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
 					       params_buffer_bytes(hw_params));
 	if (err < 0)
-		goto error;
+		return err;

+	rate_index = rate_to_index(params_rate(hw_params));
+	err = dice_change_rate(dice, rate_index << CLOCK_RATE_SHIFT);
+	if (err < 0)
+		return err;
+
+	mode = rate_index_to_mode(rate_index);
+	amdtp_out_stream_set_parameters(&dice->stream,
+					params_rate(hw_params),
+					params_channels(hw_params),
+					dice->rx_midi_ports[mode]);
 	amdtp_out_stream_set_pcm_format(&dice->stream,
 					params_format(hw_params));

 	return 0;
-
-error:
-	return err;
 }

 static int dice_hw_free(struct snd_pcm_substream *substream)

------------------------------------------------------------------------------
October Webinars: Code for Performance
Free Intel webinars can help you accelerate application performance.
Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most from 
the latest Intel processors and coprocessors. See abstracts and register >
http://pubads.g.doubleclick.net/gampad/clk?id=60135991&iu=/4140/ostg.clktrk

  parent reply	other threads:[~2013-10-21 19:34 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-10-21 19:19 [GIT PULL] [00/29] playback-only DICE driver Clemens Ladisch
2013-10-21 19:21 ` [PATCH] [01/29] ALSA: add " Clemens Ladisch
2013-10-21 19:21 ` [PATCH] [02/29] ALSA: dice: optimize bus reset handling Clemens Ladisch
2013-10-21 19:22 ` [PATCH] [03/29] ALSA: dice: allow all sample rates Clemens Ladisch
2013-10-21 19:23 ` [PATCH] [04/29] ALSA: dice: reduce noisy logging Clemens Ladisch
2013-10-21 19:23 ` [PATCH] [05/29] ALSA: dice, firewire-lib: add blocking mode Clemens Ladisch
2013-10-21 19:24 ` [PATCH] [06/29] ALSA: dice: fix hang when unplugging a running device Clemens Ladisch
2013-10-21 19:24 ` [PATCH] [07/29] ALSA: dice: implement hwdep device Clemens Ladisch
2013-10-21 19:25 ` [PATCH] [08/29] ALSA: dice: clear device lock when closing " Clemens Ladisch
2013-10-21 19:25 ` [PATCH] [09/29] ALSA: firewire: introduce amdtp_out_stream_running() Clemens Ladisch
2013-10-21 19:26 ` [PATCH] [10/29] ALSA: dice: reorganize interface definitions Clemens Ladisch
2013-10-21 19:26 ` [PATCH] [11/29] ALSA: dice: fix device detection for other vendors Clemens Ladisch
2013-10-21 19:27 ` [PATCH] [12/29] ALSA: dice: support dual-wire stream format at 192 kHz Clemens Ladisch
2013-10-21 19:27 ` [PATCH] [13/29] ALSA: dice: optimize reading of consecutive registers Clemens Ladisch
2013-10-21 19:28 ` [PATCH] [14/29] ALSA: firewire: extend snd_fw_transaction() Clemens Ladisch
2013-10-21 19:29 ` [PATCH] [15/29] ALSA: dice: avoid superflous write at bus reset Clemens Ladisch
2013-10-21 19:29 ` [PATCH] [16/29] ALSA: dice: remove 10s period length limit Clemens Ladisch
2013-10-21 19:30 ` [PATCH] [17/29] ALSA: dice: remove superfluous field Clemens Ladisch
2013-10-21 19:31 ` [PATCH] [18/29] ALSA: dice: fix locking Clemens Ladisch
2013-10-21 19:31 ` [PATCH] [19/29] ALSA: dice: make amdtp_rates[] const Clemens Ladisch
2013-10-21 19:32 ` [PATCH] [20/29] ALSA: dice: get clock capabilities Clemens Ladisch
2013-10-21 19:32 ` [PATCH] [21/29] ALSA: dice: allow notifications during initialization Clemens Ladisch
2013-10-21 19:33 ` [PATCH] [22/29] ALSA: dice: get rate-dependent parameters Clemens Ladisch
2013-10-21 19:34 ` Clemens Ladisch [this message]
2013-10-21 19:34 ` [PATCH] [24/29] ALSA: dice: check clock change timeout Clemens Ladisch
2013-10-21 19:34 ` [PATCH] [25/29] ALSA: dice: add a proc file to show device information Clemens Ladisch
2013-10-21 19:35 ` [PATCH] [26/29] ALSA: dice: document quadlet alignment Clemens Ladisch
2013-10-21 19:40 ` [PATCH] [27/29] ALSA: dice: dice_proc_read: remove wrong typecast Clemens Ladisch
2013-10-21 19:41 ` [PATCH] [28/29] ALSA: dice: fix detection of Weiss devices Clemens Ladisch
2013-10-21 19:42 ` [PATCH] [29/29] ALSA: dice: restrict the driver to playback-only devices Clemens Ladisch
2013-10-24  9:39 ` [GIT PULL] [00/29] playback-only DICE driver Takashi Iwai

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=526581A8.7090708@ladisch.de \
    --to=clemens@ladisch.de \
    --cc=alsa-devel@alsa-project.org \
    --cc=linux1394-devel@lists.sourceforge.net \
    --cc=tiwai@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).