From patchwork Sat Dec 12 03:06:05 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Sakamoto X-Patchwork-Id: 7834061 Return-Path: X-Original-To: patchwork-alsa-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 15C8ABEEE1 for ; Sat, 12 Dec 2015 03:09:38 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 0F5F4203E5 for ; Sat, 12 Dec 2015 03:09:37 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.kernel.org (Postfix) with ESMTP id 88FF620380 for ; Sat, 12 Dec 2015 03:09:35 +0000 (UTC) Received: by alsa0.perex.cz (Postfix, from userid 1000) id BB6722668F2; Sat, 12 Dec 2015 04:09:34 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Level: X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id C135926572A; Sat, 12 Dec 2015 04:06:34 +0100 (CET) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id D94A826570A; Sat, 12 Dec 2015 04:06:32 +0100 (CET) Received: from smtp310.phy.lolipop.jp (smtp310.phy.lolipop.jp [210.157.22.78]) by alsa0.perex.cz (Postfix) with ESMTP id E426E2654BE for ; Sat, 12 Dec 2015 04:06:16 +0100 (CET) Received: from smtp310.phy.lolipop.lan (HELO smtp310.phy.lolipop.jp) (172.17.1.10) (smtp-auth username m12129643-o-takashi, mechanism plain) by smtp310.phy.lolipop.jp (qpsmtpd/0.82) with ESMTPA; Sat, 12 Dec 2015 12:06:13 +0900 Received: from 127.0.0.1 (127.0.0.1) by smtp310.phy.lolipop.jp (LOLIPOP-Fsecure); Sat, 12 Dec 2015 12:06:10 +0900 (JST) X-Virus-Status: clean(LOLIPOP-Fsecure) From: Takashi Sakamoto To: clemens@ladisch.de, tiwai@suse.de Date: Sat, 12 Dec 2015 12:06:05 +0900 Message-Id: <1449889570-26641-6-git-send-email-o-takashi@sakamocchi.jp> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1449889570-26641-1-git-send-email-o-takashi@sakamocchi.jp> References: <1449889570-26641-1-git-send-email-o-takashi@sakamocchi.jp> Cc: alsa-devel@alsa-project.org, ffado-devel@lists.sf.net Subject: [alsa-devel] [PATCH 05/10] ALSA: dice: limit to current sampling transfer frequency X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP ALSA PCM core has a functionality for rule of parameters for PCM substream. Typically, when userspace opens PCM character device, each driver adds its own rules to PCM substream, according to design of devices. When the userspace executes hw_params ioctl with favorable parameters, the actual parameters are calculated with the rules and the given parameters. Currently, ALSA Dice driver has the rule between channels and rates, while Dice interface design doesn't allow drivers to retrieve all of their combinations in advance. Dice devices just allows drivers to get current sampling transfer frequency, the number of multi bit linear audio data channels and MIDI conformant data channels in an data block of an AMDTP packet. This commit purges the rule and limit PCM substreams to current sampling transfer frequency, following to the interface design. Signed-off-by: Takashi Sakamoto --- sound/firewire/dice/dice-pcm.c | 172 ++++++++--------------------------------- 1 file changed, 33 insertions(+), 139 deletions(-) diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index 9b34319..eaaabf0 100644 --- a/sound/firewire/dice/dice-pcm.c +++ b/sound/firewire/dice/dice-pcm.c @@ -9,99 +9,42 @@ #include "dice.h" -static int dice_rate_constraint(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - struct snd_pcm_substream *substream = rule->private; - struct snd_dice *dice = substream->private_data; - - const struct snd_interval *c = - hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_interval *r = - hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval rates = { - .min = UINT_MAX, .max = 0, .integer = 1 - }; - unsigned int i, rate, mode, *pcm_channels; - - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - pcm_channels = dice->tx_channels; - else - pcm_channels = dice->rx_channels; - - for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) { - rate = snd_dice_rates[i]; - if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0) - continue; - - if (!snd_interval_test(c, pcm_channels[mode])) - continue; - - rates.min = min(rates.min, rate); - rates.max = max(rates.max, rate); - } - - return snd_interval_refine(r, &rates); -} - -static int dice_channels_constraint(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) -{ - struct snd_pcm_substream *substream = rule->private; - struct snd_dice *dice = substream->private_data; - - const struct snd_interval *r = - hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *c = - hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_interval channels = { - .min = UINT_MAX, .max = 0, .integer = 1 - }; - unsigned int i, rate, mode, *pcm_channels; - - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - pcm_channels = dice->tx_channels; - else - pcm_channels = dice->rx_channels; - - for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) { - rate = snd_dice_rates[i]; - if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0) - continue; - - if (!snd_interval_test(r, rate)) - continue; - - channels.min = min(channels.min, pcm_channels[mode]); - channels.max = max(channels.max, pcm_channels[mode]); - } - - return snd_interval_refine(c, &channels); -} - -static void limit_channels_and_rates(struct snd_dice *dice, - struct snd_pcm_runtime *runtime, - unsigned int *pcm_channels) +static int limit_channels_and_rates(struct snd_dice *dice, + struct snd_pcm_runtime *runtime, + struct amdtp_stream *stream) { struct snd_pcm_hardware *hw = &runtime->hw; - unsigned int i, rate, mode; + unsigned int rate; + __be32 reg[2]; + int err; - hw->channels_min = UINT_MAX; - hw->channels_max = 0; + /* + * Retrieve current Multi Bit Linear Audio data channel and limit to + * it. + */ + if (stream == &dice->tx_stream) { + err = snd_dice_transaction_read_tx(dice, TX_NUMBER_AUDIO, + reg, sizeof(reg)); + } else { + err = snd_dice_transaction_read_rx(dice, RX_NUMBER_AUDIO, + reg, sizeof(reg)); + } + if (err < 0) + return err; - for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) { - rate = snd_dice_rates[i]; - if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0) - continue; - hw->rates |= snd_pcm_rate_to_rate_bit(rate); + hw->channels_min = hw->channels_max = be32_to_cpu(reg[0]); - if (pcm_channels[mode] == 0) - continue; - hw->channels_min = min(hw->channels_min, pcm_channels[mode]); - hw->channels_max = max(hw->channels_max, pcm_channels[mode]); - } + /* Retrieve current sampling transfer frequency and limit to it. */ + err = snd_dice_transaction_get_rate(dice, &rate); + if (err < 0) + return err; + hw->rates = snd_pcm_rate_to_rate_bit(rate); + hw->rate_min = rate; + hw->rate_max = rate; snd_pcm_limit_hw_rates(runtime); + + return 0; } static void limit_period_and_buffer(struct snd_pcm_hardware *hw) @@ -122,7 +65,6 @@ static int init_hw_info(struct snd_dice *dice, struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_hardware *hw = &runtime->hw; struct amdtp_stream *stream; - unsigned int *pcm_channels; int err; hw->info = SNDRV_PCM_INFO_MMAP | @@ -135,37 +77,22 @@ 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; - pcm_channels = dice->tx_channels; } else { hw->formats = AM824_OUT_PCM_FORMAT_BITS; stream = &dice->rx_stream; - pcm_channels = dice->rx_channels; } - limit_channels_and_rates(dice, runtime, pcm_channels); - limit_period_and_buffer(hw); - - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - dice_rate_constraint, substream, - SNDRV_PCM_HW_PARAM_CHANNELS, -1); + err = limit_channels_and_rates(dice, runtime, stream); if (err < 0) - goto end; - err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - dice_channels_constraint, substream, - SNDRV_PCM_HW_PARAM_RATE, -1); - if (err < 0) - goto end; + return err; + limit_period_and_buffer(hw); - err = amdtp_am824_add_pcm_hw_constraints(stream, runtime); -end: - return err; + return amdtp_am824_add_pcm_hw_constraints(stream, runtime); } static int pcm_open(struct snd_pcm_substream *substream) { struct snd_dice *dice = substream->private_data; - unsigned int source, rate; - bool internal; int err; err = snd_dice_stream_lock_try(dice); @@ -176,39 +103,6 @@ static int pcm_open(struct snd_pcm_substream *substream) if (err < 0) goto err_locked; - err = snd_dice_transaction_get_clock_source(dice, &source); - if (err < 0) - goto err_locked; - switch (source) { - case CLOCK_SOURCE_AES1: - case CLOCK_SOURCE_AES2: - case CLOCK_SOURCE_AES3: - case CLOCK_SOURCE_AES4: - case CLOCK_SOURCE_AES_ANY: - case CLOCK_SOURCE_ADAT: - case CLOCK_SOURCE_TDIF: - case CLOCK_SOURCE_WC: - internal = false; - break; - default: - internal = true; - break; - } - - /* - * When source of clock is not internal or any PCM streams are running, - * available sampling rate is limited at current sampling rate. - */ - if (!internal || - amdtp_stream_pcm_running(&dice->tx_stream) || - amdtp_stream_pcm_running(&dice->rx_stream)) { - err = snd_dice_transaction_get_rate(dice, &rate); - if (err < 0) - goto err_locked; - substream->runtime->hw.rate_min = rate; - substream->runtime->hw.rate_max = rate; - } - snd_pcm_set_sync(substream); end: return err;