diff options
| author | Rodrigo Vivi <[email protected]> | 2018-07-23 09:13:12 -0700 | 
|---|---|---|
| committer | Rodrigo Vivi <[email protected]> | 2018-07-23 09:13:12 -0700 | 
| commit | c74a7469f97c0f40b46e82ee979f9fb1bb6e847c (patch) | |
| tree | f2690a1a916b73ef94657fbf0e0141ae57701825 /sound/firewire/dice/dice-pcm.c | |
| parent | 6f15a7de86c8cf2dc09fc9e6d07047efa40ef809 (diff) | |
| parent | 500775074f88d9cf5416bed2ca19592812d62c41 (diff) | |
Merge drm/drm-next into drm-intel-next-queued
We need a backmerge to get DP_DPCD_REV_14 before we push other
i915 changes to dinq that could break compilation.
Signed-off-by: Rodrigo Vivi <[email protected]>
Diffstat (limited to 'sound/firewire/dice/dice-pcm.c')
| -rw-r--r-- | sound/firewire/dice/dice-pcm.c | 233 | 
1 files changed, 162 insertions, 71 deletions
| diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index 7cb9e9713ac3..80351b29fe0d 100644 --- a/sound/firewire/dice/dice-pcm.c +++ b/sound/firewire/dice/dice-pcm.c @@ -9,43 +9,115 @@  #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; +	unsigned int index = substream->pcm->device; + +	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 *pcm_channels; +	enum snd_dice_rate_mode mode; +	unsigned int i, rate; + +	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) +		pcm_channels = dice->tx_pcm_chs[index]; +	else +		pcm_channels = dice->rx_pcm_chs[index]; + +	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; +	unsigned int index = substream->pcm->device; + +	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 *pcm_channels; +	enum snd_dice_rate_mode mode; +	unsigned int i, rate; + +	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) +		pcm_channels = dice->tx_pcm_chs[index]; +	else +		pcm_channels = dice->rx_pcm_chs[index]; + +	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 int limit_channels_and_rates(struct snd_dice *dice,  				    struct snd_pcm_runtime *runtime,  				    enum amdtp_stream_direction dir, -				    unsigned int index, unsigned int size) +				    unsigned int index)  {  	struct snd_pcm_hardware *hw = &runtime->hw; -	struct amdtp_stream *stream; -	unsigned int rate; -	__be32 reg; -	int err; - -	/* -	 * Retrieve current Multi Bit Linear Audio data channel and limit to -	 * it. -	 */ -	if (dir == AMDTP_IN_STREAM) { -		stream = &dice->tx_stream[index]; -		err = snd_dice_transaction_read_tx(dice, -				size * index + TX_NUMBER_AUDIO, -				®, sizeof(reg)); -	} else { -		stream = &dice->rx_stream[index]; -		err = snd_dice_transaction_read_rx(dice, -				size * index + RX_NUMBER_AUDIO, -				®, sizeof(reg)); +	unsigned int *pcm_channels; +	unsigned int i; + +	if (dir == AMDTP_IN_STREAM) +		pcm_channels = dice->tx_pcm_chs[index]; +	else +		pcm_channels = dice->rx_pcm_chs[index]; + +	hw->channels_min = UINT_MAX; +	hw->channels_max = 0; + +	for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) { +		enum snd_dice_rate_mode mode; +		unsigned int rate, channels; + +		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); + +		channels = pcm_channels[mode]; +		if (channels == 0) +			continue; +		hw->channels_min = min(hw->channels_min, channels); +		hw->channels_max = max(hw->channels_max, channels);  	} -	if (err < 0) -		return err; -	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); -	if (err < 0) -		return err; - -	hw->rates = snd_pcm_rate_to_rate_bit(rate);  	snd_pcm_limit_hw_rates(runtime);  	return 0; @@ -56,36 +128,34 @@ static int init_hw_info(struct snd_dice *dice,  {  	struct snd_pcm_runtime *runtime = substream->runtime;  	struct snd_pcm_hardware *hw = &runtime->hw; +	unsigned int index = substream->pcm->device;  	enum amdtp_stream_direction dir;  	struct amdtp_stream *stream; -	__be32 reg[2]; -	unsigned int count, size;  	int err;  	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {  		hw->formats = AM824_IN_PCM_FORMAT_BITS;  		dir = AMDTP_IN_STREAM; -		stream = &dice->tx_stream[substream->pcm->device]; -		err = snd_dice_transaction_read_tx(dice, TX_NUMBER, reg, -						   sizeof(reg)); +		stream = &dice->tx_stream[index];  	} else {  		hw->formats = AM824_OUT_PCM_FORMAT_BITS;  		dir = AMDTP_OUT_STREAM; -		stream = &dice->rx_stream[substream->pcm->device]; -		err = snd_dice_transaction_read_rx(dice, RX_NUMBER, reg, -						   sizeof(reg)); +		stream = &dice->rx_stream[index];  	} +	err = limit_channels_and_rates(dice, substream->runtime, dir, +				       index);  	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); +	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, +				  dice_rate_constraint, substream, +				  SNDRV_PCM_HW_PARAM_CHANNELS, -1); +	if (err < 0) +		return err; +	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)  		return err; @@ -95,6 +165,8 @@ 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; +	unsigned int source; +	bool internal;  	int err;  	err = snd_dice_stream_lock_try(dice); @@ -105,6 +177,43 @@ 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[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])) { +		unsigned int rate; + +		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; @@ -318,37 +427,19 @@ int snd_dice_create_pcm(struct snd_dice *dice)  		.page      = snd_pcm_lib_get_vmalloc_page,  		.mmap      = snd_pcm_lib_mmap_vmalloc,  	}; -	__be32 reg;  	struct snd_pcm *pcm; -	unsigned int i, max_capture, max_playback, capture, playback; +	unsigned int capture, playback; +	int i, j;  	int err; -	/* Check whether PCM substreams are required. */ -	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, ®, -						   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, ®, -						   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; -		if (i < max_capture) -			capture = 1; -		if (i < max_playback) -			playback = 1; -		if (capture == 0 && playback == 0) -			break; +		for (j = 0; j < SND_DICE_RATE_MODE_COUNT; ++j) { +			if (dice->tx_pcm_chs[i][j] > 0) +				capture = 1; +			if (dice->rx_pcm_chs[i][j] > 0) +				playback = 1; +		}  		err = snd_pcm_new(dice->card, "DICE", i, playback, capture,  				  &pcm); |