diff options
Diffstat (limited to 'sound/firewire/dice/dice-stream.c')
| -rw-r--r-- | sound/firewire/dice/dice-stream.c | 78 |
1 files changed, 26 insertions, 52 deletions
diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index 8e0c0380b4c4..d5ffe7c82993 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c @@ -8,8 +8,8 @@ #include "dice.h" -#define CALLBACK_TIMEOUT 200 -#define NOTIFICATION_TIMEOUT_MS (2 * MSEC_PER_SEC) +#define READY_TIMEOUT_MS 200 +#define NOTIFICATION_TIMEOUT_MS 100 struct reg_params { unsigned int count; @@ -57,13 +57,9 @@ int snd_dice_stream_get_rate_mode(struct snd_dice *dice, unsigned int rate, return -EINVAL; } -/* - * This operation has an effect to synchronize GLOBAL_STATUS/GLOBAL_SAMPLE_RATE - * to GLOBAL_STATUS. Especially, just after powering on, these are different. - */ -static int ensure_phase_lock(struct snd_dice *dice, unsigned int rate) +static int select_clock(struct snd_dice *dice, unsigned int rate) { - __be32 reg, nominal; + __be32 reg, new; u32 data; int i; int err; @@ -87,24 +83,15 @@ static int ensure_phase_lock(struct snd_dice *dice, unsigned int rate) if (completion_done(&dice->clock_accepted)) reinit_completion(&dice->clock_accepted); - reg = cpu_to_be32(data); + new = cpu_to_be32(data); err = snd_dice_transaction_write_global(dice, GLOBAL_CLOCK_SELECT, - ®, sizeof(reg)); + &new, sizeof(new)); if (err < 0) return err; if (wait_for_completion_timeout(&dice->clock_accepted, msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0) { - /* - * Old versions of Dice firmware transfer no notification when - * the same clock status as current one is set. In this case, - * just check current clock status. - */ - err = snd_dice_transaction_read_global(dice, GLOBAL_STATUS, - &nominal, sizeof(nominal)); - if (err < 0) - return err; - if (!(be32_to_cpu(nominal) & STATUS_SOURCE_LOCKED)) + if (reg != new) return -ETIMEDOUT; } @@ -181,7 +168,7 @@ static int keep_resources(struct snd_dice *dice, struct amdtp_stream *stream, // as 'Dual Wire'. // For this quirk, blocking mode is required and PCM buffer size should // be aligned to SYT_INTERVAL. - double_pcm_frames = rate > 96000; + double_pcm_frames = (rate > 96000 && !dice->disable_double_pcm_frames); if (double_pcm_frames) { rate /= 2; pcm_chs *= 2; @@ -304,7 +291,7 @@ int snd_dice_stream_reserve_duplex(struct snd_dice *dice, unsigned int rate, // Just after owning the unit (GLOBAL_OWNER), the unit can // return invalid stream formats. Selecting clock parameters // have an effect for the unit to refine it. - err = ensure_phase_lock(dice, rate); + err = select_clock(dice, rate); if (err < 0) return err; @@ -459,20 +446,17 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice) goto error; } - err = amdtp_domain_start(&dice->domain, 0); + // MEMO: The device immediately starts packet transmission when enabled. Some + // devices are strictly to generate any discontinuity in the sequence of tx packet + // when they receives invalid sequence of presentation time in CIP header. The + // sequence replay for media clock recovery can suppress the behaviour. + err = amdtp_domain_start(&dice->domain, 0, true, false); if (err < 0) goto error; - for (i = 0; i < MAX_STREAMS; i++) { - if ((i < tx_params.count && - !amdtp_stream_wait_callback(&dice->tx_stream[i], - CALLBACK_TIMEOUT)) || - (i < rx_params.count && - !amdtp_stream_wait_callback(&dice->rx_stream[i], - CALLBACK_TIMEOUT))) { - err = -ETIMEDOUT; - goto error; - } + if (!amdtp_domain_wait_ready(&dice->domain, READY_TIMEOUT_MS)) { + err = -ETIMEDOUT; + goto error; } } @@ -493,11 +477,10 @@ void snd_dice_stream_stop_duplex(struct snd_dice *dice) struct reg_params tx_params, rx_params; if (dice->substreams_counter == 0) { - if (get_register_params(dice, &tx_params, &rx_params) >= 0) { - amdtp_domain_stop(&dice->domain); + if (get_register_params(dice, &tx_params, &rx_params) >= 0) finish_session(dice, &tx_params, &rx_params); - } + amdtp_domain_stop(&dice->domain); release_resources(dice); } } @@ -654,7 +637,7 @@ int snd_dice_stream_detect_current_formats(struct snd_dice *dice) * invalid stream formats. Selecting clock parameters have an effect * for the unit to refine it. */ - err = ensure_phase_lock(dice, rate); + err = select_clock(dice, rate); if (err < 0) return err; @@ -694,32 +677,23 @@ static void dice_lock_changed(struct snd_dice *dice) int snd_dice_stream_lock_try(struct snd_dice *dice) { - int err; - - spin_lock_irq(&dice->lock); + guard(spinlock_irq)(&dice->lock); - if (dice->dev_lock_count < 0) { - err = -EBUSY; - goto out; - } + if (dice->dev_lock_count < 0) + return -EBUSY; if (dice->dev_lock_count++ == 0) dice_lock_changed(dice); - err = 0; -out: - spin_unlock_irq(&dice->lock); - return err; + return 0; } void snd_dice_stream_lock_release(struct snd_dice *dice) { - spin_lock_irq(&dice->lock); + guard(spinlock_irq)(&dice->lock); if (WARN_ON(dice->dev_lock_count <= 0)) - goto out; + return; if (--dice->dev_lock_count == 0) dice_lock_changed(dice); -out: - spin_unlock_irq(&dice->lock); } |
