as pulseaudio use snd_pcm_rewind() which require the sound card report accurate hwptr position than those sound card which report hwptr position at period bounary when interrupt occur
the difference between hda-intel and your ca0106 is the granularity of the pointer callback
/**
* enum dma_residue_granularity - Granularity of the reported transfer residue
* @DMA_RESIDUE_GRANULARITY_DESCRIPTOR: Residue reporting is not support. The
* DMA channel is only able to tell whether a descriptor has been completed or
* not, which means residue reporting is not supported by this channel. The
* residue field of the dma_tx_state field will always be 0.
* @DMA_RESIDUE_GRANULARITY_SEGMENT: Residue is updated after each successfully
* completed segment of the transfer (For cyclic transfers this is after each
* period). This is typically implemented by having the hardware generate an
* interrupt after each transferred segment and then the drivers updates the
* outstanding residue by the size of the segment. Another possibility is if
* the hardware supports scatter-gather and the segment descriptor has a field
* which gets set after the segment has been completed. The driver then counts
* the number of segments without the flag set to compute the residue.
* @DMA_RESIDUE_GRANULARITY_BURST: Residue is updated after each transferred
* burst. This is typically only supported if the hardware has a progress
* register of some sort (E.g. a register with the current read/write address
* or a register with the amount of bursts/beats/bytes that have been
* transferred or still need to be transferred).
*/
hda-intel can report DMA_RESIDUE_GRANULARITY_BURST
seem both read hwptr from hardware register
can your ca0106 report DMA_RESIDUE_GRANULARITY_SEGMENT or DMA_RESIDUE_GRANULARITY_BURST ?
as pulseaudio use snd_pcm_rewind() which require the sound card report accurate hwptr position than those sound card which report hwptr position at period bounary when interrupt occur
the difference between hda-intel and your ca0106 is the granularity of the pointer callback
https:/ /git.kernel. org/cgit/ linux/kernel/ git/tiwai/ sound.git/ tree/include/ linux/dmaengine .h
/** granularity - Granularity of the reported transfer residue GRANULARITY_ DESCRIPTOR: Residue reporting is not support. The GRANULARITY_ SEGMENT: Residue is updated after each successfully GRANULARITY_ BURST: Residue is updated after each transferred
* enum dma_residue_
* @DMA_RESIDUE_
* DMA channel is only able to tell whether a descriptor has been completed or
* not, which means residue reporting is not supported by this channel. The
* residue field of the dma_tx_state field will always be 0.
* @DMA_RESIDUE_
* completed segment of the transfer (For cyclic transfers this is after each
* period). This is typically implemented by having the hardware generate an
* interrupt after each transferred segment and then the drivers updates the
* outstanding residue by the size of the segment. Another possibility is if
* the hardware supports scatter-gather and the segment descriptor has a field
* which gets set after the segment has been completed. The driver then counts
* the number of segments without the flag set to compute the residue.
* @DMA_RESIDUE_
* burst. This is typically only supported if the hardware has a progress
* register of some sort (E.g. a register with the current read/write address
* or a register with the amount of bursts/beats/bytes that have been
* transferred or still need to be transferred).
*/
hda-intel can report DMA_RESIDUE_ GRANULARITY_ BURST
seem both read hwptr from hardware register
can your ca0106 report DMA_RESIDUE_ GRANULARITY_ SEGMENT or DMA_RESIDUE_ GRANULARITY_ BURST ?
https:/ /git.kernel. org/cgit/ linux/kernel/ git/tiwai/ sound.git/ tree/sound/ pci/ca0106/ ca0106_ main.c
static snd_pcm_uframes_t pcm_pointer_ playback( struct snd_pcm_substream *substream) substream_ chip(substream) ; >private_ data;
snd_ca0106_
{
struct snd_ca0106 *emu = snd_pcm_
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_ca0106_pcm *epcm = runtime-
unsigned int ptr, prev_ptr;
int channel = epcm->channel_id;
int timeout = 10;
if (!epcm->running)
return 0;
prev_ptr = -1; ptr_read( emu, PLAYBACK_LIST_PTR, channel); >period_ size; frames( runtime, ca0106_ ptr_read( emu, PLAYBACK_POINTER, channel)); >buffer_ size) >buffer_ size; emu->card- >dev, "ca0106: unstable DMA pointer!\n");
do {
ptr = snd_ca0106_
ptr = (ptr >> 3) * runtime-
ptr += bytes_to_
snd_
if (ptr >= runtime-
ptr -= runtime-
if (prev_ptr == ptr)
return ptr;
prev_ptr = ptr;
} while (--timeout);
dev_warn(
return 0;
}
https:/ /git.kernel. org/cgit/ linux/kernel/ git/tiwai/ sound.git/ tree/sound/ pci/hda/ hda_controller. c
static snd_pcm_uframes_t azx_pcm_ pointer( struct snd_pcm_substream *substream) substream_ chip(substream) ; dev(substream) ; frames( substream- >runtime,
azx_ get_position( chip, azx_dev));
{
struct azx_pcm *apcm = snd_pcm_
struct azx *chip = apcm->chip;
struct azx_dev *azx_dev = get_azx_
return bytes_to_
}