mirror of https://gitee.com/openkylin/linux.git
ASoC: q6asm-dai: add support to copy callback
During gapless playback, its possible for previous track to end at unaligned boundary, starting next track on the same boundary can lead to unaligned address exception in dsp. So implement copy callback for finer control on the buffer offsets. Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> Tested-by: Vinod Koul <vkoul@kernel.org> Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Reviewed-by: Vinod Koul <vkoul@kernel.org> Link: https://lore.kernel.org/r/20200727093806.17089-11-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
ee941a338a
commit
a08cd56a45
|
@ -1052,16 +1052,71 @@ static int q6asm_dai_compr_pointer(struct snd_soc_component *component,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int q6asm_dai_compr_ack(struct snd_soc_component *component,
|
||||
struct snd_compr_stream *stream,
|
||||
size_t count)
|
||||
static int q6asm_compr_copy(struct snd_soc_component *component,
|
||||
struct snd_compr_stream *stream, char __user *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct snd_compr_runtime *runtime = stream->runtime;
|
||||
struct q6asm_dai_rtd *prtd = runtime->private_data;
|
||||
unsigned long flags;
|
||||
u32 wflags = 0;
|
||||
int avail, bytes_in_flight = 0;
|
||||
void *dstn;
|
||||
size_t copy;
|
||||
u32 app_pointer;
|
||||
u32 bytes_received;
|
||||
|
||||
bytes_received = prtd->bytes_received;
|
||||
|
||||
/**
|
||||
* Make sure that next track data pointer is aligned at 32 bit boundary
|
||||
* This is a Mandatory requirement from DSP data buffers alignment
|
||||
*/
|
||||
if (prtd->next_track)
|
||||
bytes_received = ALIGN(prtd->bytes_received, prtd->pcm_count);
|
||||
|
||||
app_pointer = bytes_received/prtd->pcm_size;
|
||||
app_pointer = bytes_received - (app_pointer * prtd->pcm_size);
|
||||
dstn = prtd->dma_buffer.area + app_pointer;
|
||||
|
||||
if (count < prtd->pcm_size - app_pointer) {
|
||||
if (copy_from_user(dstn, buf, count))
|
||||
return -EFAULT;
|
||||
} else {
|
||||
copy = prtd->pcm_size - app_pointer;
|
||||
if (copy_from_user(dstn, buf, copy))
|
||||
return -EFAULT;
|
||||
if (copy_from_user(prtd->dma_buffer.area, buf + copy,
|
||||
count - copy))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&prtd->lock, flags);
|
||||
prtd->bytes_received += count;
|
||||
|
||||
bytes_in_flight = prtd->bytes_received - prtd->copied_total;
|
||||
|
||||
if (prtd->next_track) {
|
||||
prtd->next_track = false;
|
||||
prtd->copied_total = ALIGN(prtd->copied_total, prtd->pcm_count);
|
||||
prtd->bytes_sent = ALIGN(prtd->bytes_sent, prtd->pcm_count);
|
||||
}
|
||||
|
||||
prtd->bytes_received = bytes_received + count;
|
||||
|
||||
/* Kick off the data to dsp if its starving!! */
|
||||
if (prtd->state == Q6ASM_STREAM_RUNNING && (bytes_in_flight == 0)) {
|
||||
uint32_t bytes_to_write = prtd->pcm_count;
|
||||
|
||||
avail = prtd->bytes_received - prtd->bytes_sent;
|
||||
|
||||
if (avail < prtd->pcm_count)
|
||||
bytes_to_write = avail;
|
||||
|
||||
q6asm_write_async(prtd->audio_client, prtd->stream_id,
|
||||
bytes_to_write, 0, 0, wflags);
|
||||
prtd->bytes_sent += bytes_to_write;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&prtd->lock, flags);
|
||||
|
||||
return count;
|
||||
|
@ -1124,7 +1179,7 @@ static struct snd_compress_ops q6asm_dai_compress_ops = {
|
|||
.get_caps = q6asm_dai_compr_get_caps,
|
||||
.get_codec_caps = q6asm_dai_compr_get_codec_caps,
|
||||
.mmap = q6asm_dai_compr_mmap,
|
||||
.ack = q6asm_dai_compr_ack,
|
||||
.copy = q6asm_compr_copy,
|
||||
};
|
||||
|
||||
static int q6asm_dai_pcm_new(struct snd_soc_component *component,
|
||||
|
|
Loading…
Reference in New Issue