Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ALSA: firewire-lib/dice: add arrangements of PCM pointer and interrupts for Dice quirk

In IEC 61883-6, one data block transfers one event. In ALSA, the event equals one PCM frame,
hence one data block transfers one PCM frame. But Dice has a quirk at higher sampling rate
(176.4/192.0 kHz) that one data block transfers two PCM frames.

Commit 10550bea44a8 ("ALSA: dice/firewire-lib: Keep dualwire mode but obsolete
CIP_HI_DUALWIRE") moved some codes related to this quirk into Dice driver. But the commit
forgot to add arrangements for PCM period interrupts and DMA pointer updates. As a result, Dice
driver cannot work correctly at higher sampling rate.

This commit adds 'double_pcm_frames' parameter to amdtp structure for this quirk. When this
parameter is set, PCM period interrupts and DMA pointer updates occur at double speed than in
IEC 61883-6.

Reported-by: Daniel Robbins <drobbins@funtoo.org>
Fixes: 10550bea44a8 ("ALSA: dice/firewire-lib: Keep dualwire mode but obsolete CIP_HI_DUALWIRE")
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Cc: <stable@vger.kernel.org> # 3.16
Signed-off-by: Takashi Iwai <tiwai@suse.de>

authored by

Takashi Sakamoto and committed by
Takashi Iwai
65845f29 1033eb5b

+22 -5
+10 -1
sound/firewire/amdtp.c
··· 507 507 static void update_pcm_pointers(struct amdtp_stream *s, 508 508 struct snd_pcm_substream *pcm, 509 509 unsigned int frames) 510 - { unsigned int ptr; 510 + { 511 + unsigned int ptr; 512 + 513 + /* 514 + * In IEC 61883-6, one data block represents one event. In ALSA, one 515 + * event equals to one PCM frame. But Dice has a quirk to transfer 516 + * two PCM frames in one data block. 517 + */ 518 + if (s->double_pcm_frames) 519 + frames *= 2; 511 520 512 521 ptr = s->pcm_buffer_pointer + frames; 513 522 if (ptr >= pcm->runtime->buffer_size)
+1
sound/firewire/amdtp.h
··· 125 125 unsigned int pcm_buffer_pointer; 126 126 unsigned int pcm_period_pointer; 127 127 bool pointer_flush; 128 + bool double_pcm_frames; 128 129 129 130 struct snd_rawmidi_substream *midi[AMDTP_MAX_CHANNELS_FOR_MIDI * 8]; 130 131
+11 -4
sound/firewire/dice.c
··· 567 567 return err; 568 568 569 569 /* 570 - * At rates above 96 kHz, pretend that the stream runs at half the 571 - * actual sample rate with twice the number of channels; two samples 572 - * of a channel are stored consecutively in the packet. Requires 573 - * blocking mode and PCM buffer size should be aligned to SYT_INTERVAL. 570 + * At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in 571 + * one data block of AMDTP packet. Thus sampling transfer frequency is 572 + * a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are 573 + * transferred on AMDTP packets at 96 kHz. Two successive samples of a 574 + * channel are stored consecutively in the packet. This quirk is called 575 + * as 'Dual Wire'. 576 + * For this quirk, blocking mode is required and PCM buffer size should 577 + * be aligned to SYT_INTERVAL. 574 578 */ 575 579 channels = params_channels(hw_params); 576 580 if (rate_index > 4) { ··· 585 581 586 582 rate /= 2; 587 583 channels *= 2; 584 + dice->stream.double_pcm_frames = true; 585 + } else { 586 + dice->stream.double_pcm_frames = false; 588 587 } 589 588 590 589 mode = rate_index_to_mode(rate_index);